From e305fe09800af0c87fa2f37a3b0e8e5db3ca9391 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 1 Apr 2025 00:04:01 +0200 Subject: [PATCH] Fix: enqueue next item (#2089) when callling enqueue next item too early the metadata is wrong on dlna --- music_assistant/controllers/player_queues.py | 42 ++++++-------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/music_assistant/controllers/player_queues.py b/music_assistant/controllers/player_queues.py index 95f30316..b1266ec0 100644 --- a/music_assistant/controllers/player_queues.py +++ b/music_assistant/controllers/player_queues.py @@ -781,6 +781,7 @@ class PlayerQueuesController(CoreController): queue.flow_mode_stream_log = [] queue.flow_mode = await self.mass.config.get_player_config_value(queue_id, CONF_FLOW_MODE) queue.current_item = queue_item + queue.next_item_id_enqueued = None # always update session id when we start a new playback session queue.session_id = shortuuid.random(length=8) @@ -999,6 +1000,9 @@ class PlayerQueuesController(CoreController): ) queue_item.available = False idx += 1 + if idx != 0: + # we skipped some items, signal a queue items update + self.update_items(queue_id, self._queue_items[queue_id]) if next_item is None: raise QueueEmpty("No more (playable) tracks left in the queue.") @@ -1094,8 +1098,6 @@ class PlayerQueuesController(CoreController): queue.index_in_buffer = self.index_by_id(queue_id, item_id) self.logger.debug("PlayerQueue %s loaded item %s in buffer", queue.display_name, item_id) self.signal_update(queue_id) - # enqueue next track on the player - self._enqueue_next_item(queue_id, self.get_next_item(queue_id, item_id)) # preload next streamdetails self._preload_next_item(queue_id, queue.index_in_buffer) @@ -1118,7 +1120,6 @@ class PlayerQueuesController(CoreController): - keep_remaining: keep the remaining items after the insert - shuffle: (re)shuffle the items after insert index """ - queue = self._queues[queue_id] prev_items = self._queue_items[queue_id][:insert_at_index] if keep_played else [] next_items = queue_items @@ -1134,16 +1135,6 @@ class PlayerQueuesController(CoreController): next_items = random.sample(next_items, len(next_items)) self.update_items(queue_id, prev_items + next_items) - # if the next index changed we need to tell the player to enqueue the (new) next item - index_in_buffer = queue.index_in_buffer or queue.current_index or 0 - if ( - insert_at_index == (index_in_buffer + 1) - and queue.state != PlayerState.IDLE - and (next_item := self.get_next_item(queue_id, index_in_buffer)) - and queue.next_item_id_enqueued != next_item.queue_item_id - ): - self._enqueue_next_item(queue_id, next_item) - def update_items(self, queue_id: str, queue_items: list[QueueItem]) -> None: """Update the existing queue items, mostly caused by reordering.""" self._queue_items[queue_id] = queue_items @@ -1435,7 +1426,7 @@ class PlayerQueuesController(CoreController): """Return next QueueItem for given queue.""" if isinstance(cur_index, str): cur_index = self.index_by_id(queue_id, cur_index) - for _retries in range(3): + for _ in range(5): if (next_index := self._get_next_index(queue_id, cur_index)) is None: break next_item = self.get_item(queue_id, next_index) @@ -1483,10 +1474,10 @@ class PlayerQueuesController(CoreController): self._queues[queue_id].display_name, ) - # Enqueue the next item immediately once the player started - # buffering/playing an item (with a small debounce delay). task_id = f"enqueue_next_item_{queue_id}" - self.mass.call_later(0.5, _enqueue_next_item_on_player, next_item, task_id=task_id) + self.mass.create_task( + _enqueue_next_item_on_player(next_item), task_id=task_id, abort_existing=True + ) def _preload_next_item(self, queue_id: str, item_id_in_buffer: str) -> None: """ @@ -1496,23 +1487,12 @@ class PlayerQueuesController(CoreController): If caching is enabled, this will also start filling the stream cache. If an error occurs, the item will be skipped and the next item will be loaded. """ - queue = self._queues[queue_id] async def _preload_streamdetails() -> None: try: - new_next_item = await self.preload_next_queue_item(queue_id, item_id_in_buffer) + await self.preload_next_queue_item(queue_id, item_id_in_buffer) except QueueEmpty: return - if ( - queue.current_item.queue_item_id == item_id_in_buffer - and queue.next_item != new_next_item - ): - # the next item has changed, so we need to enqueue the new one - # this can happen when fetching the streamdetails failed so the - # track was skipped. - queue.next_item = new_next_item - await self._enqueue_next_item(queue_id, next_item) - return if not (current_item := self.get_item(queue_id, item_id_in_buffer)): # this should not happen, but guard anyways @@ -1786,6 +1766,10 @@ class PlayerQueuesController(CoreController): if queue.next_item and queue.next_item.streamdetails: queue.next_item.streamdetails.dsp = dsp + if queue.next_item and queue.next_item_id_enqueued != queue.next_item.queue_item_id: + # the next item has changed, so we need to enqueue the new one + self._enqueue_next_item(queue_id, queue.next_item) + queue.next_item_id_enqueued = queue.next_item.queue_item_id # handle sending a playback progress report # we do this every 30 seconds or when the state changes if ( -- 2.34.1