refactor: improve directory handling and globbing in to-m4b.sh; update .gitignore

This commit is contained in:
Philip Henning 2025-09-10 13:49:41 +02:00
parent 351ea4bb43
commit 70919f1df5
2 changed files with 79 additions and 33 deletions

5
.gitignore vendored
View file

@ -1,5 +1,6 @@
out/ **
src/ !.gitignore
!to-m4b.sh
*~ *~

107
to-m4b.sh
View file

@ -98,9 +98,15 @@ get-book-directories() {
# - ${SRC}/<author>/<year> - <title> {<narrator>}/ # - ${SRC}/<author>/<year> - <title> {<narrator>}/
# Prints matched directories, one per line # Prints matched directories, one per line
local src_root="${1}" local src_root="${1}"
local -a results=()
local dir leaf local dir leaf
# Ensure globbing is enabled locally (script uses set -f globally)
local had_noglob=0
case $- in
*f*) had_noglob=1 ;;
esac
set +f
# Iterate candidate depths using fast globbing (avoids slow full-recursive find) # Iterate candidate depths using fast globbing (avoids slow full-recursive find)
for dir in "${src_root}"/*/*/ "${src_root}"/*/*/*/; do for dir in "${src_root}"/*/*/ "${src_root}"/*/*/*/; do
[[ -d "$dir" ]] || continue [[ -d "$dir" ]] || continue
@ -117,12 +123,18 @@ get-book-directories() {
fi fi
# Quick check: directory contains at least one likely audio file # Quick check: directory contains at least one likely audio file
if compgen -G "$dir"*.{mp3,m4a,m4b,aac,flac,wav} >/dev/null 2>&1; then local found=0 ext
results+=("${dir%/}") for ext in mp3 m4a m4b aac flac wav ogg; do
fi if compgen -G "$dir"*."$ext" >/dev/null 2>&1; then
found=1
break
fi
done
(( found )) && printf '%s\n' "${dir%/}"
done done
printf '%s\n' "${results[@]}" # Restore previous noglob state
(( had_noglob )) && set -f || true
} }
m4b-merge() { m4b-merge() {
@ -135,21 +147,38 @@ m4b-merge() {
local series="${7}" local series="${7}"
local series_index=${8} local series_index=${8}
# Ensure destination directory exists
mkdir -p "$(dirname "${output_file}")" mkdir -p "$(dirname "${output_file}")"
nix run github:sandreas/m4b-tool#m4b-tool-libfdk -- \
merge \ # Build args; add series flags only when present (standalone-friendly)
-v \ local args=(
--jobs=6 \ merge
--audio-samplerate=44100 \ -v
--audio-quality=100 \ --jobs=6
--writer="${author}" \ --audio-samplerate=44100
--artist="${narrator}" \ --audio-quality=100
--title="${title}" \ )
--year="${year}" \ if [[ -n "${author}" ]]; then
--album="${series}" \ args+=("--writer=${author}")
--album-sort="${series_index}" \ fi
--output-file="${output_file}/" \ if [[ -n "${narrator}" ]]; then
-- "${source_dir}" args+=("--artist=${narrator}")
fi
if [[ -n "${title}" ]]; then
args+=("--album=${title}")
fi
if [[ -n "${year}" ]]; then
args+=("--year=${year}")
fi
if [[ -n "${series}" ]]; then
args+=("--series=${series}")
fi
if [[ -n "${series_index}" ]]; then
args+=("--series-part=${series_index}")
fi
args+=("--output-file=${output_file}" -- "${source_dir}")
nix run github:sandreas/m4b-tool#m4b-tool-libfdk -- "${args[@]}"
} }
main() { main() {
@ -157,28 +186,44 @@ main() {
local out_root="${OUT:-${script_dir}/out}" local out_root="${OUT:-${script_dir}/out}"
local dir author narrator title year series series_index output_file local dir author narrator title year series series_index output_file
mapfile -t dirs < <(get-book-directories "${src_root}") # Build array of directories without using mapfile (Bash 3 compatibility)
# Portable array fill (Bash 3): split on newlines only
{
IFS=$'\n'
dirs=($(get-book-directories "${src_root}"))
}
for dir in "${dirs[@]}"; do if ((${#dirs[@]})); then
eval "$(parse-vars "$dir")" for dir in "${dirs[@]}"; do
if [[ -z "$title" ]]; then eval "$(parse-vars "$dir")"
echo "Skipping '$dir': could not parse title" >&2 if [[ -z "$title" ]]; then
continue echo "Skipping '$dir': could not parse title" >&2
fi continue
fi
if [[ -z "$author" ]]; then if [[ -z "$author" ]]; then
echo "Skipping '$dir': could not parse author" >&2 echo "Skipping '$dir': could not parse author" >&2
continue continue
fi fi
# Construct output path: ${OUT}/<author>/<series or standalone>/<series_index - >title {narrator}.m4b # Construct output path: ${OUT}/<author>/<series or standalone>/<series_index - >title {narrator}.m4b
if [[ -n "$series" ]]; then if [[ -n "$series" ]]; then
output_file="${out_root}/${author}/${series}/${series_index:+${series_index} - }${title}${narrator:+ {${narrator}}}.m4b" output_file="${out_root}/${author}/${series}/"
[[ -n "$series_index" ]] && output_file+="Book ${series_index} - "
[[ -n "$year" ]] && output_file+="${year} - "
output_file+="${title}"
else else
output_file="${out_root}/${author}/${year:+${year} - }${title}${narrator:+ {${narrator}}}.m4b" output_file="${out_root}/${author}/"
[[ -n "$year" ]] && output_file+="${year} - "
output_file+="${title}"
fi fi
[[ -n "$narrator" ]] && output_file+=" {${narrator}}"
output_file+=".m4b"
echo "Processing '$dir' -> '$output_file'" echo "Processing '$dir' -> '$output_file'"
# m4b-merge "$output_file" "$dir" "$author" "$narrator" "$title" "$year" "$series" "$series_index" m4b-merge "$output_file" "$dir" "$author" "$narrator" "$title" "$year" "$series" "$series_index"
done done
else
echo "No book directories found under '${src_root}'." >&2
fi
} }
main "$@" main "$@"