aboutsummaryrefslogtreecommitdiffstats
path: root/tools/media-grid-dups-test.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-22 10:12:49 -0700
committerAdam Soltys <[email protected]>2026-10-22 10:12:49 -0700
commitcc84dd0c6c852b46b309079a5a90a54080fc049c (patch)
treeaf524ce1d63d2d62b987cc456553c563391ebea5 /tools/media-grid-dups-test.js
parent7947be155d4cc4f43dd89d743c5e09bfac4b635b (diff)
downloadcoinosv3-cc84dd0c6c852b46b309079a5a90a54080fc049c.tar.gz
coinosv3-cc84dd0c6c852b46b309079a5a90a54080fc049c.zip
Images grid in justified rows too: tiles in each picture's own shape (the tile thumbnail is no longer a square crop: 360px tall, its middle cut to 1:2–2:1; vmedia pic.webp?s=row for hosts without CORS; tile cache v2)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'tools/media-grid-dups-test.js')
-rw-r--r--tools/media-grid-dups-test.js12
1 files changed, 12 insertions, 0 deletions
diff --git a/tools/media-grid-dups-test.js b/tools/media-grid-dups-test.js
index eeb105e..948e727 100644
--- a/tools/media-grid-dups-test.js
+++ b/tools/media-grid-dups-test.js
@@ -18,6 +18,8 @@ const clip = (name, size) => {
return f;
};
const CLIPS = { wide: clip('wide', '320x180'), again: clip('wide', '320x180'), other: clip('wide', '320x180'), tall: clip('tall', '180x320'), last: clip('last', '240x240') };
+const pic = (size) => Bun.spawnSync(['ffmpeg', '-loglevel', 'error', '-f', 'lavfi', '-i', 'testsrc=size=' + size, '-frames:v', '1', '-f', 'image2', '-c:v', 'png', 'pipe:1']).stdout;
+const picWide = pic('640x360'), picTall = pic('360x640');
const SK = generateSecretKey(), AUTHOR = getPublicKey(SK);
const now = Math.floor(Date.now() / 1000);
const html = await buildHtml({ minify: true, pwa: false });
@@ -30,6 +32,8 @@ const server = Bun.serve({ port: 0, fetch: (req) => {
const a = +range[1], b = range[2] ? Math.min(+range[2], f.size - 1) : f.size - 1;
return new Response(f.slice(a, b + 1), { status: 206, headers: { 'content-type': 'video/webm', 'accept-ranges': 'bytes', 'content-range': 'bytes ' + a + '-' + b + '/' + f.size, 'content-length': String(b - a + 1) } });
}
+ const pm = /^\/pic-(wide|tall)\.png$/.exec(path);
+ if (pm) return new Response(pm[1] === 'wide' ? picWide : picTall, { headers: { 'content-type': 'image/png', 'access-control-allow-origin': '*' } });
if (path === '/dead.webm') return new Response('gone', { status: 404 });
if (path === '/still.png') return new Response(png, { headers: { 'content-type': 'image/png' } });
if (path.startsWith('/punks') || path === '/verify-worker.js') return new Response(Bun.file('dist' + path));
@@ -46,6 +50,9 @@ const seeded = [
post('Transylvania lightning conference 2026 ' + U('again'), U('again'), 200),
post('Transylvania lightning conference 2026 ' + U('other'), U('other'), 300),
post('the last clip ' + U('last'), U('last'), 400),
+ // pictures, one wide and one tall, the post saying nothing of their size
+ finalizeEvent({ kind: 1, created_at: now - 120, tags: [], content: 'a wide view ' + server.url.origin + '/pic-wide.png' }, SK),
+ finalizeEvent({ kind: 1, created_at: now - 130, tags: [], content: 'a tall view ' + server.url.origin + '/pic-tall.png' }, SK),
// a tall one: out of a wide screen's grid until "All shapes"
finalizeEvent({ kind: 1, created_at: now - 450, tags: [['imeta', 'url ' + U('tall'), 'm video/webm', 'dim 180x320']], content: 'standing up ' + U('tall') }, SK),
// a clip its host has since deleted (it says so: 404) — no blank tile for it
@@ -115,6 +122,11 @@ try {
const tallT = R.rows.flatMap((r) => r.ks.map((k, i) => ({ k, ar: r.ars[i] }))).find((x) => x.k === 'tall.webm');
check('…in justified rows: every tile its clip\'s shape (the tall one tall, the wide ones wide)', R.justified && tallT && Math.abs(tallT.ar - 0.5625) < 0.03 && R.rows.flatMap((r) => r.ks.map((k, i) => ({ k, ar: r.ars[i] }))).filter((x) => x.k !== 'tall.webm' && x.k !== 'last.webm').every((x) => Math.abs(x.ar - 16 / 9) < 0.03), JSON.stringify(R));
check('…one height across each row', R.rows.every((r) => Math.max(...r.hs) - Math.min(...r.hs) <= 1), JSON.stringify(R.rows.map((r) => r.hs)));
+ // the Images grid: justified rows too, each picture in its own shape
+ await page.evaluate(() => document.querySelector('.media-mode[data-mode="images"]').click());
+ const picAr = (name) => page.evaluate((n) => { const t = [...document.querySelectorAll('.media-grid .media-tile')].find((x) => x.getAttribute('data-key').endsWith(n)); if (!t) return null; const r = t.getBoundingClientRect(); return +(r.width / r.height).toFixed(2); }, name);
+ check('the Images grid lays pictures out in justified rows, each its own shape', await waitFor(() => { const g = document.querySelector('.media-grid.justified'); if (!g) return false; const ar = (n) => { const t = [...g.querySelectorAll('.media-tile')].find((x) => x.getAttribute('data-key').endsWith(n)); if (!t) return 0; const r = t.getBoundingClientRect(); return r.width / r.height; }; return Math.abs(ar('pic-wide.png') - 16 / 9) < 0.05 && Math.abs(ar('pic-tall.png') - 9 / 16) < 0.05; }, null, 10000),
+ JSON.stringify({ wide: await picAr('pic-wide.png'), tall: await picAr('pic-tall.png') }));
check('no page errors', errs.length === 0, errs.slice(0, 2).join(' | '));
} finally {
await browser.close();