diff --git a/apps/sandbox/templates/cdn/main.ts b/apps/sandbox/templates/cdn/main.ts
index 03a535a8c..e0d6a82bc 100644
--- a/apps/sandbox/templates/cdn/main.ts
+++ b/apps/sandbox/templates/cdn/main.ts
@@ -1,9 +1,16 @@
import '@app/styles.css';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { CSS_SKIN_TAGS, LIVE_VIDEO_CSS_SKIN_TAGS } from '@app/shared/html/skin-tags';
import { renderStoryboard } from '@app/shared/html/storyboard';
import { loadAudioStylesheets, loadVideoStylesheets } from '@app/shared/html/stylesheets';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { BACKGROUND_VIDEO_SRC, getPosterSrc, getStoryboardSrc, isLiveSource, SOURCES } from '@app/shared/sources';
import type { Preset, Skin } from '@app/types';
@@ -73,10 +80,10 @@ async function loadCdnMedia(preset: Preset) {
// Rendering — produces the exact HTML markup the installation builder generates.
// ---------------------------------------------------------------------------
-function getPlayerTag(preset: Preset): string {
+function getPlayerTag(preset: Preset, live: boolean): string {
if (preset === 'background-video') return 'background-video-player';
- if (preset === 'audio' || preset === 'mux-audio') return 'audio-player';
- return 'video-player';
+ if (preset === 'audio' || preset === 'mux-audio') return live ? 'live-audio-player' : 'audio-player';
+ return live ? 'live-video-player' : 'video-player';
}
function getSkinTag(preset: Preset, skin: Skin, live: boolean): string {
@@ -135,7 +142,7 @@ async function render() {
loadStylesheets(preset, state.skin);
const root = document.getElementById('root')!;
- const playerTag = getPlayerTag(preset);
+ const playerTag = getPlayerTag(preset, live);
const skinTag = getSkinTag(preset, state.skin, live);
const mediaTag = getMediaTag(preset);
const source = SOURCES[state.source];
@@ -143,7 +150,7 @@ async function render() {
const poster = isVideoPreset(preset) ? getPosterSrc(state.source) : undefined;
const sourceAttr = preset === 'background-video' ? `src="${BACKGROUND_VIDEO_SRC}"` : `src="${source.url}"`;
- const liveAttrs = live ? 'autoplay muted' : '';
+ const mediaAttrs = renderMediaAttrs(state);
// Background video needs viewport dimensions instead of flex centering.
if (preset === 'background-video') {
@@ -167,7 +174,7 @@ async function render() {
<${playerTag}>
<${skinTag}>
- <${mediaTag} ${sourceAttr}>${mediaTag}>
+ <${mediaTag} ${sourceAttr} ${mediaAttrs}>${mediaTag}>
${skinTag}>
${playerTag}>
@@ -178,7 +185,7 @@ async function render() {
root.innerHTML = html`
<${playerTag}>
<${skinTag} class="aspect-video max-w-4xl mx-auto">
- <${mediaTag} ${sourceAttr} ${liveAttrs} playsinline crossorigin="anonymous">
+ <${mediaTag} ${sourceAttr} ${mediaAttrs} playsinline crossorigin="anonymous">
${renderStoryboard(storyboard)}
${mediaTag}>
${poster ? html`
` : ''}
@@ -198,3 +205,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-audio/main.ts b/apps/sandbox/templates/html-audio/main.ts
index 6054ba313..9e84b2394 100644
--- a/apps/sandbox/templates/html-audio/main.ts
+++ b/apps/sandbox/templates/html-audio/main.ts
@@ -1,8 +1,15 @@
import '@app/styles.css';
import '@videojs/html/audio/player';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadAudioSkinTag } from '@app/shared/html/skins';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -14,11 +21,13 @@ async function render() {
const tag = await loadLatest(() => loadAudioSkinTag(state.skin, state.styling));
if (!tag) return;
+ const mediaAttrs = renderMediaAttrs(state);
+
document.getElementById('root')!.innerHTML = html`
@@ -36,3 +45,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-dash-video/main.ts b/apps/sandbox/templates/html-dash-video/main.ts
index 3e28c698a..6b4338ee0 100644
--- a/apps/sandbox/templates/html-dash-video/main.ts
+++ b/apps/sandbox/templates/html-dash-video/main.ts
@@ -1,10 +1,17 @@
import '@app/styles.css';
import '@videojs/html/video/player';
import '@videojs/html/media/dash-video';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadVideoSkinTag } from '@app/shared/html/skins';
import { renderStoryboard } from '@app/shared/html/storyboard';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { getPosterSrc, getStoryboardSrc, SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -18,11 +25,12 @@ async function render() {
const storyboard = getStoryboardSrc(state.source);
const poster = getPosterSrc(state.source);
+ const mediaAttrs = renderMediaAttrs(state);
document.getElementById('root')!.innerHTML = html`
<${tag} class="aspect-video max-w-4xl mx-auto">
-
+
${renderStoryboard(storyboard)}
${poster ? html`
` : ''}
@@ -42,3 +50,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-hls-video/main.ts b/apps/sandbox/templates/html-hls-video/main.ts
index 2bbdb93cd..43adf4a77 100644
--- a/apps/sandbox/templates/html-hls-video/main.ts
+++ b/apps/sandbox/templates/html-hls-video/main.ts
@@ -1,10 +1,17 @@
import '@app/styles.css';
import '@videojs/html/video/player';
import '@videojs/html/media/hls-video';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadVideoSkinTag } from '@app/shared/html/skins';
import { renderStoryboard } from '@app/shared/html/storyboard';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { getPosterSrc, getStoryboardSrc, isLiveSource, SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -19,17 +26,18 @@ async function render() {
const storyboard = getStoryboardSrc(state.source);
const poster = getPosterSrc(state.source);
- const liveAttrs = live ? 'autoplay muted' : '';
+ const mediaAttrs = renderMediaAttrs(state);
+ const playerTag = live ? 'live-video-player' : 'video-player';
document.getElementById('root')!.innerHTML = html`
-
+ <${playerTag}>
<${tag} class="aspect-video max-w-4xl mx-auto">
-
+
${renderStoryboard(storyboard)}
${poster ? html`
` : ''}
${tag}>
-
+ ${playerTag}>
`;
}
@@ -44,3 +52,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-mux-audio/main.ts b/apps/sandbox/templates/html-mux-audio/main.ts
index 3a2e45bfc..1120e6bec 100644
--- a/apps/sandbox/templates/html-mux-audio/main.ts
+++ b/apps/sandbox/templates/html-mux-audio/main.ts
@@ -1,9 +1,16 @@
import '@app/styles.css';
import '@videojs/html/audio/player';
import '@videojs/html/media/mux-audio';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadAudioSkinTag } from '@app/shared/html/skins';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -15,11 +22,13 @@ async function render() {
const tag = await loadLatest(() => loadAudioSkinTag(state.skin, state.styling));
if (!tag) return;
+ const mediaAttrs = renderMediaAttrs(state);
+
document.getElementById('root')!.innerHTML = html`
@@ -37,3 +46,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-mux-video/main.ts b/apps/sandbox/templates/html-mux-video/main.ts
index b90b0cbc5..317b3fc04 100644
--- a/apps/sandbox/templates/html-mux-video/main.ts
+++ b/apps/sandbox/templates/html-mux-video/main.ts
@@ -1,10 +1,17 @@
import '@app/styles.css';
import '@videojs/html/video/player';
import '@videojs/html/media/mux-video';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadVideoSkinTag } from '@app/shared/html/skins';
import { renderStoryboard } from '@app/shared/html/storyboard';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { getPosterSrc, getStoryboardSrc, isLiveSource, SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -19,17 +26,18 @@ async function render() {
const storyboard = getStoryboardSrc(state.source);
const poster = getPosterSrc(state.source);
- const liveAttrs = live ? 'autoplay muted' : '';
+ const mediaAttrs = renderMediaAttrs(state);
+ const playerTag = live ? 'live-video-player' : 'video-player';
document.getElementById('root')!.innerHTML = html`
-
+ <${playerTag}>
<${tag} class="aspect-video max-w-4xl mx-auto">
-
+
${renderStoryboard(storyboard)}
${poster ? html`
` : ''}
${tag}>
-
+ ${playerTag}>
`;
}
@@ -44,3 +52,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-native-hls-video/main.ts b/apps/sandbox/templates/html-native-hls-video/main.ts
index e62da463d..6c0b4941a 100644
--- a/apps/sandbox/templates/html-native-hls-video/main.ts
+++ b/apps/sandbox/templates/html-native-hls-video/main.ts
@@ -1,10 +1,17 @@
import '@app/styles.css';
import '@videojs/html/video/player';
import '@videojs/html/media/native-hls-video';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadVideoSkinTag } from '@app/shared/html/skins';
import { renderStoryboard } from '@app/shared/html/storyboard';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { getPosterSrc, getStoryboardSrc, isLiveSource, SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -19,17 +26,18 @@ async function render() {
const storyboard = getStoryboardSrc(state.source);
const poster = getPosterSrc(state.source);
- const liveAttrs = live ? 'autoplay muted' : '';
+ const mediaAttrs = renderMediaAttrs(state);
+ const playerTag = live ? 'live-video-player' : 'video-player';
document.getElementById('root')!.innerHTML = html`
-
+ <${playerTag}>
<${tag} class="w-full aspect-video max-w-4xl mx-auto">
-
+
${renderStoryboard(storyboard)}
${poster ? html`
` : ''}
${tag}>
-
+ ${playerTag}>
`;
}
@@ -44,3 +52,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-simple-hls-video/main.ts b/apps/sandbox/templates/html-simple-hls-video/main.ts
index 21c820aa2..e1dd163dd 100644
--- a/apps/sandbox/templates/html-simple-hls-video/main.ts
+++ b/apps/sandbox/templates/html-simple-hls-video/main.ts
@@ -1,10 +1,17 @@
import '@app/styles.css';
import '@videojs/html/video/player';
import '@videojs/html/media/simple-hls-video';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadVideoSkinTag } from '@app/shared/html/skins';
import { renderStoryboard } from '@app/shared/html/storyboard';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { getPosterSrc, getStoryboardSrc, isLiveSource, SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -19,17 +26,18 @@ async function render() {
const storyboard = getStoryboardSrc(state.source);
const poster = getPosterSrc(state.source);
- const liveAttrs = live ? 'autoplay muted' : '';
+ const mediaAttrs = renderMediaAttrs(state);
+ const playerTag = live ? 'live-video-player' : 'video-player';
document.getElementById('root')!.innerHTML = html`
-
+ <${playerTag}>
<${tag} class="aspect-video max-w-4xl mx-auto">
-
+
${renderStoryboard(storyboard)}
${poster ? html`
` : ''}
${tag}>
-
+ ${playerTag}>
`;
}
@@ -44,3 +52,23 @@ onSourceChange((source) => {
state.source = source;
render();
});
+
+onAutoplayChange((autoplay) => {
+ state.autoplay = autoplay;
+ render();
+});
+
+onMutedChange((muted) => {
+ state.muted = muted;
+ render();
+});
+
+onLoopChange((loop) => {
+ state.loop = loop;
+ render();
+});
+
+onPreloadChange((preload) => {
+ state.preload = preload;
+ render();
+});
diff --git a/apps/sandbox/templates/html-video/main.ts b/apps/sandbox/templates/html-video/main.ts
index c82fb7014..76f31ddd0 100644
--- a/apps/sandbox/templates/html-video/main.ts
+++ b/apps/sandbox/templates/html-video/main.ts
@@ -1,9 +1,16 @@
import '@app/styles.css';
import '@videojs/html/video/player';
-import { createHtmlSandboxState, createLatestLoader } from '@app/shared/html/sandbox-state';
+import { createHtmlSandboxState, createLatestLoader, renderMediaAttrs } from '@app/shared/html/sandbox-state';
import { loadVideoSkinTag } from '@app/shared/html/skins';
import { renderStoryboard } from '@app/shared/html/storyboard';
-import { onSkinChange, onSourceChange } from '@app/shared/sandbox-listener';
+import {
+ onAutoplayChange,
+ onLoopChange,
+ onMutedChange,
+ onPreloadChange,
+ onSkinChange,
+ onSourceChange,
+} from '@app/shared/sandbox-listener';
import { getPosterSrc, getStoryboardSrc, SOURCES } from '@app/shared/sources';
const html = String.raw;
@@ -17,11 +24,12 @@ async function render() {
const storyboard = getStoryboardSrc(state.source);
const poster = getPosterSrc(state.source);
+ const mediaAttrs = renderMediaAttrs(state);
document.getElementById('root')!.innerHTML = html`
<${tag} class="aspect-video max-w-4xl mx-auto">
-