add some more guards for incomplete items
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 3 Apr 2023 18:01:54 +0000 (20:01 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 3 Apr 2023 18:01:54 +0000 (20:01 +0200)
music_assistant/server/controllers/media/albums.py
music_assistant/server/controllers/media/artists.py
music_assistant/server/controllers/media/base.py
music_assistant/server/controllers/media/tracks.py
music_assistant/server/providers/qobuz/__init__.py

index de863b7519120efb6a1e0a7e246d7f73873dcbb8..3c4faa53929bc42f85b0e0bc9448f932466ffc86 100644 (file)
@@ -9,7 +9,11 @@ from typing import TYPE_CHECKING
 from music_assistant.common.helpers.datetime import utc_timestamp
 from music_assistant.common.helpers.json import serialize_to_json
 from music_assistant.common.models.enums import EventType, ProviderFeature
-from music_assistant.common.models.errors import MediaNotFoundError, UnsupportedFeaturedException
+from music_assistant.common.models.errors import (
+    InvalidDataError,
+    MediaNotFoundError,
+    UnsupportedFeaturedException,
+)
 from music_assistant.common.models.media_items import (
     Album,
     AlbumType,
@@ -50,7 +54,7 @@ class AlbumsController(MediaControllerBase[Album]):
         provider_instance_id_or_domain: str,
         force_refresh: bool = False,
         lazy: bool = True,
-        details: Album = None,
+        details: Album | ItemMapping = None,
         add_to_db: bool = True,
     ) -> Album:
         """Return (full) details for a single media item."""
@@ -77,6 +81,8 @@ class AlbumsController(MediaControllerBase[Album]):
 
     async def add(self, item: Album, skip_metadata_lookup: bool = False) -> Album:
         """Add album to local db and return the database item."""
+        if not isinstance(item, Album):
+            raise InvalidDataError("Not a valid Album object (ItemMapping can not be added to db)")
         # resolve any ItemMapping artists
         item.artists = [
             await self.mass.music.artists.get_provider_item(
index 5d98e8033ed0ef67bb3252a4a598f704a513bb6b..d0ddc7ba1b3595a62dde0a2c470631bbe90181d8 100644 (file)
@@ -52,8 +52,10 @@ class ArtistsController(MediaControllerBase[Artist]):
         self.mass.register_api_command("music/artist/update", self._update_db_item)
         self.mass.register_api_command("music/artist/delete", self.delete)
 
-    async def add(self, item: Artist, skip_metadata_lookup: bool = False) -> Artist:
+    async def add(self, item: Artist | ItemMapping, skip_metadata_lookup: bool = False) -> Artist:
         """Add artist to local db and return the database item."""
+        if isinstance(item, ItemMapping):
+            skip_metadata_lookup = True
         # grab musicbrainz id and additional metadata
         if not skip_metadata_lookup:
             await self.mass.metadata.get_artist_metadata(item)
index 145478ce3750f264c6b6fae1280037c4a0fceb21..4fae5df029bc587b6dd66366e55f1ec122aff149 100644 (file)
@@ -567,5 +567,13 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         ):
             return ItemMapping.from_item(db_artist)
 
+        # try to request the full item
+        artist = await self.mass.music.artists.get_provider_item(
+            artist.item_id, artist.provider, fallback=artist
+        )
+        if isinstance(artist, ItemMapping):
+            # this can happen for unavailable items
+            return artist
+
         db_artist = await self.mass.music.artists.add(artist, skip_metadata_lookup=True)
         return ItemMapping.from_item(db_artist)
index d210a4958eaf3b80eeada02ff841046fed570802..e187966fe1f25a4c60b71c38f56bd4c4ff32a1b0 100644 (file)
@@ -6,7 +6,11 @@ import asyncio
 from music_assistant.common.helpers.datetime import utc_timestamp
 from music_assistant.common.helpers.json import serialize_to_json
 from music_assistant.common.models.enums import EventType, MediaType, ProviderFeature
-from music_assistant.common.models.errors import MediaNotFoundError, UnsupportedFeaturedException
+from music_assistant.common.models.errors import (
+    InvalidDataError,
+    MediaNotFoundError,
+    UnsupportedFeaturedException,
+)
 from music_assistant.common.models.media_items import (
     Album,
     DbTrack,
@@ -95,7 +99,10 @@ class TracksController(MediaControllerBase[Track]):
 
     async def add(self, item: Track, skip_metadata_lookup: bool = False) -> Track:
         """Add track to local db and return the new database item."""
-        assert item.artists, "Artist(s) missing on Track"
+        if not isinstance(item, Track):
+            raise InvalidDataError("Not a valid Track object (ItemMapping can not be added to db)")
+        if not item.artists:
+            raise InvalidDataError("Track is missing artist(s)")
         # resolve any ItemMapping artists
         item.artists = [
             await self.mass.music.artists.get_provider_item(
@@ -404,5 +411,13 @@ class TracksController(MediaControllerBase[Track]):
         ):
             return ItemMapping.from_item(db_album)
 
+        # try to request the full item
+        album = await self.mass.music.albums.get_provider_item(
+            album.item_id, album.provider, fallback=album
+        )
+        if isinstance(album, ItemMapping):
+            # this can happen for unavailable items
+            return album
+
         db_album = await self.mass.music.albums.add(album, skip_metadata_lookup=True)
         return ItemMapping.from_item(db_album)
index eb361b8f9191c11bd40c5f80cbccd914a2e0ffb5..9e50a13c69f82e16995ec1f14116be716582a668 100644 (file)
@@ -647,11 +647,9 @@ class QobuzProvider(MusicProvider):
             kwargs["user_auth_token"] = await self._auth_token()
         async with self._throttler:
             async with self.mass.http_session.get(
-                url, headers=headers, params=kwargs, ssl=False
+                url, headers=headers, params=kwargs, ssl=False, raise_for_status=True
             ) as response:
                 try:
-                    # make sure status is 200
-                    assert response.status == 200
                     result = await response.json()
                     # check for error in json
                     if error := result.get("error"):