Fix: Prevent redundant lookup of full media item in queue controller
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 28 Oct 2024 09:22:58 +0000 (10:22 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 28 Oct 2024 09:22:58 +0000 (10:22 +0100)
music_assistant/common/models/queue_item.py
music_assistant/server/controllers/music.py
music_assistant/server/controllers/player_queues.py
music_assistant/server/helpers/audio.py

index 716e2b1be49e0edef756b5e8f76f0b61ce71b546..8290b387166aa8dead69b507054ddb8f7fdf1b19 100644 (file)
@@ -19,7 +19,6 @@ class QueueItem(DataClassDictMixin):
 
     queue_id: str
     queue_item_id: str
-
     name: str
     duration: int | None
     sort_index: int = 0
index 59f6e2a941d00f81a8235c61c28e98b01292becf..1d1f0e293c631d371b37e88e5aa10a56382495df 100644 (file)
@@ -478,6 +478,19 @@ class MusicController(CoreController):
             provider_instance_id_or_domain=provider_instance_id_or_domain,
         )
 
+    async def get_library_item_by_prov_id(
+        self,
+        media_type: MediaType,
+        item_id: str,
+        provider_instance_id_or_domain: str,
+    ) -> MediaItemType | None:
+        """Get single library music item by id and media type."""
+        ctrl = self.get_controller(media_type)
+        return await ctrl.get_library_item_by_prov_id(
+            item_id=item_id,
+            provider_instance_id_or_domain=provider_instance_id_or_domain,
+        )
+
     @api_command("music/favorites/add_item")
     async def add_item_to_favorites(
         self,
index 43eac03b2e5712cadaa59c3b494b5fb989f1ade9..68eb7941c959fee8fd223c55fa12be3ab8829618 100644 (file)
@@ -1119,9 +1119,13 @@ class PlayerQueuesController(CoreController):
                     queue_item=queue_item,
                     prefer_album_loudness=prefer_album_loudness,
                 )
-                # Preload the full MediaItem for the QueueItem, making sure to get the
-                # maximum quality of thumbs
-                if queue_item.media_item:
+                # Ensure we have at least an image for the queue item,
+                # so grab full item if needed. Note that for YTM this is always needed
+                # because it has poor thumbs by default (..sigh)
+                if queue_item.media_item and (
+                    not queue_item.media_item.image
+                    or queue_item.media_item.provider.startswith("ytmusic")
+                ):
                     queue_item.media_item = await self.mass.music.get_item_by_uri(queue_item.uri)
                 # allow stripping silence from the begin/end of the track if crossfade is enabled
                 # this will allow for (much) smoother crossfades
@@ -1134,11 +1138,6 @@ class PlayerQueuesController(CoreController):
             except MediaNotFoundError:
                 # No stream details found, skip this QueueItem
                 self.logger.debug("Skipping unplayable item: %s", next_item)
-                # we need to set a fake streamdetails object on the item
-                # otherwise our flow mode logic will break which
-                # calculates where we are in the queue
-                playlog = queue_item.streamdetails.play_log if queue_item.streamdetails else []
-                playlog.append(0.0)
                 queue_item.streamdetails = StreamDetails(
                     provider=queue_item.media_item.provider if queue_item.media_item else "unknown",
                     item_id=queue_item.media_item.item_id if queue_item.media_item else "unknown",
index 472f4d7c2f55d7f91ac070a0798140a06e7ee989..22dc1ef616f869a187202247af33492a154a6b84 100644 (file)
@@ -199,11 +199,22 @@ async def get_stream_details(
     # this makes sure that playback has priority over other requests that may be
     # happening in the background
     BYPASS_THROTTLER.set(True)
-    # always request the full item as there might be other qualities available
-    full_item = await mass.music.get_item_by_uri(queue_item.uri)
+    if not queue_item.media_item:
+        # this should not happen, but guard it just in case
+        assert queue_item.streamdetails, "streamdetails required for non-mediaitem queueitems"
+        return queue_item.streamdetails
+    # always request the full library item as there might be other qualities available
+    media_item = (
+        await mass.music.get_library_item_by_prov_id(
+            queue_item.media_item.media_type,
+            queue_item.media_item.item_id,
+            queue_item.media_item.provider,
+        )
+        or queue_item.media_item
+    )
     # sort by quality and check track availability
     for prov_media in sorted(
-        full_item.provider_mappings, key=lambda x: x.quality or 0, reverse=True
+        media_item.provider_mappings, key=lambda x: x.quality or 0, reverse=True
     ):
         if not prov_media.available:
             LOGGER.debug(f"Skipping unavailable {prov_media}")