From: Marcel van der Veldt Date: Sun, 22 Feb 2026 14:17:53 +0000 (+0100) Subject: Auto ungroup when trying to form syncgroup with already synced player X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=14acde7aa9a3d3fe652a9b1866ec51c216bfa57c;p=music-assistant-server.git Auto ungroup when trying to form syncgroup with already synced player --- diff --git a/music_assistant/controllers/players/controller.py b/music_assistant/controllers/players/controller.py index 476e16b8..2056915d 100644 --- a/music_assistant/controllers/players/controller.py +++ b/music_assistant/controllers/players/controller.py @@ -1026,12 +1026,9 @@ class PlayerController(ProtocolLinkingMixin, CoreController): msg = f"Player {parent_player.name} does not support group commands" raise UnsupportedFeaturedException(msg) - # guard edge case: player already synced to another player - if parent_player.state.synced_to: - raise PlayerCommandFailed( - f"Player {parent_player.name} is already synced to another player on its own, " - "you need to ungroup it first before you can join other players to it.", - ) + # handle edge case: player already synced to another player + # automatically ungroup it first and wait for state to propagate + await self._auto_ungroup_if_synced(parent_player, "setting members") # handle dissolve sync group if the target player is currently # a sync leader and is being removed from itself should_stop = False @@ -1076,6 +1073,11 @@ class PlayerController(ProtocolLinkingMixin, CoreController): ): continue # already synced to this target + # handle edge case: child player is synced to a different player + # automatically ungroup it first and wait for state to propagate + if child_player.state.synced_to and child_player.state.synced_to != target_player: + await self._auto_ungroup_if_synced(child_player, f"joining {parent_player.name}") + # power on the player if needed if ( not child_player.state.powered @@ -2390,6 +2392,24 @@ class PlayerController(ProtocolLinkingMixin, CoreController): task_id = "update_all_players_on_registration" self.mass.call_later(delay, _update_all_players, task_id=task_id) + async def _auto_ungroup_if_synced(self, player: Player, log_context: str) -> None: + """ + Automatically ungroup a player if it's synced to another player. + + :param player: The player to check and potentially ungroup. + :param log_context: Additional context for the log message (e.g., target player name). + """ + if not player.state.synced_to: + return + self.logger.info( + "Player %s is already synced to %s, ungrouping it first before %s", + player.name, + player.state.synced_to, + log_context, + ) + await self.cmd_set_members(player.state.synced_to, player_ids_to_remove=[player.player_id]) + await asyncio.sleep(2) + async def _handle_set_members_with_protocols( self, parent_player: Player,