diff --git a/funkwhale_cli.py b/funkwhale_cli.py index b9ba331..1c96bde 100644 --- a/funkwhale_cli.py +++ b/funkwhale_cli.py @@ -3,6 +3,7 @@ from src.fw_radios import list_radios from src.fw_artists import list_artists from src.fw_albums import list_albums from src.fw_channels import list_channels +from src.fw_playlists import list_playlists import src.settings as settings import json, sys from loguru import logger @@ -16,6 +17,7 @@ def main(): 'Artists', 'Albums', 'Channels', + 'Playlists', 'Search', 'Switch instance'] if not s.headers.get('Authorization'): @@ -31,6 +33,8 @@ def main(): list_albums() if selected == 'Channels': list_channels() + if selected == 'Playlists': + list_playlists() if selected == 'Search': search_type = fzf.prompt(('Federated', 'All types'))[0] if search_type == 'Federated': diff --git a/src/fw_api.py b/src/fw_api.py index f89ddb8..8d1050f 100644 --- a/src/fw_api.py +++ b/src/fw_api.py @@ -129,6 +129,32 @@ def get_channels(page=None, q=None, tag=None, pg=None): return r.json() +@logger.catch +def get_playlists(page=None, page_size=None, q=None, pg=None): + '''List playlists''' + params = { + 'page': page, + 'page_size': page_size, + 'q': q + } + if pg: + r = s.get(pg) + else: + r = s.get(f'https://{instance}/api/v1/playlists', params=params) + r.raise_for_status() + return r.json() + + +@logger.catch +def get_playlist_tracks(playlist_id, pg=None): + '''Retrieve all tracks in the playlist''' + if pg: + r = s.get(pg) + else: + r = s.get(f'https://{instance}/api/v1/playlists/{playlist_id}/tracks') + return r.json() + + @logger.catch def list_libraries(page=None, page_size=None, q=None, scope='all', pg=None): params = { diff --git a/src/fw_playlists.py b/src/fw_playlists.py new file mode 100644 index 0000000..0444c1e --- /dev/null +++ b/src/fw_playlists.py @@ -0,0 +1,57 @@ +from src.fw_api import get_playlists, get_playlist_tracks, concatinate_endpoint +from src.mpv_control import player, player_menu +from pyfzf.pyfzf import FzfPrompt +from loguru import logger + +fzf = FzfPrompt() + +@logger.catch +def list_playlists(pg=None, search=None): + playlists = get_playlists(q=search, pg=pg) + playlists_next = playlists.get('next') + playlists_prev = playlists.get('previous') + playlists_results = playlists.get('results') + view = ['Search'] + if playlists_next: + view.append('Next page') + if playlists_prev: + view.append('Prev page') + + for i in playlists_results: + index = playlists_results.index(i) + playlist_name = i.get('name') + view.append(f'{index}.{playlist_name}') + select = fzf.prompt(view)[0].split('.', 1)[0] + if select == 'Next page': + list_playlists(pg=playlists_next) + elif select == 'Prev page': + list_playlists(pg=playlists_prev) + elif select == 'Search': + print('Search by playlist:') + list_playlists(search=input()) + else: + play_playlist(playlist_id=playlists_results[int(select)].get('id')) + +def play_playlist(playlist_id): + tracks = get_playlist_tracks(playlist_id, pg=None) + tracks_next = tracks.get('next') + tracks_count = tracks.get('count') + storage = {} + if tracks_count > 50: + print(f'Loading {tracks_count} tracks...') + elif tracks_count == 0: + logger.warning('Empty tracks. Nothing to do') + return + while True: + tracks_results = tracks.get('results') + tracks_next = tracks.get('next') + for i in tracks_results: + track = i.get('track') + listen_url = concatinate_endpoint(track['listen_url']) + storage[listen_url] = track + player.loadfile(listen_url, 'append-play') + if tracks_next: + tracks = get_playlist_tracks(playlist=playlist_id, pg=tracks_next) + else: + break + player_menu(f"Playlist playing...", storage) diff --git a/src/settings.py b/src/settings.py index 7f430b7..dfb5ec4 100644 --- a/src/settings.py +++ b/src/settings.py @@ -1,6 +1,9 @@ import json, requests, time from os.path import exists from loguru import logger +from pyfzf.pyfzf import FzfPrompt + +fzf = FzfPrompt() conf_file = 'config.json' @@ -62,6 +65,7 @@ def check_config(): correct_conf[k] = v logger.warning(f'{k} added in config. Value: {v}') set_defaults(correct_conf) + return correct_conf if not exists(conf_file):