@videojs/html 10.2.0 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/default/define/audio/compat-skin.css +161 -41
- package/dist/default/define/audio/compat-skin2.js +1 -1
- package/dist/default/define/audio/neutral-skin.css +73 -34
- package/dist/default/define/audio/neutral-skin2.js +1 -1
- package/dist/default/define/audio/scaffold-skin.css +166 -42
- package/dist/default/define/audio/scaffold-skin2.js +1 -1
- package/dist/default/define/audio/skin.css +72 -34
- package/dist/default/define/audio/skin2.js +1 -1
- package/dist/default/define/extensions/google-analytics.js +6 -0
- package/dist/default/define/live-audio/compat-skin.css +143 -41
- package/dist/default/define/live-audio/compat-skin2.js +1 -1
- package/dist/default/define/live-audio/neutral-skin.css +56 -31
- package/dist/default/define/live-audio/neutral-skin2.js +1 -1
- package/dist/default/define/live-audio/scaffold-skin.css +148 -42
- package/dist/default/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/default/define/live-audio/skin.css +55 -31
- package/dist/default/define/live-audio/skin2.js +1 -1
- package/dist/default/define/live-video/compat-skin.css +234 -51
- package/dist/default/define/live-video/compat-skin2.js +1 -1
- package/dist/default/define/live-video/neutral-skin.css +300 -46
- package/dist/default/define/live-video/neutral-skin2.js +1 -1
- package/dist/default/define/live-video/scaffold-skin.css +231 -53
- package/dist/default/define/live-video/scaffold-skin2.js +1 -1
- package/dist/default/define/live-video/skin.css +314 -49
- package/dist/default/define/live-video/skin2.js +1 -1
- package/dist/default/define/media/dailymotion-video.js +11 -0
- package/dist/default/define/media/mixcloud-audio.js +11 -0
- package/dist/default/define/media/soundcloud-audio.js +11 -0
- package/dist/default/define/ui/time-slider-markers.js +5 -0
- package/dist/default/define/video/compat-skin.css +242 -51
- package/dist/default/define/video/compat-skin2.js +1 -1
- package/dist/default/define/video/neutral-skin.css +382 -57
- package/dist/default/define/video/neutral-skin2.js +1 -1
- package/dist/default/define/video/scaffold-skin.css +240 -53
- package/dist/default/define/video/scaffold-skin2.js +1 -1
- package/dist/default/define/video/skin.css +415 -55
- package/dist/default/define/video/skin2.js +1 -1
- package/dist/default/extensions/google-analytics/extension.js +75 -0
- package/dist/default/extensions/mux-data/extension.js +7 -2
- package/dist/default/index.js +3 -1
- package/dist/default/internal/skins/compat-audio/skin.css +161 -41
- package/dist/default/internal/skins/compat-audio/template.js +1 -1
- package/dist/default/internal/skins/compat-live-audio/skin.css +143 -41
- package/dist/default/internal/skins/compat-live-video/skin.css +234 -51
- package/dist/default/internal/skins/compat-live-video/template.js +2 -0
- package/dist/default/internal/skins/compat-video/skin.css +242 -51
- package/dist/default/internal/skins/compat-video/template.js +2 -0
- package/dist/default/internal/skins/default-audio/skin.css +72 -34
- package/dist/default/internal/skins/default-live-audio/skin.css +55 -31
- package/dist/default/internal/skins/default-live-video/skin.css +314 -49
- package/dist/default/internal/skins/default-live-video/template.js +14 -0
- package/dist/default/internal/skins/default-video/register.js +3 -0
- package/dist/default/internal/skins/default-video/skin.css +415 -55
- package/dist/default/internal/skins/default-video/template.js +33 -5
- package/dist/default/internal/skins/neutral-audio/skin.css +73 -34
- package/dist/default/internal/skins/neutral-live-audio/skin.css +56 -31
- package/dist/default/internal/skins/neutral-live-video/skin.css +300 -46
- package/dist/default/internal/skins/neutral-live-video/template.js +14 -0
- package/dist/default/internal/skins/neutral-video/skin.css +382 -57
- package/dist/default/internal/skins/neutral-video/template.js +25 -11
- package/dist/default/internal/skins/scaffold-audio/skin.css +166 -42
- package/dist/default/internal/skins/scaffold-audio/template.js +1 -1
- package/dist/default/internal/skins/scaffold-live-audio/skin.css +148 -42
- package/dist/default/internal/skins/scaffold-live-video/skin.css +231 -53
- package/dist/default/internal/skins/scaffold-live-video/template.js +2 -0
- package/dist/default/internal/skins/scaffold-video/skin.css +240 -53
- package/dist/default/internal/skins/scaffold-video/template.js +3 -1
- package/dist/default/media/background-video/adapter.js +13 -35
- package/dist/default/media/background-video/base.js +95 -0
- package/dist/default/media/background-video/template.js +13 -20
- package/dist/default/media/dailymotion-video/adapter.js +31 -0
- package/dist/default/media/hls-background-video/adapter.js +23 -35
- package/dist/default/media/mixcloud-audio/adapter.js +16 -0
- package/dist/default/media/soundcloud-audio/adapter.js +16 -0
- package/dist/default/player/element.js +1 -5
- package/dist/default/presets/background/skin.js +2 -2
- package/dist/default/presets/skin.js +4 -3
- package/dist/default/ui/captions-radio-group/element.js +14 -1
- package/dist/default/ui/controls/element.js +6 -3
- package/dist/default/ui/dialog/element.js +13 -1
- package/dist/default/ui/gesture/element.js +3 -0
- package/dist/default/ui/media-button-element.js +10 -1
- package/dist/default/ui/playback-rate-button/element.js +7 -2
- package/dist/default/ui/playback-rate-radio-group/element.js +10 -3
- package/dist/default/ui/radio-options/controller.js +18 -5
- package/dist/default/ui/time-slider/markers.js +160 -0
- package/dist/default/version.js +1 -1
- package/dist/dev/define/audio/compat-skin.css +161 -41
- package/dist/dev/define/audio/compat-skin2.js +1 -1
- package/dist/dev/define/audio/compat-skin2.js.map +1 -1
- package/dist/dev/define/audio/neutral-skin.css +73 -34
- package/dist/dev/define/audio/neutral-skin2.js +1 -1
- package/dist/dev/define/audio/neutral-skin2.js.map +1 -1
- package/dist/dev/define/audio/scaffold-skin.css +166 -42
- package/dist/dev/define/audio/scaffold-skin2.js +1 -1
- package/dist/dev/define/audio/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/audio/skin.css +72 -34
- package/dist/dev/define/audio/skin2.js +1 -1
- package/dist/dev/define/audio/skin2.js.map +1 -1
- package/dist/dev/define/extensions/google-analytics.d.ts +11 -0
- package/dist/dev/define/extensions/google-analytics.js +8 -0
- package/dist/dev/define/extensions/google-analytics.js.map +1 -0
- package/dist/dev/define/live-audio/compat-skin.css +143 -41
- package/dist/dev/define/live-audio/compat-skin2.js +1 -1
- package/dist/dev/define/live-audio/compat-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/neutral-skin.css +56 -31
- package/dist/dev/define/live-audio/neutral-skin2.js +1 -1
- package/dist/dev/define/live-audio/neutral-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/scaffold-skin.css +148 -42
- package/dist/dev/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/dev/define/live-audio/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/skin.css +55 -31
- package/dist/dev/define/live-audio/skin2.js +1 -1
- package/dist/dev/define/live-audio/skin2.js.map +1 -1
- package/dist/dev/define/live-video/compat-skin.css +234 -51
- package/dist/dev/define/live-video/compat-skin2.js +1 -1
- package/dist/dev/define/live-video/compat-skin2.js.map +1 -1
- package/dist/dev/define/live-video/neutral-skin.css +300 -46
- package/dist/dev/define/live-video/neutral-skin2.js +1 -1
- package/dist/dev/define/live-video/neutral-skin2.js.map +1 -1
- package/dist/dev/define/live-video/scaffold-skin.css +231 -53
- package/dist/dev/define/live-video/scaffold-skin2.js +1 -1
- package/dist/dev/define/live-video/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/live-video/skin.css +314 -49
- package/dist/dev/define/live-video/skin2.js +1 -1
- package/dist/dev/define/live-video/skin2.js.map +1 -1
- package/dist/dev/define/media/dailymotion-video.d.ts +15 -0
- package/dist/dev/define/media/dailymotion-video.js +13 -0
- package/dist/dev/define/media/dailymotion-video.js.map +1 -0
- package/dist/dev/define/media/mixcloud-audio.d.ts +15 -0
- package/dist/dev/define/media/mixcloud-audio.js +13 -0
- package/dist/dev/define/media/mixcloud-audio.js.map +1 -0
- package/dist/dev/define/media/soundcloud-audio.d.ts +15 -0
- package/dist/dev/define/media/soundcloud-audio.js +13 -0
- package/dist/dev/define/media/soundcloud-audio.js.map +1 -0
- package/dist/dev/define/ui/time-slider-markers.d.ts +8 -0
- package/dist/dev/define/ui/time-slider-markers.js +7 -0
- package/dist/dev/define/ui/time-slider-markers.js.map +1 -0
- package/dist/dev/define/video/compat-skin.css +242 -51
- package/dist/dev/define/video/compat-skin2.js +1 -1
- package/dist/dev/define/video/compat-skin2.js.map +1 -1
- package/dist/dev/define/video/neutral-skin.css +382 -57
- package/dist/dev/define/video/neutral-skin2.js +1 -1
- package/dist/dev/define/video/neutral-skin2.js.map +1 -1
- package/dist/dev/define/video/scaffold-skin.css +240 -53
- package/dist/dev/define/video/scaffold-skin2.js +1 -1
- package/dist/dev/define/video/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/video/skin.css +415 -55
- package/dist/dev/define/video/skin2.js +1 -1
- package/dist/dev/define/video/skin2.js.map +1 -1
- package/dist/dev/extensions/google-analytics/extension.d.ts +52 -0
- package/dist/dev/extensions/google-analytics/extension.js +77 -0
- package/dist/dev/extensions/google-analytics/extension.js.map +1 -0
- package/dist/dev/extensions/google-analytics/index.d.ts +2 -0
- package/dist/dev/extensions/mux-data/extension.d.ts +4 -1
- package/dist/dev/extensions/mux-data/extension.js +7 -2
- package/dist/dev/extensions/mux-data/extension.js.map +1 -1
- package/dist/dev/index.d.ts +5 -4
- package/dist/dev/index.js +3 -1
- package/dist/dev/internal/skins/compat-audio/skin.css +161 -41
- package/dist/dev/internal/skins/compat-audio/template.js +1 -1
- package/dist/dev/internal/skins/compat-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/compat-live-audio/skin.css +143 -41
- package/dist/dev/internal/skins/compat-live-video/skin.css +234 -51
- package/dist/dev/internal/skins/compat-live-video/template.js +2 -0
- package/dist/dev/internal/skins/compat-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/compat-video/skin.css +242 -51
- package/dist/dev/internal/skins/compat-video/template.js +2 -0
- package/dist/dev/internal/skins/compat-video/template.js.map +1 -1
- package/dist/dev/internal/skins/default-audio/skin.css +72 -34
- package/dist/dev/internal/skins/default-live-audio/skin.css +55 -31
- package/dist/dev/internal/skins/default-live-video/register.js.map +1 -1
- package/dist/dev/internal/skins/default-live-video/skin.css +314 -49
- package/dist/dev/internal/skins/default-live-video/template.js +14 -0
- package/dist/dev/internal/skins/default-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/default-video/register.d.ts +1 -0
- package/dist/dev/internal/skins/default-video/register.js +3 -0
- package/dist/dev/internal/skins/default-video/register.js.map +1 -1
- package/dist/dev/internal/skins/default-video/skin.css +415 -55
- package/dist/dev/internal/skins/default-video/template.js +33 -5
- package/dist/dev/internal/skins/default-video/template.js.map +1 -1
- package/dist/dev/internal/skins/neutral-audio/skin.css +73 -34
- package/dist/dev/internal/skins/neutral-live-audio/skin.css +56 -31
- package/dist/dev/internal/skins/neutral-live-video/register.js.map +1 -1
- package/dist/dev/internal/skins/neutral-live-video/skin.css +300 -46
- package/dist/dev/internal/skins/neutral-live-video/template.js +14 -0
- package/dist/dev/internal/skins/neutral-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/neutral-video/register.js.map +1 -1
- package/dist/dev/internal/skins/neutral-video/skin.css +382 -57
- package/dist/dev/internal/skins/neutral-video/template.js +25 -11
- package/dist/dev/internal/skins/neutral-video/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-audio/skin.css +166 -42
- package/dist/dev/internal/skins/scaffold-audio/template.js +1 -1
- package/dist/dev/internal/skins/scaffold-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-live-audio/skin.css +148 -42
- package/dist/dev/internal/skins/scaffold-live-video/skin.css +231 -53
- package/dist/dev/internal/skins/scaffold-live-video/template.js +2 -0
- package/dist/dev/internal/skins/scaffold-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-video/skin.css +240 -53
- package/dist/dev/internal/skins/scaffold-video/template.js +3 -1
- package/dist/dev/internal/skins/scaffold-video/template.js.map +1 -1
- package/dist/dev/media/background-video/adapter.d.ts +7 -13
- package/dist/dev/media/background-video/adapter.js +13 -35
- package/dist/dev/media/background-video/adapter.js.map +1 -1
- package/dist/dev/media/background-video/base.d.ts +44 -0
- package/dist/dev/media/background-video/base.js +97 -0
- package/dist/dev/media/background-video/base.js.map +1 -0
- package/dist/dev/media/background-video/template.d.ts +3 -0
- package/dist/dev/media/background-video/template.js +13 -20
- package/dist/dev/media/background-video/template.js.map +1 -1
- package/dist/dev/media/dailymotion-video/adapter.d.ts +17 -0
- package/dist/dev/media/dailymotion-video/adapter.js +47 -0
- package/dist/dev/media/dailymotion-video/adapter.js.map +1 -0
- package/dist/dev/media/dailymotion-video/index.d.ts +2 -0
- package/dist/dev/media/hls-background-video/adapter.d.ts +14 -19
- package/dist/dev/media/hls-background-video/adapter.js +23 -35
- package/dist/dev/media/hls-background-video/adapter.js.map +1 -1
- package/dist/dev/media/mixcloud-audio/adapter.d.ts +11 -0
- package/dist/dev/media/mixcloud-audio/adapter.js +52 -0
- package/dist/dev/media/mixcloud-audio/adapter.js.map +1 -0
- package/dist/dev/media/mixcloud-audio/index.d.ts +2 -0
- package/dist/dev/media/soundcloud-audio/adapter.d.ts +11 -0
- package/dist/dev/media/soundcloud-audio/adapter.js +53 -0
- package/dist/dev/media/soundcloud-audio/adapter.js.map +1 -0
- package/dist/dev/media/soundcloud-audio/index.d.ts +2 -0
- package/dist/dev/player/element.js +1 -5
- package/dist/dev/player/element.js.map +1 -1
- package/dist/dev/presets/background/skin.d.ts +2 -1
- package/dist/dev/presets/background/skin.js +2 -2
- package/dist/dev/presets/background/skin.js.map +1 -1
- package/dist/dev/presets/skin.d.ts +4 -3
- package/dist/dev/presets/skin.js +4 -3
- package/dist/dev/presets/skin.js.map +1 -1
- package/dist/dev/ui/captions-button/element.d.ts +2 -0
- package/dist/dev/ui/captions-radio-group/element.d.ts +2 -1
- package/dist/dev/ui/captions-radio-group/element.js +14 -1
- package/dist/dev/ui/captions-radio-group/element.js.map +1 -1
- package/dist/dev/ui/controls/element.d.ts +2 -2
- package/dist/dev/ui/controls/element.js +6 -3
- package/dist/dev/ui/controls/element.js.map +1 -1
- package/dist/dev/ui/dialog/element.js +13 -1
- package/dist/dev/ui/dialog/element.js.map +1 -1
- package/dist/dev/ui/gesture/element.js +3 -0
- package/dist/dev/ui/gesture/element.js.map +1 -1
- package/dist/dev/ui/media-button-element.d.ts +9 -0
- package/dist/dev/ui/media-button-element.js +10 -1
- package/dist/dev/ui/media-button-element.js.map +1 -1
- package/dist/dev/ui/play-button/element.d.ts +2 -0
- package/dist/dev/ui/playback-rate-button/element.d.ts +9 -1
- package/dist/dev/ui/playback-rate-button/element.js +7 -2
- package/dist/dev/ui/playback-rate-button/element.js.map +1 -1
- package/dist/dev/ui/playback-rate-radio-group/element.d.ts +4 -0
- package/dist/dev/ui/playback-rate-radio-group/element.js +10 -3
- package/dist/dev/ui/playback-rate-radio-group/element.js.map +1 -1
- package/dist/dev/ui/radio-options/controller.js +18 -5
- package/dist/dev/ui/radio-options/controller.js.map +1 -1
- package/dist/dev/ui/time-slider/markers.d.ts +48 -0
- package/dist/dev/ui/time-slider/markers.js +165 -0
- package/dist/dev/ui/time-slider/markers.js.map +1 -0
- package/dist/dev/version.js +1 -1
- package/docs/README.md +1 -1
- package/docs/guides/autoplay.md +2 -2
- package/docs/guides/background-video.md +2 -4
- package/docs/guides/browser-support.md +23 -15
- package/docs/guides/build-your-own-skin.md +3 -1
- package/docs/guides/cdn.md +10 -9
- package/docs/guides/content-security-policy.md +3 -0
- package/docs/guides/customize-skins.md +7 -2
- package/docs/guides/features.md +1 -1
- package/docs/guides/google-analytics.md +199 -0
- package/docs/guides/installation-cdn.md +4 -4
- package/docs/guides/installation-shadcn.md +3 -3
- package/docs/guides/installation-svelte.md +4 -4
- package/docs/guides/installation-vue.md +4 -4
- package/docs/guides/installation.md +4 -4
- package/docs/guides/internationalization.md +5 -5
- package/docs/guides/keyboard-shortcuts.md +11 -1
- package/docs/guides/llms.txt +3 -1
- package/docs/guides/media-sources.md +3 -0
- package/docs/guides/migrate-from-media-chrome.md +4 -4
- package/docs/guides/migrate-from-mux-player.md +9 -9
- package/docs/guides/migrate-from-plyr.md +8 -8
- package/docs/guides/migrate-from-video-js-8.md +8 -9
- package/docs/guides/migrate-from-vidstack.md +10 -10
- package/docs/guides/mux-data.md +22 -0
- package/docs/guides/presets.md +5 -5
- package/docs/guides/self-hosting.md +5 -5
- package/docs/guides/skins.md +21 -5
- package/docs/guides/timed-metadata.md +318 -0
- package/docs/guides/ui-components.md +1 -1
- package/docs/llms.txt +25 -6
- package/docs/reference/api/chapters-track.md +71 -0
- package/docs/reference/api/define-text-track.md +113 -0
- package/docs/reference/api/feature-playback-rate.md +54 -3
- package/docs/reference/api/feature-playback.md +5 -1
- package/docs/reference/api/feature-text-cues.md +133 -0
- package/docs/reference/api/feature-text-tracks.md +11 -5
- package/docs/reference/api/get-active-text-cues.md +69 -0
- package/docs/reference/api/get-text-cues.md +69 -0
- package/docs/reference/api/get-text-tracks.md +41 -0
- package/docs/reference/api/hls-metadata-track.md +48 -0
- package/docs/reference/api/html-create-player.md +2 -2
- package/docs/reference/api/llms.txt +13 -1
- package/docs/reference/api/media-capabilities.md +4 -4
- package/docs/reference/api/player-store.md +15 -7
- package/docs/reference/api/preset-audio.md +15 -5
- package/docs/reference/api/preset-background.md +2 -2
- package/docs/reference/api/preset-live-audio.md +15 -5
- package/docs/reference/api/preset-live-video.md +14 -5
- package/docs/reference/api/preset-video.md +14 -5
- package/docs/reference/api/resolve-adapter-type.md +4 -1
- package/docs/reference/api/ui-element.md +2 -2
- package/docs/reference/components/alert-dialog.md +21 -16
- package/docs/reference/components/audio-compat-skin.md +8 -2
- package/docs/reference/components/audio-neutral-skin.md +2 -2
- package/docs/reference/components/audio-scaffold-skin.md +2 -2
- package/docs/reference/components/audio-skin.md +2 -2
- package/docs/reference/components/audio-track-radio-group.md +2 -2
- package/docs/reference/components/audio.md +19 -1
- package/docs/reference/components/background-video-skin.md +1 -1
- package/docs/reference/components/background-video.md +26 -11
- package/docs/reference/components/buffering-indicator.md +2 -2
- package/docs/reference/components/captions-radio-group.md +3 -3
- package/docs/reference/components/cloudflare-video.md +1 -1
- package/docs/reference/components/controls.md +16 -3
- package/docs/reference/components/dailymotion-video.md +192 -0
- package/docs/reference/components/dash-video.md +20 -2
- package/docs/reference/components/dialog.md +49 -22
- package/docs/reference/components/error-dialog.md +13 -10
- package/docs/reference/components/gesture.md +2 -2
- package/docs/reference/components/google-analytics.md +51 -0
- package/docs/reference/components/google-cast.md +1 -1
- package/docs/reference/components/hls-audio.md +56 -2
- package/docs/reference/components/hls-background-video.md +25 -5
- package/docs/reference/components/hls-video.md +99 -7
- package/docs/reference/components/hlsjs-video.md +53 -12
- package/docs/reference/components/hotkey.md +2 -2
- package/docs/reference/components/live-audio-compat-skin.md +8 -2
- package/docs/reference/components/live-audio-neutral-skin.md +2 -2
- package/docs/reference/components/live-audio-scaffold-skin.md +2 -2
- package/docs/reference/components/live-audio-skin.md +2 -2
- package/docs/reference/components/live-video-compat-skin.md +12 -2
- package/docs/reference/components/live-video-neutral-skin.md +6 -2
- package/docs/reference/components/live-video-scaffold-skin.md +6 -2
- package/docs/reference/components/live-video-skin.md +6 -2
- package/docs/reference/components/llms.txt +10 -5
- package/docs/reference/components/mixcloud-audio.md +203 -0
- package/docs/reference/components/mux-audio.md +35 -2
- package/docs/reference/components/mux-background-video.md +1 -1
- package/docs/reference/components/mux-data.md +20 -2
- package/docs/reference/components/mux-video.md +18 -2
- package/docs/reference/components/native-hls-video.md +32 -2
- package/docs/reference/components/play-button.md +7 -5
- package/docs/reference/components/playback-rate-button.md +26 -7
- package/docs/reference/components/playback-rate-radio-group.md +7 -4
- package/docs/reference/components/player.md +3 -3
- package/docs/reference/components/playerjs-video.md +2 -2
- package/docs/reference/components/quality-radio-group.md +2 -2
- package/docs/reference/components/shaka-video.md +2 -2
- package/docs/reference/components/soundcloud-audio.md +227 -0
- package/docs/reference/components/spotify-audio.md +3 -3
- package/docs/reference/components/tiktok-video.md +3 -3
- package/docs/reference/components/time-slider-markers.md +194 -0
- package/docs/reference/components/time-slider.md +14 -0
- package/docs/reference/components/twitch-video.md +2 -3
- package/docs/reference/components/video-compat-skin.md +12 -2
- package/docs/reference/components/video-neutral-skin.md +6 -2
- package/docs/reference/components/video-scaffold-skin.md +6 -2
- package/docs/reference/components/video-skin.md +6 -2
- package/docs/reference/components/video.md +19 -1
- package/docs/reference/components/vimeo-video.md +1 -1
- package/docs/reference/components/wistia-video.md +1 -1
- package/docs/reference/components/youtube-video.md +1 -1
- package/package.json +60 -40
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Sync content with timed metadata
|
|
2
|
+
|
|
3
|
+
Show quizzes, product cards, ad markers, chapters, and transcripts in time with playback, from cues in the media or cues your app adds.
|
|
4
|
+
|
|
5
|
+
Timed metadata is data tied to a span of playback: a quiz question, a product card, an ad break, or a chapter. Video.js reads it as text tracks and cues, the platform objects captions use, whether the cues come from the media or from your app.
|
|
6
|
+
|
|
7
|
+
## Recommended approach
|
|
8
|
+
|
|
9
|
+
Define the track with `defineTextTrack()`, add your cues to the player with `player.store.addTextTrack()`, and render the cue `getActiveTextCues()` returns each time the store changes.
|
|
10
|
+
|
|
11
|
+
**index.html**
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<video-player class="html-timed-metadata-basic">
|
|
15
|
+
<media-container class="html-timed-metadata-basic__container">
|
|
16
|
+
<video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoplay muted playsinline loop></video>
|
|
17
|
+
<p class="html-timed-metadata-basic__note">
|
|
18
|
+
<strong class="html-timed-metadata-basic__title"></strong>
|
|
19
|
+
<span class="html-timed-metadata-basic__body"></span>
|
|
20
|
+
</p>
|
|
21
|
+
</media-container>
|
|
22
|
+
</video-player>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**index.css**
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
.html-timed-metadata-basic__container {
|
|
29
|
+
position: relative;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.html-timed-metadata-basic__container video {
|
|
33
|
+
width: 100%;
|
|
34
|
+
aspect-ratio: 16 / 9;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.html-timed-metadata-basic__note {
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 12px;
|
|
40
|
+
left: 12px;
|
|
41
|
+
max-width: calc(100% - 24px);
|
|
42
|
+
padding: 10px 14px;
|
|
43
|
+
margin: 0;
|
|
44
|
+
font-size: 0.875rem;
|
|
45
|
+
line-height: 1.4;
|
|
46
|
+
color: black;
|
|
47
|
+
background: rgba(255, 255, 255, 0.85);
|
|
48
|
+
border-radius: 12px;
|
|
49
|
+
backdrop-filter: blur(10px);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.html-timed-metadata-basic__note:not([data-active]) {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.html-timed-metadata-basic__title {
|
|
57
|
+
display: block;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**index.ts**
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import '@videojs/html/video/player';
|
|
65
|
+
import '@videojs/html/ui/container';
|
|
66
|
+
import { defineTextTrack, getActiveTextCues } from '@videojs/html';
|
|
67
|
+
|
|
68
|
+
interface Note {
|
|
69
|
+
title: string;
|
|
70
|
+
body: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const notesTrack = defineTextTrack<Note>({ kind: 'metadata', label: 'notes' });
|
|
74
|
+
|
|
75
|
+
const player = document.querySelector('video-player');
|
|
76
|
+
const note = document.querySelector<HTMLElement>('.html-timed-metadata-basic__note');
|
|
77
|
+
const title = note?.querySelector('.html-timed-metadata-basic__title');
|
|
78
|
+
const body = note?.querySelector('.html-timed-metadata-basic__body');
|
|
79
|
+
|
|
80
|
+
if (player && note && title && body) {
|
|
81
|
+
player.store.addTextTrack(notesTrack, {
|
|
82
|
+
cues: [
|
|
83
|
+
{ startTime: 1, endTime: 8, value: { title: 'Timed metadata', body: 'This note is a cue the app added.' } },
|
|
84
|
+
{ startTime: 12, endTime: 19, value: { title: 'Any data', body: 'Each cue carries a value you render.' } },
|
|
85
|
+
{ startTime: 23, endTime: 30, value: { title: 'Any media', body: 'The player holds the track, not the video.' } },
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
player.store.subscribe(() => {
|
|
90
|
+
const [cue] = getActiveTextCues(player.store, notesTrack);
|
|
91
|
+
|
|
92
|
+
note.toggleAttribute('data-active', Boolean(cue?.value));
|
|
93
|
+
title.textContent = cue?.value?.title ?? '';
|
|
94
|
+
body.textContent = cue?.value?.body ?? '';
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
In your app, the cues usually come from your API or CMS. Fetch them and pass them as `cues`, or pass the file’s URL as `src` and the player loads it.
|
|
100
|
+
|
|
101
|
+
## How it works
|
|
102
|
+
|
|
103
|
+
A text track has a `kind`, `label`, and `language`, and a list of cues. Each cue spans `startTime` to `endTime`, in seconds, and carries `text`, structured data in `value`, or both. `value` and `type` are named after the platform’s `DataCue`. A cue without an `endTime` is a point, active for one second, except in a chapters track your app adds, where it runs to the next chapter.
|
|
104
|
+
|
|
105
|
+
`addTextTrack()` adds the track to the player, not the media, so it works with any media, including YouTube and other embeds. The track sits next to the media’s tracks in `textTrackList` with `source: 'app'`.
|
|
106
|
+
|
|
107
|
+
The [text cues feature](../reference/api/feature-text-cues.md), included in the video, audio, and live presets, reads cues from the media’s `metadata` and `chapters` tracks and from the tracks your app adds, and tracks which cues are active at the current time. Tracks from either place are read the same way.
|
|
108
|
+
|
|
109
|
+
`defineTextTrack<Note>()` types each cue’s `value`, and works as a filter: reading through it picks the tracks with the same kind, label, and language. A plain filter, such as `{ label: 'notes' }`, works too, but its cues’ `value` is `unknown`.
|
|
110
|
+
|
|
111
|
+
`player.store.subscribe()` calls back whenever player state changes, and `getActiveTextCues()` returns the cues active at that moment.
|
|
112
|
+
|
|
113
|
+
Browsers never draw metadata or chapters cues, so the overlay, its styles, and its accessibility are up to your UI.
|
|
114
|
+
|
|
115
|
+
## Availability and constraints
|
|
116
|
+
|
|
117
|
+
- Active cues follow `currentTime`, which updates up to about four times a second. Don’t rely on them for frame-accurate timing. A cue that playback passes between two updates still shows up as active once; a cue a seek jumps over doesn’t.
|
|
118
|
+
- `cues` are plain, JSON-serializable data, so a server-rendered page can pass them in. A `src` is fetched only once the player runs on the client, and a cross-origin file needs CORS headers.
|
|
119
|
+
- Browsers load a `<track>` element’s cues only while the track is `showing` or `hidden`. `default` makes a `<track kind="metadata">` `hidden`; without it, the track stays `disabled` and its cues never load.
|
|
120
|
+
- `value` isn’t checked at runtime unless the definition has a schema. See [Check values with a schema](#check-values-with-a-schema).
|
|
121
|
+
|
|
122
|
+
Like a `<track>` element, an app track stays through source changes until you remove it. When you play a different video, remove its tracks and add the new video’s.
|
|
123
|
+
|
|
124
|
+
## Common variations
|
|
125
|
+
|
|
126
|
+
The examples below assume `player` is the `<video-player>` element, as in the recommended approach, and that the elements they update, such as `adBadge`, are queried from your page.
|
|
127
|
+
|
|
128
|
+
### Read cues from a WebVTT file
|
|
129
|
+
|
|
130
|
+
Add a `<track kind="metadata">` to the media. Cue text that parses as a JSON object or array becomes the cue’s `value`; any other text stays in `text`.
|
|
131
|
+
|
|
132
|
+
**notes.vtt**
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
WEBVTT
|
|
136
|
+
|
|
137
|
+
00:00:01.000 --> 00:00:08.000
|
|
138
|
+
{ "title": "Timed metadata", "body": "This note came from a WebVTT file." }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<video src="video.mp4" playsinline>
|
|
143
|
+
<track kind="metadata" label="notes" src="/notes.vtt" default />
|
|
144
|
+
</video>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
A definition with the same kind and label reads it, so the rendering code from the recommended approach works unchanged. To use the file with media that has no `<track>` support, such as an embed, pass it as `src` when you add the track instead.
|
|
148
|
+
|
|
149
|
+
### Read metadata from an HLS stream
|
|
150
|
+
|
|
151
|
+
When hls.js plays a stream, in [`HlsJsVideo`](../reference/components/hlsjs-video.md) and media built on it such as [`MuxVideo`](../reference/components/mux-video.md), it publishes ID3 frames and `EXT-X-DATERANGE` tags as cues on a metadata track. Read them with [`hlsMetadataTrack`](../reference/api/hls-metadata-track.md). Each cue’s `type` tells an ID3 frame from a date range attribute, and narrows its `value`.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { getActiveTextCues, hlsMetadataTrack } from '@videojs/html';
|
|
155
|
+
|
|
156
|
+
player.store.subscribe(() => {
|
|
157
|
+
const cues = getActiveTextCues(player.store, hlsMetadataTrack);
|
|
158
|
+
const inAd = cues.some((cue) => cue.type === 'com.apple.quicktime.HLS' && cue.value?.key === 'X-AD-ID');
|
|
159
|
+
|
|
160
|
+
adBadge.hidden = !inAd;
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Where the browser plays HLS natively, as Safari does, in-band metadata arrives as `DataCue`s on the browser’s own metadata tracks. Read those with a `{ kind: 'metadata' }` filter.
|
|
165
|
+
|
|
166
|
+
### Mark cues on the time slider
|
|
167
|
+
|
|
168
|
+
Add `<media-time-slider-markers>` to the time slider to draw a marker for each cue on the tracks its attributes match, such as the notes from the recommended approach.
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<media-time-slider>
|
|
172
|
+
<media-slider-track>
|
|
173
|
+
<media-slider-fill></media-slider-fill>
|
|
174
|
+
</media-slider-track>
|
|
175
|
+
<media-time-slider-markers kind="metadata" label="notes"></media-time-slider-markers>
|
|
176
|
+
<media-slider-thumb></media-slider-thumb>
|
|
177
|
+
</media-time-slider>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
A point is a marker with no width, a range spans its cue, and a marker has `data-active` while its cue is active. Markers are unstyled: position each one with its `--media-slider-marker-*` custom properties. See [the markers reference](../reference/components/time-slider-markers.md) for the full styling contract.
|
|
181
|
+
|
|
182
|
+
### Check values with a schema
|
|
183
|
+
|
|
184
|
+
Cues from a file or a stream can carry anything. Pass a `schema` to `defineTextTrack()` to check each value where it’s read. Any [Standard Schema](https://standardschema.dev) works, such as one from zod or valibot, and the value type comes from the schema.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { z } from 'zod';
|
|
188
|
+
|
|
189
|
+
const NoteSchema = z.object({ title: z.string(), body: z.string() });
|
|
190
|
+
|
|
191
|
+
const notesTrack = defineTextTrack({ kind: 'metadata', label: 'notes', schema: NoteSchema });
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Readers skip cues whose value fails the schema, and warn in development. The schema must be synchronous.
|
|
195
|
+
|
|
196
|
+
### Add chapters
|
|
197
|
+
|
|
198
|
+
Add a `chapters` track the same way. A chapter’s title is its cue `text`, and a chapter without an `endTime` runs to the next one. When the media has no chapters track of its own, the [time slider](../reference/components/time-slider.md) shows these chapters.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
player.store.addTextTrack({
|
|
202
|
+
kind: 'chapters',
|
|
203
|
+
cues: [
|
|
204
|
+
{ startTime: 0, text: 'Introduction' },
|
|
205
|
+
{ startTime: 95, text: 'Setup' },
|
|
206
|
+
{ startTime: 410, text: 'Wrap-up' },
|
|
207
|
+
],
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
To load a Podcasting 2.0, Apple HLS, or JSON-LD chapters file, pass its converter as `format`, such as `podcastChapters`. Read the current chapter, with any artwork the file gives it, through [`chaptersTrack`](../reference/api/chapters-track.md).
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { chaptersTrack, getActiveTextCues, podcastChapters } from '@videojs/html';
|
|
215
|
+
|
|
216
|
+
player.store.addTextTrack({ kind: 'chapters', src: '/episodes/42/chapters.json', format: podcastChapters });
|
|
217
|
+
|
|
218
|
+
player.store.subscribe(() => {
|
|
219
|
+
const [chapter] = getActiveTextCues(player.store, chaptersTrack);
|
|
220
|
+
currentChapter.textContent = chapter?.text ?? '';
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Show an interactive transcript
|
|
225
|
+
|
|
226
|
+
A transcript reads captions cues, which the text cues feature skips unless something asks for them.
|
|
227
|
+
|
|
228
|
+
Call `watchTextCues()` to read them, then render with `getTextCues()` and `getActiveTextCues()`.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
import { getActiveTextCues, getTextCues } from '@videojs/html';
|
|
232
|
+
|
|
233
|
+
const captions = { kind: 'captions', language: 'en' } as const;
|
|
234
|
+
// A cue that hasn't changed stays the same object, so it keeps its line.
|
|
235
|
+
const lines = new WeakMap<object, HTMLLIElement>();
|
|
236
|
+
|
|
237
|
+
player.store.watchTextCues(captions);
|
|
238
|
+
|
|
239
|
+
player.store.subscribe(() => {
|
|
240
|
+
const [active] = getActiveTextCues(player.store, captions);
|
|
241
|
+
const next = getTextCues(player.store, captions).map((cue) => {
|
|
242
|
+
let line = lines.get(cue);
|
|
243
|
+
|
|
244
|
+
if (!line) {
|
|
245
|
+
const button = document.createElement('button');
|
|
246
|
+
|
|
247
|
+
button.type = 'button';
|
|
248
|
+
button.textContent = cue.text;
|
|
249
|
+
button.addEventListener('click', () => player.store.seek(cue.startTime));
|
|
250
|
+
|
|
251
|
+
line = document.createElement('li');
|
|
252
|
+
line.append(button);
|
|
253
|
+
lines.set(cue, line);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (cue.id === active?.id) line.setAttribute('aria-current', 'true');
|
|
257
|
+
else line.removeAttribute('aria-current');
|
|
258
|
+
|
|
259
|
+
return line;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Replace the lines only when they change, so a focused button keeps focus.
|
|
263
|
+
const current = [...transcript.children];
|
|
264
|
+
|
|
265
|
+
if (next.length !== current.length || next.some((line, index) => line !== current[index])) {
|
|
266
|
+
transcript.replaceChildren(...next);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The browser loads a `<track>` element’s cues only while captions are on. To show the transcript either way, add the captions track from your app instead of a `<track>` element. The player copies it into the media, so the browser still draws the captions when a viewer turns them on.
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
player.store.addTextTrack({ kind: 'captions', label: 'English', language: 'en', src: '/captions.vtt' });
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Troubleshooting
|
|
278
|
+
|
|
279
|
+
### No cue is ever active
|
|
280
|
+
|
|
281
|
+
Confirm that:
|
|
282
|
+
|
|
283
|
+
- The track is one the text cues feature reads: a `metadata` or `chapters` track that isn’t `disabled`. Give a `<track kind="metadata">` the `default` attribute. For other kinds, read through the hooks or call `watchTextCues()`.
|
|
284
|
+
- Your filter or definition matches the track’s `kind`, `label`, and `language` exactly. `getTextTracks()` lists the tracks the player has.
|
|
285
|
+
- Cue times are in seconds.
|
|
286
|
+
|
|
287
|
+
### A cue’s value is undefined
|
|
288
|
+
|
|
289
|
+
Only `metadata` cue text that parses as a JSON object or array becomes `value`; other text stays in `text`. With a schema, cues whose value fails it are skipped, with a warning in development.
|
|
290
|
+
|
|
291
|
+
### An app track outlives its video
|
|
292
|
+
|
|
293
|
+
App tracks stay until they’re removed, through source changes. Call the handle’s `remove()`, or the store’s `removeTextTrack()`, before adding the next video’s tracks.
|
|
294
|
+
|
|
295
|
+
### Cues from a src never load
|
|
296
|
+
|
|
297
|
+
The file failed to load, often because of a missing CORS header or a wrong URL. The track keeps any cues it already had, and a warning shows in development.
|
|
298
|
+
|
|
299
|
+
## Related pages
|
|
300
|
+
|
|
301
|
+
### Components
|
|
302
|
+
|
|
303
|
+
- [media-time-slider](../reference/components/time-slider.md): A slider component for seeking through media playback time
|
|
304
|
+
- [media-time-slider-markers](../reference/components/time-slider-markers.md): Draws a marker on the time slider for each cue on the text tracks a filter matches, such as ad breaks
|
|
305
|
+
|
|
306
|
+
### API
|
|
307
|
+
|
|
308
|
+
- [Text cues](../reference/api/feature-text-cues.md): Cues and active cues from metadata, chapters, and app text tracks
|
|
309
|
+
- [defineTextTrack](../reference/api/define-text-track.md): Define a text track once, with the type of its cue values, to add and read it with
|
|
310
|
+
- [getActiveTextCues](../reference/api/get-active-text-cues.md): The cues active now on the text tracks a filter or track definition matches
|
|
311
|
+
- [getTextCues](../reference/api/get-text-cues.md): Every cue on the text tracks a filter or track definition matches
|
|
312
|
+
- [chaptersTrack](../reference/api/chapters-track.md): A track definition for chapters, and converters that turn chapter JSON formats into cues
|
|
313
|
+
- [hlsMetadataTrack](../reference/api/hls-metadata-track.md): A track definition for the ID3 and EXT-X-DATERANGE metadata hls.js publishes
|
|
314
|
+
|
|
315
|
+
### Guides
|
|
316
|
+
|
|
317
|
+
- [Show captions and subtitles](./captions.md): Show captions and subtitles, and let users turn them on and pick a language.
|
|
318
|
+
- [Media sources](./media-sources.md): Set what a media component plays and how its engine plays it with the structured source property
|
|
@@ -39,7 +39,7 @@ import '@videojs/html/icons/element';
|
|
|
39
39
|
|
|
40
40
|
### Style components with state
|
|
41
41
|
|
|
42
|
-
Components add `data-*` attributes to describe their current state. For example, a play button adds `data-paused` while the media is paused. Use those attributes in CSS:
|
|
42
|
+
Components add `data-*` attributes to describe their current state. For example, a play button adds `data-paused` while the media is paused, except while autoplay is pending, when the button shows pause. Use those attributes in CSS:
|
|
43
43
|
|
|
44
44
|
```css
|
|
45
45
|
.my-play-button .pause-icon {
|
package/docs/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Video.js v10 — HTML Documentation
|
|
2
2
|
|
|
3
|
-
> Bundled with `@videojs/html` v10.
|
|
3
|
+
> Bundled with `@videojs/html` v10.4.0. Links are relative paths to files in this directory.
|
|
4
4
|
|
|
5
5
|
> Install the [Video.js skill](https://github.com/videojs/skills) to help AI coding agents find version-matched pages from this index.
|
|
6
6
|
|
|
@@ -71,6 +71,7 @@ Guides for one player capability each: the recommended setup, how it works, brow
|
|
|
71
71
|
- [Automatically show and hide controls](./guides/controls.md): Show controls while the user is active, hide them during playback, and toggle them by touch.
|
|
72
72
|
- [Add a poster and loading placeholder](./guides/poster.md): Set the image shown before playback, then add a lightweight placeholder while it loads
|
|
73
73
|
- [Show captions and subtitles](./guides/captions.md): Show captions and subtitles, and let users turn them on and pick a language.
|
|
74
|
+
- [Sync content with timed metadata](./guides/timed-metadata.md): Show quizzes, product cards, ad markers, chapters, and transcripts in time with playback, from cues in the media or cues your app adds.
|
|
74
75
|
- [Add keyboard shortcuts and gestures](./guides/keyboard-shortcuts.md): Add keyboard shortcuts, tap and double-tap gestures, and on-screen feedback for input actions.
|
|
75
76
|
- [Play live streams](./guides/live-streams.md): Play live streams with live-edge tracking, DVR windows, and stream-type detection.
|
|
76
77
|
- [Add a quality selector](./guides/quality.md): Read available renditions, let the engine adapt automatically, and offer manual quality selection.
|
|
@@ -82,6 +83,7 @@ Guides for one player capability each: the recommended setup, how it works, brow
|
|
|
82
83
|
- [Remember user preferences](./guides/user-preferences.md): Save volume and caption preferences, restore them after loading, and adapt the pattern for quality selection.
|
|
83
84
|
- [Add a background video](./guides/background-video.md): Add an accessible background video from an MP4, WebM, HLS, or Mux source
|
|
84
85
|
- [Internationalize the player](./guides/internationalization.md): Translate player labels and announcements: shipped locale packs, custom translations, runtime switching, and server rendering.
|
|
86
|
+
- [Track video telemetry with Google Analytics 4](./guides/google-analytics.md): Track video engagement, progress milestones, and playback interactions by adding the Google Analytics extension to a player
|
|
85
87
|
- [Monitor playback with Mux Data](./guides/mux-data.md): Measure startup time, rebuffering, failures, and watch time by adding the Mux Data extension to a player
|
|
86
88
|
|
|
87
89
|
### Migrate
|
|
@@ -115,19 +117,19 @@ API reference for the packaged skins each preset ships.
|
|
|
115
117
|
|
|
116
118
|
- [video-skin](./reference/components/video-skin.md): The video preset's default skin with the modern, frosted look
|
|
117
119
|
- [video-neutral-skin](./reference/components/video-neutral-skin.md): The video preset's visually lighter skin, closer to a classic control bar
|
|
118
|
-
- [video-compat-skin](./reference/components/video-compat-skin.md):
|
|
120
|
+
- [video-compat-skin](./reference/components/video-compat-skin.md): The video preset's plain, unbranded skin, a polished step above native controls
|
|
119
121
|
- [video-scaffold-skin](./reference/components/video-scaffold-skin.md): A video skin with minimal styling for custom skins
|
|
120
122
|
- [audio-skin](./reference/components/audio-skin.md): The audio preset's default skin with the modern, frosted look
|
|
121
123
|
- [audio-neutral-skin](./reference/components/audio-neutral-skin.md): The audio preset's visually lighter skin, closer to a classic control bar
|
|
122
|
-
- [audio-compat-skin](./reference/components/audio-compat-skin.md):
|
|
124
|
+
- [audio-compat-skin](./reference/components/audio-compat-skin.md): The audio preset's plain, unbranded skin, a polished step above native controls
|
|
123
125
|
- [audio-scaffold-skin](./reference/components/audio-scaffold-skin.md): An audio skin with minimal styling for custom skins
|
|
124
126
|
- [live-video-skin](./reference/components/live-video-skin.md): The live video preset's default skin, which swaps time controls for a Live button
|
|
125
127
|
- [live-video-neutral-skin](./reference/components/live-video-neutral-skin.md): The live video preset's visually lighter skin, closer to a classic control bar
|
|
126
|
-
- [live-video-compat-skin](./reference/components/live-video-compat-skin.md):
|
|
128
|
+
- [live-video-compat-skin](./reference/components/live-video-compat-skin.md): The live video preset's plain, unbranded skin, a polished step above native controls
|
|
127
129
|
- [live-video-scaffold-skin](./reference/components/live-video-scaffold-skin.md): A live video skin with minimal styling for custom skins
|
|
128
130
|
- [live-audio-skin](./reference/components/live-audio-skin.md): The live audio preset's default skin, which swaps time controls for a Live button
|
|
129
131
|
- [live-audio-neutral-skin](./reference/components/live-audio-neutral-skin.md): The live audio preset's visually lighter skin, closer to a classic control bar
|
|
130
|
-
- [live-audio-compat-skin](./reference/components/live-audio-compat-skin.md):
|
|
132
|
+
- [live-audio-compat-skin](./reference/components/live-audio-compat-skin.md): The live audio preset's plain, unbranded skin, a polished step above native controls
|
|
131
133
|
- [live-audio-scaffold-skin](./reference/components/live-audio-scaffold-skin.md): A live audio skin with minimal styling for custom skins
|
|
132
134
|
- [background-video-skin](./reference/components/background-video-skin.md): The background preset's chrome-less skin for ambient video
|
|
133
135
|
|
|
@@ -138,17 +140,20 @@ API reference for media components that handle streaming protocols and playback.
|
|
|
138
140
|
- [audio](./reference/components/audio.md): Native audio playback that can provide media to a Video.js player
|
|
139
141
|
- [background-video](./reference/components/background-video.md): Decorative background video element with automatic muting and looping
|
|
140
142
|
- [cloudflare-video](./reference/components/cloudflare-video.md): Video component that plays Cloudflare Stream videos through the Stream player
|
|
143
|
+
- [dailymotion-video](./reference/components/dailymotion-video.md): Video component that plays Dailymotion videos through a Dailymotion player configuration
|
|
141
144
|
- [dash-video](./reference/components/dash-video.md): DASH video element powered by dash.js for adaptive bitrate streaming
|
|
142
145
|
- [hls-audio](./reference/components/hls-audio.md): Audio-only HLS element that plays the audio rendition of an HLS stream
|
|
143
146
|
- [hls-background-video](./reference/components/hls-background-video.md): HLS background video without controls, audio, captions, or adaptive quality
|
|
144
147
|
- [hls-video](./reference/components/hls-video.md): Lightweight HLS video element with minimal bundle size
|
|
145
148
|
- [hlsjs-video](./reference/components/hlsjs-video.md): HLS video element powered by hls.js for adaptive bitrate streaming
|
|
149
|
+
- [mixcloud-audio](./reference/components/mixcloud-audio.md): Audio component that plays Mixcloud shows through the Mixcloud Widget
|
|
146
150
|
- [mux-audio](./reference/components/mux-audio.md): Audio element for Mux-hosted HLS streams
|
|
147
151
|
- [mux-background-video](./reference/components/mux-background-video.md): Mux-specific name for the HLS background video component
|
|
148
152
|
- [mux-video](./reference/components/mux-video.md): Video element for Mux-hosted HLS streams
|
|
149
153
|
- [native-hls-video](./reference/components/native-hls-video.md): HLS video element using the browser's built-in HLS support
|
|
150
154
|
- [playerjs-video](./reference/components/playerjs-video.md): Video component that plays any embed implementing the player.js protocol, such as Mux Player, Gumlet, FrameRate, Livid, Bunny Stream, and Streamable
|
|
151
155
|
- [shaka-video](./reference/components/shaka-video.md): Video element powered by Shaka Player for DASH, HLS, and progressive playback with DRM
|
|
156
|
+
- [soundcloud-audio](./reference/components/soundcloud-audio.md): Audio component that plays SoundCloud tracks and sets through the SoundCloud Widget
|
|
152
157
|
- [spotify-audio](./reference/components/spotify-audio.md): Audio component that plays Spotify tracks, episodes, playlists, and shows through the Spotify embed
|
|
153
158
|
- [tiktok-video](./reference/components/tiktok-video.md): Video component that plays TikTok videos through the TikTok embed player
|
|
154
159
|
- [twitch-video](./reference/components/twitch-video.md): Video component that plays Twitch videos and live channels through the Twitch embed player
|
|
@@ -161,6 +166,7 @@ API reference for media components that handle streaming protocols and playback.
|
|
|
161
166
|
|
|
162
167
|
API reference for extensions that connect external services to the player.
|
|
163
168
|
|
|
169
|
+
- [google-analytics](./reference/components/google-analytics.md): Options for the Google Analytics 4 extension that tracks video engagement and playback events
|
|
164
170
|
- [google-cast](./reference/components/google-cast.md): Options for the Google Cast extension that configures the receiver and load request
|
|
165
171
|
- [mux-data](./reference/components/mux-data.md): Options for the Mux Data extension that monitors playback quality
|
|
166
172
|
|
|
@@ -185,6 +191,7 @@ API reference for the slider components that scrub time and adjust volume.
|
|
|
185
191
|
|
|
186
192
|
- [media-slider](./reference/components/slider.md): A composable slider component with track, fill, thumb, preview, and value parts
|
|
187
193
|
- [media-time-slider](./reference/components/time-slider.md): A slider component for seeking through media playback time
|
|
194
|
+
- [media-time-slider-markers](./reference/components/time-slider-markers.md): Draws a marker on the time slider for each cue on the text tracks a filter matches, such as ad breaks
|
|
188
195
|
- [media-volume-slider](./reference/components/volume-slider.md): A slider component for controlling media playback volume
|
|
189
196
|
|
|
190
197
|
### Menus
|
|
@@ -237,7 +244,7 @@ API reference for the icon sets the skins use, available for your own controls.
|
|
|
237
244
|
|
|
238
245
|
## API
|
|
239
246
|
|
|
240
|
-
API reference for the player factory, presets, store controllers, features, translation tools, and utilities.
|
|
247
|
+
API reference for the player factory, presets, store controllers, features, text tracks, translation tools, and utilities.
|
|
241
248
|
|
|
242
249
|
Section index: [reference/api/llms.txt](./reference/api/llms.txt).
|
|
243
250
|
|
|
@@ -289,10 +296,22 @@ API reference for the feature modules passed to createPlayer, which provide play
|
|
|
289
296
|
- [Remote Playback](./reference/api/feature-remote-playback.md): Remote playback state and actions for the player store
|
|
290
297
|
- [Source](./reference/api/feature-source.md): Media source state and actions for the player store
|
|
291
298
|
- [Stream type](./reference/api/feature-stream-type.md): Stream delivery type (live / on-demand) state for the player store
|
|
299
|
+
- [Text cues](./reference/api/feature-text-cues.md): Cues and active cues from metadata, chapters, and app text tracks
|
|
292
300
|
- [Text tracks](./reference/api/feature-text-tracks.md): Subtitles, captions, and chapter track state for the player store
|
|
293
301
|
- [Time](./reference/api/feature-time.md): Playback position and duration state for the player store
|
|
294
302
|
- [Volume](./reference/api/feature-volume.md): Volume level and mute state for the player store
|
|
295
303
|
|
|
304
|
+
### Text tracks
|
|
305
|
+
|
|
306
|
+
API reference for reading text tracks and their cues: track definitions and readers.
|
|
307
|
+
|
|
308
|
+
- [defineTextTrack](./reference/api/define-text-track.md): Define a text track once, with the type of its cue values, to add and read it with
|
|
309
|
+
- [getTextTracks](./reference/api/get-text-tracks.md): The text tracks a filter or track definition matches, from the media or the app
|
|
310
|
+
- [getTextCues](./reference/api/get-text-cues.md): Every cue on the text tracks a filter or track definition matches
|
|
311
|
+
- [getActiveTextCues](./reference/api/get-active-text-cues.md): The cues active now on the text tracks a filter or track definition matches
|
|
312
|
+
- [chaptersTrack](./reference/api/chapters-track.md): A track definition for chapters, and converters that turn chapter JSON formats into cues
|
|
313
|
+
- [hlsMetadataTrack](./reference/api/hls-metadata-track.md): A track definition for the ID3 and EXT-X-DATERANGE metadata hls.js publishes
|
|
314
|
+
|
|
296
315
|
### i18n
|
|
297
316
|
|
|
298
317
|
API reference for translating the player: the i18n elements, controller, and the phrase registry.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# chaptersTrack
|
|
2
|
+
|
|
3
|
+
A track definition for chapters, and converters that turn chapter JSON formats into cues
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { appleHlsChapters, chaptersTrack, jsonLdChapters, podcastChapters } from '@videojs/html';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`chaptersTrack` is a [track definition](./define-text-track.md) for `{ kind: 'chapters' }`. It has no `label`, so it matches every chapters track, from the media and the app alike. A chapter’s title is its cue’s `text`, and its `value` is typed as `ChapterCueValue`, which holds what chapter formats carry beyond a title.
|
|
12
|
+
|
|
13
|
+
WebVTT chapters carry only a title, so their cues have no `value`. Chapters converted from JSON with the functions below carry one.
|
|
14
|
+
|
|
15
|
+
| `ChapterCueValue` field | Description |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `description` | The chapter’s description. |
|
|
18
|
+
| `url` | A web page for the chapter. |
|
|
19
|
+
| `images` | Images for the chapter, such as artwork or a thumbnail. Each has a `url`, and optionally a `width` and `height` in pixels. |
|
|
20
|
+
| `titles` | The chapter’s titles by language, when the source has several. |
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
**current-chapter.ts**
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { chaptersTrack, getActiveTextCues } from '@videojs/html';
|
|
28
|
+
|
|
29
|
+
const player = document.querySelector('video-player')!;
|
|
30
|
+
const label = document.querySelector('.current-chapter')!;
|
|
31
|
+
|
|
32
|
+
player.store.subscribe(() => {
|
|
33
|
+
const [chapter] = getActiveTextCues(player.store, chaptersTrack);
|
|
34
|
+
label.textContent = chapter?.text ?? '';
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Chapter formats
|
|
39
|
+
|
|
40
|
+
Each converter takes a file’s text, or JSON you already parsed, and returns cues for a chapters track. Pass one as the `format` of a track with a `src`, and the player converts the file once it loads. Or call it yourself and pass the result as `cues`. Converters skip entries they can’t read; only text that isn’t JSON throws.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
player.store.addTextTrack({ kind: 'chapters', src: '/episodes/42/chapters.json', format: podcastChapters });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
A chapter without an end runs to the next chapter, and the last one to the end of the media.
|
|
47
|
+
|
|
48
|
+
### `podcastChapters`
|
|
49
|
+
|
|
50
|
+
Reads a [Podcasting 2.0 JSON chapters](https://github.com/Podcastindex-org/podcast-namespace) file. Each chapter’s `title` becomes the cue text, `startTime` and `endTime` its times, `url` its `url`, and `img` its first image. Chapters marked `toc: false` are left out, since they aren’t meant to be shown.
|
|
51
|
+
|
|
52
|
+
### `appleHlsChapters`
|
|
53
|
+
|
|
54
|
+
Reads an Apple HLS chapters file: the JSON an `EXT-X-SESSION-DATA` tag with `DATA-ID="com.apple.hls.chapters"` points to. Each chapter starts at its `start-time` and ends after its `duration`. Its first title becomes the cue text, and every title is kept in `titles` by language. Its `images` keep their `pixel-width` and `pixel-height` as `width` and `height`.
|
|
55
|
+
|
|
56
|
+
### `jsonLdChapters`
|
|
57
|
+
|
|
58
|
+
Reads schema.org JSON-LD: a `VideoObject` whose `hasPart` lists `Clip`s, a list of `Clip`s, or one `Clip`. These are the clips Google shows as key moments. Each clip’s `name` becomes the cue text, `startOffset` and `endOffset` its times in seconds, and its `description`, `url`, and first `thumbnailUrl` its value.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const jsonLd = document.querySelector('script[type="application/ld+json"]')!.textContent!;
|
|
62
|
+
|
|
63
|
+
player.store.addTextTrack({ kind: 'chapters', cues: jsonLdChapters(jsonLd) });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Exports
|
|
67
|
+
|
|
68
|
+
| Export | Description |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| `ChapterCueValue` | What a chapter can carry beyond its title. |
|
|
71
|
+
| `ChapterImage` | An image for a chapter: a `url`, and optionally a `width` and `height`. |
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# defineTextTrack
|
|
2
|
+
|
|
3
|
+
Define a text track once, with the type of its cue values, to add and read it with
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { defineTextTrack } from '@videojs/html';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`defineTextTrack` returns a track definition: a track’s `kind`, and optionally its `label` and `language`, typed with the `value` its cues carry. A definition works anywhere a text track filter does, matching tracks by kind, label, and language. Reading through it types each cue’s `value`, and adding a track from it checks the cues you pass against that type.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Pass the value type as a type parameter. The type isn’t checked at runtime.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { defineTextTrack, getActiveTextCues, type TextCueInit } from '@videojs/html';
|
|
19
|
+
|
|
20
|
+
interface Quiz {
|
|
21
|
+
question: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const quizTrack = defineTextTrack<Quiz>({ kind: 'metadata', label: 'quiz' });
|
|
25
|
+
|
|
26
|
+
const player = document.querySelector('video-player')!;
|
|
27
|
+
const cues: TextCueInit<Quiz>[] = await fetch('/api/quiz').then((res) => res.json());
|
|
28
|
+
|
|
29
|
+
player.store.addTextTrack(quizTrack, { cues });
|
|
30
|
+
|
|
31
|
+
player.store.subscribe(() => {
|
|
32
|
+
const [cue] = getActiveTextCues(player.store, quizTrack);
|
|
33
|
+
console.log(cue?.value?.question);
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Schemas
|
|
38
|
+
|
|
39
|
+
Pass a `schema` to check values where they’re read. It takes any [Standard Schema](https://standardschema.dev), the validation interface zod, valibot, ArkType, and other libraries implement, and the value type comes from the schema’s output.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { z } from 'zod';
|
|
43
|
+
|
|
44
|
+
const QuizSchema = z.object({ question: z.string() });
|
|
45
|
+
|
|
46
|
+
const quizTrack = defineTextTrack({ kind: 'metadata', label: 'quiz', schema: QuizSchema });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Readers skip a cue whose value fails the schema, and warn in development. Each cue is checked once per schema. Schemas must be synchronous; an asynchronous schema fails every value. Adding a track doesn’t run the schema.
|
|
50
|
+
|
|
51
|
+
### Built-in definitions
|
|
52
|
+
|
|
53
|
+
[`chaptersTrack`](./chapters-track.md) matches every chapters track and types the values chapter formats carry. [`hlsMetadataTrack`](./hls-metadata-track.md) matches the metadata track hls.js publishes ID3 and `EXT-X-DATERANGE` metadata on.
|
|
54
|
+
|
|
55
|
+
## Exports
|
|
56
|
+
|
|
57
|
+
| Export | Description |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `TextTrackDefinition` | A track definition. Its type parameter is the cue type it reads. |
|
|
60
|
+
| `TextTrackIdentity` | What identifies a track: `kind`, `label`, and `language`. |
|
|
61
|
+
| `InferTextTrackCue` | The cue type a definition reads, as in `InferTextTrackCue<typeof quizTrack>`. |
|
|
62
|
+
| `InferSchemaOutput` | The value type a schema produces. |
|
|
63
|
+
| `StandardSchemaV1` | The Standard Schema interface a `schema` implements. |
|
|
64
|
+
| `StandardSchemaV1Props` | The properties a Standard Schema carries under its `~standard` key. |
|
|
65
|
+
| `StandardSchemaV1Result` | What a Standard Schema’s `validate` returns. |
|
|
66
|
+
|
|
67
|
+
## API Reference
|
|
68
|
+
|
|
69
|
+
### With Schema
|
|
70
|
+
|
|
71
|
+
`defineTextTrack<Schema extends StandardSchemaV1>(init): TextTrackDefinition<MediaTextCue<InferSchemaOutput<Schema>>>`
|
|
72
|
+
|
|
73
|
+
Define a text track whose cues carry a `value` checked by a schema, such as one from zod or valibot. Cues whose value fails it are skipped where they're read.
|
|
74
|
+
|
|
75
|
+
`const quizTrack = defineTextTrack({ kind: 'metadata', label: 'quiz', schema: QuizSchema });`
|
|
76
|
+
|
|
77
|
+
#### Parameters
|
|
78
|
+
|
|
79
|
+
| Parameter | Type | Default | Description |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| `init` (required) | `{ kind: 'subtitles' \| 'captions' \| 'descriptions' \| 'chapters' \| 'metadata'; label?: string; language?: string } & { schema: Schema }` | — | The track's kind, and optionally its label and language, with a [Standard Schema](https://standardschema.dev) for its cue values. |
|
|
82
|
+
|
|
83
|
+
#### Return Value
|
|
84
|
+
|
|
85
|
+
| Property | Type | Description |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| `kind` | `'subtitles' \| 'captions' \| 'descriptions' \| 'chapters' \| 'metadata'` | |
|
|
88
|
+
| `label` | `string \| undefined` | |
|
|
89
|
+
| `language` | `string \| undefined` | |
|
|
90
|
+
| `schema` | `{ ~standard: StandardSchemaV1Props<unknown, Input> } \| undefined` | Checks each cue's `value` where it's read. Cues whose value fails are skipped. |
|
|
91
|
+
|
|
92
|
+
### With Type
|
|
93
|
+
|
|
94
|
+
`defineTextTrack<Value = unknown>(init): TextTrackDefinition<MediaTextCue<Value>>`
|
|
95
|
+
|
|
96
|
+
Define a text track whose cues carry a `value` of a given type. The type is not checked at runtime; pass a `schema` for that.
|
|
97
|
+
|
|
98
|
+
`const quizTrack = defineTextTrack<Quiz>({ kind: 'metadata', label: 'quiz' });`
|
|
99
|
+
|
|
100
|
+
#### Parameters
|
|
101
|
+
|
|
102
|
+
| Parameter | Type | Default | Description |
|
|
103
|
+
| --- | --- | --- | --- |
|
|
104
|
+
| `init` (required) | `{ kind: 'subtitles' \| 'captions' \| 'descriptions' \| 'chapters' \| 'metadata'; label?: string; language?: string }` | — | The track's kind, and optionally its label and language. |
|
|
105
|
+
|
|
106
|
+
#### Return Value
|
|
107
|
+
|
|
108
|
+
| Property | Type | Description |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| `kind` | `'subtitles' \| 'captions' \| 'descriptions' \| 'chapters' \| 'metadata'` | |
|
|
111
|
+
| `label` | `string \| undefined` | |
|
|
112
|
+
| `language` | `string \| undefined` | |
|
|
113
|
+
| `schema` | `{ ~standard: StandardSchemaV1Props<unknown, Input> } \| undefined` | Checks each cue's `value` where it's read. Cues whose value fails are skipped. |
|