Files
2026-09-10 19:33:53 +03:00

274 lines
27 KiB
Markdown
Raw Permalink 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-10. Репозиторий находится в `MusicBridge.Agent/`.
## Цель
Личный пульт на **нативном iPhone-приложении** для музыки на Windows в одной
Wi-Fi сети. Звук играет на ПК. Телефон показывает трек, исполнителя, обложку,
позицию и позволяет управлять воспроизведением и системной громкостью ПК.
## Решения пользователя — не менять без его указания
- Windows + iPhone; своего Mac сейчас нет.
- **Не делать Safari, PWA, веб-страницы или веб-приложение.** Клиент — Swift/SwiftUI.
- 2026-09-10 пользователь разрешил начать iPhone-часть в отдельном репозитории
`C:/Users/areso/iOS MusicBridge`; актуальный iOS-план находится там в `PLAN.md`.
- Работать по этапам, самостоятельно редактировать файлы и проверять сборку.
- Основные источники: Яндекс Музыка и 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] Закрытие окна скрывает его; двойной щелчок по значку восстанавливает;
отдельный пункт меню завершает агент. Консоль остаётся отдельным режимом.
- [x] Автозапуск текущего пользователя через меню трея; скрытый старт `--minimized`.
- [x] Самостоятельный Windows x64 пакет со встроенными Runtime, ZIP-установка,
ярлык в меню Пуск и скрипт удаления. Это не MSI и не подписанный установщик.
- [x] Скрипт брандмауэра: просмотр, применение и удаление собственных правил;
только конкретный exe, Private + LocalSubnet, TCP порта агента и UDP 5353.
- [x] Восстановление опроса после ошибок чтения; освобождение WSS после обрывов.
### 4. Нативное приложение iPhone — начато 2026-09-10
- [x] Отдельный репозиторий, первый SwiftUI-клиент и workflow сборки на macOS.
Origin: dev.yukinoki.ru/musicbridge/ios; GitHub: polskikh13/musicbridgeios.
Сборка Swift подтверждена Actions run 34444563869 (Xcode 16.4, 7 XCTest прошли).
Интеграция с реальным агентом и физический 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-10:
- Пользователь подтвердил: Ethernet подключён к домашней сети. В `Firewall.ps1`
добавлены `-Profile Domain -InterfaceAlias Ethernet`; по умолчанию Private.
Domain требует точный интерфейс, Public и маски запрещены. LocalSubnet,
привязка к exe и порты сохранены. Preview/WhatIf и проверки ограничений прошли.
- После повторного запроса пользователя правила применены через Windows UAC.
В ActiveStore проверены оба правила: включены, Inbound Allow, Domain,
интерфейс Ethernet, LocalSubnet, EdgeTraversal Block, TCP 8765 и UDP 5353.
Привязаны к `bin/Release/net10.0-windows10.0.19041.0/MusicBridge.Agent.exe`;
имена `MusicBridge-0F2EC7194BF18EBC-HTTPS` и `MusicBridge-0F2EC7194BF18EBC-mDNS`.
Агент во время проверки не запущен. При установке в другой каталог нужны
правила для нового пути. Подключение со второго устройства ещё не проверено.
2026-09-09:
- Последний этап — устойчивость: **112 проверок прошли**, сборка без ошибок и
предупреждений. Конфигурация `Resilience`, параметры `--desktop-smoke
--qr-window-smoke --mdns-smoke --live-read`. Работающий Release-агент не остановлен.
Проверены ошибки первого и последующих чтений, восстановление состояния,
очистка устаревших данных при ошибке и 12 последовательных обрывов WSS.
Чтение получает отмену через 5 секунд; отправка WSS ограничена 5 секундами,
keepalive — 20 секунд с ожиданием ответа 10 секунд. После длинного перерыва
mDNS пересоздаёт объявления. Реальный сон/пробуждение ещё не проверен.
- `Packaging/Test-Firewall.ps1` проверил Preview и Apply -WhatIf без изменения
системы. Правила ещё не применены: Ethernet имеет профиль DomainAuthenticated,
Tailscale — Private, tun2 — Public. Правила Private не откроют доступ через
Ethernet. Категории сети не менять автоматически; доступ для Domain требует
отдельного решения пользователя.
- ZIP пересобран с изменениями устойчивости и `Firewall.ps1`. Повторная проверка
установки, запуска со встроенным Runtime, обновления, защиты занятого exe и
удаления прошла. Проверка правил в режиме WhatIf также прошла; реальных
изменений брандмауэра и установки в рабочую папку пользователя не выполнялось.
- Последний этап — автозапуск и упаковка: **107 проверок прошло** с
`-c Packaging --no-build -- --desktop-smoke --qr-window-smoke --mdns-smoke --live-read`.
Проверены запись/удаление тестовой записи автозапуска и скрытый старт окна.
Тестовая конфигурация Packaging использована, потому что Release exe занят
работающим агентом; его не останавливали. Сборка тестов без ошибок/предупреждений.
- Собран `dist/MusicBridge-win-x64.zip` (~65 МиБ), Release win-x64 self-contained.
`Packaging/Test-Package.ps1` проверил установку в отдельную папку без ярлыка,
запуск со встроенным Runtime, повторную установку, запрет обновления занятого
exe и удаление. Рабочий автозапуск и хранилище пользователя не менялись.
Перезагрузка Windows и реальное срабатывание автозапуска при входе ещё не проверены.
Инструкции — в `INSTALL.md`.
- Последний этап — окно управления и трей: **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. Автоизменения брандмауэра нет.
Следующий шаг: проверка с другого устройства и устойчивости при смене сети,
проверка входа Windows с автозапуском. Правила для домашнего Ethernet применены
и проверены для текущего пути Release-сборки (см. запись от 2026-09-10).
Трей, автозапуск и ZIP-упаковка реализованы. iPhone-клиент начат в отдельном репозитории.
Точные границы реализации и следующие шаги — в `CONNECTION-ROADMAP.md`.
Новая команда на разработку iOS получена 2026-09-10; следующие этапы — в его PLAN.md.
## Карта файлов
- `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-поток, значок/меню трея и жизненный цикл окна.
- `Desktop/StartupSettings.cs`: HKCU Run, экранированная команда автозапуска.
- `Packaging/`: сборка standalone ZIP, установка/удаление и изолированный smoke-тест.
- `Packaging/Firewall.ps1`: Preview/Apply/Remove правил LocalSubnet; Private по
умолчанию, Domain только с явно указанным интерфейсом домашней сети.
- `Packaging/Test-Firewall.ps1`: проверка определений правил без изменения системы.
- `INSTALL.md`: установка, автозапуск, обновление и удаление.
- `Network/LocalAddresses.cs`: подходящие домашние IPv4-адреса.
- `Network/DiscoveryDescriptor.cs`: публичные поля DNS-SD.
- `Network/MdnsPublisher.cs`: объявления mDNS, обновления адресов и goodbye.
- `tests/`: исполняемые проверки без дополнительных тестовых NuGet-пакетов.