new header implementation working

This commit is contained in:
billy 2025-10-03 19:23:40 -04:00
parent 84f8563671
commit f1d018f7ce
4 changed files with 41 additions and 37 deletions

View File

@ -102,6 +102,7 @@ class ID3Field:
gui: str # e.g., "Title" gui: str # e.g., "Title"
frame_class: Optional[type] = None # e.g., TPE1 frame_class: Optional[type] = None # e.g., TPE1
frame_id: Optional[str] = None # e.g., "TPE1" frame_id: Optional[str] = None # e.g., "TPE1"
editable: bool = True
class HeaderTags2: class HeaderTags2:
@ -113,11 +114,11 @@ class HeaderTags2:
ID3Field(frame_class=TPE2, frame_id="TPE2", db="album_artist", gui="Album Artist"), 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=TRCK, frame_id="TRCK", db="track_number", gui="Track"),
ID3Field(frame_class=TCON, frame_id="TCON", db="genre", gui="Genre"), 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(frame_class=TDRC, frame_id="TDRC", db="album_date", gui="Year"),
ID3Field(db="codec", gui="Codec"), ID3Field(frame_class=TLEN, frame_id="TLEN", db="length_ms", gui="Time", editable=False),
ID3Field(db="filepath", gui="Filepath"), ID3Field(db="codec", gui="Codec", editable=False),
ID3Field(db="bitrate", gui="Bitrate"), ID3Field(db="filepath", gui="Filepath", editable=False),
ID3Field(db="bitrate", gui="Bitrate", editable=False),
] ]
# Lookup dicts # Lookup dicts
# - Usage example: frame_id['TPE1'].db # => "artist" # - Usage example: frame_id['TPE1'].db # => "artist"
@ -125,6 +126,15 @@ class HeaderTags2:
self.db = {f.db: f for f in self.headers} self.db = {f.db: f for f in self.headers}
self.gui = {f.gui: 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: class HeaderTags:
""" """

View File

@ -11,7 +11,6 @@ from PyQt5.QtWidgets import (
from PyQt5.QtGui import QFont from PyQt5.QtGui import QFont
from components.ErrorDialog import ErrorDialog from components.ErrorDialog import ErrorDialog
from utils import set_tag, get_tags, update_song_in_database from utils import set_tag, get_tags, update_song_in_database
from logging import debug
# import re # import re
@ -71,9 +70,10 @@ class MetadataWindow(QDialog):
QMessageBox.Ok, QMessageBox.Ok,
) )
return return
for key, tag in self.headers.id3.items(): for key in self.headers.db_list:
if key not in self.headers.editable_fields: if key not in self.headers.get_editable_db_list():
continue continue
tag = self.headers.db[key].frame_id
if tag is not None: if tag is not None:
try: try:
_ = tag_sets[tag] _ = tag_sets[tag]
@ -98,7 +98,7 @@ class MetadataWindow(QDialog):
# If the ID3 tag is the same for every item we're editing # If the ID3 tag is the same for every item we're editing
field_text = str(value[0]) if value else "" field_text = str(value[0]) if value else ""
# Normal field # 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 = ID3LineEdit(field_text, tag)
input_field.setStyleSheet(None) input_field.setStyleSheet(None)
else: else:
@ -106,7 +106,7 @@ class MetadataWindow(QDialog):
# this means the metadata differs between the selected items for this tag # this means the metadata differs between the selected items for this tag
# so be careful...dangerous # so be careful...dangerous
field_text = "" 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 = ID3LineEdit(field_text, tag)
input_field.setStyleSheet("border: 1px solid red") input_field.setStyleSheet("border: 1px solid red")
# Save each input field to our dict for saving # 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, # Update the ID3 tag if the tag is not blank,
# and has been edited # and has been edited
success = set_tag( success = set_tag(
filepath=song[0], tag_name=tag, value=field.text() filepath=song[0], db_column=tag, value=field.text()
) )
if success: if success:
update_song_in_database( update_song_in_database(
song[1], song[1],
edited_column_name=self.headers.id3_keys[tag], edited_column_name=self.headers.frame_id[tag].db,
user_input_data=field.text(), user_input_data=field.text(),
) )
else: else:

View File

