fixes for queue streams and players
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 13 Feb 2021 11:44:38 +0000 (12:44 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 13 Feb 2021 11:44:38 +0000 (12:44 +0100)
music_assistant/constants.py
music_assistant/helpers/compare.py
music_assistant/managers/players.py
music_assistant/managers/streams.py
music_assistant/models/player_queue.py
music_assistant/providers/chromecast/__init__.py
music_assistant/providers/chromecast/player.py

index 186735fddf3b5f0f70caa7d2b45087f334eec3af..93738cea86e08b45dc6d735f582bdce9b60b3db6 100755 (executable)
@@ -1,6 +1,6 @@
 """All constants for Music Assistant."""
 
-__version__ = "0.0.83"
+__version__ = "0.0.84"
 REQUIRED_PYTHON_VER = "3.7"
 
 # configuration keys/attributes
index 1e357437febc9e7edc6da6e0ad76d2586309e061..098fe70424f35cd137790f43a2079e7728adc94e 100644 (file)
@@ -64,7 +64,7 @@ def compare_album(left_album: Album, right_album: Album):
     ):
         return True
     if left_album.upc and right_album.upc:
-        if left_album.upc in right_album.upc or right_album.upc in left_album.upc:
+        if (left_album.upc in right_album.upc) or (right_album.upc in left_album.upc):
             # UPC is always 100% accurate match
             return True
     if not compare_strings(left_album.name, right_album.name):
index bc6a745659f3ff8897a644c76d746ec69b69b9fe..a8ba716499ca421616758da84e50f64306c8b49a 100755 (executable)
@@ -149,15 +149,14 @@ class PlayerManager:
 
     async def async_add_player(self, player: Player) -> None:
         """Register a new player or update an existing one."""
-        if not player or not player.available or self.mass.exit:
+        # guard for invalid data or exit in progress
+        if not player or self.mass.exit:
             return
+        # redirect to update if player already exists
         if player.player_id in self._player_states:
             return await self.async_update_player(player)
-        player_enabled = self.mass.config.get_player_config(player.player_id)[
-            CONF_ENABLED
-        ]
-        if not player_enabled:
-            # do not add the player to states if it's disabled/unavailable
+        # do not add the player to states if it's disabled/unavailable
+        if not self.mass.config.get_player_config(player.player_id)[CONF_ENABLED]:
             return
         # set the mass object on the player and call on_add function
         player.mass = self.mass
index df649df6dc3121caf29d060d99f6d3336e1a686c..a0c810daf51f2473b6659b3274db8bc3b27a3d09 100755 (executable)
@@ -152,17 +152,17 @@ class StreamManager:
 
         LOGGER.info("Start Queue Stream for player %s ", player_id)
 
-        is_start = True
         last_fadeout_data = b""
+        queue_index = None
         while True:
 
             # get the (next) track in queue
-            if is_start:
+            if queue_index is None:
                 # report start of queue playback so we can calculate current track/duration etc.
-                queue_track = await player_queue.async_start_queue_stream()
-                is_start = False
+                queue_index = await player_queue.async_queue_stream_start()
             else:
-                queue_track = player_queue.next_item
+                queue_index = await player_queue.async_queue_stream_next(queue_index)
+            queue_track = player_queue.get_item(queue_index)
             if not queue_track:
                 LOGGER.info("no (more) tracks left in queue")
                 break
index bcc916de4ff1f671a236f00cdaac6f1a09368653..c6015fc3f0ee696f44ad441c239b07edf2ce2e4e 100755 (executable)
@@ -72,8 +72,8 @@ class PlayerQueue:
         self._cur_index = 0
         self._cur_item_time = 0
         self._last_item = None
-        self._next_queue_startindex = 0
-        self._last_queue_startindex = 0
+        self._queue_stream_start_index = 0
+        self._queue_stream_next_index = 0
         self._last_player_state = PlaybackState.Stopped
         # load previous queue settings from disk
         self.mass.add_job(self.__async_restore_saved_state())
@@ -315,8 +315,9 @@ class PlayerQueue:
             index = self.__index_by_id(index)
         if not len(self.items) > index:
             return
+        self._cur_index = index
+        self._queue_stream_next_index = index
         if self.use_queue_stream:
-            self._next_queue_startindex = index
             queue_stream_uri = self.get_stream_url()
             return await self.player.async_cmd_play_uri(queue_stream_uri)
         if self.supports_queue:
@@ -502,7 +503,6 @@ class PlayerQueue:
         # process new index
         if self._cur_index != new_index:
             # queue track updated
-            self._next_queue_startindex = self.next_index
             self._cur_index = new_index
         # check if a new track is loaded, wait for the streamdetails
         if (
@@ -524,11 +524,22 @@ class PlayerQueue:
                 {"queue_id": self.queue_id, "cur_item_time": track_time},
             )
 
