aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/features/messages.js20
-rw-r--r--tools/feed-media-views-test.js5
2 files changed, 23 insertions, 2 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index a0e9f96..e0e1d05 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -9939,6 +9939,7 @@ export function messagesFeature(ctx) {
const slides = [...pager.scroller.children];
const i = slides.indexOf(slide);
slides.forEach((s, j) => {
+ if (Math.abs(j - i) <= 2) slidePoster(s);
if (j === i) return;
const v = s.querySelector('video.mp-media');
if (j === i + 1) {
@@ -9961,7 +9962,16 @@ export function messagesFeature(ctx) {
if (!pager || pager.cur !== slide) return;
if (videoHeavy(url)) {
if (slide.querySelector('.vid-heavy')) return;
- pagerRelease(slide);
+ // under the cover, a picture of what it is: the kept frame, else the
+ // first frame itself (only the start of the file, when it leads with
+ // its index or is served in ranges)
+ slidePoster(slide);
+ const d = videoInfo.get(url) || {};
+ if (!videoThumbs.has(url) && (d.faststart || d.ranges || !d.probed)) {
+ v.preload = 'metadata';
+ v.addEventListener('loadeddata', () => setTimeout(() => keepVideoThumb(v, url), 150), { once: true });
+ v.setAttribute('src', url + '#t=0.1');
+ } else pagerRelease(slide);
slide.append(h('button', { class: 'vid-heavy', type: 'button', 'aria-label': t('videoTapToPlay'), onClick: (e) => {
e.stopPropagation();
tappedClips.add(url);
@@ -9973,8 +9983,16 @@ export function messagesFeature(ctx) {
startSlide(slide);
});
}
+ // the kept frame as the poster, looked up as the slide comes near (it may
+ // have been kept after the slide was built)
+ function slidePoster(slide) {
+ const v = slide.querySelector('video.mp-media');
+ const thumb = v && videoThumbs.get(v.getAttribute('data-src'));
+ if (thumb && v.getAttribute('poster') !== thumb) v.setAttribute('poster', thumb);
+ }
function startSlide(slide) {
const v = slide.querySelector('video.mp-media');
+ if (/#t=[\d.]+$/.test(v.getAttribute('src') || '')) v.setAttribute('src', v.getAttribute('data-src')); // the still's src: from the start now
v.preload = 'auto';
pagerAttach(slide);
v.muted = !pagerLoud;
diff --git a/tools/feed-media-views-test.js b/tools/feed-media-views-test.js
index 0811520..9181904 100644
--- a/tools/feed-media-views-test.js
+++ b/tools/feed-media-views-test.js
@@ -198,7 +198,10 @@ try {
st = await pagerState();
check('the 50 MB clip waits for a tap, saying what it costs', st.src === 'c.mp4' && await page.evaluate(() => {
const s = document.querySelectorAll('.mp-slide')[2]; const b = s.querySelector('.vid-heavy');
- return !!b && /50 MB/.test(b.textContent) && !s.querySelector('video').getAttribute('src'); }), JSON.stringify(st));
+ return !!b && /50 MB/.test(b.textContent) && !/^[^#]*$/.test(s.querySelector('video').getAttribute('src') || '#'); }), JSON.stringify(st));
+ check('...over a picture of it (the kept frame, or the first frame itself)', await waitFor(() => {
+ const v = document.querySelectorAll('.mp-slide')[2].querySelector('video');
+ return (v.getAttribute('poster') || '').startsWith('blob:') || (/#t=/.test(v.getAttribute('src') || '') && v.readyState >= 2); }, 5000));
await shot('heavy');
await page.evaluate(() => document.querySelectorAll('.mp-slide')[2].querySelector('.vid-heavy').click());
check('a tap plays it', await waitFor(() => { const v = document.querySelectorAll('.media-pager video')[2]; return !v.paused && v.currentTime > 0; }, 6000));