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>}/
# Prints matched directories, one per line
local src_root="${1}"
local -a results=()
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)
for dir in "${src_root}"/*/*/ "${src_root}"/*/*/*/; do
[[ -d "$dir" ]] || continue
@ -117,12 +123,18 @@ get-book-directories() {
fi
# 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
results+=("${dir%/}")
fi
local found=0 ext
for ext in mp3 m4a m4b aac flac wav ogg; do
if compgen -G "$dir"*."$ext" >/dev/null 2>&1; then
found=1
break
fi
done
(( found )) && printf '%s\n' "${dir%/}"
done
printf '%s\n' "${results[@]}"
# Restore previous noglob state
(( had_noglob )) && set -f || true
}
m4b-merge() {
@ -135,21 +147,38 @@ m4b-merge() {
local series="${7}"
local series_index=${8}
# Ensure destination directory exists
mkdir -p "$(dirname "${output_file}")"
nix run github:sandreas/m4b-tool#m4b-tool-libfdk -- \
merge \
-v \
--jobs=6 \
--audio-samplerate=44100 \
--audio-quality=100 \
--writer="${author}" \
--artist="${narrator}" \
--title="${title}" \
--year="${year}" \
--album="${series}" \
--album-sort="${series_index}" \
--output-file="${output_file}/" \
-- "${source_dir}"
# Build args; add series flags only when present (standalone-friendly)
local args=(
merge
-v
--jobs=6
--audio-samplerate=44100
--audio-quality=100
)
if [[ -n "${author}" ]]; then
args+=("--writer=${author}")
fi
if [[ -n "${narrator}" ]]; then
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() {
@ -157,28 +186,44 @@ main() {
local out_root="${OUT:-${script_dir}/out}"
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
eval "$(parse-vars "$dir")"
if [[ -z "$title" ]]; then
echo "Skipping '$dir': could not parse title" >&2
continue
fi
if ((${#dirs[@]})); then
for dir in "${dirs[@]}"; do
eval "$(parse-vars "$dir")"
if [[ -z "$title" ]]; then
echo "Skipping '$dir': could not parse title" >&2
continue
fi
if [[ -z "$author" ]]; then
echo "Skipping '$dir': could not parse author" >&2
continue
fi
# Construct output path: ${OUT}/<author>/<series or standalone>/<series_index - >title {narrator}.m4b
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
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
[[ -n "$narrator" ]] && output_file+=" {${narrator}}"
output_file+=".m4b"
echo "Processing '$dir' -> '$output_file'"
# m4b-merge "$output_file" "$dir" "$author" "$narrator" "$title" "$year" "$series" "$series_index"
done
echo "Processing '$dir' -> '$output_file'"
m4b-merge "$output_file" "$dir" "$author" "$narrator" "$title" "$year" "$series" "$series_index"
done
else
echo "No book directories found under '${src_root}'." >&2
fi
}
main "$@"