Skip to content

Commit ffc1882

Browse files
committed
feat(ui): add adaptive video player controls
1 parent a1b02f7 commit ffc1882

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"name":"@stacksjs/video","type":"module","sideEffects":false,"version":"0.70.162","description":"Native video delivery planning for Stacks.","author":"Chris Breuer","license":"MIT","funding":"https://github.com/sponsors/chrisbbreuer","repository":{"type":"git","url":"git+https://github.com/stacksjs/stacks.git","directory":"./storage/framework/core/video"},"exports":{".":{"types":"./dist/index.d.ts","development":"./src/index.ts","bun":"./dist/index.js","import":"./dist/index.js"}},"module":"dist/index.js","types":"dist/index.d.ts","files":["README.md","dist"],"scripts":{"build":"bun build.ts","typecheck":"bun tsc --noEmit","prepublishOnly":"bun run build"},"devDependencies":{"better-dx":"catalog:"}}
1+
{"name":"@stacksjs/video","type":"module","sideEffects":false,"version":"0.70.162","description":"Native video delivery planning for Stacks.","author":"Chris Breuer","license":"MIT","funding":"https://github.com/sponsors/chrisbbreuer","repository":{"type":"git","url":"git+https://github.com/stacksjs/stacks.git","directory":"./storage/framework/core/video"},"exports":{".":{"types":"./dist/index.d.ts","development":"./src/index.ts","bun":"./dist/index.js","import":"./dist/index.js"}},"module":"dist/index.js","types":"dist/index.d.ts","files":["README.md","dist"],"scripts":{"build":"bun build.ts","typecheck":"bun tsc --noEmit","prepublishOnly":"bun run build"},"dependencies":{"ts-video-player":"^0.1.0"},"devDependencies":{"better-dx":"catalog:"}}

storage/framework/defaults/resources/components/Video.stx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
<script server>
22
interface VideoSource { src: string, type?: string }
3+
interface VideoDrm {
4+
widevine?: { url: string, headers?: Record<string, string> }
5+
playready?: { url: string, headers?: Record<string, string> }
6+
fairplay?: { url: string, certificateUrl: string, headers?: Record<string, string> }
7+
}
38
interface VideoTrack { src: string, kind: 'subtitles' | 'captions' | 'descriptions' | 'chapters' | 'metadata', srclang?: string, label?: string, default?: boolean }
49
interface VideoProps {
510
src: string
611
sources?: VideoSource[]
12+
drm?: VideoDrm
713
tracks?: VideoTrack[]
814
poster?: string
915
title?: string
@@ -36,11 +42,19 @@ const preload = props.preload || 'metadata'
3642
const crossorigin = props.crossorigin || ''
3743
const controlslist = props.controlslist || 'nodownload'
3844
const className = props.class || ''
45+
const playerSources = (sources.length ? sources : src ? [{ src }] : []).map(source => props.drm && (source.type === 'application/dash+xml' || source.src.split(/[?#]/, 1)[0].toLowerCase().endsWith('.mpd')) ? { ...source, type: 'application/dash+xml', drm: props.drm } : source)
46+
const playerConfig = JSON.stringify({ sources: playerSources, ...(props.drm ? { drm: props.drm } : {}) }).replaceAll('<', '\\u003c').replaceAll('>', '\\u003e').replaceAll('&', '\\u0026')
47+
</script>
48+
49+
<script client>
50+
import { registerElements } from 'ts-video-player/elements'
51+
registerElements()
3952
</script>
4053

4154
<figure class="m-0 {{ className }}">
4255
<video-player
4356
src="{{ src }}"
57+
data-media-config="{{ playerConfig }}"
4458
@if(poster) poster="{{ poster }}" @endif
4559
@if(controls) controls @endif
4660
@if(props.autoplay) autoplay @endif
@@ -56,6 +70,7 @@ const className = props.class || ''
5670
class="block overflow-hidden relative w-full bg-black ring-1 ring-black/10 rounded-2xl dark:ring-white/10 focus-within:ring-2 focus-within:ring-sky-500 shadow-sm group"
5771
style="aspect-ratio: {{ ratio }};"
5872
>
73+
<media-error-display></media-error-display>
5974
<video data-native-fallback src="{{ src }}" @if(poster) poster="{{ poster }}" @endif @if(width) width="{{ width }}" @endif @if(height) height="{{ height }}" @endif @if(controls) controls @endif @if(props.autoplay) autoplay @endif @if(props.loop) loop @endif @if(props.muted) muted @endif @if(inline) playsinline @endif preload="{{ preload }}" @if(crossorigin) crossorigin="{{ crossorigin }}" @endif controlslist="{{ controlslist }}" @if(props.disablePictureInPicture) disablepictureinpicture @endif aria-label="{{ title }}" class="object-contain h-full w-full">
6075
@foreach (sources as source)
6176
<source src="{{ source.src }}" @if(source.type) type="{{ source.type }}" @endif>
@@ -69,12 +84,14 @@ const className = props.class || ''
6984
<media-seek-button slot="left" seconds="-10" aria-label="Back 10 seconds"></media-seek-button>
7085
<media-play-button slot="left" aria-label="Play or pause"></media-play-button>
7186
<media-seek-button slot="left" seconds="10" aria-label="Forward 10 seconds"></media-seek-button>
87+
<media-live-button slot="left" aria-label="Go to live edge"></media-live-button>
7288
<media-time-group slot="center" class="font-mono tabular-nums text-xs"></media-time-group>
7389
<media-progress-bar slot="center" previews="metadata" aria-label="Video progress"></media-progress-bar>
7490
<media-mute-button slot="right" aria-label="Mute or unmute"></media-mute-button>
7591
<media-volume-slider slot="right" aria-label="Volume"></media-volume-slider>
7692
<media-playback-rate-button slot="right" rates="0.5,0.75,1,1.25,1.5,2" aria-label="Playback speed"></media-playback-rate-button>
7793
<media-settings-menu slot="right" aria-label="Video settings"></media-settings-menu>
94+
<media-airplay-button slot="right" aria-label="Play on AirPlay"></media-airplay-button>
7895
<media-pip-button slot="right" aria-label="Picture in Picture"></media-pip-button>
7996
<media-fullscreen-button slot="right" aria-label="Fullscreen"></media-fullscreen-button>
8097
</video-skin>

0 commit comments

Comments
 (0)