app
Adom Video Post-Production
Public Made by Adomby adom
AI-driven studio for finishing demo videos: review every captured clip, flag and re-record the weak ones, speed up dead air, narrate, mux and auto-level, validate the final cut, and publish straight to the wiki, driven end to end by your AI.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
//! Shared HTTP + webview infrastructure for every `adom-video-post` subcommand
//! that exposes a web UI (voiceover, storyboard, future review apps).
//!
//! The pattern is: a subcommand implements the `Routes` trait — returning
//! its embedded UI HTML and handling app-specific routes — and calls
//! `run_webapp(cfg, routes)`. `run_webapp` starts a tiny_http server,
//! handles built-in routes (UI, favicon, /console, /eval, /shutdown),
//! delegates unknown routes to the app, opens a Hydrogen webview tab
//! pointed at the server, and blocks until /shutdown fires. On return
//! the webview tab is removed and the instance registry entry is cleaned
//! up.
//!
//! Built-in routes all apps get for free:
//!
//! GET / embedded UI HTML with EVAL_CLIENT injected
//! GET /index.html same
//! GET /favicon.svg shared favicon
//! GET /favicon.ico shared favicon
//! GET /console tail the in-app log buffer
//! POST /console append a log message (UI → server)
//! DELETE /console clear the log buffer
//! POST /eval queue a hot-patch JS snippet (app-creator §7b)
//! GET /eval/pending UI long-polls this for pending snippets
//! POST /eval/:id/result UI posts the snippet's return value back
//! POST /shutdown exit the server cleanly
//! GET /shutdown same, convenient for curl
//!
//! Apps define their own /state shape, /video routes, and any
//! app-specific command endpoints — anything that isn't in the list
//! above falls through to `Routes::handle`.
pub mod console;
pub mod eval;
pub mod icons;
pub mod registry;
pub mod server;
pub mod tab;
pub mod video;
use std::sync::Arc;
use tiny_http::{Method, Request};
/// Per-app configuration consumed by `run_webapp`.
pub struct WebappConfig {
pub port: u16,
pub tab_name: String,
pub panel_id_override: Option<String>,
pub display_icon: String,
/// Short identifier of the subcommand for the instance registry
/// ("voiceover", "storyboard", etc).
pub subcommand: String,
/// Human-readable title shown in `adom-video-post list`. Usually the
/// input filename or manifest title.
pub title: String,
/// When true, start the HTTP server but skip the Hydrogen webview
/// tab open. Useful when the user is reviewing the app in pup
/// and explicitly does not want a Hydrogen tab to appear, or for
/// AI sessions that drive the page via browser_eval.
pub no_open: bool,
}
/// Outcome returned from `Routes::handle`. Because tiny_http's `Request`
/// is a single-owner value, the app either responds to it (and returns
/// `Handled`) or returns it back so the caller can fall through to a
/// 404 (`NotHandled`).
pub enum RouteOutcome {
Handled(Result<(), String>),
NotHandled(Request),
}
/// Trait every webapp-backed subcommand implements. The server loop
/// calls `ui_html` at startup to serve GET /, and `handle` for any
/// request not claimed by a built-in route.
pub trait Routes: Send + Sync {
/// The embedded UI HTML. A `<!-- EVAL_CLIENT -->` marker in the
/// returned string is replaced with the shared eval_client.js at
/// serve time so every UI automatically gets the hot-patch channel.
fn ui_html(&self) -> &str;
/// The SVG bytes served at `GET /favicon.svg`. Hydrogen reads the
/// loaded page's `<link rel="icon">` after page-load and writes it
/// into `panelState.displayIcon`, overriding whatever placeholder
/// was passed via `--display-icon`. So the stable, post-load tab
/// icon is whatever this method returns — which means each
/// subcommand controls its own tab icon via this favicon, not via
/// the placeholder (see hydrogen-tab-icons skill). Must be a
/// self-contained, square, monochrome `#e6edf3` SVG per the Adom
/// brand rule in `gallia/skills/brand/SKILL.md`.
fn favicon_svg(&self) -> &str;
/// Handle a request the built-in router did not claim. On
/// `NotHandled` the caller responds with a 404.
fn handle(&self, request: Request, method: &Method, url: &str) -> RouteOutcome;
}
/// Run a webapp: start the HTTP server on `cfg.port`, register the
/// instance, open the Hydrogen webview tab, block until /shutdown,
/// then clean up. Returns on clean shutdown or on a hard bind error.
pub fn run_webapp(cfg: WebappConfig, routes: Arc<dyn Routes>) -> Result<(), String> {
server::serve(cfg, routes)
}