feat(themes): motion-video intros via loopback streaming server#226
feat(themes): motion-video intros via loopback streaming server#226Wangnov wants to merge 1 commit into
Conversation
Align the theme engine with awesome studio's motionAssets contract (SPEC §2a) so skins can play an opening video — delivered over a loopback HTTP streaming server instead of base64 data URLs, which don't scale (a 7 MB clip becomes ~9.5 MB of base64 re-shipped over CDP on every reload, near tungstenite's message cap). - media_server.rs: 127.0.0.1 HTTP server with Range/206 streaming, per-start path token, loopback Host check; resolves only the currently applied theme's declared motionAssets, keyed by manifest id (not directory name). - payload.rs: motion assets become loopback URLs on the __CTS_MOTION_JSON__ channel, never inlined; the stamp folds each video's size+mtime so a swapped file re-injects at a stable URL; has_motion drives the CSP lift. - theme.rs: motionAssets (mp4/webm) load into a separate map with an independent 24 MB per-file cap; assets/previews reject video mimes. - theme-runtime.js: 4-arg IIFE; playIntro mounts a muted, PiP-disabled <video>; prefers-reduced-motion / missing server / play failure fall back to art. - cdp.rs + daemon.rs: lift CSP (Page.setBypassCSP, best-effort) before injecting a motion payload — Codex's app:// page ships `media-src 'self' app: blob: data:`, which blocks the loopback <video>. 53 unit tests (ranged streaming, token/Host/id rejection, URL vs static fallback, swapped-video re-stamp, mp4 .codexskin import). clippy -D warnings clean on host + x86_64-pc-windows-msvc; src-tauri integrates.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae0ceed2ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // loopback stream — Codex's media-src blocks it otherwise. | ||
| // Best-effort: a failure just leaves the static intro. | ||
| if payload.has_motion { | ||
| let _ = session.bypass_csp().await; |
There was a problem hiding this comment.
Enable CSP bypass before page load
In the normal daemon path, sessions are attached to already-loaded Codex targets and probed before this branch runs, so calling Page.setBypassCSP here is too late to affect the document's initialized CSP; Puppeteer's CDP wrapper documents that CSP bypassing happens at CSP initialization and should be set before navigation. For motion themes on an existing renderer, Codex's media-src will still block the loopback <video> URL and the new intro path will always fall back to static art unless the page is reloaded after enabling bypass or the media source is otherwise allowed.
Useful? React with 👍 / 👎.
feat(themes): motion-video intros via a loopback streaming server
Aligns the Rust theme engine with awesome studio's new
motionAssetsruntimecontract (SPEC §2a) so packages like
ning-hongye-crimson-nightplay theiropening video — but delivers the video over a loopback HTTP streaming
server instead of the studio's inlined data URLs.
Why not data URLs
Base64-inlining a 7 MB clip means ~9.5 MB of text embedded in the injected
payload, re-
Runtime.evaluated over CDP on every renderer reload (the daemonalready frets about "pointless 30 MB evaluates"), SHA1'd into the stamp, and
held in memory several times over — near tungstenite's 64 MB message cap for a
single large asset. It works for a demo and collapses past it.
Approach
media_server.rs(new): the daemon binds a127.0.0.1:0HTTP server withRange/206 support.
<video>streams natively; reloads just re-fetch the URL —zero video bytes over CDP, scales to any size. Hardened with a per-start random
path token, a loopback
Hostcheck, and resolution restricted to thecurrently applied theme's declared
motionAssets(paths from validatedload_theme) — it cannot serve arbitrary files, and carries no CORS headers.payload.rs: motion assets become loopback URLs on a dedicated__CTS_MOTION_JSON__channel (never CSS variables, never inlined). Without aserver the map is empty → static-intro fallback. The stamp folds each motion
file's size+mtime so a swapped video re-injects/replays at a stable URL, with
the bytes stat'd, never read.
theme.rs:motionAssets(mp4/webm) load into a separatemotion_assetsmap with an independent 24 MB per-file cap (exempt from the CSS 1.4 MB cap and
the combined budget, since they never ride the payload).
assets/previewsnow reject video mimes so video can't slip into a CSS background.
theme-runtime.js: 4-arg IIFE;playIntromounts a muted, PiP-disabled<video>over the static art.prefers-reduced-motion, a missing server, orany load/play failure all fall back to the static intro (strictly additive).
daemon.rs: starts the media server (bind failure is non-fatal → staticintro), repoints it at each applied theme before building, uses
build_payload_with_media.run_daemon's signature is unchanged.CSP
A
codex reviewpass probed the real renderer: Codex 26.715.31925'sapp://page ships
media-src 'self' app: blob: data:, which blocks the loopback<video>. The daemon now lifts CSP (Page.setBypassCSP, best-effort) onlybefore injecting a payload that has motion — the engine already injects
arbitrary JS into this page, so it's no new trust boundary, and it's transient
(no DOM residue, restored on reload). If the lift ever fails, the intro falls
back to art rather than breaking.
Tests
53 unit tests incl. ranged streaming (206 + exact bytes), token/Host/unknown-key
rejection, resolution by manifest id (not directory name), motion-URL channel
vs. static fallback, stamp sensitivity to a swapped video, and a
.codexskinimport carrying an mp4.
cargo clippy -D warningsclean on host +x86_64-pc-windows-msvc; src-tauri integrates.Review
codex review --uncommittedraised two issues, both fixed here: the CSP blockabove (P1) and a media-server resolve that keyed on directory basename instead
of the manifest id (P2, would 404 motion for explicit dev checkouts). Live
end-to-end playback against a running Codex renderer is the one thing not
exercisable in CI and remains to verify in a clean environment.