From 7c2e0db6150cedabeaec373c1ff49177882158aa Mon Sep 17 00:00:00 2001 From: Lucas Vivohost Date: Mon, 14 Sep 2026 12:22:45 +0200 Subject: [PATCH] metadata scripts album from folder: create album from foldername read: read and display author, album, grouping of every folder remove author before title: remove "name - " when matching author --- .../metadata_album_from_folder.sh | 32 +++++++++++++++++++ audiobook_metadata/metadata_ffmpeg_series.sh | 5 +-- .../metadata_generate_for_pdf.sh | 0 audiobook_metadata/metadata_rank_from_list.py | 12 +++---- audiobook_metadata/metadata_read.sh | 27 ++++++++++++++++ .../metadata_remove_author_before_title.sh | 20 ++++++++++++ audiobook_metadata/metadata_remove_genre.sh | 5 ++- audiobook_metadata/metadata_scan.sh | 0 audiobook_metadata/metadata_search_display.sh | 3 +- audiobook_metadata/metadata_search_replace.sh | 28 ++++++++++++---- audiobook_metadata/metadata_write_ranking.sh | 0 11 files changed, 114 insertions(+), 18 deletions(-) create mode 100755 audiobook_metadata/metadata_album_from_folder.sh mode change 100644 => 100755 audiobook_metadata/metadata_generate_for_pdf.sh mode change 100644 => 100755 audiobook_metadata/metadata_rank_from_list.py create mode 100755 audiobook_metadata/metadata_read.sh create mode 100644 audiobook_metadata/metadata_remove_author_before_title.sh mode change 100644 => 100755 audiobook_metadata/metadata_remove_genre.sh mode change 100644 => 100755 audiobook_metadata/metadata_scan.sh mode change 100644 => 100755 audiobook_metadata/metadata_write_ranking.sh diff --git a/audiobook_metadata/metadata_album_from_folder.sh b/audiobook_metadata/metadata_album_from_folder.sh new file mode 100755 index 0000000..1952c84 --- /dev/null +++ b/audiobook_metadata/metadata_album_from_folder.sh @@ -0,0 +1,32 @@ +#!/bin/bash +cd $1 +for d in */; do + album="${d%/}" + + # Remove leading numbering: "001 - " + album=$(echo "$album" | sed -E 's/^[0-9]+[[:space:]]*-[[:space:]]*//') +album=$(echo "$album" | sed -E 's/^\([^)]*\)[[:space:]]*//; s/[[:space:]]*\([^)]*\)$//') + # Remove all (...) groups + album=$(echo "$album" | sed -E 's/$$[^)]*$$//g') + + # Remove all [...] groups + album=$(echo "$album" | sed -E 's/$$[^]]*$$//g') + + # Remove standalone years + album=$(echo "$album" | sed -E 's/[[:space:]]+[12][0-9]{3}//g') + + # Collapse multiple spaces and trim + album=$(echo "$album" | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//') + + echo "Setting album: $album" + + cd "$d" || continue + + for x in *; do + [ -f "$x" ] || continue + kid3-cli -c "set album \"$album\"" -c save "$x" + done + + cd .. +done + diff --git a/audiobook_metadata/metadata_ffmpeg_series.sh b/audiobook_metadata/metadata_ffmpeg_series.sh index 389d1bd..792a998 100755 --- a/audiobook_metadata/metadata_ffmpeg_series.sh +++ b/audiobook_metadata/metadata_ffmpeg_series.sh @@ -18,12 +18,13 @@ for d in */; do else continue fi - echo $d $num + echo Folder: $d, Number: $num /home/lucas/scripts/.venv/bin/python \ /home/lucas/scripts/ffmpeg_handling.py \ ms "$name" \ --override \ -k grouping \ -v "$series #$num" \ - "$@" + "$@" > /home/lucas/metadata_set.log + # --kidflag \ done diff --git a/audiobook_metadata/metadata_generate_for_pdf.sh b/audiobook_metadata/metadata_generate_for_pdf.sh old mode 100644 new mode 100755 diff --git a/audiobook_metadata/metadata_rank_from_list.py b/audiobook_metadata/metadata_rank_from_list.py old mode 100644 new mode 100755 index fcd88f1..00c026e --- a/audiobook_metadata/metadata_rank_from_list.py +++ b/audiobook_metadata/metadata_rank_from_list.py @@ -55,7 +55,7 @@ def get_tag(path, tag): return "" -def tag_file(path: Path, rank: int, year: str, dry_run: bool, replace_pattern: str=r"Top 100 SciFi Books" ) +def tag_file(path: Path, rank: int, year: str, dry_run: bool, replace_pattern: str=r"Top 100 SciFi Books" ): work = get_tag(path, "work") grouping = get_tag(path, "grouping") existing_year = get_tag(path, "year") @@ -69,26 +69,26 @@ def tag_file(path: Path, rank: int, year: str, dry_run: bool, replace_pattern: s else: tag = "grouping" existing = "" - pattern = f"{replace_pattern} #\d+(?:\.\d+)?" + pattern = rf"{replace_pattern} #\d+(?:\.\d+)?" if existing: if re.search(pattern, existing): new_group = re.sub( pattern, - f"{replace} #{rank};", + f"{replace_pattern} #{rank};", existing, ) else: - new_group = f"{existing}; {replace} #{rank};" + new_group = f"{existing}; {replace_pattern} #{rank};" else: - new_group = f"{replace} #{rank};" + new_group = f"{replace_pattern} #{rank};" new_group = re.sub(r";+", ";", new_group) # Skip if nothing changes if existing == new_group and existing_year == str(year): print("Skipping (already tagged)") return "skip" - print(f"Would tag {path.name}: {new_group} {year}") + print(f"New tag {path.name}: {new_group}, Year: {year}") if dry_run: return diff --git a/audiobook_metadata/metadata_read.sh b/audiobook_metadata/metadata_read.sh new file mode 100755 index 0000000..bd45c4a --- /dev/null +++ b/audiobook_metadata/metadata_read.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +ROOT="${1:-.}" + +find "$ROOT" -type d | while read -r dir; do + first_file=$( + find "$dir" -maxdepth 1 -type f \ + \( -iname "*.m4b" -o -iname "*.m4a" -o -iname "*.mp3" \ + -o -iname "*.flac" -o -iname "*.ogg" \) | + sort | + head -n1 + ) + + [[ -z "$first_file" ]] && continue + + artist=$(kid3-cli -c "get artist" "$first_file" 2>/dev/null) + album=$(kid3-cli -c "get album" "$first_file" 2>/dev/null) + composer=$(kid3-cli -c "get composer" "$first_file" 2>/dev/null) + comment=$(kid3-cli -c "get comment" "$first_file" 2>/dev/null) + echo "====≠===============================" + echo "Folder: $(basename "$dir")" + echo "Album: $album" + echo "Artist: $artist" + echo "Narrator: $composer" + echo "Comment: $comment" +done + diff --git a/audiobook_metadata/metadata_remove_author_before_title.sh b/audiobook_metadata/metadata_remove_author_before_title.sh new file mode 100644 index 0000000..9ee9ee1 --- /dev/null +++ b/audiobook_metadata/metadata_remove_author_before_title.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +WORKDIR="${1:-.}" + +cd "$WORKDIR" + +# Use $2 if provided, otherwise use current directory name +AUTHOR="${2:-$(basename "$PWD")}" + +for d in "$AUTHOR - "*; do + [[ -d "$d" ]] || continue + + new_name="${d#"$AUTHOR - "}" + + echo "Renaming: $d -> $new_name" + mv -- "$d" "$new_name" +done + diff --git a/audiobook_metadata/metadata_remove_genre.sh b/audiobook_metadata/metadata_remove_genre.sh old mode 100644 new mode 100755 index d13eedf..52c0028 --- a/audiobook_metadata/metadata_remove_genre.sh +++ b/audiobook_metadata/metadata_remove_genre.sh @@ -41,8 +41,11 @@ for file in "${FILES[@]}"; do [[ -z "$genre" ]] && continue cleaned=$(printf '%s\n' "$genre" | sed -E ' s/[Aa]udio[[:space:]]*[Bb]ooks?//g - s/\b(Hörbücher?|Hoerbücher?|Hoerbuecher?|Hörspiele?|Hoerspiele?)\b//Ig + s/\b(Hörb(uch|ücher)|Hoerb(uch|uecher)|Hörspiel(e)?|Hoerspiel(e)?)\b//Ig + s/[Gg]esprochene[[:space:]]*[Ii]nhalte//g + s/[Ss]poken[[:space:]]*[Ww]ord//g + s/[Ss]peech//g # Normalize genre names s/\b(Sci[ -]?Fi|Science Fiction|SF)\b/SciFi/Ig s/\bnonfiction\b/NonFiction/Ig diff --git a/audiobook_metadata/metadata_scan.sh b/audiobook_metadata/metadata_scan.sh old mode 100644 new mode 100755 diff --git a/audiobook_metadata/metadata_search_display.sh b/audiobook_metadata/metadata_search_display.sh index 8d1a65f..bdf34b1 100755 --- a/audiobook_metadata/metadata_search_display.sh +++ b/audiobook_metadata/metadata_search_display.sh @@ -15,13 +15,12 @@ while IFS= read -r -d '' f; do -show_entries format_tags=description \ -of default=nw=1:nk=1 \ -- "$f") - # trim comment comment="${comment#"${comment%%[![:space:]]*}"}" comment="${comment%"${comment##*[![:space:]]}"}" # ---- DELETE MODE ---- - if [[ "$mode" == "del" && -n "$comment" && ${#comment} -lt $THRESHOLD ]]; then + if [[ "$mode" == "--delete" && -n "$comment" && ${#comment} -lt $THRESHOLD ]]; then tmp=$(mktemp -p "$(dirname -- "$f")" ".fftmp.XXXXXX.${f##*.}") || continue echo "Removing short comment: $f" diff --git a/audiobook_metadata/metadata_search_replace.sh b/audiobook_metadata/metadata_search_replace.sh index 3f89145..77325aa 100755 --- a/audiobook_metadata/metadata_search_replace.sh +++ b/audiobook_metadata/metadata_search_replace.sh @@ -1,19 +1,33 @@ #!/usr/bin/env bash -root="${1:-.}" -find "$root" \( -iname '*.mp3' -o -iname '*.m4a' -o -iname '*.m4b' \) -print0 | -while IFS= read -r -d '' f; do +LIBRARY="${1:-.}" +mapfile -t FILES < <( + find "$LIBRARY" -type f \( \ + -iname "*.mp3" -o \ + -iname "*.m4b" -o \ + -iname "*.m4a" \ + \) +) +TOTAL=${#FILES[@]} +PROCESSED=0 +for f in "${FILES[@]}"; do + ((PROCESSED++)) + if (( PROCESSED % 100 == 0 )); then + echo "Progress: $PROCESSED/$TOTAL files processed" + fi comment=$(ffprobe -v error \ -show_entries format_tags=comment \ -of default=nw=1:nk=1 \ -- "$f") + shopt -s nocasematch - [[ $comment =~ ^[Rr]ead[[:space:]]+[Bb]y[[:space:]]+(.+) ]] || continue +[[ $comment =~ (read[[:space:]]+by|spoken[[:space:]]+by|narrated[[:space:]]+by|gesprochen[[:space:]]+von|gelesen[[:space:]]+von)[[:space:]]+([^.$'\n']*) ]] || continue - composer="${BASH_REMATCH[1]}" - echo "Updating: $f" - echo " Composer: $composer" + composer="${BASH_REMATCH[2]}" +composer="${composer%"${composer##*[!.,[:space:]]}"}" + printf '[%d/%d] [%s] %s | OLD="%s" | NEW="%s +"\n' "$PROCESSED" "$TOTAL" "Update" "$f" "$comment" "$composer" dir=$(dirname -- "$f") base=$(basename -- "$f") diff --git a/audiobook_metadata/metadata_write_ranking.sh b/audiobook_metadata/metadata_write_ranking.sh old mode 100644 new mode 100755