diff --git a/app/classes.py b/app/classes.py index 28f3bf1..a7a7a1c 100644 --- a/app/classes.py +++ b/app/classes.py @@ -1,14 +1,14 @@ from dataclasses import dataclass from datetime import datetime, timedelta -from typing import Any, Optional +from typing import Optional from PyQt6.QtCore import pyqtSignal, QObject, QThread import numpy as np import pyqtgraph as pg # type: ignore from config import Config -from dbconfig import scoped_session, Session -from models import PlaylistRows, Tracks +from dbconfig import scoped_session +from models import PlaylistRows import helpers @@ -213,7 +213,7 @@ class AddFadeCurve(QObject): cnp_tracks = dict( - CurrentTrack = PlaylistTrack(), - NextTrack = PlaylistTrack(), - PreviousTrack = PlaylistTrack(), + CurrentTrack=PlaylistTrack(), + NextTrack=PlaylistTrack(), + PreviousTrack=PlaylistTrack(), ) diff --git a/app/musicmuster.py b/app/musicmuster.py index b358c97..3428c8a 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -387,7 +387,7 @@ class Window(QMainWindow, Ui_MainWindow): Clear next track """ - cnp_tracks['NextTrack'] = PlaylistTrack() + cnp_tracks["NextTrack"] = PlaylistTrack() self.update_headers() def clear_selection(self) -> None: @@ -708,13 +708,13 @@ class Window(QMainWindow, Ui_MainWindow): # self.current_track.playlist_tab.play_ended() # Reset fade graph - if cnp_tracks['CurrentTrack'].fade_graph: - cnp_tracks['CurrentTrack'].fade_graph.clear() + if cnp_tracks["CurrentTrack"].fade_graph: + cnp_tracks["CurrentTrack"].fade_graph.clear() # Reset PlaylistTrack objects - if cnp_tracks['CurrentTrack'].track_id: - cnp_tracks['PreviousTrack'] = cnp_tracks['CurrentTrack'] - cnp_tracks['CurrentTrack'] = PlaylistTrack() + if cnp_tracks["CurrentTrack"].track_id: + cnp_tracks["PreviousTrack"] = cnp_tracks["CurrentTrack"] + cnp_tracks["CurrentTrack"] = PlaylistTrack() # Reset clocks self.frame_fade.setStyleSheet("") @@ -785,11 +785,14 @@ class Window(QMainWindow, Ui_MainWindow): times a second; this function has much better resolution. """ - if cnp_tracks['CurrentTrack'].track_id is None or cnp_tracks['CurrentTrack'].start_time is None: + if ( + cnp_tracks["CurrentTrack"].track_id is None + or cnp_tracks["CurrentTrack"].start_time is None + ): return 0 now = datetime.now() - track_start = cnp_tracks['CurrentTrack'].start_time + track_start = cnp_tracks["CurrentTrack"].start_time elapsed_seconds = (now - track_start).total_seconds() return int(elapsed_seconds * 1000) @@ -942,7 +945,8 @@ class Window(QMainWindow, Ui_MainWindow): plrs_to_move = [ plr for plr in playlistrows - if plr.id not in [cnp_tracks['CurrentTrack'].plr_id, cnp_tracks['NextTrack'].plr_id] + if plr.id + not in [cnp_tracks["CurrentTrack"].plr_id, cnp_tracks["NextTrack"].plr_id] ] rows_to_delete = [ @@ -1150,70 +1154,69 @@ class Window(QMainWindow, Ui_MainWindow): """ # If there is no next track set, return. - if not cnp_tracks['NextTrack'].track_id: + if not cnp_tracks["NextTrack"].track_id: log.debug("musicmuster.play_next(): no next track selected") return - if not cnp_tracks['NextTrack'].path: + if not cnp_tracks["NextTrack"].path: log.debug("musicmuster.play_next(): no path for next track") return - with Session() as session: - # If there's currently a track playing, fade it. - self.stop_playing(fade=True) + # If there's currently a track playing, fade it. + self.stop_playing(fade=True) - # Move next track to current track. - # stop_playing() above has called end_of_track_actions() - # which will have populated self.previous_track - cnp_tracks['CurrentTrack'] = cnp_tracks['NextTrack'] + # Move next track to current track. + # stop_playing() above has called end_of_track_actions() + # which will have populated self.previous_track + cnp_tracks["CurrentTrack"] = cnp_tracks["NextTrack"] - # Clear next track - self.clear_next() + # Clear next track + self.clear_next() - # Set current track playlist_tab colour - # TODO Reimplement without reference to self.current_track.playlist_tab - # current_tab = self.current_track.playlist_tab - # if current_tab: - # self.set_tab_colour(current_tab, QColor(Config.COLOUR_CURRENT_TAB)) + # Set current track playlist_tab colour + # TODO Reimplement without reference to self.current_track.playlist_tab + # current_tab = self.current_track.playlist_tab + # if current_tab: + # self.set_tab_colour(current_tab, QColor(Config.COLOUR_CURRENT_TAB)) - # Restore volume if -3dB active - if self.btnDrop3db.isChecked(): - self.btnDrop3db.setChecked(False) + # Restore volume if -3dB active + if self.btnDrop3db.isChecked(): + self.btnDrop3db.setChecked(False) - # Play (new) current track - if not cnp_tracks['CurrentTrack'].path: - return - cnp_tracks['CurrentTrack'].start() - self.music.play(cnp_tracks['CurrentTrack'].path, position) + # Play (new) current track + if not cnp_tracks["CurrentTrack"].path: + return + cnp_tracks["CurrentTrack"].start() + self.music.play(cnp_tracks["CurrentTrack"].path, position) - # Ensure 100% volume - # For as-yet unknown reasons. sometimes the volume gets - # reset to zero within 200mS or so of starting play. This - # only happened since moving to Debian 12, which uses - # Pipewire for sound (which may be irrelevant). - for _ in range(3): - if self.music.player: - volume = self.music.player.audio_get_volume() - if volume < Config.VOLUME_VLC_DEFAULT: - self.music.set_volume() - log.error(f"Reset from {volume=}") - break - sleep(0.1) + # Ensure 100% volume + # For as-yet unknown reasons. sometimes the volume gets + # reset to zero within 200mS or so of starting play. This + # only happened since moving to Debian 12, which uses + # Pipewire for sound (which may be irrelevant). + for _ in range(3): + if self.music.player: + volume = self.music.player.audio_get_volume() + if volume < Config.VOLUME_VLC_DEFAULT: + self.music.set_volume() + log.error(f"Reset from {volume=}") + break + sleep(0.1) - # Show closing volume graph - if cnp_tracks['CurrentTrack'].fade_graph: - cnp_tracks['CurrentTrack'].fade_graph.plot() + # Show closing volume graph + if cnp_tracks["CurrentTrack"].fade_graph: + cnp_tracks["CurrentTrack"].fade_graph.plot() - # Notify model - self.active_model().current_track_started() + # Notify model + self.active_model().current_track_started() - # Note that track is now playing - self.playing = True + # Note that track is now playing + self.playing = True - # Disable play next controls - self.disable_play_next_controls() + # Disable play next controls + self.disable_play_next_controls() - # Update headers - self.update_headers() + # Update headers + self.update_headers() def preview(self) -> None: """ @@ -1227,7 +1230,7 @@ class Window(QMainWindow, Ui_MainWindow): track_path = self.active_tab().get_selected_row_track_path() if not track_path: # Otherwise get path to next track to play - track_path = cnp_tracks['NextTrack'].path + track_path = cnp_tracks["NextTrack"].path if not track_path: self.btnPreview.setChecked(False) return @@ -1541,23 +1544,23 @@ class Window(QMainWindow, Ui_MainWindow): # self.next_track.set_plr(session, next_plr) # self.signals.set_next_track_signal.emit(next_plr.playlist_id) - # # Update headers - # self.update_headers() + # # Update headers + # self.update_headers() - # TODO: reimlement - # # Set playlist tab colours - # self._set_next_track_playlist_tab_colours(old_next_track) + # TODO: reimlement + # # Set playlist tab colours + # self._set_next_track_playlist_tab_colours(old_next_track) - # if next_plr_id: - # # Populate 'info' tabs with Wikipedia info, but queue it - # # because it isn't quick - # if self.next_track.title: - # QTimer.singleShot( - # 0, - # lambda: self.tabInfolist.open_in_wikipedia( - # self.next_track.title - # ), - # ) + # if next_plr_id: + # # Populate 'info' tabs with Wikipedia info, but queue it + # # because it isn't quick + # if self.next_track.title: + # QTimer.singleShot( + # 0, + # lambda: self.tabInfolist.open_in_wikipedia( + # self.next_track.title + # ), + # ) def _set_next_track_playlist_tab_colours( self, old_next_track: Optional[PlaylistTrack] @@ -1603,14 +1606,14 @@ class Window(QMainWindow, Ui_MainWindow): # Update volume fade curve if ( - cnp_tracks['CurrentTrack'].track_id - and cnp_tracks['CurrentTrack'].fade_graph - and cnp_tracks['CurrentTrack'].start_time + cnp_tracks["CurrentTrack"].track_id + and cnp_tracks["CurrentTrack"].fade_graph + and cnp_tracks["CurrentTrack"].start_time ): play_time = ( - datetime.now() - cnp_tracks['CurrentTrack'].start_time + datetime.now() - cnp_tracks["CurrentTrack"].start_time ).total_seconds() * 1000 - cnp_tracks['CurrentTrack'].fade_graph.tick(play_time) + cnp_tracks["CurrentTrack"].fade_graph.tick(play_time) def tick_500ms(self) -> None: """ @@ -1642,22 +1645,22 @@ class Window(QMainWindow, Ui_MainWindow): # starting play. if ( self.music.player - and cnp_tracks['CurrentTrack'].start_time + and cnp_tracks["CurrentTrack"].start_time and ( self.music.player.is_playing() - or (datetime.now() - cnp_tracks['CurrentTrack'].start_time) + or (datetime.now() - cnp_tracks["CurrentTrack"].start_time) < timedelta(microseconds=Config.PLAY_SETTLE) ) ): playtime = self.get_playtime() - time_to_fade = cnp_tracks['CurrentTrack'].fade_at - playtime - time_to_silence = cnp_tracks['CurrentTrack'].silence_at - playtime + time_to_fade = cnp_tracks["CurrentTrack"].fade_at - playtime + time_to_silence = cnp_tracks["CurrentTrack"].silence_at - playtime # Elapsed time self.label_elapsed_timer.setText( helpers.ms_to_mmss(playtime) + " / " - + helpers.ms_to_mmss(cnp_tracks['CurrentTrack'].duration) + + helpers.ms_to_mmss(cnp_tracks["CurrentTrack"].duration) ) # Time to fade @@ -1700,14 +1703,14 @@ class Window(QMainWindow, Ui_MainWindow): Update last / current / next track headers """ - if cnp_tracks['PreviousTrack'].title and cnp_tracks['PreviousTrack'].artist: + if cnp_tracks["PreviousTrack"].title and cnp_tracks["PreviousTrack"].artist: self.hdrPreviousTrack.setText( f"{cnp_tracks['PreviousTrack'].title} - {cnp_tracks['PreviousTrack'].artist}" ) else: self.hdrPreviousTrack.setText("") - if cnp_tracks['CurrentTrack'].title and cnp_tracks['CurrentTrack'].artist: + if cnp_tracks["CurrentTrack"].title and cnp_tracks["CurrentTrack"].artist: self.hdrCurrentTrack.setText( f"{cnp_tracks['CurrentTrack'].title.replace('&', '&&')} - " f"{cnp_tracks['CurrentTrack'].artist.replace('&', '&&')}" @@ -1715,7 +1718,7 @@ class Window(QMainWindow, Ui_MainWindow): else: self.hdrCurrentTrack.setText("") - if cnp_tracks['NextTrack'].title and cnp_tracks['NextTrack'].artist: + if cnp_tracks["NextTrack"].title and cnp_tracks["NextTrack"].artist: self.hdrNextTrack.setText( f"{cnp_tracks['NextTrack'].title.replace('&', '&&')} - " f"{cnp_tracks['NextTrack'].artist.replace('&', '&&')}" diff --git a/app/playlistmodel.py b/app/playlistmodel.py index 75d4b1b..9f79bb1 100644 --- a/app/playlistmodel.py +++ b/app/playlistmodel.py @@ -191,10 +191,10 @@ class PlaylistModel(QAbstractTableModel): if file_is_unreadable(prd.path): return QBrush(QColor(Config.COLOUR_UNREADABLE)) # Current track - if prd.plrid == cnp_tracks['CurrentTrack'].plr_id: + if prd.plrid == cnp_tracks["CurrentTrack"].plr_id: return QBrush(QColor(Config.COLOUR_CURRENT_PLAYLIST)) # Next track - if prd.plrid == cnp_tracks['NextTrack'].plr_id: + if prd.plrid == cnp_tracks["NextTrack"].plr_id: return QBrush(QColor(Config.COLOUR_NEXT_PLAYLIST)) # Individual cell colouring @@ -231,28 +231,28 @@ class PlaylistModel(QAbstractTableModel): """ # Sanity check - if not cnp_tracks['CurrentTrack'].track_id: + if not cnp_tracks["CurrentTrack"].track_id: log.error( "playlistmodel:current_track_started called with no current track" ) return - if cnp_tracks['CurrentTrack'].plr_rownum is None: + if cnp_tracks["CurrentTrack"].plr_rownum is None: log.error( "playlistmodel:current_track_started called with no row number " - f"({self.current_track=})" + f"({cnp_tracks['CurrentTrack']=})" ) return # Update display - self.invalidate_row(cnp_tracks['CurrentTrack'].plr_rownum) + self.invalidate_row(cnp_tracks["CurrentTrack"].plr_rownum) # Update track times # TODO # Update Playdates in database with Session() as session: - Playdates(session, cnp_tracks['CurrentTrack'].track_id) - plr = session.get(PlaylistRows, cnp_tracks['CurrentTrack'].plr_id) + Playdates(session, cnp_tracks["CurrentTrack"].track_id) + plr = session.get(PlaylistRows, cnp_tracks["CurrentTrack"].plr_id) if plr: plr.played = True @@ -268,7 +268,11 @@ class PlaylistModel(QAbstractTableModel): try: # Find next row after current track next_row = min( - [a for a in unplayed_rows if a > cnp_tracks['CurrentTrack'].plr_rownum] + [ + a + for a in unplayed_rows + if a > cnp_tracks["CurrentTrack"].plr_rownum + ] ) except ValueError: # Find first unplayed track @@ -587,7 +591,7 @@ class PlaylistModel(QAbstractTableModel): # Update cnp_tracks with Session() as session: - cnp_tracks['NextTrack'] = PlaylistTrack() + cnp_tracks["NextTrack"] = PlaylistTrack() try: plrid = self.playlist_rows[row_number].plrid except IndexError: @@ -604,7 +608,7 @@ class PlaylistModel(QAbstractTableModel): # Check track is readable if file_is_unreadable(plr.track.path): return - cnp_tracks['NextTrack'].set_plr(session, plr) + cnp_tracks["NextTrack"].set_plr(session, plr) self.signals.next_track_changed_signal.emit() self.invalidate_row(row_number) diff --git a/app/playlists.py b/app/playlists.py index c45cf65..c70571a 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -1292,7 +1292,7 @@ class PlaylistTab(QTableView): # for row_number in range(starting_row, self.rowCount()): # if row_number not in track_rows or row_number in played_rows: # continue - # plr = self._get_row_plr(session, row_number) + # plr = selWIP V3: play track workingf._get_row_plr(session, row_number) # if not plr: # continue # if file_is_unreadable(plr.track.path):