Release v2.5.4

This commit is contained in:
2026-08-03 21:20:54 +01:00
parent a5e8ecb21f
commit a45552fed3
22 changed files with 371 additions and 9 deletions
+2 -1
View File
@@ -22,9 +22,10 @@ async function fetchAdminData(pool) {
ORDER BY s.id DESC
`);
const [screens] = await pool.query(`
SELECT s.id, s.name, s.slug, s.playlist_id, s.created_at, s.modified_at, s.created_by, s.modified_by, p.name AS playlist_name
SELECT s.id, s.name, s.slug, s.playlist_id, s.created_at, s.modified_at, s.created_by, s.modified_by, p.name AS playlist_name, pl.public_base_url
FROM d_screens s
LEFT JOIN c_playlists p ON p.id = s.playlist_id
LEFT JOIN d_players pl ON pl.device_id = s.player_id
ORDER BY s.id DESC
`);
const [playlistSlides] = await pool.query(`
+36
View File
@@ -0,0 +1,36 @@
const QRCode = require('qrcode');
async function createQrCodeSvg(value) {
const text = String(value === undefined || value === null ? '' : value).trim();
if (!text) {
return '';
}
return QRCode.toString(text, {
type: 'svg',
margin: 1,
errorCorrectionLevel: 'M'
});
}
async function buildQrCodeContent(value) {
const text = String(value === undefined || value === null ? '' : value).trim();
const content = {
type: 'qr-code',
value: text
};
if (text) {
const svg = await createQrCodeSvg(text);
if (svg) {
content.qr_svg = svg;
}
}
return content;
}
module.exports = {
createQrCodeSvg,
buildQrCodeContent
};
+23 -2
View File
@@ -2,6 +2,7 @@
const { fetchTemplateById } = require('./templates');
const { parseJsonSafe } = require('./utils');
const { buildQrCodeContent } = require('./qr-code');
const ALLOWED_RICH_TEXT_TAGS = ['b', 'strong', 'i', 'em', 'u', 'br', 'p', 'div', 'ul', 'ol', 'li'];
const DEFAULT_FONT_SIZE = 32;
@@ -142,6 +143,14 @@ function buildTemplateContent(template, body, filesByField, existingContent) {
type: 'webpage',
value: submitted === undefined ? current : String(submitted || '').trim()
};
} else if (region.region_type === 'qr-code') {
const submitted = body[`region_qr_code_${region.id}`];
const current = existingContent && existingContent[region.region_key] ? existingContent[region.region_key] : {};
const nextValue = submitted === undefined ? String(current.value !== undefined ? current.value : current.qr_code || '').trim() : String(submitted || '').trim();
content[region.region_key] = {
type: 'qr-code',
value: nextValue
};
} else if (region.region_type === 'rtmp') {
const submitted = body[`region_rtmp_${region.id}`];
const current = existingContent && existingContent[region.region_key] ? existingContent[region.region_key] : {};
@@ -202,7 +211,7 @@ function buildTemplateContent(template, body, filesByField, existingContent) {
font_size: style.font_size,
font_color: style.font_color
};
} else if (!['text', 'image', 'video', 'webpage', 'html', 'rtmp', 'rss', 'api'].includes(String(region.region_type || '').trim())) {
} else if (!['text', 'image', 'video', 'webpage', 'qr-code', 'html', 'rtmp', 'rss', 'api'].includes(String(region.region_type || '').trim())) {
const current = existingContent && existingContent[region.region_key] && typeof existingContent[region.region_key] === 'object' ? existingContent[region.region_key] : {};
const suffix = '_' + region.id;
const generic = {};
@@ -273,10 +282,22 @@ async function buildSlidePayload(pool, req, existingSlide) {
}
if (template) {
const content = buildTemplateContent(template, req.body, filesByField, existingContent);
await Promise.all(Object.keys(content).map(async function (regionKey) {
const region = template.regions.find(function (item) {
return String(item.region_key || '').trim() === regionKey;
});
if (!region || region.region_type !== 'qr-code') {
return;
}
content[regionKey] = await buildQrCodeContent(content[regionKey].value);
}));
return {
title,
templateId: template.id,
contentJson: JSON.stringify(buildTemplateContent(template, req.body, filesByField, existingContent))
contentJson: JSON.stringify(content)
};
}