From f1d018f7ce071196c71992da855e50d7fbe30037 Mon Sep 17 00:00:00 2001 From: billy Date: Fri, 3 Oct 2025 19:23:40 -0400 Subject: [PATCH] new header implementation working --- components/HeaderTags.py | 18 ++++++++++++++---- components/MetadataWindow.py | 14 +++++++------- components/MusicTable.py | 27 ++++++++++++--------------- main.py | 19 ++++++++----------- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/components/HeaderTags.py b/components/HeaderTags.py index 37c7531..f573d82 100644 --- a/components/HeaderTags.py +++ b/components/HeaderTags.py @@ -102,6 +102,7 @@ class ID3Field: gui: str # e.g., "Title" frame_class: Optional[type] = None # e.g., TPE1 frame_id: Optional[str] = None # e.g., "TPE1" + editable: bool = True class HeaderTags2: @@ -113,11 +114,11 @@ class HeaderTags2: ID3Field(frame_class=TPE2, frame_id="TPE2", db="album_artist", gui="Album Artist"), ID3Field(frame_class=TRCK, frame_id="TRCK", db="track_number", gui="Track"), ID3Field(frame_class=TCON, frame_id="TCON", db="genre", gui="Genre"), - ID3Field(frame_class=TLEN, frame_id="TLEN", db="length_ms", gui="Time"), ID3Field(frame_class=TDRC, frame_id="TDRC", db="album_date", gui="Year"), - ID3Field(db="codec", gui="Codec"), - ID3Field(db="filepath", gui="Filepath"), - ID3Field(db="bitrate", gui="Bitrate"), + ID3Field(frame_class=TLEN, frame_id="TLEN", db="length_ms", gui="Time", editable=False), + ID3Field(db="codec", gui="Codec", editable=False), + ID3Field(db="filepath", gui="Filepath", editable=False), + ID3Field(db="bitrate", gui="Bitrate", editable=False), ] # Lookup dicts # - Usage example: frame_id['TPE1'].db # => "artist" @@ -125,6 +126,15 @@ class HeaderTags2: self.db = {f.db: f for f in self.headers} self.gui = {f.gui: f for f in self.headers} + # Simple lists + self.frame_id_list = [f.frame_id for f in self.headers] + self.db_list = [f.db for f in self.headers] + self.gui_list = [f.gui for f in self.headers] + + def get_editable_db_list(self) -> list: + return [f.db for f in self.headers if f.editable] + + class HeaderTags: """ diff --git a/components/MetadataWindow.py b/components/MetadataWindow.py index 09a5569..18fd7ee 100644 --- a/components/MetadataWindow.py +++ b/components/MetadataWindow.py @@ -11,7 +11,6 @@ from PyQt5.QtWidgets import ( from PyQt5.QtGui import QFont from components.ErrorDialog import ErrorDialog from utils import set_tag, get_tags, update_song_in_database -from logging import debug # import re @@ -71,9 +70,10 @@ class MetadataWindow(QDialog): QMessageBox.Ok, ) return - for key, tag in self.headers.id3.items(): - if key not in self.headers.editable_fields: + for key in self.headers.db_list: + if key not in self.headers.get_editable_db_list(): continue + tag = self.headers.db[key].frame_id if tag is not None: try: _ = tag_sets[tag] @@ -98,7 +98,7 @@ class MetadataWindow(QDialog): # If the ID3 tag is the same for every item we're editing field_text = str(value[0]) if value else "" # Normal field - label = QLabel(str(self.headers.id3_keys[tag])) + label = QLabel(str(self.headers.frame_id[tag].db)) input_field = ID3LineEdit(field_text, tag) input_field.setStyleSheet(None) else: @@ -106,7 +106,7 @@ class MetadataWindow(QDialog): # this means the metadata differs between the selected items for this tag # so be careful...dangerous field_text = "" - label = QLabel(str(self.headers.id3_keys[tag])) + label = QLabel(str(self.headers.frame_id[tag].db)) input_field = ID3LineEdit(field_text, tag) input_field.setStyleSheet("border: 1px solid red") # Save each input field to our dict for saving @@ -130,12 +130,12 @@ class MetadataWindow(QDialog): # Update the ID3 tag if the tag is not blank, # and has been edited success = set_tag( - filepath=song[0], tag_name=tag, value=field.text() + filepath=song[0], db_column=tag, value=field.text() ) if success: update_song_in_database( song[1], - edited_column_name=self.headers.id3_keys[tag], + edited_column_name=self.headers.frame_id[tag].db, user_input_data=field.text(), ) else: diff --git a/components/MusicTable.py b/components/MusicTable.py index 86742c5..9743bb6 100644 --- a/components/MusicTable.py +++ b/components/MusicTable.py @@ -33,7 +33,7 @@ from components.LyricsWindow import LyricsWindow from components.AddToPlaylistWindow import AddToPlaylistWindow from components.MetadataWindow import MetadataWindow from components.QuestionBoxDetails import QuestionBoxDetails -from components.HeaderTags import HeaderTags +from components.HeaderTags import HeaderTags2 from utils import ( batch_delete_filepaths_from_database, @@ -99,10 +99,7 @@ class MusicTable(QTableView): self.data_cache = {} self.playlist_scroll_positions: dict[int | None, int] = {} self.search_string: str | None = None - self.headers = HeaderTags() - # db names of headers - self.database_columns: list[str] = str( - self.config["table"]["columns"]).split(",") + self.headers = HeaderTags2() self.selected_song_filepath = "" self.selected_song_qmodel_index: QModelIndex self.current_song_filepath = "" @@ -395,15 +392,15 @@ class MusicTable(QTableView): id_index = self.model2.index(topLeft.row(), 0) # get the db song_id from the row song_id: int = self.model2.data(id_index, Qt.ItemDataRole.UserRole) - user_index = self.headers.user_fields.index("filepath") + user_index = self.headers.db_list.index("filepath") filepath = self.currentIndex().siblingAtColumn(user_index).data() # update the ID3 information user_input_data: str = topLeft.data() - edited_column_name: str = self.headers.user_fields[topLeft.column()] + edited_column_name: str = self.headers.db_list[topLeft.column()] debug(f"on_cell_data_changed | edited column name: {edited_column_name}") response = set_tag( filepath=filepath, - tag_name=edited_column_name, + db_column=edited_column_name, value=user_input_data ) if response: @@ -695,9 +692,9 @@ class MusicTable(QTableView): self.disconnect_layout_changed() self.save_scroll_position(self.current_playlist_id) self.model2.clear() - self.model2.setHorizontalHeaderLabels( - self.headers.get_user_gui_headers()) - fields = ", ".join(self.headers.user_fields) + # self.model2.setHorizontalHeaderLabels(self.headers.get_user_gui_headers()) + self.model2.setHorizontalHeaderLabels(self.headers.db_list) + fields = ", ".join(self.headers.db_list) search_clause = ( "title LIKE ? OR artist LIKE ? OR album LIKE ?" if self.search_string @@ -792,7 +789,7 @@ class MusicTable(QTableView): When data changes in the model view, its nice to re-grab the current song. might as well get the selected song too i guess? though nothing should be selected when reloading the table data """ - search_col_num = self.headers.user_fields.index("filepath") + search_col_num = self.headers.db_list.index("filepath") selected_qmodel_index = self.find_qmodel_index_by_value(self.proxymodel, search_col_num, self.selected_song_filepath) current_qmodel_index = self.find_qmodel_index_by_value(self.proxymodel, search_col_num, self.current_song_filepath) # Update the 2 QModelIndexes that we track @@ -913,7 +910,7 @@ class MusicTable(QTableView): selected_rows = self.get_selected_rows() filepaths = [] for row in selected_rows: - idx = self.proxymodel.index(row, self.headers.user_fields.index("filepath")) + idx = self.proxymodel.index(row, self.headers.db_list.index("filepath")) filepaths.append(idx.data()) return filepaths @@ -947,7 +944,7 @@ class MusicTable(QTableView): def set_selected_song_filepath(self) -> None: """Sets the filepath of the currently selected song""" try: - user_index = self.headers.user_fields.index("filepath") + user_index = self.headers.db_list.index("filepath") filepath = self.currentIndex().siblingAtColumn(user_index).data() except ValueError: # if the user doesnt have filepath selected as a header, retrieve the file from db @@ -965,7 +962,7 @@ class MusicTable(QTableView): # update the filepath if not filepath: path = self.current_song_qmodel_index.siblingAtColumn( - self.headers.user_fields.index("filepath") + self.headers.db_list.index("filepath") ).data() self.current_song_filepath: str = path else: diff --git a/main.py b/main.py index 967f6a2..2fae17c 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,10 @@ import os import sys import logging -from PyQt5 import QtCore import typing import DBA +import qdarktheme +from PyQt5 import QtCore from subprocess import run # from pyqtgraph import mkBrush from mutagen.id3 import ID3 @@ -50,13 +51,13 @@ from utils import ( Worker ) from components import ( - HeaderTags, MediaPlayer, MusicTable, PreferencesWindow, AudioVisualizer, CreatePlaylistWindow, ExportPlaylistWindow, + HeaderTags2, ) from utils.export_playlist_by_id import export_playlist_by_id @@ -129,7 +130,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.tableView.load_qapp(self) self.albumGraphicsView.load_qapp(self) self.playlistTreeView.load_qapp(self) - self.headers = HeaderTags() + self.headers = HeaderTags2() # Settings init self.current_volume: int = int(self.config["settings"]["volume"]) @@ -322,12 +323,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): return row: int = index.row() prev_row: int = row - 1 - prev_index: QModelIndex = self.tableView.proxymodel.index( - prev_row, index.column() - ) - prev_filepath = prev_index.siblingAtColumn( - self.headers.user_fields.index("filepath") - ).data() + prev_index: QModelIndex = self.tableView.proxymodel.index(prev_row, index.column()) + prev_filepath = prev_index.siblingAtColumn(self.headers.db_list.index("filepath")).data() if prev_filepath is None: return @@ -350,7 +347,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): next_row, index.column() ) next_filepath = next_index.siblingAtColumn( - self.headers.user_fields.index("filepath") + self.headers.db_list.index("filepath") ).data() if next_filepath is None: return @@ -735,7 +732,7 @@ if __name__ == "__main__": app = QApplication(sys.argv) clipboard = app.clipboard() # Dark theme >:3 - # qdarktheme.setup_theme() + qdarktheme.setup_theme() # qdarktheme.setup_theme("auto") # this is supposed to work but doesnt # Show the UI ui = ApplicationWindow(clipboard)