Add multi-player and remote bridge support

This commit is contained in:
2026-08-07 02:58:18 +01:00
parent a4f8a807ff
commit 74318eb34e
58 changed files with 3785 additions and 432 deletions
+48 -19
View File
@@ -13,6 +13,27 @@ function normalizePlayerBaseUrl(value) {
return String(value || '').trim().replace(/\/$/, '');
}
function getConfiguredPlayerIdentifier() {
return String(process.env.PLAYER_IDENTIFIER || process.env.PLAYER_DEVICE_ID || '').trim() || null;
}
async function fetchPlayerRecordByIdentifier(pool, identifier) {
const normalizedIdentifier = String(identifier || '').trim();
if (!normalizedIdentifier) {
return null;
}
const [rows] = await pool.query(
`SELECT id, identifier, public_base_url, internal_base_url, last_seen_at
FROM d_players
WHERE identifier = ?
LIMIT 1`,
[normalizedIdentifier]
);
return rows[0] || null;
}
function buildScreenPlayerUrl(screen, fallbackBaseUrl) {
const slug = String(screen && screen.slug || '').trim();
if (!slug) {
@@ -28,20 +49,21 @@ function buildScreenPlayerUrl(screen, fallbackBaseUrl) {
}
async function fetchScreenPlayerUrls(pool) {
const playerBaseUrl = await fetchPlayerPublicBaseUrl(pool);
if (!playerBaseUrl) {
return {};
}
const [rows] = await pool.query(`
SELECT s.slug, p.public_base_url
FROM d_screens s
LEFT JOIN d_players p ON p.device_id = s.player_id
WHERE p.public_base_url IS NOT NULL
AND TRIM(p.public_base_url) <> ''
ORDER BY p.modified_at DESC, s.slug ASC
SELECT slug
FROM d_screens
ORDER BY slug ASC
`);
const playerUrls = {};
rows.forEach(function (row) {
const slug = String(row && row.slug || '').trim();
const publicBaseUrl = normalizePlayerBaseUrl(row && row.public_base_url);
const playerUrl = buildScreenPlayerUrl({ slug: slug }, publicBaseUrl);
const playerUrl = buildScreenPlayerUrl({ slug: slug }, playerBaseUrl);
if (slug && playerUrl && !playerUrls[slug]) {
playerUrls[slug] = playerUrl;
}
@@ -51,27 +73,32 @@ async function fetchScreenPlayerUrls(pool) {
}
async function fetchPlayerPublicBaseUrl(pool) {
const configuredPlayerIdentifier = getConfiguredPlayerIdentifier();
const [rows] = await pool.query(`
SELECT public_base_url
FROM d_players
WHERE device_id = '1'
WHERE identifier = ?
LIMIT 1
`);
`, [configuredPlayerIdentifier]);
return normalizePlayerBaseUrl(rows[0] && rows[0].public_base_url) || null;
}
async function fetchScreenPlayerRecord(pool, slug) {
const [rows] = await pool.query(`
SELECT p.device_id, p.public_base_url, p.internal_base_url, p.last_seen_at
FROM d_screens s
JOIN d_players p ON p.device_id = s.player_id
WHERE s.slug = ?
ORDER BY p.modified_at DESC, p.device_id ASC
LIMIT 1
`, [slug]);
if (slug) {
const [rows] = await pool.query(
`SELECT slug
FROM d_screens
WHERE slug = ?
LIMIT 1`,
[slug]
);
if (!rows.length) {
return null;
}
}
return rows[0] || null;
return fetchPlayerRecordByIdentifier(pool, getConfiguredPlayerIdentifier());
}
async function uniqueScreenSlug(pool, baseSlug, excludeId) {
@@ -112,6 +139,8 @@ async function fetchScreenEditData(pool) {
module.exports = {
slugify,
normalizePlayerBaseUrl,
getConfiguredPlayerIdentifier,
fetchPlayerRecordByIdentifier,
buildScreenPlayerUrl,
fetchScreenPlayerUrls,
fetchPlayerPublicBaseUrl,