From f3631b2c2b7a512604619949311e483b4e3d33f3 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Tue, 14 Mar 2023 22:59:39 +0000 Subject: [PATCH] Synchronise row start/end updates Row start/end time updates were being run in a different SQLAlchemy session to the database updates and thus there was a lack of synchronisation. Now they run in the same session. --- app/playlists.py | 225 ++++++++++++++++++++++++----------------------- 1 file changed, 115 insertions(+), 110 deletions(-) diff --git a/app/playlists.py b/app/playlists.py index 660a95e..b038769 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -1,3 +1,4 @@ +import os import re import stackprinter # type: ignore import subprocess @@ -253,9 +254,9 @@ class PlaylistTab(QTableWidget): with Session() as session: self.save_playlist(session) + self._update_start_end_times(session) self.hide_or_show_played_tracks() - QTimer.singleShot(0, self._update_start_end_times) def _add_context_menu(self, text: str, action: Callable, disabled: bool = False) -> QAction: @@ -377,7 +378,8 @@ class PlaylistTab(QTableWidget): # Update start times in case a start time in a note has been # edited - self._update_start_end_times() + with Session() as session: + self._update_start_end_times(session) def edit(self, index: QModelIndex, # type: ignore # FIXME trigger: QAbstractItemView.EditTrigger, @@ -512,9 +514,7 @@ class PlaylistTab(QTableWidget): self.insert_row(session, plr) self._set_row_header_text(session, row_number, note) self.save_playlist(session) - # Queue up time calculations to take place after UI has - # updated - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times(session) def insert_row(self, session: scoped_session, plr: PlaylistRows, update_track_times: bool = True, played=False) -> None: @@ -592,9 +592,7 @@ class PlaylistTab(QTableWidget): row_number, note) self.insert_row(session, plr) self.save_playlist(session) - # Queue up time calculations to take place after UI has - # updated - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times(session) def play_ended(self) -> None: """ @@ -622,12 +620,13 @@ class PlaylistTab(QTableWidget): current_row = self._get_current_track_row_number() if current_row is None: - send_mail(Config.ERRORS_TO, - Config.ERRORS_FROM, - "MusicMuster unexpected failure", - stackprinter.format() - ) - print("play_started:current_row is None") + if os.environ["MM_ENV"] == "PRODUCTION": + send_mail(Config.ERRORS_TO, + Config.ERRORS_FROM, + "playlists:play_started:current_row is None", + stackprinter.format() + ) + print("playlists:play_started:current_row is None") stackprinter.show(add_summary=True, style="darkbg") return @@ -643,7 +642,7 @@ class PlaylistTab(QTableWidget): self._set_row_colour_current(current_row) # Update start/stop times - self._update_start_end_times() + self._update_start_end_times(session) # Update hidden tracks QTimer.singleShot(Config.HIDE_AFTER_PLAYING_OFFSET, @@ -667,12 +666,13 @@ class PlaylistTab(QTableWidget): # Add the rows playlist = session.get(Playlists, playlist_id) if not playlist: - send_mail(Config.ERRORS_TO, - Config.ERRORS_FROM, - "MusicMuster unexpected failure", - stackprinter.format() - ) - print("populate_display:no playlist") + if os.environ["MM_ENV"] == "PRODUCTION": + send_mail(Config.ERRORS_TO, + Config.ERRORS_FROM, + "playlists:populate_display:no playlist", + stackprinter.format() + ) + print("playlists:populate_display:no playlist") stackprinter.show(add_summary=True, style="darkbg") return @@ -692,7 +692,7 @@ class PlaylistTab(QTableWidget): self.save_playlist(session) # Queue up time calculations to take place after UI has # updated - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times(session) # Needed to wrap notes column correctly - add to event queue so # that it's processed after list is populated QTimer.singleShot(0, self.tab_visible) @@ -736,10 +736,12 @@ class PlaylistTab(QTableWidget): # Any rows in the database for this playlist that has a row # number equal to or greater than the row count needs to be # removed. - session.flush() PlaylistRows.delete_higher_rows( session, self.playlist_id, self.rowCount() - 1) + # Get changes into db + session.flush() + def scroll_current_to_top(self) -> None: """Scroll currently-playing row to top""" @@ -897,7 +899,7 @@ class PlaylistTab(QTableWidget): self.clear_selection() self.save_playlist(session) # Update times once display updated - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times(session) def _build_context_menu(self, item: QTableWidgetItem) -> None: """Used to process context (right-click) menu, which is defined here""" @@ -1081,7 +1083,7 @@ class PlaylistTab(QTableWidget): # Reset drag mode self.setDragEnabled(False) - self._update_start_end_times() + self._update_start_end_times(session) def _drop_on(self, event): """ @@ -1380,8 +1382,8 @@ class PlaylistTab(QTableWidget): if not plr: return plr.played = False + self._update_start_end_times(session) self.hide_or_show_played_tracks() - self._update_start_end_times() def _move_row(self, session: scoped_session, plr: PlaylistRows, new_row_number: int) -> None: @@ -1402,7 +1404,7 @@ class PlaylistTab(QTableWidget): self.hide_or_show_played_tracks() # Queue up time calculations to take place after UI has # updated - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times(session) def _mplayer_play(self, row_number: int) -> None: """Play track with mplayer""" @@ -1481,7 +1483,7 @@ class PlaylistTab(QTableWidget): self.clear_selection() # Set track start/end times after track list is populated - QTimer.singleShot(0, self._update_start_end_times) + self._update_start_end_times(session) def _rescan(self, row_number: int, track_id: int) -> None: """Rescan track""" @@ -1509,7 +1511,7 @@ class PlaylistTab(QTableWidget): ) self._set_row_colour_unreadable(row_number) - self._update_start_end_times() + self._update_start_end_times(session) self.clear_selection() def _run_subprocess(self, args): @@ -1730,7 +1732,7 @@ class PlaylistTab(QTableWidget): # Update start/stop times self.clear_selection() - self._update_start_end_times() + self._update_start_end_times(session) def _set_played_row(self, session: scoped_session, row_number: int) -> None: @@ -1877,14 +1879,16 @@ class PlaylistTab(QTableWidget): # Sanity check: this should be a header row and thus not have a # track associate if self._get_row_track_id(row_number): - send_mail(Config.ERRORS_TO, - Config.ERRORS_FROM, - "playists:_set_row_header_text() called on track row", - stackprinter.format() - ) - return + if os.environ["MM_ENV"] == "PRODUCTION": + send_mail( + Config.ERRORS_TO, + Config.ERRORS_FROM, + "playlists:_set_row_header_text() called on track row", + stackprinter.format() + ) print("playists:_set_row_header_text() called on track row") stackprinter.show(add_summary=True, style="darkbg") + return # Set text _ = self._set_item_text(row_number, HEADER_NOTES_COLUMN, text) @@ -1914,11 +1918,12 @@ class PlaylistTab(QTableWidget): # Sanity check: this should be a track row and thus have a # track associated if not self._get_row_track_id(row_number): - send_mail(Config.ERRORS_TO, - Config.ERRORS_FROM, - "playists:_set_row_note_colour() called on header row", - stackprinter.format() - ) + if os.environ["MM_ENV"] == "PRODUCTION": + send_mail(Config.ERRORS_TO, + Config.ERRORS_FROM, + "playlists:_set_row_note_colour() on header row", + stackprinter.format() + ) print("playists:_set_row_note_colour() called on header row") stackprinter.show(add_summary=True, style="darkbg") return @@ -1937,11 +1942,13 @@ class PlaylistTab(QTableWidget): # Sanity check: this should be a track row and thus have a # track associated if not self._get_row_track_id(row_number): - send_mail(Config.ERRORS_TO, - Config.ERRORS_FROM, - "playists:_set_row_note_text() called on header row", - stackprinter.format() - ) + if os.environ["MM_ENV"] == "PRODUCTION": + send_mail( + Config.ERRORS_TO, + Config.ERRORS_FROM, + "playlists:_set_row_note_text() called on header row", + stackprinter.format() + ) print("playists:_set_row_note_text() called on header row") stackprinter.show(add_summary=True, style="darkbg") return @@ -2103,10 +2110,9 @@ class PlaylistTab(QTableWidget): 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)] + if self._get_row_track_id(row_number) == 0] plrs = PlaylistRows.get_from_id_list(session, self.playlist_id, header_rows) - for plr in plrs: if plr.note.endswith("+"): section_start_rows.append(plr) @@ -2128,7 +2134,7 @@ class PlaylistTab(QTableWidget): section_header_cleanup_re, '', from_plr.note, ).strip() + "]" ) - self._set_row_header_text(session, plr.row_number, + self._set_row_header_text(session, to_plr.row_number, new_text) except IndexError: # This ending row may have a time left from before a @@ -2150,76 +2156,75 @@ class PlaylistTab(QTableWidget): self._set_row_header_text(session, from_plr.row_number, from_plr.note + time_str) - def _update_start_end_times(self) -> None: + def _update_start_end_times(self, session: scoped_session) -> None: """ Update track start and end times """ - with Session() as session: - current_track_end_time = self.musicmuster.current_track.end_time - current_track_row = self._get_current_track_row_number() - current_track_start_time = ( - self.musicmuster.current_track.start_time) - next_start_time = None - next_track_row = self._get_next_track_row_number() - played_rows = self._get_played_rows(session) + current_track_end_time = self.musicmuster.current_track.end_time + current_track_row = self._get_current_track_row_number() + current_track_start_time = ( + self.musicmuster.current_track.start_time) + next_start_time = None + next_track_row = self._get_next_track_row_number() + played_rows = self._get_played_rows(session) - for row_number in range(self.rowCount()): - # Don't change start times for tracks that have been - # played other than current/next row - if row_number in played_rows and row_number not in [ - current_track_row, next_track_row]: - continue + for row_number in range(self.rowCount()): + # Don't change start times for tracks that have been + # played other than current/next row + if row_number in played_rows and row_number not in [ + current_track_row, next_track_row]: + continue - # Get any timing from header row (that's all we need) - if self._get_row_track_id(row_number) == 0: - note_time = self._get_note_text_time( - self._get_row_note(row_number)) - if note_time: - next_start_time = note_time - continue + # Get any timing from header row (that's all we need) + if self._get_row_track_id(row_number) == 0: + note_time = self._get_note_text_time( + self._get_row_note(row_number)) + if note_time: + next_start_time = note_time + continue - # We have a track. Skip if it is unreadable - if file_is_unreadable(self._get_row_path(row_number)): - continue + # We have a track. Skip if it is unreadable + if file_is_unreadable(self._get_row_path(row_number)): + continue - # Set next track start from end of current track - if row_number == next_track_row: - if current_track_end_time: - next_start_time = self._set_row_times( - row_number, current_track_end_time, - self._get_row_duration(row_number)) - continue - # Else set track times below - - if row_number == current_track_row: - if not current_track_start_time: - continue - self._set_row_start_time(row_number, - current_track_start_time) - self._set_row_end_time(row_number, current_track_end_time) - # Next track may be above us so only reset - # next_start_time if it's not set - if not next_start_time: - next_start_time = current_track_end_time - continue - - if not next_start_time: - # Clear any existing times - self._set_row_start_time(row_number, None) - self._set_row_end_time(row_number, None) - continue - - # If we're between the current and next row, zero out - # times - if (current_track_row and next_track_row and - current_track_row < row_number < next_track_row): - self._set_row_start_time(row_number, None) - self._set_row_end_time(row_number, None) - else: + # Set next track start from end of current track + if row_number == next_track_row: + if current_track_end_time: next_start_time = self._set_row_times( - row_number, next_start_time, + row_number, current_track_end_time, self._get_row_duration(row_number)) + continue + # Else set track times below - self._update_section_headers(session) + if row_number == current_track_row: + if not current_track_start_time: + continue + self._set_row_start_time(row_number, + current_track_start_time) + self._set_row_end_time(row_number, current_track_end_time) + # Next track may be above us so only reset + # next_start_time if it's not set + if not next_start_time: + next_start_time = current_track_end_time + continue + + if not next_start_time: + # Clear any existing times + self._set_row_start_time(row_number, None) + self._set_row_end_time(row_number, None) + continue + + # If we're between the current and next row, zero out + # times + if (current_track_row and next_track_row and + current_track_row < row_number < next_track_row): + self._set_row_start_time(row_number, None) + self._set_row_end_time(row_number, None) + else: + next_start_time = self._set_row_times( + row_number, next_start_time, + self._get_row_duration(row_number)) + + self._update_section_headers(session) def _wikipedia(self, row_number: int) -> None: """Look up passed row title in Wikipedia and display info tab"""