openvibers/openvibe.media Commits
Watch page: do not let a video preload hold the load event (#314)
Changes
@@@ -182,9 +182,12 @@ function renderWatchPage(kind, record, readiness = null) {].filter(Boolean);const [stateTitle, stateText] = playable ? [null, null] : unavailableText(kind, readiness.reason);++ // No preload: a long recording is a fragmented MP4 whose moov has no duration, so Chrome keeps range-reading the++ // whole file to find one, never reaches HAVE_METADATA, and the window's load event waits for it (v/6170: 30 s+++ // timeout). The poster is the first frame, and pressing play still fetches the bytes; the page itself must load.const player = playable? `<div class="player">-- <video data-ov-player controls playsinline preload="metadata"${thumb ? ` poster="${esc(thumb)}"` : ''} src="${esc(rawUrl)}">++ <video data-ov-player controls playsinline preload="none"${thumb ? ` poster="${esc(thumb)}"` : ''} src="${esc(rawUrl)}">Your browser cannot play this video. <a href="${esc(rawUrl)}">Download it</a> instead.</video></div>`@@@ -58,6 +58,10 @@ const http = require('http');assert.ok(html.includes('<meta property="og:video" content="https://media.test/v/42?raw=1">'));assert.ok(html.includes('<meta name="twitter:card" content="summary_large_image">'));assert.ok(html.includes('src="https://media.test/v/42?raw=1"'), 'the player fetches the bytes with ?raw=1');++ // A long fragmented recording can report no duration, so a metadata preload never finishes and the window load++ // event waits on it (v/6170). The poster is the first frame; the bytes are fetched on play.++ assert.ok(/<video[^>]*\bpreload="none"/.test(html), 'the player does not preload the video and block the page load');++ assert.ok(!html.includes('preload="metadata"'), 'no metadata preload on the watch page');const scripts = [...html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)];assert.strictEqual(scripts.length, 1);const ld = JSON.parse(scripts[0][1])['@graph'][0];
@@ -182,9 +182,12 @@ function renderWatchPage(kind, record, readiness = null) {
@@ -182,9 +182,12 @@ function renderWatchPage(kind, record, readiness = null) {
].filter(Boolean);
].filter(Boolean);
const [stateTitle, stateText] = playable ? [null, null] : unavailableText(kind, readiness.reason);
const [stateTitle, stateText] = playable ? [null, null] : unavailableText(kind, readiness.reason);
+ // No preload: a long recording is a fragmented MP4 whose moov has no duration, so Chrome keeps range-reading the
+ // whole file to find one, never reaches HAVE_METADATA, and the window's load event waits for it (v/6170: 30 s+
+ // timeout). The poster is the first frame, and pressing play still fetches the bytes; the page itself must load.
const player = playable
const player = playable
? `<div class="player">
? `<div class="player">
- <video data-ov-player controls playsinline preload="metadata"${thumb ? ` poster="${esc(thumb)}"` : ''} src="${esc(rawUrl)}">
+ <video data-ov-player controls playsinline preload="none"${thumb ? ` poster="${esc(thumb)}"` : ''} src="${esc(rawUrl)}">
Your browser cannot play this video. <a href="${esc(rawUrl)}">Download it</a> instead.
Your browser cannot play this video. <a href="${esc(rawUrl)}">Download it</a> instead.
</video>
</video>
</div>`
</div>`
@@ -58,6 +58,10 @@ const http = require('http');
@@ -58,6 +58,10 @@ const http = require('http');
assert.ok(html.includes('<meta property="og:video" content="https://media.test/v/42?raw=1">'));
assert.ok(html.includes('<meta property="og:video" content="https://media.test/v/42?raw=1">'));
assert.ok(html.includes('<meta name="twitter:card" content="summary_large_image">'));
assert.ok(html.includes('<meta name="twitter:card" content="summary_large_image">'));
assert.ok(html.includes('src="https://media.test/v/42?raw=1"'), 'the player fetches the bytes with ?raw=1');
assert.ok(html.includes('src="https://media.test/v/42?raw=1"'), 'the player fetches the bytes with ?raw=1');
+ // A long fragmented recording can report no duration, so a metadata preload never finishes and the window load
+ // event waits on it (v/6170). The poster is the first frame; the bytes are fetched on play.
+ assert.ok(/<video[^>]*\bpreload="none"/.test(html), 'the player does not preload the video and block the page load');
+ assert.ok(!html.includes('preload="metadata"'), 'no metadata preload on the watch page');
const scripts = [...html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)];
const scripts = [...html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)];
assert.strictEqual(scripts.length, 1);
assert.strictEqual(scripts.length, 1);
const ld = JSON.parse(scripts[0][1])['@graph'][0];
const ld = JSON.parse(scripts[0][1])['@graph'][0];