This PR breaks the large web and player bootstrap files into smaller modules with clearer ownership.
Web changes: Split shared helpers, bootstrap logic, route groups, and upload-sync behavior out of web.js. Kept web.js focused on wiring and server startup. Fixed screen playlist reassignment so changing a screen’s playlist now triggers a refresh. Fixed single-slide playlist refresh behavior so updates do not get stuck behind the current slide. Player changes: Split websocket/runtime handling into runtime.js. Split playlist assembly and revision hashing into playlist.js. Split onboarding and player HTTP routes into dedicated modules. Split render utilities and template loading into render-helpers.js. Kept player.js mostly as startup/orchestration. Validation: Rebuilt both services with Docker Compose. Smoke-checked web and player routes after the refactor. Verified get_errors was clean on the touched modules.
This commit is contained in:
+36
-2
@@ -2,14 +2,44 @@ const { parseJsonSafe, readFormArray } = require('./utils');
|
||||
|
||||
const ALLOWED_TEMPLATE_REGION_TYPES = ['text', 'image', 'webpage', 'html'];
|
||||
|
||||
function sanitizeBackgroundColor(value) {
|
||||
const raw = String(value || '').trim();
|
||||
if (/^#[0-9a-fA-F]{6}$/.test(raw) || /^#[0-9a-fA-F]{3}$/.test(raw)) {
|
||||
return raw;
|
||||
}
|
||||
return '#111111';
|
||||
}
|
||||
|
||||
function normalizeTemplateRegionType(value) {
|
||||
const rawType = String(value || 'text').trim();
|
||||
return ALLOWED_TEMPLATE_REGION_TYPES.includes(rawType) ? rawType : 'text';
|
||||
}
|
||||
|
||||
function normalizeTemplateRegionName(value) {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function ensureUniqueTemplateRegionNames(regions) {
|
||||
const seen = new Map();
|
||||
for (let i = 0; i < regions.length; i += 1) {
|
||||
const region = regions[i];
|
||||
const regionName = normalizeTemplateRegionName(region.region_key || region.label);
|
||||
if (!regionName) {
|
||||
continue;
|
||||
}
|
||||
const normalized = regionName.toLowerCase();
|
||||
if (seen.has(normalized)) {
|
||||
const error = new Error('Region names must be unique on this template.');
|
||||
error.statusCode = 400;
|
||||
throw error;
|
||||
}
|
||||
seen.set(normalized, true);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchTemplateById(pool, id) {
|
||||
const [templates] = await pool.query(`
|
||||
SELECT st.id, st.name, st.canvas_size_id, st.background_image_path, st.created_at, st.modified_at,
|
||||
SELECT st.id, st.name, st.canvas_size_id, st.background_image_path, st.background_color, st.created_at, st.modified_at,
|
||||
cs.name AS canvas_size_name, cs.width AS canvas_size_width, cs.height AS canvas_size_height
|
||||
FROM slide_templates st
|
||||
LEFT JOIN canvas_sizes cs ON cs.id = st.canvas_size_id
|
||||
@@ -26,7 +56,7 @@ async function fetchTemplateById(pool, id) {
|
||||
|
||||
async function fetchTemplatesData(pool) {
|
||||
const [templates] = await pool.query(`
|
||||
SELECT st.id, st.name, st.canvas_size_id, st.background_image_path, st.created_at, st.modified_at,
|
||||
SELECT st.id, st.name, st.canvas_size_id, st.background_image_path, st.background_color, st.created_at, st.modified_at,
|
||||
cs.name AS canvas_size_name, cs.width AS canvas_size_width, cs.height AS canvas_size_height
|
||||
FROM slide_templates st
|
||||
LEFT JOIN canvas_sizes cs ON cs.id = st.canvas_size_id
|
||||
@@ -107,6 +137,7 @@ async function buildTemplatePayload(pool, req, existingTemplate) {
|
||||
const filesByField = getFilesByField(req.files || []);
|
||||
const backgroundImage = filesByField.background_image;
|
||||
const removeBackgroundImage = Boolean(req.body.remove_background_image);
|
||||
const backgroundColor = sanitizeBackgroundColor(req.body.background_color || (existingTemplate && existingTemplate.background_color));
|
||||
const backgroundImagePath = backgroundImage
|
||||
? `/uploads/${backgroundImage.filename}`
|
||||
: removeBackgroundImage
|
||||
@@ -153,12 +184,15 @@ async function buildTemplatePayload(pool, req, existingTemplate) {
|
||||
}];
|
||||
}
|
||||
|
||||
ensureUniqueTemplateRegionNames(regions);
|
||||
|
||||
return {
|
||||
name,
|
||||
canvasSizeId: resolvedCanvasSizeId,
|
||||
canvasSizeWidth: canvasWidth,
|
||||
canvasSizeHeight: canvasHeight,
|
||||
backgroundImagePath,
|
||||
backgroundColor,
|
||||
regions
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user