Release 2.22.0: normalize playlist schedules and unify player sync
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m21s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 32s

This commit is contained in:
lzstealth committed 2026-10-27 22:54:38 +00:00
1 parent 7748129307
commit b71958cb38
39 files changed
+1174 -314

No files matched your search

+61
View File
@@ -1,5 +1,8 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
require('../src/common');
@@ -63,6 +66,10 @@ function createResponse() {
headers[name] = value;
return this;
},
type(value) {
headers['Content-Type'] = value;
return this;
},
status(code) {
this.statusCode = code;
return this;
@@ -378,6 +385,60 @@ test('playlist api route returns 404, etag, and 304 responses', async () => {
assert.equal(notModifiedRes.ended, true);
});
test('remote playlist sync downloads cached API and RSS images from the bridge', async () => {
const { app, handlers } = createAppAndHandlers();
const mediaDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pulse-player-remote-images-'));
const filename = 'a'.repeat(64) + '.png';
const imageBytes = Buffer.from('cached image bytes');
const playlistData = {
screen: { id: 7, slug: 'news' },
revision: 'revision-1',
apiSources: [{ imageCache: { 'https://api.example/image.png': '/media/player-cache/remote-images/' + filename } }],
rssFeeds: []
};
const originalFetch = global.fetch;
const fetchCalls = [];
global.fetch = async function (url, init) {
fetchCalls.push({ url: String(url), init: init });
if (String(url).includes('/api/screens/news/playlist')) {
return {
status: 200,
ok: true,
headers: { get(name) { return name.toLowerCase() === 'content-type' ? 'application/json' : null; } },
async text() { return JSON.stringify(playlistData); }
};
}
if (String(url).endsWith('/api/media/remote-images/' + filename)) {
return { ok: true, async arrayBuffer() { return imageBytes; } };
}
throw new Error('Unexpected fetch: ' + String(url));
};
try {
registerPlayerRoutes(app, {
app,
pool: null,
common: { renderPlayerPage() { return ''; } },
...createPlayerRouteOptions({
bridgeBaseUrl: 'http://bridge.test',
mediaDir
})
});
const response = createResponse();
await handlers['/api/screens/:slug/playlist']({ params: { slug: 'news' }, headers: {}, query: {} }, response);
assert.equal(response.statusCode, 200);
assert.equal(fetchCalls.length, 2);
assert.match(fetchCalls[1].url, /\/api\/media\/remote-images\//);
assert.equal(fetchCalls[1].init.method, 'GET');
assert.deepEqual(fs.readFileSync(path.join(mediaDir, 'player-cache', 'remote-images', filename)), imageBytes);
} finally {
global.fetch = originalFetch;
fs.rmSync(mediaDir, { recursive: true, force: true });
}
});
test('announcement route returns 503 for transient failures and 304 on matching etag', async () => {
const { app, handlers } = createAppAndHandlers();
const announcement = {