95 lines
2.8 KiB
Bash
Executable file
95 lines
2.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Sides are encoded individually — no concatenation. Idempotent: a side is
|
|
# skipped if its output is newer than its source.
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
MANIFEST="${MANIFEST:-$REPO_ROOT/content/audio.yaml}"
|
|
RAW_DIR="${RAW_DIR:-$REPO_ROOT/content/audio}"
|
|
OUT_DIR="${OUT_DIR:-$REPO_ROOT/web/static/audio}"
|
|
|
|
for tool in yq ffmpeg; do
|
|
if ! command -v "$tool" >/dev/null; then
|
|
echo "error: $tool not in PATH (try: nix develop)" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
if [[ ! -f "$MANIFEST" ]]; then
|
|
echo "error: manifest not found: $MANIFEST" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$OUT_DIR"
|
|
|
|
DEFAULT_BITRATE=$(yq -r '.defaults.bitrate // "64k"' "$MANIFEST")
|
|
DEFAULT_CHANNELS=$(yq -r '.defaults.channels // "2"' "$MANIFEST")
|
|
DEFAULT_RATE=$(yq -r '.defaults.sample_rate // "48000"' "$MANIFEST")
|
|
|
|
encoded=0
|
|
skipped=0
|
|
missing=0
|
|
failed=0
|
|
|
|
NUM_ARTISTS=$(yq '.artists | length' "$MANIFEST")
|
|
|
|
for ((a=0; a<NUM_ARTISTS; a++)); do
|
|
ARTIST_SLUG=$(yq -r ".artists[$a].slug" "$MANIFEST")
|
|
NUM_SHOWS=$(yq ".artists[$a].shows | length" "$MANIFEST")
|
|
|
|
for ((s=0; s<NUM_SHOWS; s++)); do
|
|
SHOW_SLUG=$(yq -r ".artists[$a].shows[$s].slug" "$MANIFEST")
|
|
NUM_SIDES=$(yq ".artists[$a].shows[$s].sides | length" "$MANIFEST")
|
|
|
|
for ((sd=0; sd<NUM_SIDES; sd++)); do
|
|
SIDE_ID=$(yq -r ".artists[$a].shows[$s].sides[$sd].id" "$MANIFEST")
|
|
SOURCE=$(yq -r ".artists[$a].shows[$s].sides[$sd].source" "$MANIFEST")
|
|
BITRATE=$(yq -r ".artists[$a].shows[$s].sides[$sd].bitrate // \"$DEFAULT_BITRATE\"" "$MANIFEST")
|
|
CHANNELS=$(yq -r ".artists[$a].shows[$s].sides[$sd].channels // \"$DEFAULT_CHANNELS\"" "$MANIFEST")
|
|
RATE=$(yq -r ".artists[$a].shows[$s].sides[$sd].sample_rate // \"$DEFAULT_RATE\"" "$MANIFEST")
|
|
|
|
SRC_PATH="$RAW_DIR/$SOURCE"
|
|
OUT_NAME="${ARTIST_SLUG}-${SHOW_SLUG}-${SIDE_ID}.opus"
|
|
OUT_PATH="$OUT_DIR/$OUT_NAME"
|
|
|
|
if [[ ! -f "$SRC_PATH" ]]; then
|
|
printf ' %-50s SKIP (source not present)\n' "$OUT_NAME"
|
|
missing=$((missing + 1))
|
|
continue
|
|
fi
|
|
|
|
if [[ -f "$OUT_PATH" ]]; then
|
|
src_mt=$(stat -c %Y "$SRC_PATH")
|
|
out_mt=$(stat -c %Y "$OUT_PATH")
|
|
if (( out_mt > src_mt )); then
|
|
printf ' %-50s up to date\n' "$OUT_NAME"
|
|
skipped=$((skipped + 1))
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
printf ' %-50s encoding ...\n' "$OUT_NAME"
|
|
|
|
if ffmpeg \
|
|
-i "$SRC_PATH" \
|
|
-c:a libopus -b:a "$BITRATE" -ac "$CHANNELS" -ar "$RATE" \
|
|
-application audio -vbr on -compression_level 10 \
|
|
-y "$OUT_PATH" \
|
|
-hide_banner -loglevel warning -nostdin </dev/null; then
|
|
size=$(du -h "$OUT_PATH" | cut -f1)
|
|
printf ' %-50s done (%s)\n' "$OUT_NAME" "$size"
|
|
encoded=$((encoded + 1))
|
|
else
|
|
printf ' %-50s FAILED\n' "$OUT_NAME" >&2
|
|
failed=$((failed + 1))
|
|
fi
|
|
done
|
|
done
|
|
done
|
|
|
|
printf '\n%d encoded · %d up-to-date · %d missing sources · %d failed\n' \
|
|
"$encoded" "$skipped" "$missing" "$failed"
|
|
|
|
if (( failed > 0 )); then
|
|
exit 1
|
|
fi
|