@obipascal/player 1.0.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/LICENSE +21 -0
- package/README.md +854 -0
- package/dist/examples/cloudfront-example.d.ts +25 -0
- package/dist/examples/custom-themes.d.ts +124 -0
- package/dist/examples/events-demo.d.ts +52 -0
- package/dist/examples/public-stream-test.d.ts +38 -0
- package/dist/examples/react-examples.d.ts +32 -0
- package/dist/examples/vanilla-js-examples.d.ts +56 -0
- package/dist/index.d.ts +1 -0
- package/dist/src/analytics.d.ts +28 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/player.d.ts +63 -0
- package/dist/src/react.d.ts +48 -0
- package/dist/src/s3-handler.d.ts +95 -0
- package/dist/src/types.d.ts +113 -0
- package/dist/src/ui-controller.d.ts +51 -0
- package/dist/wontum-player.cjs.js +592 -0
- package/dist/wontum-player.esm.js +1626 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
# Wontum Player
|
|
2
|
+
|
|
3
|
+
A modern, feature-rich HLS video player SDK for educational platforms with CloudFront/S3 integration. Built with TypeScript, inspired by Mux Player with a unique modern design.
|
|
4
|
+
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
### Core Playback
|
|
8
|
+
- 🎬 **HLS Streaming**: Full HLS.js support with adaptive bitrate streaming
|
|
9
|
+
- 🔒 **CloudFront Integration**: Native support for CloudFront signed cookies and S3-hosted videos
|
|
10
|
+
- 🎯 **Skip Controls**: 10-second forward/backward skip with circular arrow buttons
|
|
11
|
+
- 🎯 **Click to Play/Pause**: Click video to toggle playback
|
|
12
|
+
- 📺 **Fullscreen**: Native fullscreen API support
|
|
13
|
+
- 🎛️ **Playback Rate**: Adjustable speed (0.5x - 2x)
|
|
14
|
+
|
|
15
|
+
### Subtitle & Accessibility
|
|
16
|
+
- 📝 **Subtitle Support**: Full subtitle/caption support with programmatic API
|
|
17
|
+
- 🌐 **Multi-language**: Support for multiple subtitle tracks with language selection
|
|
18
|
+
- ♿ **Accessibility**: WCAG compliant with keyboard navigation
|
|
19
|
+
|
|
20
|
+
### UI & Controls
|
|
21
|
+
- 🎨 **Modern UI Design**: Beautiful controls with blur effects, gradients, and smooth animations
|
|
22
|
+
- 🖱️ **Smart Controls**: Auto-hide on inactivity, fade on hover
|
|
23
|
+
- 📍 **Sticky Controls**: Optional persistent controls (toggle in settings)
|
|
24
|
+
- 🔊 **Vertical Volume**: Modern vertical volume slider with popup interface
|
|
25
|
+
- ⚙️ **Settings Menu**: Quality selection, playback speed, subtitle management
|
|
26
|
+
- 🎨 **7 Pre-made Themes**: Netflix, YouTube, Modern, Green, Cyberpunk, Pastel, Education
|
|
27
|
+
- 🎨 **Custom Theming**: Full CSS variable theming with 8 customizable properties
|
|
28
|
+
|
|
29
|
+
### Developer Experience
|
|
30
|
+
- ⚛️ **React Support**: Component, Hook, and Context Provider patterns
|
|
31
|
+
- 🔧 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
32
|
+
- 📊 **Analytics & QoE**: Built-in analytics tracking and Quality of Experience metrics
|
|
33
|
+
- 🎯 **25 Events**: Complete event system compatible with Mux Player
|
|
34
|
+
- 📱 **Responsive**: Mobile-friendly with touch support
|
|
35
|
+
- 🎬 **Quality Selector**: Automatic quality switching with manual override
|
|
36
|
+
|
|
37
|
+
## 📦 Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @wontum/player hls.js
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or with yarn:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
yarn add @wontum/player hls.js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 🚀 Quick Start
|
|
50
|
+
|
|
51
|
+
### Vanilla JavaScript
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<!DOCTYPE html>
|
|
55
|
+
<html>
|
|
56
|
+
<head>
|
|
57
|
+
<title>Wontum Player Demo</title>
|
|
58
|
+
</head>
|
|
59
|
+
<body>
|
|
60
|
+
<div id="player-container"></div>
|
|
61
|
+
|
|
62
|
+
<script type="module">
|
|
63
|
+
import { WontumPlayer } from "@wontum/player"
|
|
64
|
+
|
|
65
|
+
const player = new WontumPlayer({
|
|
66
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
67
|
+
container: "#player-container",
|
|
68
|
+
autoplay: false,
|
|
69
|
+
muted: false,
|
|
70
|
+
controls: true,
|
|
71
|
+
poster: "https://example.com/poster.jpg",
|
|
72
|
+
// Enable subtitles
|
|
73
|
+
subtitles: [
|
|
74
|
+
{
|
|
75
|
+
label: "English",
|
|
76
|
+
src: "https://example.com/subtitles/en.vtt",
|
|
77
|
+
srclang: "en",
|
|
78
|
+
default: true,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label: "Spanish",
|
|
82
|
+
src: "https://example.com/subtitles/es.vtt",
|
|
83
|
+
srclang: "es",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
// Sticky controls
|
|
87
|
+
stickyControls: false,
|
|
88
|
+
// Custom theme
|
|
89
|
+
theme: {
|
|
90
|
+
primaryColor: "#3b82f6",
|
|
91
|
+
accentColor: "#60a5fa",
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Listen to events
|
|
96
|
+
player.on("play", () => console.log("Video playing"))
|
|
97
|
+
player.on("pause", () => console.log("Video paused"))
|
|
98
|
+
player.on("timeupdate", (event) => {
|
|
99
|
+
console.log("Current time:", event.data.currentTime)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// Programmatic subtitle control
|
|
103
|
+
player.enableSubtitles(0) // Enable first subtitle track
|
|
104
|
+
player.toggleSubtitles() // Toggle subtitles on/off
|
|
105
|
+
</script>
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### React Component
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { WontumPlayerReact } from "@wontum/player"
|
|
114
|
+
|
|
115
|
+
function VideoPlayer() {
|
|
116
|
+
return (
|
|
117
|
+
<WontumPlayerReact
|
|
118
|
+
src="https://media.example.com/video/playlist.m3u8"
|
|
119
|
+
width="100%"
|
|
120
|
+
height="500px"
|
|
121
|
+
autoplay={false}
|
|
122
|
+
muted={false}
|
|
123
|
+
controls={true}
|
|
124
|
+
stickyControls={false}
|
|
125
|
+
subtitles={[
|
|
126
|
+
{
|
|
127
|
+
label: "English",
|
|
128
|
+
src: "https://example.com/subtitles/en.vtt",
|
|
129
|
+
srclang: "en",
|
|
130
|
+
default: true,
|
|
131
|
+
},
|
|
132
|
+
]}
|
|
133
|
+
theme={{
|
|
134
|
+
primaryColor: "#3b82f6",
|
|
135
|
+
accentColor: "#60a5fa",
|
|
136
|
+
}}
|
|
137
|
+
onPlay={() => console.log("Playing")}
|
|
138
|
+
onPause={() => console.log("Paused")}
|
|
139
|
+
onTimeUpdate={(time) => console.log("Time:", time)}
|
|
140
|
+
onSubtitleChange={(track) => console.log("Subtitle:", track)}
|
|
141
|
+
/>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### React Hook (Custom Controls)
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { useWontumPlayer } from "@wontum/player"
|
|
150
|
+
|
|
151
|
+
function CustomPlayer() {
|
|
152
|
+
const { containerRef, player, state } = useWontumPlayer({
|
|
153
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
154
|
+
controls: false, // Build your own custom controls
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const handleSkipForward = () => player?.skipForward(10)
|
|
158
|
+
const handleSkipBackward = () => player?.skipBackward(10)
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div>
|
|
162
|
+
<div ref={containerRef} style={{ width: "100%", height: "500px" }} />
|
|
163
|
+
|
|
164
|
+
{state && (
|
|
165
|
+
<div className="custom-controls">
|
|
166
|
+
<button onClick={() => player?.play()}>Play</button>
|
|
167
|
+
<button onClick={() => player?.pause()}>Pause</button>
|
|
168
|
+
<button onClick={handleSkipBackward}>⏪ -10s</button>
|
|
169
|
+
<button onClick={handleSkipForward}>⏩ +10s</button>
|
|
170
|
+
<button onClick={() => player?.toggleSubtitles()}>CC</button>
|
|
171
|
+
<p>
|
|
172
|
+
{Math.floor(state.currentTime)}s / {Math.floor(state.duration)}s
|
|
173
|
+
</p>
|
|
174
|
+
<p>Status: {state.playing ? "Playing" : "Paused"}</p>
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
</div>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### React Context Provider
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
import { WontumPlayerProvider, useWontumPlayerContext } from "@wontum/player"
|
|
186
|
+
|
|
187
|
+
function App() {
|
|
188
|
+
return (
|
|
189
|
+
<WontumPlayerProvider>
|
|
190
|
+
<VideoSection />
|
|
191
|
+
<ControlPanel />
|
|
192
|
+
</WontumPlayerProvider>
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function VideoSection() {
|
|
197
|
+
const { containerRef } = useWontumPlayerContext()
|
|
198
|
+
return <div ref={containerRef} style={{ width: "100%", height: "500px" }} />
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function ControlPanel() {
|
|
202
|
+
const { player, state } = useWontumPlayerContext()
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div>
|
|
206
|
+
<button onClick={() => player?.play()}>Play</button>
|
|
207
|
+
<button onClick={() => player?.pause()}>Pause</button>
|
|
208
|
+
<p>Playing: {state?.playing ? "Yes" : "No"}</p>
|
|
209
|
+
</div>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## 🔒 CloudFront & S3 Integration
|
|
215
|
+
|
|
216
|
+
### CloudFront with Signed Cookies (Recommended)
|
|
217
|
+
|
|
218
|
+
For secure video delivery, use CloudFront with signed cookies:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { WontumPlayer } from "@wontum/player"
|
|
222
|
+
|
|
223
|
+
// Your backend sets signed cookies for CloudFront
|
|
224
|
+
// Cookie names: CloudFront-Policy, CloudFront-Signature, CloudFront-Key-Pair-Id
|
|
225
|
+
|
|
226
|
+
const player = new WontumPlayer({
|
|
227
|
+
src: "https://media.yourdomain.com/video/playlist.m3u8",
|
|
228
|
+
container: "#player",
|
|
229
|
+
s3Config: {
|
|
230
|
+
cloudfront: {
|
|
231
|
+
domain: "media.yourdomain.com",
|
|
232
|
+
// Cookies are automatically sent by browser
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
})
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### CloudFront Signed Cookie Setup (Backend)
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// Node.js backend example
|
|
242
|
+
import { CloudFrontClient } from "@aws-sdk/client-cloudfront"
|
|
243
|
+
import { getSignedCookies } from "@aws-sdk/cloudfront-signer"
|
|
244
|
+
|
|
245
|
+
app.get("/api/video-auth", async (req, res) => {
|
|
246
|
+
const policy = {
|
|
247
|
+
Statement: [
|
|
248
|
+
{
|
|
249
|
+
Resource: "https://media.yourdomain.com/*",
|
|
250
|
+
Condition: {
|
|
251
|
+
DateLessThan: {
|
|
252
|
+
"AWS:EpochTime": Math.floor(Date.now() / 1000) + 3600, // 1 hour
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const cookies = getSignedCookies({
|
|
260
|
+
keyPairId: process.env.CLOUDFRONT_KEY_PAIR_ID,
|
|
261
|
+
privateKey: process.env.CLOUDFRONT_PRIVATE_KEY,
|
|
262
|
+
policy: JSON.stringify(policy),
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
// Set cookies
|
|
266
|
+
res.cookie("CloudFront-Policy", cookies["CloudFront-Policy"], {
|
|
267
|
+
domain: ".yourdomain.com",
|
|
268
|
+
secure: true,
|
|
269
|
+
httpOnly: true,
|
|
270
|
+
})
|
|
271
|
+
res.cookie("CloudFront-Signature", cookies["CloudFront-Signature"], {
|
|
272
|
+
domain: ".yourdomain.com",
|
|
273
|
+
secure: true,
|
|
274
|
+
httpOnly: true,
|
|
275
|
+
})
|
|
276
|
+
res.cookie("CloudFront-Key-Pair-Id", cookies["CloudFront-Key-Pair-Id"], {
|
|
277
|
+
domain: ".yourdomain.com",
|
|
278
|
+
secure: true,
|
|
279
|
+
httpOnly: true,
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
res.json({ success: true })
|
|
283
|
+
})
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Public S3/CloudFront (No Authentication)
|
|
287
|
+
|
|
288
|
+
For public videos:
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
const player = new WontumPlayer({
|
|
292
|
+
src: "https://d1234567890.cloudfront.net/video/playlist.m3u8",
|
|
293
|
+
container: "#player",
|
|
294
|
+
})
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## 📝 Subtitle Support
|
|
298
|
+
|
|
299
|
+
### Adding Subtitles
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
const player = new WontumPlayer({
|
|
303
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
304
|
+
container: "#player",
|
|
305
|
+
subtitles: [
|
|
306
|
+
{
|
|
307
|
+
label: "English",
|
|
308
|
+
src: "https://example.com/subtitles/en.vtt",
|
|
309
|
+
srclang: "en",
|
|
310
|
+
default: true, // Default track
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
label: "Spanish",
|
|
314
|
+
src: "https://example.com/subtitles/es.vtt",
|
|
315
|
+
srclang: "es",
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
label: "French",
|
|
319
|
+
src: "https://example.com/subtitles/fr.vtt",
|
|
320
|
+
srclang: "fr",
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
})
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Programmatic Subtitle Control
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Enable specific subtitle track by index
|
|
330
|
+
player.enableSubtitles(0) // Enable first track (English)
|
|
331
|
+
|
|
332
|
+
// Disable all subtitles
|
|
333
|
+
player.disableSubtitles()
|
|
334
|
+
|
|
335
|
+
// Toggle subtitles on/off
|
|
336
|
+
player.toggleSubtitles()
|
|
337
|
+
|
|
338
|
+
// Get all subtitle tracks
|
|
339
|
+
const tracks = player.getSubtitleTracks()
|
|
340
|
+
console.log(tracks)
|
|
341
|
+
// [
|
|
342
|
+
// { label: 'English', src: '...', srclang: 'en', default: true },
|
|
343
|
+
// { label: 'Spanish', src: '...', srclang: 'es' }
|
|
344
|
+
// ]
|
|
345
|
+
|
|
346
|
+
// Check if subtitles are enabled
|
|
347
|
+
const enabled = player.areSubtitlesEnabled()
|
|
348
|
+
console.log(enabled) // true or false
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Subtitle Events
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
player.on("subtitlechange", (event) => {
|
|
355
|
+
console.log("Subtitle changed:", event.data.track)
|
|
356
|
+
})
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## ⚙️ Settings & Controls
|
|
360
|
+
|
|
361
|
+
### Sticky Controls
|
|
362
|
+
|
|
363
|
+
Keep controls visible at all times:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
const player = new WontumPlayer({
|
|
367
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
368
|
+
container: "#player",
|
|
369
|
+
stickyControls: true, // Controls always visible
|
|
370
|
+
})
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Users can also toggle sticky controls from the settings menu in the player UI.
|
|
374
|
+
|
|
375
|
+
### Skip Controls
|
|
376
|
+
|
|
377
|
+
10-second skip buttons with circular arrow icons are automatically included:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Programmatic skip
|
|
381
|
+
player.skipForward(10) // Skip 10 seconds forward
|
|
382
|
+
player.skipBackward(10) // Skip 10 seconds backward
|
|
383
|
+
|
|
384
|
+
// Custom skip duration
|
|
385
|
+
player.seek(player.getCurrentTime() + 30) // Skip 30 seconds forward
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Click to Play/Pause
|
|
389
|
+
|
|
390
|
+
Clicking anywhere on the video toggles play/pause automatically.
|
|
391
|
+
|
|
392
|
+
### Volume Control
|
|
393
|
+
|
|
394
|
+
Modern vertical volume slider with popup interface - hover over volume button to adjust.
|
|
395
|
+
|
|
396
|
+
## 📊 Analytics
|
|
397
|
+
|
|
398
|
+
Track video engagement and quality metrics:
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
const player = new WontumPlayer({
|
|
402
|
+
src: "https://example.com/video.m3u8",
|
|
403
|
+
container: "#player",
|
|
404
|
+
analytics: {
|
|
405
|
+
enabled: true,
|
|
406
|
+
endpoint: "https://your-analytics-endpoint.com/events",
|
|
407
|
+
sessionId: "session_123",
|
|
408
|
+
userId: "user_456",
|
|
409
|
+
videoId: "video_789",
|
|
410
|
+
},
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
// Get analytics metrics
|
|
414
|
+
const metrics = player.analytics.getMetrics()
|
|
415
|
+
console.log(metrics)
|
|
416
|
+
// {
|
|
417
|
+
// sessionId: 'session_123',
|
|
418
|
+
// totalPlayTime: 120000,
|
|
419
|
+
// totalBufferTime: 2000,
|
|
420
|
+
// bufferingRatio: 0.017,
|
|
421
|
+
// rebufferCount: 3,
|
|
422
|
+
// seekCount: 5,
|
|
423
|
+
// eventCount: 42
|
|
424
|
+
// }
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## API Reference
|
|
428
|
+
|
|
429
|
+
### WontumPlayer
|
|
430
|
+
|
|
431
|
+
#### Constructor Options
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
interface WontumPlayerConfig {
|
|
435
|
+
src: string // Video source URL (HLS manifest)
|
|
436
|
+
container: HTMLElement | string // Container element or selector
|
|
437
|
+
autoplay?: boolean // Auto-play on load (default: false)
|
|
438
|
+
muted?: boolean // Start muted (default: false)
|
|
439
|
+
controls?: boolean // Show controls (default: true)
|
|
440
|
+
poster?: string // Poster image URL
|
|
441
|
+
preload?: "none" | "metadata" | "auto" // Preload strategy
|
|
442
|
+
theme?: PlayerTheme // Custom theme
|
|
443
|
+
s3Config?: S3Config // S3 configuration
|
|
444
|
+
analytics?: AnalyticsConfig // Analytics configuration
|
|
445
|
+
hlsConfig?: Partial<any> // HLS.js config override
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
#### Methods
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
// Playback control
|
|
453
|
+
player.play(): Promise<void>
|
|
454
|
+
player.pause(): void
|
|
455
|
+
player.seek(time: number): void
|
|
456
|
+
|
|
457
|
+
// Volume control
|
|
458
|
+
player.setVolume(volume: number): void // 0-1
|
|
459
|
+
player.mute(): void
|
|
460
|
+
player.unmute(): void
|
|
461
|
+
|
|
462
|
+
// Playback rate
|
|
463
|
+
player.setPlaybackRate(rate: number): void // 0.5, 1, 1.5, 2, etc.
|
|
464
|
+
|
|
465
|
+
// Quality control
|
|
466
|
+
player.setQuality(qualityIndex: number): void
|
|
467
|
+
|
|
468
|
+
// Fullscreen
|
|
469
|
+
player.enterFullscreen(): void
|
|
470
|
+
player.exitFullscreen(): void
|
|
471
|
+
|
|
472
|
+
// State
|
|
473
|
+
player.getState(): PlayerState
|
|
474
|
+
|
|
475
|
+
// Events
|
|
476
|
+
player.on(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void
|
|
477
|
+
player.off(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void
|
|
478
|
+
|
|
479
|
+
// Cleanup
|
|
480
|
+
player.destroy(): void
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
#### Events
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
type PlayerEventType =
|
|
487
|
+
| "play"
|
|
488
|
+
| "pause"
|
|
489
|
+
| "ended"
|
|
490
|
+
| "timeupdate"
|
|
491
|
+
| "volumechange"
|
|
492
|
+
| "ratechange"
|
|
493
|
+
| "seeked"
|
|
494
|
+
| "seeking"
|
|
495
|
+
| "waiting"
|
|
496
|
+
| "canplay"
|
|
497
|
+
| "loadedmetadata"
|
|
498
|
+
| "error"
|
|
499
|
+
| "qualitychange"
|
|
500
|
+
| "fullscreenchange"
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### React Components
|
|
504
|
+
|
|
505
|
+
#### WontumPlayerReact
|
|
506
|
+
|
|
507
|
+
```tsx
|
|
508
|
+
<WontumPlayerReact
|
|
509
|
+
src="https://example.com/video.m3u8"
|
|
510
|
+
width="100%"
|
|
511
|
+
height="500px"
|
|
512
|
+
autoplay={false}
|
|
513
|
+
muted={false}
|
|
514
|
+
controls={true}
|
|
515
|
+
poster="https://example.com/poster.jpg"
|
|
516
|
+
onReady={(player) => console.log("Player ready", player)}
|
|
517
|
+
onPlay={() => console.log("Playing")}
|
|
518
|
+
onPause={() => console.log("Paused")}
|
|
519
|
+
onEnded={() => console.log("Ended")}
|
|
520
|
+
onTimeUpdate={(time) => console.log("Time:", time)}
|
|
521
|
+
onVolumeChange={(volume, muted) => console.log("Volume:", volume, muted)}
|
|
522
|
+
onError={(error) => console.error("Error:", error)}
|
|
523
|
+
theme={{
|
|
524
|
+
primaryColor: "#3b82f6",
|
|
525
|
+
accentColor: "#60a5fa",
|
|
526
|
+
fontFamily: "Inter, sans-serif",
|
|
527
|
+
}}
|
|
528
|
+
analytics={{
|
|
529
|
+
enabled: true,
|
|
530
|
+
videoId: "video_123",
|
|
531
|
+
userId: "user_456",
|
|
532
|
+
}}
|
|
533
|
+
/>
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
#### useWontumPlayer Hook
|
|
537
|
+
|
|
538
|
+
```tsx
|
|
539
|
+
function CustomPlayer() {
|
|
540
|
+
const { containerRef, player, state } = useWontumPlayer({
|
|
541
|
+
src: "https://example.com/video.m3u8",
|
|
542
|
+
controls: false, // Build custom controls
|
|
543
|
+
})
|
|
544
|
+
|
|
545
|
+
return (
|
|
546
|
+
<div>
|
|
547
|
+
<div ref={containerRef} style={{ width: "100%", height: "500px" }} />
|
|
548
|
+
|
|
549
|
+
{state && (
|
|
550
|
+
<div>
|
|
551
|
+
<button onClick={() => player?.play()}>Play</button>
|
|
552
|
+
<button onClick={() => player?.pause()}>Pause</button>
|
|
553
|
+
<p>
|
|
554
|
+
Time: {state.currentTime} / {state.duration}
|
|
555
|
+
</p>
|
|
556
|
+
<p>Status: {state.playing ? "Playing" : "Paused"}</p>
|
|
557
|
+
</div>
|
|
558
|
+
)}
|
|
559
|
+
</div>
|
|
560
|
+
)
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
## 🎨 Theming
|
|
565
|
+
|
|
566
|
+
### Pre-made Themes
|
|
567
|
+
|
|
568
|
+
Wontum Player comes with 7 beautiful pre-made themes:
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import {
|
|
572
|
+
netflixTheme,
|
|
573
|
+
youtubeTheme,
|
|
574
|
+
modernTheme,
|
|
575
|
+
greenTheme,
|
|
576
|
+
cyberpunkTheme,
|
|
577
|
+
pastelTheme,
|
|
578
|
+
educationTheme,
|
|
579
|
+
} from "@wontum/player"
|
|
580
|
+
|
|
581
|
+
const player = new WontumPlayer({
|
|
582
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
583
|
+
container: "#player",
|
|
584
|
+
theme: netflixTheme(), // Netflix-inspired dark theme
|
|
585
|
+
})
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Available Themes:**
|
|
589
|
+
- `netflixTheme()` - Netflix-inspired red and black
|
|
590
|
+
- `youtubeTheme()` - YouTube-inspired red and white
|
|
591
|
+
- `modernTheme()` - Modern blue gradient
|
|
592
|
+
- `greenTheme()` - Nature-inspired green
|
|
593
|
+
- `cyberpunkTheme()` - Neon pink and purple
|
|
594
|
+
- `pastelTheme()` - Soft pastel colors
|
|
595
|
+
- `educationTheme()` - Professional education platform
|
|
596
|
+
|
|
597
|
+
### Custom Theme
|
|
598
|
+
|
|
599
|
+
Create your own custom theme with 8 customizable properties:
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
const player = new WontumPlayer({
|
|
603
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
604
|
+
container: "#player",
|
|
605
|
+
theme: {
|
|
606
|
+
primaryColor: "#3b82f6", // Primary brand color
|
|
607
|
+
accentColor: "#60a5fa", // Accent/hover color
|
|
608
|
+
backgroundColor: "#1f2937", // Control background
|
|
609
|
+
textColor: "#ffffff", // Text color
|
|
610
|
+
fontFamily: "Inter, sans-serif", // Font
|
|
611
|
+
borderRadius: "8px", // Corner radius
|
|
612
|
+
controlHeight: "50px", // Control bar height
|
|
613
|
+
iconSize: "24px", // Icon size
|
|
614
|
+
},
|
|
615
|
+
})
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### Brand Presets
|
|
619
|
+
|
|
620
|
+
Quick brand color presets:
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
import { BrandPresets } from "@wontum/player"
|
|
624
|
+
|
|
625
|
+
const player = new WontumPlayer({
|
|
626
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
627
|
+
container: "#player",
|
|
628
|
+
theme: {
|
|
629
|
+
...modernTheme(),
|
|
630
|
+
primaryColor: BrandPresets.blue,
|
|
631
|
+
accentColor: BrandPresets.lightBlue,
|
|
632
|
+
},
|
|
633
|
+
})
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Available Brand Colors:**
|
|
637
|
+
- `blue`, `lightBlue`, `darkBlue`
|
|
638
|
+
- `red`, `lightRed`, `darkRed`
|
|
639
|
+
- `green`, `lightGreen`, `darkGreen`
|
|
640
|
+
- `purple`, `lightPurple`, `darkPurple`
|
|
641
|
+
- `pink`, `lightPink`, `darkPink`
|
|
642
|
+
- `orange`, `lightOrange`, `darkOrange`
|
|
643
|
+
|
|
644
|
+
## 🔧 Advanced Usage
|
|
645
|
+
|
|
646
|
+
### Custom HLS Configuration
|
|
647
|
+
|
|
648
|
+
Pass custom HLS.js configuration:
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
const player = new WontumPlayer({
|
|
652
|
+
src: "https://example.com/video.m3u8",
|
|
653
|
+
container: "#player",
|
|
654
|
+
hlsConfig: {
|
|
655
|
+
maxBufferLength: 30,
|
|
656
|
+
maxMaxBufferLength: 600,
|
|
657
|
+
startLevel: -1, // Auto quality
|
|
658
|
+
capLevelToPlayerSize: true,
|
|
659
|
+
enableWorker: true,
|
|
660
|
+
lowLatencyMode: false,
|
|
661
|
+
},
|
|
662
|
+
})
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Multiple Players on Same Page
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
const player1 = new WontumPlayer({
|
|
669
|
+
src: "https://example.com/video1.m3u8",
|
|
670
|
+
container: "#player-1",
|
|
671
|
+
theme: netflixTheme(),
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
const player2 = new WontumPlayer({
|
|
675
|
+
src: "https://example.com/video2.m3u8",
|
|
676
|
+
container: "#player-2",
|
|
677
|
+
theme: youtubeTheme(),
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
// Each player operates independently
|
|
681
|
+
player1.play()
|
|
682
|
+
player2.pause()
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### Event Handling
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
const player = new WontumPlayer({
|
|
689
|
+
src: "https://media.example.com/video/playlist.m3u8",
|
|
690
|
+
container: "#player",
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
// Playback events
|
|
694
|
+
player.on("play", () => console.log("Playing"))
|
|
695
|
+
player.on("pause", () => console.log("Paused"))
|
|
696
|
+
player.on("ended", () => console.log("Video ended"))
|
|
697
|
+
|
|
698
|
+
// Time tracking
|
|
699
|
+
player.on("timeupdate", (event) => {
|
|
700
|
+
const { currentTime, duration } = event.data
|
|
701
|
+
console.log(`${currentTime}s / ${duration}s`)
|
|
702
|
+
})
|
|
703
|
+
|
|
704
|
+
// Quality changes
|
|
705
|
+
player.on("qualitychange", (event) => {
|
|
706
|
+
console.log("Quality changed to:", event.data.quality)
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
// Buffer events
|
|
710
|
+
player.on("waiting", () => console.log("Buffering..."))
|
|
711
|
+
player.on("canplay", () => console.log("Ready to play"))
|
|
712
|
+
|
|
713
|
+
// Error handling
|
|
714
|
+
player.on("error", (event) => {
|
|
715
|
+
console.error("Player error:", event.data)
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
// Subtitle changes
|
|
719
|
+
player.on("subtitlechange", (event) => {
|
|
720
|
+
console.log("Subtitle track:", event.data.track)
|
|
721
|
+
})
|
|
722
|
+
|
|
723
|
+
// Remove event listener
|
|
724
|
+
const handlePlay = () => console.log("Playing")
|
|
725
|
+
player.on("play", handlePlay)
|
|
726
|
+
player.off("play", handlePlay)
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
### State Management
|
|
730
|
+
|
|
731
|
+
```typescript
|
|
732
|
+
// Get current player state
|
|
733
|
+
const state = player.getState()
|
|
734
|
+
console.log(state)
|
|
735
|
+
// {
|
|
736
|
+
// playing: false,
|
|
737
|
+
// currentTime: 45.2,
|
|
738
|
+
// duration: 300,
|
|
739
|
+
// volume: 0.8,
|
|
740
|
+
// muted: false,
|
|
741
|
+
// playbackRate: 1,
|
|
742
|
+
// buffered: [...],
|
|
743
|
+
// qualities: [...],
|
|
744
|
+
// currentQuality: 2
|
|
745
|
+
// }
|
|
746
|
+
|
|
747
|
+
// Track specific properties
|
|
748
|
+
const currentTime = player.getCurrentTime() // 45.2
|
|
749
|
+
const duration = player.getDuration() // 300
|
|
750
|
+
const isPlaying = player.getState().playing // false
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Programmatic Control
|
|
754
|
+
|
|
755
|
+
```typescript
|
|
756
|
+
// Playback control
|
|
757
|
+
await player.play()
|
|
758
|
+
player.pause()
|
|
759
|
+
player.seek(60) // Seek to 60 seconds
|
|
760
|
+
player.skipForward(10) // Skip 10 seconds forward
|
|
761
|
+
player.skipBackward(10) // Skip 10 seconds backward
|
|
762
|
+
|
|
763
|
+
// Volume control
|
|
764
|
+
player.setVolume(0.5) // Set to 50%
|
|
765
|
+
player.mute()
|
|
766
|
+
player.unmute()
|
|
767
|
+
|
|
768
|
+
// Playback speed
|
|
769
|
+
player.setPlaybackRate(1.5) // 1.5x speed
|
|
770
|
+
player.setPlaybackRate(0.5) // 0.5x speed
|
|
771
|
+
|
|
772
|
+
// Quality selection
|
|
773
|
+
const qualities = player.getQualities()
|
|
774
|
+
player.setQuality(2) // Set to quality index 2
|
|
775
|
+
|
|
776
|
+
// Fullscreen
|
|
777
|
+
player.enterFullscreen()
|
|
778
|
+
player.exitFullscreen()
|
|
779
|
+
|
|
780
|
+
// Cleanup
|
|
781
|
+
player.destroy() // Remove player and clean up resources
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
## 📋 Complete API Reference
|
|
785
|
+
|
|
786
|
+
For detailed API documentation including all methods, events, types, and configuration options, see **[API-REFERENCE.md](./API-REFERENCE.md)**.
|
|
787
|
+
|
|
788
|
+
### Quick Reference
|
|
789
|
+
|
|
790
|
+
**Player Methods:**
|
|
791
|
+
- **Playback:** `play()`, `pause()`, `seek(time)`, `skipForward(seconds)`, `skipBackward(seconds)`
|
|
792
|
+
- **Volume:** `setVolume(level)`, `mute()`, `unmute()`
|
|
793
|
+
- **Subtitles:** `enableSubtitles(index)`, `disableSubtitles()`, `toggleSubtitles()`, `getSubtitleTracks()`, `areSubtitlesEnabled()`
|
|
794
|
+
- **Quality:** `setQuality(index)`, `getQualities()`
|
|
795
|
+
- **Playback Rate:** `setPlaybackRate(rate)`
|
|
796
|
+
- **Fullscreen:** `enterFullscreen()`, `exitFullscreen()`
|
|
797
|
+
- **State:** `getState()`, `getCurrentTime()`, `getDuration()`
|
|
798
|
+
- **Lifecycle:** `destroy()`
|
|
799
|
+
|
|
800
|
+
**Events (25 total):**
|
|
801
|
+
- **Playback:** `play`, `pause`, `ended`, `timeupdate`, `durationchange`
|
|
802
|
+
- **Loading:** `loadstart`, `loadedmetadata`, `loadeddata`, `canplay`, `canplaythrough`
|
|
803
|
+
- **Buffering:** `waiting`, `playing`, `stalled`, `suspend`, `abort`
|
|
804
|
+
- **Seeking:** `seeking`, `seeked`
|
|
805
|
+
- **Volume:** `volumechange`
|
|
806
|
+
- **Quality:** `qualitychange`, `renditionchange`
|
|
807
|
+
- **Errors:** `error`
|
|
808
|
+
- **Playback Rate:** `ratechange`
|
|
809
|
+
- **Fullscreen:** `fullscreenchange`
|
|
810
|
+
- **Resize:** `resize`
|
|
811
|
+
- **Subtitles:** `subtitlechange`
|
|
812
|
+
|
|
813
|
+
## 🌐 Browser Support
|
|
814
|
+
|
|
815
|
+
| Browser | Minimum Version |
|
|
816
|
+
|---------|----------------|
|
|
817
|
+
| Chrome | Latest 2 versions |
|
|
818
|
+
| Edge | Latest 2 versions |
|
|
819
|
+
| Firefox | Latest 2 versions |
|
|
820
|
+
| Safari | Latest 2 versions |
|
|
821
|
+
| iOS Safari | iOS 12+ |
|
|
822
|
+
| Android Chrome | Latest 2 versions |
|
|
823
|
+
|
|
824
|
+
**Note:** HLS playback requires HLS.js support. Native HLS playback is supported on Safari.
|
|
825
|
+
|
|
826
|
+
## 📝 License
|
|
827
|
+
|
|
828
|
+
MIT © Wontum Player
|
|
829
|
+
|
|
830
|
+
## 🤝 Contributing
|
|
831
|
+
|
|
832
|
+
Contributions are welcome! Please follow these steps:
|
|
833
|
+
|
|
834
|
+
1. Fork the repository
|
|
835
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
836
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
837
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
838
|
+
5. Open a Pull Request
|
|
839
|
+
|
|
840
|
+
## 💬 Support
|
|
841
|
+
|
|
842
|
+
- **Issues:** [GitHub Issues](https://github.com/yourorg/wontum-player/issues)
|
|
843
|
+
- **Discussions:** [GitHub Discussions](https://github.com/yourorg/wontum-player/discussions)
|
|
844
|
+
- **Email:** support@wontum.com
|
|
845
|
+
|
|
846
|
+
## 🙏 Acknowledgments
|
|
847
|
+
|
|
848
|
+
- Inspired by [Mux Player](https://www.mux.com/player)
|
|
849
|
+
- Powered by [HLS.js](https://github.com/video-dev/hls.js)
|
|
850
|
+
- Built with [TypeScript](https://www.typescriptlang.org/)
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
Made with ❤️ for educational platforms
|