myetv-player 1.0.0 → 1.0.8

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.
Files changed (38) hide show
  1. package/.github/workflows/codeql.yml +100 -0
  2. package/README.md +49 -58
  3. package/SECURITY.md +50 -0
  4. package/css/myetv-player.css +424 -219
  5. package/css/myetv-player.min.css +1 -1
  6. package/dist/myetv-player.js +1759 -1502
  7. package/dist/myetv-player.min.js +1705 -1469
  8. package/package.json +7 -1
  9. package/plugins/README.md +1016 -0
  10. package/plugins/cloudflare/README.md +1068 -0
  11. package/plugins/cloudflare/myetv-player-cloudflare-stream-plugin.js +556 -0
  12. package/plugins/facebook/README.md +1024 -0
  13. package/plugins/facebook/myetv-player-facebook-plugin.js +437 -0
  14. package/plugins/gamepad-remote-controller/README.md +816 -0
  15. package/plugins/gamepad-remote-controller/myetv-player-gamepad-remote-plugin.js +678 -0
  16. package/plugins/google-adsense-ads/README.md +1 -0
  17. package/plugins/google-adsense-ads/g-adsense-ads-plugin.js +158 -0
  18. package/plugins/google-ima-ads/README.md +1 -0
  19. package/plugins/google-ima-ads/g-ima-ads-plugin.js +355 -0
  20. package/plugins/twitch/README.md +1185 -0
  21. package/plugins/twitch/myetv-player-twitch-plugin.js +569 -0
  22. package/plugins/vast-vpaid-ads/README.md +1 -0
  23. package/plugins/vast-vpaid-ads/vast-vpaid-ads-plugin.js +346 -0
  24. package/plugins/vimeo/README.md +1416 -0
  25. package/plugins/vimeo/myetv-player-vimeo.js +640 -0
  26. package/plugins/youtube/README.md +851 -0
  27. package/plugins/youtube/myetv-player-youtube-plugin.js +1714 -210
  28. package/scss/README.md +160 -0
  29. package/scss/_controls.scss +184 -30
  30. package/scss/_menus.scss +840 -672
  31. package/scss/_responsive.scss +67 -105
  32. package/scss/_volume.scss +67 -105
  33. package/src/README.md +559 -0
  34. package/src/controls.js +17 -5
  35. package/src/core.js +1237 -1060
  36. package/src/i18n.js +27 -1
  37. package/src/quality.js +478 -436
  38. package/src/subtitles.js +2 -2
