feat: Add MSX Bridge Player Provider#3123
feat: Add MSX Bridge Player Provider#3123trudenboy wants to merge 62 commits intomusic-assistant:devfrom
Conversation
🔒 Dependency Security Report✅ No dependency changes detected in this PR. |
03aa67a to
bdc1dac
Compare
|
Ensure you run pre-commit before pushing any commits. |
3ec7d87 to
5dbb940
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
…ayback For flow_mode (multi-track queue), Content-Length was set to the first track's size. MSX player closed after receiving that many bytes, so the next track never started. Now we omit Content-Length for flow streams so the client keeps the connection open across tracks. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
7b15d21 to
0a098e9
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 6 new configuration options for Yandex Music provider: - My Wave maximum tracks (default: 150) - Control total number of tracks fetched - My Wave batch count (default: 3) - Number of API calls for initial load - Track details batch size (default: 50) - Batch size for track detail requests - Discovery initial tracks (default: 5) - Initial display limit for Discover - Browse initial tracks (default: 15) - Initial display limit for Browse - Enable Discover (default: true) - Toggle recommendations on/off Implemented duplicate protection for My Wave tracks using set-based tracking. Recommendations now refresh every 60 seconds instead of 3 hours for fresher discoveries. All new settings have sensible defaults that maintain current behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ck streaming Replace flow-mode streaming with MSX native playlists: tracks now use playlist:auto: actions that load /msx/playlist/ endpoints, enabling MSX to manage sequential playback natively while each track streams individually via force_flow_mode=False. Add .mp3 extension routes for TV compatibility, next/prev actions in WS push, and from_playlist flag to suppress duplicate WS notifications. Remove flow-mode poll logic, extract Pydantic models and mappers into dedicated modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0120c04 to
6fbcf2d
Compare
* feat: Add MSX Bridge Player Provider Co-authored-by: Cursor <cursoragent@cursor.com> * fix(msx_bridge): omit Content-Length for flow streams to fix queue playback For flow_mode (multi-track queue), Content-Length was set to the first track's size. MSX player closed after receiving that many bytes, so the next track never started. Now we omit Content-Length for flow streams so the client keeps the connection open across tracks. Co-authored-by: Cursor <cursoragent@cursor.com> * style(msx_bridge): fix Ruff TC006 runtime-cast-value Co-authored-by: Cursor <cursoragent@cursor.com> * test(msx_bridge): cover play_update websocket and flow track metadata Co-authored-by: Cursor <cursoragent@cursor.com> * ⬆️ Update music-assistant-frontend to 2.17.84 (music-assistant#3135) Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com> * feat(msx_bridge): switch to MSX native playlist playback with per-track streaming Replace flow-mode streaming with MSX native playlists: tracks now use playlist:auto: actions that load /msx/playlist/ endpoints, enabling MSX to manage sequential playback natively while each track streams individually via force_flow_mode=False. Add .mp3 extension routes for TV compatibility, next/prev actions in WS push, and from_playlist flag to suppress duplicate WS notifications. Remove flow-mode poll logic, extract Pydantic models and mappers into dedicated modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(tests): correct import path in test_models.py for CI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Михаил Невский <renso@MacBook-Pro-Mihail.local> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: music-assistant-machine <141749843+music-assistant-machine@users.noreply.github.com> Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…cursion guard, and mypy fixes - Add enable_player_grouping config option (default: true) to disable grouping entirely — removes SET_MEMBERS/SYNC_PLAYERS features - Add recursion guard (_propagating flag) in _propagate_to_group_members - Simplify _get_group_member_ids: use self.group_members directly - Skip propagation when grouping_enabled=False at provider level - Resolve all mypy errors in test files (type: ignore annotations) - Add 7 new tests for disable, recursion guard, and feature flags
32e6af0 to
af59778
Compare
Restore yandex_music provider files to upstream/dev state. These changes were accidentally included in the MSX Bridge PR.
There was a problem hiding this comment.
Pull request overview
Adds a new MSX Bridge player provider to Music Assistant, enabling Smart TV playback via the Media Station X (MSX) app (HTTP content endpoints + WebSocket control), along with a bundled web UI and a comprehensive test suite.
Changes:
- Introduce the MSX Bridge provider/player implementation, including grouping/shared-stream scaffolding and MSX content models/mappers.
- Add MSX/TV plugin + web client static assets for browsing/playback and device identification.
- Add extensive unit tests covering provider lifecycle, player behavior (queue/playlist sync, grouping), mappers/models, and HTTP server routes.
Reviewed changes
Copilot reviewed 22 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/providers/msx_bridge/init.py | Marks the MSX Bridge test package. |
| tests/providers/msx_bridge/conftest.py | Adds fixtures for provider/player/http client testing. |
| tests/providers/msx_bridge/test_http_server.py | Tests HTTP routes, MSX content endpoints, and WS inbound handling. |
| tests/providers/msx_bridge/test_init.py | Tests provider setup and config entry behavior/feature flags. |
| tests/providers/msx_bridge/test_mappers.py | Tests mapping MA media items to MSX items/actions. |
| tests/providers/msx_bridge/test_models.py | Tests Pydantic model alias serialization. |
| tests/providers/msx_bridge/test_player.py | Tests MSXPlayer playback, queue playlist sync, grouping propagation, and position reporting. |
| tests/providers/msx_bridge/test_playlist.py | Tests queue/track list → MSX playlist content mapping. |
| tests/providers/msx_bridge/test_provider.py | Tests provider lifecycle methods and player enable/disable behavior. |
| music_assistant/providers/msx_bridge/init.py | Provider entry point: setup + config entries (including grouping/stream mode). |
| music_assistant/providers/msx_bridge/constants.py | Adds provider constants and config keys/defaults. |
| music_assistant/providers/msx_bridge/icon.svg | Adds provider icon asset. |
| music_assistant/providers/msx_bridge/icon_monochrome.svg | Adds monochrome provider icon asset. |
| music_assistant/providers/msx_bridge/manifest.json | Registers the provider manifest metadata. |
| music_assistant/providers/msx_bridge/mappers.py | Implements mapping helpers for MSX content pages/items and playlist audio actions. |
| music_assistant/providers/msx_bridge/models.py | Adds Pydantic models for MSX JSON content structures. |
| music_assistant/providers/msx_bridge/player.py | Implements MSXPlayer with WS sync, queue playlist behavior, and grouping propagation. |
| music_assistant/providers/msx_bridge/provider.py | Implements provider lifecycle, player registration/timeout, stop/pause/resume notifications, and shared-group stream manager. |
| music_assistant/providers/msx_bridge/static/input.html | Adds MSX input plugin HTML wrapper. |
| music_assistant/providers/msx_bridge/static/input.js | Adds vendored MSX input interaction plugin JS. |
| music_assistant/providers/msx_bridge/static/plugin.html | Adds MSX InteractionPlugin bridge (menu + WS control + device ID). |
| music_assistant/providers/msx_bridge/static/web/index.html | Adds browser-based MSX UI shell (normal + kiosk modes). |
| music_assistant/providers/msx_bridge/static/web/web.js | Adds browser-based MSX UI logic + WS sync + optional Sendspin kiosk integration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ation, remove dead code (#50) * Initial plan * Port changes from trudenboy/msx-music-assistant#2 to msx_bridge provider Co-authored-by: trudenboy <139659391+trudenboy@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: trudenboy <139659391+trudenboy@users.noreply.github.com>
…types
Resync provider.py and constants.py from local project to fix CI errors:
- Restore is_redirect_stream_mode() and get_ma_stream_url() methods
- Use cast("int", ...) instead of int(raw_value) for MA config convention
- Restore GROUP_STREAM_MODE_REDIRECT constant import
- Fix mypy errors: redundant cast, unused type-ignore, unreachable code
- Fix WebserverController attribute access (use base_url property)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 26 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…dio URLs - Remove hardcoded .mp3 extension from audio URLs in mappers (use extensionless) - Fix XSS in web player msxIcon() by escaping user-controlled icon names - Add server-side handler for debug_info WebSocket messages (was logging unknown) - Document redirect stream mode as scaffold for future MA Streamserver integration - Remove unused type: ignore comments for get_player() (valid in PR context) - Update test assertion to match extensionless audio URLs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…am-prs Incorporates PR music-assistant#3123 review fixes: - Remove hardcoded .mp3 from audio URLs (mappers.py) - Add debug_info WS message handler (http_server.py) - XSS fix: escape icon names in msxIcon() (web.js) - Restore redirect mode scaffold methods with clear docstrings (provider.py) - Keep GROUP_STREAM_MODE_REDIRECT constant active for http_server.py references Conflict resolution: integration branch removed redirect dead code, but http_server.py still references is_redirect_stream_mode() and get_ma_stream_url(). Kept both methods with docstrings documenting them as future scaffolds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ler compat PlayerController exposes get() not get_player(). Fixed in provider.py and http_server.py (7 call sites). Also removed .mp3 extension from audio action URLs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…trudenboy/ma-server into feat/msx-bridge-player-provider
…iding controls - Full-bleed background image with blur/scale/vignette overlay - Always-visible track info overlay (top-left, fades in on play) - Auto-hiding frosted-glass controls panel (slide-down after 3.5s idle) - Cursor hidden in idle, shown on interaction - Idle state with music note icon when nothing is playing - resetKioskHideTimer() / cancelKioskHideTimer() / setKioskPlaying() helpers - mousemove, touchstart, click listeners trigger controls reveal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 26 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… get_player compat - feat(web): karaoke lyrics overlay in kiosk mode - fix(msx_bridge): use get_player() for PlayerController compat - fix(web): lyrics display, autoplay, and player protocol issues - fix(web): bypass autoplay restriction via muted-then-unmute trick Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sync with msx-music-assistant main: queue API endpoint, two-column full player (art+controls | queue), three-column kiosk layout (art | lyrics/equalizer | queue), CSS equalizer animation, and responsive breakpoints. Also fix linting: split _setup_routes, remove unused type: ignore comments, add Track type guard for lyrics. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…anup - Lock buffer snapshot in SharedGroupStream.subscribe() to prevent deque mutation race - Wrap _skip_ws_notify in try/finally to ensure flag reset on error - Apply esc() in msxIcon() to prevent XSS - Remove hardcoded .mp3 extension in WS play handlers (web.js, plugin.html) - Remove redundant list() wrapping in player.py - Add license header to input.js - Fix misleading comment in test_provider.py - Add queue API tests (test_http_server.py) - Split _setup_routes() into _setup_msx_routes() and _setup_api_routes() - Remove unused type: ignore comments (mypy cleanup) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 26 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
New Player Provider that streams Music Assistant to Smart TVs via the Media Station X (MSX) app. Runs an embedded HTTP server (default port 8099) inside the MA process — no external containers or services required.
Architecture
Provider Files
__init__.pysetup(),get_config_entries(), feature flagsprovider.pyMSXBridgeProvider(PlayerProvider): lifecycle, player registry, idle timeout, WS push,SharedGroupStreamplayer.pyMSXPlayer(Player): play/pause/stop/resume, position reporting, queue sync, echo preventionhttp_server.pyMSXHTTPServer: aiohttp server, 50 routes, WebSocket handler, audio streaming, CORSmappers.pymodels.pyMSXContentPage,MSXContentItem)constants.pymanifest.jsonstatic/plugin.htmlstatic/input.html/jsstatic/web/HTTP Endpoints
MSX Bootstrap & Navigation:
//msx/start.json/msx/plugin.html/msx/menu.json/msx/albums.json/msx/artists.json/msx/playlists.json/msx/tracks.json/msx/recently-played.json/msx/search-page.json/msx/search-input.json/msx/search.jsonMSX Detail Pages:
/msx/albums/{id}/tracks.json/msx/artists/{id}/albums.json/msx/playlists/{id}/tracks.jsonMSX Native Playlists (per-track streaming):
/msx/queue-playlist/{player_id}.json/msx/playlist/album/{id}.json/msx/playlist/playlist/{id}.json/msx/playlist/tracks.json/msx/playlist/recently-played.json/msx/playlist/search.jsonAudio Streaming:
/msx/audio/{player_id}/stream/{player_id}Library REST API:
/api/albums,/api/artists,/api/playlists,/api/tracks/api/albums/{id}/tracks,/api/artists/{id}/albums,/api/playlists/{id}/tracks/api/search,/api/recently-played/api/lyrics/{id}/api/queue/{id}/api/play/api/pause/{id},/api/stop/{id},/api/next/{id},/api/previous/{id}/api/quick-stop/{id}Other:
/health/ws/webWebSocket Protocol
Server → Client (MA → MSX):
playpath,title,artist,image_url,durationplaylisturlgoto_indexindexpauseresumestopshowNotificationClient → Server (MSX → MA):
positionposition(seconds)pausepositionresumedebug_infodata(device capabilities)Features
Dynamic Player Registration
msx_<device_id>)_pending_unregisterseventson_player_disabledoverride: keeps player registered (no re-discovery needed on enable)Native Playlist Playback
playlistmessage/msx/audio/— no flow modegoto_indexfor MA-initiated track changesBidirectional Sync
broadcast_pause/broadcast_resumenotifications_skip_ws_notifyflag prevents notification loops (wrapped intry/finally)update_position()prefers WebSocket data over wall-clock pollingAudio Streaming Pipeline
duration × bytes_per_secfor MSX progress barPlayer Grouping (Experimental)
enable_player_groupingconfig toggle (default: true)SharedGroupStream: one ffmpeg process, multiple TV readers via shared bufferBrowser Web Player
/web— full-featured player without MSX app/web?kiosk=1): immersive full-screen album art with auto-hiding controlsConfiguration
http_port8099output_formatmp3player_idle_timeout30show_stop_notificationfalseabort_stream_firstfalseenable_player_groupingtruegroup_stream_modeindependentTesting
121 unit tests (120 passed + 1 skipped):
test_http_server.pytest_player.pytest_provider.pytest_init.pytest_playlist.pytest_models.pytest_mappers.pyPre-commit: ruff ✅, mypy ✅
Screenshots
Links
🤖 Generated with Claude Code