Self-hosted IRL streaming + chat + clips + VOD stack
Find a file
davik123 cbbef4e9e8 Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor
Adds four new backend services (notifier for web push, admin for VOD management,
plus companions) and dozens of client changes since the initial import:

Backends:
- notifier/            web push (VAPID) + optional SMTP email; watches streams.json transitions
- admin/               password-gated VOD rename/delete-mark endpoint
- clips-api            (existing) — 15/30/60/90/120 s picker on the client
- auth-api             (existing) — magic-link register/identify

Frontend additions:
- www/notify.html      subscribe to browser push
- www/admin.html       VOD manage
- www/logs.html        chat log viewer (previously an overlay)
- www/site-nav.js      shared top-bar hamburger across all pages
- www/sw.js            push service worker
- www/register*.html   Discord OAuth landing pages

Behavior changes:
- chat.html            whisper handling with orange-bordered private message boxes,
                       auto-linkify URLs, 45 s WebSocket PING keepalive
- Chat bot             !register/!identify replies are now whispered (bearer-token
                       privacy), !whoami added, PAM off + MaxNickLength=20 in ngircd
- Live notifier + web push both filter to main-stream transitions only
- Side stream          detected by name (movies/sidestream/etc), memfs-only, HTTP
                       HEAD probe against Restreamer for liveness
- VOD deletion         mark-and-sweep via .trash + vod_janitor cron (safe against
                       in-flight ffmpeg encodes)
- Cinema mode          fixed to keep shared hamburger visible
- Landing              latest 3 VODs, orange 'side stream live' card, Notify button

Documentation:
- docs/ARCHITECTURE.md    full rewrite covering all seven services
- docs/SETUP.md           steps for the four new services + updated verification
- docs/OPERATIONS.md      web push testing, mark-and-sweep semantics, diagnostics
- docs/AI_REBUILD_PROMPT.md   fresh input list + design-intent for LLM handoff

Secrets: all sanitized to REPLACE_ME_* placeholders or *.example files.
Runtime state (subscribers, tokens, logs, VOD files) covered by .gitignore.
2026-07-13 05:26:34 +00:00
admin Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
auth-api Initial import of mentula.tv stack 2026-07-11 21:53:36 +00:00
chat Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
clips-api Initial import of mentula.tv stack 2026-07-11 21:53:36 +00:00
docker-templates Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
docs Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
live-notifier Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
nginx Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
notifier Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
user-scripts Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
webircgateway Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
www Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
.gitignore Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00
README.md Sync full state: notifier, admin, side-stream, whispers, keepalive, VOD janitor 2026-07-13 05:26:34 +00:00

mentula.tv

A self-hosted IRL streaming and community site. Multi-platform live view, chat, VOD archive with automatic re-encode, clips (from live and from VODs), OBS chat overlay, phone TTS, Discord OAuth nick reservation, web push notifications, Discord webhooks, admin panel — all running on a single Unraid box behind one nginx.

What's here

A landing page that auto-detects your active stream across Twitch, Kick, YouTube, AngelThump, and your own RTMP ingest (via Restreamer). A second "side stream" slot for movies or guest broadcasts, memfs-only so no VOD is created. A web chat backed by ngircd + a WebSocket gateway, with per-user mIRC colors and passwordless Discord-OAuth nick reservation. An automatic clip pipeline where viewers hit "Clip that" during a live stream (or from a VOD playhead), pick a length between 15120 s, and get a shareable URL in seconds; live clips backfill their VOD offset once the session archives. A VOD pipeline that watches Restreamer's disk HLS, fast-remuxes ended sessions to MP4 within minutes, then re-encodes with libx265 overnight. Web push notifications so subscribers get an OS-level popup when the stream starts. A Discord webhook that posts on live/offline transitions. An IRC-driven FAQ bot with !help, !discord, !vods, !clip, !register, !identify, !uptime, !whoami. A phone-friendly TTS reader for chat. An OBS browser-source overlay for chat with per-user colors, black outline, drop shadow. A password-gated admin panel for renaming and (safely) deleting VODs.

Layout

www/               Public static pages served by nginx (chat, live, clips, VOD player, admin, etc.)
nginx/             Nginx site config with all reverse-proxy rules
chat/              ngircd config + IRC bot (logger, FAQ, magic-link commands)
webircgateway/     WebSocket <-> IRC bridge (Go source cloned at build)
clips-api/         Python service: creates clips from live HLS or from VODs
auth-api/          Python service: Discord OAuth nick reservation
notifier/          Python service: web push (VAPID) + email subscribers, watches live/offline transitions
admin/             Python service: password-gated VOD rename/delete-mark
live-notifier/     Cron-driven Discord webhook (independent of notifier — fires on live/offline flips)
user-scripts/      Bash cron jobs (Unraid user.scripts): VOD rotate/archive/janitor, chat-bot watchdog, etc.
docker-templates/  Reference dockerMan XML for Restreamer / nginx / ngircd (Unraid-specific)
docs/              Architecture, setup, operations, AI-consumable rebuild guide

Start here

  • docs/ARCHITECTURE.md — system diagram, container graph, data flow, gotchas.
  • docs/SETUP.md — install from scratch. Unraid-specific + portable notes.
  • docs/AI_REBUILD_PROMPT.md — single-shot prompt to hand another LLM.
  • docs/OPERATIONS.md — day-to-day: adding chat commands, rotating secrets, VOD retention.

Design tenets

  1. Single reverse proxy. nginx terminates TLS and routes everything at one hostname. No sub-app manages its own certs.
  2. Small stateless services. Each backend is one Python file behind an internal port. State is JSON files on disk.
  3. Progressive enhancement. Anonymous by default everywhere — chat, clips, viewing all work without an account. Registration is a !register opt-in.
  4. Mark and sweep for destruction. Nothing gets deleted from disk synchronously with a user action — the admin marks VODs for deletion, a janitor cron purges when safe (so an in-flight ffmpeg encode can't race the delete).
  5. Recoverable. Every long-running data producer (recording, chat logs, clips, subscriber lists) writes to bind-mounted appdata so a container wipe doesn't destroy history.
  6. Human- and LLM-readable. Configs are declarative, code is grep-friendly, docs explain the "why" so future maintainers (human or AI) can make correct judgment calls.

Non-goals

Not a general-purpose media server (Emby/Jellyfin, separate). Not designed for tens of thousands of concurrent viewers — sized for one streamer with a modest audience.