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