#!/bin/bash
# Static LGPL-only ffmpeg for the Tastemaker bundle (arm64 macOS).
#
# Why this exists: the app may not ship the Homebrew/evermeet ffmpeg builds —
# they are GPL-enabled (--enable-gpl, libx264, ...), which is incompatible with
# a paid closed-source app. This script compiles the binary we actually bundle:
# LGPL-2.1-only, static (no Homebrew dylib deps), containing exactly what the
# engine needs — decode mp3/aac(m4a/alac)/flac/wav/ogg, aresample + loudnorm
# (all avfilter filters are kept: loudnorm/afade/aresample plus the implicit
# abuffer/aformat conversion filters), and mp3 encode via libmp3lame (LGPL).
#
# LGPL compliance for the shipped binary (see THIRD_PARTY_LICENSES.md):
#   - exact source: ffmpeg $FFVERSION from $TARBALL_URL (sha256 pinned below)
#   - this script IS the published build recipe
#   - ffmpeg runs as a separate spawned process, never linked into the app
#
# Prereqs: Xcode command line tools, Homebrew lame (brew install lame).
# Output:  ffmpeg-build/out/ffmpeg  (bundled via electron-builder extraResources)
# Verify:  `out/ffmpeg -version` must NOT contain --enable-gpl;
#          `out/ffmpeg -filters | grep loudnorm` must hit;
#          `otool -L out/ffmpeg` must list only /usr/lib + system frameworks.
set -euo pipefail

FFVERSION="8.1"
TARBALL_URL="https://ffmpeg.org/releases/ffmpeg-${FFVERSION}.tar.xz"
# sha256 of ffmpeg-8.1.tar.xz, recorded from the first TLS download 08-28-2026.
TARBALL_SHA256="b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a"

HERE="$(cd "$(dirname "$0")" && pwd)"
SRC="$HERE/src"
OUT="$HERE/out"
JOBS="$(sysctl -n hw.ncpu)"

[ "$(uname -m)" = "arm64" ] || { echo "arm64 host required (universal comes later)"; exit 1; }

LAME_PREFIX="$(brew --prefix lame 2>/dev/null || true)"
[ -f "$LAME_PREFIX/lib/libmp3lame.a" ] || { echo "libmp3lame.a not found — brew install lame"; exit 1; }
# The LAME source published at craterunner.app/open-source is 3.100; a newer
# lame must have its source published there too before it ships (LGPL).
LAME_VERSION="$(brew list --versions lame | awk '{print $2}')"
[ "$LAME_VERSION" = "3.100" ] || { echo "lame is $LAME_VERSION, expected 3.100: publish its source first, then update this check"; exit 1; }

# Link lame from a shim dir holding ONLY the static archive, so the linker can
# never pick up libmp3lame.dylib (a Homebrew path would break stranger Macs).
LAME_SHIM="$HERE/.lame-static"
mkdir -p "$LAME_SHIM"
cp -f "$LAME_PREFIX/lib/libmp3lame.a" "$LAME_SHIM/"

mkdir -p "$SRC" "$OUT"
cd "$SRC"
if [ ! -f "ffmpeg-${FFVERSION}.tar.xz" ]; then
  curl -fL --proto '=https' -o "ffmpeg-${FFVERSION}.tar.xz" "$TARBALL_URL"
fi
echo "${TARBALL_SHA256}  ffmpeg-${FFVERSION}.tar.xz" | shasum -a 256 -c -
rm -rf "ffmpeg-${FFVERSION}"
tar xf "ffmpeg-${FFVERSION}.tar.xz"
cd "ffmpeg-${FFVERSION}"

./configure \
  --prefix="$SRC/install" \
  --disable-gpl --disable-nonfree --disable-shared --enable-static \
  --disable-autodetect \
  --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \
  --disable-ffplay --disable-ffprobe \
  --disable-network --disable-debug \
  --disable-decoders --enable-decoder="mp3,mp3float,aac,aac_latm,alac,flac,vorbis,opus,pcm_s16le,pcm_s16be,pcm_u8,pcm_s24le,pcm_s24be,pcm_s32le,pcm_s32be,pcm_f32le,pcm_f32be,pcm_f64le,pcm_alaw,pcm_mulaw" \
  --disable-demuxers --enable-demuxer="mp3,mov,aac,flac,wav,ogg" \
  --disable-encoders --enable-encoder="libmp3lame,pcm_f32le,pcm_s16le" \
  --disable-muxers --enable-muxer="mp3,pcm_f32le,pcm_s16le,wav,null" \
  --disable-protocols --enable-protocol="file,pipe" \
  --disable-indevs --disable-outdevs --enable-indev=lavfi \
  --enable-zlib \
  --enable-libmp3lame \
  --extra-cflags="-I$LAME_PREFIX/include" \
  --extra-ldflags="-L$LAME_SHIM" \
  --arch=arm64 --cc=clang

