From: Marcel van der Veldt Date: Sun, 31 Jul 2022 22:49:19 +0000 (+0200) Subject: Improve Radio feature for mixed playlists (#444) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=44ab3b3d83ae7723d9c4ceb7811e019d82b845d9;p=music-assistant-server.git Improve Radio feature for mixed playlists (#444) * remove legacy get_by_name methods * Improve radio feature for mixed playlists --- diff --git a/music_assistant/controllers/media/playlists.py b/music_assistant/controllers/media/playlists.py index 69baf852..60208164 100644 --- a/music_assistant/controllers/media/playlists.py +++ b/music_assistant/controllers/media/playlists.py @@ -1,8 +1,8 @@ """Manage MediaItems of type Playlist.""" from __future__ import annotations +import random from ctypes import Union -from random import choice, random from time import time from typing import Any, List, Optional, Tuple @@ -34,10 +34,6 @@ class PlaylistController(MediaControllerBase[Playlist]): media_type = MediaType.PLAYLIST item_cls = Playlist - async def get_playlist_by_name(self, name: str) -> Playlist | None: - """Get in-library playlist by name.""" - return await self.mass.database.get_row(self.db_table, {"name": name}) - async def tracks( self, item_id: str, @@ -301,21 +297,29 @@ class PlaylistController(MediaControllerBase[Playlist]): playlist_tracks = await self._get_provider_playlist_tracks( item_id=item_id, provider=provider, provider_id=provider_id ) - # Grab a random track from the playlist that we use to obtain similar tracks for - track = choice(playlist_tracks) - # Calculate no of songs to grab from each list at a 50/50 ratio - total_no_of_tracks = limit + limit % 2 - tracks_per_list = int(total_no_of_tracks / 2) - # Grab similar tracks from the music provider - similar_tracks = await prov.get_similar_tracks( - prov_track_id=track.item_id, limit=tracks_per_list - ) - # Merge playlist content with similar tracks - dynamic_playlist = [ - *sorted(playlist_tracks, key=lambda n: random())[:tracks_per_list], - *sorted(similar_tracks, key=lambda n: random())[:tracks_per_list], - ] - return sorted(dynamic_playlist, key=lambda n: random()) + # filter out unavailable tracks + playlist_tracks = [x for x in playlist_tracks if x.available] + limit = min(limit, len(playlist_tracks)) + # use set to prevent duplicates + final_items = set() + # to account for playlists with mixed content we grab suggestions from a few + # random playlist tracks to prevent getting too many tracks of one of the + # source playlist's genres. + while len(final_items) < limit: + # grab 5 random tracks from the playlist + base_tracks = random.sample(playlist_tracks, 5) + # add the source/base playlist tracks to the final list... + final_items.update(base_tracks) + # get 5 suggestions for one of the base tracks + base_track = next(x for x in base_tracks if x.available) + similar_tracks = await prov.get_similar_tracks( + prov_track_id=base_track.item_id, limit=5 + ) + final_items.update(x for x in similar_tracks if x.available) + + # NOTE: In theory we can return a few more items than limit here + # Shuffle the final items list + return random.sample(final_items, len(final_items)) async def _get_dynamic_tracks( self, media_item: Playlist, limit: int = 25 diff --git a/music_assistant/controllers/media/radio.py b/music_assistant/controllers/media/radio.py index 3ba04d59..e9a44227 100644 --- a/music_assistant/controllers/media/radio.py +++ b/music_assistant/controllers/media/radio.py @@ -22,10 +22,6 @@ class RadioController(MediaControllerBase[Radio]): media_type = MediaType.RADIO item_cls = Radio - async def get_radio_by_name(self, name: str) -> Radio | None: - """Get in-library radio by name.""" - return await self.mass.database.get_row(self.db_table, {"name": name}) - async def versions( self, item_id: str,