openvibers/openvibe.live Commits

Thumbnails: Media's job failing (5xx) is 'no picture yet' (200, remembered 5 min), not Media's 500 in every visitor's console; Donate window skips the balance while signed out (a 401 in the console) (#187)

OP OpenVibers committed 27 days ago · 77d64461b5 · 3 files, +21 −4

Changes

ddiff --git a/public/js/vibes.js b/public/js/vibes.js
iindex 3a5b7725..bd027ffd 100644
---- a/public/js/vibes.js
++++ b/public/js/vibes.js
@@@ -253,7 +253,7 @@ function openvibeBucksDonateModal() {
async function _initDonateModal() {
const streamerId = _donateStreamerId();
const [bal, directAvailable] = await Promise.all([
-- api('/funds/balance').then(d => Math.round(d.balance || 0)).catch(() => null),
++ currentUser ? api('/funds/balance').then(d => Math.round(d.balance || 0)).catch(() => null) : null,
streamerId
? api(`/powerchat/donate-link?streamer_id=${streamerId}`).then(d => !!(d && d.mode === 'direct')).catch(() => false)
: Promise.resolve(false),
ddiff --git a/server/media-proxy/thumbnails.js b/server/media-proxy/thumbnails.js
iindex 0baf70ed..16aab6f2 100644
---- a/server/media-proxy/thumbnails.js
++++ b/server/media-proxy/thumbnails.js
@@@ -87,8 +87,12 @@ async function generateFor(kind, id, req, res) {
if (noPictureKnown(key)) return res.json({ thumbnail_url: null });
let out;
try { out = await media.generateThumbnail(kind, id); } catch (err) {
-- if (!(err && err.name === 'MediaApiError' && (err.status === 404 || err.status === 429))) throw err;
-- rememberNoPicture(key, err.status === 429 ? MEDIA_BUSY_MS : NO_PICTURE_MS);
++ // Media's job failing (5xx) is Media's to fix, not this visitor's error: no picture for now, asked
++ // again after a while (clip 455's job failed on every /@goosely visit until Media#136, 2026-10-17).
++ const failed = err && err.name === 'MediaApiError' && err.status >= 500;
++ if (!(err && err.name === 'MediaApiError' && (err.status === 404 || err.status === 429 || failed))) throw err;
++ if (failed) console.warn(`[Thumbnails] Media's thumbnail job failed for ${key}: ${err.status}${err.body && err.body.job_id ? ` (${err.body.job_id})` : ''}`);
++ rememberNoPicture(key, err.status === 404 ? NO_PICTURE_MS : MEDIA_BUSY_MS);
return res.json({ thumbnail_url: null });
}
const url = media.publicUrl(out?.url || meta.thumbnail_url);
ddiff --git a/test/thumbnail-no-picture.test.js b/test/thumbnail-no-picture.test.js
iindex 38269615..8f2d4292 100644
---- a/test/thumbnail-no-picture.test.js
++++ b/test/thumbnail-no-picture.test.js
@@@ -1,6 +1,7 @@
'use strict';
/**
-- * POST /api/thumbnails/generate/clip/:id when OpenVibe.Media answers with neither a picture nor a job: no picture yet,
++ * POST /api/thumbnails/generate/clip/:id when OpenVibe.Media answers with neither a picture nor a job, or its job fails
++ * (5xx): no picture yet,
* answered 200 with thumbnail_url null and remembered for a while (Media is not asked again at once), never a 500 in
* every visitor's console (the browser check of release 35d02c6b found one on /@goosely, clip 455).
*
@@@ -36,6 +37,18 @@ console.warn = () => {};
assert.strictEqual(again.status, 200);
assert.strictEqual(asked, 1, 'remembered: Media is not asked again at once');
++ // Media's thumbnail job failing (it answers 500 with its job id): no picture for now, remembered, never the 500.
++ media.generateThumbnail = async () => {
++ asked++;
++ const err = new Error('Failed to generate thumbnail');
++ Object.assign(err, { name: 'MediaApiError', status: 500, body: { error: 'Failed to generate thumbnail', job_id: 'mjob_x' } });
++ throw err;
++ };
++ const failed = await post('/api/thumbnails/generate/clip/456');
++ assert.deepStrictEqual([failed.status, failed.json], [200, { thumbnail_url: null }]);
++ await post('/api/thumbnails/generate/clip/456');
++ assert.strictEqual(asked, 2, 'a failed job is remembered too');
++
server.close();
console.log('thumbnail no-picture: all checks passed');
process.exit(0);