@ -33,7 +33,7 @@ from components.LyricsWindow import LyricsWindow
from components.AddToPlaylistWindow import AddToPlaylistWindow from components.AddToPlaylistWindow import AddToPlaylistWindow
from components.MetadataWindow import MetadataWindow from components.MetadataWindow import MetadataWindow
from components.QuestionBoxDetails import QuestionBoxDetails from components.QuestionBoxDetails import QuestionBoxDetails
from components.HeaderTags import HeaderTags from components.HeaderTags import HeaderTags2
from utils import ( from utils import (
batch_delete_filepaths_from_database, batch_delete_filepaths_from_database,
@ -99,10 +99,7 @@ class MusicTable(QTableView):
self.data_cache = {} self.data_cache = {}
self.playlist_scroll_positions: dict[int | None, int] = {} self.playlist_scroll_positions: dict[int | None, int] = {}
self.search_string: str | None = None self.search_string: str | None = None
self.headers = HeaderTags() self.headers = HeaderTags2()
# db names of headers
self.database_columns: list[str] = str(
self.config["table"]["columns"]).split(",")
self.selected_song_filepath = "" self.selected_song_filepath = ""
self.selected_song_qmodel_index: QModelIndex self.selected_song_qmodel_index: QModelIndex
self.current_song_filepath = "" self.current_song_filepath = ""
@ -395,15 +392,15 @@ class MusicTable(QTableView):
id_index = self.model2.index(topLeft.row(), 0) id_index = self.model2.index(topLeft.row(), 0)
# get the db song_id from the row # get the db song_id from the row
song_id: int = self.model2.data(id_index, Qt.ItemDataRole.UserRole) 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() filepath = self.currentIndex().siblingAtColumn(user_index).data()
# update the ID3 information # update the ID3 information
user_input_data: str = topLeft.data() 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}") debug(f"on_cell_data_changed | edited column name: {edited_column_name}")
response = set_tag( response = set_tag(
filepath=filepath, filepath=filepath,
tag_name=edited_column_name, db_column=edited_column_name,
value=user_input_data value=user_input_data
) )
if response: if response:
@ -695,9 +692,9 @@ class MusicTable(QTableView):
self.disconnect_layout_changed() self.disconnect_layout_changed()
self.save_scroll_position(self.current_playlist_id) self.save_scroll_position(self.current_playlist_id)
self.model2.clear() self.model2.clear()
self.model2.setHorizontalHeaderLabels( # self.model2.setHorizontalHeaderLabels(self.headers.get_user_gui_headers())
self.headers.get_user_gui_headers()) self.model2.setHorizontalHeaderLabels(self.headers.db_list)
fields = ", ".join(self.headers.user_fields) fields = ", ".join(self.headers.db_list)
search_clause = ( search_clause = (
"title LIKE ? OR artist LIKE ? OR album LIKE ?" "title LIKE ? OR artist LIKE ? OR album LIKE ?"
if self.search_string 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. 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 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) 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) 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 # Update the 2 QModelIndexes that we track
@ -913,7 +910,7 @@ class MusicTable(QTableView):
selected_rows = self.get_selected_rows() selected_rows = self.get_selected_rows()
filepaths = [] filepaths = []
for row in selected_rows: 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()) filepaths.append(idx.data())
return filepaths return filepaths
@ -947,7 +944,7 @@ class MusicTable(QTableView):
def set_selected_song_filepath(self) -> None: def set_selected_song_filepath(self) -> None:
"""Sets the filepath of the currently selected song""" """Sets the filepath of the currently selected song"""
try: try:
user_index = self.headers.user_fields.index("filepath") user_index = self.headers.db_list.index("filepath")
filepath = self.currentIndex().siblingAtColumn(user_index).data() filepath = self.currentIndex().siblingAtColumn(user_index).data()
except ValueError: except ValueError:
# if the user doesnt have filepath selected as a header, retrieve the file from db # 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 # update the filepath
if not filepath: if not filepath:
path = self.current_song_qmodel_index.siblingAtColumn( path = self.current_song_qmodel_index.siblingAtColumn(
self.headers.user_fields.index("filepath") self.headers.db_list.index("filepath")
).data() ).data()
self.current_song_filepath: str = path self.current_song_filepath: str = path
else: else:

19
main.py
View File

@ -1,9 +1,10 @@
import os import os
import sys import sys
import logging import logging
from PyQt5 import QtCore
import typing import typing
import DBA import DBA
import qdarktheme
from PyQt5 import QtCore
from subprocess import run from subprocess import run
# from pyqtgraph import mkBrush # from pyqtgraph import mkBrush
from mutagen.id3 import ID3 from mutagen.id3 import ID3
@ -50,13 +51,13 @@ from utils import (
Worker Worker
) )
from components import ( from components import (
HeaderTags,
MediaPlayer, MediaPlayer,
MusicTable, MusicTable,
PreferencesWindow, PreferencesWindow,
AudioVisualizer, AudioVisualizer,
CreatePlaylistWindow, CreatePlaylistWindow,
ExportPlaylistWindow, ExportPlaylistWindow,
HeaderTags2,
) )
from utils.export_playlist_by_id import export_playlist_by_id 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.tableView.load_qapp(self)
self.albumGraphicsView.load_qapp(self) self.albumGraphicsView.load_qapp(self)
self.playlistTreeView.load_qapp(self) self.playlistTreeView.load_qapp(self)
self.headers = HeaderTags() self.headers = HeaderTags2()
# Settings init # Settings init
self.current_volume: int = int(self.config["settings"]["volume"]) self.current_volume: int = int(self.config["settings"]["volume"])
@ -322,12 +323,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
return return
row: int = index.row() row: int = index.row()
prev_row: int = row - 1 prev_row: int = row - 1
prev_index: QModelIndex = self.tableView.proxymodel.index( prev_index: QModelIndex = self.tableView.proxymodel.index(prev_row, index.column())
prev_row, index.column() prev_filepath = prev_index.siblingAtColumn(self.headers.db_list.index("filepath")).data()
)
prev_filepath = prev_index.siblingAtColumn(
self.headers.user_fields.index("filepath")
).data()
if prev_filepath is None: if prev_filepath is None:
return return
@ -350,7 +347,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
next_row, index.column() next_row, index.column()
) )
next_filepath = next_index.siblingAtColumn( next_filepath = next_index.siblingAtColumn(
self.headers.user_fields.index("filepath") self.headers.db_list.index("filepath")
).data() ).data()
if next_filepath is None: if next_filepath is None:
return return
@ -735,7 +732,7 @@ if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)
clipboard = app.clipboard() clipboard = app.clipboard()
# Dark theme >:3 # Dark theme >:3
# qdarktheme.setup_theme() qdarktheme.setup_theme()
# qdarktheme.setup_theme("auto") # this is supposed to work but doesnt # qdarktheme.setup_theme("auto") # this is supposed to work but doesnt
# Show the UI # Show the UI
ui = ApplicationWindow(clipboard) ui = ApplicationWindow(clipboard)