From 3be3bed90393572adf3847e75d87a526eac6d59e Mon Sep 17 00:00:00 2001 From: Amir Aref Date: Thu, 14 May 2026 21:08:58 +0330 Subject: [PATCH] copy tags using a python script in reduce-bitrate --- copy_id3_tags.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ reduce_bitrate.sh | 32 +++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 3 deletions(-) create mode 100755 copy_id3_tags.py diff --git a/copy_id3_tags.py b/copy_id3_tags.py new file mode 100755 index 0000000..18b4672 --- /dev/null +++ b/copy_id3_tags.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +""" +Copy all ID3 tags from source file to target file, preserving multi-value fields. +Requires: python-mutagen +""" + +import sys +from mutagen.id3 import ID3, ID3NoHeaderError + +def copy_id3_tags(source_path, target_path): + """Copy all ID3 tags from source to target file.""" + try: + # Load source tags + source_tags = ID3(source_path) + + # Load or create target tags + try: + target_tags = ID3(target_path) + except ID3NoHeaderError: + target_tags = ID3() + + # Clear all existing tags in target + target_tags.clear() + + # Copy all frames from source to target + for key, value in source_tags.items(): + target_tags[key] = value + + # Save to target file + target_tags.save(target_path, v2_version=3) + + return 0 + + except Exception as e: + print(f"Error copying tags: {e}", file=sys.stderr) + return 1 + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: copy_id3_tags.py ", file=sys.stderr) + sys.exit(1) + + source = sys.argv[1] + target = sys.argv[2] + + sys.exit(copy_id3_tags(source, target)) diff --git a/reduce_bitrate.sh b/reduce_bitrate.sh index 8e53b17..6e401e3 100755 --- a/reduce_bitrate.sh +++ b/reduce_bitrate.sh @@ -52,6 +52,17 @@ get_bitrate_kbps() { return 1 } +restore_metadata() { + local source_file="$1" + local target_file="$2" + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + + # Use Python script with mutagen to properly copy all ID3 tags including multi-value fields + "$script_dir/copy_id3_tags.py" "$source_file" "$target_file" 2>/dev/null + + return $? +} + process_file() { local file="$1" local current_bitrate @@ -85,8 +96,18 @@ process_file() { temp_file="${file%.mp3}_temp_$$.mp3" if ffmpeg -nostdin -y -i "$file" -b:a "${TARGET_BITRATE}" -id3v2_version 3 "$temp_file" > /dev/null 2>&1; then mv "$temp_file" "$file" - log_success "Converted: ${file} (${current_bitrate} kbps ➜ ${TARGET_BITRATE}) ✅" - ((converted_count++)) + + # Restore all metadata from backup file + if restore_metadata "$backup_file" "$file"; then + log_success "Converted: ${file} (${current_bitrate} kbps ➜ ${TARGET_BITRATE}) ✅" + ((converted_count++)) + else + log_error "Metadata restoration failed: ${file}" + # Revert to backup since metadata restoration failed + cp "$backup_file" "$file" + log_warn "Reverted to backup (conversion skipped due to metadata error)" + ((error_count++)) + fi else rm -f "$temp_file" log_error "ffmpeg failed: ${file}" @@ -113,7 +134,12 @@ while getopts ":nd:ch" opt; do done if ! command -v ffprobe >/dev/null 2>&1 || ! command -v ffmpeg >/dev/null 2>&1; then - log_error "ffprobe/ffmpeg not found. Please install ffmpeg." + log_error "ffprobe/ffmpeg not found. Please install ffmpeg." + exit 1 +fi + +if ! python3 -c "import mutagen" 2>/dev/null; then + log_error "Python mutagen library not found. Please install python-mutagen (Arch) or python3-mutagen (Debian/Ubuntu)." exit 1 fi