Cleanup of playlistmodel.py

This commit is contained in:
Keith Edmunds 2024-07-29 21:49:17 +01:00
parent d6f55c5987
commit 076451ff89

View File

@ -75,7 +75,7 @@ class PlaylistModel(QAbstractTableModel):
*args: Optional[QObject], *args: Optional[QObject],
**kwargs: Optional[QObject], **kwargs: Optional[QObject],
) -> None: ) -> None:
log.debug(f"PlaylistModel.__init__({playlist_id=})") log.debug(f"{self}: PlaylistModel.__init__()")
self.playlist_id = playlist_id self.playlist_id = playlist_id
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -106,21 +106,19 @@ class PlaylistModel(QAbstractTableModel):
Add track to existing header row Add track to existing header row
""" """
log.debug(f"add_track_to_header({row_number=}, {track_id=}, {note=}") log.debug(f"{self}: add_track_to_header({row_number=}, {track_id=}, {note=}")
# Get existing row # Get existing row
try: try:
rat = self.playlist_rows[row_number] rat = self.playlist_rows[row_number]
except KeyError: except KeyError:
log.error( log.error(
f"KeyError in PlaylistModel:add_track_to_header " f"{self}: KeyError in add_track_to_header ({row_number=}, {track_id=})"
f"{row_number=}, {track_id=}, {len(self.playlist_rows)=}"
) )
return return
if rat.path: if rat.path:
log.error( log.error(
f"Error in PlaylistModel:add_track_to_header ({rat=}, " f"{self}: Header row already has track associated ({rat=}, {track_id=})"
"Header row already has track associated"
) )
return return
with db.Session() as session: with db.Session() as session:
@ -204,11 +202,11 @@ class PlaylistModel(QAbstractTableModel):
Actions required: Actions required:
- sanity check - sanity check
- change OBS scene if needed - change OBS scene if needed
- update display
- update track times
- update Playdates in database - update Playdates in database
- update PlaylistRows in database - update PlaylistRows in database
- update display
- find next track - find next track
- update track times
""" """
if not track_sequence.current: if not track_sequence.current:
@ -217,26 +215,31 @@ class PlaylistModel(QAbstractTableModel):
row_number = track_sequence.current.row_number row_number = track_sequence.current.row_number
# Check for OBS scene change # Check for OBS scene change
log.debug("Call OBS scene change") log.debug(f"{self}: Call OBS scene change")
self.obs_scene_change(row_number) self.obs_scene_change(row_number)
# Sanity check that we have a track_id
if not track_sequence.current.track_id: if not track_sequence.current.track_id:
log.error(f"current_track_started() called with {track_sequence.current.track_id=}") log.error(
f"{self}: current_track_started() called with {track_sequence.current.track_id=}"
)
return return
with db.Session() as session: with db.Session() as session:
# Update Playdates in database # Update Playdates in database
log.debug("update playdates") log.debug(f"{self): update playdates")
Playdates(session, track_sequence.current.track_id) Playdates(session, track_sequence.current.track_id)
# Mark track as played in playlist # Mark track as played in playlist
log.debug("Mark track as played") log.debug(f"{self): Mark track as played")
plr = session.get(PlaylistRows, track_sequence.current.playlistrow_id) plr = session.get(PlaylistRows, track_sequence.current.playlistrow_id)
if plr: if plr:
plr.played = True plr.played = True
self.refresh_row(session, plr.row_number) self.refresh_row(session, plr.row_number)
else: else:
log.error(f"Can't retrieve plr, {track_sequence.current.playlistrow_id=}") log.error(
f"{self}: Can't retrieve plr, {track_sequence.current.playlistrow_id=}"
)
# Update colour and times for current row # Update colour and times for current row
self.invalidate_row(row_number) self.invalidate_row(row_number)
@ -250,7 +253,7 @@ class PlaylistModel(QAbstractTableModel):
# Find next track # Find next track
# Get all unplayed track rows # Get all unplayed track rows
log.debug("Find next track") log.debug(f"{self}: Find next track")
next_row = None next_row = None
unplayed_rows = self.get_unplayed_rows() unplayed_rows = self.get_unplayed_rows()
if unplayed_rows: if unplayed_rows:
@ -326,7 +329,7 @@ class PlaylistModel(QAbstractTableModel):
with db.Session() as session: with db.Session() as session:
for row_number in sorted(row_numbers, reverse=True): for row_number in sorted(row_numbers, reverse=True):
log.info(f"delete_rows(), {row_number=}") log.info(f"{self}: delete_rows(), {row_number=}")
super().beginRemoveRows(QModelIndex(), row_number, row_number) super().beginRemoveRows(QModelIndex(), row_number, row_number)
# We need to remove data from the underlying data store, # We need to remove data from the underlying data store,
# which is the database, but we cache in # which is the database, but we cache in
@ -345,16 +348,18 @@ class PlaylistModel(QAbstractTableModel):
Return text for display Return text for display
""" """
header_row = self.is_header_row(row)
# Set / reset column span # Set / reset column span
if column == HEADER_NOTES_COLUMN: if column == HEADER_NOTES_COLUMN:
column_span = 1 column_span = 1
if self.is_header_row(row): if header_row:
column_span = self.columnCount() - 1 column_span = self.columnCount() - 1
self.signals.span_cells_signal.emit( self.signals.span_cells_signal.emit(
self.playlist_id, row, HEADER_NOTES_COLUMN, 1, column_span self.playlist_id, row, HEADER_NOTES_COLUMN, 1, column_span
) )
if self.is_header_row(row): if header_row:
if column == HEADER_NOTES_COLUMN: if column == HEADER_NOTES_COLUMN:
header_text = self.header_text(rat) header_text = self.header_text(rat)
if not header_text: if not header_text:
@ -401,10 +406,10 @@ class PlaylistModel(QAbstractTableModel):
End model reset if this is our playlist End model reset if this is our playlist
""" """
log.debug(f"end_reset_model({playlist_id=})") log.debug(f"{self}: end_reset_model({playlist_id=})")
if playlist_id != self.playlist_id: if playlist_id != self.playlist_id:
log.debug(f"end_reset_model: not us ({self.playlist_id=})") log.debug(f"{self}: end_reset_model: not us ({self.playlist_id=})")
return return
with db.Session() as session: with db.Session() as session:
self.refresh_data(session) self.refresh_data(session)
@ -475,7 +480,7 @@ class PlaylistModel(QAbstractTableModel):
(ie, ignore the first, not-yet-duplicate, track). (ie, ignore the first, not-yet-duplicate, track).
""" """
log.info("get_duplicate_rows() called") log.info(f"{self}: get_duplicate_rows() called")
found = [] found = []
result = [] result = []
@ -489,7 +494,7 @@ class PlaylistModel(QAbstractTableModel):
else: else:
found.append(track_id) found.append(track_id)
log.info(f"get_duplicate_rows() returned: {result=}") log.info(f"{self}: get_duplicate_rows() returned: {result=}")
return result return result
def _get_new_row_number(self, proposed_row_number: Optional[int]) -> int: def _get_new_row_number(self, proposed_row_number: Optional[int]) -> int:
@ -500,7 +505,7 @@ class PlaylistModel(QAbstractTableModel):
If not given, return row number to add to end of model. If not given, return row number to add to end of model.
""" """
log.debug(f"_get_new_row_number({proposed_row_number=})") log.debug(f"{self}: _get_new_row_number({proposed_row_number=})")
if proposed_row_number is None or proposed_row_number > len(self.playlist_rows): if proposed_row_number is None or proposed_row_number > len(self.playlist_rows):
# We are adding to the end of the list # We are adding to the end of the list
@ -511,7 +516,7 @@ class PlaylistModel(QAbstractTableModel):
else: else:
new_row_number = proposed_row_number new_row_number = proposed_row_number
log.debug(f"get_new_row_number() return: {new_row_number=}") log.debug(f"{self}: get_new_row_number() return: {new_row_number=}")
return new_row_number return new_row_number
def get_row_info(self, row_number: int) -> RowAndTrack: def get_row_info(self, row_number: int) -> RowAndTrack:
@ -556,7 +561,7 @@ class PlaylistModel(QAbstractTableModel):
for a in self.playlist_rows.values() for a in self.playlist_rows.values()
if not a.played and a.track_id is not None if not a.played and a.track_id is not None
] ]
log.debug(f"get_unplayed_rows() returned: {result=}") log.debug(f"{self}: get_unplayed_rows() returned: {result=}")
return result return result
def headerData( def headerData(
@ -644,7 +649,7 @@ class PlaylistModel(QAbstractTableModel):
Insert a row. Insert a row.
""" """
log.debug(f"insert_row({proposed_row_number=}, {track_id=}, {note=})") log.debug(f"{self}: insert_row({proposed_row_number=}, {track_id=}, {note=})")
new_row_number = self._get_new_row_number(proposed_row_number) new_row_number = self._get_new_row_number(proposed_row_number)
@ -668,7 +673,7 @@ class PlaylistModel(QAbstractTableModel):
def invalidate_row(self, modified_row: int) -> None: def invalidate_row(self, modified_row: int) -> None:
""" """
Signal to view to refresh invlidated row Signal to view to refresh invalidated row
""" """
self.dataChanged.emit( self.dataChanged.emit(
@ -702,7 +707,7 @@ class PlaylistModel(QAbstractTableModel):
def is_track_in_playlist(self, track_id: int) -> Optional[RowAndTrack]: def is_track_in_playlist(self, track_id: int) -> Optional[RowAndTrack]:
""" """
If this track_id is in the playlist, return the PlaylistRowData object If this track_id is in the playlist, return the RowAndTrack object
else return None else return None
""" """
@ -719,10 +724,12 @@ class PlaylistModel(QAbstractTableModel):
with db.Session() as session: with db.Session() as session:
for row_number in row_numbers: for row_number in row_numbers:
plr = session.get(PlaylistRows, self.playlist_rows[row_number].row_number) playlist_row = session.get(
if not plr: PlaylistRows, self.playlist_rows[row_number].row_number
)
if not playlist_row:
return return
plr.played = False playlist_row.played = False
session.commit() session.commit()
self.refresh_row(session, row_number) self.refresh_row(session, row_number)
@ -734,7 +741,7 @@ class PlaylistModel(QAbstractTableModel):
Move the playlist rows given to to_row and below. Move the playlist rows given to to_row and below.
""" """
log.debug(f"move_rows({from_rows=}, {to_row_number=}") log.debug(f"{self}: move_rows({from_rows=}, {to_row_number=}")
# Build a {current_row_number: new_row_number} dictionary # Build a {current_row_number: new_row_number} dictionary
row_map: dict[int, int] = {} row_map: dict[int, int] = {}
@ -814,7 +821,8 @@ class PlaylistModel(QAbstractTableModel):
""" """
log.debug( log.debug(
f"move_rows_between_playlists({from_rows=}, {to_row_number=}, {to_playlist_id=}" f"{self}: move_rows_between_playlists({from_rows=}, "
f"{to_row_number=}, {to_playlist_id=}"
) )
# Row removal must be wrapped in beginRemoveRows .. # Row removal must be wrapped in beginRemoveRows ..
@ -876,16 +884,16 @@ class PlaylistModel(QAbstractTableModel):
Move existing_rat track to new_row_number and append note to any existing note Move existing_rat track to new_row_number and append note to any existing note
""" """
log.info(f"move_track_add_note({new_row_number=}, {existing_rat=}, {note=}") log.info(f"{self}: move_track_add_note({new_row_number=}, {existing_rat=}, {note=}")
if note: if note:
with db.Session() as session: with db.Session() as session:
plr = session.get(PlaylistRows, existing_rat.playlistrow_id) playlist_row = session.get(PlaylistRows, existing_rat.playlistrow_id)
if plr: if playlist_row:
if plr.note: if playlist_row.note:
plr.note += "\n" + note playlist_row.note += "\n" + note
else: else:
plr.note = note playlist_row.note = note
session.commit() session.commit()
# Carry out the move outside of the session context to ensure # Carry out the move outside of the session context to ensure
@ -900,10 +908,10 @@ class PlaylistModel(QAbstractTableModel):
note: Optional[str], note: Optional[str],
) -> None: ) -> None:
""" """
Add the existing_rat track details to the existing header at header_row_number Add the existing_rat track details to the existing header at header_row_number
""" """
log.info(f"move_track_to_header({header_row_number=}, {existing_rat=}, {note=}") log.info(f"{self}: move_track_to_header({header_row_number=}, {existing_rat=}, {note=}")
if existing_rat.track_id: if existing_rat.track_id:
if note and existing_rat.note: if note and existing_rat.note:
@ -917,7 +925,7 @@ class PlaylistModel(QAbstractTableModel):
and execute any found and execute any found
""" """
log.info(f"obs_scene_change({row_number=})") log.info(f"{self}: obs_scene_change({row_number=})")
# Check any headers before this row # Check any headers before this row
idx = row_number - 1 idx = row_number - 1
@ -941,10 +949,10 @@ class PlaylistModel(QAbstractTableModel):
sceneName=scene_name sceneName=scene_name
) )
) )
log.info(f"OBS scene changed to '{scene_name}'") log.info(f"{self}: OBS scene changed to '{scene_name}'")
continue continue
except obswebsocket.exceptions.ConnectionFailure: except obswebsocket.exceptions.ConnectionFailure:
log.error("OBS connection refused") log.error(f"{self}: OBS connection refused")
return return
def previous_track_ended(self) -> None: def previous_track_ended(self) -> None:
@ -956,15 +964,15 @@ class PlaylistModel(QAbstractTableModel):
- update display - update display
""" """
log.info("previous_track_ended()") log.info(f"{self}: previous_track_ended()")
# Sanity check # Sanity check
if not track_sequence.previous: if not track_sequence.previous:
log.error("playlistmodel:previous_track_ended called with no current track") log.error(f"{self}: playlistmodel:previous_track_ended called with no current track")
return return
if track_sequence.previous.row_number is None: if track_sequence.previous.row_number is None:
log.error( log.error(
"playlistmodel:previous_track_ended called with no row number " f"{self}: previous_track_ended called with no row number "
f"({track_sequence.previous=})" f"({track_sequence.previous=})"
) )
return return
@ -991,12 +999,14 @@ class PlaylistModel(QAbstractTableModel):
Remove track from row, retaining row as a header row Remove track from row, retaining row as a header row
""" """
log.info(f"remove_track({row_number=})") log.info(f"{self}: remove_track({row_number=})")
with db.Session() as session: with db.Session() as session:
plr = session.get(PlaylistRows, self.playlist_rows[row_number].playlistrow_id) playlist_row = session.get(
if plr: PlaylistRows, self.playlist_rows[row_number].playlistrow_id
plr.track_id = None )
if playlist_row:
playlist_row.track_id = None
session.commit() session.commit()
self.refresh_row(session, row_number) self.refresh_row(session, row_number)
self.invalidate_row(row_number) self.invalidate_row(row_number)
@ -1027,7 +1037,7 @@ class PlaylistModel(QAbstractTableModel):
looking up the playlistrow_id and retrieving the row number from the database. looking up the playlistrow_id and retrieving the row number from the database.
""" """
log.debug("reset_track_sequence_row_numbers()") log.debug(f"{self}: reset_track_sequence_row_numbers()")
# Check the track_sequence.next, current and previous plrs and # Check the track_sequence.next, current and previous plrs and
# update the row number # update the row number
@ -1056,7 +1066,7 @@ class PlaylistModel(QAbstractTableModel):
return: [[20, 21], [17], [13], [9, 10], [7], [2, 3, 4, 5]] return: [[20, 21], [17], [13], [9, 10], [7], [2, 3, 4, 5]]
""" """
log.debug(f"_reversed_contiguous_row_groups({row_numbers=} called") log.debug(f"{self}: _reversed_contiguous_row_groups({row_numbers=} called")
result: list[list[int]] = [] result: list[list[int]] = []
temp: list[int] = [] temp: list[int] = []
@ -1072,7 +1082,7 @@ class PlaylistModel(QAbstractTableModel):
result.append(temp) result.append(temp)
result.reverse() result.reverse()
log.debug(f"_reversed_contiguous_row_groups() returned: {result=}") log.debug(f"{self}: _reversed_contiguous_row_groups() returned: {result=}")
return result return result
def rowCount(self, index: QModelIndex = QModelIndex()) -> int: def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
@ -1164,39 +1174,32 @@ class PlaylistModel(QAbstractTableModel):
return True return True
def set_next_row(self, row_number: Optional[int]) -> bool: def set_next_row(self, row_number: Optional[int]) -> None:
""" """
Set row_number as next track. If row_number is None, clear next track. Set row_number as next track. If row_number is None, clear next track.
Return True if successful else False. Return True if successful else False.
""" """
log.debug(f"set_next_row({row_number=})") log.debug(f"{self}: set_next_row({row_number=})")
if row_number is None: if row_number is None:
# Clear next track # Clear next track
if track_sequence.next is not None: if track_sequence.next is not None:
track_sequence.next = None track_sequence.next = None
else:
return True
else: else:
# Get playlistrow_id of row # Get playlistrow_id of row
try: try:
rat = self.playlist_rows[row_number] rat = self.playlist_rows[row_number]
except IndexError: except IndexError:
log.error( log.error(f"{self} set_track_sequence.next({row_number=}, IndexError")
f"playlistmodel.set_track_sequence.next({row_number=}, " return
f"{self.playlist_id=}"
"IndexError"
)
return False
if rat.track_id is None or rat.row_number is None: if rat.track_id is None or rat.row_number is None:
log.error( log.error(
f"playlistmodel.set_track_sequence.next({row_number=}, " f"{self} .set_track_sequence.next({row_number=}, "
"No track / row number " f"No track / row number {rat.track_id=}, {rat.row_number=}"
f"{self.playlist_id=}, {rat.track_id=}, {rat.row_number=}"
) )
return False return
old_next_row: Optional[int] = None old_next_row: Optional[int] = None
if track_sequence.next: if track_sequence.next:
@ -1221,8 +1224,6 @@ class PlaylistModel(QAbstractTableModel):
self.signals.next_track_changed_signal.emit() self.signals.next_track_changed_signal.emit()
self.update_track_times() self.update_track_times()
return True
def setData( def setData(
self, self,
index: QModelIndex, index: QModelIndex,
@ -1233,49 +1234,49 @@ class PlaylistModel(QAbstractTableModel):
Update model with edited data Update model with edited data
""" """
if index.isValid() and role == Qt.ItemDataRole.EditRole: if not index.isValid() or role != Qt.ItemDataRole.EditRole:
row_number = index.row() return False
column = index.column()
with db.Session() as session: row_number = index.row()
plr = session.get(PlaylistRows, self.playlist_rows[row_number].playlistrow_id) column = index.column()
if not plr:
print(
f"Error saving data: {row_number=}, {column=}, "
f"{value=}, {self.playlist_id=}"
)
return False
if plr.track_id: with db.Session() as session:
if column in [Col.TITLE.value, Col.ARTIST.value, Col.INTRO.value]: playlist_row = session.get(
track = session.get(Tracks, plr.track_id) PlaylistRows, self.playlist_rows[row_number].playlistrow_id
if not track: )
print(f"Error retreiving track: {plr=}") if not playlist_row:
return False log.error(f"{self}: Error saving data: {row_number=}, {column=}, {value=}")
if column == Col.TITLE.value: return False
track.title = str(value)
elif column == Col.ARTIST.value:
track.artist = str(value)
elif column == Col.INTRO.value:
track.intro = int(round(float(value), 1) * 1000)
else:
print(f"Error updating track: {column=}, {value=}")
return False
elif column == Col.NOTE.value:
plr.note = str(value)
else: if playlist_row.track_id:
# This is a header row if column in [Col.TITLE.value, Col.ARTIST.value, Col.INTRO.value]:
if column == HEADER_NOTES_COLUMN: track = session.get(Tracks, playlist_row.track_id)
plr.note = str(value) if not track:
log.error(f"{self}: Error retreiving track: {playlist_row=}")
return False
if column == Col.TITLE.value:
track.title = str(value)
elif column == Col.ARTIST.value:
track.artist = str(value)
elif column == Col.INTRO.value:
track.intro = int(round(float(value), 1) * 1000)
else:
log.error(f"{self}: Error updating track: {column=}, {value=}")
return False
elif column == Col.NOTE.value:
playlist_row.note = str(value)
# commit changes before refreshing data else:
session.commit() # This is a header row
self.refresh_row(session, row_number) if column == HEADER_NOTES_COLUMN:
self.dataChanged.emit(index, index, [Qt.ItemDataRole.DisplayRole, role]) playlist_row.note = str(value)
return True
return False # commit changes before refreshing data
session.commit()
self.refresh_row(session, row_number)
self.dataChanged.emit(index, index, [Qt.ItemDataRole.DisplayRole, role])
return True
def sort_by_artist(self, row_numbers: list[int]) -> None: def sort_by_artist(self, row_numbers: list[int]) -> None:
""" """
@ -1294,8 +1295,8 @@ class PlaylistModel(QAbstractTableModel):
# interested in # interested in
shortlist_rows = {k: self.playlist_rows[k] for k in row_numbers} shortlist_rows = {k: self.playlist_rows[k] for k in row_numbers}
sorted_list = [ sorted_list = [
plr.row_number playlist_row.row_number
for plr in sorted(shortlist_rows.values(), key=attrgetter(attr_name)) for playlist_row in sorted(shortlist_rows.values(), key=attrgetter(attr_name))
] ]
self.move_rows(sorted_list, min(sorted_list)) self.move_rows(sorted_list, min(sorted_list))
@ -1388,7 +1389,7 @@ class PlaylistModel(QAbstractTableModel):
Update track start/end times in self.playlist_rows Update track start/end times in self.playlist_rows
""" """
log.debug("update_track_times()") log.debug(f"{self}: update_track_times()")
next_start_time: Optional[dt.datetime] = None next_start_time: Optional[dt.datetime] = None
update_rows: list[int] = [] update_rows: list[int] = []
@ -1636,8 +1637,8 @@ class PlaylistProxyModel(QSortFilterProxyModel):
def rescan_track(self, row_number: int) -> None: def rescan_track(self, row_number: int) -> None:
return self.source_model.rescan_track(row_number) return self.source_model.rescan_track(row_number)
def set_next_row(self, row_number: Optional[int]) -> bool: def set_next_row(self, row_number: Optional[int]) -> None:
return self.source_model.set_next_row(row_number) self.source_model.set_next_row(row_number)
def sort_by_artist(self, row_numbers: list[int]) -> None: def sort_by_artist(self, row_numbers: list[int]) -> None:
return self.source_model.sort_by_artist(row_numbers) return self.source_model.sort_by_artist(row_numbers)