Skip to content

feat(runtime): add cross-platform MP4 video backgrounds - #290

Open
starsstreaming wants to merge 1 commit into
Fei-Away:mainfrom
starsstreaming:feat/video-backgrounds
Open

feat(runtime): add cross-platform MP4 video backgrounds#290
starsstreaming wants to merge 1 commit into
Fei-Away:mainfrom
starsstreaming:feat/video-backgrounds

Conversation

@starsstreaming

@starsstreaming starsstreaming commented Jul 27, 2026

Copy link
Copy Markdown

Summary / 摘要

Add optional MP4 video backgrounds on both platforms while keeping existing static-image themes fully compatible. Users can import a video from the menu/tray or declare it in a theme package; the renderer plays it as a background layer with the still image as poster and failure fallback.

在双平台增加可选 MP4 视频背景,并保持现有静态图片主题完全兼容。用户可从菜单/托盘直接导入视频,或在主题包中声明;渲染器用独立背景层播放,静态图仍作 poster 与失败回退。

Closes #240

What users get / 用户可见行为

EN 中文
Entry macOS menu bar 一键更换视频背景… · Windows tray 一键更换视频背景 同上
Theme field optional theme.json "video": "background.mp4" 可选字段,仅相对文件名
Limits non-empty .mp4, ≤ 100 MiB, real ftyp box (renamed non-MP4 rejected) 非空、≤100 MiB、真实 ftyp 容器头
Poster current/theme still image always required 图片始终保留作 poster / 失败回退
Transport loopback only — not uploaded 仅本机回环,不上传
Hot switch commit only after renderer confirms playable; else restore previous theme 渲染器确认可播放后才提交,否则恢复
Codec hint H.264/AVC + AAC (or no audio) recommended for Codex Chromium 建议 H.264/AAC 或无音轨

Direct picker is preferred for large files. Theme ZIP import still obeys existing archive caps (32 MiB compressed / 64 MiB expanded, including the MP4), so e.g. a 76 MiB video must use the menu/tray path.

大文件请用菜单/托盘直选。ZIP 仍受原有压缩/解压上限约束(含 MP4),超过解压上限的视频不能靠 ZIP 导入。


Design / 设计要点

1. Theme model / 主题模型

{
  "schemaVersion": 1,
  "image": "background.jpg",
  "video": "background.mp4"
}
  • video is optional. Image-only themes behave exactly as before.
  • video must be a relative basename inside the theme directory (background.mp4 only in the registered media map). Absolute paths, .., controls, and non-.mp4 names are rejected.
  • Package validator (runtime/theme-package-validator.mjs + platform copies):
    • LIMITS.video = 100 * 1024 * 1024
    • isMp4Container() checks first-box size + ASCII ftyp
    • official/simple packages may include background.mp4 next to the image + CSS
  • Windows PowerShell path (theme-windows.ps1): Assert-DreamSkinVideoFile mirrors the same size/extension/ftyp checks before Set-DreamSkinActiveTheme copies the file into the managed active theme.
  • Active-theme snapshot/restore for community apply (apply-community-theme.ps1) now copies and restores VideoPath, so a video theme is not restored as a broken image-only manifest.

video 可选;仅图片主题行为不变。校验层(Node 包校验 + Windows PS)统一:相对名、.mp4、≤100 MiB、真实 ftyp。社区主题应用的快照/恢复会带上 MP4,避免恢复成“清单有 video、磁盘无文件”。

2. Loopback media server / 本机回环媒体服务

New shared module (platform copies):

  • macos/scripts/media-server.mjs
  • windows/scripts/media-server.mjs

Contract:

  • Bind 127.0.0.1 only, ephemeral port
  • One-shot random token route: /media/<token>
  • Methods: GET / HEAD / OPTIONS
  • Range requests → 206 + Content-Range; invalid range → 416
  • Cache-Control: no-store, X-Content-Type-Options: nosniff
  • Origin allowlist + required X-Codex-Dream-Skin-Token; otherwise 403
  • Re-stat on each request: size/type drift or missing file → refuse
  • MediaServerController stages the next server and commits only after renderers accept the new theme (previous server kept alive across verification so in-flight playback does not break mid-switch)
  • Does not expose arbitrary filesystem paths

