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.
This commit is contained in:
Keith Edmunds 2023-03-14 22:59:39 +00:00
parent 3197c844a5
commit f3631b2c2b

View File

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