From 103f558147aa36b5bd20f90efa85e0c27fb23551 Mon Sep 17 00:00:00 2001 From: modem7 Date: Tue, 7 Jul 2026 18:31:58 +0100 Subject: [PATCH 1/2] Fix video staying paused after tapping the overlay on mobile touchstart/pointerdown fire the instant a finger touches the screen, before the browser knows it's a tap rather than the start of a scroll/drag. WebKit doesn't treat that as a strong enough gesture to permit unmuted playback, so play() was silently rejected there, and the click that follows never got a retry since {once: true} plus the manual removeEventListener calls had already torn every listener down. Drop to click + keydown only - click already fires for a completed tap on touch devices, same as a real mouse click on desktop. --- scripts/index/80-index.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/index/80-index.sh b/scripts/index/80-index.sh index 5ef86d3..4987921 100644 --- a/scripts/index/80-index.sh +++ b/scripts/index/80-index.sh @@ -335,7 +335,17 @@ tee /usr/share/nginx/html/index.html << EOF >/dev/null } } - var events = ['click', 'keydown', 'touchstart', 'pointerdown']; + // click fires for both a genuine mouse click and, on + // touch devices, the synthetic click a browser dispatches + // after a completed tap - deliberately not touchstart or + // pointerdown, which fire the instant a finger touches the + // screen, before the browser even knows it's a tap and not + // the start of a scroll/drag. WebKit in particular doesn't + // treat those as a strong enough gesture to permit unmuted + // playback, so play() silently gets rejected and the + // click that follows never gets a retry since the + // listeners here are already torn down. + var events = ['click', 'keydown']; function reveal() { video.muted = false; From 81863ca68f6a5d36cecc9dc5838975cd596f21cb Mon Sep 17 00:00:00 2001 From: modem7 Date: Tue, 7 Jul 2026 18:34:26 +0100 Subject: [PATCH 2/2] Add Firefox coverage to the autoplay/unmute test Firefox is the most divergent of the mainstream browsers on autoplay gesture policy enforcement, so it's worth checking independently of Chromium rather than assuming one implies the other. Parameterize test-autoplay.js to take a browser engine and run both overlay checks under each. --- .github/scripts/test-autoplay.js | 13 +++++++++---- .github/workflows/test.yml | 20 +++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/scripts/test-autoplay.js b/.github/scripts/test-autoplay.js index e980bed..b4fd009 100644 --- a/.github/scripts/test-autoplay.js +++ b/.github/scripts/test-autoplay.js @@ -1,4 +1,4 @@ -const { chromium } = require('playwright'); +const playwright = require('playwright'); const CONFIG = { error: { overlaySelector: '#site-error', clickSelector: '#site-error button', initialTitle: 'Internal Server Error' }, @@ -7,11 +7,16 @@ const CONFIG = { const overlayType = process.argv[2]; if (!CONFIG[overlayType]) { - throw new Error(`usage: node test-autoplay.js <${Object.keys(CONFIG).join('|')}>, got "${overlayType}"`); + throw new Error(`usage: node test-autoplay.js <${Object.keys(CONFIG).join('|')}> [chromium|firefox|webkit], got "${overlayType}"`); } const { overlaySelector, clickSelector, initialTitle } = CONFIG[overlayType]; const cookieSelector = '#cookie-banner'; +const browserType = process.argv[3] || 'chromium'; +if (!playwright[browserType]) { + throw new Error(`unknown browser engine "${browserType}", expected chromium, firefox, or webkit`); +} + async function waitFor(page, predicate, { timeout = 5000, interval = 100 } = {}) { const start = Date.now(); while (Date.now() - start < timeout) { @@ -22,7 +27,7 @@ async function waitFor(page, predicate, { timeout = 5000, interval = 100 } = {}) } (async () => { - const browser = await chromium.launch(); + const browser = await playwright[browserType].launch(); const page = await browser.newPage(); await page.goto('http://localhost:8080/', { waitUntil: 'load' }); @@ -102,7 +107,7 @@ async function waitFor(page, predicate, { timeout = 5000, interval = 100 } = {}) throw new Error('expected the cookie banner to be hidden after clicking, but it is still visible'); } - console.log(`OK: ${overlayType} overlay + cookie banner shown, video autoplays muted, and clicking unmutes + hides both`); + console.log(`OK (${browserType}): ${overlayType} overlay + cookie banner shown, video autoplays muted, and clicking unmutes + hides both`); await browser.close(); })().catch((err) => { console.error(err); diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e4b5c0a..82a34bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -161,7 +161,11 @@ jobs: run: | npm init -y >/dev/null npm install --no-save playwright@1 - npx playwright install --with-deps chromium + # Firefox gets its own engine check alongside Chromium - it's + # historically the most divergent on autoplay/gesture policy + # enforcement of the mainstream browsers, so a bug that's fine + # under one can still be broken under the other. + npx playwright install --with-deps chromium firefox - name: Start container with OVERLAY=error run: docker run -d --name rickroll-error -p 8080:8080 -e OVERLAY=error rickroll:test @@ -175,8 +179,11 @@ jobs: docker logs rickroll-error exit 1 - - name: Verify site-error + cookie banner autoplay muted and unmute on click - run: node .github/scripts/test-autoplay.js error + - name: Verify site-error + cookie banner autoplay muted and unmute on click (Chromium) + run: node .github/scripts/test-autoplay.js error chromium + + - name: Verify site-error + cookie banner autoplay muted and unmute on click (Firefox) + run: node .github/scripts/test-autoplay.js error firefox - name: Stop OVERLAY=error container if: always() @@ -194,8 +201,11 @@ jobs: docker logs rickroll-loading exit 1 - - name: Verify loading-screen + cookie banner autoplay muted and unmute on click - run: node .github/scripts/test-autoplay.js loading + - name: Verify loading-screen + cookie banner autoplay muted and unmute on click (Chromium) + run: node .github/scripts/test-autoplay.js loading chromium + + - name: Verify loading-screen + cookie banner autoplay muted and unmute on click (Firefox) + run: node .github/scripts/test-autoplay.js loading firefox - name: Stop OVERLAY=loading container if: always()