not working
This commit is contained in:
		
							parent
							
								
									fce19df179
								
							
						
					
					
						commit
						351ea4bb43
					
				
					 1 changed files with 134 additions and 11 deletions
				
			
		
							
								
								
									
										145
									
								
								to-m4b.sh
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										145
									
								
								to-m4b.sh
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
					@ -3,28 +3,126 @@ set -x
 | 
				
			||||||
set -eufo pipefail
 | 
					set -eufo pipefail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CONSTANTS
 | 
					# CONSTANTS
 | 
				
			||||||
declare -r m4b-tool="nix run github:sandreas/m4b-tool#m4b-tool-libfdk -- "
 | 
					 | 
				
			||||||
declare -r script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
					declare -r script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# VARS
 | 
					# VARS
 | 
				
			||||||
LEADING_ZEROES=2
 | 
					LEADING_ZEROES=2
 | 
				
			||||||
MAIN_SRC="${SRC:${script_dir}/src}"
 | 
					SRC="${script_dir}/src"
 | 
				
			||||||
MAIN_OUT="${OUT:${script_dir}/out}"
 | 
					OUT="${script_dir}/out"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FUNCTIONS
 | 
					# FUNCTIONS
 | 
				
			||||||
parse-vars() {
 | 
					parse-vars() {
 | 
				
			||||||
  # TODO implement parsing the directory structure of the passed directory, to fill in missing vars and return them
 | 
					 | 
				
			||||||
  # Series structure: ${SRC}/<author>/<series>/Book <part> - <year> - <book> {<narrator>}/
 | 
					  # Series structure: ${SRC}/<author>/<series>/Book <part> - <year> - <book> {<narrator>}/
 | 
				
			||||||
  # Standalone structure: ${SRC}/<author>/<year> - <book> {<narrator>}/
 | 
					  # Standalone structure: ${SRC}/<author>/<year> - <book> {<narrator>}/
 | 
				
			||||||
  # Return the <part> wihh leading zeros based on the LEADING_ZEROES variable
 | 
					  # Return variables as key=value lines; <part> zero-padded to LEADING_ZEROES as series_index
 | 
				
			||||||
 | 
					  local dir="${1%/}"
 | 
				
			||||||
 | 
					  local leaf="${dir##*/}"
 | 
				
			||||||
 | 
					  local parent="${dir%/*}"
 | 
				
			||||||
 | 
					  local grandparent="${parent%/*}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  local author=""
 | 
				
			||||||
 | 
					  local series=""
 | 
				
			||||||
 | 
					  local title=""
 | 
				
			||||||
 | 
					  local year=""
 | 
				
			||||||
 | 
					  local narrator=""
 | 
				
			||||||
 | 
					  local part=""
 | 
				
			||||||
 | 
					  local series_index=""
 | 
				
			||||||
 | 
					  local rest=""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Helper: trim leading/trailing whitespace
 | 
				
			||||||
 | 
					  trim() { local s="$1"; s="${s#${s%%[![:space:]]*}}"; s="${s%${s##*[![:space:]]}}"; printf '%s' "$s"; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Detect pattern and extract fields
 | 
				
			||||||
 | 
					  if [[ "$leaf" =~ ^[Bb]ook[[:space:]]+([0-9]+)[[:space:]]*-[[:space:]]*([0-9]{4})[[:space:]]*-[[:space:]]*(.+)$ ]]; then
 | 
				
			||||||
 | 
					    part="${BASH_REMATCH[1]}"
 | 
				
			||||||
 | 
					    year="${BASH_REMATCH[2]}"
 | 
				
			||||||
 | 
					    rest="${BASH_REMATCH[3]}"
 | 
				
			||||||
 | 
					    if [[ "$rest" =~ ^(.+)[[:space:]]*\{([^}]*)\}[[:space:]]*$ ]]; then
 | 
				
			||||||
 | 
					      title="${BASH_REMATCH[1]}"
 | 
				
			||||||
 | 
					      narrator="${BASH_REMATCH[2]}"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      title="$rest"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    series="${parent##*/}"
 | 
				
			||||||
 | 
					    author="${grandparent##*/}"
 | 
				
			||||||
 | 
					  elif [[ "$leaf" =~ ^([0-9]{4})[[:space:]]*-[[:space:]]*(.+)$ ]]; then
 | 
				
			||||||
 | 
					    year="${BASH_REMATCH[1]}"
 | 
				
			||||||
 | 
					    rest="${BASH_REMATCH[2]}"
 | 
				
			||||||
 | 
					    if [[ "$rest" =~ ^(.+)[[:space:]]*\{([^}]*)\}[[:space:]]*$ ]]; then
 | 
				
			||||||
 | 
					      title="${BASH_REMATCH[1]}"
 | 
				
			||||||
 | 
					      narrator="${BASH_REMATCH[2]}"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      title="$rest"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    author="${parent##*/}"
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    # Fallback best-effort parsing
 | 
				
			||||||
 | 
					    rest="$leaf"
 | 
				
			||||||
 | 
					    if [[ "$rest" =~ \{([^}]*)\}[[:space:]]*$ ]]; then
 | 
				
			||||||
 | 
					      narrator="${BASH_REMATCH[1]}"
 | 
				
			||||||
 | 
					      rest="${rest%\{${narrator}\}*}"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    if [[ "$rest" =~ ^([0-9]{4})[[:space:]]*-[[:space:]]*(.+)$ ]]; then
 | 
				
			||||||
 | 
					      year="${BASH_REMATCH[1]}"
 | 
				
			||||||
 | 
					      title="${BASH_REMATCH[2]}"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      title="$rest"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    author="${parent##*/}"
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Normalize whitespace
 | 
				
			||||||
 | 
					  title="$(trim "$title")"
 | 
				
			||||||
 | 
					  author="$(trim "$author")"
 | 
				
			||||||
 | 
					  series="$(trim "$series")"
 | 
				
			||||||
 | 
					  narrator="$(trim "$narrator")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Zero-pad part for series_index if available
 | 
				
			||||||
 | 
					  if [[ -n "$part" ]]; then
 | 
				
			||||||
 | 
					    part="${part//[^0-9]/}"
 | 
				
			||||||
 | 
					    series_index=$(printf "%0*d" "$LEADING_ZEROES" "$part")
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  printf 'author=%q\n' "$author"
 | 
				
			||||||
 | 
					  printf 'series=%q\n' "$series"
 | 
				
			||||||
 | 
					  printf 'series_index=%q\n' "$series_index"
 | 
				
			||||||
 | 
					  printf 'title=%q\n' "$title"
 | 
				
			||||||
 | 
					  printf 'year=%q\n' "$year"
 | 
				
			||||||
 | 
					  printf 'narrator=%q\n' "$narrator"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
