Add multi-player and remote bridge support
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
module.exports = {
|
||||
createUploadSyncService: require('./upload-sync').createUploadSyncService,
|
||||
captureSlideThumbnail: require('./slide-thumbnails').captureSlideThumbnail,
|
||||
captureSlideThumbnail: function captureSlideThumbnail(options) {
|
||||
return require('./slide-thumbnails').captureSlideThumbnail(options);
|
||||
},
|
||||
fontLibrary: require('./font-library')
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
// Pure thumbnail preview payload helpers shared by routes and screenshot capture.
|
||||
|
||||
const {
|
||||
escapeHtml,
|
||||
renderEditorJsContent,
|
||||
sanitizeFontFamily,
|
||||
sanitizeFontSize,
|
||||
sanitizeTextColor
|
||||
} = require('#src/player/render-helpers');
|
||||
|
||||
function normalizeBaseUrl(baseUrl) {
|
||||
return String(baseUrl || '').trim().replace(/\/$/, '');
|
||||
}
|
||||
|
||||
function resolveAssetUrl(baseUrl, value) {
|
||||
const raw = String(value || '').trim();
|
||||
if (!raw) {
|
||||
return '';
|
||||
}
|
||||
if (/^(?:https?:)?\/\//i.test(raw) || raw.startsWith('data:')) {
|
||||
return raw;
|
||||
}
|
||||
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
||||
if (!normalizedBaseUrl) {
|
||||
return raw;
|
||||
}
|
||||
if (raw.startsWith('/')) {
|
||||
return normalizedBaseUrl + raw;
|
||||
}
|
||||
return normalizedBaseUrl + '/' + raw.replace(/^\/+/, '');
|
||||
}
|
||||
|
||||
function getThumbnailCanvasSize(slide) {
|
||||
const template = slide && slide.template ? slide.template : null;
|
||||
return {
|
||||
width: Math.max(1, Number(template && template.canvas_size_width ? template.canvas_size_width : 1920)),
|
||||
height: Math.max(1, Number(template && template.canvas_size_height ? template.canvas_size_height : 1080))
|
||||
};
|
||||
}
|
||||
|
||||
function getRegionContent(slide, region) {
|
||||
const content = slide && slide.content && slide.content[region.region_key] ? slide.content[region.region_key] : {};
|
||||
return content && typeof content === 'object' ? content : { value: content };
|
||||
}
|
||||
|
||||
function buildThumbnailRegionStyle(region, canvasWidth, canvasHeight) {
|
||||
const left = Number.isFinite(Number(region && region.x)) && canvasWidth > 0 ? (Number(region.x) / canvasWidth) * 100 : 0;
|
||||
const top = Number.isFinite(Number(region && region.y)) && canvasHeight > 0 ? (Number(region.y) / canvasHeight) * 100 : 0;
|
||||
const width = Number.isFinite(Number(region && region.width)) && canvasWidth > 0 ? (Number(region.width) / canvasWidth) * 100 : 0;
|
||||
const height = Number.isFinite(Number(region && region.height)) && canvasHeight > 0 ? (Number(region.height) / canvasHeight) * 100 : 0;
|
||||
|
||||
return 'left:' + left + '%;top:' + top + '%;width:' + width + '%;height:' + height + '%;z-index:' + Number(region && region.z_index || 0) + ';';
|
||||
}
|
||||
|
||||
function hasVisibleContent(html) {
|
||||
return Boolean(String(html || '').replace(/<[^>]+>/g, '').trim());
|
||||
}
|
||||
|
||||
function buildTextRegionMarkup(region, regionContent) {
|
||||
const fontFamily = sanitizeFontFamily(regionContent.font_family || region.font_family);
|
||||
const fontSize = sanitizeFontSize(regionContent.font_size || region.font_size);
|
||||
const fontColor = sanitizeTextColor(regionContent.font_color || region.font_color);
|
||||
const renderedBody = renderEditorJsContent(regionContent.value || '');
|
||||
if (!hasVisibleContent(renderedBody)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<div class="slide-preview-region slide-preview-text-region" style="' + region.baseStyle + '"><div class="slide-preview-text-content" style="width:' + region.pixelWidth + 'px;height:' + region.pixelHeight + 'px;overflow:hidden;' + (fontFamily ? 'font-family:' + escapeHtml(fontFamily) + ';' : '') + 'font-size:' + fontSize + 'px;color:' + escapeHtml(fontColor || '#000000') + ';">' + renderedBody + '</div></div>';
|
||||
}
|
||||
|
||||
function buildRegionInnerHtml(region, regionContent, baseUrl) {
|
||||
const regionType = String(regionContent.type || region.region_type || 'text').trim().toLowerCase();
|
||||
const rawValue = regionContent && regionContent.value !== undefined ? regionContent.value : '';
|
||||
|
||||
if (regionType === 'image') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
? '<div class="slide-preview-region slide-preview-image-region" style="' + region.baseStyle + '"><img class="slide-preview-image" src="' + escapeHtml(src) + '" alt="' + escapeHtml(region.label || region.region_key || 'image') + '" /></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'video') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
? '<div class="slide-preview-region slide-preview-video-region" style="' + region.baseStyle + '"><video class="slide-preview-video" src="' + escapeHtml(src) + '" title="' + escapeHtml(region.label || region.region_key || 'video') + '" muted playsinline preload="metadata"></video></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'webpage') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
? '<div class="slide-preview-region slide-preview-webpage-region" style="' + region.baseStyle + '"><iframe src="' + escapeHtml(src) + '" title="' + escapeHtml(region.label || region.region_key || 'webpage') + '" loading="eager" referrerpolicy="no-referrer" scrolling="no"></iframe></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'qr-code') {
|
||||
const src = String(regionContent.qr_preview || '').trim();
|
||||
const borderRadius = Math.max(0, Math.round(Number(regionContent.qr_border_radius || 0)));
|
||||
const radiusStyle = borderRadius > 0 ? ' style="border-radius:' + borderRadius + 'px;overflow:hidden;"' : '';
|
||||
return src
|
||||
? '<div class="slide-preview-region slide-preview-qr-code-region" style="' + region.baseStyle + radiusStyle + '"><img class="slide-preview-image" src="' + escapeHtml(src) + '" alt="' + escapeHtml(region.label || region.region_key || 'qr code') + '" /></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'html') {
|
||||
const html = String(rawValue || '').trim();
|
||||
return html
|
||||
? '<div class="slide-preview-region slide-preview-html-region" style="' + region.baseStyle + '"><iframe sandbox="" srcdoc="<!doctype html><html><head><style>html,body{margin:0;width:100%;height:100%;overflow:hidden;background:transparent;}</style></head><body>' + escapeHtml(html) + '</body></html>" title="' + escapeHtml(region.label || region.region_key || 'html') + '" loading="eager" scrolling="no"></iframe></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'rtmp') {
|
||||
const label = String(rawValue || '').trim() || 'RTMP source';
|
||||
return '<div class="slide-preview-region slide-preview-rtmp-region" style="' + region.baseStyle + '"><div class="slide-preview-rtmp-placeholder">' + escapeHtml(label) + '</div></div>';
|
||||
}
|
||||
|
||||
return buildTextRegionMarkup(region, regionContent);
|
||||
}
|
||||
|
||||
function buildThumbnailPreviewMarkup(slide, baseUrl) {
|
||||
const template = slide && slide.template ? slide.template : null;
|
||||
if (!template) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const canvasSize = getThumbnailCanvasSize(slide);
|
||||
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
||||
return (Array.isArray(template.regions) ? template.regions : []).map(function (region) {
|
||||
const regionContent = getRegionContent(slide, region);
|
||||
const previewRegion = Object.assign({}, region, {
|
||||
baseStyle: buildThumbnailRegionStyle(region, canvasSize.width, canvasSize.height),
|
||||
pixelWidth: Math.max(1, Math.round(Number(region && region.width || 0) || 1)),
|
||||
pixelHeight: Math.max(1, Math.round(Number(region && region.height || 0) || 1))
|
||||
});
|
||||
return buildRegionInnerHtml(previewRegion, regionContent, normalizedBaseUrl);
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function buildThumbnailPreviewPayload(slide, options) {
|
||||
const template = slide && slide.template ? slide.template : null;
|
||||
const canvasSize = getThumbnailCanvasSize(slide);
|
||||
return {
|
||||
thumbnailPreview: true,
|
||||
canvasWidth: canvasSize.width,
|
||||
canvasHeight: canvasSize.height,
|
||||
backgroundColor: template && template.background_color ? String(template.background_color) : '#111111',
|
||||
backgroundImagePath: template && template.background_image_path ? String(template.background_image_path) : '',
|
||||
fontStylesheetHref: String(options && options.fontStylesheetHref || '').trim(),
|
||||
html: buildThumbnailPreviewMarkup(slide, options && options.baseUrl)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildThumbnailPreviewPayload: buildThumbnailPreviewPayload,
|
||||
buildThumbnailPreviewMarkup: buildThumbnailPreviewMarkup
|
||||
};
|
||||
@@ -2,14 +2,6 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const puppeteer = require('puppeteer-core');
|
||||
const chromiumModule = require('@sparticuz/chromium');
|
||||
const sharp = require('sharp');
|
||||
const chromium = chromiumModule && typeof chromiumModule.executablePath === 'function'
|
||||
? chromiumModule
|
||||
: chromiumModule && chromiumModule.default && typeof chromiumModule.default.executablePath === 'function'
|
||||
? chromiumModule.default
|
||||
: chromiumModule;
|
||||
const {
|
||||
escapeHtml,
|
||||
mediaKind,
|
||||
@@ -73,6 +65,23 @@ function getRegionContent(slide, region) {
|
||||
return content && typeof content === 'object' ? content : { value: content };
|
||||
}
|
||||
|
||||
function getThumbnailCanvasSize(slide) {
|
||||
const template = slide && slide.template ? slide.template : null;
|
||||
return {
|
||||
width: Math.max(1, Number(template && template.canvas_size_width ? template.canvas_size_width : 1920)),
|
||||
height: Math.max(1, Number(template && template.canvas_size_height ? template.canvas_size_height : 1080))
|
||||
};
|
||||
}
|
||||
|
||||
function buildThumbnailRegionStyle(region, canvasWidth, canvasHeight) {
|
||||
const left = Number.isFinite(Number(region && region.x)) && canvasWidth > 0 ? (Number(region.x) / canvasWidth) * 100 : 0;
|
||||
const top = Number.isFinite(Number(region && region.y)) && canvasHeight > 0 ? (Number(region.y) / canvasHeight) * 100 : 0;
|
||||
const width = Number.isFinite(Number(region && region.width)) && canvasWidth > 0 ? (Number(region.width) / canvasWidth) * 100 : 0;
|
||||
const height = Number.isFinite(Number(region && region.height)) && canvasHeight > 0 ? (Number(region.height) / canvasHeight) * 100 : 0;
|
||||
|
||||
return 'left:' + left + '%;top:' + top + '%;width:' + width + '%;height:' + height + '%;z-index:' + Number(region && region.z_index || 0) + ';';
|
||||
}
|
||||
|
||||
function hasVisibleContent(html) {
|
||||
return Boolean(String(html || '').replace(/<[^>]+>/g, '').trim());
|
||||
}
|
||||
@@ -86,7 +95,7 @@ function buildTextRegionMarkup(region, regionContent) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<div class="template-region text" style="' + region.baseStyle + '"><div class="template-region-text-scale" style="width:' + region.pixelWidth + 'px;height:' + region.pixelHeight + 'px;' + (fontFamily ? 'font-family:' + escapeHtml(fontFamily) + ';' : '') + 'font-size:' + fontSize + 'px;color:' + escapeHtml(fontColor || '#000000') + ';">' + renderedBody + '</div></div>';
|
||||
return '<div class="slide-preview-region slide-preview-text-region" style="' + region.baseStyle + '"><div class="slide-preview-text-content" style="width:' + region.pixelWidth + 'px;height:' + region.pixelHeight + 'px;overflow:hidden;' + (fontFamily ? 'font-family:' + escapeHtml(fontFamily) + ';' : '') + 'font-size:' + fontSize + 'px;color:' + escapeHtml(fontColor || '#000000') + ';">' + renderedBody + '</div></div>';
|
||||
}
|
||||
|
||||
function buildRegionInnerHtml(region, regionContent, baseUrl) {
|
||||
@@ -96,21 +105,21 @@ function buildRegionInnerHtml(region, regionContent, baseUrl) {
|
||||
if (regionType === 'image') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
? '<img src="' + escapeHtml(src) + '" alt="' + escapeHtml(region.label || region.region_key || 'image') + '" />'
|
||||
? '<div class="slide-preview-region slide-preview-image-region" style="' + region.baseStyle + '"><img class="slide-preview-image" src="' + escapeHtml(src) + '" alt="' + escapeHtml(region.label || region.region_key || 'image') + '" /></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'video') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
? '<video src="' + escapeHtml(src) + '" title="' + escapeHtml(region.label || region.region_key || 'video') + '" muted playsinline preload="metadata"></video>'
|
||||
? '<div class="slide-preview-region slide-preview-video-region" style="' + region.baseStyle + '"><video class="slide-preview-video" src="' + escapeHtml(src) + '" title="' + escapeHtml(region.label || region.region_key || 'video') + '" muted playsinline preload="metadata"></video></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'webpage') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
? '<iframe src="' + escapeHtml(src) + '" title="' + escapeHtml(region.label || region.region_key || 'webpage') + '" loading="eager" referrerpolicy="no-referrer" scrolling="no"></iframe>'
|
||||
? '<div class="slide-preview-region slide-preview-webpage-region" style="' + region.baseStyle + '"><iframe src="' + escapeHtml(src) + '" title="' + escapeHtml(region.label || region.region_key || 'webpage') + '" loading="eager" referrerpolicy="no-referrer" scrolling="no"></iframe></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
@@ -119,26 +128,75 @@ function buildRegionInnerHtml(region, regionContent, baseUrl) {
|
||||
const borderRadius = Math.max(0, Math.round(Number(regionContent.qr_border_radius || 0)));
|
||||
const radiusStyle = borderRadius > 0 ? ' style="border-radius:' + borderRadius + 'px;overflow:hidden;"' : '';
|
||||
return src
|
||||
? '<img src="' + escapeHtml(src) + '" alt="' + escapeHtml(region.label || region.region_key || 'qr code') + '"' + radiusStyle + ' />'
|
||||
? '<div class="slide-preview-region slide-preview-qr-code-region" style="' + region.baseStyle + radiusStyle + '"><img class="slide-preview-image" src="' + escapeHtml(src) + '" alt="' + escapeHtml(region.label || region.region_key || 'qr code') + '" /></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'html') {
|
||||
const html = String(rawValue || '').trim();
|
||||
return html
|
||||
? '<iframe sandbox="" srcdoc="<!doctype html><html><head><style>html,body{margin:0;width:100%;height:100%;overflow:hidden;background:transparent;}</style></head><body>' + escapeHtml(html) + '</body></html>" title="' + escapeHtml(region.label || region.region_key || 'html') + '" loading="eager" scrolling="no"></iframe>'
|
||||
? '<div class="slide-preview-region slide-preview-html-region" style="' + region.baseStyle + '"><iframe sandbox="" srcdoc="<!doctype html><html><head><style>html,body{margin:0;width:100%;height:100%;overflow:hidden;background:transparent;}</style></head><body>' + escapeHtml(html) + '</body></html>" title="' + escapeHtml(region.label || region.region_key || 'html') + '" loading="eager" scrolling="no"></iframe></div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (regionType === 'rtmp') {
|
||||
const label = String(rawValue || '').trim() || 'RTMP source';
|
||||
return '<div class="template-region-rtmp-placeholder">' + escapeHtml(label) + '</div>';
|
||||
return '<div class="slide-preview-region slide-preview-rtmp-region" style="' + region.baseStyle + '"><div class="slide-preview-rtmp-placeholder">' + escapeHtml(label) + '</div></div>';
|
||||
}
|
||||
|
||||
return buildTextRegionMarkup(region, regionContent);
|
||||
}
|
||||
|
||||
async function loadChromium() {
|
||||
const chromiumModule = await import('@sparticuz/chromium');
|
||||
const resolved = chromiumModule && chromiumModule.default ? chromiumModule.default : chromiumModule;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
async function loadPuppeteer() {
|
||||
return require('puppeteer-core');
|
||||
}
|
||||
|
||||
function loadSharp() {
|
||||
return require('sharp');
|
||||
}
|
||||
|
||||
function buildThumbnailPreviewMarkup(slide, baseUrl) {
|
||||
const template = slide && slide.template ? slide.template : null;
|
||||
if (!template) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const canvasSize = getThumbnailCanvasSize(slide);
|
||||
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
||||
return (Array.isArray(template.regions) ? template.regions : []).map(function (region) {
|
||||
const regionContent = getRegionContent(slide, region);
|
||||
const previewRegion = Object.assign({}, region, {
|
||||
baseStyle: buildThumbnailRegionStyle(region, canvasSize.width, canvasSize.height),
|
||||
pixelWidth: Math.max(1, Math.round(Number(region && region.width || 0) || 1)),
|
||||
pixelHeight: Math.max(1, Math.round(Number(region && region.height || 0) || 1))
|
||||
});
|
||||
return buildRegionInnerHtml(previewRegion, regionContent, normalizedBaseUrl);
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function buildThumbnailPreviewPayload(slide, options) {
|
||||
const template = slide && slide.template ? slide.template : null;
|
||||
const canvasSize = getThumbnailCanvasSize(slide);
|
||||
return {
|
||||
thumbnailPreview: true,
|
||||
canvasWidth: canvasSize.width,
|
||||
canvasHeight: canvasSize.height,
|
||||
backgroundColor: template && template.background_color ? String(template.background_color) : '#111111',
|
||||
backgroundImagePath: template && template.background_image_path ? String(template.background_image_path) : '',
|
||||
fontStylesheetHref: String(options && options.fontStylesheetHref || '').trim(),
|
||||
html: buildThumbnailPreviewMarkup(slide, options && options.baseUrl)
|
||||
};
|
||||
}
|
||||
|
||||
async function launchBrowser() {
|
||||
const puppeteer = await loadPuppeteer();
|
||||
const chromium = await loadChromium();
|
||||
let executablePath = SYSTEM_CHROMIUM_PATHS.find(function (candidate) {
|
||||
return fs.existsSync(candidate);
|
||||
}) || '';
|
||||
@@ -178,6 +236,7 @@ async function launchBrowser() {
|
||||
}
|
||||
|
||||
async function captureSlideThumbnail(options) {
|
||||
const sharp = loadSharp();
|
||||
const pool = options && options.pool;
|
||||
const common = options && options.common;
|
||||
const mediaDir = String(options && options.mediaDir || '').trim();
|
||||
@@ -194,7 +253,6 @@ async function captureSlideThumbnail(options) {
|
||||
throw new Error('Slide not found.');
|
||||
}
|
||||
|
||||
const canvasSize = getCanvasSize(slide);
|
||||
const thumbnailDir = path.join(mediaDir, 'thumbnails');
|
||||
const thumbnailRelativePath = String(slide.thumbnail_path || '').trim() || '/media/thumbnails/slides/slide-' + slide.id + '.png';
|
||||
const filePath = path.join(mediaDir, thumbnailRelativePath.replace(/^\/+media\//, ''));
|
||||
@@ -206,11 +264,11 @@ async function captureSlideThumbnail(options) {
|
||||
|
||||
async function waitForThumbnailRender(page) {
|
||||
await page.waitForFunction(function () {
|
||||
return document.readyState === 'complete' && Boolean(document.querySelector('.slide-canvas'));
|
||||
return document.readyState === 'complete' && Boolean(document.querySelector('#popup-preview-canvas'));
|
||||
}, { timeout: 30000 });
|
||||
|
||||
await page.waitForFunction(function () {
|
||||
var canvas = document.querySelector('.slide-canvas');
|
||||
var canvas = document.querySelector('#popup-preview-canvas');
|
||||
if (!canvas) {
|
||||
return false;
|
||||
}
|
||||
@@ -244,18 +302,26 @@ async function captureSlideThumbnail(options) {
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
try {
|
||||
const previewPath = '/api/internal/slide-thumbnails/' + slide.id + '/preview';
|
||||
const previewPath = '/api/internal/slide-thumbnails/' + slide.id + '/popup-preview';
|
||||
const previewUrl = baseUrl + previewPath;
|
||||
const previewPayload = buildThumbnailPreviewPayload(slide, {
|
||||
baseUrl: baseUrl,
|
||||
fontStylesheetHref: options && options.fontStylesheetHref ? options.fontStylesheetHref : ''
|
||||
});
|
||||
await page.setViewport({
|
||||
width: Math.max(1, Number(previewPayload.canvasWidth || PLAYER_VIEWPORT.width)),
|
||||
height: Math.max(1, Number(previewPayload.canvasHeight || PLAYER_VIEWPORT.height)),
|
||||
deviceScaleFactor: 1
|
||||
});
|
||||
await page.setExtraHTTPHeaders(createRequestAuthHeaders({
|
||||
method: 'GET',
|
||||
pathname: previewPath
|
||||
}));
|
||||
await page.setViewport(PLAYER_VIEWPORT);
|
||||
await page.goto(previewUrl, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await waitForThumbnailRender(page);
|
||||
const canvas = await page.$('.slide-canvas');
|
||||
const canvas = await page.$('#popup-preview-canvas');
|
||||
if (!canvas) {
|
||||
throw new Error('Player render did not produce a slide canvas.');
|
||||
throw new Error('Popup preview did not produce a slide canvas.');
|
||||
}
|
||||
await canvas.screenshot({ path: fullSizePath });
|
||||
} finally {
|
||||
@@ -298,5 +364,7 @@ async function captureSlideThumbnail(options) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
captureSlideThumbnail: captureSlideThumbnail
|
||||
captureSlideThumbnail: captureSlideThumbnail,
|
||||
buildThumbnailPreviewPayload: buildThumbnailPreviewPayload,
|
||||
buildThumbnailPreviewMarkup: buildThumbnailPreviewMarkup
|
||||
};
|
||||
@@ -6,6 +6,7 @@ const crypto = require('crypto');
|
||||
const multer = require('multer');
|
||||
const { createRequestAuthHeaders } = require('#src/request-auth');
|
||||
const { collectFontLibrarySyncOperations } = require('./font-library');
|
||||
const { getConfiguredPlayerIdentifier, resolvePlayerRegistration } = require('#src/data/player-registry');
|
||||
|
||||
function normalizeUploadRoot(uploadDir) {
|
||||
return path.resolve(String(uploadDir || '').trim());
|
||||
@@ -48,21 +49,20 @@ function createUploadSyncService(options) {
|
||||
}
|
||||
|
||||
try {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT internal_base_url
|
||||
FROM d_players
|
||||
WHERE device_id = '1'
|
||||
LIMIT 1`
|
||||
);
|
||||
const resolvedBaseUrl = String(rows && rows[0] && rows[0].internal_base_url || '').trim().replace(/\/$/, '');
|
||||
return resolvedBaseUrl || configuredPlayerInternalBaseUrl || null;
|
||||
const configuredPlayerIdentifier = getConfiguredPlayerIdentifier();
|
||||
const player = await resolvePlayerRegistration(pool, configuredPlayerIdentifier);
|
||||
const resolvedBaseUrl = String(player && player.internal_base_url || '').trim().replace(/\/$/, '');
|
||||
if (resolvedBaseUrl) {
|
||||
playerInternalBaseUrl = resolvedBaseUrl;
|
||||
return resolvedBaseUrl;
|
||||
}
|
||||
} catch (_error) {
|
||||
return configuredPlayerInternalBaseUrl || null;
|
||||
}
|
||||
|
||||
return configuredPlayerInternalBaseUrl || null;
|
||||
})().then(function (baseUrl) {
|
||||
playerInternalBaseUrl = baseUrl || null;
|
||||
playerInternalBaseUrlPromise = null;
|
||||
return playerInternalBaseUrl;
|
||||
return baseUrl || null;
|
||||
}, function () {
|
||||
playerInternalBaseUrlPromise = null;
|
||||
return configuredPlayerInternalBaseUrl || null;
|
||||
@@ -278,6 +278,11 @@ function createUploadSyncService(options) {
|
||||
return Boolean(localUploadDir);
|
||||
}
|
||||
|
||||
function isPlayerUnavailableError(error) {
|
||||
const code = String(error && error.cause && error.cause.code || error && error.code || '').trim().toUpperCase();
|
||||
return code === 'ENOTFOUND' || code === 'ECONNREFUSED' || code === 'EAI_AGAIN' || code === 'ETIMEDOUT';
|
||||
}
|
||||
|
||||
function queuePlayerUploadSync(operation) {
|
||||
if (!operation || !operation.uploadPath) {
|
||||
return;
|
||||
@@ -350,7 +355,9 @@ function createUploadSyncService(options) {
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.warn('Unable to sync upload to player:', relativePath, error);
|
||||
if (!isPlayerUnavailableError(error)) {
|
||||
console.warn('Unable to sync upload to player:', relativePath, error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -387,7 +394,9 @@ function createUploadSyncService(options) {
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.warn('Unable to remove upload from player:', relativePath, error);
|
||||
if (!isPlayerUnavailableError(error)) {
|
||||
console.warn('Unable to remove upload from player:', relativePath, error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user