The four overlays that read /data/playlist.js (loading, goodbye,
music-box, music/nc) only ever consumed `tracks.length` for cosmetic
"LIBRARY :: N TRACKS" / "indexed N tracks" flavor text — all live
playback signal flows through bridges/mpd-state.py over OBS WS. The
142 KB JSON, ffprobe walk, and ETag-cached route were all producing
one integer that MPD itself already knows.
RigData::playlistCount() now shells `mpc stats` and parses "Songs: N",
returning 0 on any failure (treated by callers as empty library).
Removes RigPlaylistCommand, DataController::playlist(), the
/data/playlist.js route, the per-overlay <script src> + window.__PLAYLIST
shims, and the stale storage/data/playlist.json artifact.
AudioController still consumes config('rig.music_dirs') for the HTTP
audio stream — that's orthogonal and stays.
OPHI-118 webapp
Laravel app that renders every on-stream overlay for the OPHI-118 Twitch rig and
hosts the streamer's control surfaces. Runs under supervisord on http://127.0.0.1:1118/.
Looking for the rig-wide picture (OBS, MPD, twitch-bot, deployment)? See
../README.md. This file is just the webapp.
What's in here
Control panel — /
Tile-based dashboard. Entry point from a browser bookmark; not used by OBS itself.
- ONBOARD — opens the project-loading wizard.
- SCENES — opens the full route index.
- ophi118.com — public channel landing page.
- gamez.ciemnosc.com — self-hosted game-server roster.
Onboard wizard — /onboard
Web equivalent of php artisan rig:loading. Compiles the Project Loading manifest
(game, subtitle, countdown, camera/mic state) and optionally pushes the channel
title + category to Twitch via Helix.
- Type-ahead game search against the Twitch Helix
search/categoriesendpoint, debounced. ↑/↓/Enter/Esc keys to pick a match; locks thegameId. - Live preview mirrors what the
/loadingoverlay will render — every edit re-renders the terminal-style output immediately. - Stepper for the countdown, ENABLED/DISABLED toggles for camera/mic, push-to-Twitch checkbox to commit the channel update via Helix.
- Graceful fallback: with
TWITCH_CLIENT_ID/TWITCH_ACCESS_TOKENunset, the search disables and the manifest still saves locally.
Scenes index — /scenes
All overlay URLs the OBS browser-sources point at, plus the data endpoints.
Overlay routes
Browser sources in basic/scenes/Default_Stream_HUD.json consume these. Edits
to the Blade views are picked up on the next OBS Refresh cache — no server
restart needed.
| Route | Purpose |
|---|---|
/landing |
Fallout-style "PLEASE STAND BY" + telemetry rotator |
/loading |
Terminal-style Project Loading + countdown |
/game |
Game HUD (camera-frame OBS-WS sync, status bar) |
/desktop |
Desktop HUD (camera + screen-capture frames) |
/goodbye |
Sign-off terminal + "OFFLINE FOR" counter |
/music-box |
Full-screen music box terminal |
/music-box/widget |
Compact 549×880 widget |
/music-box/cover |
Album-art widget (?bars=0 for compact mode) |
/music-box/nc |
ncurses-styled 2-pane variant |
/music-daemon |
Passive WebSocket listener (diagnostic) |
Data + control endpoints
| Route | Notes |
|---|---|
GET /cover.jpg |
Streams bridges/cover.jpg (kept fresh by mpd-state.py) |
GET /track?p=<base64> |
Audio stream — path-traversal-guarded |
POST /cmd/{skip|prev|pause|resume} |
Broadcasts mpd:cmd over OBS WebSocket |
Artisan commands
Each lives at app/Console/Commands/Rig*Command.php. Run from the webapp/
directory.
php artisan rig:setup # gen public/js/obs-config.js + OBS_WS_* in .env
php artisan rig:telemetry # refresh storage/data/telemetry.json
php artisan rig:telemetry --collect # re-prompt every field interactively
php artisan rig:loading # interactive Project Loading manifest (CLI mirror of /onboard)
php artisan rig:cmd skip # CLI mirror of POST /cmd/skip
Running it
The supervisord program file lives at ../scripts/obs-webapp.supervisord.conf
and is installed (root-owned) to /etc/supervisor.d/obs-webapp.conf by
scripts/deploy-rig.sh.
sudo supervisorctl status obs-webapp # → RUNNING
sudo supervisorctl restart obs-webapp # after route / controller / .env changes
tail -F storage/logs/supervisord.{out,err}.log
For local hacking without supervisord:
php artisan serve --host=127.0.0.1 --port=1118
When to restart
| Change | Action |
|---|---|
Blade view (resources/views/) |
OBS → right-click source → Refresh cache |
Static CSS / JS (public/) |
Same — Refresh cache |
Route / controller / service / config / .env |
sudo supervisorctl restart obs-webapp |
Layout
webapp/
├── app/
│ ├── Console/Commands/ rig:setup, rig:telemetry, rig:loading,
│ │ rig:cmd
│ ├── Http/Controllers/ Overlays/{Landing,Loading,Game,Desktop,
│ │ Goodbye,MusicBox,MusicDaemon}, Data,
│ │ MusicCommand, Audio, Onboard
│ ├── Services/ ObsWsClient (Pawl), TwitchHelix,
│ │ HardwareSnapshot
│ └── Support/RigData.php
├── resources/
│ ├── views/
│ │ ├── home.blade.php /
│ │ ├── scenes.blade.php /scenes
│ │ ├── onboard.blade.php /onboard
│ │ ├── overlays/ per-scene overlays
│ │ ├── partials/ topbar, hud-strip, crt-overlays, …
│ │ └── layouts/ overlay base layout
│ └── img/ favicon + screenshots (this README)
├── public/
│ ├── css/hud.css shared HUD chrome, scanlines, terminal styling
│ ├── js/ hud, crt-static, obs-ws-bootstrap, obs-ws-mini
│ ├── audio/static-hum.wav ffmpeg_source (not browser-served)
│ └── favicon.ico → symlink to ../resources/img/favicon.ico
├── routes/web.php
├── config/rig.php storage paths, OBS WS creds, Twitch keys
└── storage/data/ rig:* commands write JSON here
├── loading.json
└── telemetry.json
Config
.env keys the webapp cares about:
APP_URL=http://127.0.0.1:1118
OBS_WS_URL=ws://localhost:4455
OBS_WS_PASSWORD=… # written by `php artisan rig:setup`
TWITCH_CLIENT_ID=…
TWITCH_ACCESS_TOKEN=… # legacy TWITCH_TOKEN is also accepted
TWITCH_BROADCASTER_ID=…
RIG_NAME=…
OBS_PROFILE=ophi118
MUSIC_DIR_1=…
See .env.example for the full set.



