ProviderFeature.BROWSE,
ProviderFeature.SEARCH,
ProviderFeature.ARTIST_ALBUMS,
+ ProviderFeature.ARTIST_TOPTRACKS,
+ ProviderFeature.SIMILAR_TRACKS,
)
@property
)
},
)
+
if sonic_artist.cover_id:
artist.metadata.images = [
MediaItemImage(
type=ImageType.THUMB, path=sonic_artist.cover_id, provider=self.instance_id
)
]
+ else:
+ artist.metadata.images = []
+
if sonic_info:
if sonic_info.biography:
artist.metadata.description = sonic_info.biography
},
year=sonic_album.year,
)
+
if sonic_album.cover_id:
album.metadata.images = [
MediaItemImage(
type=ImageType.THUMB, path=sonic_album.cover_id, provider=self.instance_id
),
]
- if sonic_album.artist_id is None:
+ else:
+ album.metadata.images = []
+
+ if sonic_album.artist_id:
+ album.artists.append(
+ self._get_item_mapping(
+ MediaType.ARTIST,
+ sonic_album.artist_id,
+ sonic_album.artist if sonic_album.artist else UNKNOWN_ARTIST,
+ )
+ )
+ else:
album.artists.append(
Artist(
item_id=UNKNOWN_ARTIST_ID,
},
)
)
- else:
- album.artists.append(
- self._get_item_mapping(
- MediaType.ARTIST,
- sonic_album.artist_id,
- sonic_album.artist if sonic_album.artist else UNKNOWN_ARTIST,
- )
- )
if sonic_info:
if sonic_info.small_url:
if not extra_init_kwargs:
track.track_number = int(sonic_song.track) if sonic_song.track is not None else 1
- if sonic_song.artist_id is None:
+ # We need to find an artist for this track but various implementations seem to disagree
+ # about where the artist with the valid ID needs to be found. We will add any artist with
+ # an ID and only use UNKNOWN if none are found.
+
+ if sonic_song.artist_id:
+ track.artists.append(
+ self._get_item_mapping(
+ MediaType.ARTIST,
+ sonic_song.artist_id,
+ sonic_song.artist if sonic_song.artist else UNKNOWN_ARTIST,
+ )
+ )
+
+ for entry in sonic_song.artists:
+ if entry.id == sonic_song.artist_id:
+ continue
+ if entry.id is not None and entry.name is not None:
+ track.artists.append(self._get_item_mapping(MediaType.ARTIST, entry.id, entry.name))
+
+ if not track.artists:
track.artists.append(
Artist(
item_id=UNKNOWN_ARTIST_ID,
},
)
)
- else:
- track.artists.append(
- self._get_item_mapping(
- MediaType.ARTIST,
- sonic_song.artist_id,
- sonic_song.artist if sonic_song.artist else UNKNOWN_ARTIST,
- )
- )
-
- for entry in sonic_song.artists:
- if entry.id == sonic_song.artist_id:
- continue
- if entry.id is not None and entry.name is not None:
- track.artists.append(self._get_item_mapping(MediaType.ARTIST, entry.id, entry.name))
return track
def _parse_playlist(self, sonic_playlist: SonicPlaylist) -> Playlist:
for index, sonic_song in enumerate(sonic_playlist.songs):
yield self._parse_track(sonic_song, {"position": index + 1})
+ async def get_artist_toptracks(self, prov_artist_id: str) -> list[Track]:
+ """Get the top listed tracks for a specified artist."""
+ sonic_artist: SonicArtist = await self._run_async(self._conn.getArtist, prov_artist_id)
+ songs: list[SonicSong] = await self._run_async(self._conn.getTopSongs, sonic_artist.name)
+ return [self._parse_track(entry) for entry in songs]
+
+ async def get_similar_tracks(self, prov_track_id: str, limit: int = 25) -> list[Track]:
+ """Get tracks similar to selected track."""
+ songs: list[SonicSong] = await self._run_async(
+ self._conn.getSimilarSongs2, iid=prov_track_id, count=limit
+ )
+ return [self._parse_track(entry) for entry in songs]
+
async def get_stream_details(self, item_id: str) -> StreamDetails | None:
"""Get the details needed to process a specified track."""
try: