diff --git a/.gitignore b/.gitignore index 9178f67..58c9f11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -out/ -src/ +** +!.gitignore +!to-m4b.sh *~ diff --git a/to-m4b.sh b/to-m4b.sh index f92d736..894d653 100755 --- a/to-m4b.sh +++ b/to-m4b.sh @@ -98,9 +98,15 @@ get-book-directories() { # - ${SRC}// - {<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 "$@"