-    async def async_start_queue_stream(self) -> None:
+    async def async_queue_stream_start(self) -> None:
         """Call when queue_streamer starts playing the queue stream."""
-        self._last_queue_startindex = self._next_queue_startindex
         self._cur_item_time = 0
-        return self.get_item(self._next_queue_startindex)
+        self._cur_index = self._queue_stream_next_index
+        return self._queue_stream_next_index
+
+    async def async_queue_stream_next(self, cur_index: int) -> None:
+        """Call when queue_streamer loads next track in buffer."""
+        next_index = 0
+        if len(self.items) > (next_index):
+            next_index = cur_index + 1
+        elif self._repeat_enabled:
+            # repeat enabled, start queue at beginning
+            next_index = 0
+        self._queue_stream_next_index = next_index + 1
+        return next_index
 
     def to_dict(self) -> dict:
         """Instance attributes as dict so it can be serialized to json."""
@@ -555,9 +566,9 @@ class PlayerQueue:
         elapsed_time_queue = self.player.elapsed_time
         total_time = 0
         track_time = 0
-        if self.items and len(self.items) > self._last_queue_startindex:
+        if self.items and len(self.items) > self._queue_stream_start_index:
             queue_index = (
-                self._last_queue_startindex
+                self._queue_stream_start_index
             )  # holds the last starting position
             queue_track = None
             while len(self.items) > queue_index:
@@ -593,8 +604,8 @@ class PlayerQueue:
             self._shuffle_enabled = cache_data["shuffle_enabled"]
             self._repeat_enabled = cache_data["repeat_enabled"]
             self._items = cache_data["items"]
-            self._cur_index = cache_data["cur_item"]
-            self._next_queue_startindex = cache_data["next_queue_index"]
+            self._cur_index = cache_data.get("cur_index", 0)
+            self._queue_stream_next_index = self._cur_index
 
     # pylint: enable=unused-argument
 
@@ -605,8 +616,7 @@ class PlayerQueue:
             "shuffle_enabled": self._shuffle_enabled,
             "repeat_enabled": self._repeat_enabled,
             "items": self._items,
-            "cur_item": self._cur_index,
-            "next_queue_index": self._next_queue_startindex,
+            "cur_index": self._cur_index,
         }
         await self.mass.cache.async_set(cache_str, cache_data)
         LOGGER.info("queue state saved to file for player %s", self.queue_id)
index f6efdc4ea91942104f46bc88af5f4a1761ecafe7..12ae3ab55e2515f7290c5664733ad51b1a173720 100644 (file)
@@ -1,7 +1,6 @@
 """ChromeCast playerprovider."""
 
 import logging
-import uuid
 from typing import List
 
 import pychromecast
@@ -74,8 +73,8 @@ class ChromecastProvider(PlayerProvider):
     def __chromecast_add_update_callback(self, cast_uuid, cast_service_name):
         """Handle zeroconf discovery of a new or updated chromecast."""
         # pylint: disable=unused-argument
-        if uuid is None:
-            return  # Discovered chromecast without uuid
+        if cast_uuid is None:
+            return  # Discovered chromecast without uuid?
 
         service = self._listener.services[cast_uuid]
         cast_info = ChromecastInfo(
@@ -94,7 +93,7 @@ class ChromecastProvider(PlayerProvider):
         if not player:
             player = ChromecastPlayer(self.mass, cast_info)
         # if player was already added, the player will take care of reconnects itself.
-        self.mass.add_job(player.async_set_cast_info, cast_info)
+        player.set_cast_info(cast_info)
         self.mass.add_job(self.mass.players.async_add_player(player))
 
     @staticmethod
index 43748c293f4fc6e95b8330f4dc361094991b2875..84d47d6d2fa8fc19b177f839cef71a8b80f6bed6 100644 (file)
@@ -194,14 +194,6 @@ class ChromecastPlayer(Player):
 
     async def async_on_add(self) -> None:
         """Call when player is added to the player manager."""
-        # Only setup the chromecast once, changes will automatically be picked up.
-        if self._chromecast is not None:
-            return
-        LOGGER.debug(
-            "[%s] Connecting to cast device by service %s",
-            self._cast_info.friendly_name,
-            self.services,
-        )
         chromecast = await self.mass.loop.run_in_executor(
             None,
             pychromecast.get_chromecast_from_service,
@@ -227,7 +219,7 @@ class ChromecastPlayer(Player):
         chromecast.mz_controller = mz_controller
         self._chromecast.start()
 
-    async def async_set_cast_info(self, cast_info: ChromecastInfo) -> None:
+    def set_cast_info(self, cast_info: ChromecastInfo) -> None:
         """Set (or update) the cast discovery info."""
         self._cast_info = cast_info