diff --git a/components/MusicTable.py b/components/MusicTable.py index 60c0c90..3a43d02 100644 --- a/components/MusicTable.py +++ b/components/MusicTable.py @@ -1,4 +1,4 @@ -from mutagen.easyid3 import EasyID3 +from mutagen.id3 import ID3 import DBA from PyQt5.QtGui import ( QDragMoveEvent, @@ -141,12 +141,9 @@ class MusicTable(QTableView): current_song = self.get_selected_song_metadata() print(f"MusicTable.py | show_lyrics_menu | current song: {current_song}") try: - lyrics = current_song["lyrics"] - except Exception: - pass - try: - lyrics = current_song["USLT"] - except Exception: + lyrics = current_song["USLT::XXX"].text + except Exception as e: + print(f'MusicTable.py | show_lyrics_menu | could not retrieve lyrics | {e}') lyrics = "" lyrics_window = LyricsWindow(selected_song_filepath, lyrics) lyrics_window.exec_() @@ -224,9 +221,9 @@ class MusicTable(QTableView): for filepath in filepaths: try: # Read file metadata - audio = EasyID3(filepath) - artist = audio.get("artist", ["Unknown Artist"])[0] - album = audio.get("album", ["Unknown Album"])[0] + audio = ID3(filepath) + artist = audio["TIT2"].text[0] if not '' or None else 'Unknown Artist' + album = audio["TALB"].text[0] if not '' or None else 'Unknown Album' # Determine the new path that needs to be made new_path = os.path.join( target_dir, artist, album, os.path.basename(filepath) @@ -351,7 +348,7 @@ class MusicTable(QTableView): """Returns the selected songs filepath""" return self.selected_song_filepath - def get_selected_song_metadata(self) -> EasyID3 | dict: + def get_selected_song_metadata(self) -> ID3 | dict: """Returns the selected song's ID3 tags""" return get_id3_tags(self.selected_song_filepath) @@ -359,7 +356,7 @@ class MusicTable(QTableView): """Returns the currently playing song filepath""" return self.current_song_filepath - def get_current_song_metadata(self) -> EasyID3 | dict: + def get_current_song_metadata(self) -> ID3 | dict: """Returns the currently playing song's ID3 tags""" return get_id3_tags(self.current_song_filepath) diff --git a/out.mp3 b/out.mp3 new file mode 100644 index 0000000..afd38ee Binary files /dev/null and b/out.mp3 differ diff --git a/utils/add_files_to_library.py b/utils/add_files_to_library.py index 1f933ce..5da38d9 100644 --- a/utils/add_files_to_library.py +++ b/utils/add_files_to_library.py @@ -21,24 +21,45 @@ def add_files_to_library(files): if any(filepath.lower().endswith(ext) for ext in extensions): filename = filepath.split("/")[-1] audio = get_id3_tags(filepath) - # print("add_files_to_library audio:") - # print(audio) + print("add_files_to_library audio:") + print(audio) + # Skip if no title is found (but should never happen - if "title" not in audio: + if "TIT2" not in audio: continue + title = audio["TIT2"].text[0] + try: + artist = audio["TPE1"].text[0] + except KeyError: + artist = "" + try: + album = audio["TALB"].text[0] + except KeyError: + album = "" + try: + genre = audio["TCON"].text[0] + except KeyError: + genre = "" + try: + date = audio["TDRC"].text[0] + except KeyError: + date = "" + try: + bitrate = audio["TBIT"].text[0] + except KeyError: + bitrate = "" + # Append data tuple to insert_data list insert_data.append( ( filepath, - safe_get(audio, "title", [])[0], - safe_get(audio, "album", [])[0] if "album" in audio else None, - safe_get(audio, "artist", [])[0] if "artist" in audio else None, - ",".join(safe_get(audio, "genre", [])) - if "genre" in audio - else None, + title, + album, + artist, + genre, filename.split(".")[-1], - safe_get(audio, "date", [])[0] if "date" in audio else None, - safe_get(audio, "bitrate", [])[0] if "birate" in audio else None, + date, + bitrate ) ) # Check if batch size is reached diff --git a/utils/get_id3_tags.py b/utils/get_id3_tags.py index 8665b33..441278b 100644 --- a/utils/get_id3_tags.py +++ b/utils/get_id3_tags.py @@ -1,5 +1,5 @@ -from mutagen.easyid3 import EasyID3 -from mutagen import File +from mutagen.id3 import ID3 +from mutagen.id3._frames import TIT2 import os @@ -12,34 +12,22 @@ def get_id3_tags(file): if all tags are empty, at minimum fill in the 'title' """ - is_easy_id3 = False try: - is_easy_id3 = True - audio = EasyID3(file) - except Exception as e: - is_easy_id3 = False + audio = ID3(file) + except: audio = {} - # print('get_id3_tags audio:') - # print(audio) - # Check if all tags are empty - tags_are_empty = all(not values for values in audio.values()) - if tags_are_empty: - # split on / to get just the filename - # os.path.splitext to get name without extension - audio["title"] = [os.path.splitext(file.split("/")[-1])[0]] - - if audio["title"] is None: # I guess a song could have other tags - # without a title, so i make sure to have title - audio["title"] = [os.path.splitext(file.split("/")[-1])[0]] - - if is_easy_id3: # i can ignore this error because of this check + # tags_are_empty = all(not values for values in audio.values()) + try: + title = os.path.splitext(os.path.basename(file))[0] + frame = TIT2(encoding=3, text=[title]) + audio["TIT2"] = frame + except Exception as e: + print(f'get_id3_tags.py | Exception: {e}') + pass + try: audio.save() # type: ignore + except: + pass return audio - - -# import sys -# my_file = sys.argv[1] -# data = get_id3_tags(my_file) -# print(data) diff --git a/utils/set_id3_tag.py b/utils/set_id3_tag.py index 32d338d..889a2a6 100644 --- a/utils/set_id3_tag.py +++ b/utils/set_id3_tag.py @@ -5,7 +5,7 @@ from mutagen.id3 import ID3 from mutagen.id3._util import ID3NoHeaderError from mutagen.mp3 import MP3 from mutagen.easyid3 import EasyID3 -from mutagen.id3._frames import ( +from mutagen.id3 import ( Frame, TIT2, TPE1, @@ -89,49 +89,42 @@ def set_id3_tag(filepath: str, tag_name: str, value: str): Returns: True / False""" - print( - f"set_id3_tag.py | filepath: {filepath} | tag_name: {tag_name} | value: {value}" - ) + # print( + # f"set_id3_tag.py | filepath: {filepath} | tag_name: {tag_name} | value: {value}" + # ) try: try: # Load existing tags - audio_file = MP3(filepath, ID3=ID3) + audio_file = ID3(filepath) except ID3NoHeaderError: # Create new tags if none exist - audio_file = MP3(filepath) - audio_file.add_tags() + audio_file = ID3() if tag_name == "album_date": tyer_tag, tdat_tag = handle_year_and_date_id3_tag(value) # always update TYER - audio_file.tags.add(tyer_tag) + audio_file.add(tyer_tag) if tdat_tag: # update TDAT if we have it - audio_file.tags.add(tdat_tag) + audio_file.add(tdat_tag) elif tag_name == "lyrics": - audio = ID3(filepath) - frame = USLT(encoding=3, lang="eng", desc="desc", text=value) + try: + audio = ID3(filepath) + except: + audio = ID3() + audio.delall("USLT") + frame = USLT(encoding=3, text=value) audio.add(frame) audio.save() + return True elif tag_name in id3_tag_mapping: # Tag accounted for tag_class = id3_tag_mapping[tag_name] - print(f"set_id3_tag.py | tag_class: {tag_class}") - # if issubclass(tag_class, EasyID3) or issubclass(tag_class, ID3): # Type safety if issubclass(tag_class, Frame): - audio_file.tags.add(tag_class(encoding=3, text=value)) # Add the tag - print(f"AAAAAAAAAAAAAA") + frame = tag_class(encoding=3, text=[value]) + audio_file.add(frame) # Add the tag else: - # dialog = ErrorDialog(f'ID3 tag not supported.\nTag: {tag_name}\nTag class: {tag_class}\nValue:{value}') - # dialog.exec_() - # return False pass else: - # dialog = ErrorDialog(f"Invalid ID3 tag. Tag: {tag_name}, Value:{value}") - # dialog.exec_() - # return False pass - audio_file.save(v2_version=3) - print("set_id3_tag.py | ID3 tags updated:") - print(get_id3_tags(filepath)) - print("set_id3_tag.py | -----") + audio_file.save(filepath) return True except Exception as e: dialog = ErrorDialog(f"An unhandled exception occurred:\n{e}")