Release 2.6.7

This commit is contained in:
2026-08-08 13:02:31 +01:00
parent b20beb250b
commit 7e46fffc34
41 changed files with 2489 additions and 1290 deletions
+64 -26
View File
@@ -18,21 +18,37 @@ const { getConfiguredPlayerIdentifier, recordPlayerHeartbeat } = require('#src/d
// Player runtime, media API, and websocket wiring.
async function start() {
const app = express();
const pool = String(process.env.THIN_CLIENT_BASE_URL || '').trim().replace(/\/$/, '') ? null : common.createPool();
const pool = String(process.env.BRIDGE_PUBLIC_URL || '').trim().replace(/\/$/, '') ? null : common.createPool();
const PORT = Number(process.env.PLAYER_PORT || 8081);
const PLAYER_PUBLIC_BASE_URL = String(process.env.PLAYER_PUBLIC_BASE_URL || process.env.PLAYER_BASE_URL || '').trim().replace(/\/$/, '');
const THIN_CLIENT_BASE_URL = String(process.env.THIN_CLIENT_BASE_URL || '').trim().replace(/\/$/, '');
const isRemotePlayer = Boolean(THIN_CLIENT_BASE_URL);
const PLAYER_INTERNAL_BASE_URL = String(isRemotePlayer ? THIN_CLIENT_BASE_URL : (process.env.PLAYER_INTERNAL_BASE_URL || PLAYER_PUBLIC_BASE_URL || process.env.PLAYER_BASE_URL || '')).trim().replace(/\/$/, '');
const PLAYER_PUBLIC_URL = String(process.env.PLAYER_PUBLIC_URL || process.env.PLAYER_BASE_URL || '').trim().replace(/\/$/, '');
const BRIDGE_PUBLIC_URL = String(process.env.BRIDGE_PUBLIC_URL || '').trim().replace(/\/$/, '');
const isRemotePlayer = Boolean(BRIDGE_PUBLIC_URL);
const PLAYER_INTERNAL_URL = String(isRemotePlayer ? BRIDGE_PUBLIC_URL : (process.env.PLAYER_INTERNAL_URL || PLAYER_PUBLIC_URL || process.env.PLAYER_BASE_URL || '')).trim().replace(/\/$/, '');
const PLAYER_DEVICE_ID = getConfiguredPlayerIdentifier();
const ASSET_DIR = path.join(__dirname, 'player', 'public');
const MEDIA_DIR = path.join(__dirname, '..', 'media');
const ONBOARDING_QUEUE_FILE = path.join(MEDIA_DIR, 'player-onboarding-queue.json');
const DB_SYNC_INTERVAL_MS = Number(process.env.PLAYER_DB_SYNC_INTERVAL_MS || 15000);
const onboardingStore = createOnboardingStore(ONBOARDING_QUEUE_FILE);
let thinClientSocket = null;
const playerRuntime = createPlayerRuntime({
pool: pool,
normalizeDeviceId: normalizeDeviceId
normalizeDeviceId: normalizeDeviceId,
notifySnapshot: function (snapshot) {
if (!thinClientSocket || thinClientSocket.readyState !== WebSocket.OPEN) {
return;
}
try {
thinClientSocket.send(JSON.stringify({
type: 'snapshot',
deviceId: PLAYER_DEVICE_ID,
slug: snapshot && snapshot.slug ? String(snapshot.slug).trim() : '',
connections: Array.isArray(snapshot && snapshot.connections) ? snapshot.connections : []
}));
} catch (_error) {
}
}
});
const playerPlaylistService = isRemotePlayer
? null
@@ -59,9 +75,9 @@ async function start() {
console.info('[player] startup', {
mode: isRemotePlayer ? 'bridge client' : 'local',
connected: connectionState && typeof connectionState.connected === 'boolean' ? connectionState.connected : false,
publicBaseUrl: PLAYER_PUBLIC_BASE_URL || null,
bridgeBaseUrl: PLAYER_INTERNAL_BASE_URL || null,
bridgeWebSocketUrl: THIN_CLIENT_BASE_URL ? createThinClientWebSocketUrl() : null
publicBaseUrl: PLAYER_PUBLIC_URL || null,
bridgeBaseUrl: PLAYER_INTERNAL_URL || null,
bridgeWebSocketUrl: BRIDGE_PUBLIC_URL ? createThinClientWebSocketUrl() : null
});
}
@@ -83,7 +99,7 @@ async function start() {
}
async function triggerWebMediaSync() {
if (!isRemotePlayer || !THIN_CLIENT_BASE_URL) {
if (!isRemotePlayer || !BRIDGE_PUBLIC_URL) {
return false;
}
@@ -92,7 +108,7 @@ async function start() {
method: 'POST',
pathname: '/api/internal/sync/player-media'
});
const response = await fetch(`${THIN_CLIENT_BASE_URL}/api/internal/sync/player-media`, {
const response = await fetch(`${BRIDGE_PUBLIC_URL}/api/internal/sync/player-media`, {
method: 'POST',
headers: Object.assign({
Accept: 'application/json'
@@ -194,9 +210,9 @@ async function start() {
common: common,
playerRuntime: playerRuntime,
onboardingStore: onboardingStore,
playerPublicBaseUrl: PLAYER_PUBLIC_BASE_URL,
playerInternalBaseUrl: PLAYER_INTERNAL_BASE_URL,
thinClientBaseUrl: THIN_CLIENT_BASE_URL,
playerPublicBaseUrl: PLAYER_PUBLIC_URL,
playerInternalBaseUrl: PLAYER_INTERNAL_URL,
bridgeBaseUrl: BRIDGE_PUBLIC_URL,
playerDeviceId: PLAYER_DEVICE_ID
});
registerPlayerRoutes(app, {
@@ -207,18 +223,18 @@ async function start() {
playerRuntime: playerRuntime,
playerPlaylistService: playerPlaylistService,
rtmpStreamService: rtmpStreamService,
playerPublicBaseUrl: PLAYER_PUBLIC_BASE_URL,
playerInternalBaseUrl: PLAYER_INTERNAL_BASE_URL,
thinClientBaseUrl: THIN_CLIENT_BASE_URL,
playerPublicBaseUrl: PLAYER_PUBLIC_URL,
playerInternalBaseUrl: PLAYER_INTERNAL_URL,
bridgeBaseUrl: BRIDGE_PUBLIC_URL,
playerDeviceId: PLAYER_DEVICE_ID
});
function createThinClientWebSocketUrl() {
if (!THIN_CLIENT_BASE_URL) {
if (!BRIDGE_PUBLIC_URL) {
return null;
}
return THIN_CLIENT_BASE_URL.replace(/^http:/i, 'ws:').replace(/^https:/i, 'wss:') + '/ws/players';
return BRIDGE_PUBLIC_URL.replace(/^http:/i, 'ws:').replace(/^https:/i, 'wss:') + '/ws/players';
}
function startThinClientRegistration() {
@@ -256,6 +272,23 @@ async function start() {
'x-pulse-request-timestamp': timestamp
}, authHeaders)
});
thinClientSocket = socket;
function sendSnapshot(slug) {
if (!socket || socket.readyState !== WebSocket.OPEN) {
return;
}
try {
socket.send(JSON.stringify({
type: 'snapshot',
deviceId: PLAYER_DEVICE_ID,
slug: String(slug || '').trim(),
connections: playerRuntime.snapshotConnections(slug)
}));
} catch (_error) {
}
}
socket.on('open', function () {
logPlayerStartup({
@@ -265,10 +298,14 @@ async function start() {
socket.send(JSON.stringify({
type: 'register',
deviceId: PLAYER_DEVICE_ID,
publicBaseUrl: PLAYER_PUBLIC_BASE_URL,
internalBaseUrl: PLAYER_INTERNAL_BASE_URL
publicBaseUrl: PLAYER_PUBLIC_URL,
internalBaseUrl: PLAYER_INTERNAL_URL
}));
playerRuntime.snapshotSlugs().forEach(function (slug) {
sendSnapshot(slug);
});
if (!webMediaSyncCompleted) {
triggerWebMediaSync().then(function (success) {
webMediaSyncTriggered = Boolean(success);
@@ -285,8 +322,8 @@ async function start() {
socket.send(JSON.stringify({
type: 'heartbeat',
deviceId: PLAYER_DEVICE_ID,
publicBaseUrl: PLAYER_PUBLIC_BASE_URL,
internalBaseUrl: PLAYER_INTERNAL_BASE_URL
publicBaseUrl: PLAYER_PUBLIC_URL,
internalBaseUrl: PLAYER_INTERNAL_URL
}));
if (!webMediaSyncTriggered && !webMediaSyncCompleted) {
@@ -317,6 +354,7 @@ async function start() {
socket.on('close', function () {
clearTimers();
thinClientSocket = null;
reconnectTimer = setTimeout(connect, 5000);
});
@@ -363,8 +401,8 @@ async function start() {
try {
await recordPlayerHeartbeat(pool, {
deviceId: PLAYER_DEVICE_ID,
publicBaseUrl: PLAYER_PUBLIC_BASE_URL,
internalBaseUrl: PLAYER_INTERNAL_BASE_URL
publicBaseUrl: PLAYER_PUBLIC_URL,
internalBaseUrl: PLAYER_INTERNAL_URL
}).catch(function (error) {
console.error(error);
});
@@ -392,7 +430,7 @@ async function start() {
if (PLAYER_DEVICE_ID && !isRemotePlayer) {
const { upsertPlayerRegistration } = require('./player/onboarding');
await upsertPlayerRegistration(pool, PLAYER_DEVICE_ID, PLAYER_PUBLIC_BASE_URL, PLAYER_INTERNAL_BASE_URL).catch(function (error) {
await upsertPlayerRegistration(pool, PLAYER_DEVICE_ID, PLAYER_PUBLIC_URL, PLAYER_INTERNAL_URL).catch(function (error) {
console.error(error);
});
}