From: Marvin Schenkel Date: Wed, 5 Nov 2025 15:23:33 +0000 (+0100) Subject: Don't stop the music improvements (#2597) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=ad2ed3d7c81bd284541c6aef5c2ee6f6a6157720;p=music-assistant-server.git Don't stop the music improvements (#2597) --- diff --git a/music_assistant/controllers/player_queues.py b/music_assistant/controllers/player_queues.py index 46924f70..a92484f3 100644 --- a/music_assistant/controllers/player_queues.py +++ b/music_assistant/controllers/player_queues.py @@ -1674,6 +1674,7 @@ class PlayerQueuesController(CoreController): ) -> list[Track]: """Call the registered music providers for dynamic tracks.""" queue = self._queues[queue_id] + queue_track_items = [q.media_item for q in self._queue_items[queue_id] if q.media_item] if not queue.radio_source: # this may happen during race conditions as this method is called delayed return None @@ -1684,27 +1685,37 @@ class PlayerQueuesController(CoreController): ) available_base_tracks: list[Track] = [] base_track_sample_size = 5 - # Grab all the available base tracks based on the selected source items. - # shuffle the source items, just in case - for radio_item in random.sample(queue.radio_source, len(queue.radio_source)): - ctrl = self.mass.music.get_controller(radio_item.media_type) - try: - available_base_tracks += [ - track - for track in await ctrl.radio_mode_base_tracks( - radio_item.item_id, radio_item.provider + # Some providers have very deterministic similar track algorithms when providing + # a single track item. When we have a radio mode based on 1 track and we have to + # refill the queue (ie not initial radio mode), we use the play history as base tracks + if ( + len(queue.radio_source) == 1 + and queue.radio_source[0].media_type == MediaType.TRACK + and not is_initial_radio_mode + ): + available_base_tracks = queue_track_items + else: + # Grab all the available base tracks based on the selected source items. + # shuffle the source items, just in case + for radio_item in random.sample(queue.radio_source, len(queue.radio_source)): + ctrl = self.mass.music.get_controller(radio_item.media_type) + try: + available_base_tracks += [ + track + for track in await ctrl.radio_mode_base_tracks( + radio_item.item_id, radio_item.provider + ) + # Avoid duplicate base tracks + if track not in available_base_tracks + ] + except UnsupportedFeaturedException as err: + self.logger.debug( + "Skip loading radio items for %s: %s ", + radio_item.uri, + str(err), ) - # Avoid duplicate base tracks - if track not in available_base_tracks - ] - except UnsupportedFeaturedException as err: - self.logger.debug( - "Skip loading radio items for %s: %s ", - radio_item.uri, - str(err), - ) - if not available_base_tracks: - raise UnsupportedFeaturedException("Radio mode not available for source items") + if not available_base_tracks: + raise UnsupportedFeaturedException("Radio mode not available for source items") # Sample tracks from the base tracks, which will be used to calculate the dynamic ones base_tracks = random.sample( @@ -1718,17 +1729,27 @@ class PlayerQueuesController(CoreController): if dynamic_tracks: break for base_track in base_tracks: - [ - dynamic_tracks.add(track) - for track in await self.mass.music.tracks.similar_tracks( + try: + _similar_tracks = await self.mass.music.tracks.similar_tracks( base_track.item_id, base_track.provider, allow_lookup=allow_lookup, ) - if track not in base_tracks - # Ignore tracks that are too long for radio mode, e.g. mixes - and track.duration <= RADIO_TRACK_MAX_DURATION_SECS - ] + except MediaNotFoundError: + # Some providers don't have similar tracks for all items. For example, + # Tidal can sometimes return a 404 when the 'similar_tracks' endpoint is called. + # in that case, just skip the track. + self.logger.debug("No similar tracks not found for track %s", base_track.name) + continue + for track in _similar_tracks: + if ( + track not in base_tracks + # Exclude tracks we have already played / queued + and track not in queue_track_items + # Ignore tracks that are too long for radio mode, e.g. mixes + and track.duration <= RADIO_TRACK_MAX_DURATION_SECS + ): + dynamic_tracks.add(track) if len(dynamic_tracks) >= 50: break queue_tracks: list[Track] = []