From: anatosun <33899455+anatosun@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:27:24 +0000 (+0200) Subject: Plex: Add artist top tracks and similar tracks support (#2522) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=fdcc113e942c0fb67f0ef96364495693f87755d6;p=music-assistant-server.git Plex: Add artist top tracks and similar tracks support (#2522) --- diff --git a/music_assistant/providers/plex/__init__.py b/music_assistant/providers/plex/__init__.py index 9d2afef0..c28de5d0 100644 --- a/music_assistant/providers/plex/__init__.py +++ b/music_assistant/providers/plex/__init__.py @@ -98,6 +98,8 @@ SUPPORTED_FEATURES = { ProviderFeature.BROWSE, ProviderFeature.SEARCH, ProviderFeature.ARTIST_ALBUMS, + ProviderFeature.ARTIST_TOPTRACKS, + ProviderFeature.SIMILAR_TRACKS, } @@ -925,6 +927,50 @@ class PlexProvider(MusicProvider): return albums return [] + @use_cache(3600 * 3) # Cache for 3 hours + async def get_artist_toptracks(self, prov_artist_id: str) -> list[Track]: + """Get top tracks for the given artist using Plex artist radio/station.""" + if prov_artist_id.startswith(FAKE_ARTIST_PREFIX): + return [] + + try: + plex_artist = await self._get_data(prov_artist_id, PlexArtist) + # Get the artist radio station which contains top/popular tracks + if station := await self._run_async(plex_artist.station): + # Get tracks from the station + station_tracks = await self._run_async(station.items) + tracks = [] + for plex_track in station_tracks[:25]: # Limit to 25 top tracks + if track := await self._parse_track(plex_track): + tracks.append(track) + self.logger.debug( + "Retrieved %d top tracks for artist %s", len(tracks), prov_artist_id + ) + return tracks + self.logger.warning("No station available for artist %s", prov_artist_id) + except Exception as err: + self.logger.warning("Error getting top tracks for artist %s: %s", prov_artist_id, err) + return [] + + @use_cache(3600 * 3) # Cache for 3 hours + async def get_similar_tracks(self, prov_track_id: str, limit: int = 25) -> list[Track]: + """Get similar tracks using Plex's sonicallySimilar feature.""" + try: + plex_track = await self._get_data(prov_track_id, PlexTrack) + # Get sonically similar tracks + similar_tracks = await self._run_async(plex_track.sonicallySimilar, limit=limit) + tracks = [] + for similar_track in similar_tracks: + if track := await self._parse_track(similar_track): + tracks.append(track) + self.logger.debug( + "Retrieved %d similar tracks for track %s", len(tracks), prov_track_id + ) + return tracks + except Exception as err: + self.logger.warning("Error getting similar tracks for %s: %s", prov_track_id, err) + return [] + async def get_stream_details(self, item_id: str, media_type: MediaType) -> StreamDetails: """Get streamdetails for a track.""" plex_track = await self._get_data(item_id, PlexTrack)