Jellyfin: Get more artwork from the Jellyfin instance (#1393)
authorJc2k <john.carr@unrouted.co.uk>
Wed, 19 Jun 2024 23:00:03 +0000 (00:00 +0100)
committerGitHub <noreply@github.com>
Wed, 19 Jun 2024 23:00:03 +0000 (01:00 +0200)
music_assistant/server/providers/jellyfin/__init__.py
music_assistant/server/providers/jellyfin/const.py
music_assistant/server/providers/jellyfin/manifest.json
requirements_all.txt

index b0320e980de8e627c191690b5dc64e00e026657d..2f9986dcb52b322faec4efd0a6019376d05fab25 100644 (file)
@@ -16,6 +16,7 @@ from aiojellyfin import MediaLibrary as JellyMediaLibrary
 from aiojellyfin import Playlist as JellyPlaylist
 from aiojellyfin import SessionConfiguration, authenticate_by_name
 from aiojellyfin import Track as JellyTrack
+from aiojellyfin.const import ImageType as JellyImageType
 
 from music_assistant.common.models.config_entries import (
     ConfigEntry,
@@ -78,7 +79,7 @@ from .const import (
     ITEM_KEY_RUNTIME_TICKS,
     ITEM_KEY_SORT_NAME,
     ITEM_KEY_USER_DATA,
-    MAX_IMAGE_WIDTH,
+    MEDIA_IMAGE_TYPES,
     SUPPORTED_CONTAINER_FORMATS,
     TRACK_FIELDS,
     UNKNOWN_ARTIST_MAPPING,
@@ -271,17 +272,7 @@ class JellyfinProvider(MusicProvider):
         )
         if ITEM_KEY_PRODUCTION_YEAR in jellyfin_album:
             album.year = jellyfin_album[ITEM_KEY_PRODUCTION_YEAR]
-        if thumb := self._get_thumbnail_url(jellyfin_album):
-            album.metadata.images = UniqueList(
-                [
-                    MediaItemImage(
-                        type=ImageType.THUMB,
-                        path=thumb,
-                        provider=self.instance_id,
-                        remotely_accessible=False,
-                    )
-                ]
-            )
+        album.metadata.images = self._get_artwork(jellyfin_album)
         if ITEM_KEY_OVERVIEW in jellyfin_album:
             album.metadata.description = jellyfin_album[ITEM_KEY_OVERVIEW]
         if ITEM_KEY_MUSICBRAINZ_RELEASE_GROUP in jellyfin_album[ITEM_KEY_PROVIDER_IDS]:
@@ -350,17 +341,7 @@ class JellyfinProvider(MusicProvider):
                 )
         if ITEM_KEY_SORT_NAME in jellyfin_artist:
             artist.sort_name = jellyfin_artist[ITEM_KEY_SORT_NAME]
-        if thumb := self._get_thumbnail_url(jellyfin_artist):
-            artist.metadata.images = UniqueList(
-                [
-                    MediaItemImage(
-                        type=ImageType.THUMB,
-                        path=thumb,
-                        provider=self.instance_id,
-                        remotely_accessible=False,
-                    )
-                ]
-            )
+        artist.metadata.images = self._get_artwork(jellyfin_artist)
         user_data = jellyfin_artist.get(ITEM_KEY_USER_DATA, {})
         artist.favorite = user_data.get(USER_DATA_KEY_IS_FAVORITE, False)
         return artist
@@ -396,17 +377,7 @@ class JellyfinProvider(MusicProvider):
         if track.track_number >= 0:
             track.position = track.track_number
 
-        if thumb := self._get_thumbnail_url(jellyfin_track):
-            track.metadata.images = UniqueList(
-                [
-                    MediaItemImage(
-                        type=ImageType.THUMB,
-                        path=thumb,
-                        provider=self.instance_id,
-                        remotely_accessible=False,
-                    )
-                ]
-            )
+        track.metadata.images = self._get_artwork(jellyfin_track)
 
         if jellyfin_track[ITEM_KEY_ARTIST_ITEMS]:
             for artist_item in jellyfin_track[ITEM_KEY_ARTIST_ITEMS]:
@@ -465,17 +436,7 @@ class JellyfinProvider(MusicProvider):
         )
         if ITEM_KEY_OVERVIEW in jellyfin_playlist:
             playlist.metadata.description = jellyfin_playlist[ITEM_KEY_OVERVIEW]
-        if thumb := self._get_thumbnail_url(jellyfin_playlist):
-            playlist.metadata.images = UniqueList(
-                [
-                    MediaItemImage(
-                        type=ImageType.THUMB,
-                        path=thumb,
-                        provider=self.instance_id,
-                        remotely_accessible=False,
-                    )
-                ]
-            )
+        playlist.metadata.images = self._get_artwork(jellyfin_playlist)
         user_data = jellyfin_playlist.get(ITEM_KEY_USER_DATA, {})
         playlist.favorite = user_data.get(USER_DATA_KEY_IS_FAVORITE, False)
         playlist.is_editable = False
@@ -737,15 +698,34 @@ class JellyfinProvider(MusicProvider):
             path=url,
         )
 
-    def _get_thumbnail_url(self, media_item: JellyMediaItem) -> str | None:
-        """Return the URL for the primary image of a media item if available."""
-        image_tags = media_item[ITEM_KEY_IMAGE_TAGS]
+    def _get_artwork(self, media_item: JellyMediaItem) -> UniqueList[MediaItemImage]:
+        images: UniqueList[MediaItemImage] = UniqueList()
 
-        if "Primary" not in image_tags:
-            return None
+        for i, _ in enumerate(media_item.get("BackdropImageTags", [])):
+            images.append(
+                MediaItemImage(
+                    type=ImageType.FANART,
+                    path=self._client.artwork(
+                        media_item[ITEM_KEY_ID], JellyImageType.Backdrop, index=i
+                    ),
+                    provider=self.instance_id,
+                    remotely_accessible=False,
+                )
+            )
+
+        image_tags = media_item[ITEM_KEY_IMAGE_TAGS]
+        for jelly_image_type, image_type in MEDIA_IMAGE_TYPES.items():
+            if jelly_image_type in image_tags:
+                images.append(
+                    MediaItemImage(
+                        type=image_type,
+                        path=self._client.artwork(media_item[ITEM_KEY_ID], jelly_image_type),
+                        provider=self.instance_id,
+                        remotely_accessible=False,
+                    )
+                )
 
-        item_id = media_item[ITEM_KEY_ID]
-        return self._client.artwork(item_id, "Primary", MAX_IMAGE_WIDTH)
+        return images
 
     def _get_stream_url(self, media_item: str) -> str:
         """Return the stream URL for a media item."""
index 4220efd0c073e850f41055c53ddbadfc99867d71..b01fd7dc07cce1e15340b6828fc4be81481038d5 100644 (file)
@@ -2,7 +2,9 @@
 
 from typing import Final
 
-from music_assistant.common.models.enums import MediaType
+from aiojellyfin.const import ImageType as JellyImageType
+
+from music_assistant.common.models.enums import ImageType, MediaType
 from music_assistant.common.models.media_items import ItemMapping
 from music_assistant.constants import UNKNOWN_ARTIST
 
@@ -71,6 +73,11 @@ TRACK_FIELDS = ["ProviderIds", "CanDownload", "SortName", "MediaSources", "Media
 USER_APP_NAME: Final = "Music Assistant"
 USER_AGENT: Final = "Music-Assistant-1.0"
 
-UNKNOWN_ARTIST_MAPPING = ItemMapping(
+UNKNOWN_ARTIST_MAPPING: Final = ItemMapping(
     media_type=MediaType.ARTIST, item_id=UNKNOWN_ARTIST, provider=DOMAIN, name=UNKNOWN_ARTIST
 )
+
+MEDIA_IMAGE_TYPES: Final = {
+    JellyImageType.Primary: ImageType.THUMB,
+    JellyImageType.Logo: ImageType.LOGO,
+}
index 3647649a3d7d6bc12a707e1a1f8675bbab6bd536..a21bed18360726bfce49aeb1028569b4d8eac0fe 100644 (file)
@@ -4,7 +4,7 @@
   "name": "Jellyfin Media Server Library",
   "description": "Support for the Jellyfin streaming provider in Music Assistant.",
   "codeowners": ["@lokiberra", "@Jc2k"],
-  "requirements": ["aiojellyfin==0.5.0"],
+  "requirements": ["aiojellyfin==0.7.0"],
   "documentation": "https://music-assistant.io/music-providers/jellyfin/",
   "multi_instance": true
 }
index 66e0e4f7e2dc7bd8d5bfb8ad7fc7feae43c81177..eea9419aa9bdfb631d0f3ae5c98cc72cb8c1f5d1 100644 (file)
@@ -4,7 +4,7 @@ Brotli>=1.0.9
 aiodns>=3.0.0
 aiofiles==23.2.1
 aiohttp==3.9.5
-aiojellyfin==0.5.0
+aiojellyfin==0.7.0
 aiorun==2024.5.1
 aioslimproto==3.0.1
 aiosqlite==0.20.0