Files
beets-setup/scripts/utility/split-flac

201 lines
4.6 KiB
Bash
Executable File

#!/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."