222 lines
7.0 KiB
Python
222 lines
7.0 KiB
Python
from .base import BasePrompt, command
|
|
|
|
import os
|
|
|
|
from sqlalchemy.exc import NoResultFound
|
|
from textwrap import dedent, wrap
|
|
from rich.table import Column
|
|
from rich import box
|
|
|
|
from groove import db
|
|
from groove.exceptions import PlaylistValidationError
|
|
|
|
|
|
class _playlist(BasePrompt):
|
|
"""
|
|
"""
|
|
|
|
def __init__(self, parent, manager=None):
|
|
super().__init__(manager=manager, parent=parent)
|
|
self._parent = parent
|
|
self._console = parent.console
|
|
|
|
@property
|
|
def usage(self):
|
|
synopsis = (
|
|
f"You are currently editing the [b]{self.parent.playlist.name}[/b]"
|
|
f" playlist. From this prompt you can quickly append new tracks "
|
|
f"to the playlist. You can invoke your editor "
|
|
f"([link]{os.environ['EDITOR']}[/link]) to change the playlist "
|
|
f"name and description, or reorder or remove tracks. You can also "
|
|
f"delete the playlist."
|
|
)
|
|
|
|
try:
|
|
width = int(os.environ.get('CONSOLE_WIDTH', '80'))
|
|
except ValueError: # pragma: no cover
|
|
width = 80
|
|
synopsis = '\n '.join(wrap(synopsis, width=width))
|
|
|
|
return dedent(f"""
|
|
[title]WORKING WITH PLAYLISTS[/title]
|
|
|
|
{synopsis}
|
|
|
|
[title]USAGE[/title]
|
|
|
|
[link]playlist> COMMAND [ARG ..][/link]
|
|
|
|
[title]COMMANDS[/title]
|
|
[help]
|
|
[b]add[/b] Add one or more tracks to the playlist
|
|
[b]edit[/b] Open the playlist in the system editor
|
|
[b]show[/b] Display the complete playlist
|
|
[b]delete[/b] Delete the playlist
|
|
[b]help[/b] This message
|
|
|
|
Try 'help COMMAND' for command-specific help.[/help]
|
|
""")
|
|
|
|
@property
|
|
def prompt(self):
|
|
return [
|
|
"",
|
|
"[help]Available commands: add, edit, show, delete, help. Hit Enter to return.[/help]",
|
|
f"[prompt]{self.parent.playlist.slug}[/prompt]",
|
|
]
|
|
|
|
def start(self):
|
|
self.show()
|
|
super().start()
|
|
|
|
@command("""
|
|
[title]EDITING A PLAYLIST[/title]
|
|
|
|
Use the [b]edit[/b] commmand to edit a YAML-formatted versin of the playlist
|
|
in your external editor as specified by the $EDITOR environment variable.
|
|
|
|
You can use this feature to rename a playlist, change its description, and
|
|
delete or reorder the playlist's entries. Save and exit the file when you
|
|
are finished editing, and the playlist will be updated with your changes.
|
|
|
|
To abort the edit session, exit your editor without saving the file.
|
|
|
|
[title]USAGE[/title]
|
|
|
|
[link]playlist> edit[/link]
|
|
""")
|
|
def edit(self, *parts):
|
|
try:
|
|
self.parent.playlist.edit()
|
|
except PlaylistValidationError as e: # pragma: no cover
|
|
self.console.error(f"Changes were not saved: {e}")
|
|
else:
|
|
self.show()
|
|
return True
|
|
|
|
@command("""
|
|
[title]VIEWS FOR THE VIEWMASTER[/title]
|
|
|
|
Use the [b]show[/b] command to display the contents of the current playlist.
|
|
|
|
[title]USAGE[/title]
|
|
|
|
[link]playlist> show[/link]
|
|
""")
|
|
def show(self, *parts):
|
|
pl = self.parent.playlist
|
|
title = f"\n [b]:headphones: {pl.name}[/b]"
|
|
if pl.description:
|
|
title += f"\n [italic]{pl.description}[/italic]\n"
|
|
table = self.console.table(
|
|
Column('#', justify='right', width=4),
|
|
Column('Artist', justify='left'),
|
|
Column('Title', justify='left'),
|
|
box=box.HORIZONTALS,
|
|
title=title,
|
|
title_justify='left',
|
|
caption=f"[link]{pl.url}[/link]",
|
|
caption_justify='right',
|
|
)
|
|
for (num, entry) in enumerate(pl.entries):
|
|
table.add_row(
|
|
f"[text]{num+1}[/text]",
|
|
f"[artist]{entry.artist}[/artist]",
|
|
f"[title]{entry.title}[/title]"
|
|
)
|
|
self.console.print(table)
|
|
return True
|
|
|
|
@command("""
|
|
[title]ADDING TRACKS TO A PLAYLIST[/title]
|
|
|
|
Use the [b]add[/b] command to interactively add one or more tracks from
|
|
your media sources to the current playlist. At the prompt, start typing the
|
|
name of an artist, album, or song title; matches from the file names in
|
|
your library will be suggested automatically. To accept a match, hit <TAB>,
|
|
or use the arrow keys to choose a different suggestion.
|
|
|
|
Hit <ENTER> to add your selected track to the current playlist. You can
|
|
then add another track, or hit <ENTER> again to return to the playlist
|
|
editor.
|
|
|
|
[title]USAGE[/title]
|
|
|
|
[link]playlist> add[/link]
|
|
[link] ?> PATHNAME
|
|
""")
|
|
def add(self, *parts):
|
|
self.console.print(
|
|
"Add tracks one at a time by title. Hit Enter to finish."
|
|
)
|
|
added = False
|
|
while True:
|
|
text = self.console.prompt(
|
|
[' ?'],
|
|
completer=self.manager.fuzzy_table_completer(
|
|
db.track,
|
|
db.track.c.relpath,
|
|
lambda row: row.relpath
|
|
),
|
|
complete_in_thread=True, complete_while_typing=True
|
|
)
|
|
if not text:
|
|
if added:
|
|
self.show()
|
|
return True
|
|
self._add_track(text)
|
|
added = True
|
|
|
|
def _add_track(self, text):
|
|
sess = self.parent.manager.session
|
|
try:
|
|
track = sess.query(db.track).filter(db.track.c.relpath == text).one()
|
|
self.parent.playlist.create_entries([track])
|
|
except NoResultFound: # pragma: no cover
|
|
self.console.error("No match for '{text}'")
|
|
return
|
|
return text
|
|
|
|
@command("""
|
|
[title]DELETING A PLAYLIST[/title]
|
|
Use the [b]delete[/b] command to delete the current playlist. You will be
|
|
prompted to type DELETE, to ensure you really mean it. If you
|
|
enter anything other than DELETE, the delete request will
|
|
be aborted.
|
|
|
|
[danger]Deleting a playlist cannot be undone![/danger]
|
|
|
|
[title]USAGE[/title]
|
|
|
|
[link]playlist> delete[/link]
|
|
Type DELETE to permanently delete the playlist.
|
|
[link]DELETE playlist> DELETE
|
|
""")
|
|
def delete(self, parts):
|
|
res = self.console.prompt([
|
|
f"[error]Type [b]DELETE[/b] to permanently delete the playlist "
|
|
f'"{self.parent.playlist.record.name}".[/error]',
|
|
f"[prompt]DELETE {self.parent.playlist.slug}[/prompt]",
|
|
])
|
|
if res != 'DELETE':
|
|
self.console.error("Delete aborted. No changes have been made.")
|
|
return True
|
|
|
|
self.parent.playlist.delete()
|
|
self.console.print("Deleted the playlist.")
|
|
self.parent._playlist = None
|
|
return False
|
|
|
|
@command("""
|
|
[title]HELP![/title]
|
|
|
|
The [b]help[/b] command will print usage information for whatever you're currently
|
|
doing. You can also ask for help on any command currently available.
|
|
|
|
[title]USAGE[/title]
|
|
|
|
[link]> help [COMMAND][/link]
|
|
""")
|
|
def help(self, parts):
|
|
super().help(parts)
|