Does not widen CDP beyond loopback. Windows injector additionally prefers CDP DOM.setFileInputFiles + Blob transport for the active session, with the loopback URL only as controlled fallback; CSP bypass for media fetch is enabled only through the verified injector path and without forcing a full page reload.

新模块仅绑 127.0.0.1、一次性 token 路由、Range/206、Origin + token 门禁、文件漂移拒绝。MediaServerController 在渲染器确认前保留旧服务。Windows 优先 CDP 文件注入 + Blob,loopback URL 仅作受控回退;不为换肤强制整页 reload。

3. Injector payload / 注入载荷

  • Payload placeholder count becomes 7: existing six + __DREAM_SKIN_VIDEO_JSON__.
  • Replacements stay function-form .replace(...) (same $-safe pattern as v1.5.6 payload integrity work).
  • IIFE signature: (cssText, artDataUrl, themeConfig, videoConfig) => { ... }.
  • loadTheme resolves/realpaths the video inside the theme dir, streams content for fingerprinting (does not keep a full MP4 buffer just to hash), validates ftyp, and records size/mtime in the source stamp.
  • A renderer-rejected video revision is remembered (rejectedSourceStamp) and is not reapplied until source files change.
  • Windows watch path: blob file input handoff, media-server stage/commit ordering, verify fields videoMode / videoReady / videoFailed.
  • macOS injector/stage/write/publish/switch/load-image paths thread the optional video the same way; menu bar calls load-image-theme-macos.sh --file <mp4>.
  • Startup verify on Windows accepts --allow-hidden-applied so a deferred hidden-renderer state during video bring-up does not false-fail an otherwise healthy session (aligned with existing hidden-defer semantics).

载荷第 7 个占位符 VIDEO_JSON;函数式 replace;IIFE 增加 videoConfig。指纹对流式读 MP4,不全量读入。被渲染器拒绝的 revision 在源文件变化前不再重放。Windows 启动 verify 显式允许 hidden-applied 延迟态,避免视频拉起阶段误杀健康会话。

4. Renderer / 渲染器

runtime/renderer-inject.js (+ macos/windows assets via sync gate):

  • Background stage #codex-dream-skin-background-stage with <img> poster + <video>
  • muted / autoplay / loop / playsInline; pointer-events: none
  • Attributes: data-dream-media="video", data-dream-video-ready, failure flags
  • Modes: blob (Windows file input) or server (loopback URL); optional fallbackUrl
  • On theme switch: pause, remove listeners, revoke object URLs, hand off or dispose previous <video> to avoid double-decode / poster flash
  • On error / hidden document / theme clear: fall back to static image background
  • Does not change composer, sidebar, or home/task layout selectors used by image themes

背景舞台层 + poster 图 + video;切换时清理监听与 Blob URL,并 handoff 旧 video 节点以降低闪屏。失败/隐藏/清主题时回退静态图。不改动图片主题既有 chrome/布局选择器语义。

5. CSS / 样式

Pure additive block on top of upstream dream-skin.css (~+132 lines):

  • #codex-dream-skin-background-stage and descendants
  • html[data-dream-skin="active"][data-dream-media="video"] … visibility/stacking rules
  • Image-theme rules (composer chrome, token surfaces, etc.) are not deleted or narrowed in this PR

CSS 只增不删:视频舞台与 data-dream-media="video" 规则;本 PR 不含 chrome 收窄或其它布局删改。

6. Platform UX / 平台入口

  • macOS AppDelegate.swift: menu item → NSOpenPanel (.mpeg4Movie) → load-image-theme-macos.sh --file
  • Windows tray-dream-skin.ps1: tray item → MP4 filter dialog → Set-DreamSkinActiveTheme -VideoPath …; busy-op balloon; watcher liveness check + optional restart prompt; post-apply --verify poll
  • Installer / engine file lists include media-server.mjs (common-windows.ps1, build-release.ps1, setup-bootstrap.ps1, macOS menubar build script)
  • Docs: root README.md / README.en.md, windows/README.md; changelogs under ## 未发布 (no VERSION bump)

Files / 主要文件(44 files, +4622 / −207)

