Files
blackroad/bin/br-video
Alexa Amundson 78fbe80f2a Initial monorepo — everything BlackRoad in one place
bin/       230 CLI tools (ask-*, br-*, agent-*, roadid, carpool)
scripts/   99 automation scripts
fleet/     Node configs and deployment
workers/   Cloudflare Worker sources (roadpay, road-search, squad webhooks)
roadc/     RoadC programming language
roadnet/   Mesh network (5 APs, WireGuard)
operator/  Memory system scripts
config/    System configs
dotfiles/  Shell configs
docs/      Documentation

BlackRoad OS — Pave Tomorrow.

RoadChain-SHA2048: d1a24f55318d338b
RoadChain-Identity: alexa@sovereign
RoadChain-Full: d1a24f55318d338b24b60bad7be39286379c76ae5470817482100cb0ddbbcb97e147d07ac7243da0a9f0363e4e5c833d612b9c0df3a3cd20802465420278ef74875a5b77f55af6fe42a931b8b635b3d0d0b6bde9abf33dc42eea52bc03c951406d8cbe49f1a3d29b26a94dade05e9477f34a7d4d4c6ec4005c3c2ac54e73a68440c512c8e83fd9b1fe234750b898ef8f4032c23db173961fe225e67a0432b5293a9714f76c5c57ed5fdf35b9fb40fd73c03ebf88b7253c6a0575f5afb6a6b49b3bda310602fb1ef676859962dad2aebbb2875814b30eee0a8ba195e482d4cbc91d8819e7f38f6db53e8063401649c77bb994371473cabfb917fb53e8cbe73d60
2026-03-14 17:08:41 -05:00

