Files
obs-config/webapp/app/Support/RigData.php
Jakub Zych fd1c78b333 webapp: drop rig:playlist pipeline, source track count from mpc stats
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.
2026-05-22 21:04:24 +02:00

96 lines
2.8 KiB
PHP

<?php
namespace App\Support;
use Symfony\Component\Process\Process;
use Throwable;
class RigData
{
private array $cache = [];
private ?int $mpdSongCount = null;
public function loading(): array
{
return $this->read('loading.json', [
'game' => null, 'gameId' => null, 'subtitle' => null,
'countdownMin' => 5, 'camera' => true, 'microphone' => true,
'compiledAt' => null,
]);
}
public function telemetry(): array
{
return $this->read('telemetry.json', [
'rig' => config('rig.rig_name') ?? 'unknown',
'host' => [], 'cpu' => [], 'gpu' => [], 'mem' => [], 'obs' => [],
]);
}
/**
* Track count from MPD (the live library, queried via `mpc stats`).
* Returns 0 if mpc is missing or MPD is unreachable — callers treat
* that as "empty library" and degrade their flavor text accordingly.
*/
public function playlistCount(): int
{
if ($this->mpdSongCount !== null) return $this->mpdSongCount;
try {
$proc = new Process(['mpc', 'stats']);
$proc->setTimeout(2);
$proc->run();
if ($proc->isSuccessful() && preg_match('/^Songs:\s*(\d+)/m', $proc->getOutput(), $m)) {
return $this->mpdSongCount = (int) $m[1];
}
} catch (Throwable) {
// fall through
}
return $this->mpdSongCount = 0;
}
public function cmd(): array
{
return $this->read('cmd.json', ['id' => 0, 'type' => 'none', 'ts' => 0]);
}
public function writeCmd(string $type): array
{
$cmd = ['id' => (int) (microtime(true) * 1000), 'type' => $type, 'ts' => time()];
$this->write('cmd.json', $cmd);
$this->cache['cmd.json'] = $cmd;
return $cmd;
}
public function coverPath(): string
{
return (string) config('rig.cover_jpg');
}
private function read(string $file, array $fallback): array
{
if (isset($this->cache[$file])) return $this->cache[$file];
$path = rtrim(config('rig.storage_data'), '/') . '/' . $file;
if (!is_file($path)) return $this->cache[$file] = $fallback;
$raw = @file_get_contents($path);
if ($raw === false) return $this->cache[$file] = $fallback;
$parsed = json_decode($raw, true);
if (!is_array($parsed)) return $this->cache[$file] = $fallback;
return $this->cache[$file] = $parsed + $fallback;
}
private function write(string $file, array $data): void
{
$dir = rtrim(config('rig.storage_data'), '/');
if (!is_dir($dir)) @mkdir($dir, 0775, true);
file_put_contents(
$dir . '/' . $file,
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
);
}
}