from music_assistant.common.models.errors import (
InvalidDataError,
MediaNotFoundError,
+ MusicAssistantError,
UnsupportedFeaturedException,
)
from music_assistant.common.models.media_items import (
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(
from music_assistant.common.models.errors import (
InvalidDataError,
MediaNotFoundError,
+ MusicAssistantError,
UnsupportedFeaturedException,
)
from music_assistant.common.models.media_items import Album, ItemMapping, 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(
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)
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:
) -> 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)
InvalidProviderURI,
MediaNotFoundError,
MusicAssistantError,
+ ProviderUnavailableError,
)
from music_assistant.common.models.media_items import BrowseFolder, MediaItemType, SearchResults
from music_assistant.common.models.provider import SyncTask
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)
RANDOM_ARTIST = "random_artist"
RANDOM_ALBUM = "random_album"
RANDOM_TRACKS = "random_tracks"
+RECENTLY_PLAYED = "recently_played"
BUILTIN_PLAYLISTS = {
ALL_LIBRARY_TRACKS: "All library tracks",
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)
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