diff --git a/fix-artist-separators.sh b/fix-artist-separators.sh index 9ce3180..ec45c69 100644 --- a/fix-artist-separators.sh +++ b/fix-artist-separators.sh @@ -1,18 +1,13 @@ #!/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. +# Splits artist tags on "/" into ";" — with hardcoded exceptions for artist +# names that legitimately contain "/" (Au/Ra, HUNTR/X). # # 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 @@ -26,15 +21,54 @@ 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)" + echo "🔍 DRY RUN — no files will be changed (add --apply to apply)" fi echo "📂 Scanning: $MUSIC_DIR" +echo "🚫 Exceptions: Au/Ra, HUNTR/X" echo "" count_found=0 count_ok=0 count_fail=0 +# Splits artist string on "/" while preserving exception names. +# Example: "HUNTR/X/EJAE/AUDREY NUNA" -> "HUNTR/X;EJAE;AUDREY NUNA" +# "-Prey/zecki" -> "-Prey;zecki" +# "Au/Ra" -> "Au/Ra" (exception, unchanged) +SPLIT_PY=' +import sys + +EXCEPTIONS = ["Au/Ra", "HUNTR/X"] +exc_lookup = [(exc, exc.lower(), exc.split("/")) for exc in EXCEPTIONS] + +def smart_split(artist): + parts = artist.split("/") + result = [] + i = 0 + while i < len(parts): + matched = False + for exc, exc_lower, exc_parts in exc_lookup: + n = len(exc_parts) + candidate = parts[i:i+n] + if len(candidate) == n and "/".join(candidate).lower() == exc_lower: + result.append(exc) + i += n + matched = True + break + if not matched: + p = parts[i].strip() + if p: + result.append(p) + i += 1 + return ";".join(result) + +artist = sys.stdin.read().strip() +if "/" not in artist: + print(artist) +else: + print(smart_split(artist)) +' + get_artist() { ffprobe -v quiet -print_format json -show_format "$1" 2>/dev/null \ | python3 -c " @@ -47,11 +81,12 @@ print(next((v for k, v in tags.items() if k.lower() == 'artist'), '')) while IFS= read -r -d '' file; do artist=$(get_artist "$file") || continue - [[ "$artist" != *" / "* ]] && continue + [[ "$artist" != *"/"* ]] && continue + + new_artist=$(echo "$artist" | python3 -c "$SPLIT_PY" 2>/dev/null) || continue + [[ "$artist" == "$new_artist" ]] && continue - new_artist="${artist// \/ /;}" count_found=$((count_found + 1)) - echo "📄 $file" echo " Before : $artist" echo " After : $new_artist" @@ -77,13 +112,10 @@ done < <(find "$MUSIC_DIR" -type f \( \ -name "*.opus" \) -print0) echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Files with \" / \" in artist tag: $count_found" +echo "Files to change: $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 + [[ $count_ok -gt 0 ]] && echo "" && echo "💡 Trigger a Navidrome rescan to pick up the changes." else echo "" echo "Run with --apply to fix them:"