| Server IP : 35.80.110.71 / Your IP : 216.73.216.221 Web Server : Apache/2.4.58 (Ubuntu) System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64 User : ubuntu ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/wp/shared/scripts/ |
Upload File : |
#!/usr/bin/env bash
#
# capture-demo-screenshots.sh
#
# Captures a hero-region screenshot of every live demo and uploads it to the
# hub as the featured image of the matching Project post.
#
# - Reads demo list from /var/www/wp/projects/<slug>/ + reverse-mapped URL via
# the Project's live_url meta on hub (single source of truth).
# - Renders with headless Chromium at 1440x900, then ImageMagick crops to a
# 16:9 hero rectangle (1440x810) from the top. The demo banner is off by
# default (opt-in via ?show-demo=1), so nothing is chopped from the top.
# - WP-CLI uploads to the hub media library and atomically sets the Project's
# _thumbnail_id. Old featured image stays in the media library (cleanup is
# manual via wp media regenerate / wp post delete if desired).
#
# Idempotent: rerunning re-uploads with a fresh timestamped filename and
# updates the Project's _thumbnail_id. No de-dup of media library entries
# (kept simple; the active featured image is what counts).
#
# Usage:
# sudo /var/www/wp/shared/scripts/capture-demo-screenshots.sh
# sudo /var/www/wp/shared/scripts/capture-demo-screenshots.sh <slug> # one demo
#
set -euo pipefail
HUB=/var/www/wp/hub/public
WP_HUB="sudo -u www-data wp --path=$HUB"
CHROMIUM=$(command -v chromium-browser || command -v chromium || true)
[ -z "$CHROMIUM" ] && { echo "chromium not found"; exit 1; }
command -v convert >/dev/null || { echo "ImageMagick 'convert' not found"; exit 1; }
# chromium on Ubuntu 22+ ships as a snap whose AppArmor profile blocks writes
# outside the invoking user's home directory and refuses to run as root.
# Two staging dirs:
# RAW: under ubuntu's home (chromium can write there as the ubuntu user)
# OUT: world-readable so www-data can pick up the cropped file for media import
SCREENSHOT_USER=ubuntu
RAW_DIR=$(sudo -u "$SCREENSHOT_USER" mktemp -d -p /home/"$SCREENSHOT_USER" screenshots-XXXXXX)
OUT_DIR=$(mktemp -d -p /tmp screenshots-XXXXXX)
chmod 755 "$OUT_DIR"
trap 'sudo -u "$SCREENSHOT_USER" rm -rf "$RAW_DIR"; rm -rf "$OUT_DIR"' EXIT
ts() { date +%Y%m%d-%H%M%S; }
log() { echo "[$(date +%H:%M:%S)] $*"; }
# Filter slugs if an argument was given
filter="${1:-}"
# Iterate every published Project on hub
$WP_HUB post list --post_type=project --post_status=publish --fields=ID,post_name --format=csv | tail -n +2 |
while IFS=, read -r pid slug; do
[ -n "$filter" ] && [ "$filter" != "$slug" ] && continue
[ -z "$pid" ] || [ -z "$slug" ] && continue
url=$($WP_HUB post meta get "$pid" live_url 2>/dev/null || true)
if [ -z "$url" ]; then
log "skip $slug (no live_url meta on hub)"
continue
fi
log "Capturing $slug @ $url"
raw="$RAW_DIR/$slug-raw.png"
cropped="$OUT_DIR/$slug-$(ts).png"
# Headless render. --virtual-time-budget waits for fonts/web fonts to load.
# Run as the ubuntu user — snap AppArmor refuses root + restricts paths.
sudo -u "$SCREENSHOT_USER" "$CHROMIUM" \
--headless=new \
--no-sandbox \
--disable-gpu \
--hide-scrollbars \
--window-size=1440,900 \
--virtual-time-budget=8000 \
--screenshot="$raw" \
"$url" >/dev/null 2>&1 || { log " ✗ chromium failed for $slug"; continue; }
if [ ! -s "$raw" ]; then
log " ✗ empty screenshot for $slug"
continue
fi
# Crop to a 16:9 (1440x810) hero rectangle from the very top of the page.
# The demo banner is now off by default (sfp-demo-banner.php opts in via
# ?show-demo=1), so the URL we just rendered has no banner to chop.
# convert isn't snap-confined; run as root to write into the world-readable OUT_DIR.
convert "$raw" -crop '1440x810+0+0' +repage "$cropped"
chmod 644 "$cropped"
# Upload to hub media library + set as featured image (atomic via --featured_image)
title="${slug} hero capture"
new_id=$($WP_HUB media import "$cropped" \
--post_id="$pid" \
--featured_image \
--title="$title" \
--alt="Screenshot of the $slug demo homepage" \
--porcelain 2>&1 | tail -1)
if [[ "$new_id" =~ ^[0-9]+$ ]]; then
log " ✓ $slug featured image set (attachment id=$new_id)"
else
log " ✗ media import failed for $slug: $new_id"
fi
done
log "Done."