get-book-directories() {
 | 
					get-book-directories() {
 | 
				
			||||||
  # TODO implemet getting the book directoris based on the ${SRC} path
 | 
					  # Discover book directories under ${SRC} (or ${script_dir}/src if unset)
 | 
				
			||||||
  # find the directories that contains the books files and return them as an array
 | 
					  # Matches:
 | 
				
			||||||
  # Example book directory:
 | 
					  # - ${SRC}/<author>/<series>/Book <part> - <year> - <title> {<narrator>}/
 | 
				
			||||||
  # /path/to/src/Author/Series/Book Part - Year - Book {Narrator}/
 | 
					  # - ${SRC}/<author>/<year> - <title> {<narrator>}/
 | 
				
			||||||
  # /path/to/src/Author/Year - Book {Narrator}/
 | 
					  # Prints matched directories, one per line
 | 
				
			||||||
 | 
					  local src_root="${1}"
 | 
				
			||||||
 | 
					  local -a results=()
 | 
				
			||||||
 | 
					  local dir leaf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Iterate candidate depths using fast globbing (avoids slow full-recursive find)
 | 
				
			||||||
 | 
					  for dir in "${src_root}"/*/*/ "${src_root}"/*/*/*/; do
 | 
				
			||||||
 | 
					    [[ -d "$dir" ]] || continue
 | 
				
			||||||
 | 
					    leaf="${dir%/}"; leaf="${leaf##*/}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Match standalone: "YYYY - Title {Narrator}" or similar
 | 
				
			||||||
 | 
					    if [[ "$leaf" =~ ^[0-9]{4}[[:space:]]*-[[:space:]]*.+$ ]]; then
 | 
				
			||||||
 | 
					      :
 | 
				
			||||||
 | 
					    # Match series: "Book N - YYYY - Title {Narrator}" (Book/book, flexible spaces)
 | 
				
			||||||
 | 
					    elif [[ "$leaf" =~ ^[Bb]ook[[:space:]]+[0-9]+[[:space:]]*-[[:space:]]*[0-9]{4}[[:space:]]*-[[:space:]]*.+$ ]]; then
 | 
				
			||||||
 | 
					      :
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      continue
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					  done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  printf '%s\n' "${results[@]}"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
m4b-merge() {
 | 
					m4b-merge() {
 | 
				
			||||||
| 
						 | 
					@ -38,7 +136,7 @@ m4b-merge() {
 | 
				
			||||||
  local series_index=${8}
 | 
					  local series_index=${8}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mkdir -p "$(dirname "${output_file}")"
 | 
					  mkdir -p "$(dirname "${output_file}")"
 | 
				
			||||||
  "${m4b-tool}" \
 | 
					  nix run github:sandreas/m4b-tool#m4b-tool-libfdk -- \
 | 
				
			||||||
    merge \
 | 
					    merge \
 | 
				
			||||||
      -v \
 | 
					      -v \
 | 
				
			||||||
      --jobs=6 \
 | 
					      --jobs=6 \
 | 
				
			||||||
| 
						 | 
					@ -55,7 +153,32 @@ m4b-merge() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main() {
 | 
					main() {
 | 
				
			||||||
 | 
					  local src_root="${SRC:-${script_dir}/src}"
 | 
				
			||||||
 | 
					  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}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      output_file="${out_root}/${author}/${year:+${year} - }${title}${narrator:+ {${narrator}}}.m4b"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo "Processing '$dir' -> '$output_file'"
 | 
				
			||||||
 | 
					    # m4b-merge "$output_file" "$dir" "$author" "$narrator" "$title" "$year" "$series" "$series_index"
 | 
				
			||||||
 | 
					  done
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main "$@"
 | 
					main "$@"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue