Release 2.5.2

This commit is contained in:
2026-08-03 19:18:30 +01:00
parent 37345f3949
commit 9d5029eff6
21 changed files with 195 additions and 49 deletions
@@ -101,6 +101,7 @@
gap: 2.5rem;
min-width: 100%;
width: max-content;
backface-visibility: hidden;
will-change: transform;
animation: lower-third-scroll var(--announcement-scroll-duration, 20s) linear infinite;
}
@@ -144,10 +145,10 @@
@keyframes lower-third-scroll {
from {
transform: translateX(0);
transform: translate3d(0, 0, 0);
}
to {
transform: translateX(-50%);
transform: translate3d(-50%, 0, 0);
}
}
</style>
@@ -103,6 +103,7 @@
gap: 2.5rem;
min-width: 100%;
width: max-content;
backface-visibility: hidden;
will-change: transform;
animation: top-banner-scroll var(--announcement-scroll-duration, 20s) linear infinite;
}
@@ -146,10 +147,10 @@
@keyframes top-banner-scroll {
from {
transform: translateX(0);
transform: translate3d(0, 0, 0);
}
to {
transform: translateX(-50%);
transform: translate3d(-50%, 0, 0);
}
}
</style>
+1 -6
View File
@@ -215,12 +215,7 @@
return;
}
var socketUrl = new URL(announcementSocketPath, window.location.origin);
if (window.__pulsePageAuthToken) {
socketUrl.searchParams.set('auth', window.__pulsePageAuthToken);
}
var socket = new WebSocket(socketUrl.toString());
var socket = new WebSocket(new URL(announcementSocketPath, window.location.origin).toString());
announcementSocket = socket;
socket.onopen = function () {
+4 -1
View File
@@ -214,6 +214,8 @@ body.thumbnail-preview .player-offline-banner {
height: 100%;
opacity: 0;
transition: opacity 560ms ease;
will-change: opacity;
backface-visibility: hidden;
}
.slide-shell.is-visible {
@@ -243,7 +245,8 @@ body.screen-blackout #app {
height: var(--player-canvas-height, 100vh);
max-width: 100vw;
max-height: 100vh;
transform: translate(-50%, -50%);
transform: translate3d(-50%, -50%, 0);
backface-visibility: hidden;
z-index: 9999;
pointer-events: none;
display: flex;
+1 -6
View File
@@ -526,12 +526,7 @@ function connectCommandSocket() {
if (commandSocket && (commandSocket.readyState === WebSocket.OPEN || commandSocket.readyState === WebSocket.CONNECTING)) {
return;
}
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
var socketUrl = new URL(commandSocketPath, window.location.origin);
if (window.__pulsePageAuthToken) {
socketUrl.searchParams.set('auth', window.__pulsePageAuthToken);
}
var socket = new WebSocket(socketUrl.toString());
var socket = new WebSocket(new URL(commandSocketPath, window.location.origin).toString());
commandSocket = socket;
socket.onopen = function () {
+1 -1
View File
@@ -132,7 +132,7 @@ function renderPlayerPage(slug, initialData) {
bodyClass: bodyClass,
body: '<div id="app"><div class="empty">Loading screen...</div></div>',
stylesheets: fontStylesheetHref ? [fontStylesheetHref] : [],
script: createPageFetchAuthScript(pageAuthToken) + hlsScriptTag + serviceWorkerScript + createThumbnailPreviewBootstrapScript(initialData) + '<script>' + offlineScript + '</script>' + '<script>' + playlistScript + '</script>' + '<script>' + commandScript + '</script>' + '<script>' + renderingScript + '</script>' + '<script>' + playbackScript + '</script>' + '<script>' + getAnnouncementIconsDataScript() + '</script>' + '<script>' + getPlayerAnnouncementTemplatesDataScript() + '</script>' + '<script>' + getPlayerAnnouncementTemplatesScript() + '</script>' + onboardingScript + script + '<script>' + getPlayerPageAnnouncementsScript()() + '</script>'
script: createPageFetchAuthScript(pageAuthToken, '/ws/screens/' + encodeURIComponent(slug || '')) + hlsScriptTag + serviceWorkerScript + createThumbnailPreviewBootstrapScript(initialData) + '<script>' + offlineScript + '</script>' + '<script>' + playlistScript + '</script>' + '<script>' + commandScript + '</script>' + '<script>' + renderingScript + '</script>' + '<script>' + playbackScript + '</script>' + '<script>' + getAnnouncementIconsDataScript() + '</script>' + '<script>' + getPlayerAnnouncementTemplatesDataScript() + '</script>' + '<script>' + getPlayerAnnouncementTemplatesScript() + '</script>' + onboardingScript + script + '<script>' + getPlayerPageAnnouncementsScript()() + '</script>'
});
}
+31 -2
View File
@@ -4,6 +4,7 @@ const crypto = require('crypto');
const { WebSocketServer, WebSocket } = require('ws');
const { isClientNameAvailable } = require('#src/data/client-name-check');
const { verifyPageAuthToken, verifyRequestAuth } = require('#src/request-auth');
const PAGE_AUTH_COOKIE_NAME = 'pulse_page_auth';
function normalizePlayerPublicBaseUrl(pageUrl) {
const value = String(pageUrl || '').trim();
@@ -43,6 +44,34 @@ function createPlayerRuntime(options) {
return ip;
}
function parseCookies(cookieHeader) {
return String(cookieHeader || '').split(/;\s*/).reduce(function (cookies, pair) {
if (!pair) {
return cookies;
}
const separatorIndex = pair.indexOf('=');
if (separatorIndex === -1) {
return cookies;
}
const name = decodeURIComponent(pair.slice(0, separatorIndex).trim());
const value = decodeURIComponent(pair.slice(separatorIndex + 1).trim());
if (name) {
cookies[name] = value;
}
return cookies;
}, {});
}
function readPageAuthToken(request) {
const queryToken = String(new URL(request.url, 'http://localhost').searchParams.get('auth') || '').trim();
if (queryToken) {
return queryToken;
}
const cookies = parseCookies(request.headers && request.headers.cookie || '');
return String(cookies[PAGE_AUTH_COOKIE_NAME] || '').trim();
}
function getConnectionBucket(slug) {
const key = String(slug || '').trim();
if (!key) {
@@ -314,7 +343,7 @@ function createPlayerRuntime(options) {
}
if (playerMatch) {
const authToken = String(new URL(request.url, 'http://localhost').searchParams.get('auth') || '').trim();
const authToken = readPageAuthToken(request);
const payload = verifyPageAuthToken(authToken);
if (!payload || String(payload.scope || '').trim() !== 'player') {
socket.destroy();
@@ -323,7 +352,7 @@ function createPlayerRuntime(options) {
}
if (announcementMatch) {
const authToken = String(new URL(request.url, 'http://localhost').searchParams.get('auth') || '').trim();
const authToken = readPageAuthToken(request);
const payload = verifyPageAuthToken(authToken);
if (!payload || String(payload.scope || '').trim() !== 'player') {
socket.destroy();