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.

Rust 83.4%
TypeScript 11.2%
CSS 4.4%
HTML 0.5%
Nix 0.5%
33 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.

TODO#

  • Gifs in chat
  • Improved UX
    • Perhaps playlist / history should be somewhere else?
    • Need space for gifs
    • Improve over the default player (audio level normalization?)
    • Fix player card layering / layouting
  • Built-in search?
  • Track handling
    • Better caching
    • Cleaner file-system backend (s3 at some point?)
    • Resolving a link that we have the file for should not re-resolve
  • User management
    • ATproto login
    • Anon "login" (pick a username -- server-side)
  • Nice OG images of a room (name + most played video thumbnail, title, a few active members?)
  • Direct track upload
  • Reorder up-next tracks
  • Shuffle up-next tracks
  • Publish atmo.rsvp events for sharing moments together
  • Actual MOQ transport layer for chromium users / polyfill?
  • ACL / private rooms? (restrict to a set of dids?)

Shipped#

  • Named rooms with /r/{name} URLs (create_room returns the name; the API resolves name → UUID internally)
  • Per-room autoplay + skip-threshold settings (room settings panel in the playlist section)
  • Vote skip (replace skip with vote_skip; threshold-based, default 34%)
  • Auto-play triggers on client connect (in addition to the idle sweep)

Quick Start#

# Backend
cargo run
# Open http://localhost:3000

# Or with the SolidJS dev server (hot reload):
cd frontend && npm install && npm run dev
# Opens http://localhost:5173, proxies /api/* to backend

The built frontend (SolidJS SPA) is pre-committed to static/dist/, so cargo run alone works. If you're hacking on the frontend, use the Vite dev server from frontend/.

Configuration#

Flag Env Variable Default Description
--http-addr MOQBOX_HTTP_ADDR 0.0.0.0:3000 HTTP listen address
--cache-dir MOQBOX_CACHE_DIR /tmp/moqbox yt-dlp download dir
--db-path MOQBOX_DB_PATH moqbox.db SQLite database file

Architecture#

One Axum binary serving a REST API, WebSocket state/chat, and HTTP Range media serving on the same port. Per-room mpsc actor processes commands sequentially. Room state persisted to SQLite (WAL mode).

graph TB
    Browser[SolidJS SPA] -->|REST + WS| Axum[Axum Server]
    Browser -->|HTTP Range| Axum
    Axum -->|commands| Registry[Room Registry]
    Registry -->|spawn| Actor[Room Actor]
    Actor -->|effects| Store[SQLite Store]
    Actor -->|spawn| Download[Download Task]
    Download -->|yt-dlp| Media[Media File on Disk]
    Actor -->|publish| WS[WebSocket Clients]

Perpetual playlist#

Rooms have a persistent playlist. When the queue is empty and the room is idle, the next playlist entry is auto-filled. Entries are pre-resolved (downloaded) at add-time so auto-played tracks never show "Loading...".