diff --git a/backend/lib/metadata.js b/backend/lib/metadata.js index b090435..62f7d63 100644 --- a/backend/lib/metadata.js +++ b/backend/lib/metadata.js @@ -9,10 +9,11 @@ function sanitize(s) { function navidromeArtist(name) { if (!name) return name; return name - .replace(/\s+feat\.?\s+/gi, ' / ') - .replace(/\s+ft\.?\s+/gi, ' / ') - .replace(/\s+featuring\s+/gi, ' / ') - .replace(/,\s+/g, ' / '); + .replace(/\s+feat\.?\s+/gi, ';') + .replace(/\s+ft\.?\s+/gi, ';') + .replace(/\s+featuring\s+/gi, ';') + .replace(/\s+&\s+/g, ';') + .replace(/,\s+/g, ';'); } // Download hi-res iTunes artwork (1000x1000) to cover.jpg, return path or null diff --git a/fix-artist-separators.sh b/fix-artist-separators.sh new file mode 100644 index 0000000..9ce3180 --- /dev/null +++ b/fix-artist-separators.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# fix-artist-separators.sh +# Replaces " / " (space-slash-space) in audio file artist tags with ";" +# +# Safe: only matches " / " with surrounding spaces, so Au/Ra and HUNTR/X +# (no spaces around the slash) are left completely untouched. +# +# Requires: ffprobe, ffmpeg, python3 +# +# Usage: +# bash fix-artist-separators.sh [music_dir] -- dry run (no changes) +# bash fix-artist-separators.sh [music_dir] --apply -- actually modify files +# +# Example: +# bash fix-artist-separators.sh /opt/navidrome/music --apply + +MUSIC_DIR="${1:-/opt/navidrome/music}" +APPLY=false +[[ "${2:-}" == "--apply" ]] && APPLY=true + +if [[ ! -d "$MUSIC_DIR" ]]; then + echo "Error: directory not found: $MUSIC_DIR" + exit 1 +fi + +if $APPLY; then + echo "🔧 APPLY mode — files will be modified" +else + echo "🔍 DRY RUN — no files will be changed (add --apply to apply changes)" +fi +echo "📂 Scanning: $MUSIC_DIR" +echo "" + +count_found=0 +count_ok=0 +count_fail=0 + +get_artist() { + ffprobe -v quiet -print_format json -show_format "$1" 2>/dev/null \ + | python3 -c " +import sys, json +data = json.load(sys.stdin) +tags = data.get('format', {}).get('tags', {}) +print(next((v for k, v in tags.items() if k.lower() == 'artist'), '')) +" 2>/dev/null +} + +while IFS= read -r -d '' file; do + artist=$(get_artist "$file") || continue + [[ "$artist" != *" / "* ]] && continue + + new_artist="${artist// \/ /;}" + count_found=$((count_found + 1)) + + echo "📄 $file" + echo " Before : $artist" + echo " After : $new_artist" + + if $APPLY; then + ext="${file##*.}" + tmp="${file%.*}.artist_fix_tmp.$ext" + if ffmpeg -i "$file" -map_metadata 0 -metadata "artist=$new_artist" \ + -c copy "$tmp" -y -loglevel quiet 2>/dev/null; then + mv "$tmp" "$file" + echo " ✅ Updated" + count_ok=$((count_ok + 1)) + else + rm -f "$tmp" + echo " ❌ Failed" + count_fail=$((count_fail + 1)) + fi + fi + echo "" +done < <(find "$MUSIC_DIR" -type f \( \ + -name "*.mp3" -o -name "*.flac" -o \ + -name "*.m4a" -o -name "*.ogg" -o \ + -name "*.opus" \) -print0) + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "Files with \" / \" in artist tag: $count_found" +if $APPLY; then + echo "Updated: $count_ok | Failed: $count_fail" + if [[ $count_ok -gt 0 ]]; then + echo "" + echo "💡 Trigger a Navidrome rescan to pick up the changes." + fi +else + echo "" + echo "Run with --apply to fix them:" + echo " bash fix-artist-separators.sh \"$MUSIC_DIR\" --apply" +fi