Files
windows/PLAN.md
T

211 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MusicBridge — план проекта
Обновлено: 2026-09-09. Репозиторий находится в `MusicBridge.Agent/`.
## Цель
Личный пульт на **нативном iPhone-приложении** для музыки на Windows в одной
Wi-Fi сети. Звук играет на ПК. Телефон показывает трек, исполнителя, обложку,
позицию и позволяет управлять воспроизведением и системной громкостью ПК.
## Решения пользователя — не менять без его указания
- Windows + iPhone; своего Mac сейчас нет.
- **Не делать Safari, PWA, веб-страницы или веб-приложение.** Клиент — Swift/SwiftUI.
- iPhone-часть пока не начинать. Сначала довести Windows-агент и протокол.
- Работать по этапам, самостоятельно редактировать файлы и проверять сборку.
- Основные источники: Яндекс Музыка и SoundCloud в браузере, через текущую
системную медиасессию Windows.
- Нужны безопасное сопряжение, автоматическое переподключение, затем поиск ПК.
- В будущем желательны Lock Screen, Dynamic Island и системные команды iOS.
## Границы возможностей
- «Любой звук» относится к системной громкости. Метаданные и команды зависят от
того, что конкретный плеер передаёт в Windows Media Session.
- Позиция вычисляется из Position + времени после LastUpdatedTime с учётом
PlaybackRate. Нельзя считать Position постоянно обновляемым значением.
- Не обещать работу перемотки или переключений без проверки возможностей плеера.
- Для сборки/подписи нативного iOS-приложения потребуется доступ к macOS/Xcode;
способ установки на личный iPhone нужно выбрать перед началом iOS-этапа.
- Возможности iOS в фоне, Lock Screen и Dynamic Island исследовать отдельно.
Не имитировать воспроизведение беззвучным аудио ради фоновой работы.
- HTTPS/WebSocket внутри агента — транспорт для нативного клиента, не веб-интерфейс.
## Архитектура
Windows Media Session → общий MediaService → HTTPS/WSS → будущий SwiftUI-клиент.
Windows Core Audio → системная громкость устройства вывода по умолчанию.
Консоль и сеть используют одни команды и одни правила расчёта позиции.
## Этапы и TODO
### 1. Windows: чтение и локальное управление
- [x] Название, исполнитель, источник, состояние и длительность.
- [x] Вычисление текущей позиции с учётом времени и скорости.
- [x] Play/pause, следующий/предыдущий трек, перемотка ±10 секунд.
- [x] Системная громкость ±5%, mute.
- [x] Проверки поддержки команд и обработка отказов.
- [x] Сборка исходной консольной версии: 0 ошибок, 0 предупреждений.
- [x] Проверен запуск с реальным плеером и чтение громкости.
- [ ] Полная ручная проверка кнопок в Яндекс Музыке и SoundCloud.
### 2. Windows: общий сервис и сетевой протокол
- [x] Вынести чтение/команды из Program.cs в общий сервис.
- [x] Добавить абсолютную перемотку и установку громкости для ползунков iPhone.
- [x] Версионированное JSON-состояние, возможности плеера, результаты команд.
- [x] HTTPS для команд, WSS для обновлений состояния; без веб-интерфейса.
- [x] Ограниченное по времени сопряжение по коду, аутентификация команд.
- [x] Сертификат агента и отпечаток для будущего закрепления сертификата на iPhone.
- [x] Проверки протокола, ошибочного ввода и доступа без авторизации.
- [x] Обновить этот файл и документацию по фактическим результатам.
### 3. Довести агент перед iPhone
- [x] Обложка из медиасессии; ограничение размера, кеш и смена трека.
- [x] Системные события Windows для быстрых обновлений; таймер для прогресса.
- [x] Постоянные доверенные устройства, безопасное хранение хешей токенов, отзыв доступа.
- [x] Постоянный сертификат, защищённое хранилище Windows DPAPI, блокировка второго агента.
- [ ] Обновление истекающего сертификата с явным повторным сопряжением.
- [x] Локальный QR с адресом, кодом и отпечатком; Windows-окно по клавише I.
- [x] Обновление QR при смене адреса/кода; очистка при закрытии сопряжения.
- [x] Заготовки: payload для QR, проверка адреса/срока, клавиша I.
- [x] Заготовки: DNS-SD descriptor и авторизованный /v1/info; без multicast.
- [x] Объявление Bonjour/mDNS: PTR/SRV/TXT/A, повторные объявления и goodbye.
- [ ] Полноценное разрешение конфликтов имён mDNS (сейчас имя по хешу сертификата).
- [ ] Проверить подключение со второго устройства в домашней сети.
- [ ] Проверить смену плеера/аудиоустройства, отсутствие плеера, сон/пробуждение,
отключение Wi-Fi и несколько клиентов.
- [ ] Tray-интерфейс, автозапуск, удобная установка; правила брандмауэра только
для нужной локальной сети, без открытия доступа в интернет.
- [x] Трей и окно управления (`--tray`): медиакнопки, ползунки, QR, доверенные устройства.
- [x] Закрытие окна скрывает его; двойной щелчок по значку восстанавливает;
отдельный пункт меню завершает агент. Консоль остаётся отдельным режимом.
- [ ] Автозапуск и установщик (трей реализован, общий пункт выше ещё не завершён).
### 4. Нативное приложение iPhone — отложено пользователем
- [ ] Согласовать macOS/Xcode, подпись и установку на личный iPhone.
- [ ] SwiftUI: подключение, список компьютеров, сопряжение и сохранение в Keychain.
- [ ] Обложка, трек, исполнитель, плавный прогресс, кнопки и ползунки.
- [ ] Проверка сертификата ПК, переподключение и восстановление состояния.
- [ ] Отключать недоступные команды, отображать ошибки и потерю связи.
- [ ] Проверка на физическом iPhone.
### 5. Дополнительные возможности iOS
- [ ] Исследовать и проверить Live Activities / Dynamic Island / App Intents.
- [ ] Зафиксировать реальные ограничения системного управления и фона.
## Как продолжать работу
1. Прочитать этот файл, затем текущие исходники и `git status`.
2. Не переписывать уже работающие функции без необходимости.
3. Выполнить конкретный этап, проверить сборку и соответствующие проверки.
4. Отдельно указать: что проверено автоматически, что на реальной Windows,
а что ещё требует телефона/ручной проверки.
5. Обновить чекбоксы, результаты и следующий шаг здесь до завершения работы.
## Проверки и следующий шаг
2026-09-09:
- Последний этап — окно управления и трей: **102 проверки прошли**, Release-сборка
без ошибок/предупреждений. Прогон с `--desktop-smoke --qr-window-smoke --mdns-smoke --live-read`.
В скрытом окне проверены включение/отключение кнопок, отправка play/pause и
абсолютной громкости тестовому сервису, скрытие по крестику, продолжение работы
и остановка UI-потока. Снимок окна просмотрен. Реальную музыку тесты не меняли.
Ручное взаимодействие с видимым значком трея пока не проверялось.
- Последний этап — работающие QR и mDNS: **95 проверок прошло**, Release-сборка
без ошибок и предупреждений. Прогон: `dotnet run --project tests/MusicBridge.Agent.Tests.csproj -c Release --no-build -- --qr-window-smoke --mdns-smoke --live-read`.
Проверены декодирование QR независимой библиотекой, скрытое окно и очистка
просроченного QR, реальные объявления/goodbye mDNS отдельным слушателем на
этом же ПК. Снимок окна просмотрен. Реальная обложка: JPEG, 12068 байт.
Второе физическое устройство и сканирование телефоном пока не проверялись.
Далее — исторические результаты предыдущих этапов.
- Последний этап — заготовки подключения: Release-сборка без ошибок/предупреждений,
**82 автоматические проверки прошли** (`dotnet run --project tests/MusicBridge.Agent.Tests.csproj -c Release --no-build`).
Проверены payload, адреса, истёкший код, descriptor и авторизация /v1/info.
Debug-сборку удерживал запущенный агент; его не останавливали. Новая сборка в Release.
Реальная медиасессия в этом прогоне не проверялась; проверки ниже — с прошлого этапа.
- Сборка агента и тестового проекта: **0 ошибок, 0 предупреждений**.
- `dotnet run --project tests/MusicBridge.Agent.Tests.csproj -- --live-read`:
**74 проверки прошло** (71 общая + 3 с реальной медиасессией/обложкой).
Проверены расчёт позиции, валидация, срок/одноразовость кода, блокировка после
10 попыток, авторизация HTTPS/WSS, ошибки JSON и размер запроса, доставка
абсолютной перемотки тестовому сервису, поток состояния и закрытие WebSocket.
Добавлены проверки размера/формата обложки, отмены чтения, очистки старого кеша,
авторизации скачивания и 404, доставки событий без ожидания таймера,
объединения 1000 уведомлений и снятия подписки сервером при остановке.
Проверены сохранение/повторное открытие сертификата и устройств, реальный HTTPS
со восстановленным сертификатом/токеном, DPAPI, блокировка второго экземпляра,
ошибки записи, отказ от подмены повреждённого хранилища, постоянный отзыв доступа,
отключение открытого WSS и запрет HTTP-команд отозванным токеном.
- В тестах добавлена обработка исключений верхнего уровня. Проверен
`--test-failure`: текст `TEST FAILED` и выход 1 вместо необработанного исключения,
вызвавшего ранее окно ошибки Windows. Тестовые файлы создаются отдельно от
рабочего хранилища и удаляются после проверки.
- Эти проверки не меняют реальную музыку/громкость. Ручная проверка команд
конкретных плееров и физического iPhone всё ещё не выполнена.
- Обновлённый агент запущен в обычном сеансе Windows на loopback-порту 18765:
HTTPS-сервер стартовал, реальная медиасессия, состояние Paused, длительность
и системная громкость прочитаны. После проверки тестовый запуск остановлен.
- После добавления обложки в режиме `--live-read` прочитан реальный PNG размером
438760 байт. Повторное чтение состояния сохранило тот же ID кешированной обложки.
Подписки WinRT создаются успешно. Доставка событий проверена тестовым сервисом;
ручная смена треков/плееров во время работы агента ещё требует проверки.
- В песочнице Windows Media Session может быть недоступна. Не выдавать такую
ошибку за отсутствие Windows API на машине пользователя.
Текущие ограничения сетевого этапа:
- Состояние обновляется по событиям Windows и резервному таймеру ~500 мс.
Метаданные/обложка перечитываются по событию либо через 10 секунд.
- В кеше только текущая обложка, максимум 2 МиБ; PNG/JPEG/GIF/WebP по сигнатуре,
без декодирования на сервере. Скачивание требует авторизации.
- Сертификат и хеши токенов сохраняются в `%LOCALAPPDATA%\MusicBridge\identity.dat`
под Windows DPAPI текущего пользователя. При обычном перезапуске доверие сохраняется.
В консоли `1`…`8` отзывают доступ устройства по номеру; `B` открывает сопряжение.
- Сертификат действует 5 лет; автоматическое обновление ещё не реализовано.
При повреждении/недоступности хранилища или истечении сертификата агент завершается
с ошибкой и не создаёт молча новую идентичность. Восстановление описано в PROTOCOL.md.
- По умолчанию только loopback. `--lan` включает IPv4-сеть; брандмауэр не меняется.
- QR и mDNS реализованы на Windows. iPhone UI и интеграции iOS ещё не реализованы.
- Адреса обновляются примерно раз в секунду; mDNS пересоздаётся при смене списка,
объявляется на домашних IPv4-адаптерах с multicast. Автоизменения брандмауэра нет.
Следующий шаг: проверка с другого устройства и устойчивости при смене сети,
автозапуск/упаковка. Трей уже реализован. iPhone-клиент пока не начинать.
Точные границы реализации и следующие шаги — в `CONNECTION-ROADMAP.md`.
Начать разработку iOS только после новой команды пользователя.
## Карта файлов
- `Program.cs`: запуск, аргументы, консольные клавиши и отображение состояния.
- `Media/MediaService.cs`: чтение Windows Media Session и выполнение всех команд.
- `Media/TimelineMath.cs`: вычисление позиции и границ перемотки.
- `Media/Contracts.cs`: состояние, возможности, команды и их валидация.
- `Media/ArtworkCache.cs`: ограниченное чтение обложки, определение типа и кеш по хешу.
- `SystemVolume.cs`: Windows Core Audio, громкость устройства вывода по умолчанию.
- `Network/RemoteServer.cs`: HTTPS API и обложки, WSS, события/таймер и лимиты.
- `Network/PairingService.cs`: код сопряжения, доверенные устройства, проверка/отзыв токенов.
- `Network/IdentityStore.cs`: постоянный сертификат и устройства, атомарная запись и блокировка.
- `Network/UserProtection.cs`: Windows DPAPI текущего пользователя.
- `Network/AgentCertificate.cs`: создание сертификата TLS для первого запуска.
- `PROTOCOL.md`: команды запуска и точный контракт будущего iPhone-клиента.
- `CONNECTION-ROADMAP.md`: заготовки QR/DNS-SD и шаги будущего подключения.
- `Network/ConnectionInvitation.cs`: проверка и формат данных QR.
- `Network/PairingQr.cs`: локальная генерация PNG (QRCoder).
- `PairingWindowHost.cs`: окно QR на отдельном STA-потоке, выбор адреса и обновления.
- `Desktop/AgentWindow.cs`: окно управления, ползунки и доверенные устройства.
- `Desktop/DesktopHost.cs`: STA-поток, значок/меню трея и жизненный цикл окна.
- `Network/LocalAddresses.cs`: подходящие домашние IPv4-адреса.
- `Network/DiscoveryDescriptor.cs`: публичные поля DNS-SD.
- `Network/MdnsPublisher.cs`: объявления mDNS, обновления адресов и goodbye.
- `tests/`: исполняемые проверки без дополнительных тестовых NuGet-пакетов.