openvibers/openvibe.network Commits

The home page fetches card pictures at the size it draws them (#500)

OP OpenVibers committed 12 days ago · 6cba6f451c · 2 files, +22 −1

Changes

ddiff --git a/server/home/render.js b/server/home/render.js
iindex a05e06c8..96583c21 100644
---- a/server/home/render.js
++++ b/server/home/render.js
@@@ -115,7 +115,16 @@ const fmtCount = (n) => Number(n).toLocaleString('en-US');
// A picture that fails to load (a stream's first thumbnail is written a few seconds after it goes live) falls back to
// the avatar when there is one, else to an empty tile, never the browser's broken-image icon.
const BLANK = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
--const img = (src, fallback, w, h) => `<img src="${esc(src)}" alt="" loading="lazy" decoding="async" width="${w}" height="${h}" data-fallback="${esc(fallback || BLANK)}" onerror="this.onerror=null;this.src=this.dataset.fallback">`;
++// A Media object is stored at full size: ask its resize ladder for the width drawn here (96 for the 36 px face, 640
++// for a 320 px card picture). Any other picture address — a Live thumbnail, an avatar from another host, one already
++// sized — is used unchanged. The full-size address stays in data-full: if Media cannot resize it, the picture retries
++// the original once before the existing fallback.
++const mediaW = (src, w) => (/^https:\/\/openvibe\.media\/o\/med_[0-9A-Za-z]+$/.test(String(src || '')) ? `${src}?w=${w >= 288 ? 640 : w >= 72 ? 160 : 96}` : src);
++const img = (src, fallback, w, h) => {
++ const sized = mediaW(src, w);
++ const full = sized === src ? '' : ` data-full="${esc(src)}"`;
++ return `<img src="${esc(sized)}" alt="" loading="lazy" decoding="async" width="${w}" height="${h}"${full} data-fallback="${esc(fallback || BLANK)}" onerror="if(this.dataset.full&&this.src!==this.dataset.full){this.src=this.dataset.full;return}this.src=this.dataset.fallback">`;
++};
function rightNow(a) {
// Rich cards (the owner, 2026-10-28: "more compact, bigger, like YouTube… a preview… view count… the uploader and
// avatar… rich content"): a 16:9 picture with its length or LIVE badge, a play button and what happens in it on hover,
ddiff --git a/test/home-front-door.test.js b/test/home-front-door.test.js
iindex ce6d7115..043dd331 100644
---- a/test/home-front-door.test.js
++++ b/test/home-front-door.test.js
@@@ -133,6 +133,18 @@ assert.ok(html.includes('LIVE · 1.5k') && html.includes('Al&lt;b&gt;ice') && ht
assert.ok(html.includes('data-fallback="https://openvibe.media/a"'), 'a broken thumbnail falls back to the avatar');
assert.ok(html.includes('href="https://openvibe.community/p/one"') && html.includes('href="https://openvibe.blog/@a/b"'));
assert.ok(html.includes('href="https://openvibe.video/v/9"') && html.includes('<code class="now-code">FALL10</code>') && html.includes('Remote · Berlin · via Arbeitnow'), 'recordings, codes and jobs render');
++// A Media object is asked for the width drawn (a 36 px face: 96; a 320 px card picture: 640), keeps the full-size
++// address and retries it once before the existing fallback. Other picture hosts are used unchanged.
++{
++ const faceObj = 'https://openvibe.media/o/med_01M644DY8BFX4H7MTRKPGG052R';
++ const shotObj = 'https://openvibe.media/o/med_01M6ACHAZPBW24T4624DD7MVFJ';
++ activity._set({ live: [{ name: 'Alice', title: 'Hi', url: 'https://openvibe.live/@alice', thumb: 'https://openvibe.live/t.jpg', avatar: faceObj, viewers: 1 }], pastes: [{ title: 'Shot', url: 'https://openvibe.community/p/one', kind: 'Screenshot', shot: shotObj, avatar: '', at: null }], posts: [] });
++ const page = home.render().html;
++ assert.ok(page.includes(`src="${faceObj}?w=96"`) && page.includes(`data-full="${faceObj}"`), 'a 36 px face asks for 96 and keeps the original');
++ assert.ok(page.includes(`src="${shotObj}?w=640"`) && page.includes(`data-full="${shotObj}"`), 'a 320 px card picture asks for 640 and keeps the original');
++ assert.ok(page.includes('onerror="if(this.dataset.full&&this.src!==this.dataset.full){this.src=this.dataset.full;return}this.src=this.dataset.fallback"'), 'the original is retried once, then the fallback');
++ assert.ok(page.includes('src="https://openvibe.live/t.jpg"') && !page.includes('https://openvibe.live/t.jpg?w='), 'a Live thumbnail is not a Media object and is used unchanged');
++}
// A phone shows one of what is new at a time (the short-pages rule, 2026-10-30): radio chips and :has(), no script, every
// part still in the page; the first part present is picked, and a wider screen or a browser without :has() shows them all.
{