From e65a43b13cda0cd2dd0d0ca7639047b447220da2 Mon Sep 17 00:00:00 2001 From: Mark Rapson Date: Tue, 14 Jul 2026 15:30:05 +0100 Subject: [PATCH] Handle player redirects on screen slug change --- .gitignore | 1 + src/player.js | 25 +++++++++++++++---------- src/player/player-page.script.html | 5 +++++ src/webui.js | 7 +++++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index b374877..ef1f633 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ uploads/ +docker-compose.dev.yml .env npm-debug.log* yarn-debug.log* diff --git a/src/player.js b/src/player.js index 5ac63ec..506cfd2 100644 --- a/src/player.js +++ b/src/player.js @@ -396,27 +396,32 @@ async function start() { if (!command) { return res.status(400).json({ error: 'Command is required' }); } - if (['refresh', 'reload', 'pause', 'blackout', 'previous', 'next', 'left', 'right'].indexOf(command) === -1) { + if (['refresh', 'reload', 'redirect', 'pause', 'blackout', 'previous', 'next', 'left', 'right'].indexOf(command) === -1) { return res.status(400).json({ error: 'Unsupported command' }); } - const [screenRows] = await pool.query('SELECT id, name, slug FROM screens WHERE slug = ?', [req.params.slug]); - if (!screenRows.length) { - return res.status(404).json({ error: 'Screen not found' }); + const isRedirectCommand = command === 'redirect'; + let screenRows = []; + if (!isRedirectCommand) { + [screenRows] = await pool.query('SELECT id, name, slug FROM screens WHERE slug = ?', [req.params.slug]); + if (!screenRows.length) { + return res.status(404).json({ error: 'Screen not found' }); + } } - const commandPayload = command === 'blackout' && blackoutValue !== undefined - ? { - command: command, - blackout: blackoutValue - } + const commandPayload = req.body && typeof req.body === 'object' && !Array.isArray(req.body) + ? Object.assign({}, req.body, { command: command }) : command; + if (command === 'blackout' && blackoutValue !== undefined && commandPayload && typeof commandPayload === 'object') { + commandPayload.blackout = blackoutValue; + } const sent = connectionId ? sendCommandToConnection(req.params.slug, connectionId, commandPayload) : broadcastCommand(req.params.slug, commandPayload); + res.json({ - screen: screenRows[0], + screen: screenRows[0] || null, screenSlug: req.params.slug, command: command, connectionId: connectionId || null, diff --git a/src/player/player-page.script.html b/src/player/player-page.script.html index 90da36b..375655f 100644 --- a/src/player/player-page.script.html +++ b/src/player/player-page.script.html @@ -488,6 +488,11 @@ case 'refresh': refresh(); return; + case 'redirect': + if (payload.url) { + window.location.replace(String(payload.url)); + } + return; case 'pause': setPaused(!isPaused); return; diff --git a/src/webui.js b/src/webui.js index 5a5c974..e6b1fc2 100644 --- a/src/webui.js +++ b/src/webui.js @@ -1481,7 +1481,14 @@ async function start() { const slugInput = String(req.body.slug || '').trim(); const playlistId = req.body.playlist_id ? Number(req.body.playlist_id) : null; const slug = await common.uniqueScreenSlug(pool, common.slugify(slugInput || name), screen.id); + const previousSlug = String(screen.slug || '').trim(); await pool.query('UPDATE screens SET name = ?, slug = ?, playlist_id = ?, modified_by = ? WHERE id = ?', [name, slug, playlistId, getAuditUserId(req), screen.id]); + if (previousSlug && previousSlug !== slug) { + await forwardPlayerCommand(previousSlug, { + command: 'redirect', + url: `${PLAYER_PUBLIC_BASE_URL}/screen/${encodeURIComponent(slug)}` + }); + } res.redirect('/admin/screens?edit=' + screen.id + '&message=' + encodeURIComponent('Screen updated.')); } catch (error) { next(error);