make -j"$JOBS"
cp -f ffmpeg "$OUT/ffmpeg"
strip "$OUT/ffmpeg" || true
# strip invalidates the linker's ad-hoc signature and arm64 macOS kills
# unsigned binaries on exec — re-sign ad-hoc (this is NOT distribution signing).
codesign -s - -f "$OUT/ffmpeg"

echo
echo "=== verification ==="
BIN="$OUT/ffmpeg"

# NOTE: checks capture output first — `cmd | grep -q` under pipefail reports
# failure when grep exits early and the producer takes SIGPIPE.
VER="$("$BIN" -version)"
grep -q "^configuration:" <<<"$VER" || { echo "FAIL: binary did not run"; exit 1; }
if grep -q -- "--enable-gpl" <<<"$VER"; then
  echo "FAIL: build is GPL-enabled"; exit 1
fi
echo "OK: binary runs, no --enable-gpl in the configuration"

FILTERS="$("$BIN" -hide_banner -filters 2>/dev/null)"
grep -q loudnorm <<<"$FILTERS" || { echo "FAIL: loudnorm missing"; exit 1; }
echo "OK: loudnorm filter present"

LINKED="$(otool -L "$BIN" | tail -n +2)"
if grep -vE "^\s+(/usr/lib/|/System/)" <<<"$LINKED" | grep -q .; then
  echo "FAIL: non-system dynamic libraries linked:"; otool -L "$BIN"; exit 1
fi
echo "OK: only system dylibs/frameworks linked"

# Functional smoke: sine -> loudnorm+fades -> libmp3lame (the exact filter/encoder
# path snippet.mjs uses), then decode that mp3 back to f32le (embed.mjs's path).
TMP="$(mktemp -d)"
"$BIN" -hide_banner -loglevel error -f lavfi -i "sine=frequency=440:duration=3" \
  -ac 2 -ar 44100 -af "loudnorm=I=-14:TP=-1.5,afade=t=in:d=0.3,afade=t=out:st=2.5:d=0.5" \
  -c:a libmp3lame -q:a 4 "$TMP/t.mp3"
"$BIN" -hide_banner -loglevel error -i "$TMP/t.mp3" -f f32le -acodec pcm_f32le -ac 1 -ar 48000 "$TMP/t.raw"
[ -s "$TMP/t.raw" ] || { echo "FAIL: decode produced no samples"; exit 1; }
echo "OK: loudnorm+lame encode and f32le decode round-trip"

# Format coverage (needs any system ffmpeg to synthesize the fixtures; skipped
# cleanly if none is installed — the round-trip above already ran regardless).
SYS_FF="$(command -v ffmpeg || true)"
if [ -n "$SYS_FF" ] && [ "$SYS_FF" != "$BIN" ]; then
  "$SYS_FF" -hide_banner -loglevel error -y -f lavfi -i "sine=frequency=440:duration=2" "$TMP/f.wav"
  "$SYS_FF" -hide_banner -loglevel error -y -i "$TMP/f.wav" -c:a aac "$TMP/f.m4a"
  "$SYS_FF" -hide_banner -loglevel error -y -i "$TMP/f.wav" -c:a alac "$TMP/f_alac.m4a"
  "$SYS_FF" -hide_banner -loglevel error -y -i "$TMP/f.wav" -c:a flac "$TMP/f.flac"
  "$SYS_FF" -hide_banner -loglevel error -y -i "$TMP/f.wav" -c:a libopus "$TMP/f.ogg" 2>/dev/null \
    || "$SYS_FF" -hide_banner -loglevel error -y -i "$TMP/f.wav" -c:a libvorbis "$TMP/f.ogg" 2>/dev/null || true
  for f in "$TMP/f.wav" "$TMP/f.m4a" "$TMP/f_alac.m4a" "$TMP/f.flac" "$TMP/f.ogg"; do
    [ -f "$f" ] || continue
    "$BIN" -hide_banner -loglevel error -i "$f" -f f32le -acodec pcm_f32le -ac 1 -ar 48000 - > "$TMP/d.raw"
    [ -s "$TMP/d.raw" ] || { echo "FAIL: could not decode $(basename "$f")"; exit 1; }
    echo "OK: decodes $(basename "$f")"
  done
else
  echo "skip: no system ffmpeg for format fixtures"
fi
rm -rf "$TMP"

echo
echo "Built: $OUT/ffmpeg ($(du -h "$OUT/ffmpeg" | cut -f1 | tr -d ' '))"
