Files
PastilhasandClaude Opus 5 81c8e17a8e Start av-club: what it is, and a verified installer
Media processing pulled out of the website that first needed it. ffmpeg,
ImageMagick, libvips and exiftool are a real installation rather than an npm
install, and encoder settings get revisited as browser support moves — neither of
which belongs on the same clock as page templates and database schemas.

No processing code yet. What is here is the tooling requirement, an installer, and
docs/PIPELINE.md writing down what has NOT been decided — how a consumer talks to
this, whether processing blocks an upload, where output goes — so those get chosen
deliberately instead of by whatever gets written first.

verify.sh checks by running: it encodes a video and probes the result against what
ffmpeg was told to make, loads sharp under Bun specifically, and asserts a
re-encode still strips GPS. That last one guards a real leak — if a future sharp
changes its default, this fails a check rather than quietly publishing the
coordinates of a client's living room. Confirmed non-vacuous by hiding ffmpeg and
watching it exit 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 02:18:14 +01:00

147 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Check the media tooling by RUNNING it, not by asking the package manager whether it is present.
#
# A package can be installed and still not work: sharp is a native module that can resolve to a
# broken wasm build, and a codec can be missing from an ffmpeg that reports a version happily. Every
# check here does real work and compares the result against what was asked for.
#
# Exits non-zero if anything fails, so it is usable in CI or as the last step of install.sh.
set -uo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
FAILED=0
pass() { printf ' \033[32mok\033[0m %s\n' "$1"; }
fail() { printf ' \033[31mFAIL\033[0m %s\n' "$1"; FAILED=1; }
note() { printf ' \033[33m--\033[0m %s\n' "$1"; }
echo
echo "Binaries on PATH"
# `magick` is deliberately absent from this list: Ubuntu 24.04 ships ImageMagick 6, which provides
# convert/identify and no `magick`. See docs/TOOLING.md.
for cmd in ffmpeg ffprobe convert identify exiftool vipsthumbnail cwebp dwebp avifenc avifdec; do
if command -v "$cmd" >/dev/null 2>&1; then
pass "$cmd"
else
fail "$cmd is not on PATH"
fi
done
echo
echo "ffmpeg encodes and ffprobe reads back what was asked for"
if ffmpeg -hide_banner -loglevel error \
-f lavfi -i testsrc=duration=3:size=1280x720:rate=30 \
-c:v libx264 -pix_fmt yuv420p "$WORK/test.mp4" 2>"$WORK/ffmpeg.err"; then
probe=$(ffprobe -v error \
-show_entries stream=codec_name,width,height \
-show_entries format=duration \
-of default=noprint_wrappers=1 "$WORK/test.mp4" 2>/dev/null)
# Compared against what ffmpeg was TOLD to produce. A version string proves nothing; this proves
# the h264 encoder is actually present and the container is readable.
for expect in "codec_name=h264" "width=1280" "height=720" "duration=3.000000"; do
if grep -qx "$expect" <<<"$probe"; then pass "$expect"; else fail "expected $expect"; fi
done
else
fail "ffmpeg could not encode h264: $(head -1 "$WORK/ffmpeg.err")"
fi
echo
echo "ffmpeg extracts a poster frame"
if ffmpeg -hide_banner -loglevel error -i "$WORK/test.mp4" -ss 1 -frames:v 1 "$WORK/poster.jpg" 2>/dev/null \
&& [ -s "$WORK/poster.jpg" ]; then
pass "poster.jpg $(identify -format '%wx%h' "$WORK/poster.jpg" 2>/dev/null)"
else
fail "could not extract a poster frame"
fi
echo
echo "sharp runs under Bun"
# Run with the REPO as cwd, deliberately. Resolved from anywhere else, Bun finds sharp in its global
# install cache and lands on the wasm32 build, which is missing @emnapi/runtime and dies with
# "sharp.libvipsVersion is not a function" — a broken-looking failure that is not a broken install.
if [ -d "$REPO_ROOT/node_modules/sharp" ]; then
if out=$(cd "$REPO_ROOT" && bun -e '
import sharp from "sharp";
const px = 64;
const src = await sharp({ create: { width: 300, height: 200, channels: 3, background: "#888" } })
.jpeg().toBuffer();
for (const fmt of ["webp", "avif", "jpeg"]) {
const buf = await sharp(src).resize(px)[fmt]().toBuffer();
const m = await sharp(buf).metadata();
if (m.width !== px) throw new Error(`${fmt}: expected ${px}px, got ${m.width}`);
}
console.log(`${sharp.versions.sharp} libvips ${sharp.versions.vips}`);
' 2>&1); then
pass "sharp $out"
else
fail "sharp failed under Bun: $(tail -3 <<<"$out" | tr '\n' ' ')"
fi
else
note "sharp not installed — run 'bun install' in $REPO_ROOT"
FAILED=1
fi
echo
echo "exiftool reads metadata, and a sharp re-encode strips it"
if [ -s "$WORK/poster.jpg" ]; then
exiftool -q -overwrite_original \
-GPSLatitude=38.7223 -GPSLatitudeRef=N \
-GPSLongitude=-9.1393 -GPSLongitudeRef=W \
-Make="Apple" -Model="iPhone 15 Pro" "$WORK/poster.jpg" 2>/dev/null
if exiftool -s3 -GPSLatitude "$WORK/poster.jpg" 2>/dev/null | grep -q .; then
pass "exiftool wrote and read back GPS tags"
if [ -d "$REPO_ROOT/node_modules/sharp" ] \
&& (cd "$REPO_ROOT" && bun -e "
import sharp from 'sharp';
await sharp('$WORK/poster.jpg').resize(300).jpeg().toFile('$WORK/stripped.jpg');
" 2>/dev/null); then
# The point of the check: sharp drops EXIF unless .withMetadata() is called. If that ever
# stops being true, client GPS coordinates start getting published and nothing else says so.
leaked=$(exiftool -s3 -GPSLatitude -GPSLongitude -Make -Model "$WORK/stripped.jpg" 2>/dev/null | grep -c .)
if [ "$leaked" -eq 0 ]; then
pass "GPS, Make and Model gone after re-encode"
else
fail "$leaked identifying tag(s) SURVIVED the re-encode"
fi
else
note "skipped strip check — sharp unavailable"
fi
else
fail "exiftool could not write test tags"
fi
else
note "skipped — no poster frame to test with"
fi
echo
echo "Command-line encoders"
cwebp -quiet "$WORK/poster.jpg" -o "$WORK/t.webp" 2>/dev/null && [ -s "$WORK/t.webp" ] \
&& pass "cwebp" || fail "cwebp"
avifenc -s 10 "$WORK/poster.jpg" "$WORK/t.avif" >/dev/null 2>&1 && [ -s "$WORK/t.avif" ] \
&& pass "avifenc" || fail "avifenc"
vipsthumbnail "$WORK/poster.jpg" -s 100 -o "$WORK/thumb-%s.jpg" >/dev/null 2>&1 \
&& [ -s "$WORK/thumb-poster.jpg" ] && pass "vipsthumbnail" || fail "vipsthumbnail"
echo
if [ "$FAILED" -eq 0 ]; then
printf '\033[32mAll checks passed.\033[0m\n\n'
else
printf '\033[31mSomething failed above.\033[0m See docs/TOOLING.md.\n\n'
fi
exit "$FAILED"