diff --git a/components/MusicTable.py b/components/MusicTable.py index b02dc40..2b9b595 100644 --- a/components/MusicTable.py +++ b/components/MusicTable.py @@ -75,58 +75,38 @@ class MusicTable(QTableView): focusEnterSignal = pyqtSignal() focusLeaveSignal = pyqtSignal() - def focusInEvent(self, e): - """ - Event filter: when self is focused - """ - self.focusEnterSignal.emit() - # arrow keys act normal - super().focusInEvent(e) - - def focusOutEvent(self, e): - """ - Event filter: when self becomes unfocused - """ - self.focusLeaveSignal.emit() - def __init__(self, parent=None, application_window=None): super().__init__(parent) # why do i need this? self.application_window = application_window - - # NOTE: wtf is actually going on here with the models? - # Create QStandardItemModel - # Create QSortFilterProxyModel - # Set QSortFilterProxyModel source to QStandardItemModel - # Set QTableView model to the Proxy model - # so it looks like this, i guess: - # QTableView model2 = QSortFilterProxyModel(QStandardItemModel) - - # need a standard item model to do actions on cells - self.model2: QStandardItemModel = QStandardItemModel() - # proxy model for sorting i guess? - self.proxymodel = QSortFilterProxyModel() - self.proxymodel.setSourceModel(self.model2) - self.setModel(self.proxymodel) - self.setSortingEnabled(True) - self.search_string = None - + self.config = ConfigParser() # Config cfg_file = ( Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini" ) - self.config = ConfigParser() self.config.read(cfg_file) debug(f"music table config: {self.config}") - # Threads - self.threadpool = QThreadPool - # headers class thing - self.headers = HeaderTags() + # NOTE: + # QTableView model2 = QSortFilterProxyModel(QStandardItemModel) + # + # wtf is actually going on here with the models? + # Create QStandardItemModel + # Create QSortFilterProxyModel + # Set QSortFilterProxyModel source to QStandardItemModel + # Set QTableView model to the Proxy model + # so it looks like that, i guess + # need a QStandardItemModel to do actions on cells + self.model2: QStandardItemModel = QStandardItemModel() + self.proxymodel = QSortFilterProxyModel() + self.search_string = None + self.threadpool = QThreadPool + self.headers = HeaderTags() # db names of headers - self.database_columns = str(self.config["table"]["columns"]).split(",") + self.database_columns: list[str] = str( + self.config["table"]["columns"]).split(",") self.vertical_scroll_position = 0 self.selected_song_filepath = "" self.selected_song_qmodel_index: QModelIndex @@ -135,6 +115,11 @@ class MusicTable(QTableView): self.current_song_qmodel_index: QModelIndex self.selected_playlist_id: int | None = None + # proxy model for sorting i guess? + self.proxymodel.setSourceModel(self.model2) + self.setModel(self.proxymodel) + self.setSortingEnabled(True) + # Properties self.setAcceptDrops(True) self.setHorizontalScrollBarPolicy( @@ -175,6 +160,20 @@ class MusicTable(QTableView): # | | # |_________________| + def focusInEvent(self, e): + """ + Event filter: when self is focused + """ + self.focusEnterSignal.emit() + # arrow keys act normal + super().focusInEvent(e) + + def focusOutEvent(self, e): + """ + Event filter: when self becomes unfocused + """ + self.focusLeaveSignal.emit() + def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None: """Do something when the QTableView is resized""" if e is None: @@ -490,7 +489,8 @@ class MusicTable(QTableView): """ worker = Worker(add_files_to_database, files) _ = worker.signals.signal_progress.connect(self.qapp.handle_progress) - _ = worker.signals.signal_result.connect(self.on_add_files_to_database_finished) + _ = worker.signals.signal_result.connect( + self.on_add_files_to_database_finished) worker.signals.signal_finished.connect(self.load_music_table) if self.qapp: threadpool = self.qapp.threadpool @@ -660,7 +660,7 @@ class MusicTable(QTableView): def reorganize_files(self, filepaths, progress_callback=None): """ Reorganizes files into Artist/Album/Song, - based on self.config['directories'][reorganize_destination'] + based on self.config['settings'][reorganize_destination'] """ debug("reorganizing files") # FIXME: batch update, instead of doing 1 file at a time @@ -671,7 +671,7 @@ class MusicTable(QTableView): # FIXME: change reorganize location in config, try to reorganize, failed - old reference # Get target directory - target_dir = str(self.config["directories"]["reorganize_destination"]) + target_dir = str(self.config["settings"]["reorganize_destination"]) for filepath in filepaths: # Read file metadata artist, album = get_reorganize_vars(filepath) @@ -737,7 +737,8 @@ class MusicTable(QTableView): self.selected_playlist_id = playlist_id[0] try: with DBA.DBAccess() as db: - query = f"SELECT id, {fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?" + query = f"SELECT id, { + fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?" # fulltext search if self.search_string: # params = 3 * [self.search_string] @@ -821,7 +822,8 @@ class MusicTable(QTableView): db_name: str = self.config.get("settings", "db").split("/").pop() db_filename = self.config.get("settings", "db") self.playlistStatsSignal.emit( - f"Songs: {row_count} | Total time: {total_time} | {db_name} | {db_filename}" + f"Songs: {row_count} | Total time: { + total_time} | {db_name} | {db_filename}" ) self.loadMusicTableSignal.emit() self.connect_data_changed() diff --git a/main.py b/main.py index 1fd2544..6799046 100644 --- a/main.py +++ b/main.py @@ -57,6 +57,8 @@ from utils import ( add_files_to_database, set_album_art, id3_remap, + get_album_art, + Worker ) from components import ( HeaderTags, @@ -68,9 +70,6 @@ from components import ( ExportPlaylistWindow, SearchLineEdit, ) -from utils.get_album_art import get_album_art -# from utils.Worker import Worker -from utils import Worker # good help with signals slots in threads # https://stackoverflow.com/questions/52993677/how-do-i-setup-signals-and-slots-in-pyqt-with-qthreads-in-both-directions @@ -162,18 +161,23 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.playbackSlider.sliderReleased.connect( lambda: self.player.setPosition(self.playbackSlider.value()) ) # sliderReleased works better than sliderMoved - self.volumeSlider.sliderMoved[int].connect(lambda: self.on_volume_changed()) + self.volumeSlider.sliderMoved[int].connect( + lambda: self.on_volume_changed()) self.speedSlider.sliderMoved.connect( lambda: self.on_speed_changed(self.speedSlider.value()) ) # self.speedSlider.doubleClicked.connect(lambda: self.on_speed_changed(1)) - self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause + self.playButton.clicked.connect( + self.on_play_clicked) # Click to play/pause self.previousButton.clicked.connect(self.on_prev_clicked) - self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song + self.nextButton.clicked.connect( + self.on_next_clicked) # Click to next song # FILE MENU - self.actionOpenFiles.triggered.connect(self.open_files) # Open files window - self.actionNewPlaylist.triggered.connect(self.playlistTreeView.create_playlist) + self.actionOpenFiles.triggered.connect( + self.open_files) # Open files window + self.actionNewPlaylist.triggered.connect( + self.playlistTreeView.create_playlist) self.actionExportPlaylist.triggered.connect(self.export_playlist) # EDIT MENU @@ -195,14 +199,16 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.lineEditSearch: QLineEdit # CONNECTIONS - self.lineEditSearch.textTypedSignal.connect(self.handle_search_box_text) + self.lineEditSearch.textTypedSignal.connect( + self.handle_search_box_text) # tableView self.tableView.playSignal.connect(self.play_audio_file) self.tableView.playPauseSignal.connect( self.on_play_clicked ) # Spacebar toggle play/pause signal self.tableView.handleProgressSignal.connect(self.handle_progress) - self.tableView.searchBoxSignal.connect(self.handle_search_box_visibility) + self.tableView.searchBoxSignal.connect( + self.handle_search_box_visibility) self.tableView.playlistStatsSignal.connect( self.set_permanent_status_bar_message ) @@ -213,7 +219,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.playlistTreeView.playlistChoiceSignal.connect( self.tableView.load_music_table ) - self.playlistTreeView.allSongsSignal.connect(self.tableView.load_music_table) + self.playlistTreeView.allSongsSignal.connect( + self.tableView.load_music_table) # albumGraphicsView self.albumGraphicsView.albumArtDropped.connect( @@ -315,7 +322,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): current_real_index = self.tableView.current_song_qmodel_index try: index = self.tableView.proxymodel.mapFromSource(current_real_index) - except: + except Exception: return row: int = index.row() prev_row: int = row - 1 @@ -392,7 +399,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): def load_config(self) -> None: """does what it says""" cfg_file = ( - Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini" + Path(user_config_dir(appname="musicpom", + appauthor="billypom")) / "config.ini" ) self.config.read(cfg_file) debug("load_config()") @@ -470,7 +478,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): selected_songs = self.tableView.get_selected_songs_filepaths() for song in selected_songs: debug( - f"main.py set_album_art_for_selected_songs() | updating album art for {song}" + f"main.py set_album_art_for_selected_songs() | updating album art for { + song}" ) set_album_art(song, album_art_path) @@ -497,7 +506,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.playbackSlider.setMaximum(self.player.duration()) slider_position = self.player.position() self.playbackSlider.setValue(slider_position) - current_minutes, current_seconds = divmod(slider_position / 1000, 60) + current_minutes, current_seconds = divmod( + slider_position / 1000, 60) duration_minutes, duration_seconds = divmod( self.player.duration() / 1000, 60 ) @@ -548,7 +558,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): def create_playlist(self) -> None: """Creates a database record for a playlist, given a name""" window = CreatePlaylistWindow(self.playlistCreatedSignal) - window.playlistCreatedSignal.connect(self.add_latest_playlist_to_tree) # type: ignore + window.playlistCreatedSignal.connect( + self.add_latest_playlist_to_tree) # type: ignore window.exec_() def import_playlist(self) -> None: @@ -574,8 +585,10 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): preferences_window = PreferencesWindow( self.reloadConfigSignal, self.reloadDatabaseSignal ) - preferences_window.reloadConfigSignal.connect(self.load_config) # type: ignore - preferences_window.reloadDatabaseSignal.connect(self.tableView.load_music_table) # type: ignore + preferences_window.reloadConfigSignal.connect( + self.load_config) # type: ignore + preferences_window.reloadDatabaseSignal.connect( + self.tableView.load_music_table) # type: ignore preferences_window.exec_() # Display the preferences window modally # Quick Actions @@ -609,9 +622,11 @@ def update_database_file() -> bool: Reads the database file (specified by config file) """ cfg_file = ( - Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini" + Path(user_config_dir(appname="musicpom", + appauthor="billypom")) / "config.ini" ) - cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom"))) + cfg_path = str(Path(user_config_dir( + appname="musicpom", appauthor="billypom"))) config = ConfigParser() config.read(cfg_file) db_filepath: str = config.get("settings", "db") @@ -620,9 +635,10 @@ def update_database_file() -> bool: if not db_filepath.startswith(cfg_path): new_path = f"{cfg_path}/{db_filepath}" debug( - f"Set new config [db] database path: \n> Current: {db_filepath}\n> New:{new_path}" + f"Set new config [db] database path: \n> Current: { + db_filepath}\n> New:{new_path}" ) - config["db"]["database"] = new_path + config["settings"]["db"] = new_path # Save the config with open(cfg_file, "w") as configfile: config.write(configfile) @@ -654,9 +670,11 @@ def update_config_file() -> ConfigParser: If the user config file is not up to date, update it with examples from sample config """ cfg_file = ( - Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini" + Path(user_config_dir(appname="musicpom", + appauthor="billypom")) / "config.ini" ) - cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom"))) + cfg_path = str(Path(user_config_dir( + appname="musicpom", appauthor="billypom"))) # If config path doesn't exist, create it if not os.path.exists(cfg_path): @@ -720,8 +738,8 @@ if __name__ == "__main__": app = QApplication(sys.argv) clipboard = app.clipboard() # Dark theme >:3 - qdarktheme.setup_theme() - # qdarktheme.setup_theme("auto") # this is supposed to work but doesnt + # qdarktheme.setup_theme() + qdarktheme.setup_theme("auto") # this is supposed to work but doesnt # Show the UI ui = ApplicationWindow(clipboard) # window size diff --git a/requirements.txt b/requirements.txt index 7aa6995..594c1e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,8 @@ matplotlib appdirs pyqt5 pydub -pyqtdarktheme-fork; python_version > '3.11' -pyqtdarktheme; python_version < '3.12' +audioop-lts +pyqtdarktheme-fork; python_version < '3.11' +pyqtdarktheme; python_version > '3.12' pyqtgraph scipy