Fix queue repeat issues (#349)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 31 May 2022 09:45:13 +0000 (11:45 +0200)
committerGitHub <noreply@github.com>
Tue, 31 May 2022 09:45:13 +0000 (11:45 +0200)
* clear current item when playback stopped (and repeat off)

* restart queue from beginning when repeat enabled

music_assistant/models/player_queue.py

index 24181b87be6d0f47879917dbf41ee60166a211ea..471837bf95456db72aa63526f6a9800b5719c4fd 100644 (file)
@@ -351,9 +351,11 @@ class PlayerQueue:
 
         Returns None if queue is empty or no more items.
         """
-        if next_index := self.get_next_index(self._current_index):
+        try:
+            next_index = self.get_next_index(self._current_index)
             return self._items[next_index]
-        return None
+        except IndexError:
+            return None
 
     def get_item(self, index: int) -> QueueItem | None:
         """Get queue item by index."""
@@ -660,10 +662,19 @@ class PlayerQueue:
             self._last_state = self.player.state
             # always signal update if playback state changed
             self.signal_update()
-            # handle case where stream stopped on purpose and we need to restart it
-            if self.player.state != PlayerState.PLAYING and self._signal_next:
-                self._signal_next = False
-                self.mass.create_task(self.resume())
+            if self.player.state != PlayerState.PLAYING:
+                # handle end of queue
+                if self._current_index >= (len(self._items) - 1):
+                    self._current_index += 1
+                    self._current_item_elapsed_time = 0
+                    # repeat enabled (of whole queue), play queue from beginning
+                    if self.settings.repeat_mode == RepeatMode.ALL:
+                        self.mass.create_task(self.play_index(0))
+
+                # handle case where stream stopped on purpose and we need to restart it
+                elif self._signal_next:
+                    self._signal_next = False
+                    self.mass.create_task(self.resume())
 
             # start poll/updater task if playback starts on player
             async def updater() -> None:
@@ -688,7 +699,6 @@ class PlayerQueue:
         new_index = self._current_index
         track_time = self._current_item_elapsed_time
         new_item_loaded = False
-        # if self.player.state == PlayerState.PLAYING:
         if self.player.state == PlayerState.PLAYING and self.player.elapsed_time > 0:
             new_index, track_time = self.__get_queue_stream_index()
         # process new index
@@ -753,19 +763,15 @@ class PlayerQueue:
         self._next_start_index = self.get_next_index(self._next_start_index)
         return next_idx
 
-    def get_next_index(self, index: int) -> int | None:
-        """Return the next index or None if no more items."""
-        if not self._items or index is None:
-            # queue is empty
-            return None
+    def get_next_index(self, cur_index: int) -> int:
+        """Return the next index for the queue, accounting for repeat settings."""
+        if not self._items or cur_index is None:
+            raise IndexError("No (more) items in queue")
         if self.settings.repeat_mode == RepeatMode.ONE:
-            return index
-        if len(self._items) > (index + 1):
-            return index + 1
-        if self.settings.repeat_mode == RepeatMode.ALL:
-            # repeat enabled, start queue at beginning
-            return 0
-        return None
+            return cur_index
+        # simply return the next index. other logic is guarded to detect the index
+        # being higher than the number of items to detect end of queue and/or handle repeat.
+        return cur_index + 1
 
     async def queue_stream_signal_next(self):
         """Indicate that queue stream needs to start next index once playback finished."""