Merge players with multiple protocols together (#3150)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sun, 15 Feb 2026 14:50:45 +0000 (15:50 +0100)
committerGitHub <noreply@github.com>
Sun, 15 Feb 2026 14:50:45 +0000 (15:50 +0100)
commit6385ab565acee763f390057dbd38fd5c65718960
treefa0a04f8c671daa73a04ca0c7e0c34793bbc61f6
parent1eb9d0c815119907ad7f7a14025a4f18e2cf8435
Merge players with multiple protocols together (#3150)

* Base implementation of merging players through protocol linking

* Restore after merge conflict

* follow-up

* Fix config handling for players

* some tweaks

* Handle more (edge) cases

* bunch of fixes

* More fixes

* Some more tweaks

* Fix group_members calc

* A bunch of tweaks and refactoring

* more tweaks

* more follow-up

* Update controller.py

* refactoring groups

* more fixes for syncgroup

* fix readme nitpick

* revert frozen in uv run

* Add default providers conf

* fix tests

* more tweaks

* fixes for syncgroups

* More small tweaks

* more sync player tweaks
79 files changed:
music_assistant/constants.py
music_assistant/controllers/config.py
music_assistant/controllers/player_queues.py
music_assistant/controllers/players/README.md [new file with mode: 0644]
music_assistant/controllers/players/__init__.py
music_assistant/controllers/players/controller.py [new file with mode: 0644]
music_assistant/controllers/players/helpers.py [new file with mode: 0644]
music_assistant/controllers/players/player_controller.py [deleted file]
music_assistant/controllers/players/protocol_linking.py [new file with mode: 0644]
music_assistant/controllers/players/sync_groups.py [deleted file]
music_assistant/controllers/streams/streams_controller.py
music_assistant/controllers/webserver/README.md
music_assistant/helpers/audio.py
music_assistant/helpers/util.py
music_assistant/mass.py
music_assistant/models/player.py
music_assistant/models/player_provider.py
music_assistant/models/provider.py
music_assistant/providers/_demo_player_provider/player.py
music_assistant/providers/_demo_player_provider/provider.py
music_assistant/providers/airplay/helpers.py
music_assistant/providers/airplay/player.py
music_assistant/providers/airplay/protocols/raop.py
music_assistant/providers/airplay/provider.py
music_assistant/providers/airplay/stream_session.py
music_assistant/providers/airplay_receiver/__init__.py
music_assistant/providers/alexa/__init__.py
music_assistant/providers/bluesound/const.py
music_assistant/providers/bluesound/player.py
music_assistant/providers/bluesound/provider.py
music_assistant/providers/chromecast/helpers.py
music_assistant/providers/chromecast/player.py
music_assistant/providers/chromecast/provider.py
music_assistant/providers/dlna/manifest.json
music_assistant/providers/dlna/player.py
music_assistant/providers/dlna/provider.py
music_assistant/providers/fully_kiosk/player.py
music_assistant/providers/hass_players/player.py
music_assistant/providers/hass_players/provider.py
music_assistant/providers/heos/player.py
music_assistant/providers/heos/provider.py
music_assistant/providers/musiccast/player.py
music_assistant/providers/musiccast/provider.py
music_assistant/providers/plex_connect/__init__.py
music_assistant/providers/plex_connect/player_remote.py
music_assistant/providers/roku_media_assistant/player.py
music_assistant/providers/roku_media_assistant/provider.py
music_assistant/providers/sendspin/player.py
music_assistant/providers/snapcast/player.py
music_assistant/providers/snapcast/provider.py
music_assistant/providers/sonos/const.py
music_assistant/providers/sonos/player.py
music_assistant/providers/sonos/provider.py
music_assistant/providers/sonos_s1/constants.py
music_assistant/providers/sonos_s1/player.py
music_assistant/providers/sonos_s1/provider.py
music_assistant/providers/spotify_connect/ARCHITECTURE.md
music_assistant/providers/spotify_connect/__init__.py
music_assistant/providers/squeezelite/player.py
music_assistant/providers/squeezelite/provider.py
music_assistant/providers/sync_group/__init__.py [new file with mode: 0644]
music_assistant/providers/sync_group/constants.py [new file with mode: 0644]
music_assistant/providers/sync_group/icon.svg [new file with mode: 0644]
music_assistant/providers/sync_group/icon_monochrome.svg [new file with mode: 0644]
music_assistant/providers/sync_group/manifest.json [new file with mode: 0644]
music_assistant/providers/sync_group/player.py [new file with mode: 0644]
music_assistant/providers/sync_group/provider.py [new file with mode: 0644]
music_assistant/providers/universal_group/player.py
music_assistant/providers/universal_player/README.md [new file with mode: 0644]
music_assistant/providers/universal_player/__init__.py [new file with mode: 0644]
music_assistant/providers/universal_player/constants.py [new file with mode: 0644]
music_assistant/providers/universal_player/manifest.json [new file with mode: 0644]
music_assistant/providers/universal_player/player.py [new file with mode: 0644]
music_assistant/providers/universal_player/provider.py [new file with mode: 0644]
pyproject.toml
tests/common.py
tests/core/test_player_controller.py [new file with mode: 0644]
tests/core/test_player_grouping.py [new file with mode: 0644]
tests/core/test_protocol_linking.py [new file with mode: 0644]