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.
- package/.github/workflows/codeql.yml +100 -0
- package/README.md +49 -58
- package/SECURITY.md +50 -0
- package/css/myetv-player.css +424 -219
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +1759 -1502
- package/dist/myetv-player.min.js +1705 -1469
- package/package.json +7 -1
- package/plugins/README.md +1016 -0
- package/plugins/cloudflare/README.md +1068 -0
- package/plugins/cloudflare/myetv-player-cloudflare-stream-plugin.js +556 -0
- package/plugins/facebook/README.md +1024 -0
- package/plugins/facebook/myetv-player-facebook-plugin.js +437 -0
- package/plugins/gamepad-remote-controller/README.md +816 -0
- package/plugins/gamepad-remote-controller/myetv-player-gamepad-remote-plugin.js +678 -0
- package/plugins/google-adsense-ads/README.md +1 -0
- package/plugins/google-adsense-ads/g-adsense-ads-plugin.js +158 -0
- package/plugins/google-ima-ads/README.md +1 -0
- package/plugins/google-ima-ads/g-ima-ads-plugin.js +355 -0
- package/plugins/twitch/README.md +1185 -0
- package/plugins/twitch/myetv-player-twitch-plugin.js +569 -0
- package/plugins/vast-vpaid-ads/README.md +1 -0
- package/plugins/vast-vpaid-ads/vast-vpaid-ads-plugin.js +346 -0
- package/plugins/vimeo/README.md +1416 -0
- package/plugins/vimeo/myetv-player-vimeo.js +640 -0
- package/plugins/youtube/README.md +851 -0
- package/plugins/youtube/myetv-player-youtube-plugin.js +1714 -210
- package/scss/README.md +160 -0
- package/scss/_controls.scss +184 -30
- package/scss/_menus.scss +840 -672
- package/scss/_responsive.scss +67 -105
- package/scss/_volume.scss +67 -105
- package/src/README.md +559 -0
- package/src/controls.js +17 -5
- package/src/core.js +1237 -1060
- package/src/i18n.js +27 -1
- package/src/quality.js +478 -436
- package/src/subtitles.js +2 -2
|
@@ -1 +1,852 @@
|
|
|
1
|
+
# MYETV Player - YouTube Plugin
|
|
2
|
+
Official YouTube integration plugin for MYETV Video Player. Play YouTube videos directly in your player with full control and quality management.
|
|
1
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
|
+
- [Examples](#examples)
|
|
17
|
+
- [FAQ](#faq)
|
|
18
|
+
- [Troubleshooting](#troubleshooting)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Full YouTube Integration**: Play any YouTube video using video ID or URL
|
|
25
|
+
- **Auto-Detection**: Automatically detects YouTube URLs from multiple sources
|
|
26
|
+
- **Quality Control**: Manage video quality (144p to 4K) with custom quality menu
|
|
27
|
+
- **Smart Loading**: Asynchronous YouTube IFrame API loading
|
|
28
|
+
- **Seamless Sync**: Synchronizes player controls with YouTube player
|
|
29
|
+
- **Flexible UI**: Show/hide YouTube native controls
|
|
30
|
+
- **Event System**: Rich event callbacks for all YouTube player states
|
|
31
|
+
- **Easy Integration**: Works with existing MYETV Player installations
|
|
32
|
+
- **Responsive**: Works on desktop and mobile devices
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
### Method 1: Direct Script Include
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<!-- Load MYETV Player Core -->
|
|
42
|
+
<script src="dist/myetv-player.js"></script>
|
|
43
|
+
|
|
44
|
+
<!-- Load YouTube Plugin -->
|
|
45
|
+
<script src="plugins/myetv-player-youtube-plugin.js"></script>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Method 2: Module Import
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import MYETVPlayer from './myetv-player.js';
|
|
52
|
+
import './plugins/myetv-player-youtube-plugin.js';
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
### Basic Usage
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<!DOCTYPE html>
|
|
63
|
+
<html lang="en">
|
|
64
|
+
<head>
|
|
65
|
+
<meta charset="UTF-8">
|
|
66
|
+
<title>MYETV Player - YouTube Plugin</title>
|
|
67
|
+
<link rel="stylesheet" href="dist/myetv-player.css">
|
|
68
|
+
</head>
|
|
69
|
+
<body>
|
|
70
|
+
<!-- Video Element -->
|
|
71
|
+
<video id="myVideo" class="video-player"></video>
|
|
72
|
+
|
|
73
|
+
<script src="dist/myetv-player.js"></script>
|
|
74
|
+
<script src="plugins/myetv-player-youtube-plugin.js"></script>
|
|
75
|
+
|
|
76
|
+
<script>
|
|
77
|
+
// Initialize player with YouTube plugin
|
|
78
|
+
const player = new MYETVPlayer('myVideo', {
|
|
79
|
+
debug: true,
|
|
80
|
+
plugins: {
|
|
81
|
+
youtube: {
|
|
82
|
+
videoId: 'dQw4w9WgXcQ', // YouTube video ID
|
|
83
|
+
autoplay: false,
|
|
84
|
+
quality: 'hd720'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
</script>
|
|
89
|
+
</body>
|
|
90
|
+
</html>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Configuration Options
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const player = new MYETVPlayer('myVideo', {
|
|
99
|
+
plugins: {
|
|
100
|
+
youtube: {
|
|
101
|
+
// YouTube video ID (required if not using auto-detection)
|
|
102
|
+
videoId: 'dQw4w9WgXcQ',
|
|
103
|
+
|
|
104
|
+
// YouTube Data API key (optional, for future features)
|
|
105
|
+
apiKey: null,
|
|
106
|
+
|
|
107
|
+
// Auto-play video on load
|
|
108
|
+
autoplay: false,
|
|
109
|
+
|
|
110
|
+
// Show YouTube native controls (true) or use player controls (false)
|
|
111
|
+
showYouTubeUI: false,
|
|
112
|
+
|
|
113
|
+
// Auto-detect video ID from data attributes and sources
|
|
114
|
+
autoLoadFromData: true,
|
|
115
|
+
|
|
116
|
+
// Initial quality ('default', 'small', 'medium', 'large', 'hd720', 'hd1080', 'highres')
|
|
117
|
+
quality: 'default',
|
|
118
|
+
|
|
119
|
+
// Enable quality control in player UI
|
|
120
|
+
enableQualityControl: true
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Quality Options
|
|
127
|
+
|
|
128
|
+
| Quality Value | Resolution | Description |
|
|
129
|
+
|---------------|------------|-------------|
|
|
130
|
+
| `'highres'` | 2160p (4K) | Ultra HD (if available) |
|
|
131
|
+
| `'hd1080'` | 1080p | Full HD |
|
|
132
|
+
| `'hd720'` | 720p | HD |
|
|
133
|
+
| `'large'` | 480p | Standard |
|
|
134
|
+
| `'medium'` | 360p | Low |
|
|
135
|
+
| `'small'` | 240p | Very Low |
|
|
136
|
+
| `'tiny'` | 144p | Minimal |
|
|
137
|
+
| `'default'` or `'auto'` | Auto | YouTube auto-selects |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Usage Methods
|
|
142
|
+
|
|
143
|
+
### Method 1: Using Data Attributes (Recommended)
|
|
144
|
+
|
|
145
|
+
```html
|
|
146
|
+
<video id="myVideo" class="video-player"
|
|
147
|
+
data-video-id="dQw4w9WgXcQ"
|
|
148
|
+
data-video-type="youtube">
|
|
149
|
+
</video>
|
|
150
|
+
|
|
151
|
+
<script>
|
|
152
|
+
const player = new MYETVPlayer('myVideo', {
|
|
153
|
+
plugins: {
|
|
154
|
+
youtube: {
|
|
155
|
+
autoLoadFromData: true // Enable auto-detection (default)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
</script>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Method 2: Using Source Element
|
|
163
|
+
|
|
164
|
+
```html
|
|
165
|
+
<video id="myVideo" class="video-player">
|
|
166
|
+
<source src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
|
167
|
+
type="video/youtube">
|
|
168
|
+
</video>
|
|
169
|
+
|
|
170
|
+
<script>
|
|
171
|
+
const player = new MYETVPlayer('myVideo', {
|
|
172
|
+
plugins: { youtube: {} }
|
|
173
|
+
});
|
|
174
|
+
</script>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Method 3: Load Video Dynamically
|
|
178
|
+
|
|
179
|
+
```html
|
|
180
|
+
<video id="myVideo" class="video-player"></video>
|
|
181
|
+
|
|
182
|
+
<script>
|
|
183
|
+
const player = new MYETVPlayer('myVideo', {
|
|
184
|
+
plugins: { youtube: {} }
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Load YouTube video after initialization
|
|
188
|
+
player.loadYouTubeVideo('dQw4w9WgXcQ');
|
|
189
|
+
|
|
190
|
+
// Or with options
|
|
191
|
+
player.loadYouTubeVideo('dQw4w9WgXcQ', {
|
|
192
|
+
playerVars: {
|
|
193
|
+
autoplay: 1,
|
|
194
|
+
start: 30 // Start at 30 seconds
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
</script>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Method 4: YouTube URL in Video Source
|
|
201
|
+
|
|
202
|
+
```html
|
|
203
|
+
<video id="myVideo" class="video-player"
|
|
204
|
+
src="https://youtu.be/dQw4w9WgXcQ">
|
|
205
|
+
</video>
|
|
206
|
+
|
|
207
|
+
<script>
|
|
208
|
+
const player = new MYETVPlayer('myVideo', {
|
|
209
|
+
plugins: { youtube: {} }
|
|
210
|
+
});
|
|
211
|
+
</script>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Supported URL Formats:**
|
|
215
|
+
- `https://www.youtube.com/watch?v=VIDEO_ID`
|
|
216
|
+
- `https://youtu.be/VIDEO_ID`
|
|
217
|
+
- `https://www.youtube.com/embed/VIDEO_ID`
|
|
218
|
+
- `VIDEO_ID` (11-character ID directly)
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## API Methods
|
|
223
|
+
|
|
224
|
+
The YouTube plugin adds the following methods to your player instance:
|
|
225
|
+
|
|
226
|
+
### `player.loadYouTubeVideo(videoId, options)`
|
|
227
|
+
|
|
228
|
+
Load a YouTube video by ID.
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// Basic usage
|
|
232
|
+
player.loadYouTubeVideo('dQw4w9WgXcQ');
|
|
233
|
+
|
|
234
|
+
// With options
|
|
235
|
+
player.loadYouTubeVideo('dQw4w9WgXcQ', {
|
|
236
|
+
playerVars: {
|
|
237
|
+
autoplay: 1,
|
|
238
|
+
start: 60, // Start at 1 minute
|
|
239
|
+
end: 180, // End at 3 minutes
|
|
240
|
+
cc_load_policy: 1 // Show captions by default
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Parameters:**
|
|
246
|
+
- `videoId` (String): YouTube video ID
|
|
247
|
+
- `options` (Object): Optional configuration
|
|
248
|
+
- `playerVars` (Object): YouTube player parameters
|
|
249
|
+
|
|
250
|
+
**Returns:** void
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### `player.getYouTubeVideoId()`
|
|
255
|
+
|
|
256
|
+
Get the currently loaded YouTube video ID.
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
const videoId = player.getYouTubeVideoId();
|
|
260
|
+
console.log('Current video ID:', videoId);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Returns:** String - YouTube video ID or null
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### `player.isYouTubeActive()`
|
|
268
|
+
|
|
269
|
+
Check if YouTube player is currently active.
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
if (player.isYouTubeActive()) {
|
|
273
|
+
console.log('YouTube player is active');
|
|
274
|
+
} else {
|
|
275
|
+
console.log('Regular video player is active');
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Returns:** Boolean
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### `player.getYouTubeQualities()`
|
|
284
|
+
|
|
285
|
+
Get available quality levels for current YouTube video.
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
const qualities = player.getYouTubeQualities();
|
|
289
|
+
console.log('Available qualities:', qualities);
|
|
290
|
+
|
|
291
|
+
// Output example:
|
|
292
|
+
// [
|
|
293
|
+
// { id: 'hd1080', label: 'Full HD (1080p)', value: 'hd1080' },
|
|
294
|
+
// { id: 'hd720', label: 'HD (720p)', value: 'hd720' },
|
|
295
|
+
// { id: 'large', label: '480p', value: 'large' },
|
|
296
|
+
// ...
|
|
297
|
+
// ]
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Returns:** Array of quality objects
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
### `player.setYouTubeQuality(quality)`
|
|
305
|
+
|
|
306
|
+
Set YouTube video quality.
|
|
307
|
+
|
|
308
|
+
```javascript
|
|
309
|
+
// Set to 720p
|
|
310
|
+
player.setYouTubeQuality('hd720');
|
|
311
|
+
|
|
312
|
+
// Set to 1080p
|
|
313
|
+
player.setYouTubeQuality('hd1080');
|
|
314
|
+
|
|
315
|
+
// Set to auto
|
|
316
|
+
player.setYouTubeQuality('auto');
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Parameters:**
|
|
320
|
+
- `quality` (String): Quality level identifier
|
|
321
|
+
|
|
322
|
+
**Returns:** Boolean - Success status
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### `player.getYouTubeCurrentQuality()`
|
|
327
|
+
|
|
328
|
+
Get current playback quality.
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
const currentQuality = player.getYouTubeCurrentQuality();
|
|
332
|
+
console.log('Current quality:', currentQuality);
|
|
333
|
+
// Output: 'hd720'
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Returns:** String - Quality identifier
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Events
|
|
341
|
+
|
|
342
|
+
The YouTube plugin triggers the following custom events:
|
|
343
|
+
|
|
344
|
+
### `youtubeplugin:ready`
|
|
345
|
+
|
|
346
|
+
Fired when YouTube IFrame API is loaded and ready.
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
player.addEventListener('youtubeplugin:ready', (data) => {
|
|
350
|
+
console.log('YouTube API is ready');
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
### `youtubeplugin:videoloaded`
|
|
357
|
+
|
|
358
|
+
Fired when a YouTube video is loaded.
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
player.addEventListener('youtubeplugin:videoloaded', (data) => {
|
|
362
|
+
console.log('YouTube video loaded:', data.videoId);
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Event Data:**
|
|
367
|
+
- `videoId` (String): Loaded video ID
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
### `youtubeplugin:playerready`
|
|
372
|
+
|
|
373
|
+
Fired when YouTube player is ready and initialized.
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
player.addEventListener('youtubeplugin:playerready', (data) => {
|
|
377
|
+
console.log('YouTube player ready');
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
### `youtubeplugin:qualitiesloaded`
|
|
384
|
+
|
|
385
|
+
Fired when available quality levels are loaded.
|
|
386
|
+
|
|
387
|
+
```javascript
|
|
388
|
+
player.addEventListener('youtubeplugin:qualitiesloaded', (data) => {
|
|
389
|
+
console.log('Available qualities:', data.qualities);
|
|
390
|
+
|
|
391
|
+
// Create custom quality selector
|
|
392
|
+
data.qualities.forEach(quality => {
|
|
393
|
+
console.log(`${quality.label}: ${quality.value}`);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Event Data:**
|
|
399
|
+
- `qualities` (Array): Array of quality objects
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### `youtubeplugin:qualitychanged`
|
|
404
|
+
|
|
405
|
+
Fired when video quality changes.
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
player.addEventListener('youtubeplugin:qualitychanged', (data) => {
|
|
409
|
+
console.log('Quality changed to:', data.quality);
|
|
410
|
+
console.log('Label:', data.label);
|
|
411
|
+
});
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Event Data:**
|
|
415
|
+
- `quality` (String): New quality value
|
|
416
|
+
- `label` (String): Human-readable quality label
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### `youtubeplugin:error`
|
|
421
|
+
|
|
422
|
+
Fired when YouTube player encounters an error.
|
|
423
|
+
|
|
424
|
+
```javascript
|
|
425
|
+
player.addEventListener('youtubeplugin:error', (data) => {
|
|
426
|
+
console.error('YouTube error:', data.errorMessage);
|
|
427
|
+
console.error('Error code:', data.errorCode);
|
|
428
|
+
});
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Event Data:**
|
|
432
|
+
- `errorCode` (Number): YouTube error code
|
|
433
|
+
- `errorMessage` (String): Error description
|
|
434
|
+
|
|
435
|
+
**Error Codes:**
|
|
436
|
+
- `2`: Invalid video ID
|
|
437
|
+
- `5`: HTML5 player error
|
|
438
|
+
- `100`: Video not found or private
|
|
439
|
+
- `101`: Video not allowed to be embedded
|
|
440
|
+
- `150`: Video not allowed to be embedded
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
### Standard Player Events
|
|
445
|
+
|
|
446
|
+
The plugin also triggers standard player events:
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
// Play event
|
|
450
|
+
player.addEventListener('played', (data) => {
|
|
451
|
+
console.log('YouTube video playing');
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// Pause event
|
|
455
|
+
player.addEventListener('paused', (data) => {
|
|
456
|
+
console.log('YouTube video paused');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// End event
|
|
460
|
+
player.addEventListener('ended', (data) => {
|
|
461
|
+
console.log('YouTube video ended');
|
|
462
|
+
});
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## Quality Control
|
|
468
|
+
|
|
469
|
+
### Automatic Quality Menu Integration
|
|
470
|
+
|
|
471
|
+
The plugin automatically integrates with MYETV Player's quality selector if available:
|
|
472
|
+
|
|
473
|
+
```javascript
|
|
474
|
+
const player = new MYETVPlayer('myVideo', {
|
|
475
|
+
plugins: {
|
|
476
|
+
youtube: {
|
|
477
|
+
videoId: 'dQw4w9WgXcQ',
|
|
478
|
+
enableQualityControl: true // Enable quality menu integration
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
The quality menu will be automatically populated with available YouTube qualities.
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
### Custom Quality Selector
|
|
489
|
+
|
|
490
|
+
Create a custom quality selector:
|
|
491
|
+
|
|
492
|
+
```html
|
|
493
|
+
<div id="custom-quality-selector"></div>
|
|
494
|
+
|
|
495
|
+
<script>
|
|
496
|
+
const player = new MYETVPlayer('myVideo', {
|
|
497
|
+
plugins: { youtube: { videoId: 'dQw4w9WgXcQ' } }
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// Wait for qualities to load
|
|
501
|
+
player.addEventListener('youtubeplugin:qualitiesloaded', (data) => {
|
|
502
|
+
const selector = document.getElementById('custom-quality-selector');
|
|
503
|
+
|
|
504
|
+
data.qualities.forEach(quality => {
|
|
505
|
+
const button = document.createElement('button');
|
|
506
|
+
button.textContent = quality.label;
|
|
507
|
+
button.onclick = () => {
|
|
508
|
+
player.setYouTubeQuality(quality.value);
|
|
509
|
+
};
|
|
510
|
+
selector.appendChild(button);
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// Highlight current quality
|
|
515
|
+
player.addEventListener('youtubeplugin:qualitychanged', (data) => {
|
|
516
|
+
console.log('Now playing at:', data.label);
|
|
517
|
+
});
|
|
518
|
+
</script>
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Examples
|
|
524
|
+
|
|
525
|
+
### Example 1: Video Playlist
|
|
526
|
+
|
|
527
|
+
```html
|
|
528
|
+
<video id="myVideo" class="video-player"></video>
|
|
529
|
+
|
|
530
|
+
<div id="playlist">
|
|
531
|
+
<button onclick="loadVideo('dQw4w9WgXcQ')">Video 1</button>
|
|
532
|
+
<button onclick="loadVideo('9bZkp7q19f0')">Video 2</button>
|
|
533
|
+
<button onclick="loadVideo('kJQP7kiw5Fk')">Video 3</button>
|
|
534
|
+
</div>
|
|
535
|
+
|
|
536
|
+
<script>
|
|
537
|
+
const player = new MYETVPlayer('myVideo', {
|
|
538
|
+
plugins: { youtube: {} }
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
function loadVideo(videoId) {
|
|
542
|
+
player.loadYouTubeVideo(videoId);
|
|
543
|
+
}
|
|
544
|
+
</script>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
### Example 2: Quality Presets
|
|
550
|
+
|
|
551
|
+
```javascript
|
|
552
|
+
const player = new MYETVPlayer('myVideo', {
|
|
553
|
+
plugins: { youtube: { videoId: 'dQw4w9WgXcQ' } }
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// Create quality preset buttons
|
|
557
|
+
const qualityPresets = {
|
|
558
|
+
'High': 'hd1080',
|
|
559
|
+
'Medium': 'hd720',
|
|
560
|
+
'Low': 'large',
|
|
561
|
+
'Auto': 'auto'
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
Object.entries(qualityPresets).forEach(([label, quality]) => {
|
|
565
|
+
const btn = document.createElement('button');
|
|
566
|
+
btn.textContent = label;
|
|
567
|
+
btn.onclick = () => player.setYouTubeQuality(quality);
|
|
568
|
+
document.body.appendChild(btn);
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
### Example 3: Video Information Display
|
|
575
|
+
|
|
576
|
+
```javascript
|
|
577
|
+
const player = new MYETVPlayer('myVideo', {
|
|
578
|
+
plugins: { youtube: { videoId: 'dQw4w9WgXcQ' } }
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// Display video info
|
|
582
|
+
player.addEventListener('youtubeplugin:videoloaded', (data) => {
|
|
583
|
+
document.getElementById('video-id').textContent = data.videoId;
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
player.addEventListener('youtubeplugin:qualitiesloaded', (data) => {
|
|
587
|
+
const maxQuality = data.qualities[0]?.label || 'Unknown';
|
|
588
|
+
document.getElementById('max-quality').textContent = maxQuality;
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
player.addEventListener('youtubeplugin:qualitychanged', (data) => {
|
|
592
|
+
document.getElementById('current-quality').textContent = data.label;
|
|
593
|
+
});
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
### Example 4: Error Handling
|
|
599
|
+
|
|
600
|
+
```javascript
|
|
601
|
+
const player = new MYETVPlayer('myVideo', {
|
|
602
|
+
plugins: { youtube: {} }
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// Handle errors gracefully
|
|
606
|
+
player.addEventListener('youtubeplugin:error', (data) => {
|
|
607
|
+
const errorDiv = document.createElement('div');
|
|
608
|
+
errorDiv.className = 'error-message';
|
|
609
|
+
errorDiv.textContent = `Error: ${data.errorMessage}`;
|
|
610
|
+
|
|
611
|
+
document.getElementById('player-container').appendChild(errorDiv);
|
|
612
|
+
|
|
613
|
+
// Try fallback video
|
|
614
|
+
if (data.errorCode === 100 || data.errorCode === 101) {
|
|
615
|
+
setTimeout(() => {
|
|
616
|
+
player.loadYouTubeVideo('FALLBACK_VIDEO_ID');
|
|
617
|
+
}, 3000);
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
### Example 5: Advanced Configuration
|
|
625
|
+
|
|
626
|
+
```javascript
|
|
627
|
+
const player = new MYETVPlayer('myVideo', {
|
|
628
|
+
debug: true,
|
|
629
|
+
plugins: {
|
|
630
|
+
youtube: {
|
|
631
|
+
videoId: 'dQw4w9WgXcQ',
|
|
632
|
+
autoplay: true,
|
|
633
|
+
quality: 'hd720',
|
|
634
|
+
showYouTubeUI: false,
|
|
635
|
+
enableQualityControl: true
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// Track video state
|
|
641
|
+
let watchTime = 0;
|
|
642
|
+
setInterval(() => {
|
|
643
|
+
if (player.isYouTubeActive()) {
|
|
644
|
+
watchTime++;
|
|
645
|
+
console.log('Watch time:', watchTime, 'seconds');
|
|
646
|
+
}
|
|
647
|
+
}, 1000);
|
|
648
|
+
|
|
649
|
+
// Log quality changes
|
|
650
|
+
player.addEventListener('youtubeplugin:qualitychanged', (data) => {
|
|
651
|
+
console.log(`Quality changed from previous to ${data.quality}`);
|
|
652
|
+
});
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
### Example 6: Mobile-Optimized Setup
|
|
658
|
+
|
|
659
|
+
```javascript
|
|
660
|
+
// Detect mobile device
|
|
661
|
+
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
662
|
+
|
|
663
|
+
const player = new MYETVPlayer('myVideo', {
|
|
664
|
+
plugins: {
|
|
665
|
+
youtube: {
|
|
666
|
+
videoId: 'dQw4w9WgXcQ',
|
|
667
|
+
autoplay: false, // Don't autoplay on mobile
|
|
668
|
+
quality: isMobile ? 'large' : 'hd1080', // Lower quality for mobile
|
|
669
|
+
showYouTubeUI: isMobile // Use YouTube UI on mobile
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## FAQ
|
|
678
|
+
|
|
679
|
+
### Q: Does this plugin work without an API key?
|
|
680
|
+
|
|
681
|
+
**A:** Yes! The plugin works perfectly without an API key. The `apiKey` option is reserved for future features that might use the YouTube Data API for fetching video metadata.
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
### Q: Can I play age-restricted videos?
|
|
686
|
+
|
|
687
|
+
**A:** Age-restricted videos may not work in embedded players due to YouTube's policies. You'll receive error code 101 or 150 in such cases.
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
### Q: How do I extract video ID from a YouTube URL?
|
|
692
|
+
|
|
693
|
+
**A:** The plugin automatically extracts video IDs from various URL formats:
|
|
694
|
+
- `https://www.youtube.com/watch?v=dQw4w9WgXcQ`
|
|
695
|
+
- `https://youtu.be/dQw4w9WgXcQ`
|
|
696
|
+
- `https://www.youtube.com/embed/dQw4w9WgXcQ`
|
|
697
|
+
|
|
698
|
+
You can also use the video ID directly: `dQw4w9WgXcQ`
|
|
699
|
+
|
|
700
|
+
---
|
|
701
|
+
|
|
702
|
+
### Q: Can I use both YouTube and regular videos?
|
|
703
|
+
|
|
704
|
+
**A:** Yes! The plugin coexists with regular video playback. Load YouTube videos using plugin methods, and regular videos using standard video sources.
|
|
705
|
+
|
|
706
|
+
```javascript
|
|
707
|
+
// Load YouTube video
|
|
708
|
+
player.loadYouTubeVideo('dQw4w9WgXcQ');
|
|
709
|
+
|
|
710
|
+
// Later, load regular video
|
|
711
|
+
player.video.src = 'local-video.mp4';
|
|
712
|
+
player.play();
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
### Q: Does quality switching work immediately?
|
|
718
|
+
|
|
719
|
+
**A:** Quality switching depends on YouTube's API. The new quality might not apply immediately, especially if the requested quality isn't available or if the video is buffering.
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
### Q: Can I customize the YouTube player appearance?
|
|
724
|
+
|
|
725
|
+
**A:** You can use the `showYouTubeUI` option:
|
|
726
|
+
- `false` (default): Use MYETV Player controls
|
|
727
|
+
- `true`: Show YouTube native controls
|
|
728
|
+
|
|
729
|
+
For advanced customization, YouTube's embedded player has limited styling options due to YouTube's policies.
|
|
730
|
+
|
|
731
|
+
---
|
|
732
|
+
|
|
733
|
+
### Q: How do I handle videos that can't be embedded?
|
|
734
|
+
|
|
735
|
+
**A:** Listen to the error event:
|
|
736
|
+
|
|
737
|
+
```javascript
|
|
738
|
+
player.addEventListener('youtubeplugin:error', (data) => {
|
|
739
|
+
if (data.errorCode === 101 || data.errorCode === 150) {
|
|
740
|
+
// Video cannot be embedded
|
|
741
|
+
// Redirect to YouTube or show message
|
|
742
|
+
window.open(`https://youtube.com/watch?v=${player.getYouTubeVideoId()}`, '_blank');
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
---
|
|
748
|
+
|
|
749
|
+
## Troubleshooting
|
|
750
|
+
|
|
751
|
+
### Issue: YouTube API not loading
|
|
752
|
+
|
|
753
|
+
**Solution:**
|
|
754
|
+
- Check browser console for errors
|
|
755
|
+
- Ensure internet connection is active
|
|
756
|
+
- Verify no ad blockers are blocking YouTube scripts
|
|
757
|
+
- Check for CSP (Content Security Policy) restrictions
|
|
758
|
+
|
|
759
|
+
```javascript
|
|
760
|
+
// Listen for API ready event
|
|
761
|
+
player.addEventListener('youtubeplugin:ready', () => {
|
|
762
|
+
console.log('YouTube API loaded successfully');
|
|
763
|
+
});
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
### Issue: Video not playing
|
|
769
|
+
|
|
770
|
+
**Possible causes:**
|
|
771
|
+
1. Invalid video ID
|
|
772
|
+
2. Video is private or deleted
|
|
773
|
+
3. Video is age-restricted
|
|
774
|
+
4. Video cannot be embedded
|
|
775
|
+
|
|
776
|
+
**Solution:**
|
|
777
|
+
```javascript
|
|
778
|
+
player.addEventListener('youtubeplugin:error', (data) => {
|
|
779
|
+
console.error('Error:', data.errorCode, data.errorMessage);
|
|
780
|
+
// Handle accordingly
|
|
781
|
+
});
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
|
|
786
|
+
### Issue: Quality not changing
|
|
787
|
+
|
|
788
|
+
**Solution:**
|
|
789
|
+
- Ensure `enableQualityControl` is true
|
|
790
|
+
- Check if requested quality is available using `getYouTubeQualities()`
|
|
791
|
+
- Quality changes may take a few seconds to apply
|
|
792
|
+
|
|
793
|
+
```javascript
|
|
794
|
+
// Check available qualities first
|
|
795
|
+
player.addEventListener('youtubeplugin:qualitiesloaded', (data) => {
|
|
796
|
+
console.log('Available:', data.qualities);
|
|
797
|
+
|
|
798
|
+
// Set quality only if available
|
|
799
|
+
if (data.qualities.some(q => q.value === 'hd1080')) {
|
|
800
|
+
player.setYouTubeQuality('hd1080');
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
---
|
|
806
|
+
|
|
807
|
+
### Issue: Controls not synchronizing
|
|
808
|
+
|
|
809
|
+
**Solution:**
|
|
810
|
+
- Ensure plugin is loaded after core player
|
|
811
|
+
- Check for JavaScript errors in console
|
|
812
|
+
- Verify `showYouTubeUI` is set correctly
|
|
813
|
+
|
|
814
|
+
---
|
|
815
|
+
|
|
816
|
+
### Debug Mode
|
|
817
|
+
|
|
818
|
+
Enable debug mode to see detailed logs:
|
|
819
|
+
|
|
820
|
+
```javascript
|
|
821
|
+
const player = new MYETVPlayer('myVideo', {
|
|
822
|
+
debug: true,
|
|
823
|
+
plugins: { youtube: { videoId: 'dQw4w9WgXcQ' } }
|
|
824
|
+
});
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
Debug messages will appear in the browser console with the `[YouTube Plugin]` prefix.
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## Resources
|
|
832
|
+
|
|
833
|
+
- **MYETV Player**: [https://www.myetv.tv](https://www.myetv.tv)
|
|
834
|
+
- **YouTube IFrame API**: [YouTube IFrame Player API Documentation](https://developers.google.com/youtube/iframe_api_reference)
|
|
835
|
+
- **GitHub**: [MYETV Video Player Open Source](https://github.com/OskarCosimo/myetv-video-player-opensource/)
|
|
836
|
+
- **Author**: [https://oskarcosimo.com](https://oskarcosimo.com)
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## License
|
|
841
|
+
|
|
842
|
+
MIT License - See main project for details.
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## Contributing
|
|
847
|
+
|
|
848
|
+
Contributions are welcome! Please submit pull requests or open issues on GitHub.
|
|
849
|
+
|
|
850
|
+
---
|
|
851
|
+
|
|
852
|
+
**Enjoy seamless YouTube integration!**
|