Add pause function and time-pos

This commit is contained in:
Nguyễn Gia Phong 2017-03-30 11:14:51 +07:00 committed by Nguyễn Gia Phong
parent 1b130724d2
commit d5117c65c8
2 changed files with 88 additions and 72 deletions

158
comp.py
View File

@ -21,48 +21,47 @@ import json
from argparse import ArgumentParser
from configparser import ConfigParser
from os.path import expanduser
from time import gmtime, strftime
import mpv
from mpv import MPV
def mpv_wrapper(media, video=True):
def initmpv(ytdl_format, video):
if video:
player = mpv.MPV(ytdl=True, input_default_bindings=True,
input_vo_keyboard=True, ytdl_format=ytdl_format)
return MPV(input_default_bindings=True, input_vo_keyboard=True,
ytdl=True, ytdl_format=ytdl_format)
else:
player = mpv.MPV(ytdl=True, input_default_bindings=True,
input_vo_keyboard=True, vid=False,
ytdl_format=ytdl_format)
player.play(media)
player.wait_for_playback()
del player
return MPV(input_default_bindings=True, input_vo_keyboard=True,
ytdl=True, ytdl_format=ytdl_format, vid=False)
def reattr(stdscr, y, track):
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 setno(data, keys):
"""Set all keys of each track in data to False."""
for key in keys:
for track in data:
track[key] = False
def reprint(stdscr, data2print):
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(data2print):
y = i + 1
stdscr.addstr(y, 0, d['url'].rjust(curses.COLS - 1))
stdscr.addstr(y, 0, d['title'][:curses.COLS-12])
reattr(stdscr, y, data[start + i])
def secpair2hhmmss(pos, duration):
"""Quick hack to convert a pair of seconds to HHMMSS / HHMMSS
string as MPV.get_property_osd_string isn't available.
"""
if pos is None:
return ''
postime, durationtime = gmtime(pos), gmtime(duration)
# Let's hope media durations are shorter than a day
timestr = '%M:%S' if duration < 3600 else '%H:%M:%S'
return '{} / {}'.format(strftime(timestr, postime),
strftime(timestr, durationtime))
def updatestatusline(stdscr):
stdscr.addstr(curses.LINES - 2, 1, '{} {}'.format(
'|' if mp._get_property('pause', bool) else '>',
secpair2hhmmss(mp._get_property('time-pos', int),
mp._get_property('duration', int))
))
stdscr.addstr(
curses.LINES - 2,
curses.COLS - 16,
@ -72,46 +71,61 @@ def reprint(stdscr, data2print):
stdscr.refresh()
def reprint(stdscr, data2print):
stdscr.clear()
stdscr.addstr(0, curses.COLS-12, 'URL')
stdscr.addstr(0, 1, 'Title')
stdscr.chgat(0, 0, curses.color_pair(10) | curses.A_BOLD)
for i, track in enumerate(data2print):
y = i + 1
stdscr.addstr(y, 0, track['url'].rjust(curses.COLS - 1))
stdscr.addstr(y, 1, track['title'][:curses.COLS-12])
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)
updatestatusline(stdscr)
def move(stdscr, data, y, delta):
global start
reattr(stdscr, y, data[start + y - 1])
if start + y + delta < 1:
start = 0
reprint(stdscr, data[:curses.LINES-3])
stdscr.move(1, 0)
setno(data, ['highlight'])
data[0]['highlight'] = True
reattr(stdscr, 1, data[start])
data[0]['highlight'] = False
reprint(stdscr, data[:curses.LINES-3])
return 1
elif start + y + delta > len(data):
start = len(data) - curses.LINES + 3
reprint(stdscr, data[-curses.LINES+3:])
y = curses.LINES - 3
stdscr.move(y, 0)
setno(data, ['highlight'])
data[-1]['highlight'] = True
reattr(stdscr, y, data[start + y - 1])
data[-1]['highlight'] = False
reprint(stdscr, data[-curses.LINES+3:])
return y
if 0 < y + delta < curses.LINES - 2:
y = y + delta
elif y + delta < 1:
start += y + delta - 1
reprint(stdscr, data[start : start+curses.LINES-3])
y = 1
else:
start += y + delta - curses.LINES + 3
reprint(stdscr, data[start : start+curses.LINES-3])
y = curses.LINES - 3
stdscr.move(y, 0)
setno(data, ['highlight'])
data[start + y - 1]['highlight'] = True
reattr(stdscr, y, data[start + y - 1])
data[start + y - 1]['highlight'] = False
reprint(stdscr, data[start : start+curses.LINES-3])
stdscr.refresh()
return y
parser = ArgumentParser(description="console/curses online media player")
parser = ArgumentParser(description="console/curses online media mp")
parser.add_argument('-j', '--json-playlist', required=False,
help='path to playlist in JSON format')
args = parser.parse_args()
@ -125,12 +139,7 @@ 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
setno(data, ['error', 'playing', 'selected', 'highlight'])
stdscr = curses.initscr()
curses.noecho()
@ -154,43 +163,50 @@ curses.init_pair(12, -1, 4)
curses.init_pair(13, -1, 5)
curses.init_pair(14, -1, 6)
mp = initmpv(ytdl_format, video)
mp.observe_property('time-pos', lambda pos: updatestatusline(stdscr))
# Print initial content
start = 0
reprint(stdscr, data[:curses.LINES-3])
y = 1
data[0]['highlight'] = True
stdscr.move(1, 0)
reattr(stdscr, 1, data[start])
data[0]['highlight'] = False
reprint(stdscr, data[:curses.LINES-3])
# mpv keys: []{}<>.,qQ/*90m-#fTweoPOvjJxzlLVrtsSIdA
# yuighkcbn
c = stdscr.getch()
while c != 113: # letter q
if c == curses.KEY_RESIZE:
curses.update_lines_cols()
reprint(stdscr, data[start : start+curses.LINES-3])
y = 1
reattr(stdscr, 1, data[start])
elif c in (ord('j'), curses.KEY_DOWN):
move(stdscr, data, y, 1 - y)
y = move(stdscr, data, 1, y - 1)
elif c in (106, curses.KEY_DOWN): # letter j or down arrow
y = move(stdscr, data, y, 1)
elif c in (ord('k'), curses.KEY_UP):
elif c in (107, curses.KEY_UP): # letter k or up arrow
y = move(stdscr, data, y, -1)
elif c == curses.KEY_PPAGE:
elif c == curses.KEY_PPAGE: # page up
y = move(stdscr, data, y, -curses.LINES)
elif c == curses.KEY_NPAGE:
elif c == curses.KEY_NPAGE: # page down
y = move(stdscr, data, y, curses.LINES)
elif c == curses.KEY_HOME:
elif c == curses.KEY_HOME: # home
y = move(stdscr, data, y, -len(data))
elif c == curses.KEY_END:
elif c == curses.KEY_END: # end
y = move(stdscr, data, y, len(data))
elif c == ord(' '):
elif c == 32: # space
setno(data, ['playing'])
mp.play('https://youtu.be/' + data[start + y - 1]['url'])
data[start + y - 1]['playing'] = True
reprint(stdscr, data[start : start+curses.LINES-3])
elif c == 112: # letter p
mp._set_property('pause', not mp._get_property('pause', bool), bool)
elif c == 99: # letter c
data[start + y - 1]['selected'] = not data[start + y - 1]['selected']
y = move(stdscr, data, y, 1)
elif c == ord('x'): # temporally behavior
mpv_wrapper('https://youtu.be/' + data[start + y - 1]['url'], video)
stdscr.refresh()
c = stdscr.getch()
curses.nocbreak()
stdscr.keypad(False)
curses.echo()
curses.endwin()
del mp

View File

@ -12,7 +12,7 @@ setup(name = 'comp', version = '0.1.0a1',
author = 'McSinyx', author_email = 'vn.mcsinyx@gmail.com',
py_modules = ['mpv'], scripts=['comp.py'],
classifiers = [
'Development Status :: 1 - Planning',
'Development Status :: 2 - Pre-alpha',
'Environment :: Console :: Curses',
'Intended Audience :: End Users/Desktop',
'License :: OSI Approved :: GNU Affero General Public License v3',