subclient

Subsonic ncurses client
git clone https://git.e1e0.net/subclient.git
Log | Files | Refs | README

commit 43d1062cc6c524fe6886dd4f26fc68b5ae393f89
parent e70610b698c890548db9dc477ba9edef1734fd72
Author: Paco Esteban <paco@e1e0.net>
Date:   Thu, 24 Jun 2021 20:32:02 +0200

I hate py_cui, trying to get ride of it.  Part I

Diffstat:
Mrequirements.txt | 1-
Msubclient/subclient.py | 228+++++++++++--------------------------------------------------------------------
2 files changed, 32 insertions(+), 197 deletions(-)

diff --git a/requirements.txt b/requirements.txt @@ -1,2 +1 @@ py-sonic==0.7.9 -py-cui==0.1.3 diff --git a/subclient/subclient.py b/subclient/subclient.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 +# -*- coding: utf-8 -*- import configparser +import curses from subclient import subsonic -from subclient import helpers -from subclient import playback import os -import py_cui __version__ = 'v0.0.1' @@ -21,205 +20,42 @@ def get_config_file(): class SubClient: - - def __init__(self, master: py_cui.PyCUI): - + def __init__(self): self.config = configparser.ConfigParser() self.config.read(get_config_file()) self.subsonic = subsonic.Subsonic(self.config['subclient']) - self.player = playback.Player() - self.master = master - self.current_artist = None - self.current_album = None - self.current_song = None - self.playlist = [] - self.what = 0 - - self.master.add_key_command(py_cui.keys.KEY_SPACE, self.pause) - # The scrolled list cells that will contain our tasks in each of the - # three categories - self.nav_scroll_cell = self.master.add_scroll_menu( - 'Artists', 0, 0, row_span=4, column_span=1) - self.play_scroll_cell = self.master.add_scroll_menu( - 'Playlist', 0, 1, row_span=4, column_span=1) - self.now_playing_block = self.master.add_block_label( - 'Now', 4, 0, row_span=1, column_span=2) - - # self.master.add_key_command(py_cui.keys.KEY_Q_LOWER, self._exit) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_ENTER, - self.play_from_here) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_TAB, - self._switch_to_play) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_SPACE, - self.pause) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_Q_LOWER, - self.quit) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_H_LOWER, - self._nav_back) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_J_LOWER, - self._nav_down) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_K_LOWER, - self._nav_up) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_L_LOWER, - self._nav_forward) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_G_LOWER, - self._nav_top) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_G_UPPER, - self._nav_bottom) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_F_LOWER, - self.song_seek_fwd_short) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_F_UPPER, - self.song_seek_fwd_long) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_B_LOWER, - self.song_seek_bck_short) - self.nav_scroll_cell.add_key_command(py_cui.keys.KEY_B_UPPER, - self.song_seek_bck_long) - self.play_scroll_cell.add_key_command(py_cui.keys.KEY_TAB, - self._switch_to_nav) - self.play_scroll_cell.add_key_command(py_cui.keys.KEY_SPACE, - self.pause) - self.play_scroll_cell.add_key_command(py_cui.keys.KEY_Q_LOWER, - self.quit) - - status_bar_text = ('Quit - q | Enter - play/pause | ' - 'j/k - up/down | h/l - back/forward' - 'Cycle windows - tab') - self.nav_scroll_cell.set_focus_text(status_bar_text) - self.play_scroll_cell.set_focus_text(status_bar_text) - - self.update_nav() - self.master.move_focus(self.nav_scroll_cell) - - def update_nav(self, back=False): - if self.what == 0: - items = self.subsonic.get_artists() - self.nav_scroll_cell.set_title('Artists') - elif self.what == 1: - if not back: - self.current_artist = self.nav_scroll_cell.get() - items = self.subsonic.get_albums_from_artist(self.current_artist) - self.nav_scroll_cell.set_title(self.current_artist.name) - elif self.what == 2: - if not back: - self.current_album = self.nav_scroll_cell.get() - items = self.subsonic.get_songs_from_album(self.current_album) - self.curr_album_songs = items - self.nav_scroll_cell.set_title( - self.current_artist.name - + ' | ' - + self.current_album.title) - else: - raise Exception('unknown nav update') - self.nav_scroll_cell.clear() - self.nav_scroll_cell.add_item_list(items) - - def play_from_here(self): - if self.what == 2: - self.current_song = self.nav_scroll_cell.get() - self.update_playlist() - self.play_song() - else: - self._nav_forward() - - def update_playlist(self): - self.playlist = self.curr_album_songs[ - self.curr_album_songs.index(self.current_song):] - self.play_scroll_cell.clear() - self.play_scroll_cell.add_item_list(self.playlist) - - def play_song(self): - self._now_playing('Now Playing', self.playlist[0]) - stream = self.subsonic.get_song_stream(self.playlist[0]) - if not self.player.is_idle(): - self.player.stop() - self.player.play(stream, self.next_song) - - def next_song(self, event): - if len(self.playlist) > 0: - del self.playlist[0] - self.current_song = self.playlist[0] - self.update_playlist() - self.play_song() - - def pause(self): - paused = self.player.is_paused() - state = 'Paused' - if paused: - state = 'Now Playing' - self._now_playing(state, self.current_song) - self.player.set_pause(not paused) - - def song_seek_fwd_short(self): - self._song_seek('+5') - - def song_seek_bck_short(self): - self._song_seek('-5') - - def song_seek_fwd_long(self): - self._song_seek('+20') - - def song_seek_bck_long(self): - self._song_seek('-20') - - def _song_seek(self, duration='+5'): - self.player.seek(duration) - - def _now_playing(self, state, song): - self.now_playing_block.set_title( - f'{state}:\n' - f'{song.title} ({helpers.format_duration(song.duration)})') - - def _switch_to_nav(self): - self.master.move_focus(self.nav_scroll_cell) - - def _switch_to_play(self): - self.master.move_focus(self.play_scroll_cell) - - def _nav_down(self): - self.nav_scroll_cell._scroll_down( - self.nav_scroll_cell.get_viewport_height()) - - def _nav_up(self): - self.nav_scroll_cell._scroll_up() - - def _nav_top(self): - self.nav_scroll_cell.set_selected_item_index(0) - self.nav_scroll_cell._jump_to_top() - - def _nav_bottom(self): - max_len = len(self.nav_scroll_cell.get_item_list()) - 1 - self.nav_scroll_cell.set_selected_item_index(max_len) - self.nav_scroll_cell._jump_to_bottom( - self.nav_scroll_cell.get_viewport_height()) - - def _nav_back(self): - self.what -= 1 - if self.what < 0: - self.what = 0 - return - self.update_nav(back=True) - - def _nav_forward(self): - self.what += 1 - if self.what > 2: - self.what = 2 - return - self.update_nav() - - def quit(self): - if self.player.is_idle(): - self.player.stop() - self.player.exit() - self.master.stop() + self.artists = self.subsonic.get_artists() + + def load_artists(self): + for i, artist in enumerate(self.artists): + self.nav_win.addstr(i, 0, artist.name) + + def refresh(self): + self.stdscr.noutrefresh() + self.nav_win.noutrefresh(0, 0, 0, 0, curses.LINES - 1, curses.COLS - 1) + curses.doupdate() + + def main_loop(self): + while True: + c = self.stdscr.getkey() + if c == 'q': # quit + break + elif c == 'j': + self.stdscr.clear() + + def start(self, stdscr): + self.stdscr = stdscr + self.nav_win = curses.newpad(len(self.artists) + 1, curses.COLS - 1) + self.stdscr.clear() + curses.curs_set(0) # disable cursor + self.load_artists() + self.refresh() + self.main_loop() def main(): - root = py_cui.PyCUI(5, 2) - # enable unicode box chars - root.toggle_unicode_borders() - root.set_title('SubsonicClient') - wrapper = SubClient(root) - root.start() + subclient = SubClient() + curses.wrapper(subclient.start) if __name__ == "__main__":