mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
[docs] Blanket rule: bitvid hosts nothing but a static client — lock publish decisions
Maintainer blanket rule: bitvid.network runs NO servers / media infra, ever. All media receiving/routing is self-hosted by the creator (the Bridge run headless) or handled by an external provider. live-publish-plan: - Add the blanket rule as a non-negotiable principle in the Core Decision. - Lock all 6 decisions: D1 self-host OR external only (managed bitvid node REMOVED); D2 signing A-then-NIP46, managed account (D) removed; D3 pass-through; D4 HLS-first; D5 Bridge IS the self-host path; D6 keep specific flags. - Sweep every "managed / public BitVid node" reference: the Media Node is always self-hosted (= Bridge headless per DECISION 7) or external; Phase 3 reframed as a reference node the CREATOR runs; risks reframed (burden is the self-hoster's, not bitvid's). Status: decisions locked. bitvid-bridge-plan: - Remove "public Media Node" implications; the Bridge is the self-hosting vehicle. - Add the reachability/NAT reality: a home-only Bridge can't serve public HLS → headless-on-VPS is the path (why DECISION 7 matters). Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
01545056af
commit
1fd3862a95
2 files changed
+90
-67
No files matched your search
@@ -38,9 +38,11 @@ it solves two hard problems at once —
|
||||
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).
|
||||
**When you don't need the Bridge at all:** OBS → an **external provider**
|
||||
(zap.stream/YouTube) works for a basic stream (bitvid runs no node — blanket
|
||||
rule). The Bridge earns its place by letting a creator **self-host** their own
|
||||
node and by multi-restream, local recording, hardware/appliance input, turnkey UX
|
||||
— and later, built-in capture (no OBS).
|
||||
|
||||
---
|
||||
|
||||
@@ -203,9 +205,14 @@ becomes a normal bitvid video automatically.
|
||||
- **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 1 — Receive → serve (the MVP).** Local RTMP ingest → serve HLS. For
|
||||
public viewers the playback origin must be **reachable**, so either run the
|
||||
Bridge **headless on a reachable host** (VPS — the self-hosted node) or
|
||||
copy-forward from a local Bridge to that reachable node / an external provider
|
||||
(never a bitvid-run node). Publish planned→live→ended NIP-53 from the webview via
|
||||
MediaMTX input hooks. "OBS → your node → bitvid, one window."
|
||||
*(NAT note: a home-only Bridge can't serve public HLS without a tunnel/
|
||||
port-forward — hence the headless-on-VPS path.)*
|
||||
- **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
|
||||
@@ -232,8 +239,9 @@ becomes a normal bitvid video automatically.
|
||||
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.
|
||||
5. **Optional, not required** — a creator can still stream OBS → an external
|
||||
provider without the Bridge; the Bridge *adds* self-hosting + convenience/power
|
||||
(and bitvid never runs a node — blanket rule).
|
||||
6. **Respect the connected instance's config.** The embedded Studio webview loads
|
||||
a specific bitvid instance, so it inherits that instance's flags — if the
|
||||
instance has `FEATURE_LIVE_PUBLISH` **off**, the Bridge shows go-live as
|
||||
@@ -272,6 +280,12 @@ becomes a normal bitvid video automatically.
|
||||
- **Local ingest exposure.** A misconfigured wide bind would expose an unauth'd
|
||||
RTMP receiver on the network — default to loopback (invariant 7); require auth
|
||||
for any non-loopback bind.
|
||||
- **Reachability / NAT (self-hosting reality).** With the blanket rule, the
|
||||
playback origin is the creator's own node — a **home-only Bridge behind NAT
|
||||
can't serve public HLS**. The clean path is running the Bridge **headless on a
|
||||
reachable VPS**; document that, plus optional tunnel/port-forward for the local
|
||||
case. This is the main friction of "self-host everything" and the reason the
|
||||
headless mode (Phase 7 / DECISION 7) matters.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+68
-59
@@ -4,25 +4,34 @@ TODO ref: **#16c** in `todo/TODO_2026-06-20_pre-launch.md` (this doc expands the
|
||||
stub). Companion to **`docs/live-ingest-plan.md`** (#16, watch-only) — the *watch*
|
||||
side (Live tab, player, chat, zaps) is built there and **reused** here; this doc
|
||||
adds the *broadcast* side.
|
||||
Status: **FUTURE / exploratory.** Sequenced **after** #16 (live ingest) and #16b
|
||||
(shorts) ship. This is the largest of the three plans and the only one that
|
||||
introduces **server-side media infrastructure** — read the Core Decision first.
|
||||
Status: **FUTURE / exploratory — all six decisions LOCKED** (see Core Decision's
|
||||
blanket rule: bitvid hosts nothing; self-host or external only). Sequenced
|
||||
**after** #16 (live ingest) and #16b (shorts). The largest plan, and the only one
|
||||
touching **(self-hosted, never bitvid-run) media infrastructure**.
|
||||
|
||||
---
|
||||
|
||||
## Core decision
|
||||
|
||||
> **BLANKET RULE (maintainer, non-negotiable): bitvid.network hosts NOTHING but a
|
||||
> static client — no servers, no media infrastructure, ever.** All media
|
||||
> receiving/routing is **self-hosted by the creator** (the Bridge run headless — a
|
||||
> single self-hosted binary, see `docs/bitvid-bridge-plan.md`) or handled by an
|
||||
> **external provider** (zap.stream/YouTube/Twitch). There is no bitvid-operated
|
||||
> Media Node and no managed publishing — those options are off the table.
|
||||
|
||||
Build **BitVid Live** as a **Nostr-native live-stream control layer**, not a
|
||||
video-hosting backend. BitVid the client stays exactly what it is — a static site
|
||||
that signs client-side, holds no keys, runs no server. The one thing a static
|
||||
browser app genuinely *cannot* do (receive + route live media) is isolated into a
|
||||
**separate, optional** service. Split:
|
||||
**separate, self-hosted-or-external** service (never bitvid-operated). Split:
|
||||
|
||||
```
|
||||
BitVid static client = identity, metadata, NIP-53 publishing, discovery, chat,
|
||||
zaps, player UI, archive→VOD publishing
|
||||
BitVid Media Node/Bridge = RTMP/SRT/WHIP ingest, HLS/WebRTC output, recording,
|
||||
restreaming, status API (server-side, optional)
|
||||
Media Node / Bridge = RTMP/SRT/WHIP ingest, HLS/WebRTC output, recording,
|
||||
(self-hosted OR restreaming, status API
|
||||
external provider)
|
||||
```
|
||||
|
||||
This keeps BitVid's architecture intact while adding broadcast. Crucially,
|
||||
@@ -85,45 +94,39 @@ BitVid Live over zap.stream/Twitch/YouTube.
|
||||
|
||||
## Decisions needed
|
||||
|
||||
> **DECISION 1 — Media hosting model.** Who runs the Media Node? (a) a **managed
|
||||
> BitVid Media Node** (bitvid-operated infra — easiest for creators, but ops/cost
|
||||
> and least "self-sovereign"); (b) **self-hosted** (creator/instance runs their
|
||||
> own node — most aligned, higher friction); (c) **external-provider-only** (no
|
||||
> node; stream to zap.stream/YouTube and just publish the NIP-53 event).
|
||||
> *Recommendation: ship (c) first — zero infra, immediate utility — then offer (b)
|
||||
> self-host with a reference node, and consider (a) managed as an opt-in later.*
|
||||
> **DECISION 1 — Media hosting model. ✅ LOCKED by the blanket rule: self-host OR
|
||||
> external-provider only — NO bitvid-operated node, ever.** Two supported paths:
|
||||
> **(c) external-provider-only** (no node — stream to zap.stream/YouTube/Twitch,
|
||||
> bitvid just publishes the NIP-53 event; **ships first**, zero infra) and
|
||||
> **(b) self-hosted** (the creator runs their own Media Node = the Bridge headless;
|
||||
> most aligned). The managed-BitVid-node option is **removed**. Order: ship (c)
|
||||
> first, then ship (b) as the Bridge/headless path.
|
||||
|
||||
> **DECISION 2 — Signing during a live stream.** The Media Node can detect
|
||||
> start/stop, but must NOT hold the creator's Nostr key. How do status updates get
|
||||
> signed? (A) **BitVid tab stays open**, browser signs status=live/ended;
|
||||
> (B) **NIP-46 remote signer** so the node can request signatures; (C) node
|
||||
> publishes *provider-status* under its **own** pubkey while the creator's canonical
|
||||
> 30311 stays user-signed; (D) managed publishing account (least sovereign).
|
||||
> *Recommendation: A for MVP, explore B (NIP-46) later. Never D.*
|
||||
> **DECISION 2 — Signing during a live stream. ✅ LOCKED: A for MVP, B (NIP-46)
|
||||
> later; D removed by the blanket rule.** The node must NOT hold the creator's key.
|
||||
> **(A) BitVid tab/app stays open** and signs status=live/ended (matches the
|
||||
> Bridge's embedded-webview design) — MVP. **(B) NIP-46 remote signer** for a
|
||||
> hands-off experience — later. **(C)** a *self-hosted* node may also publish
|
||||
> provider-status under its own pubkey while the canonical 30311 stays user-signed
|
||||
> — available to self-hosters. **(D) managed publishing account is off the table**
|
||||
> (blanket rule).
|
||||
|
||||
> **DECISION 3 — Transcode now or pass-through only?** v1 should be **stream-copy
|
||||
> only** (`-c copy`, no transcode) — require OBS to send H.264/AAC, ~2s keyframes.
|
||||
> Transcoding (multi-bitrate ladders) adds heavy CPU/GPU + cost. *Recommendation:
|
||||
> pass-through v1; transcode profiles much later, if ever.*
|
||||
> **DECISION 3 — Transcode. ✅ LOCKED: pass-through only (`-c copy`) in v1.**
|
||||
> Require H.264/AAC + ~2s keyframes in; no transcode ladders. Transcoding is a
|
||||
> heavy, self-hoster-only opt-in much later, if ever.
|
||||
|
||||
> **DECISION 4 — WebRTC (low-latency) in scope for v1?** HLS (~6–30s latency) is
|
||||
> the safe default and works everywhere via hls.js (from #16). WebRTC (<500ms) is
|
||||
> nicer but more complex. *Recommendation: HLS first; WebRTC as a later phase.*
|
||||
> **DECISION 4 — WebRTC low-latency. ✅ LOCKED: HLS first, WebRTC later.** HLS
|
||||
> (~6–30s) works everywhere via #16's hls.js; WebRTC (<500ms) is a later phase.
|
||||
|
||||
> **DECISION 5 — Local Bridge app in scope, or Media Node only?** The local Bridge
|
||||
> (desktop helper for hardware encoders / multi-restream / local recording) is
|
||||
> powerful but a separate packaged app. *Recommendation: NOT required for MVP —
|
||||
> OBS → public Media Node covers most creators; Bridge is a later phase and the
|
||||
> seed of a future "BitVid Box".*
|
||||
> **DECISION 5 — Local Bridge in MVP. ✅ LOCKED: not required for the external-
|
||||
> provider MVP; it IS the self-hosting path (DECISION 1b).** With the blanket rule,
|
||||
> self-hosting a Media Node **is** running the Bridge headless, so the Bridge isn't
|
||||
> an optional extra for self-hosters — it's *the* mechanism. The external-provider
|
||||
> MVP (Phase 1) still needs neither. Full plan: `docs/bitvid-bridge-plan.md`.
|
||||
|
||||
> **DECISION 6 — Flag naming reconciliation.** #16 already established
|
||||
> `FEATURE_LIVE_INGEST` (watch) + `FEATURE_LIVE_CHAT_POST`. This plan adds
|
||||
> `FEATURE_LIVE_PUBLISH` (Studio / Go Live), `FEATURE_LIVE_BRIDGE` (Media
|
||||
> Node/Bridge integration), `FEATURE_LIVE_RESTREAM` (external outputs). Confirm we
|
||||
> keep the specific `*_INGEST` / `*_PUBLISH` split rather than a single umbrella
|
||||
> `FEATURE_LIVE`. *Recommendation: keep the specific flags; publishing needs
|
||||
> ingest on (you watch your own stream), so `FEATURE_LIVE_PUBLISH` implies
|
||||
> `FEATURE_LIVE_INGEST`.*
|
||||
> **DECISION 6 — Flag naming. ✅ LOCKED: keep the specific split.**
|
||||
> `FEATURE_LIVE_INGEST` / `_PUBLISH` / `_BRIDGE` / `_RESTREAM` (+ `_CHAT_POST` from
|
||||
> #16). No umbrella `FEATURE_LIVE`. `FEATURE_LIVE_PUBLISH` implies ingest is on.
|
||||
|
||||
---
|
||||
|
||||
@@ -221,13 +224,15 @@ public metadata. **Never** publish RTMP/SRT ingest URLs or stream keys into Nost
|
||||
metadata, publish planned→live→ended NIP-53 updates, show OBS/encoder ingest
|
||||
settings, connect to Bridge/Node, monitor health, manage restream outputs,
|
||||
publish the recording.
|
||||
- **BitVid Media Node** *(server-side; new)* — RTMP/SRT/WHIP ingest → HLS/WebRTC
|
||||
out, recording, S3-compatible upload, status API, optional restream. **Built on
|
||||
[MediaMTX](https://mediamtx.org/docs/kickoff/introduction)** (handles the
|
||||
protocol matrix, recording, hooks, control API) — not from scratch.
|
||||
- **BitVid Bridge** *(local helper; optional, later)* — local RTMP/SRT receiver
|
||||
for hardware encoders, one-input→many-outputs restream, local recording, archive
|
||||
upload, OBS-WebSocket control bridge. Foundation for a future "BitVid Box".
|
||||
- **Media Node** *(server-side; **self-hosted by the creator**, never bitvid-run)*
|
||||
— RTMP/SRT/WHIP ingest → HLS/WebRTC out, recording, S3-compatible upload, status
|
||||
API, optional restream. **Built on
|
||||
[MediaMTX](https://mediamtx.org/docs/kickoff/introduction)** — not from scratch.
|
||||
Per DECISION 7 it's the **same binary as the Bridge, run headless**.
|
||||
- **BitVid Bridge** *(the self-hosting vehicle — desktop app or headless node)* —
|
||||
local RTMP/SRT receiver for hardware encoders, one-input→many-outputs restream,
|
||||
local recording, archive upload, OBS-WebSocket control. **This is how a creator
|
||||
self-hosts** (DECISION 1b) and the seed of a future "BitVid Box".
|
||||
|
||||
New client modules (matching repo style): `js/services/liveEventService.js`,
|
||||
`liveChatService.js`, `liveBridgeClient.js`, `livePlaybackService.js` (or extend
|
||||
@@ -308,10 +313,12 @@ has enough concurrent viewers — see the ingest plan + Advantages above. The en
|
||||
- **Phase 2 — Bridge API client + mock backend (medium).** `liveBridgeClient`,
|
||||
Pair-Bridge UI, mocked `/sessions`, setup wizard, status dashboard,
|
||||
recording-ready flow — builds the client contract before real infra exists.
|
||||
- **Phase 3 — Media Node MVP (large, server-side).** `bitvid-media-node` around
|
||||
MediaMTX: session API, NIP-98-verified auth, token'd RTMP ingest, HLS playback,
|
||||
start/stop detection, status endpoint. OBS → node → bitvid watches. No keys in
|
||||
Nostr. *This is BitVid Live v1.*
|
||||
- **Phase 3 — Self-hosted Media Node MVP (large, server-side).** A **reference
|
||||
node the creator runs themselves** (never bitvid-operated) around MediaMTX:
|
||||
session API, NIP-98-verified auth, token'd RTMP ingest, HLS playback, start/stop
|
||||
detection, status endpoint. OBS → the creator's node → bitvid watches. No keys in
|
||||
Nostr. Per DECISION 7 (Bridge plan) this is the **same binary as the Bridge, run
|
||||
headless** — so Phase 3 and Phase 7 share code. *This is BitVid Live v1.*
|
||||
- **Phase 4 — Recording → archive → VOD (medium).** MediaMTX recording → finalize
|
||||
→ S3 upload → manifest → the archive→VOD publish flow above.
|
||||
- **Phase 5 — Restream outputs (medium; `FEATURE_LIVE_RESTREAM`).** Output manager,
|
||||
@@ -348,17 +355,19 @@ has enough concurrent viewers — see the ingest plan + Advantages above. The en
|
||||
|
||||
## Risks / watch-items
|
||||
|
||||
- **Departure from static-only.** The Media Node/Bridge is real server infra with
|
||||
real ops + cost — the biggest philosophical + practical shift. Mitigated by
|
||||
keeping it **optional** (Phase-1 external mode needs none) and off by default.
|
||||
- **bitvid stays static; infra is the creator's.** The Media Node/Bridge is real
|
||||
server infra, but per the **blanket rule it's never bitvid-operated** — it's
|
||||
self-hosted by the creator or replaced by an external provider. So the ops/cost
|
||||
burden lives with whoever self-hosts, not bitvid.network. The static client is
|
||||
unaffected; Phase-1 external mode needs no infra at all.
|
||||
- **Self-hoster burden (DECISION 1b).** Bandwidth/storage cost, encoder config, and
|
||||
keeping the node reachable fall on the self-hoster. Good docs + a turnkey
|
||||
headless Bridge (one binary) are the mitigation.
|
||||
- **Signing during long streams (DECISION 2).** Tab-open (A) is fragile for long
|
||||
broadcasts; NIP-53 lets clients treat a live event with no update in ~1h as
|
||||
ended, so plan a heartbeat and a graceful "stale → ended" story.
|
||||
- **CORS / cross-origin HLS** — segments served by the node's origin must allow the
|
||||
bitvid origin (same class as the storage/edge CORS work).
|
||||
- **Cost & abuse of a managed node (DECISION 1a)** — bandwidth/storage cost,
|
||||
transcode temptation, and moderation of who can ingest. Self-host (1b) pushes
|
||||
this to the operator.
|
||||
- **CORS / cross-origin HLS** — segments served by the (self-hosted) node's origin
|
||||
must allow the bitvid origin (same class as the storage/edge CORS work).
|
||||
- **Encoder compatibility** — pass-through requires H.264/AAC + sane keyframes;
|
||||
document encoder settings; reject or warn on incompatible input.
|
||||
- **Scope discipline** — publishing is genuinely large; ship Phase 1 (no infra)
|
||||
|
||||
Reference in new issue
Block a user