@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/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