from urllib.parse import urlparse
from aiohttp import ClientTimeout, web
-from music_assistant_models.enums import EventType, PlayerType, QueueOption, RepeatMode
+from music_assistant_models.enums import (
+ EventType,
+ PlayerFeature,
+ PlayerType,
+ QueueOption,
+ RepeatMode,
+)
from plexapi.playqueue import PlayQueue
from .gdm import PlexGDMAdvertiser
},
)
+ async def _ungroup_player_if_needed(self, player_id: str) -> None:
+ """Ungroup player before playback if it's part of a group/sync."""
+ player = self.provider.mass.players.get(player_id)
+ if not player or player.type == PlayerType.GROUP:
+ return
+
+ if not (player.synced_to or player.group_members or player.active_group):
+ return
+
+ LOGGER.debug("Ungrouping player %s before starting playback from Plex", player.display_name)
+ # Use set_members directly on the group to bypass static member check
+ if (
+ player.active_group
+ and (group := self.provider.mass.players.get(player.active_group))
+ and group.supports_feature(PlayerFeature.SET_MEMBERS)
+ ):
+ await group.set_members(player_ids_to_remove=[player_id])
+ elif (
+ player.synced_to
+ and (sync_leader := self.provider.mass.players.get(player.synced_to))
+ and sync_leader.supports_feature(PlayerFeature.SET_MEMBERS)
+ ):
+ await sync_leader.set_members(player_ids_to_remove=[player_id])
+ elif player.group_members and player.supports_feature(PlayerFeature.SET_MEMBERS):
+ await player.set_members(player_ids_to_remove=player.group_members)
+
async def handle_play_media(self, request: web.Request) -> web.Response:
"""
Handle playMedia command from Plex controller.
if not player_id:
return web.Response(status=500, text="No player assigned to this server")
+ # Ungroup player if it's part of a group/sync
+ # User selected this specific player, so remove from any groups
+ await self._ungroup_player_if_needed(player_id)
+
if container_key and "/playQueues/" in container_key:
# Extract play queue ID from container key
queue_id_match = re.search(r"/playQueues/(\d+)", container_key)
self._updating_from_plex = True
try:
if self._ma_player_id:
+ # Ungroup player before resuming playback
+ await self._ungroup_player_if_needed(self._ma_player_id)
await self.provider.mass.players.cmd_play(self._ma_player_id)
await self._broadcast_timeline()
return web.Response(status=200)