#!/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