mirror of
https://github.com/zoriya/v10.git
synced 2026-08-05 13:48:14 +00:00
8.4 KiB
8.4 KiB
Examples
Progressive journey from simple to fully custom.
1. It Works (Minimal)
React
import { createPlayer } from '@videojs/react';
import { features } from '@videojs/core/dom';
const { Provider: VideoProvider, Container: VideoContainer } = createPlayer({
features: [...features.video],
});
function App() {
return (
<VideoProvider>
<VideoContainer>
<video src="video.mp4" />
{/* Custom UI */}
</VideoContainer>
</VideoProvider>
);
}
HTML
import '@videojs/html/video/player';
<video-player>
<video src="video.mp4">
<!-- Custom UI -->
</video-player>
2. It's Pretty (Add Skin)
React
import '@videojs/react/video/skin.css';
import { createPlayer } from '@videojs/react';
import { features } from '@videojs/core/dom';
import { VideoSkin } from '@videojs/react/video/skin';
const { Provider: VideoProvider } = createPlayer({
features: [...features.video],
});
function App() {
return (
<VideoProvider>
<VideoSkin>
<video src="video.mp4" />
</VideoSkin>
</VideoProvider>
);
}
HTML
import '@videojs/html/video/player';
import '@videojs/html/video/skin.css';
import '@videojs/html/video/skin';
<video-player>
<video-skin>
<video src="video.mp4">
</video-skin>
</video-player>
3. I Need a Feature (Chapters)
Skin detects chapters feature, shows chapter menu.
React
import '@videojs/react/video/skin.css';
import { createPlayer } from '@videojs/react';
import { features, chaptersSlice } from '@videojs/core/dom';
import { VideoSkin } from '@videojs/react/video/skin';
const { Provider: VideoProvider } = createPlayer({
features: [...features.video, chaptersSlice],
});
function App() {
return (
<VideoProvider>
<VideoSkin>
<video src="video.mp4" />
</VideoSkin>
</VideoProvider>
);
}
HTML
import '@videojs/html/video/player';
import '@videojs/html/feature/chapters';
import '@videojs/html/video/skin.css';
import '@videojs/html/video/skin';
<video-player>
<video-skin>
<video src="video.mp4">
</video-skin>
</video-player>
4. I Need Streaming (HLS)
Skin detects streaming features, shows quality/tracks menus.
React
import '@videojs/react/video/skin.css';
import { createPlayer } from '@videojs/react';
import { features } from '@videojs/core/dom';
import { HlsVideo } from '@videojs/react/media/hls';
import { VideoSkin } from '@videojs/react/video/skin';
const { Provider: VideoProvider } = createPlayer({
features: [...features.video, ...features.streaming],
});
function App() {
return (
<VideoProvider>
<VideoSkin>
<HlsVideo src="stream.m3u8" />
</VideoSkin>
</VideoProvider>
);
}
HTML
import '@videojs/html/video/player';
import '@videojs/html/feature/streaming';
import '@videojs/html/media/hls-video';
import '@videojs/html/video/skin.css';
import '@videojs/html/video/skin';
<video-player>
<video-skin>
<hls-video src="stream.m3u8">
</video-skin>
</video-player>
5. I Need Ads
Same skin adapts to show ad UI.
React
import '@videojs/react/video/skin.css';
import { createPlayer } from '@videojs/react';
import { features } from '@videojs/core/dom';
import { HlsVideo } from '@videojs/react/media/hls';
import { VideoSkin } from '@videojs/react/video/skin';
const { Provider: VideoProvider } = createPlayer({
features: [...features.video, ...features.streaming, ...features.ads],
});
function App() {
return (
<VideoProvider>
<VideoSkin>
<HlsVideo src="stream.m3u8" />
</VideoSkin>
</VideoProvider>
);
}
HTML
import '@videojs/html/video/player';
import '@videojs/html/feature/streaming';
import '@videojs/html/feature/ads';
import '@videojs/html/media/hls-video';
import '@videojs/html/video/skin.css';
import '@videojs/html/video/skin';
6. Full Custom (Escape Hatch)
React
import { createPlayer } from '@videojs/react';
import { defineSlice } from '@videojs/store';
import { features, selectPlayback, selectTime, type PlayerTarget } from '@videojs/core/dom';
import { HlsVideo } from '@videojs/react/media/hls';
const analyticsSlice = defineSlice<PlayerTarget>()({
state: ({ task }) => ({
trackEvent: task('trackEvent', ({ get }, name: string) => {
console.log('track', name, get());
}),
}),
});
const { Provider: VideoProvider, Container: VideoContainer, usePlayer } = createPlayer({
features: [...features.video, ...features.streaming, analyticsSlice],
});
function App() {
return (
<VideoProvider>
<VideoContainer>
<HlsVideo src="stream.m3u8" />
<MyCustomSkin />
</VideoContainer>
</VideoProvider>
);
}
function MyCustomSkin() {
const playback = usePlayer(selectPlayback);
const time = usePlayer(selectTime);
if (!playback || !time) return null;
return (
<div className="my-skin">
<button onClick={playback.toggle}>
{playback.paused ? 'Play' : 'Pause'}
</button>
<span>{time.currentTime} / {time.duration}</span>
</div>
);
}
HTML
import { createPlayer, MediaElement } from '@videojs/html';
import { features, selectPlayback } from '@videojs/core/dom';
const { PlayerElement, PlayerController, context } = createPlayer({
features: [...features.video, ...features.streaming, myCustomSlice],
});
// Define player element
customElements.define('my-video-player', PlayerElement);
// Custom play button
class MyPlayButton extends MediaElement {
#playback = new PlayerController(this, context, selectPlayback);
override connectedCallback() {
super.connectedCallback();
this.addEventListener('click', this.#handleClick);
}
#handleClick = () => {
this.#playback.value?.toggle();
};
override update() {
const playback = this.#playback.value;
if (!playback) return;
this.textContent = playback.paused ? 'Play' : 'Pause';
}
}
customElements.define('my-play-button', MyPlayButton);
<my-video-player>
<hls-video src="stream.m3u8"></hls-video>
<my-play-button></my-play-button>
</my-video-player>
7. Configure Media Engine
HTML
<hls-video
src="stream.m3u8"
buffer-size="30"
abr-strategy="bandwidth"
>
React
<HlsVideo
src="stream.m3u8"
bufferSize={30}
abrStrategy="bandwidth"
onManifestLoaded={() => {}}
/>
8. Headless (No UI)
React
import { createPlayer } from '@videojs/react';
import { features, selectPlayback, selectTime } from '@videojs/core/dom';
const { Provider: AudioProvider, usePlayer } = createPlayer({
features: [...features.audio],
});
function AudioController() {
const playback = usePlayer(selectPlayback);
const time = usePlayer(selectTime);
// Programmatic control, no UI
useEffect(() => {
if (time && time.currentTime > 60) {
playback?.pause();
}
}, [time?.currentTime, playback]);
return <audio src="audio.mp3" />;
}
9. Using Selectors
Performance-Optimized Access
function TimeDisplay() {
// Only re-renders when currentTime changes
const currentTime = usePlayer((s) => s.currentTime);
if (currentTime === undefined) return null;
return <span>{formatTime(currentTime)}</span>;
}
Derived Values
function PlayState() {
// Derived value, re-renders when paused OR ended changes
const isPlaying = usePlayer((s) => !s.paused && !s.ended);
if (isPlaying === undefined) return null;
return <span>{isPlaying ? 'Playing' : 'Stopped'}</span>;
}
Cross-Feature Selection
function DebugPanel() {
// Select across multiple properties
const debug = usePlayer((s) => ({
paused: s.paused,
currentTime: s.currentTime,
volume: s.volume,
}));
return <pre>{JSON.stringify(debug, null, 2)}</pre>;
}
10. Using Mixins (HTML)
When you need custom player behavior:
import { createPlayer, MediaElement } from '@videojs/html';
import { features } from '@videojs/core/dom';
const { PlayerMixin } = createPlayer({
features: [...features.video],
});
class MyVideoPlayer extends PlayerMixin(MediaElement) {
override connectedCallback() {
super.connectedCallback();
// Custom initialization
this.addEventListener('fullscreenchange', this.#onFullscreen);
}
#onFullscreen = () => {
// Custom fullscreen handling
};
}
customElements.define('my-video-player', MyVideoPlayer);