1717from music_assistant_models .errors import (
1818 InvalidCommand ,
1919 MediaNotFoundError ,
20+ ProviderUnavailableError ,
2021)
2122
2223from .const import (
2324 ATTR_COMMAND ,
2425 ATTR_DATA ,
26+ ATTR_DURATION ,
2527 ATTR_FAVORITE ,
2628 ATTR_LIMIT ,
2729 ATTR_LIMIT_AFTER ,
6264 MOVE_QUEUE_ITEM_NEXT_SERVICE_SCHEMA ,
6365 MOVE_QUEUE_ITEM_UP_SERVICE_SCHEMA ,
6466 PLAY_QUEUE_ITEM_SERVICE_SCHEMA ,
65- PLAYLIST_ITEM_SCHEMA ,
6667 QUEUE_ITEM_SCHEMA ,
6768 QUEUE_ITEMS_SERVICE_SCHEMA ,
6869 REMOVE_QUEUE_ITEM_SERVICE_SCHEMA ,
6970 SEND_COMMAND_SERVICE_SCHEMA ,
7071 SET_GROUP_VOLUME_SERVICE_SCHEMA ,
72+ TRACK_ITEM_SCHEMA ,
7173)
7274from .utils import (
7375 find_image ,
@@ -196,7 +198,6 @@ async def get_active_queue(self, entity_id: str):
196198
197199 async def _format_queue_item (self , queue_item : dict ) -> dict :
198200 """Format list of queue items for response."""
199- LOGGER .debug (f"Got queue item with keys { queue_item .keys ()} " )
200201 media = queue_item ["media_item" ]
201202
202203 queue_item_id = queue_item ["queue_item_id" ]
@@ -224,7 +225,6 @@ async def _format_queue_item(self, queue_item: dict) -> dict:
224225 )
225226 if local_image_encoded :
226227 response [ATTR_LOCAL_IMAGE_ENCODED ] = local_image_encoded
227- LOGGER .debug (f"Sending back response with keys { response .keys ()} " )
228228 return response
229229
230230 async def send_command (self , call : ServiceCall ) -> ServiceResponse :
@@ -346,22 +346,72 @@ async def unfavorite_item(self, call: ServiceCall) -> ServiceResponse:
346346 library_item_id = item_id ,
347347 )
348348
349- async def get_playlist_items (self , playlist_uri : str ):
349+ async def get_artist_details (self , artist_uri ):
350+ """Retrieves the details for an artist."""
351+ provider , item_id = parse_uri (artist_uri )
352+ LOGGER .debug (f"Getting artist details for provider { provider } " )
353+ return await self ._client .music .get_artist (item_id , provider )
354+
355+ async def get_album_details (self , album_uri ):
356+ """Retrieves the details for an album."""
357+ provider , item_id = parse_uri (album_uri )
358+ LOGGER .debug (f"Getting album details for provider { provider } " )
359+ return await self ._client .music .get_album (item_id , provider )
360+
361+ async def get_playlist_details (self , playlist_uri ):
362+ """Retrieves the details for a playlist."""
363+ provider , item_id = parse_uri (playlist_uri )
364+ LOGGER .debug (f"Getting album details for provider { provider } " )
365+ return await self ._client .music .get_playlist (item_id , provider )
366+
367+ async def get_artist_tracks (self , artist_uri : str , page : int | None = None ):
368+ """Retrieves a limited number of tracks from an artist."""
369+ details = await self .get_artist_details (artist_uri )
370+ mappings = list (details .provider_mappings )
371+ if not len (mappings ) > 0 :
372+ msg = f"URI { artist_uri } returned no results!"
373+ raise ProviderUnavailableError (msg )
374+ mapping = mappings [0 ]
375+ item_id = mapping .item_id
376+ provider = mapping .provider_domain
377+ resp = (
378+ await self ._client .music .get_artist_tracks (item_id , provider )
379+ if not page
380+ else await self ._client .music .get_artist_tracks (item_id , provider , page )
381+ )
382+ return [self .format_track_item (item .to_dict ()) for item in resp ]
383+
384+ async def get_album_tracks (self , album_uri : str , page : int | None = None ):
385+ """Retrieves all tracks from an album."""
386+ details = await self .get_album_details (album_uri )
387+ mappings = list (details .provider_mappings )
388+ if not len (mappings ) > 0 :
389+ msg = f"URI { album_uri } returned no results!"
390+ raise ProviderUnavailableError (msg )
391+ mapping = mappings [0 ]
392+ item_id = mapping .item_id
393+ provider = mapping .provider_domain
394+ resp = (
395+ await self ._client .music .get_album_tracks (item_id , provider )
396+ if not page
397+ else await self ._client .music .get_album_tracks (item_id , provider , page )
398+ )
399+ return [self .format_track_item (item .to_dict ()) for item in resp ]
400+
401+ async def get_playlist_tracks (self , playlist_uri : str , page : int | None = None ):
350402 """Retrieves all playlist items."""
351403 provider , item_id = parse_uri (playlist_uri )
352404 LOGGER .debug (
353405 f"Getting playlist items for provider { provider } , item_id { item_id } " ,
354406 )
355- resp = await self ._client .music .get_playlist_tracks (item_id , provider )
356- LOGGER .debug (f"Got response with { len (resp ) if resp else 0 } items" )
357- result = [self .format_playlist_item (item .to_dict ()) for item in resp ]
358- msg = f"Got response { result [0 ]} "
359- if len (msg ) > 200 :
360- msg = f"{ msg [180 ]} ..." + "}"
361- LOGGER .debug (msg )
362- return result
363-
364- def format_playlist_item (self , playlist_item : dict ) -> dict :
407+ resp = (
408+ await self ._client .music .get_playlist_tracks (item_id , provider )
409+ if not page
410+ else await self ._client .music .get_playlist_tracks (item_id , provider , page )
411+ )
412+ return [self .format_track_item (item .to_dict ()) for item in resp ]
413+
414+ def format_track_item (self , playlist_item : dict ) -> TRACK_ITEM_SCHEMA :
365415 """Processes the individual items in a playlist."""
366416 media_title = playlist_item .get ("name" ) or "N/A"
367417 media_album = playlist_item .get ("album" ) or "N/A"
@@ -370,16 +420,18 @@ def format_playlist_item(self, playlist_item: dict) -> dict:
370420 media_image = find_image (playlist_item ) or ""
371421 local_image_encoded = playlist_item .get (ATTR_LOCAL_IMAGE_ENCODED )
372422 favorite = playlist_item ["favorite" ]
423+ duration = playlist_item ["duration" ] or 0
373424
374425 artists = playlist_item ["artists" ]
375426 artist_names = [artist ["name" ] for artist in artists ]
376427 media_artist = ", " .join (artist_names )
377- response : ServiceResponse = PLAYLIST_ITEM_SCHEMA (
428+ response : ServiceResponse = TRACK_ITEM_SCHEMA (
378429 {
379430 ATTR_MEDIA_TITLE : media_title ,
380431 ATTR_MEDIA_ALBUM_NAME : media_album_name ,
381432 ATTR_MEDIA_ARTIST : media_artist ,
382433 ATTR_MEDIA_CONTENT_ID : media_content_id ,
434+ ATTR_DURATION : duration ,
383435 ATTR_MEDIA_IMAGE : media_image ,
384436 ATTR_FAVORITE : favorite ,
385437 },
0 commit comments