241 lines
5.7 KiB
Bash
Executable File
241 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
CSV_DEFAULT="wunf_scenes.csv"
|
||
DRY_RUN=0
|
||
|
||
usage() {
|
||
echo "Användning:"
|
||
echo " $0 [--dry-run] <filnamn> [csv-fil]"
|
||
echo " $0 [--dry-run] --all <katalog> [csv-fil]"
|
||
echo " $0 [--dry-run] --list <textfil> [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
|