experiments of a tiny cytube-like player with yt-dlp
0

Configure Feed

Select the types of activity you want to include in your feed.

7 1 0

Clone this repository

https://tangled.org/karitham.dev/moqbox https://tangled.org/did:plc:f5jvakvxxw4ffgyrxx2ut5jv
git@tangled.org:karitham.dev/moqbox git@tangled.org:did:plc:f5jvakvxxw4ffgyrxx2ut5jv

For self-hosted knots, clone URLs may differ based on your setup.



README.md

moqbox#

Shared media rooms. Paste a URL, everyone watches together. Requires ffmpeg and yt-dlp on PATH. Run with cargo run, open localhost:3000.

Architecture#

One Axum binary serving SSR pages, REST API, and a custom media streaming protocol over WebSocket on the same port. Per-room mpsc actor processes commands (queue, skip, chat, register, metadata) sequentially -- no locks. Room state persisted to SQLite (WAL mode).

Async metadata extraction#

The ingest HTTP handler returns immediately after queuing a URL. Metadata extraction (yt-dlp) runs in a spawned task within the actor. When extraction completes, the result is sent back to the actor which updates the DB and pushes the resolved metadata to clients via the state broadcast channel.

sequenceDiagram
    participant Client
    participant HTTP as HTTP Handler
    participant Actor as Room Actor
    participant Extract as Extraction Task

    Client->>HTTP: POST /api/ingest
    HTTP->>Actor: QueueUrl(url)
    HTTP-->>Client: {ok: true}
    Actor->>Actor: insert placeholder
    Actor->>Extract: spawn extraction
    Extract->>Actor: MetadataReady
    Actor->>Client: PublishSnapshot via WS

Playback pipeline#

yt-dlp resolves URLs to direct stream addresses. FFmpeg transcodes to fragmented MP4 at real-time speed (-re). fMP4 boxes are read from stdout as moof+mdat pairs and published over per-room broadcast channels. The video init segment (ftyp+moov) is cached for late-joining clients.

State machine#

PlaybackState is pure -- all transitions are deterministic. The actor follows the impure-pure-impure sandwich:

  1. Gather -- DB queries, wall clock
  2. Transition -- PlaybackState::transition(event, now) -- returns Effects
  3. Commit -- actor executes effects

Events: TrackQueued, Skip, TrackEnded, MetadataUpdated. Effects: AbortPipeline, StartPipeline, PersistStarted, PersistFinished, PublishSnapshot.

Client delivery#

Clients use MSE with a single SourceBuffer in segments mode. A state track (watch channel) delivers current playback position, queue, and history as JSON. Queue items carry a pending flag while metadata is unresolved. Chat is persisted to SQLite, replayed on subscribe, then live.