# 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-пакетов.