WIP V3: check track already present in playlist when adding

This commit is contained in:
Keith Edmunds 2023-11-27 20:55:24 +00:00
parent 3cab9f737c
commit b1442b2c7d
7 changed files with 103 additions and 60 deletions

View File

@ -79,8 +79,6 @@ class MusicMusterSignals(QObject):
https://refactoring.guru/design-patterns/singleton/python/example#example-0
"""
add_track_to_header_signal = pyqtSignal(int, int, int)
add_track_to_playlist_signal = pyqtSignal(int, int, int, str)
begin_reset_model_signal = pyqtSignal(int)
enable_escape_signal = pyqtSignal(bool)
end_reset_model_signal = pyqtSignal(int)

View File

@ -6,10 +6,12 @@ from PyQt6.QtWidgets import QDialog, QListWidgetItem
from classes import MusicMusterSignals
from dbconfig import scoped_session
from helpers import (
ask_yes_no,
get_relative_date,
ms_to_mmss,
)
from models import Settings, Tracks
from playlistmodel import PlaylistModel
from ui.dlg_TrackSelect_ui import Ui_Dialog # type: ignore
@ -20,7 +22,7 @@ class TrackSelectDialog(QDialog):
self,
session: scoped_session,
new_row_number: int,
playlist_id: int,
model: PlaylistModel,
add_to_header: Optional[bool] = False,
*args,
**kwargs,
@ -32,7 +34,7 @@ class TrackSelectDialog(QDialog):
super().__init__(*args, **kwargs)
self.session = session
self.new_row_number = new_row_number
self.playlist_id = playlist_id
self.model = model
self.add_to_header = add_to_header
self.ui = Ui_Dialog()
self.ui.setupUi(self)
@ -73,14 +75,30 @@ class TrackSelectDialog(QDialog):
track_id = None
if track:
track_id = track.id
if self.add_to_header:
self.signals.add_track_to_header_signal.emit(
self.playlist_id, self.new_row_number, track_id
)
else:
self.signals.add_track_to_playlist_signal.emit(
self.playlist_id, self.new_row_number, track_id, note
)
return
# Check whether track is already in playlist
move_existing = False
existing_prd = self.model.is_track_in_playlist(track_id)
if existing_prd is not None:
if ask_yes_no(
"Duplicate row",
"Track already in playlist. " "Move to new location?",
default_yes=True,
):
move_existing = True
if self.add_to_header and existing_prd: # and existing_prd for mypy's benefit
if move_existing:
self.model.move_track_to_header(self.new_row_number, existing_prd, note)
else:
self.model.add_track_to_header(self.new_row_number, track_id)
# Close dialog - we can only add one track to a header
self.accept()
else:
if move_existing and existing_prd: # and existing_prd for mypy's benefit
self.model.move_track_add_note(self.new_row_number, existing_prd, note)
else:
self.model.insert_row(self.new_row_number, track_id, note)
def add_selected_and_close(self) -> None:
"""Handle Add and Close button"""

View File

@ -148,11 +148,11 @@ class ImportTrack(QObject):
import_finished = pyqtSignal()
def __init__(
self, filenames: List[str], playlist_id: int, row_number: Optional[int]
self, filenames: List[str], model: PlaylistModel, row_number: Optional[int]
) -> None:
super().__init__()
self.filenames = filenames
self.playlist_id = playlist_id
self.model = model
self.next_row_number = row_number
self.signals = MusicMusterSignals()
@ -179,9 +179,7 @@ class ImportTrack(QObject):
# previous additions in this loop. So, commit now to
# lock in what we've just done.
session.commit()
self.signals.add_track_to_playlist_signal.emit(
self.playlist_id, self.next_row_number, track.id, ""
)
self.model.insert_row(self.next_row_number, track.id, "")
self.next_row_number += 1
self.signals.status_message_signal.emit(
f"{len(self.filenames)} tracks imported", 10000
@ -532,8 +530,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionSelect_duplicate_rows.triggered.connect(
lambda: self.active_tab().select_duplicate_rows()
)
self.actionSelect_next_track.triggered.connect(self.select_next_row)
self.actionSelect_previous_track.triggered.connect(self.select_previous_row)
self.actionMoveUnplayed.triggered.connect(self.move_unplayed)
self.actionSetNext.triggered.connect(self.set_selected_track_next)
self.actionSkipToNext.triggered.connect(self.play_next)
@ -832,8 +828,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.import_thread = QThread()
self.worker = ImportTrack(
new_tracks,
self.active_tab().playlist_id,
self.active_tab().get_selected_row_number(),
self.active_model(),
self.active_tab().selected_model_row_number(),
)
self.worker.moveToThread(self.import_thread)
self.import_thread.started.connect(self.worker.run)
@ -871,8 +867,8 @@ class Window(QMainWindow, Ui_MainWindow):
with Session() as session:
dlg = TrackSelectDialog(
session=session,
new_row_number=self.active_tab().get_selected_row_number(),
playlist_id=self.active_tab().playlist_id,
new_row_number=self.active_tab().selected_model_row_number(),
model=self.active_model()
)
dlg.exec()
@ -893,7 +889,7 @@ class Window(QMainWindow, Ui_MainWindow):
Display songfacts page for title in highlighted row
"""
row_number = self.active_tab().get_selected_row_number()
row_number = self.active_tab().selected_model_row_number()
if row_number is None:
return
@ -908,7 +904,7 @@ class Window(QMainWindow, Ui_MainWindow):
Display Wikipedia page for title in highlighted row
"""
row_number = self.active_tab().get_selected_row_number()
row_number = self.active_tab().selected_model_row_number()
if row_number is None:
return

View File

@ -124,8 +124,6 @@ class PlaylistModel(QAbstractTableModel):
self.signals = MusicMusterSignals()
self.played_tracks_hidden = False
self.signals.add_track_to_header_signal.connect(self.add_track_to_header)
self.signals.add_track_to_playlist_signal.connect(self.add_track)
self.signals.begin_reset_model_signal.connect(self.begin_reset_model)
self.signals.end_reset_model_signal.connect(self.end_reset_model)
self.signals.row_order_changed_signal.connect(self.row_order_changed)
@ -142,45 +140,22 @@ class PlaylistModel(QAbstractTableModel):
f"<PlaylistModel: playlist_id={self.playlist_id}, {self.rowCount()} rows>"
)
def add_track(
self,
playlist_id: int,
new_row_number: int,
track_id: Optional[int],
note: Optional[str],
) -> None:
"""
Add track if it's for our playlist
"""
# Ignore if it's not for us
if playlist_id != self.playlist_id:
return
self.insert_row(
proposed_row_number=new_row_number, track_id=track_id, note=note
)
def add_track_to_header(
self,
playlist_id: int,
row_number: int,
track_id: int,
note: Optional[str] = None
) -> None:
"""
Add track to existing header row if it's for our playlist
Add track to existing header row
"""
# Ignore if it's not for us
if playlist_id != self.playlist_id:
return
# Get existing row
try:
prd = self.playlist_rows[row_number]
except KeyError:
log.error(
f"KeyError in PlaylistModel:add_track_to_header ({playlist_id=}, "
f"KeyError in PlaylistModel:add_track_to_header "
f"{row_number=}, {track_id=}, {len(self.playlist_rows)=}"
)
return
@ -195,6 +170,9 @@ class PlaylistModel(QAbstractTableModel):
if plr:
# Add track to PlaylistRows
plr.track_id = track_id
# Add any further note
if note:
plr.note += "\n" + note
# Reset header row spanning
self.signals.span_cells_signal.emit(
row_number, HEADER_NOTES_COLUMN, 1, 1
@ -723,7 +701,8 @@ class PlaylistModel(QAbstractTableModel):
"""
self.dataChanged.emit(
self.index(modified_row, 0), self.index(modified_row, self.columnCount() - 1)
self.index(modified_row, 0),
self.index(modified_row, self.columnCount() - 1),
)
def invalidate_rows(self, modified_rows: List[int]) -> None:
@ -734,6 +713,18 @@ class PlaylistModel(QAbstractTableModel):
for modified_row in modified_rows:
self.invalidate_row(modified_row)
def is_track_in_playlist(self, track_id: int) -> Optional[PlaylistRowData]:
"""
If this track_id is in the playlist, return the PlaylistRowData object
else return None
"""
for row_number in range(len(self.playlist_rows)):
if self.playlist_rows[row_number].track_id == track_id:
return self.playlist_rows[row_number]
return None
def mark_unplayed(self, row_numbers: List[int]) -> None:
"""
Mark row as unplayed
@ -869,6 +860,39 @@ class PlaylistModel(QAbstractTableModel):
self.signals.end_reset_model_signal.emit(to_playlist_id)
self.update_track_times()
def move_track_add_note(
self, new_row_number: int, existing_prd: PlaylistRowData, note: str
) -> None:
"""
Move existing_prd track to new_row_number and append note to any existing note
"""
if note:
with Session() as session:
plr = session.get(PlaylistRows, existing_prd.plrid)
if plr:
if plr.note:
plr.note += "\n" + note
else:
plr.note = note
# Carry out the move outside of the session context to ensure
# database updated with any note change
self.move_rows([existing_prd.plr_rownum], new_row_number)
def move_track_to_header(
self, header_row_number: int, existing_prd: PlaylistRowData, note: Optional[str]
) -> None:
"""
Add the existing_prd track details to the existing header at header_row_number
"""
if existing_prd.track_id:
if note and existing_prd.note:
note += "\n" + existing_prd.note
self.add_track_to_header(header_row_number, existing_prd.track_id, note)
self.delete_rows([existing_prd.plr_rownum])
def open_in_audacity(self, row_number: int) -> None:
"""
Open track at passed row number in Audacity
@ -1338,6 +1362,9 @@ class PlaylistProxyModel(QSortFilterProxyModel):
def is_played_row(self, row_number: int) -> bool:
return self.playlist_model.is_played_row(row_number)
def is_track_in_playlist(self, track_id: int) -> Optional[PlaylistRowData]:
return self.playlist_model.is_track_in_playlist(track_id)
def mark_unplayed(self, row_numbers: List[int]) -> None:
return self.playlist_model.mark_unplayed(row_numbers)
@ -1351,6 +1378,16 @@ class PlaylistProxyModel(QSortFilterProxyModel):
from_rows, to_row_number, to_playlist_id
)
def move_track_add_note(
self, new_row_number: int, existing_prd: PlaylistRowData, note: str
) -> None:
return self.playlist_model.move_track_add_note(new_row_number, existing_prd, note)
def move_track_to_header(
self, header_row_number: int, existing_prd: PlaylistRowData, note: Optional[str]
) -> None:
return self.playlist_model.move_track_to_header(header_row_number, existing_prd)
def open_in_audacity(self, row_number: int) -> None:
return self.playlist_model.open_in_audacity(row_number)

