From 4196c6ae2d1cd9bf10e2612140abc4124993e724 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 13 Oct 2026 06:22:43 +0000 Subject: Media pager: one clip plays — nothing under it starts, and nothing beside it. Adam turned his phone while watching a clip and heard it start again from the beginning while the picture played on: a second copy playing unseen. Not reproduced here (a turn in the test browser, with the clip muted or unmuted in the feed first, on this build or the last, leaves one clip playing), but three ways to a second copy are now closed. The feed under the pager stays laid out, and its autoplay watched it: anything there coming into view — a turn re-lays the page out — started, the pager's own clip as often as not, with sound if it had been unmuted there (with the guard off, the test's scroll under the pager starts the feed's copy). Under the pager the feed's autoplay now starts nothing, and opening the pager pauses every player on the page (YouTube too). In the pager only the slide on screen may start (not one a half-way layout passed over, whose start was still on its way), and starting one pauses any other. tools/pager-rotate-test.js (installed app, no full screen: one clip through a turn and back, on the slide it was on; a feed clip brought into view under the pager stays still; muted and unmuted in the feed first). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt --- src/features/messages.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/features/messages.js b/src/features/messages.js index 6548e99..1c74526 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -7466,6 +7466,10 @@ export function messagesFeature(ctx) { for (const en of entries) { const el2 = en.target; if (!el2.isConnected) { playerWatch.unobserve(el2); continue; } + // under the media pager nothing starts: the page laid out again + // beneath it (a turn of the phone) "showed" a clip — the pager's own, + // as often as not — and a second copy played behind it + if (ui.mediaPager && en.isIntersecting) continue; if (en.isIntersecting && en.intersectionRatio >= 0.5) { if (el2._onIn) el2._onIn(); } else if (el2._onOut) el2._onOut(); } }, { threshold: [0, 0.5] }); @@ -12027,6 +12031,11 @@ export function messagesFeature(ctx) { // clips, in the feed's order), rather than from the media grid; `at`: where // the clip it opened on was, so it carries on from there function openMediaPager(kind, start, { fromFeed = false, at = 0 } = {}) { + // the page's own players stop: the pager's is the one to hear + for (const v of document.querySelectorAll('video')) { try { v.pause(); } catch {} } + for (const f of document.querySelectorAll('.yt-embed[data-playing] iframe')) { + try { f.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'pauseVideo', args: [] }), '*'); f.closest('.yt-embed')._pausedByUs = true; } catch {} + } ui.mediaPager = { kind, start, feed: curFeedId, fromFeed, at }; render(); } @@ -12398,7 +12407,11 @@ export function messagesFeature(ctx) { if (thumb && v.getAttribute('poster') !== thumb) v.setAttribute('poster', thumb); } function startSlide(slide) { + // only the slide on screen plays (not one a half-way layout — a turn of + // the phone — passed over), and it alone + if (!pager || pager.cur !== slide) return; const v = slide.querySelector('video.mp-media'); + for (const o of pager.el.querySelectorAll('video.mp-media')) if (o !== v && !o.paused) { try { o.pause(); } catch {} } if (/#t=[\d.]+$/.test(v.getAttribute('src') || '')) v.setAttribute('src', playSrc(v.getAttribute('data-src'))); // the still's src: from the start now v.preload = 'auto'; pagerAttach(slide); -- cgit v1.2.3