MetadataWindow update to DB and id3 tags complete
This commit is contained in:
parent
3f8d632de8
commit
63c54f9de7
@ -8,13 +8,19 @@ from PyQt5.QtWidgets import (
|
||||
QPushButton,
|
||||
)
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from mutagen.id3 import ID3
|
||||
from components.ErrorDialog import ErrorDialog
|
||||
from utils.get_id3_tags import get_id3_tags
|
||||
from utils.set_id3_tag import set_id3_tag
|
||||
from utils.update_song_in_database import update_song_in_database
|
||||
from utils.id3_tag_mapping import id3_tag_mapping
|
||||
|
||||
|
||||
class MetadataWindow(QDialog):
|
||||
def __init__(self, songs: list):
|
||||
refreshMusicTableSignal = pyqtSignal()
|
||||
|
||||
def __init__(self, refreshMusicTableSignal, songs: list, ids: list):
|
||||
"""
|
||||
Window that allows batch editing of metadata for multiple files
|
||||
|
||||
@ -22,17 +28,9 @@ class MetadataWindow(QDialog):
|
||||
- list of strings, absolute paths to mp3 files
|
||||
"""
|
||||
super(MetadataWindow, self).__init__()
|
||||
self.songs = songs
|
||||
self.id3_tag_mapping = {
|
||||
"TIT2": "title",
|
||||
"TPE1": "artist",
|
||||
"TALB": "album",
|
||||
"TPE2": "album_artist",
|
||||
"TCON": "genre",
|
||||
"TRCK": "track_number",
|
||||
"APIC": "album_cover",
|
||||
"TCOP": "copyright",
|
||||
}
|
||||
self.refreshMusicTableSignal = refreshMusicTableSignal
|
||||
self.songs = list(zip(songs, ids))
|
||||
self.id3_tag_mapping = id3_tag_mapping
|
||||
# Keep a dictionary of the input fields for save function
|
||||
self.input_fields = {}
|
||||
self.setWindowTitle("Edit metadata")
|
||||
@ -52,7 +50,7 @@ class MetadataWindow(QDialog):
|
||||
# Get a dict of all tags for all songs
|
||||
# e.g., { "TIT2": ["song_title1", "song_title2"], ... }
|
||||
for song in self.songs:
|
||||
song_data = get_id3_tags(song)
|
||||
song_data = get_id3_tags(song[0])
|
||||
for tag in self.id3_tag_mapping:
|
||||
try:
|
||||
_ = tag_sets[tag]
|
||||
@ -107,5 +105,22 @@ class MetadataWindow(QDialog):
|
||||
"""Save changes made to metadata for each song in dict"""
|
||||
for song in self.songs:
|
||||
for tag, field in self.input_fields.items():
|
||||
set_id3_tag(filepath=song, tag_name=tag, value=field)
|
||||
if field.text() is not None and field.text() != "":
|
||||
# Update the ID3 tag if not blank
|
||||
success = set_id3_tag(
|
||||
filepath=song[0], tag_name=tag, value=field.text()
|
||||
)
|
||||
if success:
|
||||
update_song_in_database(
|
||||
song[1],
|
||||
edited_column_name=self.id3_tag_mapping[tag],
|
||||
user_input_data=field.text(),
|
||||
)
|
||||
else:
|
||||
error_dialog = ErrorDialog(
|
||||
f"Could not update metadata for {song}. Exiting early"
|
||||
)
|
||||
error_dialog.exec()
|
||||
self.close()
|
||||
self.refreshMusicTableSignal.emit()
|
||||
self.close()
|
||||
|
||||
@ -23,7 +23,7 @@ from components.AddToPlaylistWindow import AddToPlaylistWindow
|
||||
from components.MetadataWindow import MetadataWindow
|
||||
from utils.delete_song_id_from_database import delete_song_id_from_database
|
||||
from utils.add_files_to_library import add_files_to_library
|
||||
from utils.update_song_in_library import update_song_in_library
|
||||
from utils.update_song_in_database import update_song_in_database
|
||||
from utils.get_id3_tags import get_id3_tags
|
||||
from utils.get_album_art import get_album_art
|
||||
from utils import set_id3_tag
|
||||
@ -38,12 +38,15 @@ class MusicTable(QTableView):
|
||||
playPauseSignal = pyqtSignal()
|
||||
enterKey = pyqtSignal()
|
||||
deleteKey = pyqtSignal()
|
||||
refreshMusicTable = pyqtSignal()
|
||||
|
||||
def __init__(self: QTableView, parent=None):
|
||||
# QTableView.__init__(self, parent)
|
||||
super().__init__(parent)
|
||||
# Necessary for actions related to cell values
|
||||
# FIXME: why do these give me pyright errors
|
||||
self.model = QStandardItemModel(self)
|
||||
# self.model = QAbstractItemModel(self)
|
||||
self.setModel(self.model)
|
||||
|
||||
# Config
|
||||
@ -165,7 +168,9 @@ class MusicTable(QTableView):
|
||||
# FIXME:
|
||||
"""Opens a form with metadata from the selected audio files"""
|
||||
files = self.get_selected_songs_filepaths()
|
||||
window = MetadataWindow(files)
|
||||
song_ids = self.get_selected_songs_db_ids()
|
||||
window = MetadataWindow(self.refreshMusicTable, files, song_ids)
|
||||
window.refreshMusicTableSignal.connect(self.load_music_table)
|
||||
window.exec_() # Display the preferences window modally
|
||||
|
||||
def add_selected_files_to_playlist(self):
|
||||
@ -231,9 +236,11 @@ class MusicTable(QTableView):
|
||||
else:
|
||||
e.ignore()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
def keyPressEvent(self, e):
|
||||
"""Press a key. Do a thing"""
|
||||
key = event.key()
|
||||
if not e:
|
||||
return
|
||||
key = e.key()
|
||||
if key == Qt.Key_Space: # Spacebar to play/pause
|
||||
self.toggle_play_pause()
|
||||
elif key == Qt.Key_Up: # Arrow key navigation
|
||||
@ -254,9 +261,9 @@ class MusicTable(QTableView):
|
||||
if self.state() != QAbstractItemView.EditingState:
|
||||
self.enterKey.emit() # Enter key detected
|
||||
else:
|
||||
super().keyPressEvent(event)
|
||||
super().keyPressEvent(e)
|
||||
else: # Default behavior
|
||||
super().keyPressEvent(event)
|
||||
super().keyPressEvent(e)
|
||||
|
||||
def setup_keyboard_shortcuts(self):
|
||||
"""Setup shortcuts here"""
|
||||
@ -267,7 +274,7 @@ class MusicTable(QTableView):
|
||||
"""Handles updating ID3 tags when data changes in a cell"""
|
||||
print("on_cell_data_changed")
|
||||
id_index = self.model.index(topLeft.row(), 0) # ID is column 0, always
|
||||
library_id = self.model.data(id_index, Qt.UserRole)
|
||||
song_id = self.model.data(id_index, Qt.UserRole)
|
||||
# filepath is always the last column
|
||||
filepath_column_idx = self.model.columnCount() - 1
|
||||
filepath_index = self.model.index(topLeft.row(), filepath_column_idx)
|
||||
@ -280,7 +287,7 @@ class MusicTable(QTableView):
|
||||
response = set_id3_tag(filepath, edited_column_name, user_input_data)
|
||||
if response:
|
||||
# Update the library with new metadata
|
||||
update_song_in_library(library_id, edited_column_name, user_input_data)
|
||||
update_song_in_database(song_id, edited_column_name, user_input_data)
|
||||
|
||||
def reorganize_selected_files(self):
|
||||
"""Ctrl+Shift+R = Reorganize"""
|
||||
@ -411,6 +418,7 @@ class MusicTable(QTableView):
|
||||
self.model.layoutChanged.emit() # emits a signal that the view should be updated
|
||||
try:
|
||||
self.model.dataChanged.connect(self.on_cell_data_changed)
|
||||
self.restore_scroll_position()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
2
main.py
2
main.py
@ -440,7 +440,7 @@ if __name__ == "__main__":
|
||||
sys.path.append(project_root)
|
||||
# Start the app
|
||||
app = QApplication(sys.argv)
|
||||
print(f"main.py app: {app}")
|
||||
# print(f"main.py app: {app}")
|
||||
# Dark theme >:3
|
||||
qdarktheme.setup_theme()
|
||||
# Show the UI
|
||||
|
||||
@ -7,7 +7,7 @@ from .get_id3_tags import get_id3_tags
|
||||
from .set_id3_tag import set_id3_tag
|
||||
from .delete_song_id_from_database import delete_song_id_from_database
|
||||
from .delete_and_create_library_database import delete_and_create_library_database
|
||||
from .update_song_in_library import update_song_in_library
|
||||
from .update_song_in_database import update_song_in_database
|
||||
from .scan_for_music import scan_for_music
|
||||
from .add_files_to_library import add_files_to_library
|
||||
from .handle_year_and_date_id3_tag import handle_year_and_date_id3_tag
|
||||
|
||||
10
utils/id3_tag_mapping.py
Normal file
10
utils/id3_tag_mapping.py
Normal file
@ -0,0 +1,10 @@
|
||||
id3_tag_mapping = {
|
||||
"TIT2": "title",
|
||||
"TPE1": "artist",
|
||||
"TALB": "album",
|
||||
"TPE2": "album_artist",
|
||||
"TCON": "genre",
|
||||
"TRCK": "track_number",
|
||||
# "APIC": "album_cover",
|
||||
"TCOP": "copyright",
|
||||
}
|
||||
@ -40,7 +40,7 @@ from mutagen.id3._frames import (
|
||||
WPUB,
|
||||
)
|
||||
|
||||
id3_tag_mapping = {
|
||||
mutagen_id3_tag_mapping = {
|
||||
"title": TIT2, # Title/song name/content description
|
||||
"artist": TPE1, # Lead performer(s)/Soloist(s)
|
||||
"album": TALB, # Album/Movie/Show title
|
||||
@ -119,8 +119,8 @@ def set_id3_tag(filepath: str, tag_name: str, value: str):
|
||||
audio.save()
|
||||
return True
|
||||
# Other
|
||||
elif tag_name in id3_tag_mapping: # Tag accounted for
|
||||
tag_class = id3_tag_mapping[tag_name]
|
||||
elif tag_name in mutagen_id3_tag_mapping: # Tag accounted for
|
||||
tag_class = mutagen_id3_tag_mapping[tag_name]
|
||||
if issubclass(tag_class, Frame):
|
||||
frame = tag_class(encoding=3, text=[value])
|
||||
audio_file.add(frame) # Add the tag
|
||||
|
||||
@ -2,13 +2,13 @@ import DBA
|
||||
from components.ErrorDialog import ErrorDialog
|
||||
|
||||
|
||||
def update_song_in_library(
|
||||
library_id: int, edited_column_name: str, user_input_data: str
|
||||
def update_song_in_database(
|
||||
song_id: int, edited_column_name: str, user_input_data: str
|
||||
):
|
||||
"""Updates a field in the library database based on an ID
|
||||
"""Updates a field in the database based on an ID
|
||||
|
||||
Args:
|
||||
library_id: the database ID of the song
|
||||
song_id: the database ID of the song
|
||||
edited_column_name: the name of the database column
|
||||
user_input_data: the data to input
|
||||
|
||||
@ -19,11 +19,11 @@ def update_song_in_library(
|
||||
# yeah yeah this is bad... the column names are defined in the program by me so im ok with it because it works
|
||||
db.execute(
|
||||
f"UPDATE song SET {edited_column_name} = ? WHERE id = ?",
|
||||
(user_input_data, library_id),
|
||||
(user_input_data, song_id),
|
||||
)
|
||||
except Exception as e:
|
||||
dialog = ErrorDialog(
|
||||
f"Unable to update [{edited_column_name}] to [{user_input_data}]. ID: {library_id} | {e}"
|
||||
f"Unable to update [{edited_column_name}] to [{user_input_data}]. ID: {song_id} | {e}"
|
||||
)
|
||||
dialog.exec_()
|
||||
return False
|
||||
Loading…
x
Reference in New Issue
Block a user