Fix: relay WebSocket messages as text frames (browsers got Blobs they could not parse)

Root cause of 'track does not start': the server re-broadcast incoming frames as
binary (Buffer), so the browser output page received Blobs, JSON.parse failed,
and every command (playTrack, etc.) was silently dropped — only the text-encoded
lastEffect sync got through. Broadcast as text now; net.js also handles Blob
defensively. Also: no-store for app assets + kiosk --disk-cache-size=1 so
redeploys always take effect; /api/clients debug endpoint; /api/peaks duration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
lucianoandClaude Opus 4.8 committed 2026-06-29 14:58:33 +02:00
1 parent c0230ee1d6
commit 1a66a46b1f
4 files changed
+22 -4

No files matched your search

+11 -2
View File
@@ -30,7 +30,11 @@ function ffmpegPath() {
const app = express();
app.use(express.json({ limit: '4mb' }));
app.use(express.static(path.join(ROOT, 'public')));
// Never cache the app shell (HTML/JS/CSS): on a local appliance the network is
// fast and this guarantees the kiosk/phone always run the latest deployed code.
// Media files (large) stay cacheable.
app.use((req, res, next) => { if (!req.path.startsWith('/media')) res.set('Cache-Control', 'no-store'); next(); });
app.use(express.static(path.join(ROOT, 'public'), { etag: false, lastModified: false }));
app.use('/media', express.static(MEDIA_DIR));
app.use('/svg', express.static(SVG_DIR));
@@ -63,6 +67,8 @@ app.post('/api/upload', upload.array('files'), (req, res) => {
res.json({ ok: true, count: (req.files || []).length });
});
app.get('/api/clients', (_req, res) => { res.json([...wss.clients].map((c) => ({ role: c.role, open: c.readyState === 1 }))); });
app.get('/api/svgs', (_req, res) => {
let files = [];
try { files = fs.readdirSync(SVG_DIR).filter(f => /\.svg$/i.test(f)); } catch (e) {}
@@ -163,7 +169,10 @@ wss.on('connection', (ws, req) => {
}
});
function broadcast(role, data) {
wss.clients.forEach(c => { if (c.readyState === 1 && c.role === role) c.send(data); });
// Always send a TEXT frame: browsers receive binary frames as Blob and would
// fail JSON.parse, so commands would silently never reach the output page.
const txt = typeof data === 'string' ? data : data.toString();
wss.clients.forEach(c => { if (c.readyState === 1 && c.role === role) c.send(txt); });
}
server.listen(PORT, () => {