Area Paths
Shared runtime runtime/renderer-inject.js, runtime/dream-skin.css, runtime/theme-package-validator.mjs
Media server macos/scripts/media-server.mjs, windows/scripts/media-server.mjs
Injectors macos/scripts/injector.mjs, windows/scripts/injector.mjs
Theme IO macos/scripts/{stage,write,publish,load-image,switch,extract,theme-content-fingerprint}*, windows/scripts/theme-windows.ps1, apply-community-theme.ps1
UX macos/menubar-app/.../AppDelegate.swift, windows/scripts/tray-dream-skin.ps1
Engine lists windows/scripts/common-windows.ps1, installers, macos/scripts/build-menubar-app.sh
Assets (synced) macos/assets/*, windows/assets/* copies of runtime CSS/JS/validator
Tests see below
Docs README.md, README.en.md, windows/README.md, macos/CHANGELOG.md, windows/CHANGELOG.md

TASK_PROGRESS.md and VERSION files are not in this PR.


Tests / 测试

Added / extended coverage

  • macos/tests/media-server.test.mjs, windows/tests/media-server.test.mjs — loopback bind, token route, Range/206/416, origin/token rejection, size gate
  • tools/renderer-runtime.test.mjs — video stage, handoff, poster fallback, blob/server config, no-reload media policy expectations
  • windows/tests/injector-bootstrap.test.mjs — MP4 fingerprint changes when bytes change under same name; blob transport / CSP bypass / no full-file fingerprint buffer; reject-stamp; media commit-after-verify ordering
  • windows/tests/injector-window-readiness.test.mjs — visible-but-not-ready video is a real failure (not hidden-window defer)
  • macos/tests/theme-package-validator.test.mjs, theme-stage.test.mjs, payload-template-integrity.test.mjs — video field, ftyp, 7 placeholders + videoConfig IIFE
  • windows/tests/run-tests.ps1 — video write path + image-switch fingerprint regression hooks
  • macos/tests/injector-bootstrap.test.mjs — video-related bootstrap assertions

windows已经人工测试可用
macOS 真机测试与截图待补;其它叠放改动非本功能阻塞项。

Checks actually run for this PR / 本 PR 实跑

Check Result
node tools/sync-runtime-assets.mjs exit 0
node --test tools/renderer-runtime.test.mjs windows/tests/injector-bootstrap.test.mjs windows/tests/media-server.test.mjs windows/tests/injector-window-readiness.test.mjs 14/14 pass
windows/tests/run-tests.ps1 exit 0
git diff --check clean
Manual Windows MP4 import / hot switch passed (author)
macos/tests/run-tests.sh full suite not run — Windows host lacks /bin/bash; known symlink EPERM on this environment (same limitation on plain upstream/main)
macOS live verify / doctor not run here

Type / 类型

  • Bug fix / 缺陷修复
  • Feature / 新功能
  • Docs / 文档
  • Theme / CSS / visual / 主题或视觉
  • Scripts / install / restore / 脚本或安装恢复
  • Chore / 杂项

Platform / 平台

  • macOS
  • Windows
  • Both / 双平台
  • Docs / repo only / 仅文档或仓库元数据

Self-check / 自测

Docs-only / 仅文档

  • Links and wording reviewed / 已检查链接与表述

macOS (when code under macos/ changes)

  • macos/tests/run-tests.sh passed / 已通过
  • Doctor (optional): macos/scripts/doctor-macos.sh
  • Live verify (if inject/CSS/start path): verify-dream-skin-macos.sh or Desktop Verify
  • Restore / re-apply smoke (if install/restore/start changed) / 若改了安装恢复启动则做过恢复再应用

macOS full suite and live verify pending on a Mac. Shared Node media/renderer/validator coverage and payload-template integrity updates are in tree; environment limits called out above.

macOS 完整套件与真机 verify 待 Mac 补跑;共享 Node 媒体/渲染/校验与 payload 完整性改动已在树内。

Windows (when code under windows/ changes)

  • Relevant install / start / verify / restore scripts exercised / 已按改动跑过对应脚本
  • Environment noted below (OS build, Codex source) / 下方注明环境

Security / 安全

  • Does not modify official Codex install / asar / signatures / 未修改官方安装与签名
  • Does not silently write API Base URL or keys / 未静默写入 API Base URL 或 Key
  • CDP remains loopback-oriented (127.0.0.1) where applicable / CDP 仍仅本机回环(如适用)

Additional video-path hardening called out above: ftyp gate, 100 MiB cap, theme-dir containment (no symlink escape), loopback+token media server, no arbitrary path expose, Windows WS host check stays 127.0.0.1-only in the touched validation path, streaming fingerprint (no full-buffer retain for hash only).

视频路径额外约束见上文:ftyp、100 MiB、主题目录封闭、loopback+token 媒体服务、不暴露任意路径、指纹流式计算。

Notes / 补充

Out of scope / 明确不在本 PR

  • CSS chrome / composer / panel narrowing (layout-only deletes) — separate discussion; would overlap open UI PRs
  • Atomic theme-update marker / tray verified transaction wrapper refactors unrelated to video
  • VERSION bump / release packaging

本 PR 不做 CSS chrome 收窄、与视频无关的原子 marker / 托盘 verified transaction 重构,也不 bump VERSION。

Environment / 环境

  • Windows 11 Pro 10.0.26200
  • Official Codex Windows install (no asar / WindowsApps patch)
  • Branch: starsstreaming:feat/video-backgrounds @ 865b906 on top of v1.5.6 (611c101)

Screenshots / demo / 截图与演示

  • Demo video / 演示视频 (Windows tray import walkthrough, ~44s, 7.2 MiB, H.264/AAC, no private chat):

  • Still homepage / task-route screenshots can be added if reviewers want frame captures; the video already covers import → apply → home/task routes.

  • 演示视频(Windows 托盘导入全程,约 44s,7.2 MiB,H.264/AAC,不含隐私对话):同上链接。

  • 如需静态截图可再补;视频已覆盖导入 → 生效 → 首页/任务页。

Reviewer map / 建议审阅顺序

  1. runtime/theme-package-validator.mjs + */media-server.mjs — trust boundary
  2. windows/scripts/injector.mjs media stage/commit + blob handoff
  3. runtime/renderer-inject.js video lifecycle / fallback
  4. runtime/dream-skin.css additive stage only
  5. tray / menubar entry + theme-windows.ps1 / apply-community-theme.ps1 snapshot
  6. tests listed above

