grooveondemand/groove/shell/playlist.py

222 lines
7.0 KiB
Python
Raw Normal View History

2022-12-17 18:02:12 -08:00
from .base import BasePrompt, command
2022-11-30 00:09:23 -08:00
import os
2022-11-30 00:09:23 -08:00
from sqlalchemy.exc import NoResultFound
from textwrap import dedent, wrap
2022-12-17 10:50:02 -08:00
from rich.table import Column
from rich import box
2022-11-30 00:09:23 -08:00
from groove import db
from groove.exceptions import PlaylistValidationError
2022-11-30 00:09:23 -08:00
class _playlist(BasePrompt):
"""
"""
def __init__(self, parent, manager=None):
super().__init__(manager=manager, parent=parent)
self._parent = parent
2022-12-17 18:02:12 -08:00
self._console = parent.console
2022-11-30 00:09:23 -08:00
@property
2022-12-17 18:02:12 -08:00
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'))
2022-12-17 18:02:12 -08:00
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
2022-12-17 18:02:12 -08:00
Try 'help COMMAND' for command-specific help.[/help]
""")
2022-11-30 00:09:23 -08:00
@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]",
]
2022-11-30 00:09:23 -08:00
2022-12-17 18:02:12 -08:00
def start(self):
self.show()
super().start()
2022-12-17 18:02:12 -08:00
@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.
2022-11-30 00:09:23 -08:00
2022-12-17 18:02:12 -08:00
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()
2022-12-17 18:02:12 -08:00
except PlaylistValidationError as e: # pragma: no cover
self.console.error(f"Changes were not saved: {e}")
else:
self.show()
2022-11-30 00:09:23 -08:00
return True
2022-12-17 18:02:12 -08:00
@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):
2022-12-17 10:50:02 -08:00
pl = self.parent.playlist
title = f"\n [b]:headphones: {pl.name}[/b]"
if pl.description:
title += f"\n [italic]{pl.description}[/italic]\n"
2022-12-17 18:02:12 -08:00
table = self.console.table(
2022-12-17 10:50:02 -08:00
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]"
)
2022-12-17 18:02:12 -08:00
self.console.print(table)
2022-12-06 22:17:53 -08:00
return True
2022-12-17 18:02:12 -08:00
@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):
2022-12-17 18:02:12 -08:00
self.console.print(
"Add tracks one at a time by title. Hit Enter to finish."
)
added = False
2022-11-30 00:09:23 -08:00
while True:
2022-12-17 18:02:12 -08:00
text = self.console.prompt(
[' ?'],
2022-11-30 00:09:23 -08:00
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()
2022-11-30 00:09:23 -08:00
return True
self._add_track(text)
added = True
2022-11-30 00:09:23 -08:00
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])
2022-12-17 18:02:12 -08:00
except NoResultFound: # pragma: no cover
self.console.error("No match for '{text}'")
return
return text
2022-12-17 18:02:12 -08:00
@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]",
])
2022-11-30 00:09:23 -08:00
if res != 'DELETE':
2022-12-17 18:02:12 -08:00
self.console.error("Delete aborted. No changes have been made.")
2022-11-30 00:09:23 -08:00
return True
self.parent.playlist.delete()
2022-12-17 18:02:12 -08:00
self.console.print("Deleted the playlist.")
2022-11-30 00:09:23 -08:00
self.parent._playlist = None
return False
2022-12-17 18:02:12 -08:00
@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)