aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/features/messages.js21
-rw-r--r--tools/video-autoplay-test.js6
2 files changed, 22 insertions, 5 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index f57c3ee..945f01e 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -5087,21 +5087,32 @@ export function messagesFeature(ctx) {
}
// An inline video, in a box with the sound button; plays on its own while
// on screen. Once it has played, the box is the viewer's (no morph).
+ // A clip the reader turned the sound on for stays that way for the session,
+ // however its box is rebuilt: a repaint pairing children differently, the
+ // window unmounting the row and mounting it again, a quoted note loading.
+ // Pinning the box alone left every one of those a muted restart.
+ const unmutedClips = new Set();
function videoNode(url, { stable = false } = {}) {
+ const loud = unmutedClips.has(url);
const v = h('video', { src: url, class: 'note-video', controls: true,
- preload: 'metadata', playsinline: true, muted: true, // play() in view fetches; a window of videos must not all stream
+ preload: 'metadata', playsinline: true, muted: loud ? undefined : true, // play() in view fetches; a window of videos must not all stream
style: stable ? 'width:100%;aspect-ratio:16/9;object-fit:contain' : undefined,
onError: (e) => { if (!stable) { const b = e.target.parentElement; if (b) b.style.display = 'none'; } } });
- v.muted = true; // the property, not just the attribute: a script-made element autoplays only muted
+ v.muted = !loud; // the property, not just the attribute: a script-made element autoplays only muted
const box = h('div', { class: 'note-video-box' }, v);
- const btn = soundBtn(() => {
+ if (loud) box._skipMorph = true;
+ const btn = loud ? null : soundBtn(() => {
v.muted = false;
+ unmutedClips.add(url);
box._skipMorph = true; // the box is the viewer's now: no repaint rebuilds it muted
if (v.paused) v.play().catch(() => {});
btn.remove(); // the player's own controls carry mute from here
});
- v.onvolumechange = () => { if (!v.muted && btn.isConnected) btn.remove(); }; // unmuted from the native control: same
- box.append(btn);
+ v.onvolumechange = () => {
+ if (!v.muted) { unmutedClips.add(url); if (btn && btn.isConnected) btn.remove(); } // unmuted from the native control: same
+ else unmutedClips.delete(url); // muted again from the control: the next box starts quiet
+ };
+ if (btn) box.append(btn);
// Off screen, a muted preview lets go of its media entirely (a paused
// player keeps buffering the whole file — a scroll past ten clips
// streamed seventy megabytes); back in view it reattaches and plays
diff --git a/tools/video-autoplay-test.js b/tools/video-autoplay-test.js
index 29a1437..583c908 100644
--- a/tools/video-autoplay-test.js
+++ b/tools/video-autoplay-test.js
@@ -77,6 +77,12 @@ try {
JSON.stringify(await page.evaluate(() => { const v = document.querySelector('.note-video-box video'); return v && { paused: v.paused, t: v.currentTime, err: v.error && v.error.code, ready: v.readyState }; })));
await page.evaluate(() => document.querySelector('.note-video-box .vid-sound').click()); await sleep(500);
check('Unmute turns the sound on, and the button leaves (the player\'s own controls carry mute)', await page.evaluate(() => { const v = document.querySelector('.note-video-box video'); const b = document.querySelector('.note-video-box .vid-sound'); return !v.muted && !b; }));
+ // the box rebuilt from scratch (the row re-rendered by hand, the way a
+ // window remount or a quote load would) comes back loud, with no button
+ await page.evaluate(() => { const box = document.querySelector('.note-video-box'); const row = box.closest('.row'); row.remove(); });
+ await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((n) => /dark mode/i.test(n.textContent)); if (b) { b.click(); b.click(); } }); await sleep(800);
+ check('a rebuilt box keeps the sound on for the session', await waitFor(() => { const v = document.querySelector('.note-video-box video'); return v && !v.muted && !document.querySelector('.note-video-box .vid-sound'); }, 6000),
+ JSON.stringify(await page.evaluate(() => { const v = document.querySelector('.note-video-box video'); return v && { muted: v.muted, btn: !!document.querySelector('.note-video-box .vid-sound') }; })));
await page.evaluate(() => window.scrollTo(0, 1000)); await sleep(700);
check('scrolled away, it pauses', await waitFor(() => { const v = document.querySelector('.note-video-box video'); return v && v.paused; }, 4000));