-
-
Notifications
You must be signed in to change notification settings - Fork 60
Replace musicbrainz with eyed3 for ID tag reading #322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e022588
9af0597
930e2ec
1f7bd33
f8069b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||
| """UltraSinger uses AI to automatically create UltraStar song files""" | ||||||||||||||
|
|
||||||||||||||
| import copy | ||||||||||||||
| import eyed3 | ||||||||||||||
| import getopt | ||||||||||||||
| import os | ||||||||||||||
| import sys | ||||||||||||||
|
|
@@ -64,7 +65,6 @@ | |||||||||||||
| from modules.common_print import print_support, print_help, print_version | ||||||||||||||
| from modules.os_helper import check_file_exists, get_unused_song_output_dir | ||||||||||||||
| from modules.plot import create_plots | ||||||||||||||
| from modules.musicbrainz_client import search_musicbrainz | ||||||||||||||
| from modules.sheet import create_sheet | ||||||||||||||
| from modules.ProcessData import ProcessData, ProcessDataPaths, MediaInfo | ||||||||||||||
| from modules.DeviceDetection.device_detection import check_gpu_support | ||||||||||||||
|
|
@@ -646,6 +646,8 @@ def transcribe_audio(cache_folder_path: str, processing_audio_path: str) -> Tran | |||||||||||||
|
|
||||||||||||||
| def infos_from_audio_video_input_file() -> tuple[str, str, str, MediaInfo]: | ||||||||||||||
| """Infos from audio/video input file""" | ||||||||||||||
| import eyed3 | ||||||||||||||
|
|
||||||||||||||
| basename = os.path.basename(settings.input_file_path) | ||||||||||||||
| basename_without_ext = os.path.splitext(basename)[0] | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -655,8 +657,32 @@ def infos_from_audio_video_input_file() -> tuple[str, str, str, MediaInfo]: | |||||||||||||
| else: | ||||||||||||||
| title = basename_without_ext | ||||||||||||||
|
|
||||||||||||||
| song_info = search_musicbrainz(title, artist) | ||||||||||||||
| basename_without_ext = f"{song_info.artist} - {song_info.title}" | ||||||||||||||
| # Read ID3 tags from file | ||||||||||||||
| file_artist, file_title, year, genres, cover_image_data = None, None, None, [], None | ||||||||||||||
|
|
||||||||||||||
| try: | ||||||||||||||
| audio_file = eyed3.load(settings.input_file_path) | ||||||||||||||
| if audio_file is not None and audio_file.tag is not None: | ||||||||||||||
| file_artist = audio_file.tag.artist or artist or "Unknown Artist" | ||||||||||||||
| file_title = audio_file.tag.title or title | ||||||||||||||
| if audio_file.tag.best_release_date: | ||||||||||||||
| year = audio_file.tag.best_release_date.year | ||||||||||||||
| if audio_file.tag.genre: | ||||||||||||||
| genres = audio_file.tag.genre.name | ||||||||||||||
| if audio_file.tag.images: | ||||||||||||||
| cover_image_data = audio_file.tag.images[0].image_data | ||||||||||||||
| except Exception: | ||||||||||||||
| file_artist = artist or "Unknown Artist" | ||||||||||||||
| file_title = title | ||||||||||||||
|
Comment on lines
+661
to
+676
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check which audio formats are referenced in the codebase
echo "=== Searching for audio format references ==="
rg -i --type=py -C2 '(mp3|flac|ogg|m4a|wav|aac)' -g '!test*' | head -30
echo ""
echo "=== Checking eyed3 format support documentation ==="
# Search for format-related checks or conversions
rg -i --type=py 'is_video_file|audio.*format|file.*extension' -C3Repository: rakuri255/UltraSinger Length of output: 9299 🏁 Script executed: # First, let's look at the broader context around lines 661-676 in UltraSinger.py
sed -n '600,700p' src/UltraSinger.py | cat -nRepository: rakuri255/UltraSinger Length of output: 5295 🏁 Script executed: # Search for where input_file_path is processed before the metadata extraction
rg -n 'input_file_path|eyed3' src/UltraSinger.py | head -40Repository: rakuri255/UltraSinger Length of output: 1163 🏁 Script executed: # Check if there's format detection or conversion before metadata extraction
rg -B10 'eyed3.load' src/UltraSinger.pyRepository: rakuri255/UltraSinger Length of output: 434 🏁 Script executed: # Check if there's any eyed3 configuration or documentation in the codebase
rg -i 'eyed3|id3' src/ --type=py -B2 -A2Repository: rakuri255/UltraSinger Length of output: 1406 🏁 Script executed: # Check requirements/dependencies to see eyed3 version
fd -i requirements '\.(txt|in|toml|yaml|yml)$' -exec cat {} \;Repository: rakuri255/UltraSinger Length of output: 325 🌐 Web query:
💡 Result: The eyeD3 library is primarily designed for working with MP3 files and ID3 metadata [1][2]. According to the official documentation, it explicitly supports the following file types: - MP3 audio files (via eyed3.mp3.Mp3AudioFile) [3] - Raw ID3 data files (via eyed3.id3.TagFile) [3] While the library's design is abstract to allow for potential future support of other formats [1][4], its current core functionality is focused on MP3s and ID3 tags. When using the library's loading functions (such as eyed3.load), it will return None if the file type or MIME type is not recognized [3]. Additionally, eyeD3 supports ID3 metadata versions 1.x (1.0/1.1), 2.2 (read-only), 2.3, and 2.4 [1][5]. Citations:
eyed3 only supports MP3 files with ID3 tags—non-MP3 formats will silently fail to extract metadata. The Consider adding explicit format validation before attempting ID3 extraction, or use a format-agnostic metadata library for broader audio format support. 🧰 Tools🪛 Ruff (0.15.12)[warning] 674-674: Do not catch blind exception: (BLE001) 🤖 Prompt for AI Agents
Comment on lines
+674
to
+676
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace bare The broad exception handler can mask unexpected errors and make debugging difficult. 🛡️ Proposed fix to catch specific exceptions- except Exception:
+ except (OSError, IOError, AttributeError):
file_artist = artist or "Unknown Artist"
file_title = title📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.15.12)[warning] 674-674: Do not catch blind exception: (BLE001) 🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| if not file_artist: | ||||||||||||||
| file_artist = "Unknown Artist" | ||||||||||||||
| if not file_title: | ||||||||||||||
| file_title = basename_without_ext | ||||||||||||||
| if not genres: | ||||||||||||||
| genres = None | ||||||||||||||
|
|
||||||||||||||
| basename_without_ext = f"{file_artist} - {file_title}" | ||||||||||||||
|
|
||||||||||||||
| song_folder_output_path = os.path.join(settings.output_folder_path, basename_without_ext) | ||||||||||||||
| song_folder_output_path = get_unused_song_output_dir(song_folder_output_path) | ||||||||||||||
|
Comment on lines
+685
to
688
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sanitize tag-derived artist/title before using them in filesystem paths. Line 685 uses raw ID3 values to build directory/file names. Tag values can contain path separators or invalid filename characters, causing path traversal-like folder creation or OS-specific failures. 🛠️ Proposed minimal change+ invalid_chars = '\\/:*?"<>|'
+ safe_artist = "".join("_" if c in invalid_chars else c for c in file_artist).replace("..", "_").strip().strip(".")
+ safe_title = "".join("_" if c in invalid_chars else c for c in file_title).replace("..", "_").strip().strip(".")
- basename_without_ext = f"{file_artist} - {file_title}"
+ basename_without_ext = f"{safe_artist} - {safe_title}"🤖 Prompt for AI Agents |
||||||||||||||
|
|
@@ -686,20 +712,20 @@ def infos_from_audio_video_input_file() -> tuple[str, str, str, MediaInfo]: | |||||||||||||
| ) | ||||||||||||||
| ultrastar_audio_input_path = os.path.join(song_folder_output_path, basename_with_ext) | ||||||||||||||
|
|
||||||||||||||
| # Todo: Read ID3 tags | ||||||||||||||
| if song_info.cover_image_data is not None: | ||||||||||||||
| save_image(song_info.cover_image_data, basename_without_ext, song_folder_output_path) | ||||||||||||||
| # Save cover image from ID3 tags | ||||||||||||||
| if cover_image_data is not None: | ||||||||||||||
| save_image(cover_image_data, basename_without_ext, song_folder_output_path) | ||||||||||||||
|
|
||||||||||||||
| return ( | ||||||||||||||
| basename_without_ext, | ||||||||||||||
| song_folder_output_path, | ||||||||||||||
| ultrastar_audio_input_path, | ||||||||||||||
| MediaInfo( | ||||||||||||||
| artist=song_info.artist, | ||||||||||||||
| title=song_info.title, | ||||||||||||||
| year=song_info.year, | ||||||||||||||
| genre=song_info.genres, | ||||||||||||||
| cover_url=song_info.cover_url, | ||||||||||||||
| artist=file_artist, | ||||||||||||||
| title=file_title, | ||||||||||||||
| year=year, | ||||||||||||||
| genre=genres, | ||||||||||||||
| cover_url=None, | ||||||||||||||
| audio_extension=audio_ext, | ||||||||||||||
| video_extension=video_ext | ||||||||||||||
| ), | ||||||||||||||
|
|
||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.