Release v2.12.0
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 2m6s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 33s

This commit is contained in:
lzstealth committed 2026-09-11 17:22:31 +01:00
1 parent bdb5ab4bac
commit 0a03cdd0b7
32 files changed
+2211 -18

No files matched your search

+55
View File
@@ -13,6 +13,7 @@ const { createPlayerPlaylistService } = require('../player/playlist');
const { commitDeviceBinding, bindPlayerToScreen, getOnboardingStatus, getPlayerPublicBaseUrl } = require('../player/onboarding');
const { createStyledQrCodeSvg } = require('../data/qr-code');
const { verifyPageAuthToken } = require('#src/request-auth');
const { collectLocalControlUsers } = require('../web/lib/local-control-users');
function createThinClientConfig() {
@@ -186,6 +187,7 @@ async function start() {
const server = http.createServer(app);
const pool = common.createPool();
const config = createThinClientConfig();
const localPlayerInternalUrl = String(process.env.LOCAL_PLAYER_INTERNAL_URL || process.env.PLAYER_INTERNAL_URL || '').trim().replace(/\/$/, '');
const playerPlaylistService = createPlayerPlaylistService({
pool: pool,
common: common,
@@ -416,6 +418,18 @@ async function start() {
return sendPlayerCommandToSocket(socket, commandPayload);
}
async function syncLocalControlOnRegistration(socket, player) {
const playerInternalUrl = String(player && player.internal_base_url || '').trim().replace(/\/$/, '');
if (localPlayerInternalUrl && playerInternalUrl === localPlayerInternalUrl) {
return;
}
const users = await collectLocalControlUsers(pool);
await sendPlayerCommandToSocket(socket, {
command: 'sync-local-control',
users: users
});
}
function sendPlayerCommandToSocket(socket, commandPayload) {
if (!socket || socket.readyState !== WebSocket.OPEN) {
return Promise.resolve({ ok: false, status: 503, error: 'Player is not connected.' });
@@ -1009,6 +1023,9 @@ async function start() {
}
logBridge(`Player ${formatPlayerConnectionLabel(deviceId)} has connected`);
socket.send(JSON.stringify({ type: 'registered', ok: true, player: player }));
syncLocalControlOnRegistration(socket, player).catch(function (error) {
logBridge(`Unable to synchronize Local Control authorization for ${formatPlayerConnectionLabel(deviceId)}`, error);
});
return;
}
@@ -1327,6 +1344,44 @@ async function start() {
}
});
app.post('/api/internal/sync/player-control', requireRequestAuth, async function (_req, res, next) {
try {
logBridge('Relaying player control sync request to web');
const webBaseUrl = resolveWebBaseUrl(_req);
if (!webBaseUrl) {
return res.status(502).json({ error: 'Web base URL is not configured.' });
}
const requestBody = _req.body && typeof _req.body === 'object' && !Array.isArray(_req.body)
? Object.assign({}, _req.body)
: {};
const response = await fetch(`${webBaseUrl}/api/internal/sync/player-control`, {
method: 'POST',
headers: Object.assign({
Accept: 'application/json',
'Content-Type': 'application/json'
}, createRequestAuthHeaders({
method: 'POST',
pathname: '/api/internal/sync/player-control',
body: requestBody
})),
body: JSON.stringify(requestBody)
});
res.status(response.status);
const contentType = response.headers.get('content-type');
if (contentType) {
res.type(contentType);
}
res.send(await response.text());
} catch (error) {
logBridge('Player control sync relay failed', {
error: error && error.message ? error.message : String(error)
});
next(error);
}
});
fs.mkdirSync(config.mediaDir, { recursive: true });
server.listen(config.port, function () {