@@ -0,0 +1,1416 @@
1
+ # MYETV Player - Vimeo Plugin
2
+ Official Vimeo integration plugin for MYETV Video Player. Play Vimeo videos directly in your player with full control, quality management, and extensive API support.
3
+
4
+ ---
5
+
6
+ ## Table of Contents
7
+
8
+ - [Features](#features)
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [Configuration Options](#configuration-options)
12
+ - [Usage Methods](#usage-methods)
13
+ - [API Methods](#api-methods)
14
+ - [Events](#events)
15
+ - [Quality Control](#quality-control)
16
+ - [Advanced Features](#advanced-features)
17
+ - [Examples](#examples)
18
+ - [FAQ](#faq)
19
+ - [Troubleshooting](#troubleshooting)
20
+
21
+ ---
22
+
23
+ ## Features
24
+
25
+ - **Full Vimeo Integration**: Play any Vimeo video using video ID or URL
26
+ - **Flexible Source**: Support for video ID, URL, or full Vimeo URL
27
+ - **Quality Control**: Manage video quality from 360p to 4K with automatic quality detection
28
+ - **Smart Loading**: Asynchronous Vimeo Player SDK loading
29
+ - **Full API Support**: Complete access to Vimeo Player API methods
30
+ - **Extensive Options**: 20+ Vimeo embed options (color, controls, loop, etc.)
31
+ - **Rich Events**: Comprehensive event system for all player states
32
+ - **Easy Integration**: Seamless integration with MYETV Player
33
+ - **Responsive**: Fully responsive design for all devices
34
+ - **Picture-in-Picture**: Built-in PiP support
35
+ - **Subtitles/CC**: Text track support with multiple languages
36
+ - **Metadata API**: Fetch video information via oEmbed API
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ ### Method 1: Direct Script Include
43
+
44
+ ```html
45
+ <!-- Load MYETV Player Core -->
46
+ <script src="dist/myetv-player.js"></script>
47
+
48
+ <!-- Load Vimeo Plugin -->
49
+ <script src="plugins/myetv-player-vimeo.js"></script>
50
+ ```
51
+
52
+ ### Method 2: Module Import
53
+
54
+ ```javascript
55
+ import MYETVPlayer from './myetv-player.js';
56
+ import './plugins/myetv-player-vimeo.js';
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Quick Start
62
+
63
+ ### Basic Usage
64
+
65
+ ```html
66
+ <!DOCTYPE html>
67
+ <html lang="en">
68
+ <head>
69
+ <meta charset="UTF-8">
70
+ <title>MYETV Player - Vimeo Plugin</title>
71
+ <link rel="stylesheet" href="dist/myetv-player.css">
72
+ </head>
73
+ <body>
74
+ <!-- Video Element -->
75
+ <video id="myVideo" class="video-player"></video>
76
+
77
+ <script src="dist/myetv-player.js"></script>
78
+ <script src="plugins/myetv-player-vimeo.js"></script>
79
+
80
+ <script>
81
+ // Initialize player with Vimeo plugin
82
+ const player = new MYETVPlayer('myVideo', {
83
+ debug: true,
84
+ plugins: {
85
+ vimeo: {
86
+ videoId: '76979871', // Vimeo video ID
87
+ autoplay: false,
88
+ quality: '720p',
89
+ color: 'ff0000' // Custom player color
90
+ }
91
+ }
92
+ });
93
+ </script>
94
+ </body>
95
+ </html>
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Configuration Options
101
+
102
+ ```javascript
103
+ const player = new MYETVPlayer('myVideo', {
104
+ plugins: {
105
+ vimeo: {
106
+ // ========== Video Source ==========
107
+ // Vimeo video ID (number or string)
108
+ videoId: '76979871',
109
+
110
+ // OR use full Vimeo URL
111
+ videoUrl: 'https://vimeo.com/76979871',
112
+
113
+ // ========== Player Dimensions ==========
114
+ width: null, // Player width (null = auto)
115
+ height: null, // Player height (null = auto)
116
+
117
+ // ========== Vimeo Embed Options ==========
118
+ autopause: true, // Pause video when another video plays
119
+ autoplay: false, // Auto-play on load
120
+ background: false, // Enable background mode (no controls)
121
+ byline: true, // Show video author byline
122
+ color: null, // Player color (hex without #, e.g., 'ff0000')
123
+ controls: true, // Show player controls
124
+ dnt: false, // Do Not Track (privacy)
125
+ loop: false, // Loop video playback
126
+ muted: false, // Start muted
127
+ pip: true, // Enable Picture-in-Picture
128
+ playsinline: true, // Play inline on mobile
129
+ portrait: true, // Show author portrait
130
+ quality: 'auto', // Initial quality ('auto', '360p', '540p', '720p', '1080p', '2k', '4k')
131
+ responsive: true, // Responsive sizing
132
+ speed: false, // Enable playback speed controls
133
+ texttrack: null, // Default text track language (e.g., 'en', 'es')
134
+ title: true, // Show video title
135
+ transparent: true, // Transparent background
136
+
137
+ // ========== Plugin Options ==========
138
+ debug: false, // Enable debug logging
139
+ replaceNativePlayer: true, // Replace native video element
140
+ syncControls: false // Sync with custom controls
141
+ }
142
+ }
143
+ });
144
+ ```
145
+
146
+ ### Quality Options
147
+
148
+ | Quality Value | Resolution | Description |
149
+ |---------------|------------|-------------|
150
+ | `'4k'` | 2160p (4K) | Ultra HD (if available) |
151
+ | `'2k'` | 1440p | Quad HD |
152
+ | `'1080p'` | 1080p | Full HD |
153
+ | `'720p'` | 720p | HD |
154
+ | `'540p'` | 540p | SD |
155
+ | `'360p'` | 360p | Low |
156
+ | `'auto'` | Auto | Vimeo auto-selects |
157
+
158
+ ---
159
+
160
+ ## Usage Methods
161
+
162
+ ### Method 1: Using Video ID
163
+
164
+ ```html
165
+ <video id="myVideo" class="video-player"></video>
166
+
167
+ <script>
168
+ const player = new MYETVPlayer('myVideo', {
169
+ plugins: {
170
+ vimeo: {
171
+ videoId: '76979871' // Just the ID
172
+ }
173
+ }
174
+ });
175
+ </script>
176
+ ```
177
+
178
+ ---
179
+
180
+ ### Method 2: Using Full URL
181
+
182
+ ```html
183
+ <video id="myVideo" class="video-player"></video>
184
+
185
+ <script>
186
+ const player = new MYETVPlayer('myVideo', {
187
+ plugins: {
188
+ vimeo: {
189
+ videoUrl: 'https://vimeo.com/76979871'
190
+ }
191
+ }
192
+ });
193
+ </script>
194
+ ```
195
+
196
+ ---
197
+
198
+ ### Method 3: Load Video Dynamically
199
+
200
+ ```html
201
+ <video id="myVideo" class="video-player"></video>
202
+
203
+ <script>
204
+ const player = new MYETVPlayer('myVideo', {
205
+ plugins: { vimeo: {} }
206
+ });
207
+
208
+ // Get plugin instance
209
+ const vimeoPlugin = player.getPlugin('vimeo');
210
+
211
+ // Load video after initialization
212
+ vimeoPlugin.loadVideo('76979871').then(id => {
213
+ console.log('Video loaded:', id);
214
+ });
215
+
216
+ // Or use URL
217
+ vimeoPlugin.loadVideo('https://vimeo.com/76979871');
218
+ </script>
219
+ ```
220
+
221
+ ---
222
+
223
+ ### Method 4: With Custom Styling
224
+
225
+ ```html
226
+ <video id="myVideo" class="video-player"></video>
227
+
228
+ <script>
229
+ const player = new MYETVPlayer('myVideo', {
230
+ plugins: {
231
+ vimeo: {
232
+ videoId: '76979871',
233
+ color: 'ff0000', // Red controls
234
+ background: false,
235
+ byline: false,
236
+ portrait: false,
237
+ title: true,
238
+ transparent: true
239
+ }
240
+ }
241
+ });
242
+ </script>
243
+ ```
244
+
245
+ **Supported URL Formats:**
246
+ - `https://vimeo.com/VIDEO_ID`
247
+ - `https://player.vimeo.com/video/VIDEO_ID`
248
+ - `VIDEO_ID` (numeric ID directly)
249
+
250
+ ---
251
+
252
+ ## API Methods
253
+
254
+ The Vimeo plugin provides extensive API methods through the plugin instance:
255
+
256
+ ```javascript
257
+ const vimeoPlugin = player.getPlugin('vimeo');
258
+ ```
259
+
260
+ ### Playback Control
261
+
262
+ #### `play()`
263
+ Play the video.
264
+
265
+ ```javascript
266
+ vimeoPlugin.play().then(() => {
267
+ console.log('Video playing');
268
+ });
269
+ ```
270
+
271
+ **Returns:** Promise
272
+
273
+ ---
274
+
275
+ #### `pause()`
276
+ Pause the video.
277
+
278
+ ```javascript
279
+ vimeoPlugin.pause().then(() => {
280
+ console.log('Video paused');
281
+ });
282
+ ```
283
+
284
+ **Returns:** Promise
285
+
286
+ ---
287
+
288
+ #### `getCurrentTime()`
289
+ Get current playback position in seconds.
290
+
291
+ ```javascript
292
+ vimeoPlugin.getCurrentTime().then(seconds => {
293
+ console.log('Current time:', seconds);
294
+ });
295
+ ```
296
+
297
+ **Returns:** Promise<Number>
298
+
299
+ ---
300
+
301
+ #### `setCurrentTime(seconds)`
302
+ Set playback position.
303
+
304
+ ```javascript
305
+ vimeoPlugin.setCurrentTime(60).then(seconds => {
306
+ console.log('Seeked to:', seconds);
307
+ });
308
+ ```
309
+
310
+ **Parameters:**
311
+ - `seconds` (Number): Time position in seconds
312
+
313
+ **Returns:** Promise<Number>
314
+
315
+ ---
316
+
317
+ #### `getDuration()`
318
+ Get video duration in seconds.
319
+
320
+ ```javascript
321
+ vimeoPlugin.getDuration().then(duration => {
322
+ console.log('Duration:', duration, 'seconds');
323
+ });
324
+ ```
325
+
326
+ **Returns:** Promise<Number>
327
+
328
+ ---
329
+
330
+ ### Volume Control
331
+
332
+ #### `getVolume()`
333
+ Get current volume (0-1).
334
+
335
+ ```javascript
336
+ vimeoPlugin.getVolume().then(volume => {
337
+ console.log('Volume:', volume);
338
+ });
339
+ ```
340
+
341
+ **Returns:** Promise<Number>
342
+
343
+ ---
344
+
345
+ #### `setVolume(volume)`
346
+ Set volume level.
347
+
348
+ ```javascript
349
+ vimeoPlugin.setVolume(0.5).then(volume => {
350
+ console.log('Volume set to:', volume);
351
+ });
352
+ ```
353
+
354
+ **Parameters:**
355
+ - `volume` (Number): Volume level (0-1)
356
+
357
+ **Returns:** Promise<Number>
358
+
359
+ ---
360
+
361
+ #### `getMuted()`
362
+ Check if video is muted.
363
+
364
+ ```javascript
365
+ vimeoPlugin.getMuted().then(muted => {
366
+ console.log('Muted:', muted);
367
+ });
368
+ ```
369
+
370
+ **Returns:** Promise<Boolean>
371
+
372
+ ---
373
+
374
+ #### `setMuted(muted)`
375
+ Mute or unmute video.
376
+
377
+ ```javascript
378
+ vimeoPlugin.setMuted(true).then(muted => {
379
+ console.log('Muted:', muted);
380
+ });
381
+ ```
382
+
383
+ **Parameters:**
384
+ - `muted` (Boolean): Mute state
385
+
386
+ **Returns:** Promise<Boolean>
387
+
388
+ ---
389
+
390
+ ### Quality Control
391
+
392
+ #### `getQualities()`
393
+ Get available quality levels (synchronous).
394
+
395
+ ```javascript
396
+ const qualities = vimeoPlugin.getQualities();
397
+ console.log('Available qualities:', qualities);
398
+
399
+ // Output example:
400
+ // ['360p', '540p', '720p', '1080p']
401
+ ```
402
+
403
+ **Returns:** Array<String>
404
+
405
+ ---
406
+
407
+ #### `getCurrentQuality()`
408
+ Get current quality level.
409
+
410
+ ```javascript
411
+ vimeoPlugin.getCurrentQuality().then(quality => {
412
+ console.log('Current quality:', quality);
413
+ });
414
+ ```
415
+
416
+ **Returns:** Promise<String>
417
+
418
+ ---
419
+
420
+ #### `setQuality(quality)`
421
+ Set video quality.
422
+
423
+ ```javascript
424
+ vimeoPlugin.setQuality('1080p').then(quality => {
425
+ console.log('Quality changed to:', quality);
426
+ });
427
+ ```
428
+
429
+ **Parameters:**
430
+ - `quality` (String): Quality identifier ('360p', '720p', '1080p', etc.)
431
+
432
+ **Returns:** Promise<String>
433
+
434
+ ---
435
+
436
+ ### Playback Speed
437
+
438
+ #### `getPlaybackRate()`
439
+ Get playback speed.
440
+
441
+ ```javascript
442
+ vimeoPlugin.getPlaybackRate().then(rate => {
443
+ console.log('Playback rate:', rate);
444
+ });
445
+ ```
446
+
447
+ **Returns:** Promise<Number>
448
+
449
+ ---
450
+
451
+ #### `setPlaybackRate(rate)`
452
+ Set playback speed.
453
+
454
+ ```javascript
455
+ vimeoPlugin.setPlaybackRate(1.5).then(rate => {
456
+ console.log('Speed set to:', rate);
457
+ });
458
+ ```
459
+
460
+ **Parameters:**
461
+ - `rate` (Number): Playback rate (0.5 - 2.0)
462
+
463
+ **Returns:** Promise<Number>
464
+
465
+ ---
466
+
467
+ ### Video Management
468
+
469
+ #### `loadVideo(videoIdOrUrl)`
470
+ Load a new video.
471
+
472
+ ```javascript
473
+ // By ID
474
+ vimeoPlugin.loadVideo('76979871').then(id => {
475
+ console.log('Video loaded:', id);
476
+ });
477
+
478
+ // By URL
479
+ vimeoPlugin.loadVideo('https://vimeo.com/76979871');
480
+ ```
481
+
482
+ **Parameters:**
483
+ - `videoIdOrUrl` (String|Number): Vimeo video ID or URL
484
+
485
+ **Returns:** Promise<Number>
486
+
487
+ ---
488
+
489
+ #### `getVideoMetadata(videoIdOrUrl)`
490
+ Fetch video metadata via oEmbed API.
491
+
492
+ ```javascript
493
+ vimeoPlugin.getVideoMetadata('76979871').then(metadata => {
494
+ console.log('Title:', metadata.title);
495
+ console.log('Author:', metadata.author);
496
+ console.log('Thumbnail:', metadata.thumbnail);
497
+ console.log('Duration:', metadata.duration);
498
+ });
499
+ ```
500
+
501
+ **Returns:** Promise<Object>
502
+
503
+ Metadata object:
504
+ ```javascript
505
+ {
506
+ title: String,
507
+ description: String,
508
+ thumbnail: String,
509
+ thumbnailLarge: String,
510
+ duration: Number,
511
+ author: String,
512
+ authorUrl: String,
513
+ width: Number,
514
+ height: Number,
515
+ html: String
516
+ }
517
+ ```
518
+
519
+ ---
520
+
521
+ ### Fullscreen
522
+
523
+ #### `requestFullscreen()`
524
+ Enter fullscreen mode.
525
+
526
+ ```javascript
527
+ vimeoPlugin.requestFullscreen().then(() => {
528
+ console.log('Entered fullscreen');
529
+ });
530
+ ```
531
+
532
+ **Returns:** Promise
533
+
534
+ ---
535
+
536
+ #### `exitFullscreen()`
537
+ Exit fullscreen mode.
538
+
539
+ ```javascript
540
+ vimeoPlugin.exitFullscreen().then(() => {
541
+ console.log('Exited fullscreen');
542
+ });
543
+ ```
544
+
545
+ **Returns:** Promise
546
+
547
+ ---
548
+
549
+ ### Text Tracks (Subtitles/CC)
550
+
551
+ #### `getTextTracks()`
552
+ Get available text tracks.
553
+
554
+ ```javascript
555
+ vimeoPlugin.getTextTracks().then(tracks => {
556
+ tracks.forEach(track => {
557
+ console.log(`${track.label} (${track.language})`);
558
+ });
559
+ });
560
+ ```
561
+
562
+ **Returns:** Promise<Array>
563
+
564
+ ---
565
+
566
+ #### `enableTextTrack(language, kind)`
567
+ Enable a text track.
568
+
569
+ ```javascript
570
+ vimeoPlugin.enableTextTrack('en', 'subtitles').then(track => {
571
+ console.log('Enabled track:', track);
572
+ });
573
+ ```
574
+
575
+ **Parameters:**
576
+ - `language` (String): Language code (e.g., 'en', 'es')
577
+ - `kind` (String): Track kind ('subtitles', 'captions')
578
+
579
+ **Returns:** Promise<Object>
580
+
581
+ ---
582
+
583
+ #### `disableTextTrack()`
584
+ Disable current text track.
585
+
586
+ ```javascript
587
+ vimeoPlugin.disableTextTrack().then(() => {
588
+ console.log('Text track disabled');
589
+ });
590
+ ```
591
+
592
+ **Returns:** Promise
593
+
594
+ ---
595
+
596
+ ## Events
597
+
598
+ The Vimeo plugin triggers comprehensive events:
599
+
600
+ ### Playback Events
601
+
602
+ #### `play`
603
+ Video started playing.
604
+
605
+ ```javascript
606
+ player.addEventListener('play', (data) => {
607
+ console.log('Video playing');
608
+ });
609
+ ```
610
+
611
+ ---
612
+
613
+ #### `playing`
614
+ Video is actively playing (after buffering).
615
+
616
+ ```javascript
617
+ player.addEventListener('playing', (data) => {
618
+ console.log('Video is now playing');
619
+ });
620
+ ```
621
+
622
+ ---
623
+
624
+ #### `pause`
625
+ Video paused.
626
+
627
+ ```javascript
628
+ player.addEventListener('pause', (data) => {
629
+ console.log('Video paused');
630
+ });
631
+ ```
632
+
633
+ ---
634
+
635
+ #### `ended`
636
+ Video playback ended.
637
+
638
+ ```javascript
639
+ player.addEventListener('ended', (data) => {
640
+ console.log('Video ended');
641
+ });
642
+ ```
643
+
644
+ ---
645
+
646
+ #### `timeupdate`
647
+ Playback position changed.
648
+
649
+ ```javascript
650
+ player.addEventListener('timeupdate', (data) => {
651
+ console.log('Current time:', data.currentTime);
652
+ console.log('Duration:', data.duration);
653
+ console.log('Percent:', data.percent);
654
+ });
655
+ ```
656
+
657
+ **Event Data:**
658
+ - `currentTime` (Number): Current time in seconds
659
+ - `duration` (Number): Total duration in seconds
660
+ - `percent` (Number): Playback progress (0-1)
661
+
662
+ ---
663
+
664
+ ### Buffering Events
665
+
666
+ #### `progress`
667
+ Download progress.
668
+
669
+ ```javascript
670
+ player.addEventListener('progress', (data) => {
671
+ console.log('Buffering progress:', data);
672
+ });
673
+ ```
674
+
675
+ ---
676
+
677
+ #### `waiting`
678
+ Video buffering started.
679
+
680
+ ```javascript
681
+ player.addEventListener('waiting', () => {
682
+ console.log('Buffering...');
683
+ });
684
+ ```
685
+
686
+ ---
687
+
688
+ #### `canplay`
689
+ Video buffering ended, ready to play.
690
+
691
+ ```javascript
692
+ player.addEventListener('canplay', () => {
693
+ console.log('Ready to play');
694
+ });
695
+ ```
696
+
697
+ ---
698
+
699
+ ### Seeking Events
700
+
701
+ #### `seeking`
702
+ Seek operation started.
703
+
704
+ ```javascript
705
+ player.addEventListener('seeking', (data) => {
706
+ console.log('Seeking...');
707
+ });
708
+ ```
709
+
710
+ ---
711
+
712
+ #### `seeked`
713
+ Seek operation completed.
714
+
715
+ ```javascript
716
+ player.addEventListener('seeked', (data) => {
717
+ console.log('Seeked to:', data.seconds);
718
+ });
719
+ ```
720
+
721
+ ---
722
+
723
+ ### Quality Events
724
+
725
+ #### `qualitiesloaded`
726
+ Available qualities loaded.
727
+
728
+ ```javascript
729
+ player.addEventListener('qualitiesloaded', (data) => {
730
+ console.log('Available qualities:', data.qualities);
731
+ });
732
+ ```
733
+
734
+ **Event Data:**
735
+ - `qualities` (Array): Array of quality strings
736
+
737
+ ---
738
+
739
+ #### `qualitychange`
740
+ Quality changed.
741
+
742
+ ```javascript
743
+ player.addEventListener('qualitychange', (data) => {
744
+ console.log('Quality changed to:', data.quality);
745
+ });
746
+ ```
747
+
748
+ **Event Data:**
749
+ - `quality` (String): New quality level
750
+
751
+ ---
752
+
753
+ ### Volume Events
754
+
755
+ #### `volumechange`
756
+ Volume level changed.
757
+
758
+ ```javascript
759
+ player.addEventListener('volumechange', (data) => {
760
+ console.log('Volume:', data.volume);
761
+ });
762
+ ```
763
+
764
+ ---
765
+
766
+ ### Speed Events
767
+
768
+ #### `playbackratechange`
769
+ Playback speed changed.
770
+
771
+ ```javascript
772
+ player.addEventListener('playbackratechange', (data) => {
773
+ console.log('Playback rate:', data.playbackRate);
774
+ });
775
+ ```
776
+
777
+ ---
778
+
779
+ ### Fullscreen Events
780
+
781
+ #### `fullscreenchange`
782
+ Fullscreen state changed.
783
+
784
+ ```javascript
785
+ player.addEventListener('fullscreenchange', (data) => {
786
+ console.log('Fullscreen:', data.fullscreen);
787
+ });
788
+ ```
789
+
790
+ ---
791
+
792
+ ### Picture-in-Picture Events
793
+
794
+ #### `enterpictureinpicture`
795
+ Entered PiP mode.
796
+
797
+ ```javascript
798
+ player.addEventListener('enterpictureinpicture', () => {
799
+ console.log('Entered Picture-in-Picture');
800
+ });
801
+ ```
802
+
803
+ ---
804
+
805
+ #### `leavepictureinpicture`
806
+ Left PiP mode.
807
+
808
+ ```javascript
809
+ player.addEventListener('leavepictureinpicture', () => {
810
+ console.log('Left Picture-in-Picture');
811
+ });
812
+ ```
813
+
814
+ ---
815
+
816
+ ### Text Track Events
817
+
818
+ #### `texttrackchange`
819
+ Text track changed.
820
+
821
+ ```javascript
822
+ player.addEventListener('texttrackchange', (data) => {
823
+ console.log('Text track changed:', data);
824
+ });
825
+ ```
826
+
827
+ ---
828
+
829
+ #### `chapterchange`
830
+ Video chapter changed.
831
+
832
+ ```javascript
833
+ player.addEventListener('chapterchange', (data) => {
834
+ console.log('Chapter:', data.title);
835
+ });
836
+ ```
837
+
838
+ ---
839
+
840
+ ### Metadata Events
841
+
842
+ #### `loadedmetadata`
843
+ Video metadata loaded.
844
+
845
+ ```javascript
846
+ player.addEventListener('loadedmetadata', (data) => {
847
+ console.log('Video metadata loaded:', data);
848
+ });
849
+ ```
850
+
851
+ ---
852
+
853
+ ### Error Events
854
+
855
+ #### `error`
856
+ Player error occurred.
857
+
858
+ ```javascript
859
+ player.addEventListener('error', (data) => {
860
+ console.error('Vimeo error:', data);
861
+ });
862
+ ```
863
+
864
+ ---
865
+
866
+ ## Quality Control
867
+
868
+ ### Automatic Quality Selection
869
+
870
+ ```javascript
871
+ const player = new MYETVPlayer('myVideo', {
872
+ plugins: {
873
+ vimeo: {
874
+ videoId: '76979871',
875
+ quality: 'auto' // Vimeo selects best quality
876
+ }
877
+ }
878
+ });
879
+ ```
880
+
881
+ ---
882
+
883
+ ### Manual Quality Selection
884
+
885
+ ```javascript
886
+ const vimeoPlugin = player.getPlugin('vimeo');
887
+
888
+ // Get available qualities
889
+ player.addEventListener('qualitiesloaded', (data) => {
890
+ console.log('Available:', data.qualities);
891
+
892
+ // Set specific quality
893
+ if (data.qualities.includes('1080p')) {
894
+ vimeoPlugin.setQuality('1080p');
895
+ }
896
+ });
897
+ ```
898
+
899
+ ---
900
+
901
+ ### Custom Quality Selector
902
+
903
+ ```html
904
+ <div id="quality-selector"></div>
905
+
906
+ <script>
907
+ const player = new MYETVPlayer('myVideo', {
908
+ plugins: { vimeo: { videoId: '76979871' } }
909
+ });
910
+
911
+ const vimeoPlugin = player.getPlugin('vimeo');
912
+
913
+ // Create quality buttons
914
+ player.addEventListener('qualitiesloaded', (data) => {
915
+ const selector = document.getElementById('quality-selector');
916
+
917
+ data.qualities.forEach(quality => {
918
+ const btn = document.createElement('button');
919
+ btn.textContent = quality;
920
+ btn.onclick = () => {
921
+ vimeoPlugin.setQuality(quality).then(selected => {
922
+ console.log('Quality set to:', selected);
923
+ });
924
+ };
925
+ selector.appendChild(btn);
926
+ });
927
+ });
928
+
929
+ // Highlight current quality
930
+ player.addEventListener('qualitychange', (data) => {
931
+ console.log('Now playing at:', data.quality);
932
+ });
933
+ </script>
934
+ ```
935
+
936
+ ---
937
+
938
+ ## Advanced Features
939
+
940
+ ### Background Mode
941
+
942
+ Use video as background with no controls:
943
+
944
+ ```javascript
945
+ const player = new MYETVPlayer('myVideo', {
946
+ plugins: {
947
+ vimeo: {
948
+ videoId: '76979871',
949
+ background: true, // Background mode
950
+ autoplay: true,
951
+ loop: true,
952
+ muted: true
953
+ }
954
+ }
955
+ });
956
+ ```
957
+
958
+ ---
959
+
960
+ ### Custom Player Color
961
+
962
+ Match video player to your brand:
963
+
964
+ ```javascript
965
+ const player = new MYETVPlayer('myVideo', {
966
+ plugins: {
967
+ vimeo: {
968
+ videoId: '76979871',
969
+ color: 'ff0000' // Red (hex without #)
970
+ }
971
+ }
972
+ });
973
+ ```
974
+
975
+ ---
976
+
977
+ ### Privacy Mode (Do Not Track)
978
+
979
+ Enable privacy-focused playback:
980
+
981
+ ```javascript
982
+ const player = new MYETVPlayer('myVideo', {
983
+ plugins: {
984
+ vimeo: {
985
+ videoId: '76979871',
986
+ dnt: true // Enable Do Not Track
987
+ }
988
+ }
989
+ });
990
+ ```
991
+
992
+ ---
993
+
994
+ ### Fetch Video Metadata
995
+
996
+ Get video information before/after loading:
997
+
998
+ ```javascript
999
+ const vimeoPlugin = player.getPlugin('vimeo');
1000
+
1001
+ vimeoPlugin.getVideoMetadata('76979871').then(metadata => {
1002
+ // Display video info
1003
+ document.getElementById('title').textContent = metadata.title;
1004
+ document.getElementById('author').textContent = metadata.author;
1005
+ document.getElementById('thumbnail').src = metadata.thumbnail;
1006
+
1007
+ // Use duration
1008
+ const minutes = Math.floor(metadata.duration / 60);
1009
+ const seconds = metadata.duration % 60;
1010
+ document.getElementById('duration').textContent = `${minutes}:${seconds}`;
1011
+ });
1012
+ ```
1013
+
1014
+ ---
1015
+
1016
+ ## Examples
1017
+
1018
+ ### Example 1: Video Gallery
1019
+
1020
+ ```html
1021
+ <video id="myVideo" class="video-player"></video>
1022
+
1023
+ <div id="gallery">
1024
+ <button onclick="loadVimeoVideo('76979871')">Video 1</button>
1025
+ <button onclick="loadVimeoVideo('148751763')">Video 2</button>
1026
+ <button onclick="loadVimeoVideo('259411563')">Video 3</button>
1027
+ </div>
1028
+
1029
+ <script>
1030
+ const player = new MYETVPlayer('myVideo', {
1031
+ plugins: { vimeo: {} }
1032
+ });
1033
+
1034
+ const vimeoPlugin = player.getPlugin('vimeo');
1035
+
1036
+ function loadVimeoVideo(videoId) {
1037
+ vimeoPlugin.loadVideo(videoId).then(() => {
1038
+ // Optionally fetch and display metadata
1039
+ vimeoPlugin.getVideoMetadata(videoId).then(meta => {
1040
+ console.log('Loaded:', meta.title);
1041
+ });
1042
+ });
1043
+ }
1044
+ </script>
1045
+ ```
1046
+
1047
+ ---
1048
+
1049
+ ### Example 2: Quality Presets
1050
+
1051
+ ```javascript
1052
+ const player = new MYETVPlayer('myVideo', {
1053
+ plugins: { vimeo: { videoId: '76979871' } }
1054
+ });
1055
+
1056
+ const vimeoPlugin = player.getPlugin('vimeo');
1057
+
1058
+ // Create preset buttons
1059
+ const presets = {
1060
+ 'High Quality': '1080p',
1061
+ 'Medium Quality': '720p',
1062
+ 'Low Quality': '360p',
1063
+ 'Auto': 'auto'
1064
+ };
1065
+
1066
+ Object.entries(presets).forEach(([label, quality]) => {
1067
+ const btn = document.createElement('button');
1068
+ btn.textContent = label;
1069
+ btn.onclick = () => {
1070
+ vimeoPlugin.setQuality(quality).then(selected => {
1071
+ alert(`Quality: ${selected}`);
1072
+ });
1073
+ };
1074
+ document.body.appendChild(btn);
1075
+ });
1076
+ ```
1077
+
1078
+ ---
1079
+
1080
+ ### Example 3: Progress Tracker
1081
+
1082
+ ```javascript
1083
+ const player = new MYETVPlayer('myVideo', {
1084
+ plugins: { vimeo: { videoId: '76979871' } }
1085
+ });
1086
+
1087
+ const vimeoPlugin = player.getPlugin('vimeo');
1088
+
1089
+ // Track viewing progress
1090
+ let watchedSeconds = 0;
1091
+ let milestones = [25, 50, 75, 100];
1092
+
1093
+ player.addEventListener('timeupdate', (data) => {
1094
+ watchedSeconds = data.currentTime;
1095
+ const percent = (data.currentTime / data.duration) * 100;
1096
+
1097
+ // Check milestones
1098
+ milestones.forEach((milestone, index) => {
1099
+ if (percent >= milestone && milestones.includes(milestone)) {
1100
+ console.log(`Milestone: ${milestone}% watched!`);
1101
+ milestones.splice(index, 1);
1102
+ }
1103
+ });
1104
+
1105
+ // Update progress bar
1106
+ document.getElementById('progress-bar').style.width = percent + '%';
1107
+ });
1108
+ ```
1109
+
1110
+ ---
1111
+
1112
+ ### Example 4: Multi-Language Subtitles
1113
+
1114
+ ```javascript
1115
+ const player = new MYETVPlayer('myVideo', {
1116
+ plugins: {
1117
+ vimeo: {
1118
+ videoId: '76979871',
1119
+ texttrack: 'en' // Default to English
1120
+ }
1121
+ }
1122
+ });
1123
+
1124
+ const vimeoPlugin = player.getPlugin('vimeo');
1125
+
1126
+ // Load available subtitles
1127
+ vimeoPlugin.getTextTracks().then(tracks => {
1128
+ const selector = document.getElementById('subtitle-selector');
1129
+
1130
+ tracks.forEach(track => {
1131
+ const option = document.createElement('option');
1132
+ option.value = track.language;
1133
+ option.textContent = track.label;
1134
+ selector.appendChild(option);
1135
+ });
1136
+
1137
+ // Change subtitle on selection
1138
+ selector.onchange = (e) => {
1139
+ const lang = e.target.value;
1140
+ if (lang) {
1141
+ vimeoPlugin.enableTextTrack(lang, 'subtitles');
1142
+ } else {
1143
+ vimeoPlugin.disableTextTrack();
1144
+ }
1145
+ };
1146
+ });
1147
+ ```
1148
+
1149
+ ---
1150
+
1151
+ ### Example 5: Playback Speed Controller
1152
+
1153
+ ```javascript
1154
+ const player = new MYETVPlayer('myVideo', {
1155
+ plugins: {
1156
+ vimeo: {
1157
+ videoId: '76979871',
1158
+ speed: true // Enable speed controls
1159
+ }
1160
+ }
1161
+ });
1162
+
1163
+ const vimeoPlugin = player.getPlugin('vimeo');
1164
+
1165
+ // Create speed buttons
1166
+ [0.5, 0.75, 1, 1.25, 1.5, 2].forEach(speed => {
1167
+ const btn = document.createElement('button');
1168
+ btn.textContent = `${speed}x`;
1169
+ btn.onclick = () => {
1170
+ vimeoPlugin.setPlaybackRate(speed).then(rate => {
1171
+ console.log('Speed:', rate);
1172
+ });
1173
+ };
1174
+ document.getElementById('speed-controls').appendChild(btn);
1175
+ });
1176
+ ```
1177
+
1178
+ ---
1179
+
1180
+ ### Example 6: Responsive with Custom Controls
1181
+
1182
+ ```javascript
1183
+ const player = new MYETVPlayer('myVideo', {
1184
+ plugins: {
1185
+ vimeo: {
1186
+ videoId: '76979871',
1187
+ responsive: true,
1188
+ controls: false, // Hide Vimeo controls
1189
+ syncControls: true // Use custom controls
1190
+ }
1191
+ }
1192
+ });
1193
+
1194
+ const vimeoPlugin = player.getPlugin('vimeo');
1195
+
1196
+ // Custom play/pause button
1197
+ document.getElementById('play-btn').onclick = () => {
1198
+ vimeoPlugin.vimeoPlayer.getPaused().then(paused => {
1199
+ if (paused) {
1200
+ vimeoPlugin.play();
1201
+ } else {
1202
+ vimeoPlugin.pause();
1203
+ }
1204
+ });
1205
+ };
1206
+
1207
+ // Custom seek bar
1208
+ const seekBar = document.getElementById('seek-bar');
1209
+ seekBar.oninput = (e) => {
1210
+ vimeoPlugin.getDuration().then(duration => {
1211
+ const time = (e.target.value / 100) * duration;
1212
+ vimeoPlugin.setCurrentTime(time);
1213
+ });
1214
+ };
1215
+
1216
+ // Update seek bar
1217
+ player.addEventListener('timeupdate', (data) => {
1218
+ seekBar.value = data.percent * 100;
1219
+ });
1220
+ ```
1221
+
1222
+ ---
1223
+
1224
+ ## FAQ
1225
+
1226
+ ### Q: Do I need a Vimeo API key?
1227
+
1228
+ **A:** No! The plugin uses the Vimeo Player SDK which doesn't require authentication for public videos.
1229
+
1230
+ ---
1231
+
1232
+ ### Q: Can I play private videos?
1233
+
1234
+ **A:** Yes, but the video must be set to "Unlisted" or you must be logged into the Vimeo account that owns the video. Completely private videos won't work in embedded players.
1235
+
1236
+ ---
1237
+
1238
+ ### Q: What's the difference between `videoId` and `videoUrl`?
1239
+
1240
+ **A:** Both work! Use whichever is more convenient:
1241
+ - `videoId`: Just the numeric ID (e.g., `'76979871'`)
1242
+ - `videoUrl`: Full URL (e.g., `'https://vimeo.com/76979871'`)
1243
+
1244
+ ---
1245
+
1246
+ ### Q: Can I customize the player appearance?
1247
+
1248
+ **A:** Yes! Use the `color` option to change the control bar color, and combine options like `byline`, `portrait`, `title` to control what's displayed.
1249
+
1250
+ ---
1251
+
1252
+ ### Q: How do I handle videos that can't be embedded?
1253
+
1254
+ **A:** Listen to the error event:
1255
+
1256
+ ```javascript
1257
+ player.addEventListener('error', (data) => {
1258
+ console.error('Vimeo error:', data);
1259
+ // Redirect to Vimeo or show message
1260
+ });
1261
+ ```
1262
+
1263
+ ---
1264
+
1265
+ ### Q: Can I use both Vimeo and regular videos?
1266
+
1267
+ **A:** Yes! The plugin coexists with standard video playback:
1268
+
1269
+ ```javascript
1270
+ const vimeoPlugin = player.getPlugin('vimeo');
1271
+
1272
+ // Load Vimeo video
1273
+ vimeoPlugin.loadVideo('76979871');
1274
+
1275
+ // Later, load regular video
1276
+ player.video.src = 'local-video.mp4';
1277
+ ```
1278
+
1279
+ ---
1280
+
1281
+ ### Q: Does the plugin support live streams?
1282
+
1283
+ **A:** Yes! Vimeo live streams work the same way as regular videos. Just use the video ID of the live event.
1284
+
1285
+ ---
1286
+
1287
+ ### Q: How do I get the video thumbnail?
1288
+
1289
+ **A:** Use the metadata API:
1290
+
1291
+ ```javascript
1292
+ vimeoPlugin.getVideoMetadata('76979871').then(meta => {
1293
+ document.getElementById('thumbnail').src = meta.thumbnail;
1294
+ // Or use high-res version
1295
+ document.getElementById('thumbnail-hd').src = meta.thumbnailLarge;
1296
+ });
1297
+ ```
1298
+
1299
+ ---
1300
+
1301
+ ## Troubleshooting
1302
+
1303
+ ### Issue: Vimeo SDK not loading
1304
+
1305
+ **Solution:**
1306
+ - Check browser console for errors
1307
+ - Verify internet connection
1308
+ - Check for Content Security Policy restrictions
1309
+ - Ensure no ad blockers blocking Vimeo scripts
1310
+
1311
+ ```javascript
1312
+ // Check if SDK loaded
1313
+ player.addEventListener('loadedmetadata', () => {
1314
+ console.log('Vimeo player ready');
1315
+ });
1316
+ ```
1317
+
1318
+ ---
1319
+
1320
+ ### Issue: Video not playing
1321
+
1322
+ **Possible causes:**
1323
+ 1. Invalid video ID
1324
+ 2. Video is private
1325
+ 3. Video doesn't allow embedding
1326
+ 4. Domain restrictions
1327
+
1328
+ **Solution:**
1329
+ ```javascript
1330
+ player.addEventListener('error', (data) => {
1331
+ console.error('Error:', data);
1332
+ // Show user-friendly message
1333
+ });
1334
+ ```
1335
+
1336
+ ---
1337
+
1338
+ ### Issue: Quality not available
1339
+
1340
+ **Solution:**
1341
+ - Not all videos have all quality levels
1342
+ - Check available qualities first:
1343
+
1344
+ ```javascript
1345
+ player.addEventListener('qualitiesloaded', (data) => {
1346
+ console.log('Available:', data.qualities);
1347
+
1348
+ // Only set if available
1349
+ if (data.qualities.includes('1080p')) {
1350
+ vimeoPlugin.setQuality('1080p');
1351
+ }
1352
+ });
1353
+ ```
1354
+
1355
+ ---
1356
+
1357
+ ### Issue: Controls not showing
1358
+
1359
+ **Solution:**
1360
+ - Set `controls: true` in options
1361
+ - If using custom controls, ensure `syncControls: true`
1362
+
1363
+ ```javascript
1364
+ plugins: {
1365
+ vimeo: {
1366
+ videoId: '76979871',
1367
+ controls: true
1368
+ }
1369
+ }
1370
+ ```
1371
+
1372
+ ---
1373
+
1374
+ ### Debug Mode
1375
+
1376
+ Enable detailed logging:
1377
+
1378
+ ```javascript
1379
+ const player = new MYETVPlayer('myVideo', {
1380
+ debug: true,
1381
+ plugins: {
1382
+ vimeo: {
1383
+ videoId: '76979871',
1384
+ debug: true
1385
+ }
1386
+ }
1387
+ });
1388
+ ```
1389
+
1390
+ Debug messages appear with the `Vimeo` prefix.
1391
+
1392
+ ---
1393
+
1394
+ ## Resources
1395
+
1396
+ - **MYETV Player**: [https://www.myetv.tv](https://www.myetv.tv)
1397
+ - **Vimeo Player SDK**: [Vimeo Player API Documentation](https://developer.vimeo.com/player/sdk)
1398
+ - **Vimeo oEmbed API**: [Vimeo oEmbed Documentation](https://developer.vimeo.com/api/oembed)
1399
+ - **GitHub**: [MYETV Video Player Open Source](https://github.com/OskarCosimo/myetv-video-player-opensource)
1400
+ - **Author**: [https://oskarcosimo.com](https://oskarcosimo.com)
1401
+
1402
+ ---
1403
+
1404
+ ## License
1405
+
1406
+ MIT License - See main project for details.
1407
+
1408
+ ---
1409
+
1410
+ ## Contributing
1411
+
1412
+ Contributions are welcome! Please submit pull requests or open issues on GitHub.
1413
+
1414
+ ---
1415
+
1416
+ **Enjoy professional Vimeo integration!**