Files
obs-config/webapp/resources/views/overlays/music/daemon.blade.php
Jakub Zych 0b4f121a92 webapp: archive pre-migration scene dirs + bash scripts, update docs
Moves the seven HTML scene dirs (landing/, loading/, game/, desktop/,
goodbye/, music-box/, music/) and the superseded bash helpers (setup.sh,
loading.sh, playlist.sh, telemetry.sh) into archived/ rather than deleting.
The Laravel webapp/ replaces all of them; archived/README.md spells out
the rollback procedure.

Also:
 - rewrite the relevant sections of CLAUDE.md so it points at webapp/
   blade views, the Artisan commands, and the supervisord lifecycle
   (`supervisorctl restart obs-webapp` after route / controller / .env
   changes; Blade view edits are still safe-while-running via OBS's
   Refresh cache).
 - extend scripts/deploy-rig.sh to install php + composer + supervisor,
   run `composer install`, copy obs-webapp.supervisord.conf into
   /etc/supervisor.d/, start the program, and call `php artisan
   rig:setup` + `rig:telemetry --collect` instead of the old bash.
 - .gitignore catches the generated machine-local files that came along
   when the old scene dirs moved (telemetry.js, loading.json, playlist.js,
   cmd.js, obs-config.js).
 - daemon.blade.php is now passive — listens to mpd:state but does not
   play audio or broadcast its own queue, so it stops fighting with
   bridges/mpd-state.py (the post-browser-daemon-migration source of
   truth for mpd:state).
 - nc.blade.php overrides .terminal { overflow: hidden } from hud.css
   so the `┤ TERMINAL ├` and `┤ NOW PLAYING ├` pane-tabs stick above
   the pane border instead of being clipped.
2026-05-21 13:08:49 +02:00

88 lines
3.6 KiB
PHP

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>OPHI-118 / Music Daemon</title>
<style>
/* Diagnostic status page. Music is actually played by MPD (system service)
and broadcast over OBS WS by bridges/mpd-state.py. This page no longer
plays audio or broadcasts mpd:state — those would conflict with the
bridge. It only listens to incoming mpd:state events so you can sanity-
check the bridge from a single browser source. */
html, body { margin: 0; padding: 0; background: #0a0e0a; overflow: hidden; color: #5fdc62;
font: 14px/1.45 'DejaVu Sans Mono', 'Consolas', monospace; }
#status { padding: 12px 14px; }
#status h1 { font-size: 11px; letter-spacing: 0.25em; color: #2c8d2f; margin: 0 0 8px; font-weight: 700; }
#status .row { display: flex; gap: 10px; margin: 2px 0; }
#status .k { color: #2c8d2f; min-width: 70px; }
#status .v { color: #97f99a; word-break: break-all; }
#status .err { color: #ff6f5a; }
#status .ok { color: #97f99a; }
#status .dim { color: #2c8d2f; }
</style>
</head>
<body>
<div id="status">
<h1>OPHI MUSIC DAEMON (passive)</h1>
<div class="row"><span class="k">role</span><span class="v dim">listener playback handled by mpd + bridges/mpd-state.py</span></div>
<div class="row"><span class="k">ws</span><span class="v" id="s-ws">init…</span></div>
<div class="row"><span class="k">now</span><span class="v" id="s-now"></span></div>
<div class="row"><span class="k">queue</span><span class="v" id="s-queue"></span></div>
<div class="row"><span class="k">elapsed</span><span class="v" id="s-elapsed"></span></div>
<div class="row"><span class="k">last cmd</span><span class="v" id="s-cmd"></span></div>
</div>
@include('partials.obs-ws-scripts')
<script>
'use strict';
const $ws = document.getElementById('s-ws');
const $now = document.getElementById('s-now');
const $queue = document.getElementById('s-queue');
const $elapsed = document.getElementById('s-elapsed');
const $cmd = document.getElementById('s-cmd');
const pad = n => String(n).padStart(2, '0');
const fmtClock = s => (!isFinite(s) || s < 0)
? '--:--' : `${pad(Math.floor(s / 60))}:${pad(Math.floor(s % 60))}`;
function setWs(text, cls = '') { $ws.textContent = text; $ws.className = 'v ' + cls; }
let obs = null;
async function connectOBS() {
if (!window.__OBSWS) {
setWs('public/js/obs-config.js MISSING — run `php artisan rig:setup`', 'err');
return;
}
try {
setWs(`connecting → ${window.__OBSWS.url}`);
obs = new OBSWSMini(window.__OBSWS.url, window.__OBSWS.password);
await obs.connect();
setWs('identified ✓', 'ok');
obs.addEventListener('close', () => {
setWs('closed — retrying in 2s', 'err');
setTimeout(connectOBS, 2000);
});
obs.onCustom('mpd:state', (s) => {
$now.textContent = s.title ? `${s.title}${s.artist ? ` ${s.artist}` : ''}` : '—';
const total = Number(s.total) || 0;
const idx = Number.isInteger(s.index) ? s.index : -1;
$queue.textContent = (total > 0 && idx >= 0)
? `${idx + 1} / ${total}${s.paused ? ' (paused)' : ''}`
: '—';
$elapsed.textContent = `${fmtClock(s.currentTime)} / ${fmtClock(s.duration)}`;
});
obs.onCustom('mpd:cmd', (d) => {
$cmd.textContent = `${d.type || '?'} @ ${new Date().toLocaleTimeString()}`;
});
} catch (e) {
setWs(`connect failed (${e.message}) — retrying`, 'err');
setTimeout(connectOBS, 2500);
}
}
connectOBS();
</script>
</body>
</html>