#!/usr/bin/env bash set -euo pipefail CSV_DEFAULT="wunf_scenes.csv" DRY_RUN=0 usage() { echo "Användning:" echo " $0 [--dry-run] [csv-fil]" echo " $0 [--dry-run] --all [csv-fil]" echo " $0 [--dry-run] --list [csv-fil] # en väg per rad" exit 1 } rename_file() { local FILE="$1" local CSV="$2" if [[ ! -f "$FILE" ]]; then echo "Fel: Filen finns inte: $FILE" >&2 return 1 fi local base dir rest name_segment code newbase newpath base="$(basename -- "$FILE")" dir="$(dirname -- "$FILE")" # Hoppa över om den redan har index, t.ex. [WUNF_427]... if [[ "${base:0:7}" == "[WUNF_" ]]; then echo "Hoppar över (har redan index): $base" >&2 return 0 fi # Kräver exakt prefixet "[WUNF]" if [[ "${base:0:6}" != "[WUNF]" ]]; then echo "Hoppar över (ej [WUNF]-prefix): $base" >&2 return 0 fi # Ta bort prefixet "[WUNF]" rest="${base:6}" # Ta bort ett eller flera ledande underscores efter prefixet while [[ "${rest:0:1}" == "_" ]]; do rest="${rest:1}" done # Ta bort extension (.mp4, .mkv osv) name_segment="${rest%.*}" if [[ -z "$name_segment" ]]; then echo "Ingen namn-del efter prefix i: $base" >&2 return 0 fi # Slå upp kod i CSV via tokeniserad matchning code="$( awk -F';' -v fstring="$name_segment" ' BEGIN { # 1) Tokenisera filnamnets namn-del s = fstring gsub(/_+/, " ", s) # "_" -> mellanslag gsub(/[[:space:]]+/, " ", s) # normalisera whitespace sub(/^[[:space:]]+/, "", s) sub(/[[:space:]]+$/, "", s) s = tolower(s) if (length(s) == 0) { exit 0 } n_ft = split(s, ft, " ") # ft[] = filtokens bestScore = 0 bestCode = "" ambiguous = 0 } { # 2) Tokenisera namn-kolumnen i CSV name = $1 gsub(/,/, " ", name) # kommatecken ignoreras gsub(/[[:space:]]+/, " ", name) sub(/^[[:space:]]+/, "", name) sub(/[[:space:]]+$/, "", name) lname = tolower(name) if (length(lname) == 0) next n_rt = split(lname, rt, " ") # rt[] = CSV-tokens # kan inte vara prefix om den är längre än filens tokenlista if (n_rt > n_ft) next # 3) Kolla om CSV-tokenlistan är prefix till filnamnets tokens matchOK = 1 for (i = 1; i <= n_rt; i++) { if (rt[i] != ft[i]) { matchOK = 0; break } } if (!matchOK) next matchLen = n_rt if (matchLen > 0) { if (matchLen > bestScore) { bestScore = matchLen bestCode = $2 ambiguous = 0 } else if (matchLen == bestScore) { # Fler rader med samma bästa längd => tvetydigt ambiguous = 1 } } } END { if (bestScore > 0 && !ambiguous && length(bestCode) > 0) { c = bestCode gsub(/^[ \t]+|[ \t]+$/, "", c) print c } } ' "$CSV" )" if [[ -z "$code" ]]; then echo "Ingen unik match för filen: $base" >&2 return 0 fi # Bygg prefix med paddad index: # förväntat format: t.ex. "WUNF 1", "WUNF 88", "WUNF 427" local trimmed_code prefix number number_padded code_us trimmed_code="$(printf '%s' "$code" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')" if [[ "$trimmed_code" =~ ^([A-Za-z]+)[[:space:]]*([0-9]+)$ ]]; then prefix="${BASH_REMATCH[1]}" number="${BASH_REMATCH[2]}" printf -v number_padded "%03d" "$number" code_us="${prefix}_${number_padded}" else # Fallback om formatet skulle avvika – använd gammal logik code_us="${trimmed_code// /_}" fi # Ersätt bara själva prefixet [WUNF] i början newbase="$(printf '%s' "$base" | sed -E "s/^\[WUNF\]/[$code_us]/")" newpath="$dir/$newbase" if [[ "$base" == "$newbase" ]]; then echo "Hoppar över (redan rätt prefix): $base" >&2 return 0 fi if [[ -e "$newpath" && $DRY_RUN -eq 0 ]]; then echo "Fel: Målfilen finns redan: $newpath" >&2 return 1 fi if [[ $DRY_RUN -eq 1 ]]; then echo "DRY-RUN: skulle byta namn:" echo " Från: $base" echo " Till: $newbase" else mv -- "$dir/$base" "$newpath" echo "Bytt namn:" echo " Från: $base" echo " Till: $newbase" fi } ### Huvudprogram if [[ $# -lt 1 ]]; then usage fi # Global flagga --dry-run if [[ "${1:-}" == "--dry-run" ]]; then DRY_RUN=1 shift fi if [[ $# -lt 1 ]]; then usage fi mode="$1" case "$mode" in --all) if [[ $# -lt 2 ]]; then usage; fi DIR="$2" CSV="${3:-$CSV_DEFAULT}" if [[ ! -d "$DIR" ]]; then echo "Fel: Katalog finns inte: $DIR" >&2 exit 1 fi if [[ ! -f "$CSV" ]]; then echo "Fel: CSV-filen finns inte: $CSV" >&2 exit 1 fi shopt -s nullglob for f in "$DIR"/\[WUNF\]*.mp4; do rename_file "$f" "$CSV" || true done ;; --list) if [[ $# -lt 2 ]]; then usage; fi LIST="$2" CSV="${3:-$CSV_DEFAULT}" if [[ ! -f "$LIST" ]]; then echo "Fel: Textfil finns inte: $LIST" >&2 exit 1 fi if [[ ! -f "$CSV" ]]; then echo "Fel: CSV-filen finns inte: $CSV" >&2 exit 1 fi while IFS= read -r line || [[ -n "$line" ]]; do line="${line%$'\r'}" trimmed="$(printf '%s' "$line" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')" [[ -z "$trimmed" || "$trimmed" =~ ^# ]] && continue rename_file "$trimmed" "$CSV" || true done < "$LIST" ;; *) FILE="$mode" CSV="${2:-$CSV_DEFAULT}" if [[ ! -f "$CSV" ]]; then echo "Fel: CSV-filen finns inte: $CSV" >&2 exit 1 fi rename_file "$FILE" "$CSV" ;; esac