Fix JSON playlist dumper and edit keybindings
This commit is contained in:
parent
04901f33d9
commit
ba3a065006
119
README.rst
119
README.rst
|
@ -35,7 +35,6 @@ Command line options
|
|||
|
||||
::
|
||||
|
||||
$ comp --help
|
||||
usage: comp [-h] [-e {json,mpv,youtube-dl}] [-c CONFIG] [--vid VID]
|
||||
[--vo DRIVER] [-f YTDL_FORMAT]
|
||||
playlist
|
||||
|
@ -47,6 +46,7 @@ Command line options
|
|||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --version show program's version number and exit
|
||||
-e {json,mpv,youtube-dl}, --extractor {json,mpv,youtube-dl}
|
||||
playlist extractor, default is youtube-dl
|
||||
-c CONFIG, --config CONFIG
|
||||
|
@ -73,55 +73,74 @@ Open a Youtube playlist with video height lower than 720::
|
|||
Keyboard control
|
||||
----------------
|
||||
|
||||
+--------------+----------------------------------------------+
|
||||
| Key | Action |
|
||||
+==============+==============================================+
|
||||
| Return | Start playing |
|
||||
+--------------+----------------------------------------------+
|
||||
| Space | Select the current track |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``/``, ``?`` | Search forward/backward for a pattern |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``<``, ``>`` | Go backward/forward in the playlist |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``A`` | Toggle mute |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``N`` | Repeat previous search in reverse direction |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``V`` | Toggle video |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``W`` | Save the current playlist under JSON format |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``d`` | Delete current entry |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``i`` | Insert playlist |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``m``, ``M`` | Cycle forward/backward through playing modes |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``n`` | Repeat previous search |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``p`` | Toggle pause |
|
||||
+--------------+----------------------------------------------+
|
||||
| ``o`` | Open playlist |
|
||||
+--------------+----------------------------------------------+
|
||||
| Up, ``k`` | Move a single line up |
|
||||
+--------------+----------------------------------------------+
|
||||
| Down, ``j`` | Move a single line down |
|
||||
+--------------+----------------------------------------------+
|
||||
| Left, ``h`` | Seek backward 5 seconds |
|
||||
+--------------+----------------------------------------------+
|
||||
| Right, ``l`` | Seek forward 5 seconds |
|
||||
+--------------+----------------------------------------------+
|
||||
| Home | Move to the beginning of the playlist |
|
||||
+--------------+----------------------------------------------+
|
||||
| End | Move to the end of the playlist |
|
||||
+--------------+----------------------------------------------+
|
||||
| Page Up | Move a single page up |
|
||||
+--------------+----------------------------------------------+
|
||||
| Page Down | Move a single page down |
|
||||
+--------------+----------------------------------------------+
|
||||
| F5 | Redraw the screen content |
|
||||
+--------------+----------------------------------------------+
|
||||
Return
|
||||
Start playing.
|
||||
|
||||
Space, ``p``
|
||||
Toggle pause.
|
||||
|
||||
``/``, ``?``
|
||||
Search forward/backward for a pattern.
|
||||
|
||||
``<``, ``>``
|
||||
Go backward/forward in the playlist.
|
||||
|
||||
``A``
|
||||
Toggle mute.
|
||||
|
||||
``D``
|
||||
Delete the current entry.
|
||||
|
||||
``N``
|
||||
Repeat previous search in reverse direction.
|
||||
|
||||
``V``
|
||||
Toggle video.
|
||||
|
||||
``W``
|
||||
Save the current playlist under JSON format.
|
||||
|
||||
``d``
|
||||
Deselect/reselect the current entry.
|
||||
|
||||
``i``
|
||||
Insert playlist.
|
||||
|
||||
``m``, ``M``
|
||||
Cycle forward/backward through playing modes.
|
||||
|
||||
``n``
|
||||
Repeat previous search.
|
||||
|
||||
``o``
|
||||
Open playlist.
|
||||
|
||||
Up, ``k``
|
||||
Move a single line up.
|
||||
|
||||
Down, ``j``
|
||||
Move a single line down.
|
||||
|
||||
Left, ``h``
|
||||
Seek backward 5 seconds.
|
||||
|
||||
Right, ``l``
|
||||
Seek forward 5 seconds.
|
||||
|
||||
Home
|
||||
Move to the beginning of the playlist.
|
||||
|
||||
End
|
||||
Move to the end of the playlist.
|
||||
|
||||
Page Up
|
||||
Move a single page up.
|
||||
|
||||
Page Down
|
||||
Move a single page down.
|
||||
|
||||
F5
|
||||
Redraw the screen content.
|
||||
|
||||
Configuration files
|
||||
-------------------
|
||||
|
|
41
comp
41
comp
|
@ -102,15 +102,16 @@ class Comp(Omp):
|
|||
|
||||
if self.mp.osd.duration is not None:
|
||||
self.played[self.playing]['duration'] = self.mp.osd.duration
|
||||
add_status_str(self.mp.osd.time_pos or '00:00:00', X=8)
|
||||
add_status_str('/', x=9, X=10)
|
||||
add_status_str(self.mp.osd.duration or '00:00:00', x=11, X=19)
|
||||
add_status_str('|' if self.mp.pause else '>', x=20, X=21)
|
||||
add_status_str((self.mp.media_title or b'').decode(), x=22,
|
||||
add_status_str(':', X=5, lpad=3)
|
||||
if self.vid != 'no': add_status_str('V', x=1, X=2)
|
||||
if not self.mp.mute: add_status_str('A', X=1)
|
||||
add_status_str(self.mp.osd.time_pos or '00:00:00', x=4, X=12)
|
||||
add_status_str('/', x=13, X=14)
|
||||
add_status_str(self.mp.osd.duration or '00:00:00', x=15, X=23)
|
||||
add_status_str('|' if self.mp.pause else '>', x=24, X=25)
|
||||
add_status_str((self.mp.media_title or b'').decode(), x=26,
|
||||
attr=curses.color_pair(12)|curses.A_BOLD)
|
||||
add_status_str(_(self.mode), x=-5-len(_(self.mode)))
|
||||
if not self.mp.mute: add_status_str('A', x=-4, X=-3)
|
||||
if self.vid != 'no': add_status_str('V', x=-2, lpad=0)
|
||||
add_status_str(_(self.mode), x=-2-len(_(self.mode)))
|
||||
self.scr.refresh()
|
||||
|
||||
def print_msg(self, message, error=False):
|
||||
|
@ -326,6 +327,8 @@ class Comp(Omp):
|
|||
|
||||
|
||||
parser = ArgumentParser(description=_("Curses Omni Media Player"))
|
||||
parser.add_argument('-v', '--version', action='version',
|
||||
version='%(prog)s 0.3.10')
|
||||
parser.add_argument('-e', '--extractor', default='youtube-dl',
|
||||
choices=('json', 'mpv', 'youtube-dl'), required=False,
|
||||
help=_("playlist extractor, default is youtube-dl"))
|
||||
|
@ -360,9 +363,8 @@ with Comp(entries, json_file, mode, vid, vo, ytdlf) as comp:
|
|||
if c == 10: # curses.KEY_ENTER doesn't work
|
||||
comp.update_playlist()
|
||||
comp.next(force=True)
|
||||
elif c == 32: # space
|
||||
comp.current()['selected'] = not comp.current().get('selected')
|
||||
comp.move(1)
|
||||
elif c in (32, 112): # space or letter p
|
||||
comp.mp.pause ^= True
|
||||
elif c == 47: # /
|
||||
comp.search()
|
||||
elif c == 60: # <
|
||||
|
@ -379,6 +381,13 @@ with Comp(entries, json_file, mode, vid, vo, ytdlf) as comp:
|
|||
comp.search(backward=True)
|
||||
elif c == 65: # letter A
|
||||
comp.mp.mute ^= True # hack to toggle bool value
|
||||
elif c == 68: # letter D
|
||||
comp.entries.pop(comp.idx())
|
||||
if 1 < len(comp.entries) - curses.LINES + 4 == comp.start:
|
||||
comp.start -= 1
|
||||
elif comp.idx() == len(comp.entries):
|
||||
comp.y -= 1
|
||||
comp.refresh()
|
||||
elif c == 77: # letter M
|
||||
comp.mode = MODES[(MODES.index(comp.mode) - 1) % 8]
|
||||
comp.update_status()
|
||||
|
@ -391,12 +400,8 @@ with Comp(entries, json_file, mode, vid, vo, ytdlf) as comp:
|
|||
elif c == 87: # letter W
|
||||
comp.dump_json()
|
||||
elif c == 100: # letter d
|
||||
comp.entries.pop(comp.idx())
|
||||
if 1 < len(comp.entries) - curses.LINES + 4 == comp.start:
|
||||
comp.start -= 1
|
||||
elif comp.idx() == len(comp.entries):
|
||||
comp.y -= 1
|
||||
comp.refresh()
|
||||
comp.current()['selected'] = not comp.current().get('selected')
|
||||
comp.move(1)
|
||||
elif c == 105: # letter i
|
||||
extractor = comp.read_input(_("Playlist extractor: "))
|
||||
filename = comp.read_input(_("Insert: "))
|
||||
|
@ -425,8 +430,6 @@ with Comp(entries, json_file, mode, vid, vo, ytdlf) as comp:
|
|||
else:
|
||||
comp.entries, comp.start, comp.y = entries, 0, 1
|
||||
comp.refresh()
|
||||
elif c == 112: # letter p
|
||||
comp.mp.pause ^= True
|
||||
elif c in (curses.KEY_UP, 107): # up arrow or letter k
|
||||
comp.move(-1)
|
||||
elif c in (curses.KEY_DOWN, 106): # down arrow or letter j
|
||||
|
|
58
doc/comp.1
58
doc/comp.1
|
@ -25,6 +25,9 @@ path or URL to the playlist
|
|||
.B -h, --help
|
||||
show this help message and exit
|
||||
.TP
|
||||
.B -v, --version
|
||||
show program's version number and exit
|
||||
.TP
|
||||
.B -e \fR{json,mpv,youtube-dl}, \fB--extractor \fR{json,mpv,youtube-dl}
|
||||
playlist extractor, default is \fIyoutube-dl
|
||||
.TP
|
||||
|
@ -46,76 +49,73 @@ video format/quality to be passed to youtube-dl
|
|||
.SH KEYBOARD CONTROL
|
||||
.TP
|
||||
.B Return
|
||||
start playing
|
||||
Start playing.
|
||||
.TP
|
||||
.B Space
|
||||
select the current track
|
||||
.B Space, p
|
||||
Toggle pause.
|
||||
.TP
|
||||
.B /, ?
|
||||
search forward/backward for a pattern
|
||||
Search forward/backward for a pattern.
|
||||
.TP
|
||||
.B <, >
|
||||
go backward/forward in the playlist
|
||||
Go backward/forward in the playlist.
|
||||
.TP
|
||||
.B A
|
||||
toggle mute
|
||||
Toggle mute.
|
||||
.TP
|
||||
.B D
|
||||
Delete the current entry.
|
||||
.TP
|
||||
.B N
|
||||
repeat previous search in reverse direction
|
||||
Repeat previous search in reverse direction.
|
||||
.TP
|
||||
.B V
|
||||
toggle video
|
||||
Toggle video.
|
||||
.TP
|
||||
.B W
|
||||
save the current playlist under JSON format
|
||||
Save the current playlist under JSON format.
|
||||
.TP
|
||||
.B d
|
||||
delete current entry
|
||||
Deselect/reselect the current entry.
|
||||
.TP
|
||||
.B i
|
||||
insert playlist
|
||||
Insert playlist.
|
||||
.TP
|
||||
.B m, M
|
||||
cycle forward/backward through playing modes
|
||||
Cycle forward/backward through playing modes.
|
||||
.TP
|
||||
.B n
|
||||
repeat previous search
|
||||
.TP
|
||||
.B p
|
||||
toggle pause
|
||||
Repeat previous search.
|
||||
.TP
|
||||
.B o
|
||||
open playlist
|
||||
.TP
|
||||
.B w
|
||||
download tracks set by playing mode
|
||||
Open playlist.
|
||||
.TP
|
||||
.B Up, k
|
||||
move a single line up
|
||||
Move a single line up.
|
||||
.TP
|
||||
.B Down, j
|
||||
move a single line down
|
||||
Move a single line down.
|
||||
.TP
|
||||
.B Left, h
|
||||
seek backward 5 seconds
|
||||
Seek backward 5 seconds.
|
||||
.TP
|
||||
.B Right, l
|
||||
seek forward 5 seconds
|
||||
Seek forward 5 seconds.
|
||||
.TP
|
||||
.B Home
|
||||
move to the beginning of the playlist
|
||||
Move to the beginning of the playlist.
|
||||
.TP
|
||||
.B End
|
||||
move to the end of the playlist
|
||||
Move to the end of the playlist.
|
||||
.TP
|
||||
.B Page Up
|
||||
move a single page up
|
||||
Move a single page up.
|
||||
.TP
|
||||
.B Page Down
|
||||
move a single page down
|
||||
Move a single page down.
|
||||
.TP
|
||||
.B F5
|
||||
redraw the screen content
|
||||
Redraw the screen content.
|
||||
.SH FILES
|
||||
.TP
|
||||
.I ~/.config/comp/settings.ini
|
||||
|
|
15
omp/omp.py
15
omp/omp.py
|
@ -20,7 +20,8 @@ import json
|
|||
from collections import deque
|
||||
from gettext import bindtextdomain, gettext as _, textdomain
|
||||
from itertools import cycle
|
||||
from os.path import abspath, expanduser, expandvars, isfile
|
||||
from os import makedirs
|
||||
from os.path import abspath, dirname, expanduser, expandvars, isfile
|
||||
from random import choice
|
||||
from time import gmtime, sleep, strftime
|
||||
from urllib import request
|
||||
|
@ -141,18 +142,18 @@ class Omp(object):
|
|||
def dump_json(self):
|
||||
s = self.read_input(
|
||||
_("Save playlist to [{}]: ").format(self.json_file))
|
||||
if s: self.json_file = abspath(expanduser(expandvars(s)))
|
||||
self.json_file = abspath(expanduser(expandvars(s or self.json_file)))
|
||||
try:
|
||||
makedirs(dirname(comp.json_file), exist_ok=True)
|
||||
with open(self.json_file, 'w') as f:
|
||||
json.dump(self.entries, f, ensure_ascii=False,
|
||||
indent=2, sort_keys=True)
|
||||
makedirs(dirname(self.json_file), exist_ok=True)
|
||||
except:
|
||||
errmsg = _("'{}': Can't open file for writing").format(
|
||||
self.json_file)
|
||||
self.print_msg(errmsg, error=True)
|
||||
else:
|
||||
self.print_msg(_("'{}' written").format(comp.json_file))
|
||||
with open(self.json_file, 'w') as f:
|
||||
json.dump(self.entries, f, ensure_ascii=False,
|
||||
indent=2, sort_keys=True)
|
||||
self.print_msg(_("'{}' written").format(self.json_file))
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.mp.quit()
|
||||
|
|
Loading…
Reference in New Issue