224 lines
8.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# br-video — BlackRoad Video Production System
# Usage: br-video [list|preview|record|serve] [video-name]
set -e
PINK='\033[38;5;205m'
AMBER='\033[38;5;214m'
GREEN='\033[38;5;82m'
BLUE='\033[38;5;69m'
VIOLET='\033[38;5;135m'
RESET='\033[0m'
VIDEOS_DIR="$HOME/blackroad-operator/videos"
case "${1:-list}" in
list)
echo -e "${PINK}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${PINK} BlackRoad Video Library${RESET}"
echo -e "${PINK}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo ""
for category in brand product social tutorials roadtv; do
if [[ -d "$VIDEOS_DIR/$category" ]]; then
echo -e " ${VIOLET}$category${RESET}"
for f in "$VIDEOS_DIR/$category"/*.html; do
[[ -f "$f" ]] || continue
name=$(basename "$f" .html)
title=$(grep -m1 '<title>' "$f" | sed 's/.*<title>\(.*\)<\/title>.*/\1/' 2>/dev/null || echo "$name")
# Detect aspect ratio
if grep -q 'width=1080.*height=1920\|width:1080.*height:1920' "$f" 2>/dev/null; then
ratio="9:16"
else
ratio="16:9"
fi
echo -e " ${GREEN}${name}${RESET} ${BLUE}[$ratio]${RESET} $title"
done
echo ""
fi
done
;;
preview|open)
video="${2:-}"
if [[ -z "$video" ]]; then
echo -e "${AMBER}Usage: br-video preview <category/name>${RESET}"
echo -e " Example: br-video preview brand/01-manifesto"
exit 1
fi
file="$VIDEOS_DIR/${video}.html"
if [[ ! -f "$file" ]]; then
# Try finding it
file=$(find "$VIDEOS_DIR" -name "${video}*.html" 2>/dev/null | head -1)
fi
if [[ -f "$file" ]]; then
echo -e "${GREEN}Opening: $file${RESET}"
open "$file"
else
echo -e "${AMBER}Video not found: $video${RESET}"
exit 1
fi
;;
serve)
port="${2:-8888}"
echo -e "${PINK}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${PINK} Video Preview Server${RESET}"
echo -e "${PINK}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo ""
echo -e " ${GREEN}Serving at: http://localhost:${port}${RESET}"
echo -e " ${BLUE}Videos dir: $VIDEOS_DIR${RESET}"
echo ""
echo -e " ${VIOLET}Brand:${RESET}"
for f in "$VIDEOS_DIR/brand"/*.html; do
[[ -f "$f" ]] && echo -e " http://localhost:${port}/brand/$(basename "$f")"
done
echo -e " ${VIOLET}Product:${RESET}"
for f in "$VIDEOS_DIR/product"/*.html; do
[[ -f "$f" ]] && echo -e " http://localhost:${port}/product/$(basename "$f")"
done
echo -e " ${VIOLET}Social:${RESET}"
for f in "$VIDEOS_DIR/social"/*.html; do
[[ -f "$f" ]] && echo -e " http://localhost:${port}/social/$(basename "$f")"
done
echo -e " ${VIOLET}Tutorials:${RESET}"
for f in "$VIDEOS_DIR/tutorials"/*.html; do
[[ -f "$f" ]] && echo -e " http://localhost:${port}/tutorials/$(basename "$f")"
done
echo -e " ${VIOLET}RoadTV:${RESET}"
for f in "$VIDEOS_DIR/roadtv"/*.html; do
[[ -f "$f" ]] && echo -e " http://localhost:${port}/roadtv/$(basename "$f")"
done
echo ""
cd "$VIDEOS_DIR" && python3 -m http.server "$port"
;;
record)
video="${2:-}"
if [[ -z "$video" ]]; then
echo -e "${AMBER}Usage: br-video record <category/name> [duration-seconds]${RESET}"
exit 1
fi
duration="${3:-30}"
file="$VIDEOS_DIR/${video}.html"
if [[ ! -f "$file" ]]; then
file=$(find "$VIDEOS_DIR" -name "${video}*.html" 2>/dev/null | head -1)
fi
if [[ ! -f "$file" ]]; then
echo -e "${AMBER}Video not found: $video${RESET}"
exit 1
fi
output_dir="$HOME/blackroad-operator/videos/output"
mkdir -p "$output_dir"
output_name=$(basename "$file" .html)
output_file="$output_dir/${output_name}-$(date +%Y%m%d).mp4"
# Detect dimensions
if grep -q 'width=1080.*height=1920\|width:1080.*height:1920' "$file" 2>/dev/null; then
width=1080; height=1920
else
width=1920; height=1080
fi
echo -e "${PINK}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${PINK} Recording: $(basename "$file")${RESET}"
echo -e "${PINK}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo ""
echo -e " ${BLUE}Resolution:${RESET} ${width}x${height}"
echo -e " ${BLUE}Duration:${RESET} ${duration}s"
echo -e " ${BLUE}Output:${RESET} $output_file"
echo ""
# Check for puppeteer/playwright
if command -v npx &>/dev/null && npx playwright --version &>/dev/null 2>&1; then
echo -e "${GREEN}Using Playwright to record...${RESET}"
# Start local server
cd "$VIDEOS_DIR"
python3 -m http.server 9876 &
SERVER_PID=$!
sleep 1
# Record with playwright
node -e "
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: $width, height: $height } });
await page.goto('http://localhost:9876/$(dirname "$video")/$(basename "$file")');
// Screenshot sequence for ffmpeg
const frames = $duration * 30;
const outputDir = '$output_dir/frames-${output_name}';
require('fs').mkdirSync(outputDir, { recursive: true });
for (let i = 0; i < frames; i++) {
await page.screenshot({ path: outputDir + '/frame-' + String(i).padStart(5, '0') + '.png' });
await page.waitForTimeout(33);
}
await browser.close();
console.log('Frames captured. Converting to video...');
})();
" 2>/dev/null
kill $SERVER_PID 2>/dev/null
# Convert frames to video with ffmpeg
if command -v ffmpeg &>/dev/null; then
ffmpeg -framerate 30 -i "$output_dir/frames-${output_name}/frame-%05d.png" \
-c:v libx264 -pix_fmt yuv420p -crf 18 "$output_file" -y 2>/dev/null
rm -rf "$output_dir/frames-${output_name}"
echo -e "${GREEN}✓ Video saved: $output_file${RESET}"
else
echo -e "${AMBER}ffmpeg not found. Frames saved to: $output_dir/frames-${output_name}/${RESET}"
fi
else
echo -e "${AMBER}For automated recording, install playwright: npm i -g playwright${RESET}"
echo -e "${AMBER}Or use OBS/screen recording with: br-video preview $video${RESET}"
echo ""
echo -e "${GREEN}Opening in browser for manual recording...${RESET}"
open "$file"
fi
;;
create)
shift
exec br-video-create "$@"
;;
example)
echo -e "${GREEN}Generating example config...${RESET}"
br-video-create --example > "$VIDEOS_DIR/example-config.json"
echo -e "${GREEN}✓ Saved: $VIDEOS_DIR/example-config.json${RESET}"
echo -e "${BLUE} Edit it, then: br-video create example-config.json output.html${RESET}"
;;
types)
br-video-create --types
;;
*)
echo -e "${PINK}br-video${RESET} — BlackRoad Video Production"
echo ""
echo -e " ${GREEN}list${RESET} List all videos"
echo -e " ${GREEN}preview${RESET} <name> Open video in browser"
echo -e " ${GREEN}serve${RESET} [port] Start preview server (default: 8888)"
echo -e " ${GREEN}record${RESET} <name> [seconds] Record video to MP4"
echo -e " ${GREEN}create${RESET} <config> [output] Generate video from JSON config"
echo -e " ${GREEN}example${RESET} Generate example config file"
echo -e " ${GREEN}types${RESET} List available scene types"
echo ""
echo -e " ${VIOLET}Scene Types:${RESET}"
echo -e " title, subtitle, bigtext, quote, stats, bullets, cards,"
echo -e " timeline, terminal, comparison, code, split, flow,"
echo -e " metrics, image, logos, cta, countdown, reveal"
echo ""
echo -e " Examples:"
echo -e " br-video preview brand/01-manifesto"
echo -e " br-video serve 8888"
echo -e " br-video record social/01-30s-intro 30"
echo -e " br-video create my-config.json videos/brand/03-new.html"
;;
esac