diff --git a/app/classes.py b/app/classes.py new file mode 100644 index 0000000..08ce0ae --- /dev/null +++ b/app/classes.py @@ -0,0 +1,176 @@ +from dataclasses import dataclass +from datetime import datetime, timedelta +from typing import Optional + +from PyQt6.QtCore import pyqtSignal, QObject +import numpy as np +import pyqtgraph as pg # type: ignore + +from config import Config +from dbconfig import scoped_session +from models import PlaylistRows +import helpers + + +class FadeCurve: + GraphWidget = None + + def __init__(self, track): + """ + Set up fade graph array + """ + + audio = helpers.get_audio_segment(track.path) + if not audio: + return None + + # Start point of curve is Config.FADE_CURVE_MS_BEFORE_FADE + # milliseconds before fade starts to silence + self.start_ms = max(0, track.fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1) + self.end_ms = track.silence_at + self.audio_segment = audio[self.start_ms : self.end_ms] + self.graph_array = np.array(self.audio_segment.get_array_of_samples()) + + # Calculate the factor to map milliseconds of track to array + self.ms_to_array_factor = len(self.graph_array) / (self.end_ms - self.start_ms) + + self.region = None + + def clear(self) -> None: + """Clear the current graph""" + + if self.GraphWidget: + self.GraphWidget.clear() + + def plot(self): + self.curve = self.GraphWidget.plot(self.graph_array) + self.curve.setPen(Config.FADE_CURVE_FOREGROUND) + + def tick(self, play_time) -> None: + """Update volume fade curve""" + + if not self.GraphWidget: + return + + ms_of_graph = play_time - self.start_ms + if ms_of_graph < 0: + return + + if self.region is None: + # Create the region now that we're into fade + self.region = pg.LinearRegionItem([0, 0], bounds=[0, len(self.graph_array)]) + self.GraphWidget.addItem(self.region) + + # Update region position + self.region.setRegion([0, ms_of_graph * self.ms_to_array_factor]) + + +@helpers.singleton +@dataclass +class MusicMusterSignals(QObject): + """ + Class for all MusicMuster signals. See: + - https://zetcode.com/gui/pyqt5/eventssignals/ + - https://stackoverflow.com/questions/62654525/ + emit-a-signal-from-another-class-to-main-class + and Singleton class at + https://refactoring.guru/design-patterns/singleton/python/example#example-0 + """ + + add_track_to_header_signal = pyqtSignal(int, int, int) + add_track_to_playlist_signal = pyqtSignal(int, int, int, str) + enable_escape_signal = pyqtSignal(bool) + set_next_track_signal = pyqtSignal(int, int) + span_cells_signal = pyqtSignal(int, int, int, int) + + def __post_init__(self): + super().__init__() + + +class PlaylistTrack: + """ + Used to provide a single reference point for specific playlist tracks, + typically the previous, current and next track. + """ + + def __init__(self) -> None: + """ + Only initialises data structure. Call set_plr to populate. + + Do NOT store row_number here - that changes if tracks are reordered + in playlist (add, remove, drag/drop) and we shouldn't care about row + number: that's the playlist's problem. + """ + + self.artist: Optional[str] = None + self.duration: Optional[int] = None + self.end_time: Optional[datetime] = None + self.fade_at: Optional[int] = None + self.fade_curve: Optional[FadeCurve] = None + self.fade_length: Optional[int] = None + self.path: Optional[str] = None + self.playlist_id: Optional[int] = None + self.plr_id: Optional[int] = None + self.silence_at: Optional[int] = None + self.start_gap: Optional[int] = None + self.start_time: Optional[datetime] = None + self.title: Optional[str] = None + self.track_id: Optional[int] = None + + def __repr__(self) -> str: + return ( + f"" + ) + + def set_plr(self, session: scoped_session, plr: PlaylistRows) -> None: + """ + Update with new plr information + """ + + if not plr.track: + return + + session.add(plr) + track = plr.track + + self.artist = track.artist + self.duration = track.duration + self.end_time = None + self.fade_at = track.fade_at + self.fade_graph = FadeCurve(track) + self.path = track.path + self.playlist_id = plr.playlist_id + self.plr_id = plr.id + self.silence_at = track.silence_at + self.start_gap = track.start_gap + self.start_time = None + self.title = track.title + self.track_id = track.id + + if track.silence_at and track.fade_at: + self.fade_length = track.silence_at - track.fade_at + + def start(self) -> None: + """ + Called when track starts playing + """ + + self.start_time = datetime.now() + if self.duration: + self.end_time = self.start_time + timedelta(milliseconds=self.duration) + + +@helpers.singleton +class CurrentTrack(PlaylistTrack): + pass + + +@helpers.singleton +class NextTrack(PlaylistTrack): + pass + + +@helpers.singleton +class PreviousTrack(PlaylistTrack): + pass diff --git a/app/dialogs.py b/app/dialogs.py index 3b3712b..a5a80e9 100644 --- a/app/dialogs.py +++ b/app/dialogs.py @@ -1,14 +1,14 @@ -from PyQt6.QtCore import QEvent, Qt -from PyQt6.QtWidgets import QDialog, QListWidgetItem from typing import Optional +from PyQt6.QtCore import QEvent, Qt +from PyQt6.QtWidgets import QDialog, QListWidgetItem + +from classes import MusicMusterSignals +from dbconfig import scoped_session from helpers import ( get_relative_date, ms_to_mmss, - MusicMusterSignals, ) - -from dbconfig import scoped_session from models import Settings, Tracks from ui.dlg_TrackSelect_ui import Ui_Dialog # type: ignore diff --git a/app/helpers.py b/app/helpers.py index 0c9b369..35a1943 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -1,3 +1,6 @@ +from datetime import datetime +from email.message import EmailMessage +from typing import Any, Dict, Optional import functools import os import psutil @@ -6,52 +9,19 @@ import smtplib import ssl import tempfile -from config import Config -from datetime import datetime -from email.message import EmailMessage -from log import log from mutagen.flac import FLAC # type: ignore from mutagen.mp3 import MP3 # type: ignore from pydub import AudioSegment, effects from pydub.utils import mediainfo -from PyQt6.QtCore import pyqtSignal, QObject from PyQt6.QtWidgets import QMainWindow, QMessageBox # type: ignore from tinytag import TinyTag # type: ignore -from typing import Any, Dict, Optional +from config import Config +from log import log -def singleton(cls): - """ - Make a class a Singleton class (see - https://realpython.com/primer-on-python-decorators/#creating-singletons) - """ +# Classes are defined after global functions so that classes can use +# those functions. - @functools.wraps(cls) - def wrapper_singleton(*args, **kwargs): - if not wrapper_singleton.instance: - wrapper_singleton.instance = cls(*args, **kwargs) - return wrapper_singleton.instance - - wrapper_singleton.instance = None - return wrapper_singleton - - -@singleton -class MusicMusterSignals(QObject): - """ - Class for all MusicMuster signals. See: - - https://zetcode.com/gui/pyqt5/eventssignals/ - - https://stackoverflow.com/questions/62654525/ - emit-a-signal-from-another-class-to-main-class - and Singleton class at - https://refactoring.guru/design-patterns/singleton/python/example#example-0 - """ - - add_track_to_header_signal = pyqtSignal(int, int, int) - add_track_to_playlist_signal = pyqtSignal(int, int, int, str) - enable_escape_signal = pyqtSignal(bool) - set_next_track_signal = pyqtSignal(int, int) - span_cells_signal = pyqtSignal(int, int, int, int) def ask_yes_no(title: str, question: str, default_yes: bool = False) -> bool: """Ask question; return True for yes, False for no""" @@ -414,6 +384,22 @@ def show_warning(parent: QMainWindow, title: str, msg: str) -> None: QMessageBox.warning(parent, title, msg, buttons=QMessageBox.StandardButton.Cancel) +def singleton(cls): + """ + Make a class a Singleton class (see + https://realpython.com/primer-on-python-decorators/#creating-singletons) + """ + + @functools.wraps(cls) + def wrapper_singleton(*args, **kwargs): + if not wrapper_singleton.instance: + wrapper_singleton.instance = cls(*args, **kwargs) + return wrapper_singleton.instance + + wrapper_singleton.instance = None + return wrapper_singleton + + def trailing_silence( audio_segment: AudioSegment, silence_threshold: int = -50, diff --git a/app/musicmuster.py b/app/musicmuster.py index 1bef710..a0158ef 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -1,18 +1,7 @@ #!/usr/bin/env python3 -from log import log -from os.path import basename -import argparse -import os -import numpy as np -import pyqtgraph as pg # type: ignore -import stackprinter # type: ignore -import subprocess -import sys -import threading - from datetime import datetime, timedelta -from pygame import mixer +from os.path import basename from time import sleep from typing import ( cast, @@ -20,18 +9,20 @@ from typing import ( Optional, Sequence, ) +import argparse +import os +import subprocess +import sys +import threading -from playlistmodel import PlaylistModel - -from sqlalchemy import text - +from pygame import mixer from PyQt6.QtCore import ( pyqtSignal, QDate, QEvent, QObject, - Qt, QSize, + Qt, QThread, QTime, QTimer, @@ -54,27 +45,39 @@ from PyQt6.QtWidgets import ( QListWidgetItem, QMainWindow, QMessageBox, - QPushButton, QProgressBar, + QPushButton, ) +from sqlalchemy import text +import stackprinter # type: ignore +from classes import ( + CurrentTrack, + FadeCurve, + MusicMusterSignals, + NextTrack, + PlaylistTrack, + PreviousTrack, +) +from config import Config from dbconfig import ( engine, - Session, scoped_session, + Session, ) -import helpers -import icons_rc # noqa F401 -import music from dialogs import TrackSelectDialog +from log import log from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks -from config import Config +from playlistmodel import PlaylistModel from playlists import PlaylistTab from ui.dlg_cart_ui import Ui_DialogCartEdit # type: ignore from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore from ui.downloadcsv_ui import Ui_DateSelect # type: ignore from ui.main_window_ui import Ui_MainWindow # type: ignore from utilities import check_db, update_bitrates +import helpers +import icons_rc # noqa F401 +import music class CartButton(QPushButton): @@ -144,59 +147,6 @@ class CartButton(QPushButton): self.pgb.setGeometry(0, 0, self.width(), 10) -class FadeCurve: - GraphWidget = None - - def __init__(self, track): - """ - Set up fade graph array - """ - - audio = helpers.get_audio_segment(track.path) - if not audio: - return None - - # Start point of curve is Config.FADE_CURVE_MS_BEFORE_FADE - # milliseconds before fade starts to silence - self.start_ms = max(0, track.fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1) - self.end_ms = track.silence_at - self.audio_segment = audio[self.start_ms : self.end_ms] - self.graph_array = np.array(self.audio_segment.get_array_of_samples()) - - # Calculate the factor to map milliseconds of track to array - self.ms_to_array_factor = len(self.graph_array) / (self.end_ms - self.start_ms) - - self.region = None - - def clear(self) -> None: - """Clear the current graph""" - - if self.GraphWidget: - self.GraphWidget.clear() - - def plot(self): - self.curve = self.GraphWidget.plot(self.graph_array) - self.curve.setPen(Config.FADE_CURVE_FOREGROUND) - - def tick(self, play_time) -> None: - """Update volume fade curve""" - - if not self.GraphWidget: - return - - ms_of_graph = play_time - self.start_ms - if ms_of_graph < 0: - return - - if self.region is None: - # Create the region now that we're into fade - self.region = pg.LinearRegionItem([0, 0], bounds=[0, len(self.graph_array)]) - self.GraphWidget.addItem(self.region) - - # Update region position - self.region.setRegion([0, ms_of_graph * self.ms_to_array_factor]) - - class ImportTrack(QObject): import_error = pyqtSignal(str) importing = pyqtSignal(str) @@ -237,84 +187,6 @@ class ImportTrack(QObject): self.finished.emit(self.playlist) -class PlaylistTrack: - """ - Used to provide a single reference point for specific playlist tracks, - typically the previous, current and next track. - """ - - def __init__(self) -> None: - """ - Only initialises data structure. Call set_plr to populate. - - Do NOT store row_number here - that changes if tracks are reordered - in playlist (add, remove, drag/drop) and we shouldn't care about row - number: that's the playlist's problem. - """ - - self.artist: Optional[str] = None - self.duration: Optional[int] = None - self.end_time: Optional[datetime] = None - self.fade_at: Optional[int] = None - self.fade_curve: Optional[FadeCurve] = None - self.fade_length: Optional[int] = None - self.path: Optional[str] = None - self.playlist_id: Optional[int] = None - self.playlist_tab: Optional[PlaylistTab] = None - self.plr_id: Optional[int] = None - self.silence_at: Optional[int] = None - self.start_gap: Optional[int] = None - self.start_time: Optional[datetime] = None - self.title: Optional[str] = None - self.track_id: Optional[int] = None - - def __repr__(self) -> str: - return ( - f"" - ) - - def set_plr( - self, session: scoped_session, plr: PlaylistRows, tab: PlaylistTab - ) -> None: - """ - Update with new plr information - """ - - if not plr.track: - return - - self.playlist_tab = tab - session.add(plr) - track = plr.track - - self.artist = track.artist - self.duration = track.duration - self.end_time = None - self.fade_at = track.fade_at - self.fade_graph = FadeCurve(track) - self.path = track.path - self.playlist_id = plr.playlist_id - self.plr_id = plr.id - self.silence_at = track.silence_at - self.start_gap = track.start_gap - self.start_time = None - self.title = track.title - self.track_id = track.id - - if track.silence_at and track.fade_at: - self.fade_length = track.silence_at - track.fade_at - - def start(self) -> None: - """ - Called when track starts playing - """ - - self.start_time = datetime.now() - if self.duration: - self.end_time = self.start_time + timedelta(milliseconds=self.duration) - - class Window(QMainWindow, Ui_MainWindow): def __init__(self, parent=None, *args, **kwargs) -> None: super().__init__(parent) @@ -327,9 +199,9 @@ class Window(QMainWindow, Ui_MainWindow): self.music: music.Music = music.Music() self.playing: bool = False - self.current_track = PlaylistTrack() - self.next_track = PlaylistTrack() - self.previous_track = PlaylistTrack() + self.current_track = CurrentTrack() + self.next_track = NextTrack() + self.previous_track = PreviousTrack() self.previous_track_position: Optional[float] = None self.selected_plrs: Optional[List[PlaylistRows]] = None @@ -362,7 +234,7 @@ class Window(QMainWindow, Ui_MainWindow): self.timer10.start(10) self.timer500.start(500) self.timer1000.start(1000) - self.signals = helpers.MusicMusterSignals() + self.signals = MusicMusterSignals() self.connect_signals_slots() def about(self) -> None: @@ -521,7 +393,7 @@ class Window(QMainWindow, Ui_MainWindow): Clear next track """ - self.next_track = PlaylistTrack() + self.next_track = NextTrack() self.update_headers() def clear_selection(self) -> None: @@ -598,27 +470,29 @@ class Window(QMainWindow, Ui_MainWindow): Return True if tab closed else False. """ - # Don't close current track playlist - if self.tabPlaylist.widget(tab_index) == (self.current_track.playlist_tab): - self.statusbar.showMessage("Can't close current track playlist", 5000) - return False + return False + # TODO Reimplement without ussing self.current_track.playlist_tab + # # Don't close current track playlist + # if self.tabPlaylist.widget(tab_index) == (self.current_track.playlist_tab): + # self.statusbar.showMessage("Can't close current track playlist", 5000) + # return False - # Attempt to close next track playlist - if self.tabPlaylist.widget(tab_index) == self.next_track.playlist_tab: - self.next_track.playlist_tab.clear_next() + # # Attempt to close next track playlist + # if self.tabPlaylist.widget(tab_index) == self.next_track.playlist_tab: + # self.next_track.playlist_tab.clear_next() - # Record playlist as closed and update remaining playlist tabs - with Session() as session: - playlist_id = self.tabPlaylist.widget(tab_index).playlist_id - playlist = session.get(Playlists, playlist_id) - if playlist: - playlist.close(session) + # # Record playlist as closed and update remaining playlist tabs + # with Session() as session: + # playlist_id = self.tabPlaylist.widget(tab_index).playlist_id + # playlist = session.get(Playlists, playlist_id) + # if playlist: + # playlist.close(session) - # Close playlist and remove tab - self.tabPlaylist.widget(tab_index).close() - self.tabPlaylist.removeTab(tab_index) + # # Close playlist and remove tab + # self.tabPlaylist.widget(tab_index).close() + # self.tabPlaylist.removeTab(tab_index) - return True + # return True def connect_signals_slots(self) -> None: self.action_About.triggered.connect(self.about) @@ -834,16 +708,17 @@ class Window(QMainWindow, Ui_MainWindow): self.playing = False # Tell playlist_tab track has finished - if self.current_track.playlist_tab: - self.current_track.playlist_tab.play_ended() + # TODO Reimplement as a signal + # if self.current_track.playlist_tab: + # self.current_track.playlist_tab.play_ended() # Reset fade graph self.current_track.fade_graph.clear() # Reset PlaylistTrack objects if self.current_track.track_id: - self.previous_track = self.current_track - self.current_track = PlaylistTrack() + self.previous_track = cast(PreviousTrack, self.current_track) + self.current_track = CurrentTrack() # Reset clocks self.frame_fade.setStyleSheet("") @@ -907,18 +782,6 @@ class Window(QMainWindow, Ui_MainWindow): self.stop_playing(fade=True) - def get_one_track(self, session: scoped_session) -> Optional[Tracks]: - """Show dialog box to select one track and return it to caller""" - - dlg = TrackSelectDialog(self, session) - dlg.ui.txtNote.hide() - dlg.ui.lblNote.hide() - - if dlg.exec(): - return dlg.track - else: - return None - def get_playtime(self) -> int: """ Return number of milliseconds current track has been playing or @@ -1013,7 +876,7 @@ class Window(QMainWindow, Ui_MainWindow): self.worker.finished.connect(self.import_complete) self.import_thread.start() - def import_complete(self, playlist_tab: PlaylistTab): + def import_complete(self): """ Called by thread when track import complete """ @@ -1302,7 +1165,7 @@ class Window(QMainWindow, Ui_MainWindow): # Move next track to current track. # stop_playing() above has called end_of_track_actions() # which will have populated self.previous_track - self.current_track = self.next_track + self.current_track = cast(CurrentTrack, self.next_track) self.clear_next() if not self.current_track.track_id: @@ -1313,9 +1176,10 @@ class Window(QMainWindow, Ui_MainWindow): return # Set current track playlist_tab colour - current_tab = self.current_track.playlist_tab - if current_tab: - self.set_tab_colour(current_tab, QColor(Config.COLOUR_CURRENT_TAB)) + # 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(): @@ -1344,8 +1208,9 @@ class Window(QMainWindow, Ui_MainWindow): Playdates(session, self.current_track.track_id) # Tell playlist track is now playing - if self.current_track.playlist_tab: - self.current_track.playlist_tab.play_started(session) + # TODO Reimplement without reference to self.current_track.playlist_tab: + # if self.current_track.playlist_tab: + # self.current_track.playlist_tab.play_started(session) # Note that track is now playing self.playing = True @@ -1404,41 +1269,45 @@ class Window(QMainWindow, Ui_MainWindow): - If a track is playing, make that the next track """ - # Return if no saved position - if not self.previous_track_position: - return + return + # TODO Reimplement without reference to playlist_tab + # # Return if no saved position + # if not self.previous_track_position: + # return - # Note any playing track as this will become the next track - playing_track = None - if self.current_track.track_id: - playing_track = self.current_track + # # Note any playing track as this will become the next track + # playing_track = None + # if self.current_track.track_id: + # playing_track = self.current_track - # Set next plr to be track to resume - if not self.previous_track.plr_id: - return - if not self.previous_track.playlist_tab: - return + # # Set next plr to be track to resume + # if not self.previous_track.plr_id: + # return + # # TODO Reimplement following two lines + # # if not self.previous_track.playlist_tab: + # # return - # Resume last track - self.set_next_plr_id( - self.previous_track.plr_id, self.previous_track.playlist_tab - ) - self.play_next(self.previous_track_position) + # # Resume last track + # # TODO Reimplement next four lines + # # self.set_next_plr_id( + # # self.previous_track.plr_id, self.previous_track.playlist_tab + # # ) + # # self.play_next(self.previous_track_position) - # Adjust track info so that clocks and graph are correct. - # Easiest way is to fake the start time. - if self.current_track.start_time and self.current_track.duration: - elapsed_ms = self.current_track.duration * self.previous_track_position - self.current_track.start_time -= timedelta(milliseconds=elapsed_ms) + # # Adjust track info so that clocks and graph are correct. + # # Easiest way is to fake the start time. + # if self.current_track.start_time and self.current_track.duration: + # elapsed_ms = self.current_track.duration * self.previous_track_position + # self.current_track.start_time -= timedelta(milliseconds=elapsed_ms) - # If a track was playing when we were called, get details to - # set it as the next track - if playing_track: - if not playing_track.plr_id: - return - if not playing_track.playlist_tab: - return - self.set_next_plr_id(playing_track.plr_id, playing_track.playlist_tab) + # # If a track was playing when we were called, get details to + # # set it as the next track + # if playing_track: + # if not playing_track.plr_id: + # return + # if not playing_track.playlist_tab: + # return + # self.set_next_plr_id(playing_track.plr_id, playing_track.playlist_tab) def save_as_template(self) -> None: """Save current playlist as template""" @@ -1564,16 +1433,20 @@ class Window(QMainWindow, Ui_MainWindow): def show_current(self) -> None: """Scroll to show current track""" - if self.current_track.playlist_tab != self.active_tab(): - self.tabPlaylist.setCurrentWidget(self.current_track.playlist_tab) - self.tabPlaylist.currentWidget().scroll_current_to_top() + return + # TODO Reimplement + # if self.current_track.playlist_tab != self.active_tab(): + # self.tabPlaylist.setCurrentWidget(self.current_track.playlist_tab) + # self.tabPlaylist.currentWidget().scroll_current_to_top() def show_next(self) -> None: """Scroll to show next track""" - if self.next_track.playlist_tab != self.active_tab(): - self.tabPlaylist.setCurrentWidget(self.next_track.playlist_tab) - self.tabPlaylist.currentWidget().scroll_next_to_top() + return + # TODO Reimplement + # if self.next_track.playlist_tab != self.active_tab(): + # self.tabPlaylist.setCurrentWidget(self.next_track.playlist_tab) + # self.tabPlaylist.currentWidget().scroll_next_to_top() def solicit_playlist_name(self, default: Optional[str] = "") -> Optional[str]: """Get name of playlist from user""" @@ -1618,15 +1491,16 @@ class Window(QMainWindow, Ui_MainWindow): self.music.stop() # Reset playlist_tab colour - if self.current_track.playlist_tab: - if self.current_track.playlist_tab == self.next_track.playlist_tab: - self.set_tab_colour( - self.current_track.playlist_tab, QColor(Config.COLOUR_NEXT_TAB) - ) - else: - self.set_tab_colour( - self.current_track.playlist_tab, QColor(Config.COLOUR_NORMAL_TAB) - ) + # TODO Reimplement + # if self.current_track.playlist_tab: + # if self.current_track.playlist_tab == self.next_track.playlist_tab: + # self.set_tab_colour( + # self.current_track.playlist_tab, QColor(Config.COLOUR_NEXT_TAB) + # ) + # else: + # self.set_tab_colour( + # self.current_track.playlist_tab, QColor(Config.COLOUR_NORMAL_TAB) + # ) # Run end-of-track actions self.end_of_track_actions() @@ -1670,11 +1544,11 @@ class Window(QMainWindow, Ui_MainWindow): with Session() as session: # Update self.next_track PlaylistTrack structure old_next_track = self.next_track - self.next_track = PlaylistTrack() + self.next_track = NextTrack() if next_plr_id: next_plr = session.get(PlaylistRows, next_plr_id) if next_plr: - self.next_track.set_plr(session, next_plr, playlist_tab) + self.next_track.set_plr(session, next_plr) # Tell playlist tabs to update their 'next track' highlighting # Args must both be ints, so use zero for no next track @@ -1709,30 +1583,32 @@ class Window(QMainWindow, Ui_MainWindow): # If the original next playlist tab isn't the same as the # new one or the current track, it needs its colour reset. - if ( - old_next_track - and old_next_track.playlist_tab - and old_next_track.playlist_tab - not in [self.next_track.playlist_tab, self.current_track.playlist_tab] - ): - self.set_tab_colour( - old_next_track.playlist_tab, QColor(Config.COLOUR_NORMAL_TAB) - ) - # If the new next playlist tab isn't the same as the - # old one or the current track, it needs its colour set. - if old_next_track: - old_tab = old_next_track.playlist_tab - else: - old_tab = None - if ( - self.next_track - and self.next_track.playlist_tab - and self.next_track.playlist_tab - not in [old_tab, self.current_track.playlist_tab] - ): - self.set_tab_colour( - self.next_track.playlist_tab, QColor(Config.COLOUR_NEXT_TAB) - ) + return + # TODO Reimplement + # if ( + # old_next_track + # and old_next_track.playlist_tab + # and old_next_track.playlist_tab + # not in [self.next_track.playlist_tab, self.current_track.playlist_tab] + # ): + # self.set_tab_colour( + # old_next_track.playlist_tab, QColor(Config.COLOUR_NORMAL_TAB) + # ) + # # If the new next playlist tab isn't the same as the + # # old one or the current track, it needs its colour set. + # if old_next_track: + # old_tab = old_next_track.playlist_tab + # else: + # old_tab = None + # if ( + # self.next_track + # and self.next_track.playlist_tab + # and self.next_track.playlist_tab + # not in [old_tab, self.current_track.playlist_tab] + # ): + # self.set_tab_colour( + # self.next_track.playlist_tab, QColor(Config.COLOUR_NEXT_TAB) + # ) def tick_10ms(self) -> None: """ diff --git a/app/playlistmodel.py b/app/playlistmodel.py index f5b971b..60a9597 100644 --- a/app/playlistmodel.py +++ b/app/playlistmodel.py @@ -1,7 +1,6 @@ from datetime import datetime from enum import auto, Enum -from sqlalchemy import bindparam, update -from typing import List, Optional, TYPE_CHECKING +from typing import List, Optional from PyQt6.QtCore import ( QAbstractTableModel, @@ -15,12 +14,10 @@ from PyQt6.QtGui import ( QFont, ) +from classes import CurrentTrack, MusicMusterSignals, NextTrack from config import Config from dbconfig import scoped_session, Session -from helpers import ( - file_is_unreadable, - MusicMusterSignals, -) +from helpers import file_is_unreadable from log import log from models import PlaylistRows, Tracks diff --git a/app/playlists.py b/app/playlists.py index 5966035..b93c55d 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -37,13 +37,13 @@ from PyQt6.QtWidgets import ( from dbconfig import Session, scoped_session from dialogs import TrackSelectDialog +from classes import MusicMusterSignals from config import Config from helpers import ( ask_yes_no, file_is_unreadable, get_relative_date, ms_to_mmss, - MusicMusterSignals, open_in_audacity, send_mail, set_track_metadata,