new header implementation working
This commit is contained in:
parent
84f8563671
commit
f1d018f7ce
@ -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:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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
19
main.py
@ -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)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user