#!/usr/bin/env bash # Interactive manifest builder for the Project Loading scene. # # ./loading.sh # # Walks you through 5 prompts, writes loading.json + loading.js, then # refresh the Project Loading browser source in OBS. Re-running uses # previous answers as defaults — press Enter to keep them. set -euo pipefail DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" JSON="$DIR/loading.json" JS="$DIR/loading.js" # Reads a top-level field from the previous loading.json. Always exits 0; # prints empty string if file/field is missing. prev() { [[ -f "$JSON" ]] || return 0 python3 - "$JSON" "$1" <<'PY' 2>/dev/null || true import json, sys try: d = json.load(open(sys.argv[1])) v = d.get(sys.argv[2]) if v is None: print('') elif isinstance(v, bool): print('y' if v else 'n') else: print(v) except Exception: pass PY } ask() { # ask "question" "default" → echoes user input or default if blank local q="$1" def="${2:-}" local prompt=" $q" [[ -n "$def" ]] && prompt+=" [$def]" prompt+=": " local v read -rp "$prompt" v [[ -z "$v" && -n "$def" ]] && v="$def" printf '%s' "$v" } ask_yn() { local v; v=$(ask "$1" "${2:-y}") case "${v,,}" in y|yes|on|true|1) printf 'true' ;; n|no|off|false|0) printf 'false' ;; *) printf 'true' ;; esac } ask_int() { local v while :; do v=$(ask "$1" "${2:-}") [[ "$v" =~ ^[0-9]+$ ]] && { printf '%s' "$v"; return; } echo " ✗ must be a whole number" >&2 done } sanitize() { printf '%s' "${1:-}" \ | tr -d '"\\' \ | tr '\n\r\t' ' ' \ | sed 's/ */ /g; s/^ //; s/ $//' } emit_str() { [[ -z "${1:-}" ]] && printf 'null' || printf '"%s"' "$1"; } # ── Pull previous answers as defaults ─────────────── prev_game=$(prev game) prev_subtitle=$(prev subtitle) prev_count=$(prev countdownMin); [[ -z "$prev_count" ]] && prev_count="5" prev_camera=$(prev camera); [[ -z "$prev_camera" ]] && prev_camera="y" prev_mic=$(prev microphone); [[ -z "$prev_mic" ]] && prev_mic="y" echo "── Project Loading manifest ──" echo " (press Enter to keep [defaults])" echo game=$(ask "Game" "$prev_game") while [[ -z "$game" ]]; do echo " ✗ Game is required" >&2 game=$(ask "Game" "") done subtitle=$(ask "Subtitle (mode / episode / note)" "$prev_subtitle") countdown=$(ask_int "Countdown (minutes)" "$prev_count") camera=$(ask_yn "Camera" "$prev_camera") mic=$(ask_yn "Microphone" "$prev_mic") game=$(sanitize "$game") subtitle=$(sanitize "$subtitle") now_iso=$(date -u +%FT%TZ) tmp="$JSON.tmp.$$" cat > "$tmp" </dev/null 2>&1; then echo " ✗ produced invalid JSON, leaving $tmp for inspection" >&2 exit 1 fi mv -f "$tmp" "$JSON" { printf 'window.__LOADING = '; cat "$JSON"; printf ';\n'; } > "$JS.tmp.$$" mv -f "$JS.tmp.$$" "$JS" echo echo " ✓ wrote $JSON" echo " ✓ wrote $JS" echo " → refresh the Project Loading browser source in OBS."