Support optional theme.json video fields, loopback media serving,
menu/tray import, poster fallback, and renderer handoff on both
platforms. Closes Fei-Away#240.
@starsstreaming

Copy link
Copy Markdown
Author

Demo video / 演示视频

Compressed author walkthrough of MP4 video background import on Windows (tray → pick MP4 → apply → homepage/task route).

Windows 托盘「一键更换视频背景」导入与生效演示(作者录屏压缩版)。

File dream-skin-video-import-demo.mp4
Size 7.2 MiB (source ~15 MiB → H.264 1440×872 + AAC, faststart)
Duration ~44 s
Notes No private chat content / 不含隐私对话内容

Direct download:

https://github.com/starsstreaming/Codex-Dream-Skin/releases/download/pr-290-video-demo/dream-skin-video-import-demo.mp4

Hosted as a prerelease asset on the contributor fork (starsstreaming/Codex-Dream-Skin@pr-290-video-demo) so reviewers can open it without cloning. Not part of the product release train.

挂在贡献者 fork 的 prerelease 资源上,方便审阅;不属于产品发版产物。

@starsstreaming

Copy link
Copy Markdown
Author

Stack / 叠放后续

Linear stack on top of this PR (please merge in order):

  1. feat(runtime): add cross-platform MP4 video backgrounds #290 (this) — video backgrounds
  2. fix(windows): gate active-theme writes with a short update marker #291 — atomic active-theme write marker
  3. feat(windows): verified tray theme switching with rollback #292 — verified tray theme switching with rollback
  4. refactor(css): narrow home-shell overrides so Codex owns native chrome #293 — CSS narrow native chrome (notes overlap with fix(runtime): keep theme artwork stable around panels #177 / Fix native toolbar overlap and task canvas seams #263)

线性叠放,请按序合并:#290#291#292#293

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: 支持视频背景主题

1 participant