diff --git a/app/models.py b/app/models.py index c7fc811..bd04296 100644 --- a/app/models.py +++ b/app/models.py @@ -190,14 +190,13 @@ class Playdates(Base): tracks: RelationshipProperty = relationship( "Tracks", back_populates="playdates", lazy="joined") - def __init__(self, session: Session, track: "Tracks") -> None: + def __init__(self, session: Session, track_id: int) -> None: """Record that track was played""" - DEBUG(f"add_playdate(track={track})") + DEBUG(f"add_playdate({track_id=})") self.lastplayed = datetime.now() - self.track_id = track.id - track.update_lastplayed(session) + self.track_id = track_id session.add(self) session.flush() @@ -594,9 +593,13 @@ class Tracks(Base): .order_by(cls.title) ).all() - def update_lastplayed(self, session: Session) -> None: - self.lastplayed = datetime.now() - session.add(self) + @staticmethod + def update_lastplayed(session: Session, track_id: int) -> None: + """Update the last_played field to current datetime""" + + rec = session.query(Tracks).get(track_id) + rec.lastplayed = datetime.now() + session.add(rec) session.flush() def update_artist(self, session: Session, artist: str) -> None: diff --git a/app/musicmuster.py b/app/musicmuster.py index 2ebe1e8..4cebaa5 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -24,12 +24,13 @@ from PyQt5.QtWidgets import ( ) import dbconfig +from dbconfig import Session import helpers import music from config import Config -from models import (Playdates, Playlists, PlaylistTracks, - Session, Settings, Tracks) +from models import (Base, Playdates, Playlists, PlaylistTracks, + Settings, Tracks) from playlists import PlaylistTab from utilities import create_track_from_file from sqlalchemy.orm.exc import DetachedInstanceError @@ -38,6 +39,20 @@ from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist from ui.main_window_ui import Ui_MainWindow +class TrackData: + def __init__(self, track): + self.id = track.id + self.title = track.title + self.artist = track.artist + self.duration = track.duration + self.start_gap = track.start_gap + self.fade_at = track.fade_at + self.silence_at = track.silence_at + self.path = track.path + self.mtime = track.mtime + self.lastplayed = track.lastplayed + + class Window(QMainWindow, Ui_MainWindow): def __init__(self, parent=None) -> None: super().__init__(parent) @@ -511,10 +526,6 @@ class Window(QMainWindow, Ui_MainWindow): self.current_track = self.next_track self.next_track = None - # Ensure track is in session - if self.current_track not in session: - session.add(self.current_track) - # If current track on different playlist_tab to last, reset # last track playlist_tab colour # Set current track playlist_tab colour @@ -534,7 +545,10 @@ class Window(QMainWindow, Ui_MainWindow): self.music.play(self.current_track.path) # Tell database to record it as played - Playdates(session, self.current_track) + Playdates(session, self.current_track.id) + + # Set last_played date + Tracks.update_lastplayed(session, self.current_track.id) # Tell playlist track is now playing self.current_track_playlist_tab.play_started(session) @@ -713,7 +727,7 @@ class Window(QMainWindow, Ui_MainWindow): QColor(Config.COLOUR_NEXT_TAB)) # Note next track - self.next_track = track + self.next_track = TrackData(track) # Update headers self.update_headers() @@ -747,58 +761,55 @@ class Window(QMainWindow, Ui_MainWindow): # If track is playing, update track clocks time and colours if self.music.player and self.music.playing(): - with Session() as session: - self.playing = True - if self.current_track not in session: - session.add(self.current_track) - playtime: int = self.music.get_playtime() - time_to_fade: int = (self.current_track.fade_at - playtime) - time_to_silence: int = ( - self.current_track.silence_at - playtime) - time_to_end: int = (self.current_track.duration - playtime) + self.playing = True + playtime: int = self.music.get_playtime() + time_to_fade: int = (self.current_track.fade_at - playtime) + time_to_silence: int = ( + self.current_track.silence_at - playtime) + time_to_end: int = (self.current_track.duration - playtime) - # Elapsed time - if time_to_end < 500: - self.label_elapsed_timer.setText( - helpers.ms_to_mmss(playtime) - ) - else: - self.label_elapsed_timer.setText( - helpers.ms_to_mmss(playtime) - ) - - # Time to fade - self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade)) - - # If silent in the next 5 seconds, put warning colour on - # time to silence box and enable play controls - if time_to_silence <= 5500: - self.frame_silent.setStyleSheet( - f"background: {Config.COLOUR_ENDING_TIMER}" - ) - self.enable_play_next_controls() - # Set warning colour on time to silence box when fade starts - elif time_to_fade <= 500: - self.frame_silent.setStyleSheet( - f"background: {Config.COLOUR_WARNING_TIMER}" - ) - # Five seconds before fade starts, set warning colour on - # time to silence box and enable play controls - elif time_to_fade <= 5500: - self.frame_fade.setStyleSheet( - f"background: {Config.COLOUR_WARNING_TIMER}" - ) - self.enable_play_next_controls() - else: - self.frame_silent.setStyleSheet("") - self.frame_fade.setStyleSheet("") - - self.label_silent_timer.setText( - helpers.ms_to_mmss(time_to_silence) + # Elapsed time + if time_to_end < 500: + self.label_elapsed_timer.setText( + helpers.ms_to_mmss(playtime) + ) + else: + self.label_elapsed_timer.setText( + helpers.ms_to_mmss(playtime) ) - # Time to end - self.label_end_timer.setText(helpers.ms_to_mmss(time_to_end)) + # Time to fade + self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade)) + + # If silent in the next 5 seconds, put warning colour on + # time to silence box and enable play controls + if time_to_silence <= 5500: + self.frame_silent.setStyleSheet( + f"background: {Config.COLOUR_ENDING_TIMER}" + ) + self.enable_play_next_controls() + # Set warning colour on time to silence box when fade starts + elif time_to_fade <= 500: + self.frame_silent.setStyleSheet( + f"background: {Config.COLOUR_WARNING_TIMER}" + ) + # Five seconds before fade starts, set warning colour on + # time to silence box and enable play controls + elif time_to_fade <= 5500: + self.frame_fade.setStyleSheet( + f"background: {Config.COLOUR_WARNING_TIMER}" + ) + self.enable_play_next_controls() + else: + self.frame_silent.setStyleSheet("") + self.frame_fade.setStyleSheet("") + + self.label_silent_timer.setText( + helpers.ms_to_mmss(time_to_silence) + ) + + # Time to end + self.label_end_timer.setText(helpers.ms_to_mmss(time_to_end)) else: if self.playing: diff --git a/app/playlists.py b/app/playlists.py index c802ca6..5305e44 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -341,7 +341,7 @@ class PlaylistTab(QTableWidget): # Add track details to columns mss_item: QTableWidgetItem = QTableWidgetItem(str(track.start_gap)) if track.start_gap and track.start_gap >= 500: - item.setBackground(QColor(Config.COLOUR_LONG_START)) + mss_item.setBackground(QColor(Config.COLOUR_LONG_START)) self.setItem(row, self.COL_MSS, mss_item) title_item: QTableWidgetItem = QTableWidgetItem(track.title) @@ -485,7 +485,7 @@ class PlaylistTab(QTableWidget): self._insert_note(session, item, repaint=False) # Scroll to top - scroll_to: QTableWidgetItem = self.item(0, self.COL_TITLE) + scroll_to: QTableWidgetItem = self.item(0, 0) self.scrollToItem(scroll_to, QAbstractItemView.PositionAtTop) # We possibly don't need to save the playlist here, but row @@ -1170,12 +1170,12 @@ class PlaylistTab(QTableWidget): "\n\n" f"Path: {track.path}\n" ) - info: QMessageBox = QMessageBox(self) - info.setIcon(QMessageBox.Information) - info.setText(txt) - info.setStandardButtons(QMessageBox.Ok) - info.setDefaultButton(QMessageBox.Cancel) - info.exec() + info: QMessageBox = QMessageBox(self) + info.setIcon(QMessageBox.Information) + info.setText(txt) + info.setStandardButtons(QMessageBox.Ok) + info.setDefaultButton(QMessageBox.Cancel) + info.exec() def _insert_note(self, session: Session, note: Notes, row: Optional[int] = None, repaint: bool = True) -> None: @@ -1364,6 +1364,10 @@ class PlaylistTab(QTableWidget): # Get the row number of all selected items and put into a set # to deduplicate sel_rows: Set[int] = set([item.row() for item in self.selectedItems()]) + # If no rows are selected, we have nothing to do + if len(sel_rows) == 0: + return + notes_rows: Set[int] = set(self._get_notes_rows()) ms: int = 0 with Session() as session: @@ -1388,7 +1392,7 @@ class PlaylistTab(QTableWidget): self.clearSelection() if played: - rows = self. _get_played_track_rows() + rows = self._get_played_track_rows() else: rows = self._get_unplayed_track_rows() diff --git a/app/utilities.py b/app/utilities.py index 4459710..1fb39d7 100755 --- a/app/utilities.py +++ b/app/utilities.py @@ -246,7 +246,7 @@ def update_db(session): for path in list(os_paths - db_paths): DEBUG(f"songdb.update_db: {path=} not in database") # is filename in database? - track = Tracks.get_from_filename(session, os.path.basename(path)) + track = Tracks.get_by_filename(session, os.path.basename(path)) if not track: messages.append(f"Track missing from database: {path}") else: @@ -262,7 +262,7 @@ def update_db(session): # Remote any tracks from database whose paths don't exist for path in list(db_paths - os_paths): # Manage tracks listed in database but where path is invalid - track = Tracks.get_from_path(session, path) + track = Tracks.get_by_path(session, path) messages.append(f"Remove from database: {path=} {track=}") # Remove references from Playdates