From a2050ccd5011721941aa275af5b2ab75aea750c9 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:22:02 -0400 Subject: [PATCH] [docs] Dev plan for the BitVid Bridge cross-platform streaming app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expands live-publish-plan Phase 7 into docs/bitvid-bridge-plan.md: a super-simple Windows/macOS/Linux app that makes going live turnkey. Core design: native media core (MediaMTX + FFmpeg + rclone; never sees the Nostr key) + an embedded bitvid "Studio" webview that signs — talking over in-app IPC, NOT browser->localhost (dodges mixed-content/PNA and keeps signing in the web layer, honoring "BitVid signs; Bridge routes"). Surfaced 10 decisions: framework (Wails/Go vs Tauri), control model (embedded webview vs website-drives-localhost), capture vs receive, webview signer support (NIP-46 + encrypted nsec), ingest protocols (RTMP MVP), upload (bundled rclone), one-codebase-two-modes (Bridge desktop == self-hosted Media Node headless), pass-through-only transcode, code-signing/notarization ownership (the real cost of "easy install"), license/telemetry. Phases 0-7 (shell+core -> receive MVP -> record/VOD -> restream -> turnkey/packaging -> built-in capture -> SRT/WHIP/WebRTC -> headless node + BitVid Box), invariants, packaging/signing, risks, sources. Linked from the publish plan. Co-Authored-By: Claude Opus 4.8 --- docs/bitvid-bridge-plan.md | 248 +++++++++++++++++++++++++++++++++++++ docs/live-publish-plan.md | 5 +- 2 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 docs/bitvid-bridge-plan.md diff --git a/docs/bitvid-bridge-plan.md b/docs/bitvid-bridge-plan.md new file mode 100644 index 00000000..63148b28 --- /dev/null +++ b/docs/bitvid-bridge-plan.md @@ -0,0 +1,248 @@ +# BitVid Bridge — cross-platform streaming helper app — Dev Plan + +Companion to **`docs/live-publish-plan.md`** (#16c) — this expands its **Phase 7 +(Local Bridge app)** into its own plan. The Bridge is the piece that fills the one +gap a static web client can't: **receiving and routing live media** on the +creator's machine. +Status: **FUTURE / exploratory.** Sequenced after the #16c Media Node MVP, but the +Bridge and the server-side Media Node can share a codebase (see DECISION 7). + +Goal (maintainer): a **super-simple, easy-to-install, easy-to-use** cross-platform +app (Windows / macOS / Linux) that makes going live on bitvid turnkey. + +--- + +## Core decision + +The Bridge is a **local media receiver + router**, not a Nostr identity holder. +It pairs a **native media core** (receive/record/restream/upload) with an +**embedded bitvid "Studio" webview** that does all Nostr signing. The two stay +logically separated inside one app: + +``` +BitVid Bridge (one installable app) +├── Native media core → RTMP/SRT/WHIP ingest, HLS/WebRTC out, record, restream, +│ S3 upload (never sees the Nostr key) +└── Embedded Studio webview → bitvid client that signs NIP-53 + publishes VOD + (talks to the core over in-app IPC, not localhost HTTP) +``` + +**Why an embedded webview instead of "the website controls a localhost server":** +it solves two hard problems at once — +1. **No browser↔localhost pain.** An HTTPS page calling `http://127.0.0.1` hits + mixed-content + Private-Network-Access preflight/permission rules. In-app IPC + (Tauri commands / Wails bindings) sidesteps all of it. +2. **Signing stays in the web layer.** The webview is a bitvid client, so it signs + exactly as the browser does; the native core never touches the key. This + honors the publish plan's Rule 1 ("BitVid signs; Bridge routes") while still + being one self-contained app. + +**When you don't need the Bridge at all:** OBS → the public Media Node works for a +basic stream. The Bridge earns its place via multi-restream, local recording, +hardware/appliance input, and turnkey UX — and later, built-in capture (no OBS). + +--- + +## Decisions needed + +> **DECISION 1 — App framework.** Go/**Wails** vs **Tauri** vs Electron. +> *Recommendation: **Wails (Go)** or **Tauri (Rust)** — both give a web UI (reuse +> bitvid's components/tokens) and small binaries; Electron is ~100MB+ and heavy, +> against "simple install." Slight lean **Wails/Go**: the media stack is Go-native +> and **MediaMTX is written in Go**, so it's one language, one small static binary, +> trivial cross-compile. Tauri is a very close second with a more mature app-shell +> + updater. Pick based on team comfort (Go vs Rust).* + +> **DECISION 2 — Control model.** Embedded Studio webview (self-contained app) vs +> website-drives-localhost-API vs both. +> *Recommendation: **embedded webview primary** (dodges PNA/mixed-content + keeps +> signing in the web layer). Optionally expose a **localhost API later** for people +> who want to drive it from the bitvid website (with the PNA/CORS work done then).* + +> **DECISION 3 — Capture vs receive.** MVP receives (OBS/hardware → Bridge) vs push +> built-in screen/camera capture earlier. +> *Recommendation: **receiver-first MVP** — works with the OBS/encoders people +> already have and ships fast. **Built-in capture (no OBS)** is the "super simple" +> headline but is effectively a mini-OBS (encoder is hard) → make it a fast-follow +> phase, not MVP.* + +> **DECISION 4 — Signer support in the Bridge webview.** Since the webview signs, +> which login methods? **NIP-46 remote signer** (no key on device — safest), the +> **encrypted-nsec** flow the web app already has (key encrypted on-device), or +> both. NIP-07 extensions generally aren't available inside an app webview. +> *Recommendation: **both NIP-46 + encrypted-nsec**, NIP-46 preferred/first. Reuse +> the web app's existing session/signer code so there's nothing new to audit.* + +> **DECISION 5 — Ingest protocols for MVP.** RTMP only, or RTMP + SRT + WHIP. +> *Recommendation: **RTMP for MVP** (universal — OBS/hardware all speak it), add +> **SRT** (better over lossy networks) and **WHIP** (WebRTC ingest, low latency) +> in a later phase. MediaMTX supports all three, so it's mostly UI/config.* + +> **DECISION 6 — Recording upload mechanism.** Bundle **rclone** (one binary, +> speaks R2/B2/S3/MinIO + resumable) vs a native S3 SDK in the core vs reuse +> bitvid's browser S3 upload from the webview. +> *Recommendation: **rclone** bundled as a sidecar — dead-simple multi-provider +> support + resumable uploads of large recordings, matches the storage providers +> bitvid already supports. Native SDK only if we want to drop the extra binary.* + +> **DECISION 7 — One codebase, two modes?** The server-side **Media Node** (#16c) +> and the local **Bridge** are ~the same thing (MediaMTX + session API + upload + +> restream). Build **one codebase that runs headless (Media Node) or with the +> embedded UI (Bridge)?** +> *Recommendation: **yes** — "self-host the Media Node" (publish-plan DECISION 1b) +> becomes literally "run the Bridge in `--headless` mode on a VPS." Big reuse win; +> steers DECISION 1 toward Go (server + desktop from one Go binary).* + +> **DECISION 8 — Transcode.** Pass-through (`-c copy`) only, or offer local +> transcode profiles? +> *Recommendation: **pass-through only** (same as the publish plan). Require +> H.264/AAC in; the Bridge repackages/forwards without re-encoding — keeps CPU low +> and the app light. Transcoding is a later, opt-in power feature.* + +> **DECISION 9 — Code signing + distribution ownership.** "Easy install" *requires* +> **Apple notarization** (Developer ID — or macOS Gatekeeper blocks it) and a +> **Windows Authenticode cert** (or SmartScreen scares users). Who holds the certs +> and pays (~$99/yr Apple + Windows cert)? Linux = AppImage + `.deb`/`.rpm` +> (no signing gate). *Recommendation: the project owns the certs; budget for them — +> this is the true cost of "easy to install," not optional.* + +> **DECISION 10 — License / telemetry.** Open-source license (match bitvid's) and +> **no telemetry by default** (opt-in crash reports at most). *Recommendation: +> same license as bitvid; privacy-first, opt-in only.* + +--- + +## Architecture + +``` +BitVid Bridge +├── App shell (Tauri/Rust or Wails/Go) DECISION 1 +│ └── Embedded Studio webview (bitvid client, signs NIP-53/VOD) DECISION 2,4 +├── Native media core +│ ├── MediaMTX (bundled sidecar) → ingest RTMP/SRT/WHIP, HLS/WebRTC out, record +│ ├── FFmpeg (bundled) → copy-forward restreams (-c copy) DECISION 8 +│ └── rclone (bundled) → upload recordings to R2/B2/S3/MinIO DECISION 6 +├── Session/state manager → LiveSession model, status, tokens +├── IPC bridge → webview ↔ core (Tauri cmds / Wails bindings) +└── (optional) localhost API → for website control, later DECISION 2 +``` + +- **Media core = a local Media Node.** Same engine as the server-side node (#16c), + which is why DECISION 7 (one codebase, two modes) is attractive. +- **Stream keys / ingest URLs never leave the device** and never go into Nostr; the + webview only ever publishes the *playback* URL. +- **Status → Nostr:** MediaMTX hooks fire `input_connected / input_live / + input_lost / recording_finalized / upload_complete`; the core forwards these to + the webview over IPC; the **webview signs** the corresponding NIP-53 update + (planned → live → ended + recording). + +--- + +## UX flow (the "super simple" target) + +``` +1. Install (signed installer / AppImage). DECISION 9 +2. Open app → sign in (NIP-46 or encrypted nsec) in the Studio webview. DECISION 4 +3. Fill title/thumbnail/tags → "Prepare stream" (publishes status=planned). +4. App shows one of: + a. RECEIVE MODE: local ingest URL + key to paste into OBS/encoder. DECISION 3 + b. (later) CAPTURE MODE: pick a screen/window/camera → "Go Live". +5. Encoder connects → core detects input → webview publishes status=live. +6. (optional) toggle restream outputs (YouTube/Twitch/zap.stream). DECISION 5 +7. "End" → status=ended → core finalizes recording → uploads → webview + offers "Publish recording as a BitVid video" (archive→VOD). +``` + +The whole point: **one window, sign in, go live, done** — and the recording +becomes a normal bitvid video automatically. + +--- + +## Cross-platform packaging + +- **Windows:** signed `.msi`/`.exe` (Authenticode). Auto-update. +- **macOS:** signed **+ notarized** `.dmg` (Developer ID) — mandatory. Universal + (arm64 + x86_64). +- **Linux:** **AppImage** (zero-install portable) + `.deb`/`.rpm`; consider Flatpak. +- **Bundled binaries per-platform:** MediaMTX, FFmpeg, rclone. FFmpeg is the size + hog (~50–80MB) — ship a **minimal build** (only the muxers/protocols we use: + flv/rtmp/mpegts/hls/webrtc, aac/h264 passthrough) to keep the installer lean. +- **Auto-updater** (both Tauri and Wails have one) with signed release artifacts. + +--- + +## Phases + +- **Phase 0 — Shell + media core (foundational).** App skeleton (DECISION 1), + bundle + supervise MediaMTX, embedded Studio webview, webview↔core IPC, signed + dev builds on all three OS. Sign-in works (DECISION 4). +- **Phase 1 — Receive → BitVid (the MVP).** Local RTMP ingest; copy-forward to the + BitVid Media Node; publish planned→live→ended NIP-53 from the webview driven by + MediaMTX input hooks. "OBS → Bridge → bitvid, one window." +- **Phase 2 — Record → archive → VOD.** Local recording, finalize, rclone upload + to the user's storage, manifest → webview publishes a normal bitvid video + (reuses the `s`-tag/info.json/30078 flow). Optional torrent/webseed for full + WebTorrent VOD. +- **Phase 3 — Multi-restream (`FEATURE_LIVE_RESTREAM`).** One input → many outputs + (YouTube/Twitch/zap.stream/custom RTMP/SRT), copy-only, per-output status + + retry/backoff. Keys stay local; optional public mirror links as `r` tags. +- **Phase 4 — Turnkey UX + packaging.** One-click go-live, OBS auto-config or + OBS-WebSocket control, signed/notarized installers + AppImage, auto-update. +- **Phase 5 — Built-in capture (no OBS).** Screen/window/camera capture + encode + inside the app (`getDisplayMedia`/`getUserMedia` → WebCodecs/FFmpeg). The "super + simple" headline: go live with no external encoder. +- **Phase 6 — SRT/WHIP ingest + WebRTC low-latency** (DECISION 5). +- **Phase 7 — Headless "Media Node" mode + hardware / "BitVid Box".** Run the same + binary headless as the self-hosted Media Node (DECISION 7); harden for + appliance/headless use — the seed of a physical device. + +--- + +## Engineering rules (invariants) + +1. **The native core never sees the Nostr key.** Only the webview signs. +2. **Ingest URLs/keys stay on the device; only playback URLs reach Nostr.** +3. **Pass-through first** — copy H.264/AAC, don't transcode (DECISION 8). +4. **Reuse bitvid's web client** for the Studio webview (session, signer, publish, + upload-modal-style VOD flow) — minimize net-new signing/auth code. +5. **Optional, not required** — a creator can still stream OBS → public Media Node + without the Bridge; the Bridge only *adds* convenience/power. + +--- + +## Risks / watch-items + +- **Code signing is the real "easy install" cost (DECISION 9).** Apple + notarization + Windows cert are non-negotiable for a frictionless install and + cost money + setup. Budget for them up front. +- **Bundle size vs simplicity.** MediaMTX + FFmpeg + rclone add up; a minimal + FFmpeg build and per-platform packaging keep it reasonable, but it won't be + tiny. Trade-off vs "super light." +- **Built-in capture is a mini-OBS (DECISION 3/Phase 5).** Reliable capture + + encode across GPUs/OSes is genuinely hard — don't let it block the receiver MVP. +- **Signing during long streams.** Same issue as the publish plan (DECISION 2 + there): the webview must stay running to sign status updates + heartbeats; + handle sleep/crash gracefully (NIP-53 treats no-update-in-~1h as ended). +- **Webview signer support.** NIP-07 extensions typically aren't present in an app + webview → lean on NIP-46 / encrypted-nsec (DECISION 4). +- **Encoder compatibility.** Pass-through needs H.264/AAC + sane keyframes; + detect + warn on incompatible input rather than failing silently. +- **Scope creep.** This app can sprawl (capture, transcode, appliance). Ship the + receiver MVP (Phase 0–1) first; everything else is additive. + +--- + +## Sources + +- **MediaMTX** (ingest/playback/record/forward/control API): + https://mediamtx.org/docs/kickoff/introduction +- **OBS WebSocket** (built into OBS 28+): + https://obsproject.com/kb/remote-control-guide +- App frameworks: [Tauri](https://tauri.app/) · [Wails (Go)](https://wails.io/) · + packaging binaries (MediaMTX, [FFmpeg](https://ffmpeg.org/), + [rclone](https://rclone.org/)). +- Companion plans: `docs/live-publish-plan.md` (#16c, this expands its Phase 7), + `docs/live-ingest-plan.md` (#16, watch side + P2P-assisted HLS). +- bitvid code reused by the Studio webview: session/signer (NIP-46 + encrypted + nsec), the upload/publish flow, `js/utils/storagePointer.js` (`s`-tag → + `.info.json`) for archive→VOD. diff --git a/docs/live-publish-plan.md b/docs/live-publish-plan.md index 51379b77..ab717af7 100644 --- a/docs/live-publish-plan.md +++ b/docs/live-publish-plan.md @@ -293,7 +293,10 @@ has enough concurrent viewers — see the ingest plan + Advantages above. The en Bridge to avoid browser↔localhost/mixed-content pain. - **Phase 7 — Local Bridge app (large; `FEATURE_LIVE_BRIDGE`).** Packaged desktop helper: local RTMP/SRT receiver, forward to Node + external, local record + - archive upload, localhost API + pairing. *BitVid Live v2 / "BitVid Box" seed.* + archive upload, embedded Studio webview (signs) + optional localhost API. + *BitVid Live v2 / "BitVid Box" seed.* **Full plan: `docs/bitvid-bridge-plan.md`** + (cross-platform app; note DECISION 7 there — the Bridge and this Media Node can + share one codebase running headless vs with-UI). - **Phase 8 — WebRTC low-latency (later, DECISION 4).** ---