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],
**kwargs: Optional[QObject],
) -> None:
log.debug(f"PlaylistModel.__init__({playlist_id=})")
log.debug(f"{self}: PlaylistModel.__init__()")
self.playlist_id = playlist_id
super().__init__(*args, **kwargs)
@ -106,21 +106,19 @@ class PlaylistModel(QAbstractTableModel):
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
try:
rat = self.playlist_rows[row_number]
except KeyError:
log.error(
f"KeyError in PlaylistModel:add_track_to_header "
f"{row_number=}, {track_id=}, {len(self.playlist_rows)=}"
f"{self}: KeyError in add_track_to_header ({row_number=}, {track_id=})"
)
return
if rat.path:
log.error(
f"Error in PlaylistModel:add_track_to_header ({rat=}, "
"Header row already has track associated"
f"{self}: Header row already has track associated ({rat=}, {track_id=})"
)
return
with db.Session() as session:
@ -204,11 +202,11 @@ class PlaylistModel(QAbstractTableModel):
Actions required:
- sanity check
- change OBS scene if needed
- update display
- update track times
- update Playdates in database
- update PlaylistRows in database
- update display
- find next track
- update track times
"""
if not track_sequence.current:
@ -217,26 +215,31 @@ class PlaylistModel(QAbstractTableModel):
row_number = track_sequence.current.row_number
# 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)
# Sanity check that we have a 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
with db.Session() as session:
# Update Playdates in database
log.debug("update playdates")
log.debug(f"{self): update playdates")
Playdates(session, track_sequence.current.track_id)
# 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)
if plr:
plr.played = True
self.refresh_row(session, plr.row_number)
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
self.invalidate_row(row_number)
@ -250,7 +253,7 @@ class PlaylistModel(QAbstractTableModel):
# Find next track
# Get all unplayed track rows
log.debug("Find next track")
log.debug(f"{self}: Find next track")
next_row = None
unplayed_rows = self.get_unplayed_rows()
if unplayed_rows:
@ -326,7 +329,7 @@ class PlaylistModel(QAbstractTableModel):
with db.Session() as session:
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)
# We need to remove data from the underlying data store,
# which is the database, but we cache in
@ -345,16 +348,18 @@ class PlaylistModel(QAbstractTableModel):
Return text for display
"""
header_row = self.is_header_row(row)
# Set / reset column span
if column == HEADER_NOTES_COLUMN:
column_span = 1
if self.is_header_row(row):
if header_row:
column_span = self.columnCount() - 1
self.signals.span_cells_signal.emit(
self.playlist_id, row, HEADER_NOTES_COLUMN, 1, column_span
)
if self.is_header_row(row):
if header_row:
if column == HEADER_NOTES_COLUMN:
header_text = self.header_text(rat)
if not header_text:
@ -401,10 +406,10 @@ class PlaylistModel(QAbstractTableModel):
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:
log.debug(f"end_reset_model: not us ({self.playlist_id=})")
log.debug(f"{self}: end_reset_model: not us ({self.playlist_id=})")
return
with db.Session() as session:
self.refresh_data(session)
@ -475,7 +480,7 @@ class PlaylistModel(QAbstractTableModel):
(ie, ignore the first, not-yet-duplicate, track).
"""
log.info("get_duplicate_rows() called")
log.info(f"{self}: get_duplicate_rows() called")
found = []
result = []
@ -489,7 +494,7 @@ class PlaylistModel(QAbstractTableModel):
else:
found.append(track_id)
log.info(f"get_duplicate_rows() returned: {result=}")
log.info(f"{self}: get_duplicate_rows() returned: {result=}")
return result
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.
"""
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):
# We are adding to the end of the list
@ -511,7 +516,7 @@ class PlaylistModel(QAbstractTableModel):
else:
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
def get_row_info(self, row_number: int) -> RowAndTrack:
@ -556,7 +561,7 @@ class PlaylistModel(QAbstractTableModel):
for a in self.playlist_rows.values()
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
def headerData(
@ -644,7 +649,7 @@ class PlaylistModel(QAbstractTableModel):
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)
@ -668,7 +673,7 @@ class PlaylistModel(QAbstractTableModel):
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(
@ -702,7 +707,7 @@ class PlaylistModel(QAbstractTableModel):
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
"""
@ -719,10 +724,12 @@ class PlaylistModel(QAbstractTableModel):
with db.Session() as session:
for row_number in row_numbers:
plr = session.get(PlaylistRows, self.playlist_rows[row_number].row_number)
if not plr:
playlist_row = session.get(
PlaylistRows, self.playlist_rows[row_number].row_number
)
if not playlist_row:
return
plr.played = False
playlist_row.played = False
session.commit()
self.refresh_row(session, row_number)
@ -734,7 +741,7 @@ class PlaylistModel(QAbstractTableModel):
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
row_map: dict[int, int] = {}
@ -814,7 +821,8 @@ class PlaylistModel(QAbstractTableModel):
"""
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 ..
@ -876,16 +884,16 @@ class PlaylistModel(QAbstractTableModel):
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:
with db.Session() as session:
plr = session.get(PlaylistRows, existing_rat.playlistrow_id)
if plr:
if plr.note:
plr.note += "\n" + note
playlist_row = session.get(PlaylistRows, existing_rat.playlistrow_id)
if playlist_row:
if playlist_row.note:
playlist_row.note += "\n" + note
else:
plr.note = note
playlist_row.note = note
session.commit()
# Carry out the move outside of the session context to ensure
@ -900,10 +908,10 @@ class PlaylistModel(QAbstractTableModel):
note: Optional[str],
) -> 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 note and existing_rat.note:
@ -917,7 +925,7 @@ class PlaylistModel(QAbstractTableModel):
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
idx = row_number - 1
@ -941,10 +949,10 @@ class PlaylistModel(QAbstractTableModel):
sceneName=scene_name
)
)
log.info(f"OBS scene changed to '{scene_name}'")
log.info(f"{self}: OBS scene changed to '{scene_name}'")
continue
except obswebsocket.exceptions.ConnectionFailure:
log.error("OBS connection refused")
log.error(f"{self}: OBS connection refused")
return
def previous_track_ended(self) -> None:
@ -956,15 +964,15 @@ class PlaylistModel(QAbstractTableModel):
- update display
"""
log.info("previous_track_ended()")
log.info(f"{self}: previous_track_ended()")
# Sanity check
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
if track_sequence.previous.row_number is None:
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=})"
)
return
@ -991,12 +999,14 @@ class PlaylistModel(QAbstractTableModel):
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:
plr = session.get(PlaylistRows, self.playlist_rows[row_number].playlistrow_id)
if plr:
plr.track_id = None
playlist_row = session.get(
PlaylistRows, self.playlist_rows[row_number].playlistrow_id
)
if playlist_row:
playlist_row.track_id = None
session.commit()
self.refresh_row(session, 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.
"""
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
# update the row number
@ -1056,7 +1066,7 @@ class PlaylistModel(QAbstractTableModel):
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]] = []
temp: list[int] = []
@ -1072,7 +1082,7 @@ class PlaylistModel(QAbstractTableModel):
result.append(temp)
result.reverse()
log.debug(f"_reversed_contiguous_row_groups() returned: {result=}")
log.debug(f"{self}: _reversed_contiguous_row_groups() returned: {result=}")
return result
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
@ -1164,39 +1174,32 @@ class PlaylistModel(QAbstractTableModel):
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.
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:
# Clear next track
if track_sequence.next is not None:
track_sequence.next = None
else:
return True
else:
# Get playlistrow_id of row
try:
rat = self.playlist_rows[row_number]
except IndexError:
log.error(
f"playlistmodel.set_track_sequence.next({row_number=}, "
f"{self.playlist_id=}"
"IndexError"
)
return False
log.error(f"{self} set_track_sequence.next({row_number=}, IndexError")
return
if rat.track_id is None or rat.row_number is None:
log.error(
f"playlistmodel.set_track_sequence.next({row_number=}, "
"No track / row number "
f"{self.playlist_id=}, {rat.track_id=}, {rat.row_number=}"
f"{self} .set_track_sequence.next({row_number=}, "
f"No track / row number {rat.track_id=}, {rat.row_number=}"
)
return False
return
old_next_row: Optional[int] = None
if track_sequence.next:
@ -1221,8 +1224,6 @@ class PlaylistModel(QAbstractTableModel):
self.signals.next_track_changed_signal.emit()
self.update_track_times()
return True
def setData(
self,
index: QModelIndex,
@ -1233,49 +1234,49 @@ class PlaylistModel(QAbstractTableModel):
Update model with edited data
"""
if index.isValid() and role == Qt.ItemDataRole.EditRole:
row_number = index.row()
column = index.column()
if not index.isValid() or role != Qt.ItemDataRole.EditRole:
return False
with db.Session() as session:
plr = session.get(PlaylistRows, self.playlist_rows[row_number].playlistrow_id)
if not plr:
print(
f"Error saving data: {row_number=}, {column=}, "
f"{value=}, {self.playlist_id=}"
)
return False
row_number = index.row()
column = index.column()
if plr.track_id:
if column in [Col.TITLE.value, Col.ARTIST.value, Col.INTRO.value]:
track = session.get(Tracks, plr.track_id)
if not track:
print(f"Error retreiving track: {plr=}")
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:
print(f"Error updating track: {column=}, {value=}")
return False
elif column == Col.NOTE.value:
plr.note = str(value)
with db.Session() as session:
playlist_row = session.get(
PlaylistRows, self.playlist_rows[row_number].playlistrow_id
)
if not playlist_row:
log.error(f"{self}: Error saving data: {row_number=}, {column=}, {value=}")
return False
else:
# This is a header row
if column == HEADER_NOTES_COLUMN:
plr.note = str(value)
if playlist_row.track_id:
if column in [Col.TITLE.value, Col.ARTIST.value, Col.INTRO.value]:
track = session.get(Tracks, playlist_row.track_id)
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
session.commit()
self.refresh_row(session, row_number)
self.dataChanged.emit(index, index, [Qt.ItemDataRole.DisplayRole, role])
return True
else:
# This is a header row
if column == HEADER_NOTES_COLUMN:
playlist_row.note = str(value)
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:
"""
@ -1294,8 +1295,8 @@ class PlaylistModel(QAbstractTableModel):
# interested in
shortlist_rows = {k: self.playlist_rows[k] for k in row_numbers}
sorted_list = [
plr.row_number
for plr in sorted(shortlist_rows.values(), key=attrgetter(attr_name))
playlist_row.row_number
for playlist_row in sorted(shortlist_rows.values(), key=attrgetter(attr_name))
]
self.move_rows(sorted_list, min(sorted_list))
@ -1388,7 +1389,7 @@ class PlaylistModel(QAbstractTableModel):
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
update_rows: list[int] = []
@ -1636,8 +1637,8 @@ class PlaylistProxyModel(QSortFilterProxyModel):
def rescan_track(self, row_number: int) -> None:
return self.source_model.rescan_track(row_number)
def set_next_row(self, row_number: Optional[int]) -> bool:
return self.source_model.set_next_row(row_number)
def set_next_row(self, row_number: Optional[int]) -> None:
self.source_model.set_next_row(row_number)
def sort_by_artist(self, row_numbers: list[int]) -> None:
return self.source_model.sort_by_artist(row_numbers)