grooveondemand/groove/shell/playlist.py
2022-12-17 10:50:02 -08:00

173 lines
5.3 KiB
Python

from .base import BasePrompt
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._commands = None
@property
def help_text(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:
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]",
]
@property
def values(self):
return self.commands.keys()
@property
def commands(self):
if not self._commands:
self._commands = {
'delete': self.delete,
'add': self.add,
'show': self.show,
'edit': self.edit,
'help': self.help
}
return self._commands
def process(self, cmd, *parts):
if cmd in self.commands:
return True if self.commands[cmd](parts) else False
self.parent.console.error(f"Command not understood: {cmd}")
return True
def edit(self, *parts):
try:
self.parent.playlist.edit()
except PlaylistValidationError as e:
self.parent.console.error(f"Changes were not saved: {e}")
else:
self.show()
return True
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.parent.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.parent.console.print(table)
return True
def add(self, *parts):
self.parent.console.print(
"Add tracks one at a time by title. Hit Enter to finish."
)
added = False
while True:
text = self.parent.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:
self.parent.console.error("No match for '{text}'")
return
return text
def delete(self, *parts):
res = self.parent.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.parent.console.error("Delete aborted. No changes have been made.")
return True
self.parent.playlist.delete()
self.parent.console.print("Deleted the playlist.")
self.parent._playlist = None
return False
def start(self):
self.show()
super().start()