diff --git a/music_assistant/server/providers/chromecast/__init__.py b/music_assistant/server/providers/chromecast/__init__.py index daa3f57b9..8cabdabe2 100644 --- a/music_assistant/server/providers/chromecast/__init__.py +++ b/music_assistant/server/providers/chromecast/__init__.py @@ -105,6 +105,7 @@ class CastPlayer: mz_controller: MultizoneController | None = None next_url: str | None = None active_group: str | None = None + current_queue_item_id: str | None = None class ChromecastProvider(PlayerProvider): @@ -425,6 +426,7 @@ def on_new_media_status(self, castplayer: CastPlayer, status: MediaStatus): """Handle updated MediaStatus.""" castplayer.logger.debug("Received media status update: %s", status.player_state) # player state + prev_state = castplayer.player.state if status.player_is_playing: castplayer.player.state = PlayerState.PLAYING elif status.player_is_paused: @@ -443,15 +445,26 @@ def on_new_media_status(self, castplayer: CastPlayer, status: MediaStatus): castplayer.player.current_url = status.content_id self.mass.loop.call_soon_threadsafe(self.mass.players.update, castplayer.player_id) - # enqueue next item if needed - if ( + # enqueue next item if player is almost at the end of the track + if ( # noqa: SIM114 castplayer.player.state == PlayerState.PLAYING and castplayer.player.active_source == castplayer.player.player_id - and castplayer.next_url in (None, castplayer.player.current_url) + and (queue := self.mass.player_queues.get(castplayer.player_id)) + and (current_item := queue.current_item) + and current_item.duration + and (current_item.duration - castplayer.player.elapsed_time) <= 10 + ): + asyncio.run_coroutine_threadsafe(self._enqueue_next_track(castplayer), self.mass.loop) + # failsafe enqueue next item if player stopped at the end of the track + elif ( + castplayer.player.state == PlayerState.IDLE + and prev_state == PlayerState.PLAYING + and castplayer.player.active_source == castplayer.player.player_id + and castplayer.player.current_url == castplayer.next_url ): asyncio.run_coroutine_threadsafe(self._enqueue_next_track(castplayer), self.mass.loop) # handle end of MA queue - set current item to None - if ( + elif ( castplayer.player.state == PlayerState.IDLE and castplayer.player.current_url and (queue := self.mass.player_queues.get(castplayer.player_id)) @@ -495,7 +508,7 @@ async def _enqueue_next_track(self, castplayer: CastPlayer) -> None: """Enqueue the next track of the MA queue on the CC queue.""" try: next_url, next_item, _ = await self.mass.player_queues.preload_next_url( - castplayer.player_id + castplayer.player_id, castplayer.current_queue_item_id ) except QueueEmpty: return @@ -503,6 +516,7 @@ async def _enqueue_next_track(self, castplayer: CastPlayer) -> None: if castplayer.next_url == next_url: return # already set ?! castplayer.next_url = next_url + castplayer.current_queue_item_id = next_item.queue_item_id # in flow/direct url mode, we just send the url and the metadata is of no use if not next_item: