diff --git a/CHANGELOG.md b/CHANGELOG.md index 1481531..c7cb344 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file. - Fixed the template background image media picker Upload media button so it opens the file selector. - Fixed the template designer empty background message moving when the background image is removed. +- Fixed cached API and RSS images not being served by the player after being downloaded. +- Fixed blank time/date regions displaying the default clock format on the player. ## 2.13.2 - 2026-09-11 diff --git a/src/player/local-control.js b/src/player/local-control.js index e7db0c5..9ee5ed0 100644 --- a/src/player/local-control.js +++ b/src/player/local-control.js @@ -489,10 +489,6 @@ function createLocalControlService(options) { } } - app.use('/media/player-cache', function (_req, res) { - return res.sendStatus(404); - }); - app.get('/local-control', function (req, res) { res.set('Cache-Control', 'no-store'); res.type('html').send(renderPageV2()); diff --git a/src/player/regions/time-date.js b/src/player/regions/time-date.js index 5445aa8..a38b1fa 100644 --- a/src/player/regions/time-date.js +++ b/src/player/regions/time-date.js @@ -2,7 +2,6 @@ var registry = window.pulsePlayerRegionTypes; var placeholderUtils = window.placeholderUtils || {}; -var DEFAULT_FORMAT = '{{hh}}:{{mm}}'; var DEFAULT_STYLE = { font_family: 'Arial', font_size: 32, @@ -223,7 +222,7 @@ function resolveTimeDateTemplatePlaceholder(values, expression) { } function renderTimeDateTemplate(format, timeZone, date) { - var template = String(format || '').trim() || DEFAULT_FORMAT; + var template = String(format || '').trim(); var values = getTimeDateFormattedParts(timeZone, date); return template.replace(/\{\{\s*([a-zA-Z0-9_.()\-]+)\s*\}\}/g, function (_match, key) { return String(resolveTimeDateTemplatePlaceholder(values, key, { timeZone: timeZone }) || ''); @@ -243,7 +242,7 @@ function getTextStyle(regionContent, region) { function renderTimeDateRegion(region, regionContent) { var content = regionContent && typeof regionContent === 'object' ? regionContent : {}; - var format = String(content.value !== undefined ? content.value : content.text || '').trim() || DEFAULT_FORMAT; + var format = String(content.value !== undefined ? content.value : content.text || '').trim(); var timeZone = resolveTimeZone(content.timezone || content.time_zone || ''); var style = getTextStyle(content, region); var fontFamily = style.font_family ? 'font-family:' + escapeHtml(style.font_family) + ';' : ''; @@ -259,7 +258,7 @@ function updateTimeDateRegion(element) { return; } - var format = String(element.dataset.timeDateFormat || '').trim() || DEFAULT_FORMAT; + var format = String(element.dataset.timeDateFormat || '').trim(); var timeZone = String(element.dataset.timeDateTimezone || '').trim(); var scaleWrapper = element.querySelector('.template-region-text-scale'); if (!scaleWrapper) { diff --git a/test/player-local-control.test.js b/test/player-local-control.test.js index dce798a..ce76a81 100644 --- a/test/player-local-control.test.js +++ b/test/player-local-control.test.js @@ -31,6 +31,25 @@ async function createTestService(options) { return { app, server, service, temporaryDirectory }; } +test('local control leaves cached player media available to the static media route', async () => { + const { app, server, temporaryDirectory } = await createTestService(); + const cachedImagePath = path.join(temporaryDirectory, 'player-cache', 'remote-images', 'cached-image.png'); + await fs.promises.mkdir(path.dirname(cachedImagePath), { recursive: true }); + await fs.promises.writeFile(cachedImagePath, 'cached-image'); + app.use('/media', express.static(temporaryDirectory)); + const listener = app.listen(0); + try { + const address = listener.address(); + const response = await fetch(`http://127.0.0.1:${address.port}/media/player-cache/remote-images/cached-image.png`); + assert.equal(response.status, 200); + assert.equal(await response.text(), 'cached-image'); + } finally { + await new Promise((resolve) => listener.close(resolve)); + server.close(); + await fs.promises.rm(temporaryDirectory, { recursive: true, force: true }); + } +}); + test('local control authenticates only cached eligible users and scopes commands to local runtime', async () => { const { app, service, temporaryDirectory } = await createTestService(); const password = hashPassword('CorrectHorseBatteryStaple!'); diff --git a/test/player-time-date-region.test.js b/test/player-time-date-region.test.js index 5afe250..c8e3553 100644 --- a/test/player-time-date-region.test.js +++ b/test/player-time-date-region.test.js @@ -62,4 +62,23 @@ test('time/date region renders placeholder tokens on the player side', () => { ); assert.match(markup, /
\d{2}:\d{2}<\/p>/); +}); + +test('time/date region stays blank when its format is blank', () => { + const module = loadTimeDateModule(); + const markup = module.renderRegion( + { + pixelWidth: 320, + pixelHeight: 180, + canvasScale: 1, + baseStyle: 'position:absolute;' + }, + { + value: '', + timezone: 'UTC' + } + ); + + assert.match(markup, /data-time-date-format=""/); + assert.doesNotMatch(markup, /
\d{2}:\d{2}<\/p>/); }); \ No newline at end of file