openvibers/openvibe.mediahub Commits
The small player plays the plain file, named on the watch page (#376)
Changes
@@@ -114,8 +114,10 @@ function posterAttr(url) {* A watch page's video may come along (openvibe-shared 4.192 mini.js): the player's picture-in-picture button takes the* person to the front page and the video goes on in the small player, on every page, from the same second.*/--function miniAttr(title, by, page) {-- return html` data-ov-mini data-ov-mini-title="${String(title || 'Video')}" data-ov-mini-by="${String(by || '')}" data-ov-mini-page="${String(page || '')}"`;++function miniAttr(title, by, page, file) {++ // The file is named here: the page's script gives the element its streaming playlist once it runs, and the small++ // player on another page plays the plain file (11-10: it was handed the playlist and drew nothing).++ return html` data-ov-mini data-ov-mini-title="${String(title || 'Video')}" data-ov-mini-by="${String(by || '')}" data-ov-mini-page="${String(page || '')}"${file ? html` data-ov-mini-src="${String(file)}"` : ''}`;}function avatarAttr(username, networkUrl) {@@@ -1502,7 +1504,7 @@ ${found ? sections.map((x) => (x.cards.length || kind ? html`<section class="ovv<div class="ovv-col ovv-col--main"><div class="ovv-stage">${savedNotice(req)}${ownOnly ? notice('Private: only you (and OpenVibe staff) can see this recording.', 'info') : ''}--<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(vod), { owner: vod.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(vod.title || 'Stream recording', channelName || vod.username, watchPath)} controls preload="metadata" playsinline${posterAttr(httpsUrl(vod.thumbnail_url))}${avatarAttr(vod.username, config.networkUrl)}${shapeAttr} src="${fileOf(vod) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}>${segs.length ? html`<track kind="captions" label="Transcript (AI)" src="/v/${id}/captions.vtt" default>` : ''}${mems.length ? html`<track kind="chapters" src="/v/${id}/chapters.vtt">` : ''}</video>${pipsTag(pips)}</div>++<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(vod), { owner: vod.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(vod.title || 'Stream recording', channelName || vod.username, watchPath, fileOf(vod))} controls preload="metadata" playsinline${posterAttr(httpsUrl(vod.thumbnail_url))}${avatarAttr(vod.username, config.networkUrl)}${shapeAttr} src="${fileOf(vod) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}>${segs.length ? html`<track kind="captions" label="Transcript (AI)" src="/v/${id}/captions.vtt" default>` : ''}${mems.length ? html`<track kind="chapters" src="/v/${id}/chapters.vtt">` : ''}</video>${pipsTag(pips)}</div><div class="ovv-head">${titleLine('Stream recording', vod.title || 'Stream recording')}${labelsUi.chips(labelsUi.inForce(vod))}@@@ -1628,7 +1630,7 @@ ${more || ''}<div class="ovv-stage">${savedNotice(req)}${req.query.made === '1' ? notice('Your clip was made. It is credited to you on OpenVibe.Live and here.', 'ok') : ''}${ownOnly ? notice('Private: only you (and OpenVibe staff) can see this clip.', 'info') : ''}${cutting ? html`<div class="ovv-player-wrap ovv-cutting" role="status" data-ovv-reload="8"><p><i class="fa-solid fa-scissors" aria-hidden="true"></i> This clip is being cut. It plays here in a moment; the page checks again by itself.</p></div>`-- : html`<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(clip), { owner: clip.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(clip.title || 'Clip', clip.source_streamer_display_name || clip.display_name || clip.username, watchPath)} controls preload="metadata" playsinline${avatarAttr(clip.username, config.networkUrl)}${posterAttr(httpsUrl(clip.thumbnail_url))} src="${fileOf(clip) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}></video></div>`}++ : html`<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(clip), { owner: clip.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(clip.title || 'Clip', clip.source_streamer_display_name || clip.display_name || clip.username, watchPath, fileOf(clip))} controls preload="metadata" playsinline${avatarAttr(clip.username, config.networkUrl)}${posterAttr(httpsUrl(clip.thumbnail_url))} src="${fileOf(clip) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}></video></div>`}<div class="ovv-head">${titleLine(aiClip ? 'AI clip' : 'Clip', clip.title || 'Clip')}${labelsUi.chips(labelsUi.inForce(clip))}@@@ -145,7 +145,7 @@ function hreq(base, host, path, { method = 'GET', cookie, form, body, type, sameconst v = await video('/v/301');const more = (v.text.split('<section class="ovv-panel ovv-also"')[1] || '').split('</section>')[0];// The video may come along (the small player): it carries its title, who made it and its own page.-- assert.match(v.text, /<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="\/(?:watch\?v=[^"]+|v\/301)"/, 'a recording says it may come along');++ assert.match(v.text, /<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="\/(?:watch\?v=[^"]+|v\/301)"(?: data-ov-mini-src="[^"]+")?/, 'a recording says it may come along');assert.match(v.text, /<script src="[^"]*mini[^"]*\.js[^"]*" defer><\/script>/, 'every Video page loads the small player');assert.ok(!/Kim labelled/.test(more), 'never the recording playing');assert.ok(!/Kim clip/.test(more), 'its own clips are in Clips from this stream, not again here');@@@ -348,7 +348,7 @@ function countOccurrences(haystack, needle) {assert.ok(r.text.includes('playsinline'));assert.ok(r.text.includes('data-ovv-video'));// The network's player (openvibe-shared player.js/css): marked, and both files load on the page.-- assert.ok(/<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="[^"]+" controls /.test(r.text), 'the video takes the network player, and may come along in the small player');++ assert.ok(/<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="[^"]+" data-ov-mini-src="[^"]+" controls /.test(r.text), 'the video takes the network player, and may come along in the small player');// The streamer's face for an audio-only recording (openvibe-shared 4.90 player.js, plan R4): Network's avatar URL.assert.match(r.text, /<video class="ovv-player"[^>]* data-ov-avatar="[^"]+\/avatar\/streamer"/, 'the player knows the streamer\'s face');assert.ok(/<link rel="stylesheet" href="\/shared\/player\.css\?v=[0-9a-f]+">/.test(r.text) && /<script src="\/shared\/player\.js\?v=[0-9a-f]+" defer><\/script>/.test(r.text), 'player.css and player.js load');
@@ -114,8 +114,10 @@ function posterAttr(url) {
@@ -114,8 +114,10 @@ function posterAttr(url) {
* A watch page's video may come along (openvibe-shared 4.192 mini.js): the player's picture-in-picture button takes the
* A watch page's video may come along (openvibe-shared 4.192 mini.js): the player's picture-in-picture button takes the
* person to the front page and the video goes on in the small player, on every page, from the same second.
* person to the front page and the video goes on in the small player, on every page, from the same second.
*/
*/
-function miniAttr(title, by, page) {
- return html` data-ov-mini data-ov-mini-title="${String(title || 'Video')}" data-ov-mini-by="${String(by || '')}" data-ov-mini-page="${String(page || '')}"`;
+function miniAttr(title, by, page, file) {
+ // The file is named here: the page's script gives the element its streaming playlist once it runs, and the small
+ // player on another page plays the plain file (11-10: it was handed the playlist and drew nothing).
+ return html` data-ov-mini data-ov-mini-title="${String(title || 'Video')}" data-ov-mini-by="${String(by || '')}" data-ov-mini-page="${String(page || '')}"${file ? html` data-ov-mini-src="${String(file)}"` : ''}`;
}
}
function avatarAttr(username, networkUrl) {
function avatarAttr(username, networkUrl) {
@@ -1502,7 +1504,7 @@ ${found ? sections.map((x) => (x.cards.length || kind ? html`<section class="ovv
@@ -1502,7 +1504,7 @@ ${found ? sections.map((x) => (x.cards.length || kind ? html`<section class="ovv
<div class="ovv-col ovv-col--main">
<div class="ovv-col ovv-col--main">
<div class="ovv-stage">
<div class="ovv-stage">
${savedNotice(req)}${ownOnly ? notice('Private: only you (and OpenVibe staff) can see this recording.', 'info') : ''}
${savedNotice(req)}${ownOnly ? notice('Private: only you (and OpenVibe staff) can see this recording.', 'info') : ''}
-<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(vod), { owner: vod.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(vod.title || 'Stream recording', channelName || vod.username, watchPath)} controls preload="metadata" playsinline${posterAttr(httpsUrl(vod.thumbnail_url))}${avatarAttr(vod.username, config.networkUrl)}${shapeAttr} src="${fileOf(vod) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}>${segs.length ? html`<track kind="captions" label="Transcript (AI)" src="/v/${id}/captions.vtt" default>` : ''}${mems.length ? html`<track kind="chapters" src="/v/${id}/chapters.vtt">` : ''}</video>${pipsTag(pips)}</div>
+<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(vod), { owner: vod.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(vod.title || 'Stream recording', channelName || vod.username, watchPath, fileOf(vod))} controls preload="metadata" playsinline${posterAttr(httpsUrl(vod.thumbnail_url))}${avatarAttr(vod.username, config.networkUrl)}${shapeAttr} src="${fileOf(vod) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}>${segs.length ? html`<track kind="captions" label="Transcript (AI)" src="/v/${id}/captions.vtt" default>` : ''}${mems.length ? html`<track kind="chapters" src="/v/${id}/chapters.vtt">` : ''}</video>${pipsTag(pips)}</div>
<div class="ovv-head">
<div class="ovv-head">
${titleLine('Stream recording', vod.title || 'Stream recording')}
${titleLine('Stream recording', vod.title || 'Stream recording')}
${labelsUi.chips(labelsUi.inForce(vod))}
${labelsUi.chips(labelsUi.inForce(vod))}
@@ -1628,7 +1630,7 @@ ${more || ''}
@@ -1628,7 +1630,7 @@ ${more || ''}
<div class="ovv-stage">
<div class="ovv-stage">
${savedNotice(req)}${req.query.made === '1' ? notice('Your clip was made. It is credited to you on OpenVibe.Live and here.', 'ok') : ''}${ownOnly ? notice('Private: only you (and OpenVibe staff) can see this clip.', 'info') : ''}
${savedNotice(req)}${req.query.made === '1' ? notice('Your clip was made. It is credited to you on OpenVibe.Live and here.', 'ok') : ''}${ownOnly ? notice('Private: only you (and OpenVibe staff) can see this clip.', 'info') : ''}
${cutting ? html`<div class="ovv-player-wrap ovv-cutting" role="status" data-ovv-reload="8"><p><i class="fa-solid fa-scissors" aria-hidden="true"></i> This clip is being cut. It plays here in a moment; the page checks again by itself.</p></div>`
${cutting ? html`<div class="ovv-player-wrap ovv-cutting" role="status" data-ovv-reload="8"><p><i class="fa-solid fa-scissors" aria-hidden="true"></i> This clip is being cut. It plays here in a moment; the page checks again by itself.</p></div>`
- : html`<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(clip), { owner: clip.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(clip.title || 'Clip', clip.source_streamer_display_name || clip.display_name || clip.username, watchPath)} controls preload="metadata" playsinline${avatarAttr(clip.username, config.networkUrl)}${posterAttr(httpsUrl(clip.thumbnail_url))} src="${fileOf(clip) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}></video></div>`}
+ : html`<div class="ovv-player-wrap"${labelsUi.attrs(labelsUi.inForce(clip), { owner: clip.username, opened: true })}><video class="ovv-player" data-ov-player${miniAttr(clip.title || 'Clip', clip.source_streamer_display_name || clip.display_name || clip.username, watchPath, fileOf(clip))} controls preload="metadata" playsinline${avatarAttr(clip.username, config.networkUrl)}${posterAttr(httpsUrl(clip.thumbnail_url))} src="${fileOf(clip) || ''}" data-ovv-video${nextAttr}${viewAttr}${hlsAttr}></video></div>`}
<div class="ovv-head">
<div class="ovv-head">
${titleLine(aiClip ? 'AI clip' : 'Clip', clip.title || 'Clip')}
${titleLine(aiClip ? 'AI clip' : 'Clip', clip.title || 'Clip')}
${labelsUi.chips(labelsUi.inForce(clip))}
${labelsUi.chips(labelsUi.inForce(clip))}
@@ -145,7 +145,7 @@ function hreq(base, host, path, { method = 'GET', cookie, form, body, type, same
@@ -145,7 +145,7 @@ function hreq(base, host, path, { method = 'GET', cookie, form, body, type, same
const v = await video('/v/301');
const v = await video('/v/301');
const more = (v.text.split('<section class="ovv-panel ovv-also"')[1] || '').split('</section>')[0];
const more = (v.text.split('<section class="ovv-panel ovv-also"')[1] || '').split('</section>')[0];
// The video may come along (the small player): it carries its title, who made it and its own page.
// The video may come along (the small player): it carries its title, who made it and its own page.
- assert.match(v.text, /<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="\/(?:watch\?v=[^"]+|v\/301)"/, 'a recording says it may come along');
+ assert.match(v.text, /<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="\/(?:watch\?v=[^"]+|v\/301)"(?: data-ov-mini-src="[^"]+")?/, 'a recording says it may come along');
assert.match(v.text, /<script src="[^"]*mini[^"]*\.js[^"]*" defer><\/script>/, 'every Video page loads the small player');
assert.match(v.text, /<script src="[^"]*mini[^"]*\.js[^"]*" defer><\/script>/, 'every Video page loads the small player');
assert.ok(!/Kim labelled/.test(more), 'never the recording playing');
assert.ok(!/Kim labelled/.test(more), 'never the recording playing');
assert.ok(!/Kim clip/.test(more), 'its own clips are in Clips from this stream, not again here');
assert.ok(!/Kim clip/.test(more), 'its own clips are in Clips from this stream, not again here');
@@ -348,7 +348,7 @@ function countOccurrences(haystack, needle) {
@@ -348,7 +348,7 @@ function countOccurrences(haystack, needle) {
assert.ok(r.text.includes('playsinline'));
assert.ok(r.text.includes('playsinline'));
assert.ok(r.text.includes('data-ovv-video'));
assert.ok(r.text.includes('data-ovv-video'));
// The network's player (openvibe-shared player.js/css): marked, and both files load on the page.
// The network's player (openvibe-shared player.js/css): marked, and both files load on the page.
- assert.ok(/<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="[^"]+" controls /.test(r.text), 'the video takes the network player, and may come along in the small player');
+ assert.ok(/<video class="ovv-player" data-ov-player data-ov-mini data-ov-mini-title="[^"]+" data-ov-mini-by="[^"]*" data-ov-mini-page="[^"]+" data-ov-mini-src="[^"]+" controls /.test(r.text), 'the video takes the network player, and may come along in the small player');
// The streamer's face for an audio-only recording (openvibe-shared 4.90 player.js, plan R4): Network's avatar URL.
// The streamer's face for an audio-only recording (openvibe-shared 4.90 player.js, plan R4): Network's avatar URL.
assert.match(r.text, /<video class="ovv-player"[^>]* data-ov-avatar="[^"]+\/avatar\/streamer"/, 'the player knows the streamer\'s face');
assert.match(r.text, /<video class="ovv-player"[^>]* data-ov-avatar="[^"]+\/avatar\/streamer"/, 'the player knows the streamer\'s face');
assert.ok(/<link rel="stylesheet" href="\/shared\/player\.css\?v=[0-9a-f]+">/.test(r.text) && /<script src="\/shared\/player\.js\?v=[0-9a-f]+" defer><\/script>/.test(r.text), 'player.css and player.js load');
assert.ok(/<link rel="stylesheet" href="\/shared\/player\.css\?v=[0-9a-f]+">/.test(r.text) && /<script src="\/shared\/player\.js\?v=[0-9a-f]+" defer><\/script>/.test(r.text), 'player.css and player.js load');