#!/usr/bin/env bash # Regenerate the website capture assets: search.webm, manage-indexing.webm, # duplicates.png, query-highlight.png — all landing in packaging/captures/ # (gitignored). Needs a graphical session (X11 or Wayland — screenshots and # video frames are read back from the app's own framebuffer, so the display # server does not matter) and ffmpeg with libx264rgb and libvpx-vp9. # # The app is built with the `capture` feature and drives itself through # packaging/capture-scenario.txt (see crates/quicksearch-gui/src/capture.rs # for the command grammar). It runs against a throwaway index of this # repository plus ~/.cargo/registry/src, under scratch XDG dirs — the real # ~/.config/quicksearch and index are never touched. # # The scratch dirs live OUTSIDE both index roots on purpose: the demo config # has an empty ignore list, so a scratch index database inside an indexed # tree would be indexed and watched by the very run that writes it. set -euo pipefail here="$(cd "$(dirname "$0")" && pwd)" repo="$(dirname "$here")" out="$here/captures" work="${TMPDIR:-/tmp}/quicksearch-capture" # --- preflight -------------------------------------------------------------- if [ -z "${DISPLAY:-}" ] && [ -z "${WAYLAND_DISPLAY:-}" ]; then echo "capture needs a graphical session (neither DISPLAY nor" \ "WAYLAND_DISPLAY is set)" >&2 exit 1 fi for tool in ffmpeg ffprobe cargo; do command -v "$tool" >/dev/null || { echo "missing tool: $tool" >&2; exit 1; } done # The encoder list is captured first: `grep -q` closing the pipe early would # make ffmpeg exit on SIGPIPE, which pipefail reports as failure. encoders="$(ffmpeg -hide_banner -encoders 2>/dev/null)" for enc in libx264rgb libvpx-vp9; do grep -q "$enc" <<< "$encoders" \ || { echo "ffmpeg lacks the $enc encoder" >&2; exit 1; } done # A config.toml beside the binary would silently override the scratch XDG # config entirely (portable mode) — refuse to run with one present. if [ -e "$repo/target/release/config.toml" ]; then echo "remove $repo/target/release/config.toml first: portable mode would" \ "override the capture config" >&2 exit 1 fi registry="$HOME/.cargo/registry/src" [ -d "$registry" ] || { echo "missing demo index root: $registry" >&2; exit 1; } # --- build + parser tests --------------------------------------------------- cargo test --manifest-path "$repo/Cargo.toml" --release --locked \ -p quicksearch-gui --features capture capture:: cargo build --manifest-path "$repo/Cargo.toml" --release --locked \ -p quicksearch-gui --features capture # --- scratch environment ---------------------------------------------------- # Fresh every run: no stale index, no schema-mismatch prompt, and a fresh # app.ron so the window opens at its default 1000x700 geometry. rm -rf "$work" mkdir -p "$work/config/quicksearch" "$work/data" "$work/tmp" "$out" cat > "$work/config/quicksearch/config.toml" <&2; exit 1; } # --- transcode the lossless intermediates to VP9 webm ----------------------- # The recording itself is lossless, so webm quality is decided entirely here. # QS_WEBM_CRF is the knob: constant-quality factor, 0 (best) to 63; UI text # stays crisp around 24-32, and each step of ~6 roughly halves/doubles the # file size. QS_WEBM_CPU trades encode time for compression efficiency # (0 slowest/best to 5 fastest). crf="${QS_WEBM_CRF:-26}" cpu="${QS_WEBM_CPU:-0}" for clip in manage-indexing search; do [ -s "$work/tmp/$clip.cap.mkv" ] \ || { echo "missing recording: $clip.cap.mkv" >&2; exit 1; } # The crop drops at most one row/column: yuv420p needs even dimensions, # and fractional display scaling can make the window an odd size. ffmpeg -y -hide_banner -loglevel warning -i "$work/tmp/$clip.cap.mkv" \ -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" \ -c:v libvpx-vp9 -b:v 0 -crf "$crf" -deadline good -cpu-used "$cpu" \ -row-mt 1 -pix_fmt yuv420p -an "$out/$clip.webm" done mv "$work/tmp/query-highlight.png" "$work/tmp/duplicates.png" "$out/" # --- verify ----------------------------------------------------------------- fail=0 for f in "$out/search.webm" "$out/manage-indexing.webm"; do codec=$(ffprobe -v error -select_streams v:0 \ -show_entries stream=codec_name -of csv=p=0 "$f") dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$f") [ "$codec" = vp9 ] || { echo "FAIL: $f codec=$codec" >&2; fail=1; } awk -v d="$dur" 'BEGIN{exit !(d>=4 && d<=60)}' \ || { echo "FAIL: $f duration=${dur}s (expected 4-60s)" >&2; fail=1; } echo "OK: $f (vp9, ${dur}s)" done for f in "$out/duplicates.png" "$out/query-highlight.png"; do dims=$(ffprobe -v error -select_streams v:0 \ -show_entries stream=width,height -of csv=p=0 "$f") echo "OK: $f (${dims})" done [ "$fail" -eq 0 ] # $work is kept for post-mortems (app stderr is on this terminal; the scratch # index and raw .cap.mkv files live there) and recreated fresh next run. echo echo "Assets:" ls -l "$out"/*.webm "$out"/*.png