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:
parent
3197c844a5
commit
f3631b2c2b
225
app/playlists.py
225
app/playlists.py
@ -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"""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user