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.
|
||
|---|---|---|
| admin | ||
| auth-api | ||
| chat | ||
| clips-api | ||
| docker-templates | ||
| docs | ||
| live-notifier | ||
| nginx | ||
| notifier | ||
| user-scripts | ||
| webircgateway | ||
| www | ||
| .gitignore | ||
| README.md | ||
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 15–120 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
- Single reverse proxy. nginx terminates TLS and routes everything at one hostname. No sub-app manages its own certs.
- Small stateless services. Each backend is one Python file behind an internal port. State is JSON files on disk.
- Progressive enhancement. Anonymous by default everywhere — chat, clips, viewing all work without an account. Registration is a
!registeropt-in. - 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).
- 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.
- 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.