From 76dd42ee34d079cd9e4a7d0999de1fd930d25dfe Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 20 Feb 2024 01:33:43 +0100 Subject: [PATCH] Fixes for the Active source being wrong in some cases (#1099) --- music_assistant/server/controllers/players.py | 14 ++++++++++---- .../server/providers/airplay/__init__.py | 11 +---------- .../server/providers/chromecast/__init__.py | 6 ++++-- .../server/providers/chromecast/helpers.py | 2 +- music_assistant/server/providers/dlna/__init__.py | 2 +- music_assistant/server/providers/sonos/player.py | 2 +- .../server/providers/spotify/__init__.py | 4 ++-- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/music_assistant/server/controllers/players.py b/music_assistant/server/controllers/players.py index 9608742f..f6f580d6 100644 --- a/music_assistant/server/controllers/players.py +++ b/music_assistant/server/controllers/players.py @@ -238,7 +238,7 @@ class PlayerController(CoreController): if player_id not in self._players: return player = self._players[player_id] - # calculate active_source + # calculate active_source (if needed) player.active_source = self._get_active_source(player) # calculate group volume player.group_volume = self._get_group_volume_level(player) @@ -534,6 +534,7 @@ class PlayerController(CoreController): elif member.active_source == group_player.player_id: # turn off child player when group turns off tg.create_task(self.cmd_power(member.player_id, False)) + member.active_source = None # edge case: group turned on but no members are powered, power them all! if not members_powered and power: for member in self.iter_group_members(group_player, only_powered=False): @@ -789,9 +790,14 @@ class PlayerController(CoreController): """Return the active_source id for given player.""" # if player is synced, return group leader's active source if player.synced_to and (parent_player := self.get(player.synced_to)): - return parent_player.player_id - if active_player_group := self._get_active_player_group(player): - return active_player_group.player_id + return parent_player.active_source + # fallback to the first active group player + if player.powered: + for group_player in self._get_player_groups( + player, available_only=True, powered_only=True + ): + if group_player.state in (PlayerState.PLAYING, PlayerState.PAUSED): + return group_player.active_source # defaults to the player's own player id if not active source set return player.active_source or player.player_id diff --git a/music_assistant/server/providers/airplay/__init__.py b/music_assistant/server/providers/airplay/__init__.py index 1e652c51..23dedfc0 100644 --- a/music_assistant/server/providers/airplay/__init__.py +++ b/music_assistant/server/providers/airplay/__init__.py @@ -177,7 +177,6 @@ class AirPlayPlayer(DeviceListener): self.connected = False self._connection_attempts = 0 self._connection_was_lost = False - self._task = None self._playing: interface.Playing | None = None self.logger = self.mass.players.logger.getChild("airplay").getChild(self.player_id) self.cliraop_proc: AsyncProcess | None = None @@ -229,9 +228,6 @@ class AirPlayPlayer(DeviceListener): if self.atv: self.atv.close() self.atv = None - if self._task: - self._task.cancel() - self._task = None except Exception: # pylint: disable=broad-except self.logger.exception("An error occurred while disconnecting") @@ -416,11 +412,6 @@ class AirPlayPlayer(DeviceListener): mass_player.state = PlayerState.IDLE self.mass.players.update(self.player_id) - @property - def is_connecting(self): - """Return true if connection is in progress.""" - return self._task is not None - def address_updated(self, address): """Update cached address in config entry.""" self.logger.debug("Changing address to %s", address) @@ -974,7 +965,7 @@ class AirplayProvider(PlayerProvider): ): extra_args += ["-u"] if self.mass.config.get_raw_player_config_value( - atv_player.player_id, CONF_ALAC_ENCODE, False + atv_player.player_id, CONF_ALAC_ENCODE, True ): extra_args += ["-a"] if self.mass.config.get_raw_player_config_value( diff --git a/music_assistant/server/providers/chromecast/__init__.py b/music_assistant/server/providers/chromecast/__init__.py index e4cdbc55..9cfebcd7 100644 --- a/music_assistant/server/providers/chromecast/__init__.py +++ b/music_assistant/server/providers/chromecast/__init__.py @@ -527,8 +527,10 @@ class ChromecastProvider(PlayerProvider): # active source if ( - status.content_id and castplayer.player_id in status.content_id - ) or castplayer.cc.app_id == pychromecast.config.APP_MEDIA_RECEIVER: + status.content_id + and self.mass.streams.base_url in status.content_id + and castplayer.player_id in status.content_id + ): castplayer.player.active_source = castplayer.player_id else: castplayer.player.active_source = castplayer.cc.app_display_name diff --git a/music_assistant/server/providers/chromecast/helpers.py b/music_assistant/server/providers/chromecast/helpers.py index 114a3383..d49a38a6 100644 --- a/music_assistant/server/providers/chromecast/helpers.py +++ b/music_assistant/server/providers/chromecast/helpers.py @@ -177,7 +177,7 @@ class CastStatusListener: if not self._valid: return if group_uuid == self.castplayer.player.active_source: - self.castplayer.player.active_source = "" + self.castplayer.player.active_source = None self.prov.logger.debug( "%s is removed from multizone: %s", self.castplayer.player.display_name, group_uuid ) diff --git a/music_assistant/server/providers/dlna/__init__.py b/music_assistant/server/providers/dlna/__init__.py index 83924d9b..d13ed181 100644 --- a/music_assistant/server/providers/dlna/__init__.py +++ b/music_assistant/server/providers/dlna/__init__.py @@ -251,7 +251,7 @@ class DLNAPlayer: return PlayerState.IDLE @staticmethod - def get_supported_features(device: DmrDevice) -> set(PlayerFeature): + def get_supported_features(device: DmrDevice) -> set[PlayerFeature]: """Get player features that are supported at this moment. Supported features may change as the device enters different states. diff --git a/music_assistant/server/providers/sonos/player.py b/music_assistant/server/providers/sonos/player.py index bba358c9..ec542e25 100644 --- a/music_assistant/server/providers/sonos/player.py +++ b/music_assistant/server/providers/sonos/player.py @@ -710,7 +710,7 @@ class SonosPlayer: # media info (track info) self.mass_player.current_item_id = self.uri - if self.uri and self.player_id in self.uri: + if self.uri and self.mass.streams.base_url in self.uri and self.player_id in self.uri: self.mass_player.active_source = self.player_id else: self.mass_player.active_source = self.source_name diff --git a/music_assistant/server/providers/spotify/__init__.py b/music_assistant/server/providers/spotify/__init__.py index 593c2948..5e5cd8ac 100644 --- a/music_assistant/server/providers/spotify/__init__.py +++ b/music_assistant/server/providers/spotify/__init__.py @@ -122,7 +122,7 @@ class SpotifyProvider(MusicProvider): async def handle_async_init(self) -> None: """Handle async initialization of the provider.""" - self._throttler = Throttler(rate_limit=1, period=0.1) + self._throttler = Throttler(rate_limit=1, period=1) self._cache_dir = CACHE_DIR self._ap_workaround = False # try to get a token, raise if that fails @@ -742,7 +742,7 @@ class SpotifyProvider(MusicProvider): async with self.mass.http_session.get( url, headers=headers, params=kwargs, ssl=False, timeout=120 ) as response: - # get text before json so we can log the body in case of errorrs + # get text before json so we can log the body in case of errors result = await response.text() result = json_loads(result) if "error" in result or ("status" in result and "error" in result["status"]): -- 2.34.1