diff --git a/app/classes.py b/app/classes.py index d3be8fe..4ec381b 100644 --- a/app/classes.py +++ b/app/classes.py @@ -116,6 +116,7 @@ class PlaylistTrack: self.end_time: Optional[dt.datetime] = None self.fade_at: Optional[int] = None self.fade_graph: Optional[FadeCurve] = None + self.fade_graph_start_updates: Optional[dt.datetime] = None self.fade_length: Optional[int] = None self.path: Optional[str] = None self.playlist_id: Optional[int] = None @@ -182,10 +183,20 @@ class PlaylistTrack: Called when track starts playing """ - self.start_time = dt.datetime.now() + now = dt.datetime.now() + self.start_time = now if self.duration: self.end_time = self.start_time + dt.timedelta(milliseconds=self.duration) + # Calculate time fade_graph should start updating + if self.fade_at: + update_graph_at_ms = max( + 0, self.fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1 + ) + self.fade_graph_start_updates = now + dt.timedelta( + milliseconds=update_graph_at_ms + ) + class AddFadeCurve(QObject): """ diff --git a/app/dialogs.py b/app/dialogs.py index 02b0ba2..3c195e1 100644 --- a/app/dialogs.py +++ b/app/dialogs.py @@ -1,17 +1,15 @@ # Standard library imports - -# PyQt imports - -# Third party imports - -# App imports from typing import Optional +# PyQt imports from PyQt6.QtCore import QEvent, Qt from PyQt6.QtWidgets import QDialog, QListWidgetItem +# Third party imports +from sqlalchemy.orm.session import Session + +# App imports from classes import MusicMusterSignals -from sqlalchemy.orm import scoped_session from helpers import ( ask_yes_no, get_relative_date, @@ -28,7 +26,7 @@ class TrackSelectDialog(QDialog): def __init__( self, - session: scoped_session, + session: Session, new_row_number: int, source_model: PlaylistModel, add_to_header: Optional[bool] = False, diff --git a/app/music.py b/app/music.py index 0aecc21..d5a295f 100644 --- a/app/music.py +++ b/app/music.py @@ -44,7 +44,7 @@ class FadeTrack(QRunnable): sleep(1 / Config.FADEOUT_STEPS_PER_SECOND) self.player.stop() - log.error(f"Releasing player {self.player=}") + log.debug(f"Releasing player {self.player=}") self.player.release() diff --git a/app/musicmuster.py b/app/musicmuster.py index d12ae44..0799910 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -48,7 +48,7 @@ from PyQt6.QtWidgets import ( # Third party imports from pygame import mixer import pipeclient -from sqlalchemy.orm import scoped_session +from sqlalchemy.orm.session import Session import stackprinter # type: ignore # App imports @@ -562,7 +562,7 @@ class Window(QMainWindow, Ui_MainWindow): self.timer1000.timeout.connect(self.tick_1000ms) def create_playlist( - self, session: scoped_session, playlist_name: Optional[str] = None + self, session: Session, playlist_name: Optional[str] = None ) -> Optional[Playlists]: """Create new playlist""" @@ -1140,34 +1140,25 @@ class Window(QMainWindow, Ui_MainWindow): break sleep(0.1) - # TODO: remove sleep() calls - used to try to isolate bug #223 # Show closing volume graph - sleep(1) if track_sequence.now.fade_graph: track_sequence.now.fade_graph.plot() else: log.error("No fade_graph") # Note that track is playing - sleep(1) - log.error("set track_sequence") + log.debug("set track_sequence") track_sequence.now.start() self.playing = True # Disable play next controls - sleep(1) - log.error("catch return key") self.catch_return_key = True self.show_status_message("Play controls: Disabled", 0) # Notify model - sleep(1) - log.error("active_proxy_model().current_track_started()") self.active_proxy_model().current_track_started() # Update headers - sleep(1) - log.error("update headers") self.update_headers() def preview(self) -> None: @@ -1413,7 +1404,7 @@ class Window(QMainWindow, Ui_MainWindow): self.tabPlaylist.currentWidget().scroll_to_top(display_row) def solicit_playlist_name( - self, session: scoped_session, default: str = "" + self, session: Session, default: str = "" ) -> Optional[str]: """Get name of new playlist from user""" @@ -1514,6 +1505,12 @@ class Window(QMainWindow, Ui_MainWindow): """ # Update volume fade curve + if ( + track_sequence.now.fade_graph_start_updates is None + or track_sequence.now.fade_graph_start_updates > dt.datetime.now() + ): + return + if ( track_sequence.now.track_id and track_sequence.now.fade_graph @@ -1642,7 +1639,7 @@ class CartDialog(QDialog): """Edit cart details""" def __init__( - self, musicmuster: Window, session: scoped_session, cart: Carts, *args, **kwargs + self, musicmuster: Window, session: Session, cart: Carts, *args, **kwargs ) -> None: """ Manage carts diff --git a/app/pipeclient.py b/app/pipeclient.py index 9ef0c38..749ebac 100755 --- a/app/pipeclient.py +++ b/app/pipeclient.py @@ -160,7 +160,7 @@ class PipeClient: def _write_pipe_open(self) -> None: """Open _write_pipe.""" - self._write_pipe = open(WRITE_NAME, 'w') + self._write_pipe = open(WRITE_NAME, "w") def _read_thread_start(self) -> None: """Start read_pipe thread.""" @@ -204,8 +204,8 @@ class PipeClient: """Read FIFO in worker thread.""" # Thread will wait at this read until it connects. # Connection should occur as soon as _write_pipe has connected. - with open(READ_NAME, 'r') as read_pipe: - message = '' + with open(READ_NAME, "r") as read_pipe: + message = "" pipe_ok = True while pipe_ok: line = read_pipe.readline() diff --git a/app/playlistmodel.py b/app/playlistmodel.py index bed4bf4..5956792 100644 --- a/app/playlistmodel.py +++ b/app/playlistmodel.py @@ -279,21 +279,16 @@ class PlaylistModel(QAbstractTableModel): ) return - # TODO: remove sleep/log calls, used to debug #223 - # Check for OBS scene change - sleep(1) - log.error("Call OBS scene change") + log.debug("Call OBS scene change") self.obs_scene_change(row_number) with db.Session() as session: # Update Playdates in database - sleep(1) - log.error("update playdates") + log.debug("update playdates") Playdates(session, track_sequence.now.track_id) # Mark track as played in playlist - sleep(1) - log.error("Mark track as played") + log.debug("Mark track as played") plr = session.get(PlaylistRows, track_sequence.now.plr_id) if plr: plr.played = True @@ -302,8 +297,7 @@ class PlaylistModel(QAbstractTableModel): log.error(f"Can't retrieve plr, {track_sequence.now.plr_id=}") # Update track times - sleep(1) - log.error("Update track times") + log.debug("Update track times") if prd: prd.start_time = track_sequence.now.start_time prd.end_time = track_sequence.now.end_time @@ -320,8 +314,7 @@ class PlaylistModel(QAbstractTableModel): # Find next track # Get all unplayed track rows - sleep(1) - log.error("Find next track") + log.debug("Find next track") next_row = None unplayed_rows = self.get_unplayed_rows() if unplayed_rows: @@ -1222,7 +1215,7 @@ class PlaylistModel(QAbstractTableModel): self.signals.next_track_changed_signal.emit() return - # Update playing_track + # Update track_sequence with db.Session() as session: track_sequence.next = PlaylistTrack() try: @@ -1576,7 +1569,7 @@ class PlaylistProxyModel(QSortFilterProxyModel): self, proposed_row_number: Optional[int], track_id: Optional[int] = None, - note: Optional[str] = None, + note: str = "", ) -> None: return self.source_model.insert_row(proposed_row_number, track_id, note) diff --git a/tests/test_playlistmodel.py b/tests/test_playlistmodel.py index 35e9242..d164750 100644 --- a/tests/test_playlistmodel.py +++ b/tests/test_playlistmodel.py @@ -79,12 +79,13 @@ class TestMMMiscTracks(unittest.TestCase): self.model.insert_row(proposed_row_number=END_ROW, note="-") prd = self.model.playlist_rows[START_ROW] - qv_value = self.model.display_role(START_ROW, playlistmodel.HEADER_NOTES_COLUMN, prd) + qv_value = self.model.display_role( + START_ROW, playlistmodel.HEADER_NOTES_COLUMN, prd + ) assert qv_value.value() == "start [1 tracks, 4:23 unplayed]" class TestMMMiscNoPlaylist(unittest.TestCase): - PLAYLIST_NAME = "tracks playlist" test_tracks = [ "testdata/isa.mp3", @@ -121,10 +122,13 @@ class TestMMMiscNoPlaylist(unittest.TestCase): _ = str(prd) assert ( - model.edit_role(model.rowCount() - 1, playlistmodel.Col.TITLE.value, prd) + model.edit_role( + model.rowCount() - 1, playlistmodel.Col.TITLE.value, prd + ) == metadata["title"] ) + class TestMMMiscRowMove(unittest.TestCase): PLAYLIST_NAME = "rowmove playlist" ROWS_TO_CREATE = 11 @@ -292,7 +296,6 @@ class TestMMMiscRowMove(unittest.TestCase): self.model.add_track_to_header(insert_row, prd.track_id) def test_reverse_row_groups_one_row(self): - rows_to_move = [3] result = self.model._reversed_contiguous_row_groups(rows_to_move) @@ -301,7 +304,6 @@ class TestMMMiscRowMove(unittest.TestCase): assert result[0] == [3] def test_reverse_row_groups_multiple_row(self): - rows_to_move = [2, 3, 4, 5, 7, 9, 10, 13, 17, 20, 21] result = self.model._reversed_contiguous_row_groups(rows_to_move) @@ -357,7 +359,6 @@ class TestMMMiscRowMove(unittest.TestCase): assert [int(a) for a in row_notes] == [0, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9, 10] def test_move_multiple_rows_between_playlists_to_end(self): - from_rows = [1, 3, 4] to_row = 2 destination_playlist = "destination" @@ -382,7 +383,22 @@ class TestMMMiscRowMove(unittest.TestCase): assert len(model_src.playlist_rows) == self.ROWS_TO_CREATE - len(from_rows) assert len(model_dst.playlist_rows) == self.ROWS_TO_CREATE + len(from_rows) - assert [int(a) for a in row_notes] == [0, 1, 3, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + assert [int(a) for a in row_notes] == [ + 0, + 1, + 3, + 4, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + ] # # def test_edit_header(monkeypatch, session): # edit header row in middle of playlist diff --git a/tests/test_playlists.py b/tests/test_playlists.py index 8962e91..ad4f80d 100644 --- a/tests/test_playlists.py +++ b/tests/test_playlists.py @@ -41,13 +41,14 @@ def qtbot_adapter(qapp, request): # Wrapper to handle setup/teardown operations def with_updown(function): def test_wrapper(self, *args, **kwargs): - if callable(getattr(self, 'up', None)): + if callable(getattr(self, "up", None)): self.up() try: function(self, *args, **kwargs) finally: - if callable(getattr(self, 'down', None)): + if callable(getattr(self, "down", None)): self.down() + test_wrapper.__doc__ = function.__doc__ return test_wrapper @@ -103,12 +104,11 @@ class MyTestCase(unittest.TestCase): # }, # ] - # for track in tracks: - # db_track = models.Tracks(session=session, **track) - # session.add(db_track) - - # session.commit() +# for track in tracks: +# db_track = models.Tracks(session=session, **track) +# session.add(db_track) +# session.commit() # def test_save_and_restore(qtbot, session):