From c53e57a3a462b47d9a59e8e2b800b5344669c479 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 28 Sep 2026 10:45:18 -0700 Subject: Fix video unmute after feed repaints --- tools/video-unmute-test.js | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tools/video-unmute-test.js (limited to 'tools') diff --git a/tools/video-unmute-test.js b/tools/video-unmute-test.js new file mode 100644 index 0000000..16cb56f --- /dev/null +++ b/tools/video-unmute-test.js @@ -0,0 +1,51 @@ +// Repaint before autoplay used to copy a handler closing over a detached video. +// Run: bun tools/video-unmute-test.js +// Phone: adb reverse tcp:5302 tcp:5302; BROWSER_URL=http://localhost:9223 bun tools/video-unmute-test.js +import assert from 'node:assert/strict'; +import puppeteer from 'puppeteer-core'; +const app = await Bun.file('src/app.js').text(); +const messages = await Bun.file('src/features/messages.js').text(); +const dom = app.slice(app.indexOf('function h(tag,'), app.indexOf("const root = document.getElementById('app');")); +const video = messages.slice(messages.indexOf(' const autoplayOk ='), messages.indexOf(' // The still, with a play button')); +const clip = '/tmp/coinos-unmute-test.webm'; +const ffmpeg = Bun.spawnSync(['ffmpeg', '-y', '-loglevel', 'error', '-f', 'lavfi', '-i', 'color=size=160x90:rate=10', '-f', 'lavfi', '-i', 'sine=frequency=440', '-t', '10', '-c:v', 'libvpx', '-c:a', 'libvorbis', clip]); +assert.equal(ffmpeg.exitCode, 0, 'generate a video with audio'); +const server = Bun.serve({ port: 5302, fetch(req) { + if (new URL(req.url).pathname === '/clip.webm') return new Response(Bun.file(clip), { headers: { 'content-type': 'video/webm' } }); + return new Response(`
`, { headers: { 'content-type': 'text/html' } }); +} }); +const remote = !!process.env.BROWSER_URL; +const browser = remote + ? await puppeteer.connect({ browserURL: process.env.BROWSER_URL }) + : await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: true, args: ['--no-sandbox'] }); +const page = await browser.newPage(); +try { + if (!remote) await page.setViewport({ width: 390, height: 844, isMobile: true, hasTouch: true }); + await page.goto('http://localhost:5302/'); + await page.waitForFunction(() => test.live.querySelector('video').readyState >= 2); + assert.equal(await page.evaluate(() => test.originalButton === test.live.querySelector('button') && !test.fresh.isConnected && test.live.querySelector('video').muted), true, 'repaint retains the live muted player and button'); + await page.tap('.vid-sound'); + await page.waitForFunction(() => !test.live.querySelector('video').paused); + assert.deepEqual(await page.evaluate(() => ({ muted: test.live.querySelector('video').muted, button: !!test.live.querySelector('button'), detachedMuted: test.fresh.querySelector('video').muted, frozen: test.live._skipMorph })), { muted: false, button: false, detachedMuted: true, frozen: true }); + assert.equal(await page.evaluate(() => test.rebuild()), false, 'remounted clip remembers sound'); + console.log('✓ Touch after repaint unmutes the live player, starts playback, removes the button, and survives remount'); +} finally { + await page.close(); + if (remote) await browser.disconnect(); else await browser.close(); + server.stop(true); +} -- cgit v1.2.3