Refactor playlist management functions
This commit is contained in:
parent
911859ef49
commit
040020e7ed
@ -179,12 +179,18 @@ class Playdates(dbtables.PlaydatesTable):
|
||||
|
||||
|
||||
class Playlists(dbtables.PlaylistsTable):
|
||||
def __init__(self, session: Session, name: str):
|
||||
def __init__(self, session: Session, name: str, template_id: int) -> None:
|
||||
"""Create playlist with passed name"""
|
||||
|
||||
self.name = name
|
||||
self.last_used = dt.datetime.now()
|
||||
session.add(self)
|
||||
session.commit()
|
||||
|
||||
# If a template is specified, copy from it
|
||||
if template_id:
|
||||
PlaylistRows.copy_playlist(session, template_id, self.id)
|
||||
|
||||
@staticmethod
|
||||
def clear_tabs(session: Session, playlist_ids: list[int]) -> None:
|
||||
"""
|
||||
@ -201,26 +207,6 @@ class Playlists(dbtables.PlaylistsTable):
|
||||
self.open = False
|
||||
session.commit()
|
||||
|
||||
@classmethod
|
||||
def create_playlist_from_template(
|
||||
cls, session: Session, template_id: int, playlist_name: str
|
||||
) -> Optional["Playlists"]:
|
||||
"""Create a new playlist from template"""
|
||||
|
||||
# Sanity check
|
||||
if not template_id:
|
||||
return None
|
||||
|
||||
playlist = cls(session, playlist_name)
|
||||
|
||||
# Sanity / mypy checks
|
||||
if not playlist or not playlist.id:
|
||||
return None
|
||||
|
||||
PlaylistRows.copy_playlist(session, template_id, playlist.id)
|
||||
|
||||
return playlist
|
||||
|
||||
def delete(self, session: Session) -> None:
|
||||
"""
|
||||
Delete playlist
|
||||
|
||||
@ -694,15 +694,19 @@ class Window(QMainWindow):
|
||||
and template_id.
|
||||
"""
|
||||
|
||||
submenu_items: list[dict[str, str | tuple[Session, int]]] = []
|
||||
|
||||
with db.Session() as session:
|
||||
templates = Playlists.get_all_templates(session)
|
||||
submenu_items: list[dict[str, str | tuple[Session, int]]] = [
|
||||
{"text": "Show all",
|
||||
"handler": "create_playlist_from_template",
|
||||
"args": (session, 0)
|
||||
}
|
||||
]
|
||||
templates = Playlists.get_favourite_templates(session)
|
||||
for template in templates:
|
||||
submenu_items.append(
|
||||
{
|
||||
"text": template.name,
|
||||
"handler": "create_and_show_playlist",
|
||||
"handler": "create_playlist_from_template",
|
||||
"args": (
|
||||
session,
|
||||
template.id,
|
||||
@ -719,6 +723,178 @@ class Window(QMainWindow):
|
||||
{"text": "Action Y", "handler": "action_y_handler"},
|
||||
]
|
||||
|
||||
# # # # # # # # # # Playlist management functions # # # # # # # # # #
|
||||
|
||||
def _create_playlist(
|
||||
self, session: Session, name: str, template_id: int
|
||||
) -> Playlists:
|
||||
"""
|
||||
Create a playlist in the database, populate it from the template
|
||||
if template_id > 0, and return the Playlists object.
|
||||
"""
|
||||
|
||||
log.debug(f" _create_playlist({name=}, {template_id=})")
|
||||
|
||||
return Playlists(session, name, template_id)
|
||||
|
||||
def _open_playlist(self, playlist: Playlists, is_template: bool = False) -> int:
|
||||
"""
|
||||
With passed playlist:
|
||||
- create models
|
||||
- create tab
|
||||
- switch to tab
|
||||
- mark playist as open
|
||||
return: tab index
|
||||
"""
|
||||
|
||||
log.debug(f" _open_playlist({playlist=}, {is_template=})")
|
||||
|
||||
# Create base model and proxy model
|
||||
base_model = PlaylistModel(playlist.id, is_template)
|
||||
proxy_model = PlaylistProxyModel()
|
||||
proxy_model.setSourceModel(base_model)
|
||||
|
||||
# Create tab
|
||||
playlist_tab = PlaylistTab(musicmuster=self, model=proxy_model)
|
||||
idx = self.playlist_section.tabPlaylist.addTab(playlist_tab, playlist.name)
|
||||
|
||||
# Mark playlist as open
|
||||
playlist.mark_open()
|
||||
|
||||
# Switch to new tab
|
||||
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||
self.update_playlist_icons()
|
||||
|
||||
return idx
|
||||
|
||||
def create_playlist_from_template(self, session: Session, template_id: int) -> None:
|
||||
"""
|
||||
Prompt for new playlist name and create from passed template_id
|
||||
"""
|
||||
|
||||
if template_id == 0:
|
||||
# Show all templates
|
||||
selected_template_id = self.solicit_template_to_use(session)
|
||||
if selected_template_id is None:
|
||||
return
|
||||
else:
|
||||
template_id = selected_template_id
|
||||
|
||||
playlist_name = self.solicit_playlist_name(session)
|
||||
if not playlist_name:
|
||||
return
|
||||
|
||||
playlist = self._create_playlist(session, playlist_name, template_id)
|
||||
self._open_playlist(playlist)
|
||||
session.commit()
|
||||
|
||||
def delete_playlist(self) -> None:
|
||||
"""
|
||||
Delete current playlist
|
||||
"""
|
||||
|
||||
with db.Session() as session:
|
||||
playlist_id = self.current.playlist_id
|
||||
playlist = session.get(Playlists, playlist_id)
|
||||
if playlist:
|
||||
if helpers.ask_yes_no(
|
||||
"Delete playlist",
|
||||
f"Delete playlist '{playlist.name}': " "Are you sure?",
|
||||
):
|
||||
if self.close_playlist_tab():
|
||||
playlist.delete(session)
|
||||
session.commit()
|
||||
else:
|
||||
log.error("Failed to retrieve playlist")
|
||||
|
||||
def open_existing_playlist(self) -> None:
|
||||
"""Open existing playlist"""
|
||||
|
||||
with db.Session() as session:
|
||||
playlists = Playlists.get_closed(session)
|
||||
dlg = SelectPlaylistDialog(self, playlists=playlists, session=session)
|
||||
dlg.exec()
|
||||
playlist = dlg.playlist
|
||||
if playlist:
|
||||
self._open_playlist(playlist)
|
||||
session.commit()
|
||||
|
||||
def save_as_template(self) -> None:
|
||||
"""Save current playlist as template"""
|
||||
|
||||
with db.Session() as session:
|
||||
template_names = [a.name for a in Playlists.get_all_templates(session)]
|
||||
|
||||
while True:
|
||||
# Get name for new template
|
||||
dlg = QInputDialog(self)
|
||||
dlg.setInputMode(QInputDialog.InputMode.TextInput)
|
||||
dlg.setLabelText("Template name:")
|
||||
dlg.resize(500, 100)
|
||||
ok = dlg.exec()
|
||||
if not ok:
|
||||
return
|
||||
|
||||
template_name = dlg.textValue()
|
||||
if template_name not in template_names:
|
||||
break
|
||||
helpers.show_warning(
|
||||
self, "Duplicate template", "Template name already in use"
|
||||
)
|
||||
Playlists.save_as_template(session, self.current.playlist_id, template_name)
|
||||
session.commit()
|
||||
helpers.show_OK("Template", "Template saved", self)
|
||||
|
||||
def solicit_playlist_name(
|
||||
self, session: Session, default: str = "", prompt: str = "Playlist name:"
|
||||
) -> Optional[str]:
|
||||
"""Get name of new playlist from user"""
|
||||
|
||||
dlg = QInputDialog(self)
|
||||
dlg.setInputMode(QInputDialog.InputMode.TextInput)
|
||||
dlg.setLabelText(prompt)
|
||||
while True:
|
||||
if default:
|
||||
dlg.setTextValue(default)
|
||||
dlg.resize(500, 100)
|
||||
ok = dlg.exec()
|
||||
if ok:
|
||||
proposed_name = dlg.textValue()
|
||||
if Playlists.name_is_available(session, proposed_name):
|
||||
return proposed_name
|
||||
else:
|
||||
helpers.show_warning(
|
||||
self,
|
||||
"Name in use",
|
||||
f"There's already a playlist called '{proposed_name}'",
|
||||
)
|
||||
continue
|
||||
else:
|
||||
return None
|
||||
|
||||
def solicit_template_to_use(
|
||||
self, session: Session, template_prompt: Optional[str] = None
|
||||
) -> Optional[int]:
|
||||
"""
|
||||
Have user select a template. Return the template.id, or None if they cancel.
|
||||
template_id of zero means don't use a template.
|
||||
"""
|
||||
|
||||
template_name_id_list: list[tuple[str, int]] = []
|
||||
template_name_id_list.append((Config.NO_TEMPLATE_NAME, 0))
|
||||
|
||||
with db.Session() as session:
|
||||
for template in Playlists.get_all_templates(session):
|
||||
template_name_id_list.append((template.name, template.id))
|
||||
|
||||
dlg = TemplateSelectorDialog(template_name_id_list, template_prompt)
|
||||
if not dlg.exec() or dlg.selected_id is None:
|
||||
return None # User cancelled
|
||||
|
||||
return dlg.selected_id
|
||||
|
||||
# # # # # # # # # # Miscellaneous functions # # # # # # # # # #
|
||||
|
||||
def select_duplicate_rows(self) -> None:
|
||||
"""Call playlist to select duplicate rows"""
|
||||
|
||||
@ -898,55 +1074,6 @@ class Window(QMainWindow):
|
||||
self.signals.search_songfacts_signal.connect(self.open_songfacts_browser)
|
||||
self.signals.search_wikipedia_signal.connect(self.open_wikipedia_browser)
|
||||
|
||||
def create_and_show_playlist(
|
||||
self, session: Session, template_id: int
|
||||
) -> Optional[Playlists]:
|
||||
"""Create new playlist"""
|
||||
|
||||
# Get a name for this new playlist
|
||||
playlist_name = self.solicit_playlist_name(session)
|
||||
if not playlist_name:
|
||||
return None
|
||||
|
||||
# If template.id == 0, user doesn't want a template
|
||||
playlist: Optional[Playlists]
|
||||
if template_id == 0:
|
||||
playlist = Playlists(session, playlist_name)
|
||||
else:
|
||||
playlist = Playlists.create_playlist_from_template(
|
||||
session, template_id, playlist_name
|
||||
)
|
||||
|
||||
if playlist:
|
||||
self.open_and_show_playlist(session, playlist)
|
||||
else:
|
||||
log.error(f"Failed to create playlist, {playlist_name=}")
|
||||
|
||||
return None
|
||||
|
||||
def create_playlist_tab(
|
||||
self, playlist: Playlists, is_template: bool = False
|
||||
) -> int:
|
||||
"""
|
||||
Take the passed playlist, create a playlist tab and
|
||||
add tab to display. Return index number of tab.
|
||||
"""
|
||||
|
||||
log.debug(f"create_playlist_tab({playlist=})")
|
||||
|
||||
# Create model and proxy model
|
||||
base_model = PlaylistModel(playlist.id, is_template)
|
||||
proxy_model = PlaylistProxyModel()
|
||||
proxy_model.setSourceModel(base_model)
|
||||
|
||||
# Create tab
|
||||
playlist_tab = PlaylistTab(musicmuster=self, model=proxy_model)
|
||||
idx = self.playlist_section.tabPlaylist.addTab(playlist_tab, playlist.name)
|
||||
|
||||
log.debug(f"create_playlist_tab() returned: {idx=}")
|
||||
|
||||
return idx
|
||||
|
||||
def current_row_or_end(self) -> int:
|
||||
"""
|
||||
If a row or rows are selected, return the row number of the first
|
||||
@ -965,25 +1092,6 @@ class Window(QMainWindow):
|
||||
|
||||
ipdb.set_trace()
|
||||
|
||||
def delete_playlist(self) -> None:
|
||||
"""
|
||||
Delete current playlist
|
||||
"""
|
||||
|
||||
with db.Session() as session:
|
||||
playlist_id = self.current.playlist_id
|
||||
playlist = session.get(Playlists, playlist_id)
|
||||
if playlist:
|
||||
if helpers.ask_yes_no(
|
||||
"Delete playlist",
|
||||
f"Delete playlist '{playlist.name}': " "Are you sure?",
|
||||
):
|
||||
if self.close_playlist_tab():
|
||||
playlist.delete(session)
|
||||
session.commit()
|
||||
else:
|
||||
log.error("Failed to retrieve playlist")
|
||||
|
||||
def download_played_tracks(self) -> None:
|
||||
"""Download a CSV of played tracks"""
|
||||
|
||||
@ -1191,7 +1299,7 @@ class Window(QMainWindow):
|
||||
if playlist:
|
||||
log.debug(f"load_last_playlists() loaded {playlist=}")
|
||||
# Create tab
|
||||
playlist_ids.append(self.create_playlist_tab(playlist))
|
||||
playlist_ids.append(self._open_playlist(playlist))
|
||||
|
||||
# Set active tab
|
||||
record = Settings.get_setting(session, "active_tab")
|
||||
@ -1270,8 +1378,7 @@ class Window(QMainWindow):
|
||||
)
|
||||
# Simply load the template as a playlist. Any changes
|
||||
# made will persist
|
||||
idx = self.create_playlist_tab(template, is_template=True)
|
||||
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||
self._open_playlist(template, is_template=True)
|
||||
|
||||
def favourite(template_id: int, favourite: bool) -> None:
|
||||
"""Mark template as (not) favourite"""
|
||||
@ -1285,14 +1392,24 @@ class Window(QMainWindow):
|
||||
|
||||
# Get base template
|
||||
template_id = self.solicit_template_to_use(
|
||||
session, template_prmompt="New template based upon:"
|
||||
session, template_prompt="New template based upon:"
|
||||
)
|
||||
if template_id is None:
|
||||
return
|
||||
|
||||
new_template = self.create_and_show_playlist(session, template_id)
|
||||
if new_template:
|
||||
self.open_and_show_playlist(session, new_template, is_template=True)
|
||||
# Get new template name
|
||||
name = self.solicit_playlist_name(
|
||||
session, default="", prompt="New template name:"
|
||||
)
|
||||
if not name:
|
||||
return
|
||||
|
||||
# Create playlist for template and mark is as a template
|
||||
template = self._create_playlist(session, name, template_id)
|
||||
template.is_template = True
|
||||
|
||||
# Open it for editing
|
||||
self._open_playlist(template, is_template=True)
|
||||
|
||||
def rename(template_id: int) -> Optional[str]:
|
||||
"""rename template"""
|
||||
@ -1419,53 +1536,6 @@ class Window(QMainWindow):
|
||||
self.move_playlist_rows(unplayed_rows)
|
||||
self.disable_selection_timing = False
|
||||
|
||||
def new_playlist(self) -> Optional[Playlists]:
|
||||
"""
|
||||
Create new playlist, optionally from template
|
||||
"""
|
||||
|
||||
with db.Session() as session:
|
||||
template_id = self.solicit_template_to_use(session)
|
||||
if not template_id:
|
||||
return None # User cancelled
|
||||
|
||||
playlist = self.create_and_show_playlist(session, template_id)
|
||||
|
||||
if playlist:
|
||||
playlist.mark_open()
|
||||
# Need to ensure that the new playlist is committed to
|
||||
# the database before it is opened by the model.
|
||||
session.commit()
|
||||
idx = self.create_playlist_tab(playlist)
|
||||
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||
return playlist
|
||||
else:
|
||||
ApplicationError("new_playlist: Playlist failed to create")
|
||||
|
||||
return None
|
||||
|
||||
def open_existing_playlist(self) -> None:
|
||||
"""Open existing playlist"""
|
||||
|
||||
with db.Session() as session:
|
||||
playlists = Playlists.get_closed(session)
|
||||
dlg = SelectPlaylistDialog(self, playlists=playlists, session=session)
|
||||
dlg.exec()
|
||||
playlist = dlg.playlist
|
||||
if playlist:
|
||||
self.open_and_show_playlist(session, playlist)
|
||||
|
||||
def open_and_show_playlist(
|
||||
self, session: Session, playlist: Playlists, is_template: bool = False
|
||||
) -> None:
|
||||
"""Open passed playlist"""
|
||||
|
||||
idx = self.create_playlist_tab(playlist, is_template)
|
||||
playlist.mark_open()
|
||||
session.commit()
|
||||
|
||||
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||
|
||||
def open_songfacts_browser(self, title: str) -> None:
|
||||
"""Search Songfacts for title"""
|
||||
|
||||
@ -1789,32 +1859,6 @@ class Window(QMainWindow):
|
||||
)
|
||||
track_sequence.current.start_time -= dt.timedelta(milliseconds=elapsed_ms)
|
||||
|
||||
def save_as_template(self) -> None:
|
||||
"""Save current playlist as template"""
|
||||
|
||||
with db.Session() as session:
|
||||
template_names = [a.name for a in Playlists.get_all_templates(session)]
|
||||
|
||||
while True:
|
||||
# Get name for new template
|
||||
dlg = QInputDialog(self)
|
||||
dlg.setInputMode(QInputDialog.InputMode.TextInput)
|
||||
dlg.setLabelText("Template name:")
|
||||
dlg.resize(500, 100)
|
||||
ok = dlg.exec()
|
||||
if not ok:
|
||||
return
|
||||
|
||||
template_name = dlg.textValue()
|
||||
if template_name not in template_names:
|
||||
break
|
||||
helpers.show_warning(
|
||||
self, "Duplicate template", "Template name already in use"
|
||||
)
|
||||
Playlists.save_as_template(session, self.current.playlist_id, template_name)
|
||||
session.commit()
|
||||
helpers.show_OK("Template", "Template saved", self)
|
||||
|
||||
def search_playlist(self) -> None:
|
||||
"""Show text box to search playlist"""
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user