View File

@ -562,7 +562,7 @@ class PlaylistTab(QTableView):
dlg = TrackSelectDialog(
session=session,
new_row_number=model_row_number,
playlist_id=self.playlist_id,
model=self.playlist_model,
add_to_header=True,
)
dlg.exec()

View File

@ -786,9 +786,6 @@ padding-left: 8px;</string>
</property>
<addaction name="actionSearch"/>
<addaction name="separator"/>
<addaction name="actionSelect_next_track"/>
<addaction name="actionSelect_previous_track"/>
<addaction name="separator"/>
<addaction name="actionSearch_title_in_Wikipedia"/>
<addaction name="actionSearch_title_in_Songfacts"/>
</widget>

View File

@ -493,9 +493,6 @@ class Ui_MainWindow(object):
self.menuPlaylist.addAction(self.actionPaste)
self.menuSearc_h.addAction(self.actionSearch)
self.menuSearc_h.addSeparator()
self.menuSearc_h.addAction(self.actionSelect_next_track)
self.menuSearc_h.addAction(self.actionSelect_previous_track)
self.menuSearc_h.addSeparator()
self.menuSearc_h.addAction(self.actionSearch_title_in_Wikipedia)
self.menuSearc_h.addAction(self.actionSearch_title_in_Songfacts)
self.menuHelp.addAction(self.action_About)