#!/usr/bin/env bash set -euo pipefail usage() { cat >&2 <<'EOF' Usage: split-cue-flac.sh /path/to/album-folder [--keep-originals] Behavior: - Finds one .cue file in the folder. - Finds the matching single .flac file. - Splits into a temporary directory inside the album folder. - Tags the generated tracks from the CUE. - Verifies generated FLACs. - Moves split tracks back into the album folder. - Deletes the original single FLAC and CUE unless --keep-originals is passed. EOF exit 2 } die() { echo "ERROR: $*" >&2 exit 1 } need_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1" } [[ $# -ge 1 && $# -le 2 ]] || usage album_dir="${1%/}" keep_originals=0 if [[ "${2:-}" == "--keep-originals" ]]; then keep_originals=1 elif [[ $# -eq 2 ]]; then usage fi [[ -d "$album_dir" ]] || die "Not a directory: $album_dir" need_cmd find need_cmd shnsplit need_cmd flac if command -v cuetag.sh >/dev/null 2>&1; then CUETAG_CMD="cuetag.sh" elif command -v cuetag >/dev/null 2>&1; then CUETAG_CMD="cuetag" else die "Missing required command: cuetag.sh or cuetag" fi # Optional but useful validation. HAS_CUEPRINT=0 if command -v cueprint >/dev/null 2>&1; then HAS_CUEPRINT=1 fi mapfile -d '' cue_files < <( find "$album_dir" -maxdepth 1 -type f -iname '*.cue' -print0 | sort -z ) [[ ${#cue_files[@]} -eq 1 ]] || die "Expected exactly one .cue file, found ${#cue_files[@]}" cue_file="${cue_files[0]}" mapfile -d '' flac_files < <( find "$album_dir" -maxdepth 1 -type f -iname '*.flac' -print0 | sort -z ) [[ ${#flac_files[@]} -ge 1 ]] || die "No .flac files found in $album_dir" # Try to identify the source FLAC. # First, if there is exactly one FLAC, use it. # Otherwise, try to match the CUE FILE line by basename/stem. flac_file="" if [[ ${#flac_files[@]} -eq 1 ]]; then flac_file="${flac_files[0]}" else cue_ref="$( awk ' BEGIN { IGNORECASE=1 } /^[[:space:]]*FILE[[:space:]]+/ { line=$0 sub(/^[[:space:]]*FILE[[:space:]]+/, "", line) if (line ~ /^"/) { sub(/^"/, "", line) sub(/"[[:space:]]+[A-Za-z0-9_]+[[:space:]]*$/, "", line) print line exit } else { print $2 exit } } ' "$cue_file" )" if [[ -n "$cue_ref" ]]; then cue_ref_base="$(basename "$cue_ref")" cue_ref_stem="${cue_ref_base%.*}" matches=() for f in "${flac_files[@]}"; do f_base="$(basename "$f")" f_stem="${f_base%.*}" if [[ "$f_base" == "$cue_ref_base" || "$f_stem" == "$cue_ref_stem" ]]; then matches+=("$f") fi done if [[ ${#matches[@]} -eq 1 ]]; then flac_file="${matches[0]}" fi fi [[ -n "$flac_file" ]] || die "Multiple .flac files found and could not determine which one matches the CUE" fi echo "Album dir: $album_dir" echo "CUE: $(basename "$cue_file")" echo "Source: $(basename "$flac_file")" # Validate source FLAC before doing anything. echo "Verifying source FLAC..." flac -t --silent "$flac_file" if [[ "$HAS_CUEPRINT" -eq 1 ]]; then echo "Validating CUE syntax..." cueprint "$cue_file" >/dev/null fi tmp_dir="$(mktemp -d "$album_dir/.cue-split.tmp.XXXXXXXX")" cleanup() { if [[ -d "$tmp_dir" ]]; then rm -rf -- "$tmp_dir" fi } trap cleanup EXIT split_dir="$tmp_dir/split" original_dir="$tmp_dir/originals" mkdir -p "$split_dir" "$original_dir" echo "Splitting into temporary directory..." shnsplit \ -f "$cue_file" \ -o flac \ -t "%n - %t" \ -d "$split_dir" \ "$flac_file" mapfile -d '' split_files < <( find "$split_dir" -maxdepth 1 -type f -iname '*.flac' -print0 | sort -z ) [[ ${#split_files[@]} -gt 0 ]] || die "No split FLAC files were produced" echo "Tagging split tracks from CUE..." "$CUETAG_CMD" "$cue_file" "${split_files[@]}" echo "Verifying split FLAC files..." flac -t --silent "${split_files[@]}" echo "Checking for filename collisions in album directory..." for f in "${split_files[@]}"; do dest="$album_dir/$(basename "$f")" if [[ -e "$dest" ]]; then die "Refusing to overwrite existing file: $dest" fi done echo "Moving original files aside..." mv -- "$flac_file" "$original_dir/" mv -- "$cue_file" "$original_dir/" echo "Moving split tracks into album directory..." for f in "${split_files[@]}"; do mv -- "$f" "$album_dir/" done if [[ "$keep_originals" -eq 1 ]]; then keep_dir="$album_dir/.cue-split-originals" mkdir -p "$keep_dir" echo "Keeping originals in: $keep_dir" mv -- "$original_dir/"* "$keep_dir/" else echo "Deleting original single FLAC and CUE..." rm -rf -- "$original_dir" fi echo "Done."