Compare commits

...

3 Commits

Author SHA1 Message Date
Keith Edmunds
ffb1b238f4 WIP: Make ds.track_update more generic 2025-04-13 16:34:37 +01:00
Keith Edmunds
83780bfb68 Clean up unused signals 2025-04-13 15:38:09 +01:00
Keith Edmunds
cd793f9668 WIP: fix ds names, tidy row moving 2025-04-13 15:17:01 +01:00
8 changed files with 94 additions and 103 deletions

View File

@ -123,6 +123,10 @@ class AudioMetadata(NamedTuple):
class Col(Enum):
"""
Columns in playlist
"""
START_GAP = 0
TITLE = auto()
ARTIST = auto()
@ -142,6 +146,10 @@ class FileErrors(NamedTuple):
@dataclass
class Filter:
"""
Filter used in queries to select tracks
"""
version: int = 1
path_type: str = "contains"
path: str = ""
@ -172,6 +180,10 @@ class PlaylistStyle(QProxyStyle):
class QueryCol(Enum):
"""
Columns in querylist
"""
TITLE = 0
ARTIST = auto()
DURATION = auto()
@ -221,9 +233,7 @@ class MusicMusterSignals(QObject):
- https://stackoverflow.com/questions/62654525/emit-a-signal-from-another-class-to-main-class
"""
begin_reset_model_signal = pyqtSignal(int)
enable_escape_signal = pyqtSignal(bool)
end_reset_model_signal = pyqtSignal(int)
next_track_changed_signal = pyqtSignal()
resize_rows_signal = pyqtSignal(int)
search_songfacts_signal = pyqtSignal(str)

View File

@ -451,7 +451,7 @@ def track_set_intro(track_id: int, intro: int) -> None:
# @log_call
def track_update(
path: str, track_id: int, metadata: dict[str, str | int | float]
track_id: int, metadata: dict[str, str | int | float]
) -> TrackDTO:
"""
Update an existing track db entry return the DTO
@ -462,14 +462,12 @@ def track_update(
if not track:
raise ApplicationError(f"Can't retrieve Track ({track_id=})")
track.path = str(metadata["path"])
track.title = str(metadata["title"])
track.artist = str(metadata["artist"])
track.duration = int(metadata["duration"])
track.start_gap = int(metadata["start_gap"])
track.fade_at = int(metadata["fade_at"])
track.silence_at = int(metadata["silence_at"])
track.bitrate = int(metadata["bitrate"])
for key, value in metadata.items():
if hasattr(track, key):
setattr(track, key, value)
else:
raise ApplicationError(f"Tried to set attribute {key} on {track}")
session.commit()

View File

@ -640,9 +640,7 @@ class DoTrackImport(QThread):
if self.track_id == 0:
track_dto = ds.track_create(metadata)
else:
track_dto = ds.track_update(
self.destination_track_path, self.track_id, metadata
)
track_dto = ds.track_update(self.track_id, metadata)
self.signals.status_message_signal.emit(
f"{os.path.basename(self.import_file_path)} imported", 10000

View File

@ -67,8 +67,8 @@ from classes import (
Filter,
MusicMusterSignals,
PlaylistDTO,
TrackAndPlaylist,
QueryDTO,
TrackAndPlaylist,
TrackInfo,
)
from config import Config
@ -472,7 +472,7 @@ class ManageQueries(ItemlistManager):
# Build a list of queries
query_list: list[ItemlistItem] = []
for query in ds.get_all_queries():
for query in ds.queries_all():
query_list.append(
ItemlistItem(
name=query.name, id=query.query_id, favourite=query.favourite
@ -494,7 +494,7 @@ class ManageQueries(ItemlistManager):
"Delete query",
f"Delete query '{query.name}': " "Are you sure?",
):
ds.delete_query(query_id)
ds.query_delete(query_id)
self.refresh_table()
@ -503,8 +503,9 @@ class ManageQueries(ItemlistManager):
dlg = FilterDialog(query.name, query.filter)
if dlg.exec():
ds.update_query_filter(query.query_id, dlg.filter)
ds.update_query_name(query.query_id, dlg.name_text.text())
ds.query_update_filter
(query.query_id, dlg.filter)
ds.query_update_name(query.query_id, dlg.name_text.text())
def edit_item(self, query_id: int) -> None:
"""Edit query"""
@ -519,7 +520,7 @@ class ManageQueries(ItemlistManager):
def toggle_favourite(self, query_id: int, favourite: bool) -> None:
"""Mark query as (not) favourite"""
ds.update_query_favourite(query_id, favourite)
ds.query_update_favourite(query_id, favourite)
def new_item(self) -> None:
"""Create new query"""
@ -528,7 +529,7 @@ class ManageQueries(ItemlistManager):
if not query_name:
return
query = ds.create_query(query_name, Filter())
query = ds.query_create(query_name, Filter())
self._edit_item(query)
self.refresh_table()
@ -542,7 +543,7 @@ class ManageQueries(ItemlistManager):
if not new_name:
return
ds.update_query_name(query_id, new_name)
ds.query_update_name(query_id, new_name)
self.change_text(query_id, new_name)
@ -567,7 +568,7 @@ class ManageTemplates(ItemlistManager):
# Build a list of templates
template_list: list[ItemlistItem] = []
for template in ds.playlists_templates():
for template in ds.playlists_templates_all():
template_list.append(
ItemlistItem(
name=template.name,
@ -602,7 +603,7 @@ class ManageTemplates(ItemlistManager):
else:
self.musicmuster.playlist_section.tabPlaylist.removeTab(open_idx)
ds.delete_playlist(template.playlist_id)
ds.playlist_delete(template.playlist_id)
def edit_item(self, template_id: int) -> None:
"""Edit template"""
@ -619,7 +620,7 @@ class ManageTemplates(ItemlistManager):
def toggle_favourite(self, template_id: int, favourite: bool) -> None:
"""Mark template as (not) favourite"""
ds.update_template_favourite(template_id, favourite)
ds.playlist_update_template_favourite(template_id, favourite)
def new_item(
self,
@ -634,12 +635,14 @@ class ManageTemplates(ItemlistManager):
return
# Get new template name
name = self.musicmuster.get_playlist_name(default="", prompt="New template name:")
name = self.musicmuster.get_playlist_name(
default="", prompt="New template name:"
)
if not name:
return
# Create playlist for template and mark is as a template
template = ds.create_playlist(name, template_id, as_template=True)
template = ds.playlist_create(name, template_id, as_template=True)
# Open it for editing
self.musicmuster._open_playlist(template, is_template=True)
@ -780,7 +783,7 @@ class QueryDialog(QDialog):
self.query_list: list[tuple[str, int]] = []
self.query_list.append((Config.NO_QUERY_NAME, 0))
for query in ds.get_all_queries():
for query in ds.queries_all():
self.query_list.append((query.name, query.query_id))
self.setWindowTitle("Query Selector")
@ -908,9 +911,7 @@ class QueryDialog(QDialog):
return
for column_number in range(column_count - 1):
attr_name = f"querylist_col_{column_number}_width"
ds.setting_set(
attr_name, self.table_view.columnWidth(column_number)
)
ds.setting_set(attr_name, self.table_view.columnWidth(column_number))
def _column_resize(self, column_number: int, _old: int, _new: int) -> None:
"""
@ -1022,6 +1023,12 @@ class SelectPlaylistDialog(QDialog):
self.accept()
@dataclass
class MoveSource:
model: PlaylistModel
rows: list[int]
class TemplateSelectorDialog(QDialog):
"""
Class to manage user selection of template
@ -1145,8 +1152,7 @@ class Window(QMainWindow):
self.footer_section.widgetFadeVolume.setDefaultPadding(0)
self.footer_section.widgetFadeVolume.setBackground(Config.FADE_CURVE_BACKGROUND)
self.move_source_rows: list[PlaylistRow] = []
self.move_source_model: Optional[PlaylistModel] = None
self.move_source: MoveSource | None = None
self.disable_selection_timing = False
self.clock_counter = 0
@ -1324,7 +1330,7 @@ class Window(QMainWindow):
"separator": True,
},
]
templates = ds.playlists_templates()
templates = ds.playlists_templates_all()
for template in templates:
submenu_items.append(
{
@ -1357,7 +1363,7 @@ class Window(QMainWindow):
"separator": True,
},
]
queries = ds.get_all_queries(favourites_only=True)
queries = ds.queries_all(favourites_only=True)
for query in queries:
submenu_items.append(
{
@ -1458,7 +1464,7 @@ class Window(QMainWindow):
if not playlist_name:
return
_ = ds.create_playlist(playlist_name, template_id)
_ = ds.playlist_create(playlist_name, template_id)
# @log_call
def delete_playlist(self, checked: bool = False) -> None:
@ -1474,7 +1480,7 @@ class Window(QMainWindow):
f"Delete playlist '{playlist.name}': " "Are you sure?",
):
if self.close_playlist_tab():
ds.delete_playlist(self.current.playlist_id)
ds.playlist_delete(self.current.playlist_id)
else:
log.error("Failed to retrieve playlist")
@ -1491,7 +1497,7 @@ class Window(QMainWindow):
def save_as_template(self, checked: bool = False) -> None:
"""Save current playlist as template"""
template_names = [a.name for a in ds.playlists_templates()]
template_names = [a.name for a in ds.playlists_templates_all()]
while True:
# Get name for new template
@ -1509,7 +1515,7 @@ class Window(QMainWindow):
helpers.show_warning(
self, "Duplicate template", "Template name already in use"
)
ds.save_as_template(self.current.playlist_id, template_name)
ds.playlist_save_as_template(self.current.playlist_id, template_name)
helpers.show_OK("Template", "Template saved", self)
def get_playlist_name(
@ -1520,7 +1526,7 @@ class Window(QMainWindow):
dlg = QInputDialog(self)
dlg.setInputMode(QInputDialog.InputMode.TextInput)
dlg.setLabelText(prompt)
all_playlist_names = [a.name for a in ds.get_all_playlists()]
all_playlist_names = [a.name for a in ds.playlists_all()]
while True:
if default:
@ -1552,7 +1558,7 @@ class Window(QMainWindow):
template_name_id_list: list[tuple[str, int]] = []
template_name_id_list.append((Config.NO_TEMPLATE_NAME, 0))
for template in ds.playlists_templates():
for template in ds.playlists_templates_all():
template_name_id_list.append((template.name, template.playlist_id))
dlg = TemplateSelectorDialog(template_name_id_list, template_prompt)
@ -1661,7 +1667,7 @@ class Window(QMainWindow):
return False
# Record playlist as closed
ds.playlist_mark_status(open=False)
ds.playlist_mark_status(closing_tab_playlist_id, open=False)
# Close playlist and remove tab
self.playlist_section.tabPlaylist.widget(tab_index).close()
@ -1828,7 +1834,7 @@ class Window(QMainWindow):
with open(path, "w") as f:
# Required directive on first line
f.write("#EXTM3U\n")
for playlistrow in ds.get_playlist_rows(playlist_id):
for playlistrow in ds.playlistrows_by_playlist(playlist_id):
if playlistrow.track:
f.write(
"#EXTINF:"
@ -1948,13 +1954,13 @@ class Window(QMainWindow):
# Save the selected PlaylistRows items ready for a later
# paste
self.move_source_rows = self.current.base_model.selected_rows
self.move_source_model = self.current.base_model
log.debug(
f"mark_rows_for_moving(): {self.move_source_rows=} {self.move_source_model=}"
self.move_source = MoveSource(
model=self.current.base_model,
rows=[a.row_number for a in self.current.base_model.selected_rows],
)
log.debug(f"mark_rows_for_moving(): {self.move_source=}")
# @log_call
def move_playlist_rows(self, row_numbers: list[int]) -> None:
"""
@ -1965,7 +1971,7 @@ class Window(QMainWindow):
playlists = []
source_playlist_id = self.current.playlist_id
for playlist in ds.get_all_playlists():
for playlist in ds.playlists_all():
if playlist.id == source_playlist_id:
continue
else:
@ -2035,36 +2041,37 @@ class Window(QMainWindow):
# @log_call
def paste_rows(self, checked: bool = False) -> None:
"""
Paste earlier cut rows.
Paste earlier rows identified in self.mark_rows_for_moving()
'checked' is a dummy parameter passed to us by the menu
"""
if not self.move_source_rows or not self.move_source_model:
if not self.move_source:
return
to_playlist_model = self.current.base_model
destination_row = self.current_row_or_end()
from_playlist_model = self.move_source.model
to_row = self.current_row_or_end()
from_rows = self.move_source.rows
# If we move a row to immediately under the current track, make
# that moved row the next track
set_next_row: Optional[int] = None
if (
self.track_sequence.current
and self.track_sequence.current.playlist_id == to_playlist_model.playlist_id
and destination_row == self.track_sequence.current.row_number + 1
):
set_next_row = destination_row
if to_playlist_model.playlist_id == self.move_source_model.playlist_id:
self.move_source_model.move_rows(self.move_source_rows, destination_row)
if from_playlist_model == to_playlist_model:
from_playlist_model.move_rows(from_rows, to_row)
else:
self.move_source_model.move_rows_between_playlists(
self.move_source_rows, destination_row, to_playlist_model.playlist_id
from_playlist_model.move_rows_between_playlists(
from_rows, to_row, to_playlist_model.playlist_id
)
self.active_tab().resize_rows()
self.active_tab().clear_selection()
if set_next_row:
to_playlist_model.set_next_row(set_next_row)
# If we move a row to immediately under the current track, make
# that moved row the next track
if (
self.track_sequence.current
and self.track_sequence.current.playlist_id == to_playlist_model.playlist_id
and to_row == self.track_sequence.current.row_number + 1
):
to_playlist_model.set_next_row(to_row)
# @log_call
def play_next(
@ -2141,8 +2148,10 @@ class Window(QMainWindow):
# Notify others
self.signals.signal_track_started.emit(
TrackAndPlaylist(self.track_sequence.current.playlist_id,
self.track_sequence.current.track_id)
TrackAndPlaylist(
self.track_sequence.current.playlist_id,
self.track_sequence.current.track_id,
)
)
# TODO: ensure signal_track_started does all this:
@ -2192,7 +2201,9 @@ class Window(QMainWindow):
f"musicmuster.preview: unable to retreive track {track_info.track_id=}"
)
self.preview_manager.set_track_info(
track_id=track.track_id, track_path=track.path, track_intro=track.intro or 0
track_id=track.track_id,
track_path=track.path,
track_intro=track.intro or 0,
)
self.preview_manager.play()
self.show_status_message(
@ -2236,7 +2247,7 @@ class Window(QMainWindow):
return
intro = round(self.preview_manager.get_playtime() / 100) * 100
ds.set_track_intro(track_id, intro)
ds.track_set_intro(track_id, intro)
self.preview_manager.set_intro(intro)
self.current.base_model.refresh_row(row_number)
roles = [
@ -2274,7 +2285,7 @@ class Window(QMainWindow):
if playlist:
new_name = self.get_playlist_name(playlist.name)
if new_name:
ds.playlist_rename(playlist.id, new_name)
ds.playlist_rename(playlist.playlist_id, new_name)
idx = self.tabBar.currentIndex()
self.tabBar.setTabText(idx, new_name)

View File

@ -92,8 +92,6 @@ class PlaylistModel(QAbstractTableModel):
self.played_tracks_hidden = False
# Connect signals
self.signals.begin_reset_model_signal.connect(self.begin_reset_model)
self.signals.end_reset_model_signal.connect(self.end_reset_model)
self.signals.signal_add_track_to_header.connect(self.add_track_to_header)
self.signals.signal_begin_insert_rows.connect(self.begin_insert_rows)
self.signals.signal_end_insert_rows.connect(self.end_insert_rows)
@ -239,16 +237,6 @@ class PlaylistModel(QAbstractTableModel):
return QBrush()
# @log_call
def begin_reset_model(self, playlist_id: int) -> None:
"""
Reset model if playlist_id is ours
"""
if playlist_id != self.playlist_id:
return
super().beginResetModel()
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
"""Standard function for view"""
@ -463,19 +451,6 @@ class PlaylistModel(QAbstractTableModel):
return ""
# @log_call
def end_reset_model(self, playlist_id: int) -> None:
"""
End model reset if this is our playlist
"""
if playlist_id != self.playlist_id:
return
self.refresh_data()
super().endResetModel()
self.track_sequence.update()
self.update_track_times()
def _edit_role(self, row: int, column: int, plr: PlaylistRow) -> str | int:
"""
Return value for editing
@ -1063,7 +1038,7 @@ class PlaylistModel(QAbstractTableModel):
track = self.playlist_rows[row_number]
metadata = get_all_track_metadata(track.path)
_ = ds.track_update(track.path, track.track_id, metadata)
_ = ds.track_update(track.track_id, metadata)
roles = [
Qt.ItemDataRole.BackgroundRole,

View File

@ -574,7 +574,7 @@ class PlaylistTab(QTableView):
"Rescan track", lambda: self._rescan(model_row_number)
)
self._add_context_menu("Mark for moving", lambda: self._mark_for_moving())
if self.musicmuster.move_source_rows:
if self.musicmuster.move_source:
self._add_context_menu(
"Move selected rows here", lambda: self._move_selected_rows()
)

View File

@ -228,7 +228,7 @@ class QuerylistModel(QAbstractTableModel):
row = 0
try:
results = ds.get_filtered_tracks(self.filter)
results = ds.tracks_filtered(self.filter)
for result in results:
queryrow = QueryRow(
artist=result.artist,

View File

@ -91,7 +91,6 @@ def update_bitrates() -> None:
for track in ds.tracks_all():
try:
t = get_tags(track.path)
# TODO this won't persist as we're updating DTO
track.bitrate = t.bitrate
ds.track_update(t)
except FileNotFoundError:
continue