From 202280f760fe62e7eb45dbf9bda5705171c878da Mon Sep 17 00:00:00 2001 From: Raphael McSinyx Date: Thu, 23 Mar 2017 21:37:52 +0700 Subject: [PATCH] Add bottom panel and improve data structure --- comp.py | 92 ++++++++++++++++++++++++++++++++++++++++---------------- setup.py | 13 ++++++-- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/comp.py b/comp.py index 53c8907..078f4f3 100755 --- a/comp.py +++ b/comp.py @@ -3,6 +3,8 @@ import curses import json from argparse import ArgumentParser +from configparser import ConfigParser +from os.path import expanduser import mpv @@ -10,35 +12,46 @@ import mpv def mpv_wrapper(media, video=True): if video: player = mpv.MPV(ytdl=True, input_default_bindings=True, - input_vo_keyboard=True) + input_vo_keyboard=True, ytdl_format=ytdl_format) else: player = mpv.MPV(ytdl=True, input_default_bindings=True, - input_vo_keyboard=True, vid=False) - player.register_key_binding('b', player.quit_watch_later) + input_vo_keyboard=True, vid=False, + ytdl_format=ytdl_format) player.play(media) player.wait_for_playback() del player def interface(stdscr): - def reattr(y, highlight=False): - if DATA[start + y - 1]['selected'] and highlight: - stdscr.chgat(y, 0, curses.color_pair(11) | curses.A_BOLD) - elif DATA[start + y - 1]['selected']: - stdscr.chgat(y, 0, curses.color_pair(3) | curses.A_BOLD) - elif highlight: + def reattr(y): + track = DATA[start + y - 1] + invert = 8 if track['highlight'] else 0 + if track['error']: + stdscr.chgat(y, 0, curses.color_pair(1 + invert) | curses.A_BOLD) + elif track['playing']: + stdscr.chgat(y, 0, curses.color_pair(3 + invert) | curses.A_BOLD) + elif track['selected']: + stdscr.chgat(y, 0, curses.color_pair(5 + invert) | curses.A_BOLD) + elif invert: stdscr.chgat(y, 0, curses.color_pair(12) | curses.A_BOLD) else: stdscr.chgat(y, 0, curses.color_pair(0) | curses.A_NORMAL) def reprint(): + stdscr.clear() stdscr.addstr(0, curses.COLS-12, 'URL') stdscr.addstr(0, 0, 'Title') stdscr.chgat(0, 0, curses.color_pair(10) | curses.A_BOLD) - for i, d in enumerate(DATA[start : start+curses.LINES-1]): + for i, d in enumerate(DATA[start : start+curses.LINES-3]): stdscr.addstr(i + 1, 0, d['url'].rjust(curses.COLS - 1)) stdscr.addstr(i + 1, 0, d['title'][:curses.COLS-12]) reattr(i + 1) + stdscr.addstr( + curses.LINES - 2, + curses.COLS - 16, + '{:7} {:8}'.format(mode, 'selected' if selected else 'all') + ) + stdscr.chgat(curses.LINES - 2, 0, curses.color_pair(8)) stdscr.refresh() def move(y, delta): @@ -48,28 +61,34 @@ def interface(stdscr): start = 0 reprint() stdscr.move(1, 0) - reattr(1, True) + DATA[0]['highlight'] = True + reattr(1) + DATA[0]['highlight'] = False return 1 elif start + y + delta > len(DATA): - start = len(DATA) - curses.LINES + 1 + start = len(DATA) - curses.LINES + 3 reprint() - y = curses.LINES - 1 + y = curses.LINES - 3 stdscr.move(y, 0) - reattr(y, True) + DATA[-1]['highlight'] = True + reattr(y) + DATA[-1]['highlight'] = False return y - if 0 < y + delta < curses.LINES: + if 0 < y + delta < curses.LINES - 2: y = y + delta elif y + delta < 1: start += y + delta - 1 reprint() y = 1 else: - start += y + delta - curses.LINES + 1 + start += y + delta - curses.LINES + 3 reprint() - y = curses.LINES - 1 + y = curses.LINES - 3 stdscr.move(y, 0) - reattr(y, True) + DATA[start + y - 1]['highlight'] = True + reattr(y) + DATA[start + y - 1]['highlight'] = False stdscr.refresh() return y @@ -92,16 +111,22 @@ def interface(stdscr): curses.curs_set(False) # Print initial content - stdscr.clear() start = 0 reprint() y = 1 - stdscr.move(y, 0) - reattr(y, True) + DATA[0]['highlight'] = True + stdscr.move(1, 0) + reattr(1) + DATA[0]['highlight'] = False while True: c = stdscr.getch() - if c in (ord('j'), curses.KEY_DOWN): + if c == curses.KEY_RESIZE: + curses.update_lines_cols() + reprint() + y = 1 + reattr(y) + elif c in (ord('j'), curses.KEY_DOWN): y = move(y, 1) elif c in (ord('k'), curses.KEY_UP): y = move(y, -1) @@ -116,10 +141,15 @@ def interface(stdscr): elif c == ord(' '): DATA[start + y - 1]['selected'] = not DATA[start + y - 1]['selected'] y = move(y, 1) - elif c == ord('c'): # temporally behavior - mpv_wrapper('https://youtu.be/' + DATA[start + y - 1]['url']) + elif c == ord('x'): # temporally behavior + mpv_wrapper('https://youtu.be/' + DATA[start + y - 1]['url'], video) + elif c == ord('v'): + player.quit_watch_later() elif c in (ord('q'), 27): # 27 is Escape key - break + stdscr.addstr(curses.LINES - 1, 0, 'Quit comp? [y/N]') + if stdscr.getch() == ord('y'): + break + reprint() stdscr.refresh() @@ -127,9 +157,19 @@ parser = ArgumentParser(description="console/curses online media player") parser.add_argument('-j', '--json-playlist', required=False, help='path to playlist in JSON format') args = parser.parse_args() + +config = ConfigParser() +config.read(expanduser('~/.config/comp/settings.ini')) +ytdl_format = config.get('Init', 'ytdl-format', fallback='best') +mode = config.get('Runtime', 'play-mode', fallback='normal') +selected = config.getboolean('Runtime', 'play-selected-only', fallback=False) +video = config.getboolean('Runtime', 'video', fallback=True) + with open(args.json_playlist) as f: DATA = json.load(f) for i in DATA: + i['error'] = False + i['playing'] = False i['selected'] = False - + i['highlight'] = False curses.wrapper(interface) diff --git a/setup.py b/setup.py index 650ad08..0c393b7 100755 --- a/setup.py +++ b/setup.py @@ -12,7 +12,16 @@ setup(name = 'comp', long_description=long_description, author = 'McSinyx', author_email = 'vn.mcsinyx@gmail.com', - license = 'AGPLv2', py_modules = ['mpv'], - scripts=['comp'] + scripts=['comp'], + classifiers = ['Development Status :: 1 - Planning', + 'Environment :: Console :: Curses', + 'Intended Audience :: End Users/Desktop', + 'Natural Language :: English', + 'Natural Language :: Vietnamese', # planned + 'Operating System :: POSIX', + 'Programming Language :: Python :: 3.5', + 'Topic :: Multimedia :: Sound/Audio :: Players', + 'Topic :: Multimedia :: Video :: Display'], + license = 'AGPLv2' )