aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/pager-no-poster-test.js33
1 files changed, 23 insertions, 10 deletions
diff --git a/tools/pager-no-poster-test.js b/tools/pager-no-poster-test.js
index 4153bba..0930834 100644
--- a/tools/pager-no-poster-test.js
+++ b/tools/pager-no-poster-test.js
@@ -1,9 +1,11 @@
-// A clip that plays by itself in the video pager has no poster: every
-// poster there is comes 480px wide and from some moment of the clip, so it
-// showed soft for a beat and the clip's first frame replaced it — a flash
-// on every flick. The slide is the pager's black until the player has its
-// first frame. On a connection to be careful with (Data Saver), where a
-// clip may never load, the poster stays.
+// A clip that plays by itself in the video pager has no thumbnail poster:
+// every poster there was came 480px wide and from some moment of the
+// clip, so it showed soft for a beat and the clip's first frame replaced
+// it — a flash on every flick. What the clip ahead holds instead is its
+// own first frame, full size, drawn from the opening of the file: the
+// flick glides onto the very picture the player shows first. On a
+// connection to be careful with (Data Saver), where a clip may never load,
+// the thumbnail poster stays.
// Run: bun tools/pager-no-poster-test.js
import puppeteer from './puppeteer.js';
import { cacheKeyFor } from '../src/wallet.js';
@@ -26,7 +28,13 @@ const html = await buildHtml({ minify: true, pwa: false });
const server = Bun.serve({ port: 0, fetch: (req) => {
const path = new URL(req.url).pathname;
const m = /^\/(wide|tall|last)\.webm$/.exec(path);
- if (m) return new Response(Bun.file(CLIPS[m[1]]), { headers: { 'content-type': 'video/webm' } });
+ if (m) {
+ // a host that serves ranges, as the real ones do
+ const f = Bun.file(CLIPS[m[1]]), range = /^bytes=(\d+)-(\d*)$/.exec(req.headers.get('range') || '');
+ if (!range) return new Response(f, { headers: { 'content-type': 'video/webm', 'accept-ranges': 'bytes' } });
+ 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) } });
+ }
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));
return new Response(html, { headers: { 'content-type': 'text/html' } });
@@ -94,10 +102,15 @@ try {
let s = await open();
check('the clip on screen plays', s.some((x) => x.here && x.playing), JSON.stringify(s));
check('…with no poster on it', s.filter((x) => x.here).every((x) => !x.poster), JSON.stringify(s.filter((x) => x.here)));
- check('…nor on the clips ahead', s.filter((x) => !x.here).every((x) => !x.poster), JSON.stringify(s.filter((x) => !x.here)));
+ check('…no thumbnail on the clips ahead either', s.filter((x) => !x.here).every((x) => !/still\.png/.test(x.poster || '')), JSON.stringify(s.filter((x) => !x.here)));
+ check('the next clip holds its own first frame', await waitFor(() => { const v = [...document.querySelectorAll('.mp-slide')].find((x) => x.getAttribute('data-k').endsWith('/tall.webm'))?.querySelector('video.mp-media'); return !!v && /^blob:/.test(v.getAttribute('poster') || ''); }, null, 8000), JSON.stringify(await slides()));
+ const frame = await page.evaluate(() => new Promise((r) => { const v = [...document.querySelectorAll('.mp-slide')].find((x) => x.getAttribute('data-k').endsWith('/tall.webm')).querySelector('video.mp-media'); const im = new Image(); im.onload = () => r({ w: im.naturalWidth, h: im.naturalHeight }); im.onerror = () => r(null); im.src = v.getAttribute('poster'); }));
+ check('…full size, the clip\'s own shape', !!frame && frame.w === 180 && frame.h === 320, JSON.stringify(frame));
+ check('…and the clip after it, not yet near, holds nothing', s.some((x) => x.clip === 'last.webm' && !x.poster), JSON.stringify(s));
await page.keyboard.press('ArrowDown'); await sleep(900);
s = await slides();
- check('the next clip plays, no poster either', s.some((x) => x.here && x.playing && !x.poster && x.clip === 'tall.webm'), JSON.stringify(s));
+ check('the next clip plays, its first frame under it', s.some((x) => x.here && x.playing && /^blob:/.test(x.poster || '') && x.clip === 'tall.webm'), JSON.stringify(s));
+ check('…and the one after now holds its first frame', await waitFor(() => { const v = [...document.querySelectorAll('.mp-slide')].find((x) => x.getAttribute('data-k').endsWith('/last.webm'))?.querySelector('video.mp-media'); return !!v && /^blob:/.test(v.getAttribute('poster') || ''); }, null, 8000));
await page.keyboard.press('Escape'); await sleep(500);
console.log('\n[a careful connection: the poster stays]');
@@ -106,5 +119,5 @@ try {
check('the slides carry their posters', s.length >= 3 && s.every((x) => /still\.png$/.test(x.poster || '')), JSON.stringify(s));
check('no page errors', errs.length === 0, errs.slice(0, 2).join(' | '));
} catch (e) { console.error(e); ok = false; } finally { await browser.close(); server.stop(true); }
-console.log(ok ? '\n✅ an autoplaying clip starts on its own first frame, no poster' : '\n❌ failed');
+console.log(ok ? '\n✅ an autoplaying clip starts on its own first frame, the one ahead holds it already' : '\n❌ failed');
process.exit(ok ? 0 : 1);