From: Marcel van der Veldt Date: Mon, 15 Apr 2024 22:46:09 +0000 (+0200) Subject: fix bug in (recursive) item retrieval X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=f01f4d75bb07c944684b14fe60795015216e3d59;p=music-assistant-server.git fix bug in (recursive) item retrieval --- diff --git a/music_assistant/server/controllers/media/albums.py b/music_assistant/server/controllers/media/albums.py index aa1e5a8f..deb83705 100644 --- a/music_assistant/server/controllers/media/albums.py +++ b/music_assistant/server/controllers/media/albums.py @@ -13,6 +13,7 @@ from music_assistant.common.models.enums import EventType, ProviderFeature from music_assistant.common.models.errors import ( InvalidDataError, MediaNotFoundError, + MusicAssistantError, UnsupportedFeaturedException, ) from music_assistant.common.models.media_items import ( @@ -76,17 +77,25 @@ class AlbumsController(MediaControllerBase[Album]): details=details, add_to_library=add_to_library, ) - # append full artist details to full album item - album.artists = [ - await self.mass.music.artists.get( - item.item_id, - item.provider, - lazy=lazy, - details=item, - add_to_library=add_to_library, - ) - for item in album.artists - ] + # append artist details to full track item (resolve ItemMappings) + album_artists = [] + for artist in album.artists: + if not isinstance(artist, ItemMapping): + album_artists.append(artist) + continue + try: + album_artists.append( + await self.mass.music.artists.get( + artist.item_id, + artist.provider, + lazy=lazy, + add_to_library=False, # TODO: make this configurable + ) + ) + except MusicAssistantError as err: + # edge case where playlist track has invalid artistdetails + self.logger.warning("Unable to fetch artist details %s - %s", artist.uri, str(err)) + album.artists = album_artists return album async def add_item_to_library( diff --git a/music_assistant/server/controllers/media/base.py b/music_assistant/server/controllers/media/base.py index ff61dbdc..977eeb13 100644 --- a/music_assistant/server/controllers/media/base.py +++ b/music_assistant/server/controllers/media/base.py @@ -276,7 +276,11 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta): # returns the first provider that is available if not prov_mapping.available: continue - if provider := self.mass.get_provider(prov_mapping.provider_instance): + if provider := self.mass.get_provider( + prov_mapping.provider_instance + if prefer_unique + else prov_mapping.provider_domain + ): if prefer_unique and provider.is_streaming_provider: continue return (prov_mapping.provider_instance, prov_mapping.item_id) diff --git a/music_assistant/server/controllers/media/tracks.py b/music_assistant/server/controllers/media/tracks.py index 70ef210e..517a5f48 100644 --- a/music_assistant/server/controllers/media/tracks.py +++ b/music_assistant/server/controllers/media/tracks.py @@ -12,6 +12,7 @@ from music_assistant.common.models.enums import AlbumType, EventType, MediaType, from music_assistant.common.models.errors import ( InvalidDataError, MediaNotFoundError, + MusicAssistantError, UnsupportedFeaturedException, ) from music_assistant.common.models.media_items import Album, ItemMapping, Track @@ -75,18 +76,10 @@ class TracksController(MediaControllerBase[Track]): details=details, add_to_library=add_to_library, ) - # append full album details to full track item + # append full album details to full track item (resolve ItemMappings) try: if album_uri and (album := await self.mass.music.get_item_by_uri(album_uri)): track.album = album - elif track.album: - track.album = await self.mass.music.albums.get( - track.album.item_id, - track.album.provider, - lazy=lazy, - details=None if isinstance(track.album, ItemMapping) else track.album, - add_to_library=add_to_library, - ) elif provider_instance_id_or_domain == "library": # grab the first album this track is attached to for album_track_row in await self.mass.music.database.get_rows( @@ -95,9 +88,17 @@ class TracksController(MediaControllerBase[Track]): track.album = await self.mass.music.albums.get_library_item( album_track_row["album_id"] ) - except MediaNotFoundError: + elif isinstance(track.album, ItemMapping) or track.album and not track.album.image: + track.album = await self.mass.music.albums.get( + track.album.item_id, + track.album.provider, + lazy=lazy, + details=None if isinstance(track.album, ItemMapping) else track.album, + add_to_library=False, # TODO: make this configurable + ) + except MusicAssistantError as err: # edge case where playlist track has invalid albumdetails - self.logger.warning("Unable to fetch album details %s", track.album.uri) + self.logger.warning("Unable to fetch album details %s - %s", track.album.uri, str(err)) # prefer album image if album explicitly given or track has no image on its own if ( (album_uri or not track.metadata.images) @@ -105,19 +106,25 @@ class TracksController(MediaControllerBase[Track]): and track.album.image ): track.metadata.images = [track.album.image] - # append full artist details to full track item - full_artists = [] + # append artist details to full track item (resolve ItemMappings) + track_artists = [] for artist in track.artists: - full_artists.append( - await self.mass.music.artists.get( - artist.item_id, - artist.provider, - lazy=lazy, - details=None if isinstance(artist, ItemMapping) else artist, - add_to_library=add_to_library, + if not isinstance(artist, ItemMapping): + track_artists.append(artist) + continue + try: + track_artists.append( + await self.mass.music.artists.get( + artist.item_id, + artist.provider, + lazy=lazy, + add_to_library=False, # TODO: make this configurable + ) ) - ) - track.artists = full_artists + except MusicAssistantError as err: + # edge case where playlist track has invalid artistdetails + self.logger.warning("Unable to fetch artist details %s - %s", artist.uri, str(err)) + track.artists = track_artists return track async def add_item_to_library(self, item: Track, metadata_lookup: bool = True) -> Track: @@ -236,7 +243,7 @@ class TracksController(MediaControllerBase[Track]): ) -> list[Track]: """Return all versions of a track we can find on all providers.""" track = await self.get(item_id, provider_instance_id_or_domain, add_to_library=False) - search_query = f"{track.artists[0].name} - {track.name}" + search_query = f"{track.artist_str} - {track.name}" result: list[Track] = [] for provider_id in self.mass.music.get_unique_providers(): provider = self.mass.get_provider(provider_id) diff --git a/music_assistant/server/controllers/music.py b/music_assistant/server/controllers/music.py index 2d699d92..02d3da99 100644 --- a/music_assistant/server/controllers/music.py +++ b/music_assistant/server/controllers/music.py @@ -25,6 +25,7 @@ from music_assistant.common.models.errors import ( InvalidProviderURI, MediaNotFoundError, MusicAssistantError, + ProviderUnavailableError, ) from music_assistant.common.models.media_items import BrowseFolder, MediaItemType, SearchResults from music_assistant.common.models.provider import SyncTask @@ -342,7 +343,7 @@ class MusicController(CoreController): db_rows = await self.mass.music.database.get_rows_from_query(query, limit=limit) result: list[MediaItemType] = [] for db_row in db_rows: - with suppress(MediaNotFoundError): + with suppress(MediaNotFoundError, ProviderUnavailableError): media_type = MediaType(db_row["media_type"]) item = await self.get_item(media_type, db_row["item_id"], db_row["provider"]) result.append(item) diff --git a/music_assistant/server/providers/builtin/__init__.py b/music_assistant/server/providers/builtin/__init__.py index 86344035..320c22bb 100644 --- a/music_assistant/server/providers/builtin/__init__.py +++ b/music_assistant/server/providers/builtin/__init__.py @@ -68,6 +68,7 @@ ALL_FAVORITE_TRACKS = "all_favorite_tracks" RANDOM_ARTIST = "random_artist" RANDOM_ALBUM = "random_album" RANDOM_TRACKS = "random_tracks" +RECENTLY_PLAYED = "recently_played" BUILTIN_PLAYLISTS = { ALL_LIBRARY_TRACKS: "All library tracks", @@ -75,6 +76,7 @@ BUILTIN_PLAYLISTS = { RANDOM_ARTIST: "Random Artist (from library)", RANDOM_ALBUM: "Random Album (from library)", RANDOM_TRACKS: "100 Random tracks (from library)", + RECENTLY_PLAYED: "Recently played tracks", } COLLAGE_IMAGE_PLAYLISTS = (ALL_FAVORITE_TRACKS, ALL_LIBRARY_TRACKS, RANDOM_TRACKS) @@ -537,3 +539,8 @@ class BuiltinProvider(MusicProvider): count += 1 yield PlaylistTrack.from_dict({**artist_track.to_dict(), "position": count}) return + if builtin_playlist_id == RECENTLY_PLAYED: + for track in await self.mass.music.recently_played(250, [MediaType.TRACK]): + count += 1 + yield PlaylistTrack.from_dict({**track.to_dict(), "position": count}) + return