a
This commit is contained in:
parent
0f459d3216
commit
8bfc269f42
@ -7,7 +7,7 @@ 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_id3_tag
|
from utils import set_tag
|
||||||
from logging import debug
|
from logging import debug
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ class LyricsWindow(QDialog):
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Saves the current lyrics text to the USLT/lyrics ID3 tag"""
|
"""Saves the current lyrics text to the USLT/lyrics ID3 tag"""
|
||||||
success = set_id3_tag(
|
success = set_tag(
|
||||||
filepath=self.song_filepath,
|
filepath=self.song_filepath,
|
||||||
tag_name="lyrics",
|
tag_name="lyrics",
|
||||||
value=self.input_field.toPlainText(),
|
value=self.input_field.toPlainText(),
|
||||||
|
|||||||
@ -12,10 +12,7 @@ from PyQt5.QtGui import QFont
|
|||||||
from PyQt5.QtCore import pyqtSignal
|
from PyQt5.QtCore import pyqtSignal
|
||||||
from mutagen.id3 import ID3
|
from mutagen.id3 import ID3
|
||||||
from components.ErrorDialog import ErrorDialog
|
from components.ErrorDialog import ErrorDialog
|
||||||
from utils.get_id3_tags import get_id3_tags
|
from utils import set_tag, get_tag, update_song_in_database, id3_tag_mapping
|
||||||
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
|
|
||||||
from logging import debug
|
from logging import debug
|
||||||
# import re
|
# import re
|
||||||
|
|
||||||
@ -65,7 +62,7 @@ class MetadataWindow(QDialog):
|
|||||||
# Get a dict of all tags for all songs
|
# Get a dict of all tags for all songs
|
||||||
# e.g., { "TIT2": ["song_title1", "song_title2"], ... }
|
# e.g., { "TIT2": ["song_title1", "song_title2"], ... }
|
||||||
for song in self.songs:
|
for song in self.songs:
|
||||||
song_data = get_id3_tags(song[0])
|
song_data = get_tags(song[0])
|
||||||
if not song_data:
|
if not song_data:
|
||||||
QMessageBox.error(
|
QMessageBox.error(
|
||||||
self,
|
self,
|
||||||
@ -135,7 +132,7 @@ class MetadataWindow(QDialog):
|
|||||||
if field.has_changed():
|
if field.has_changed():
|
||||||
# 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_id3_tag(
|
success = set_tag(
|
||||||
filepath=song[0], tag_name=tag, value=field.text()
|
filepath=song[0], tag_name=tag, value=field.text()
|
||||||
)
|
)
|
||||||
if success:
|
if success:
|
||||||
|
|||||||
@ -42,16 +42,17 @@ from components.MetadataWindow import MetadataWindow
|
|||||||
from components.QuestionBoxDetails import QuestionBoxDetails
|
from components.QuestionBoxDetails import QuestionBoxDetails
|
||||||
|
|
||||||
from main import Worker
|
from main import Worker
|
||||||
from utils.batch_delete_filepaths_from_database import (
|
from utils import (
|
||||||
batch_delete_filepaths_from_database,
|
batch_delete_filepaths_from_database,
|
||||||
|
delete_song_id_from_database,
|
||||||
|
add_files_to_database,
|
||||||
|
get_reorganize_vars,
|
||||||
|
update_song_in_database,
|
||||||
|
get_album_art,
|
||||||
|
id3_remap,
|
||||||
|
get_tags,
|
||||||
|
set_tag
|
||||||
)
|
)
|
||||||
from utils.delete_song_id_from_database import delete_song_id_from_database
|
|
||||||
from utils.add_files_to_database import add_files_to_database
|
|
||||||
from utils.get_reorganize_vars import get_reorganize_vars
|
|
||||||
from utils.update_song_in_database import update_song_in_database
|
|
||||||
from utils.get_id3_tags import get_id3_tags, id3_remap
|
|
||||||
from utils.get_album_art import get_album_art
|
|
||||||
from utils import set_id3_tag
|
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from logging import debug, error
|
from logging import debug, error
|
||||||
import os
|
import os
|
||||||
@ -91,7 +92,7 @@ class TableHeader:
|
|||||||
"artist": "TPE1",
|
"artist": "TPE1",
|
||||||
"album": "TALB",
|
"album": "TALB",
|
||||||
"track_number": "TRCK",
|
"track_number": "TRCK",
|
||||||
"genre": "content_type",
|
"genre": "TCON",
|
||||||
"codec": None,
|
"codec": None,
|
||||||
"length_seconds": "TLEN",
|
"length_seconds": "TLEN",
|
||||||
"album_date": "TDRC",
|
"album_date": "TDRC",
|
||||||
@ -440,7 +441,7 @@ class MusicTable(QTableView):
|
|||||||
user_input_data = topLeft.data()
|
user_input_data = topLeft.data()
|
||||||
edited_column_name = self.database_columns[topLeft.column()]
|
edited_column_name = self.database_columns[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_id3_tag(filepath, edited_column_name, user_input_data)
|
response = set_tag(filepath, edited_column_name, user_input_data)
|
||||||
if response:
|
if response:
|
||||||
# Update the library with new metadata
|
# Update the library with new metadata
|
||||||
update_song_in_database(song_id, edited_column_name, user_input_data)
|
update_song_in_database(song_id, edited_column_name, user_input_data)
|
||||||
@ -600,7 +601,7 @@ class MusicTable(QTableView):
|
|||||||
selected_song_filepath = self.get_selected_song_filepath()
|
selected_song_filepath = self.get_selected_song_filepath()
|
||||||
if selected_song_filepath is None:
|
if selected_song_filepath is None:
|
||||||
return
|
return
|
||||||
dic = id3_remap(get_id3_tags(selected_song_filepath)[0])
|
dic = id3_remap(get_tags(selected_song_filepath)[0])
|
||||||
lyrics = dic["lyrics"]
|
lyrics = dic["lyrics"]
|
||||||
lyrics_window = LyricsWindow(selected_song_filepath, lyrics)
|
lyrics_window = LyricsWindow(selected_song_filepath, lyrics)
|
||||||
lyrics_window.exec_()
|
lyrics_window.exec_()
|
||||||
@ -860,11 +861,11 @@ class MusicTable(QTableView):
|
|||||||
|
|
||||||
def get_current_song_metadata(self) -> dict:
|
def get_current_song_metadata(self) -> dict:
|
||||||
"""Returns the currently playing song's ID3 tags"""
|
"""Returns the currently playing song's ID3 tags"""
|
||||||
return id3_remap(get_id3_tags(self.current_song_filepath)[0])
|
return id3_remap(get_tags(self.current_song_filepath)[0])
|
||||||
|
|
||||||
def get_selected_song_metadata(self) -> dict:
|
def get_selected_song_metadata(self) -> dict:
|
||||||
"""Returns the selected song's ID3 tags"""
|
"""Returns the selected song's ID3 tags"""
|
||||||
return id3_remap(get_id3_tags(self.selected_song_filepath)[0])
|
return id3_remap(get_tags(self.selected_song_filepath)[0])
|
||||||
|
|
||||||
def get_current_song_album_art(self) -> bytes:
|
def get_current_song_album_art(self) -> bytes:
|
||||||
"""Returns the APIC data (album art lol) for the currently playing song"""
|
"""Returns the APIC data (album art lol) for the currently playing song"""
|
||||||
|
|||||||
4
main.py
4
main.py
@ -41,7 +41,7 @@ from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QAudioProbe, QMediaP
|
|||||||
from PyQt5.QtGui import QClipboard, QCloseEvent, QFont, QPixmap, QResizeEvent
|
from PyQt5.QtGui import QClipboard, QCloseEvent, QFont, QPixmap, QResizeEvent
|
||||||
from utils import (
|
from utils import (
|
||||||
delete_album_art,
|
delete_album_art,
|
||||||
get_id3_tags,
|
get_tags,
|
||||||
scan_for_music,
|
scan_for_music,
|
||||||
initialize_db,
|
initialize_db,
|
||||||
add_files_to_database,
|
add_files_to_database,
|
||||||
@ -430,7 +430,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
if not filepath:
|
if not filepath:
|
||||||
filepath = self.tableView.get_current_song_filepath()
|
filepath = self.tableView.get_current_song_filepath()
|
||||||
# get metadata
|
# get metadata
|
||||||
metadata = get_id3_tags(filepath)[0]
|
metadata = get_tags(filepath)[0]
|
||||||
# read the file
|
# read the file
|
||||||
url = QUrl.fromLocalFile(filepath)
|
url = QUrl.fromLocalFile(filepath)
|
||||||
# load the audio content
|
# load the audio content
|
||||||
|
|||||||
@ -3,9 +3,9 @@ from .convert_id3_timestamp_to_datetime import convert_id3_timestamp_to_datetime
|
|||||||
from .initialize_db import initialize_db
|
from .initialize_db import initialize_db
|
||||||
from .safe_get import safe_get
|
from .safe_get import safe_get
|
||||||
from .get_album_art import get_album_art
|
from .get_album_art import get_album_art
|
||||||
from .get_id3_tags import get_id3_tags, id3_remap
|
from .get_tags import get_tags, id3_remap
|
||||||
from .get_reorganize_vars import get_reorganize_vars
|
from .get_reorganize_vars import get_reorganize_vars
|
||||||
from .set_id3_tag import set_id3_tag
|
from .set_tag import set_tag
|
||||||
from .delete_song_id_from_database import delete_song_id_from_database
|
from .delete_song_id_from_database import delete_song_id_from_database
|
||||||
from .batch_delete_filepaths_from_database import batch_delete_filepaths_from_database
|
from .batch_delete_filepaths_from_database import batch_delete_filepaths_from_database
|
||||||
from .delete_and_create_library_database import delete_and_create_library_database
|
from .delete_and_create_library_database import delete_and_create_library_database
|
||||||
|
|||||||
@ -2,7 +2,7 @@ from PyQt5.QtWidgets import QMessageBox
|
|||||||
from mutagen.id3 import ID3
|
from mutagen.id3 import ID3
|
||||||
import DBA
|
import DBA
|
||||||
from logging import debug
|
from logging import debug
|
||||||
from utils import get_id3_tags, convert_id3_timestamp_to_datetime, id3_remap
|
from utils import get_tags, convert_id3_timestamp_to_datetime, id3_remap
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from appdirs import user_config_dir
|
from appdirs import user_config_dir
|
||||||
@ -37,7 +37,7 @@ def add_files_to_database(files, progress_callback=None):
|
|||||||
progress_callback.emit(filepath)
|
progress_callback.emit(filepath)
|
||||||
filename = filepath.split("/")[-1]
|
filename = filepath.split("/")[-1]
|
||||||
|
|
||||||
tags, details = get_id3_tags(filepath)
|
tags, details = get_tags(filepath)
|
||||||
if details:
|
if details:
|
||||||
failed_dict[filepath] = details
|
failed_dict[filepath] = details
|
||||||
continue
|
continue
|
||||||
@ -55,6 +55,7 @@ def add_files_to_database(files, progress_callback=None):
|
|||||||
filename.split(".")[-1],
|
filename.split(".")[-1],
|
||||||
audio["date"],
|
audio["date"],
|
||||||
audio["bitrate"],
|
audio["bitrate"],
|
||||||
|
audio["length"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Check if batch size is reached
|
# Check if batch size is reached
|
||||||
@ -62,7 +63,7 @@ def add_files_to_database(files, progress_callback=None):
|
|||||||
debug(f"inserting a LOT of songs: {len(insert_data)}")
|
debug(f"inserting a LOT of songs: {len(insert_data)}")
|
||||||
with DBA.DBAccess() as db:
|
with DBA.DBAccess() as db:
|
||||||
db.executemany(
|
db.executemany(
|
||||||
"INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
"INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate, length_seconds) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
insert_data,
|
insert_data,
|
||||||
)
|
)
|
||||||
insert_data = [] # Reset the insert_data list
|
insert_data = [] # Reset the insert_data list
|
||||||
@ -75,20 +76,9 @@ def add_files_to_database(files, progress_callback=None):
|
|||||||
debug(f"inserting some songs: {len(insert_data)}")
|
debug(f"inserting some songs: {len(insert_data)}")
|
||||||
with DBA.DBAccess() as db:
|
with DBA.DBAccess() as db:
|
||||||
db.executemany(
|
db.executemany(
|
||||||
"INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
"INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate, length_seconds) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
insert_data,
|
insert_data,
|
||||||
)
|
)
|
||||||
return True, failed_dict
|
return True, failed_dict
|
||||||
|
|
||||||
|
|
||||||
# id int unsigned auto_increment,
|
|
||||||
# title varchar(255),
|
|
||||||
# album varchar(255),
|
|
||||||
# artist varchar(255),
|
|
||||||
# genre varchar(255),
|
|
||||||
# codec varchar(15),
|
|
||||||
# album_date date,
|
|
||||||
# bitrate int unsigned,
|
|
||||||
# date_added TIMESTAMP default CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
# scan_for_music(config.get('directories', 'library1'))
|
|
||||||
|
|||||||
@ -9,6 +9,8 @@ def get_reorganize_vars(filepath: str) -> tuple[str, str]:
|
|||||||
if no artist or album or ID3 tags at all are found,
|
if no artist or album or ID3 tags at all are found,
|
||||||
function will return ("Unknown Artist", "Unknown Album")
|
function will return ("Unknown Artist", "Unknown Album")
|
||||||
"""
|
"""
|
||||||
|
# TODO: fix this func. id3_remap(get_tags())
|
||||||
|
# or is what i have less memory so more better? :shrug:
|
||||||
audio = ID3(filepath)
|
audio = ID3(filepath)
|
||||||
try:
|
try:
|
||||||
artist = str(audio["TPE1"].text[0])
|
artist = str(audio["TPE1"].text[0])
|
||||||
|
|||||||
@ -36,7 +36,7 @@ def get_mp3_tags(filename: str) -> tuple[MP3 | ID3 | FLAC, str]:
|
|||||||
|
|
||||||
def id3_remap(audio: MP3 | ID3 | FLAC) -> dict:
|
def id3_remap(audio: MP3 | ID3 | FLAC) -> dict:
|
||||||
"""
|
"""
|
||||||
Turns an ID3 dict into a normal dict that I, the human, can use.
|
Turns the ID3 dict of an audio file into a normal dict that I, the human, can use.
|
||||||
Add extra fields too :D yahooo
|
Add extra fields too :D yahooo
|
||||||
"""
|
"""
|
||||||
remap = {}
|
remap = {}
|
||||||
@ -59,9 +59,9 @@ def id3_remap(audio: MP3 | ID3 | FLAC) -> dict:
|
|||||||
return remap
|
return remap
|
||||||
|
|
||||||
|
|
||||||
def get_id3_tags(filename: str) -> tuple[MP3 | ID3 | FLAC, str]:
|
def get_tags(filename: str) -> tuple[MP3 | ID3 | FLAC, str]:
|
||||||
"""
|
"""
|
||||||
Get the ID3 tags for an audio file
|
Get the "ID3" tags for an audio file
|
||||||
Returns a tuple of:
|
Returns a tuple of:
|
||||||
- mutagen ID3 object OR python dictionary
|
- mutagen ID3 object OR python dictionary
|
||||||
- string reason for failure (failure = empty dict above)
|
- string reason for failure (failure = empty dict above)
|
||||||
@ -82,7 +82,7 @@ mutagen_id3_tag_mapping = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def set_id3_tag(filepath: str, tag_name: str, value: str):
|
def set_tag(filepath: str, tag_name: str, value: str):
|
||||||
"""Sets the ID3 tag for a file given a filepath, tag_name, and a value for the tag
|
"""Sets the ID3 tag for a file given a filepath, tag_name, and a value for the tag
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -136,6 +136,6 @@ def set_id3_tag(filepath: str, tag_name: str, value: str):
|
|||||||
audio_file.save(filepath)
|
audio_file.save(filepath)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
dialog = ErrorDialog(f"set_id3_tag.py | An unhandled exception occurred:\n{e}")
|
dialog = ErrorDialog(f"set_tag.py | An unhandled exception occurred:\n{e}")
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
return False
|
return False
|
||||||
Loading…
x
Reference in New Issue
Block a user