diff --git a/app/models.py b/app/models.py index 65428af..7191428 100644 --- a/app/models.py +++ b/app/models.py @@ -464,26 +464,32 @@ class PlaylistRows(Base): session.commit() @classmethod - def get_section_header_rows(cls, session: scoped_session, - playlist_id: int) -> List["PlaylistRows"]: + def get_from_id_list(cls, session: scoped_session, playlist_id: int, + plr_ids: List[int]) -> List["PlaylistRows"]: """ - Return a list of PlaylistRows that are section headers for this - playlist + Take a list of PlaylistRows ids and return a list of corresponding + PlaylistRows objects """ plrs = session.execute( select(cls) .where( cls.playlist_id == playlist_id, - cls.track_id.is_(None), - ( - cls.note.endswith("-") | - cls.note.endswith("+") - ) + cls.id.in_(plr_ids) ).order_by(cls.row_number)).scalars().all() return plrs + @staticmethod + def get_last_used_row(session: scoped_session, + playlist_id: int) -> Optional[int]: + """Return the last used row for playlist, or None if no rows""" + + return session.execute( + select(func.max(PlaylistRows.row_number)) + .where(PlaylistRows.playlist_id == playlist_id) + ).scalar_one() + @staticmethod def get_track_plr(session: scoped_session, track_id: int, playlist_id: int) -> Optional["PlaylistRows"]: @@ -498,16 +504,6 @@ class PlaylistRows(Base): .limit(1) ).first() - @staticmethod - def get_last_used_row(session: scoped_session, - playlist_id: int) -> Optional[int]: - """Return the last used row for playlist, or None if no rows""" - - return session.execute( - select(func.max(PlaylistRows.row_number)) - .where(PlaylistRows.playlist_id == playlist_id) - ).scalar_one() - @classmethod def get_played_rows(cls, session: scoped_session, playlist_id: int) -> List["PlaylistRows"]: @@ -572,27 +568,6 @@ class PlaylistRows(Base): return plrs - @staticmethod - def indexed_by_id(session: scoped_session, - plr_ids: Union[Iterable[int], ValuesView]) -> dict: - """ - Return a dictionary of playlist_rows indexed by their plr id from - the passed plr_id list. - """ - - plrs = session.execute( - select(PlaylistRows) - .where( - PlaylistRows.id.in_(plr_ids) - ) - ).scalars().all() - - result = {} - for plr in plrs: - result[plr.id] = plr - - return result - @staticmethod def move_rows_down(session: scoped_session, playlist_id: int, starting_row: int, move_by: int) -> None: diff --git a/app/playlists.py b/app/playlists.py index a98999a..e65cb64 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -63,6 +63,7 @@ if TYPE_CHECKING: from musicmuster import Window, MusicMusterSignals start_time_re = re.compile(r"@\d\d:\d\d:\d\d") +section_header_cleanup_re = re.compile(r"(@\d\d:\d\d:\d\d.*)?(\+)?") HEADER_NOTES_COLUMN = 2 # Columns @@ -255,9 +256,6 @@ class PlaylistTab(QTableWidget): with Session() as session: self.save_playlist(session) - # Update track times - self._update_start_end_times() - def _add_context_menu(self, text: str, action: Callable, disabled: bool = False) -> QAction: """ @@ -565,8 +563,7 @@ class PlaylistTab(QTableWidget): self._set_row_bold(row, bold) if update_track_times: - # Queue time updates so playlist updates first - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times() def insert_track(self, session: scoped_session, track: Tracks, note: str = "", repaint: bool = True) -> None: @@ -606,10 +603,6 @@ class PlaylistTab(QTableWidget): plr = PlaylistRows(session, self.playlist_id, track.id, row_number, note) self.insert_row(session, plr) - session.flush() - - # Let display update, then save playlist - # TODO: QTimer.singleShot(0, lambda: self.save_playlist(session)) self.save_playlist(session) def play_ended(self) -> None: @@ -686,8 +679,6 @@ class PlaylistTab(QTableWidget): self.insert_row(session, plr, update_track_times=False, played=plr.row_number in played_rows) - self._update_start_end_times() - # Scroll to top if scroll_to_top: row0_item = self.item(0, 0) @@ -1086,10 +1077,7 @@ class PlaylistTab(QTableWidget): # Reset drag mode self.setDragEnabled(False) - self.save_playlist(session) - - # Queue time updates so playlist updates first - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times() def _drop_on(self, event): """ @@ -1520,7 +1508,6 @@ class PlaylistTab(QTableWidget): _ = self._set_row_note_colour(session, row, plr.note, section_header=True) - self._update_start_end_times() self.clear_selection() # Set track start/end times after track list is populated @@ -2127,42 +2114,47 @@ class PlaylistTab(QTableWidget): Update section headers with run time of section """ - header_rows = [] + section_start_rows: List[PlaylistRows] = [] + + header_rows = [self._get_row_plr_id(row_number) for row_number in + range(self.rowCount()) + if not self._get_row_track_id(row_number)] + plrs = PlaylistRows.get_from_id_list(session, self.playlist_id, + header_rows) - # Get section header PlaylistRows. Flush session first in case - # there are pending playlist changes that affect which row - # numbers are headers. - session.flush() - plrs = PlaylistRows.get_section_header_rows(session, self.playlist_id) for plr in plrs: - # TODO: print(f"{plr.row_number=}") if plr.note.endswith("+"): - header_rows.append(plr) + section_start_rows.append(plr) continue - assert plr.note.endswith("-") - try: - from_plr = header_rows.pop() - to_plr = plr - total_time = self._track_time_between_rows(session, - from_plr, to_plr) - time_str = self._get_section_timing_string(total_time) - self._update_note_text(from_plr, from_plr.note + time_str) + elif plr.note.endswith("-"): + try: + from_plr = section_start_rows.pop() + to_plr = plr + total_time = self._track_time_between_rows( + session, from_plr, to_plr) + time_str = self._get_section_timing_string(total_time) + self._update_note_text(from_plr, from_plr.note + time_str) - # Update section end - if to_plr.note.strip() == "-": - new_text = ( - "[End " + from_plr.note.strip()[:-1].strip() + "]" - ) - self._update_note_text(plr, new_text) - except IndexError: - continue + # Update section end + if to_plr.note.strip() == "-": + new_text = ( + "[End " + re.sub( + section_header_cleanup_re, '', from_plr.note, + ).strip() + "]" + ) + self._update_note_text(plr, new_text) + except IndexError: + # This ending row may have a time left from before a + # starting row above was deleted, so replace content + self._update_note_text(plr, plr.note) + continue - # If we still have plrs in header_rows, there isn't an end + # If we still have plrs in section_start_rows, there isn't an end # section row for them possible_plr = self._get_row_plr(session, self.rowCount() - 1) if possible_plr: to_plr = possible_plr - for from_plr in header_rows: + for from_plr in section_start_rows: total_time = self._track_time_between_rows(session, from_plr, to_plr) time_str = self._get_section_timing_string(total_time,