fix addming to db from file providers
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 4 Apr 2023 23:37:17 +0000 (01:37 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 4 Apr 2023 23:37:17 +0000 (01:37 +0200)
music_assistant/common/models/media_items.py
music_assistant/server/controllers/media/base.py
music_assistant/server/controllers/media/tracks.py

index 9321cbd9a91e11bdab14b86314d6da8faa2dfab2..32f75f30f2a4fc279460d8dc97e7938e55144f52 100755 (executable)
@@ -335,6 +335,10 @@ class TrackAlbumMapping(ItemMapping):
     disc_number: int | None = None
     track_number: int | None = None
 
+    def __hash__(self):
+        """Return custom hash."""
+        return hash((self.media_type, self.provider, self.item_id))
+
 
 @dataclass
 class Track(MediaItem):
index a2aea7b9fb95effe8a9b5089e1964cb32ecd8df2..12d16cdacaa881bb9c229bc8a2706ada7b33f3fa 100644 (file)
@@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, Generic, TypeVar
 
 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
+from music_assistant.common.models.errors import InvalidDataError, MediaNotFoundError
 from music_assistant.common.models.media_items import (
     ItemMapping,
     MediaItemType,
@@ -546,14 +546,13 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         overwrite: bool = False,
     ) -> list[ItemMapping]:
         """Extract (database) album/track artist(s) as ItemMapping."""
-        if not update_item or isinstance(update_item, ItemMapping):
-            return org_item.artists
-        if overwrite and update_item.provider_mappings:
-            return update_item.artists
-        item_artists: set[ItemMapping] = set()
-        for item in (org_item, update_item):
-            for artist in item.artists:
-                item_artists.add(await self._get_artist_mapping(artist))
+        if update_item is None or isinstance(update_item, ItemMapping):
+            source_artists = org_item.artists
+        elif overwrite and update_item.artists:
+            source_artists = update_item.artists
+        else:
+            source_artists = org_item.artists + update_item.artists
+        item_artists = {await self._get_artist_mapping(artist) for artist in source_artists}
         # use intermediate set to prevent duplicates
         # filter various artists if multiple artists
         if len(item_artists) > 1:
@@ -573,12 +572,14 @@ 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(
+        with suppress(MediaNotFoundError, AssertionError, InvalidDataError):
+            db_artist = await self.mass.music.artists.add(artist, skip_metadata_lookup=True)
+            return ItemMapping.from_item(db_artist)
+        # fallback to just the provider item
+        album = await self.mass.music.albums.get_provider_item(
             artist.item_id, artist.provider, fallback=artist
         )
-        if isinstance(artist, ItemMapping):
+        if isinstance(album, 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)
+        return ItemMapping.from_item(album)
index f0f9236e16a70c38bb8837e088153fd119387dbc..15ea8d340e6dee07161a4545ea69c17cbfcbbd14 100644 (file)
@@ -2,6 +2,7 @@
 from __future__ import annotations
 
 import asyncio
+from contextlib import suppress
 
 from music_assistant.common.helpers.datetime import utc_timestamp
 from music_assistant.common.helpers.json import serialize_to_json
@@ -335,8 +336,8 @@ class TracksController(MediaControllerBase[Track]):
         provider_mappings = self._get_provider_mappings(cur_item, item, overwrite)
         if getattr(item, "isrc", None):
             cur_item.isrc.update(item.isrc)
-        track_artists = await self._get_artist_mappings(cur_item, item)
-        track_albums = await self._get_track_albums(cur_item, item)
+        track_artists = await self._get_artist_mappings(cur_item, item, overwrite=overwrite)
+        track_albums = await self._get_track_albums(cur_item, item, overwrite=overwrite)
         async with self._db_add_lock:
             await self.mass.music.database.update(
                 self.db_table,
@@ -361,42 +362,51 @@ class TracksController(MediaControllerBase[Track]):
 
     async def _get_track_albums(
         self,
-        base_track: Track,
-        upd_track: Track | ItemMapping | None = None,
+        org_item: DbTrack,
+        update_item: Track | ItemMapping | None = None,
+        overwrite: bool = False,
     ) -> list[TrackAlbumMapping]:
         """Extract all (unique) albums of track as TrackAlbumMapping."""
-        track_albums: list[TrackAlbumMapping] = []
-        # existing TrackAlbumMappings are starting point
-        if base_track.albums:
-            track_albums = base_track.albums
-        elif upd_track and getattr(upd_track, "albums", None):
-            track_albums = upd_track.albums
-        # append update item album if needed
-        if upd_track and getattr(upd_track, "album", None):
-            mapping = await self._get_album_mapping(upd_track.album)
-            mapping = TrackAlbumMapping.from_dict(
-                {
-                    **mapping.to_dict(),
-                    "disc_number": upd_track.disc_number,
-                    "track_number": upd_track.track_number,
-                }
-            )
-            if mapping not in track_albums:
-                track_albums.append(mapping)
-        # append base item album if needed
-        elif base_track and base_track.album:
-            mapping = await self._get_album_mapping(base_track.album)
-            mapping = TrackAlbumMapping.from_dict(
-                {
-                    **mapping.to_dict(),
-                    "disc_number": base_track.disc_number,
-                    "track_number": base_track.track_number,
-                }
-            )
-            if mapping not in track_albums:
-                track_albums.append(mapping)
-
-        return track_albums
+        if update_item is None or isinstance(update_item, ItemMapping) and org_item.albums:
+            # already TrackAlbumMappings
+            return org_item.albums
+        track_albums: set[TrackAlbumMapping] = set()
+        # add base albums (only if not overwriting)
+        if (
+            not overwrite
+            or update_item is None
+            or isinstance(update_item, ItemMapping)
+            or not (update_item.album or update_item.albums)
+        ):
+            track_albums.update(org_item.albums)
+            if org_item.album:
+                mapping = await self._get_album_mapping(update_item.album)
+                track_albums.add(
+                    TrackAlbumMapping.from_dict(
+                        {
+                            **mapping.to_dict(),
+                            "disc_number": org_item.disc_number,
+                            "track_number": org_item.track_number,
+                        }
+                    )
+                )
+        # album(s) from update item
+        if update_item and not isinstance(update_item, ItemMapping):
+            if update_item.albums:
+                track_albums.update(update_item.albums)
+            if update_item.album:
+                mapping = await self._get_album_mapping(update_item.album)
+                track_albums.add(
+                    TrackAlbumMapping.from_dict(
+                        {
+                            **mapping.to_dict(),
+                            "disc_number": update_item.disc_number,
+                            "track_number": update_item.track_number,
+                        }
+                    )
+                )
+        # use intermediate set to prevent duplicates
+        return list(track_albums)
 
     async def _get_album_mapping(
         self,
@@ -414,12 +424,14 @@ class TracksController(MediaControllerBase[Track]):
             return ItemMapping.from_item(db_album)
 
         # try to request the full item
+        with suppress(MediaNotFoundError, AssertionError, InvalidDataError):
+            db_album = await self.mass.music.albums.add(album, skip_metadata_lookup=True)
+            return ItemMapping.from_item(db_album)
+        # fallback to just the provider 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)
+        return ItemMapping.from_item(album)