openvibers/openvibe.live Commits
Thumbnails: a VOD still recording asks Media for no job (it fails on a file still being written: a 500 every 5 minutes for VOD 5833); a quiet empty answer until the recording finalizes (#249)
Changes
@@@ -88,6 +88,12 @@ async function generateFor(kind, id, req, res) {if (!canManage && !isPublic) return res.status(403).json({ error: `Not your ${kind}` });const key = `${kind}:${Number(id)}`;if (noPictureKnown(key)) return res.json({ thumbnail_url: null });++ // A recording still being written has no finished file to draw from: Media's job fails (a 500 every 5 minutes++ // for VOD 5833 while it recorded, 2026-10-18). No picture yet; Media makes one when the recording finalizes.++ if (kind === 'vod' && (meta.is_recording || meta.status === 'recording')) {++ rememberNoPicture(key, MEDIA_BUSY_MS);++ return res.json({ thumbnail_url: null });++ }let out;try { out = await media.generateThumbnail(kind, id); } catch (err) {// Media's job failing (5xx) is Media's to fix, not this visitor's error: no picture for now, asked@@@ -71,6 +71,13 @@ console.warn = () => {};assert.strictEqual(asked, 5, 'another 404: asked again after an hour');Date.now = realNow;++ // A VOD still recording: no Media job (it fails on a file still being written), a quiet empty answer.++ media.getVod = async (id) => ({ id: Number(id), user_id: 1, visibility: 'public', thumbnail_url: null, is_recording: 1 });++ let jobs = 0;++ media.generateThumbnail = async () => { jobs++; return {}; };++ const live = await post('/api/thumbnails/generate/vod/5833');++ assert.deepStrictEqual([live.status, live.json, jobs], [200, { thumbnail_url: null }, 0], 'a recording VOD asks Media for nothing');++server.close();console.log('thumbnail no-picture: all checks passed');process.exit(0);
@@ -88,6 +88,12 @@ async function generateFor(kind, id, req, res) {
@@ -88,6 +88,12 @@ async function generateFor(kind, id, req, res) {
if (!canManage && !isPublic) return res.status(403).json({ error: `Not your ${kind}` });
if (!canManage && !isPublic) return res.status(403).json({ error: `Not your ${kind}` });
const key = `${kind}:${Number(id)}`;
const key = `${kind}:${Number(id)}`;
if (noPictureKnown(key)) return res.json({ thumbnail_url: null });
if (noPictureKnown(key)) return res.json({ thumbnail_url: null });
+ // A recording still being written has no finished file to draw from: Media's job fails (a 500 every 5 minutes
+ // for VOD 5833 while it recorded, 2026-10-18). No picture yet; Media makes one when the recording finalizes.
+ if (kind === 'vod' && (meta.is_recording || meta.status === 'recording')) {
+ rememberNoPicture(key, MEDIA_BUSY_MS);
+ return res.json({ thumbnail_url: null });
+ }
let out;
let out;
try { out = await media.generateThumbnail(kind, id); } catch (err) {
try { out = await media.generateThumbnail(kind, id); } catch (err) {
// Media's job failing (5xx) is Media's to fix, not this visitor's error: no picture for now, asked
// Media's job failing (5xx) is Media's to fix, not this visitor's error: no picture for now, asked
@@ -71,6 +71,13 @@ console.warn = () => {};
@@ -71,6 +71,13 @@ console.warn = () => {};
assert.strictEqual(asked, 5, 'another 404: asked again after an hour');
assert.strictEqual(asked, 5, 'another 404: asked again after an hour');
Date.now = realNow;
Date.now = realNow;
+ // A VOD still recording: no Media job (it fails on a file still being written), a quiet empty answer.
+ media.getVod = async (id) => ({ id: Number(id), user_id: 1, visibility: 'public', thumbnail_url: null, is_recording: 1 });
+ let jobs = 0;
+ media.generateThumbnail = async () => { jobs++; return {}; };
+ const live = await post('/api/thumbnails/generate/vod/5833');
+ assert.deepStrictEqual([live.status, live.json, jobs], [200, { thumbnail_url: null }, 0], 'a recording VOD asks Media for nothing');
+
server.close();
server.close();
console.log('thumbnail no-picture: all checks passed');
console.log('thumbnail no-picture: all checks passed');
process.exit(0);
process.exit(0);