Files
obs-config/webapp/app/Console/Commands/RigSetupCommand.php
Jakub Zych 059f069ef4 webapp: introduce Laravel app under webapp/ for scene overlays
Replaces the per-scene HTML directories (landing/, loading/, game/,
desktop/, goodbye/, music-box/, music/) with a single Laravel app
serving every overlay over HTTP. Supervisord runs `php artisan serve`
on 127.0.0.1:1118 and the OBS scene JSON now references HTTP routes
instead of file:// URLs.

Highlights:
 - public/css/hud.css consolidates the duplicated HUD chrome,
   scanlines/vignette/flicker, terminal styling, and pulse keyframes
   that were copy-pasted across all seven scenes.
 - Blade partials own hud-strip, crt-overlays, obs-ws-scripts,
   camera-frame, screen-frame; the seven scenes extend a shared
   overlay layout.
 - Artisan commands (`rig:setup`, `rig:telemetry`, `rig:loading`,
   `rig:playlist`, `rig:cmd`) replace the shell scripts that wrote
   per-rig JSON snapshots. TwitchHelix + HardwareSnapshot services
   handle the work the bash + Python helpers used to.
 - ObsWsClient + MusicCommandController kill the 250 ms cmd.js poll
   in the music daemon: POST /cmd/{skip|prev|pause|resume} opens a
   short-lived Pawl WS, authenticates, and broadcasts mpd:cmd.
 - AudioController streams files from the configured music dirs so
   CEF can load tracks under the HTTP origin (Chromium blocks
   HTTP-origin pages from loading file:// media).
 - DataController serves /data/playlist.js (with ETag mtime cache)
   and /cover.jpg (no-store) so the existing overlays' window.__PLAYLIST
   and cover.jpg cache-bust pattern keeps working.

scripts/obs-webapp.supervisord.conf is the supervisord unit; install
to /etc/supervisor.d/obs-webapp.conf.
scripts/rewrite-scene-urls.py is a one-shot tool that rewrites
basic/scenes/Default_Stream_HUD.json from file:// to HTTP URLs.
basic/scenes/Default_Stream_HUD.json.pre-webapp is the rollback
artifact (made with OBS closed; full pre-migration state).

The seven old scene directories, vendor/, and the bash scripts are
still on disk pending visual verification; the next commit will
prune them.
2026-05-21 12:47:10 +02:00

85 lines
2.9 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class RigSetupCommand extends Command
{
protected $signature = 'rig:setup';
protected $description = 'Generate public/js/obs-config.js and OBS_WS_* env vars from plugin_config/obs-websocket/config.json';
public function handle(): int
{
$src = (string) config('rig.obs_ws_config_json');
if (!is_file($src)) {
$this->error("{$src} not found.");
$this->line(' Open OBS once with obs-websocket loaded so it generates the config.');
return self::FAILURE;
}
$cfg = json_decode((string) file_get_contents($src), true);
if (!is_array($cfg)) {
$this->error("{$src} did not parse as JSON.");
return self::FAILURE;
}
$port = (int) ($cfg['server_port'] ?? 4455);
$pass = (string) ($cfg['server_password'] ?? '');
$url = "ws://localhost:{$port}";
$out = (string) config('rig.obs_config_js');
@mkdir(dirname($out), 0775, true);
$js = <<<JS
// Auto-generated by `php artisan rig:setup`. Reflects the current contents of
// plugin_config/obs-websocket/config.json. Re-run if you rotate the password.
window.__OBSWS = {
url: {$this->jsString($url)},
password: {$this->jsString($pass)},
};
JS;
file_put_contents($out, $js);
$this->info(" ✓ wrote {$out}");
// Mirror into .env so MusicCommandController / ObsWsClient can authenticate.
$this->writeEnv('OBS_WS_URL', $url);
$this->writeEnv('OBS_WS_PASSWORD', $pass);
$this->info(' ✓ updated .env OBS_WS_URL / OBS_WS_PASSWORD');
$this->line('');
$this->line(" url = {$url}");
$this->line(' password = ' . ($pass === '' ? '(none)' : '(set, ' . strlen($pass) . ' chars)'));
$this->line('');
$this->line(' → if obs-webapp is running under supervisord, restart it so the new env takes effect:');
$this->line(' sudo supervisorctl restart obs-webapp');
return self::SUCCESS;
}
private function jsString(string $s): string
{
return json_encode($s, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
private function writeEnv(string $key, string $value): void
{
$env = base_path('.env');
$raw = is_file($env) ? file_get_contents($env) : '';
$line = $key . '=' . $this->escapeEnvValue($value);
if (preg_match("/^{$key}=.*$/m", $raw)) {
$raw = preg_replace("/^{$key}=.*$/m", $line, $raw);
} else {
$raw = rtrim($raw, "\n") . "\n" . $line . "\n";
}
file_put_contents($env, $raw);
}
private function escapeEnvValue(string $v): string
{
if ($v === '') return '';
if (preg_match('/[\s"#=]/', $v)) {
return '"' . str_replace('"', '\"', $v) . '"';
}
return $v;
}
}