myetv-player 1.0.0 → 1.0.6
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 +36 -58
- package/SECURITY.md +50 -0
- package/css/myetv-player.css +301 -218
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +1713 -1503
- package/dist/myetv-player.min.js +1670 -1471
- package/package.json +6 -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/_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 +16 -4
- package/src/core.js +1192 -1062
- package/src/i18n.js +27 -1
- package/src/quality.js +478 -436
- package/src/subtitles.js +2 -2
|
@@ -0,0 +1,1185 @@
|
|
|
1
|
+
# MYETV Player - Twitch Plugin
|
|
2
|
+
Official Twitch integration plugin for MYETV Video Player. Embed live streams and VODs with full API control and interactive features.
|
|
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
|
+
- [Parent Domains (Important!)](#parent-domains-important)
|
|
13
|
+
- [Usage Methods](#usage-methods)
|
|
14
|
+
- [API Methods](#api-methods)
|
|
15
|
+
- [Events](#events)
|
|
16
|
+
- [Live Streams vs VODs](#live-streams-vs-vods)
|
|
17
|
+
- [Examples](#examples)
|
|
18
|
+
- [FAQ](#faq)
|
|
19
|
+
- [Troubleshooting](#troubleshooting)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Full Twitch Integration**: Embed live streams, VODs, and collections
|
|
26
|
+
- **Live Streaming**: Real-time live stream playback with chat support
|
|
27
|
+
- **Video on Demand**: Play Twitch VODs with full playback control
|
|
28
|
+
- **Smart Detection**: Auto-detects Twitch URLs from multiple sources
|
|
29
|
+
- **Quality Control**: Manage video quality with available stream qualities
|
|
30
|
+
- **Complete API**: Full control over playback, volume, seeking, and more
|
|
31
|
+
- **Playback Stats**: Access detailed playback statistics
|
|
32
|
+
- **Stream Status**: Detect when streams go online/offline
|
|
33
|
+
- **Easy Integration**: Seamless integration with MYETV Player
|
|
34
|
+
- **Responsive**: Works on desktop and mobile devices
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
### Method 1: Direct Script Include
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<!-- Load MYETV Player Core -->
|
|
44
|
+
<script src="dist/myetv-player.js"></script>
|
|
45
|
+
|
|
46
|
+
<!-- Load Twitch Plugin -->
|
|
47
|
+
<script src="plugins/myetv-player-twitch-plugin.js"></script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Method 2: Module Import
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import MYETVPlayer from './myetv-player.js';
|
|
54
|
+
import './plugins/myetv-player-twitch-plugin.js';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
### Live Stream Example
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<!DOCTYPE html>
|
|
65
|
+
<html lang="en">
|
|
66
|
+
<head>
|
|
67
|
+
<meta charset="UTF-8">
|
|
68
|
+
<title>MYETV Player - Twitch Live Stream</title>
|
|
69
|
+
<link rel="stylesheet" href="dist/myetv-player.css">
|
|
70
|
+
</head>
|
|
71
|
+
<body>
|
|
72
|
+
<!-- Video Element -->
|
|
73
|
+
<video id="myVideo" class="video-player"></video>
|
|
74
|
+
|
|
75
|
+
<script src="dist/myetv-player.js"></script>
|
|
76
|
+
<script src="plugins/myetv-player-twitch-plugin.js"></script>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
// Initialize player with Twitch live stream
|
|
80
|
+
const player = new MYETVPlayer('myVideo', {
|
|
81
|
+
debug: true,
|
|
82
|
+
plugins: {
|
|
83
|
+
twitch: {
|
|
84
|
+
channel: 'shroud', // Twitch channel name
|
|
85
|
+
parent: ['yourdomain.com'], // REQUIRED!
|
|
86
|
+
autoplay: true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
</script>
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### VOD (Video on Demand) Example
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<script>
|
|
99
|
+
const player = new MYETVPlayer('myVideo', {
|
|
100
|
+
plugins: {
|
|
101
|
+
twitch: {
|
|
102
|
+
video: '1234567890', // Twitch VOD ID
|
|
103
|
+
parent: ['yourdomain.com'],
|
|
104
|
+
time: '1h30m0s' // Start at 1 hour 30 minutes
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Configuration Options
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
const player = new MYETVPlayer('myVideo', {
|
|
117
|
+
plugins: {
|
|
118
|
+
twitch: {
|
|
119
|
+
// ========== Video Source (choose one) ==========
|
|
120
|
+
// For live streams
|
|
121
|
+
channel: 'shroud',
|
|
122
|
+
|
|
123
|
+
// OR for VODs (Video on Demand)
|
|
124
|
+
video: '1234567890',
|
|
125
|
+
|
|
126
|
+
// OR for collections
|
|
127
|
+
collection: 'abc123xyz',
|
|
128
|
+
|
|
129
|
+
// ========== Parent Domains (REQUIRED!) ==========
|
|
130
|
+
parent: ['yourdomain.com', 'www.yourdomain.com'],
|
|
131
|
+
|
|
132
|
+
// ========== Player Dimensions ==========
|
|
133
|
+
width: '100%', // Width (pixels or percentage)
|
|
134
|
+
height: '100%', // Height (pixels or percentage)
|
|
135
|
+
|
|
136
|
+
// ========== Playback Options ==========
|
|
137
|
+
autoplay: true, // Auto-play on load
|
|
138
|
+
muted: false, // Start muted
|
|
139
|
+
time: '0h0m0s', // Start time for VODs (e.g., '1h30m45s')
|
|
140
|
+
|
|
141
|
+
// ========== UI Options ==========
|
|
142
|
+
allowfullscreen: true, // Enable fullscreen button
|
|
143
|
+
|
|
144
|
+
// ========== Plugin Options ==========
|
|
145
|
+
debug: false, // Enable debug logging
|
|
146
|
+
replaceNativePlayer: true, // Replace native video element
|
|
147
|
+
autoLoadFromData: true // Auto-detect from data attributes
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Time Format
|
|
154
|
+
For VODs, use format: `'1h30m45s'` where:
|
|
155
|
+
- `h` = hours
|
|
156
|
+
- `m` = minutes
|
|
157
|
+
- `s` = seconds
|
|
158
|
+
|
|
159
|
+
Examples:
|
|
160
|
+
- `'0h0m0s'` - Start from beginning
|
|
161
|
+
- `'1h0m0s'` - Start at 1 hour
|
|
162
|
+
- `'0h30m0s'` - Start at 30 minutes
|
|
163
|
+
- `'2h15m30s'` - Start at 2 hours, 15 minutes, 30 seconds
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Parent Domains (Important!)
|
|
168
|
+
|
|
169
|
+
**CRITICAL**: Twitch requires you to specify parent domains where the player will be embedded. This is a security feature.
|
|
170
|
+
|
|
171
|
+
### What are parent domains?
|
|
172
|
+
The `parent` parameter must include all domains where your page will be loaded.
|
|
173
|
+
|
|
174
|
+
### Examples:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Single domain
|
|
178
|
+
parent: ['mysite.com']
|
|
179
|
+
|
|
180
|
+
// Multiple domains (with and without www)
|
|
181
|
+
parent: ['mysite.com', 'www.mysite.com']
|
|
182
|
+
|
|
183
|
+
// For development
|
|
184
|
+
parent: ['localhost']
|
|
185
|
+
|
|
186
|
+
// For embedded sites
|
|
187
|
+
parent: ['mysite.com', 'embed.mysite.com', 'cdn.mysite.com']
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Important Notes:
|
|
191
|
+
- **Do NOT include protocol** (http://, https://)
|
|
192
|
+
- **Do NOT include port** (localhost:3000)
|
|
193
|
+
- **Do NOT include paths** (/page/video)
|
|
194
|
+
- **Just the hostname**: `example.com`
|
|
195
|
+
|
|
196
|
+
### What happens if parent is wrong?
|
|
197
|
+
The player will show an error: "This video is not available on this domain"
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Usage Methods
|
|
202
|
+
|
|
203
|
+
### Method 1: Live Stream by Channel Name
|
|
204
|
+
|
|
205
|
+
```html
|
|
206
|
+
<video id="myVideo" class="video-player"></video>
|
|
207
|
+
|
|
208
|
+
<script>
|
|
209
|
+
const player = new MYETVPlayer('myVideo', {
|
|
210
|
+
plugins: {
|
|
211
|
+
twitch: {
|
|
212
|
+
channel: 'shroud',
|
|
213
|
+
parent: ['yourdomain.com']
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
</script>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### Method 2: VOD by Video ID
|
|
223
|
+
|
|
224
|
+
```html
|
|
225
|
+
<video id="myVideo" class="video-player"></video>
|
|
226
|
+
|
|
227
|
+
<script>
|
|
228
|
+
const player = new MYETVPlayer('myVideo', {
|
|
229
|
+
plugins: {
|
|
230
|
+
twitch: {
|
|
231
|
+
video: '1234567890',
|
|
232
|
+
parent: ['yourdomain.com'],
|
|
233
|
+
time: '0h30m0s' // Start at 30 minutes
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
</script>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### Method 3: Using Data Attributes
|
|
243
|
+
|
|
244
|
+
```html
|
|
245
|
+
<video id="myVideo" class="video-player"
|
|
246
|
+
data-twitch-channel="shroud"
|
|
247
|
+
data-video-type="twitch">
|
|
248
|
+
</video>
|
|
249
|
+
|
|
250
|
+
<script>
|
|
251
|
+
const player = new MYETVPlayer('myVideo', {
|
|
252
|
+
plugins: {
|
|
253
|
+
twitch: {
|
|
254
|
+
parent: ['yourdomain.com'],
|
|
255
|
+
autoLoadFromData: true
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
</script>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### Method 4: Using Twitch URLs
|
|
265
|
+
|
|
266
|
+
```html
|
|
267
|
+
<video id="myVideo" class="video-player"
|
|
268
|
+
src="https://www.twitch.tv/shroud">
|
|
269
|
+
</video>
|
|
270
|
+
|
|
271
|
+
<script>
|
|
272
|
+
const player = new MYETVPlayer('myVideo', {
|
|
273
|
+
plugins: {
|
|
274
|
+
twitch: {
|
|
275
|
+
parent: ['yourdomain.com']
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
</script>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Supported URL Formats:**
|
|
283
|
+
- `https://www.twitch.tv/channelname` (live stream)
|
|
284
|
+
- `https://www.twitch.tv/videos/1234567890` (VOD)
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
### Method 5: Load Dynamically
|
|
289
|
+
|
|
290
|
+
```html
|
|
291
|
+
<video id="myVideo" class="video-player"></video>
|
|
292
|
+
|
|
293
|
+
<script>
|
|
294
|
+
const player = new MYETVPlayer('myVideo', {
|
|
295
|
+
plugins: {
|
|
296
|
+
twitch: {
|
|
297
|
+
parent: ['yourdomain.com']
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
303
|
+
|
|
304
|
+
// Load channel
|
|
305
|
+
twitchPlugin.loadChannel('shroud');
|
|
306
|
+
|
|
307
|
+
// Or load VOD
|
|
308
|
+
twitchPlugin.loadVideo('1234567890', '1h0m0s');
|
|
309
|
+
</script>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## API Methods
|
|
315
|
+
|
|
316
|
+
Get the plugin instance:
|
|
317
|
+
```javascript
|
|
318
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Playback Control
|
|
322
|
+
|
|
323
|
+
#### `play()`
|
|
324
|
+
Play the stream/video.
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
twitchPlugin.play().then(() => {
|
|
328
|
+
console.log('Playing');
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Returns:** Promise
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
#### `pause()`
|
|
337
|
+
Pause the stream/video.
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
twitchPlugin.pause().then(() => {
|
|
341
|
+
console.log('Paused');
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Returns:** Promise
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
#### `seek(seconds)`
|
|
350
|
+
Seek to position (VODs only).
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
twitchPlugin.seek(120).then(() => {
|
|
354
|
+
console.log('Seeked to 2 minutes');
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Parameters:**
|
|
359
|
+
- `seconds` (Number): Position in seconds
|
|
360
|
+
|
|
361
|
+
**Returns:** Promise
|
|
362
|
+
|
|
363
|
+
**Note:** Seeking only works for VODs, not live streams.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
#### `getCurrentTime()`
|
|
368
|
+
Get current playback position.
|
|
369
|
+
|
|
370
|
+
```javascript
|
|
371
|
+
twitchPlugin.getCurrentTime().then(time => {
|
|
372
|
+
console.log('Current time:', time, 'seconds');
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Returns:** Promise<Number>
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
#### `getDuration()`
|
|
381
|
+
Get video duration (VODs only).
|
|
382
|
+
|
|
383
|
+
```javascript
|
|
384
|
+
twitchPlugin.getDuration().then(duration => {
|
|
385
|
+
console.log('Duration:', duration, 'seconds');
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Returns:** Promise<Number>
|
|
390
|
+
|
|
391
|
+
**Note:** Returns 0 for live streams.
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
#### `isPaused()`
|
|
396
|
+
Check if player is paused.
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
twitchPlugin.isPaused().then(paused => {
|
|
400
|
+
console.log('Is paused:', paused);
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Returns:** Promise<Boolean>
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### Volume Control
|
|
409
|
+
|
|
410
|
+
#### `setVolume(volume)`
|
|
411
|
+
Set volume level.
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
twitchPlugin.setVolume(0.5).then(() => {
|
|
415
|
+
console.log('Volume set to 50%');
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Parameters:**
|
|
420
|
+
- `volume` (Number): Volume level (0-1)
|
|
421
|
+
|
|
422
|
+
**Returns:** Promise
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
#### `getVolume()`
|
|
427
|
+
Get current volume.
|
|
428
|
+
|
|
429
|
+
```javascript
|
|
430
|
+
twitchPlugin.getVolume().then(volume => {
|
|
431
|
+
console.log('Current volume:', volume);
|
|
432
|
+
});
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Returns:** Promise<Number>
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
#### `setMuted(muted)`
|
|
440
|
+
Mute or unmute.
|
|
441
|
+
|
|
442
|
+
```javascript
|
|
443
|
+
twitchPlugin.setMuted(true).then(() => {
|
|
444
|
+
console.log('Muted');
|
|
445
|
+
});
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Parameters:**
|
|
449
|
+
- `muted` (Boolean): Mute state
|
|
450
|
+
|
|
451
|
+
**Returns:** Promise
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
#### `getMuted()`
|
|
456
|
+
Get muted state.
|
|
457
|
+
|
|
458
|
+
```javascript
|
|
459
|
+
twitchPlugin.getMuted().then(muted => {
|
|
460
|
+
console.log('Is muted:', muted);
|
|
461
|
+
});
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Returns:** Promise<Boolean>
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
### Quality Control
|
|
469
|
+
|
|
470
|
+
#### `getQuality()`
|
|
471
|
+
Get current quality.
|
|
472
|
+
|
|
473
|
+
```javascript
|
|
474
|
+
twitchPlugin.getQuality().then(quality => {
|
|
475
|
+
console.log('Current quality:', quality);
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**Returns:** Promise<String>
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
#### `setQuality(quality)`
|
|
484
|
+
Set video quality.
|
|
485
|
+
|
|
486
|
+
```javascript
|
|
487
|
+
twitchPlugin.setQuality('720p60').then(() => {
|
|
488
|
+
console.log('Quality set to 720p60');
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Parameters:**
|
|
493
|
+
- `quality` (String): Quality identifier
|
|
494
|
+
|
|
495
|
+
**Returns:** Promise
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
#### `getQualities()`
|
|
500
|
+
Get available qualities.
|
|
501
|
+
|
|
502
|
+
```javascript
|
|
503
|
+
twitchPlugin.getQualities().then(qualities => {
|
|
504
|
+
console.log('Available qualities:', qualities);
|
|
505
|
+
});
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**Returns:** Promise<Array>
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
### Video/Channel Management
|
|
513
|
+
|
|
514
|
+
#### `loadChannel(channel)`
|
|
515
|
+
Load a Twitch channel (live stream).
|
|
516
|
+
|
|
517
|
+
```javascript
|
|
518
|
+
twitchPlugin.loadChannel('shroud').then(() => {
|
|
519
|
+
console.log('Channel loaded');
|
|
520
|
+
});
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**Parameters:**
|
|
524
|
+
- `channel` (String): Twitch channel name
|
|
525
|
+
|
|
526
|
+
**Returns:** Promise
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
#### `loadVideo(videoId, timestamp)`
|
|
531
|
+
Load a VOD.
|
|
532
|
+
|
|
533
|
+
```javascript
|
|
534
|
+
twitchPlugin.loadVideo('1234567890', '1h30m0s').then(() => {
|
|
535
|
+
console.log('VOD loaded');
|
|
536
|
+
});
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**Parameters:**
|
|
540
|
+
- `videoId` (String): Twitch video ID
|
|
541
|
+
- `timestamp` (String): Start time (optional, default: '0h0m0s')
|
|
542
|
+
|
|
543
|
+
**Returns:** Promise
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
#### `loadCollection(collectionId, videoId)`
|
|
548
|
+
Load a collection.
|
|
549
|
+
|
|
550
|
+
```javascript
|
|
551
|
+
twitchPlugin.loadCollection('abc123', '1234567890').then(() => {
|
|
552
|
+
console.log('Collection loaded');
|
|
553
|
+
});
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Parameters:**
|
|
557
|
+
- `collectionId` (String): Collection ID
|
|
558
|
+
- `videoId` (String): Video ID to start from (optional)
|
|
559
|
+
|
|
560
|
+
**Returns:** Promise
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
#### `getChannel()`
|
|
565
|
+
Get current channel name.
|
|
566
|
+
|
|
567
|
+
```javascript
|
|
568
|
+
twitchPlugin.getChannel().then(channel => {
|
|
569
|
+
console.log('Current channel:', channel);
|
|
570
|
+
});
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
**Returns:** Promise<String>
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
#### `getVideo()`
|
|
578
|
+
Get current video ID.
|
|
579
|
+
|
|
580
|
+
```javascript
|
|
581
|
+
twitchPlugin.getVideo().then(video => {
|
|
582
|
+
console.log('Current video:', video);
|
|
583
|
+
});
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Returns:** Promise<String>
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
### Playback Stats
|
|
591
|
+
|
|
592
|
+
#### `getPlaybackStats()`
|
|
593
|
+
Get detailed playback statistics.
|
|
594
|
+
|
|
595
|
+
```javascript
|
|
596
|
+
twitchPlugin.getPlaybackStats().then(stats => {
|
|
597
|
+
console.log('Playback stats:', stats);
|
|
598
|
+
console.log('Backend version:', stats.backendVersion);
|
|
599
|
+
console.log('Buffer size:', stats.bufferSize);
|
|
600
|
+
console.log('Codecs:', stats.codecs);
|
|
601
|
+
console.log('Display resolution:', stats.displayResolution);
|
|
602
|
+
console.log('FPS:', stats.fps);
|
|
603
|
+
console.log('HLS latency:', stats.hlsLatencyBroadcaster);
|
|
604
|
+
console.log('Playback rate:', stats.playbackRate);
|
|
605
|
+
console.log('Skipped frames:', stats.skippedFrames);
|
|
606
|
+
console.log('Video resolution:', stats.videoResolution);
|
|
607
|
+
});
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
**Returns:** Promise<Object>
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## 📡 Events
|
|
615
|
+
|
|
616
|
+
### Playback Events
|
|
617
|
+
|
|
618
|
+
#### `play`
|
|
619
|
+
Video started playing.
|
|
620
|
+
|
|
621
|
+
```javascript
|
|
622
|
+
player.addEventListener('play', () => {
|
|
623
|
+
console.log('Playing');
|
|
624
|
+
});
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
#### `playing`
|
|
630
|
+
Video is actively playing.
|
|
631
|
+
|
|
632
|
+
```javascript
|
|
633
|
+
player.addEventListener('playing', () => {
|
|
634
|
+
console.log('Playing');
|
|
635
|
+
});
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
#### `pause`
|
|
641
|
+
Video paused.
|
|
642
|
+
|
|
643
|
+
```javascript
|
|
644
|
+
player.addEventListener('pause', () => {
|
|
645
|
+
console.log('Paused');
|
|
646
|
+
});
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
#### `ended`
|
|
652
|
+
Video ended (VODs only).
|
|
653
|
+
|
|
654
|
+
```javascript
|
|
655
|
+
player.addEventListener('ended', () => {
|
|
656
|
+
console.log('Video ended');
|
|
657
|
+
});
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
### Plugin-Specific Events
|
|
663
|
+
|
|
664
|
+
#### `twitchplugin:ready`
|
|
665
|
+
Player is ready.
|
|
666
|
+
|
|
667
|
+
```javascript
|
|
668
|
+
player.addEventListener('twitchplugin:ready', () => {
|
|
669
|
+
console.log('Twitch player ready');
|
|
670
|
+
});
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
#### `twitchplugin:playerready`
|
|
676
|
+
Player created and initialized.
|
|
677
|
+
|
|
678
|
+
```javascript
|
|
679
|
+
player.addEventListener('twitchplugin:playerready', (data) => {
|
|
680
|
+
console.log('Channel:', data.channel);
|
|
681
|
+
console.log('Video:', data.video);
|
|
682
|
+
console.log('Is live:', data.isLive);
|
|
683
|
+
});
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
#### `twitchplugin:online`
|
|
689
|
+
Stream went online (for channels).
|
|
690
|
+
|
|
691
|
+
```javascript
|
|
692
|
+
player.addEventListener('twitchplugin:online', () => {
|
|
693
|
+
console.log('Stream is now live!');
|
|
694
|
+
});
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
---
|
|
698
|
+
|
|
699
|
+
#### `twitchplugin:offline`
|
|
700
|
+
Stream went offline.
|
|
701
|
+
|
|
702
|
+
```javascript
|
|
703
|
+
player.addEventListener('twitchplugin:offline', () => {
|
|
704
|
+
console.log('Stream went offline');
|
|
705
|
+
});
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
#### `twitchplugin:playbackblocked`
|
|
711
|
+
Playback blocked by browser (autoplay restrictions).
|
|
712
|
+
|
|
713
|
+
```javascript
|
|
714
|
+
player.addEventListener('twitchplugin:playbackblocked', () => {
|
|
715
|
+
console.log('Playback blocked - user interaction required');
|
|
716
|
+
// Show play button or prompt user
|
|
717
|
+
});
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
#### `twitchplugin:channelloaded`
|
|
723
|
+
New channel loaded.
|
|
724
|
+
|
|
725
|
+
```javascript
|
|
726
|
+
player.addEventListener('twitchplugin:channelloaded', (data) => {
|
|
727
|
+
console.log('Channel loaded:', data.channel);
|
|
728
|
+
});
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
---
|
|
732
|
+
|
|
733
|
+
#### `twitchplugin:videoloaded`
|
|
734
|
+
New VOD loaded.
|
|
735
|
+
|
|
736
|
+
```javascript
|
|
737
|
+
player.addEventListener('twitchplugin:videoloaded', (data) => {
|
|
738
|
+
console.log('Video loaded:', data.video);
|
|
739
|
+
console.log('Timestamp:', data.timestamp);
|
|
740
|
+
});
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
---
|
|
744
|
+
|
|
745
|
+
## Live Streams vs VODs
|
|
746
|
+
|
|
747
|
+
### Live Streams
|
|
748
|
+
|
|
749
|
+
**Characteristics:**
|
|
750
|
+
- Real-time playback
|
|
751
|
+
- No seeking (always "live")
|
|
752
|
+
- Duration is 0
|
|
753
|
+
- Can detect online/offline status
|
|
754
|
+
- May have latency
|
|
755
|
+
|
|
756
|
+
**Example:**
|
|
757
|
+
```javascript
|
|
758
|
+
plugins: {
|
|
759
|
+
twitch: {
|
|
760
|
+
channel: 'shroud',
|
|
761
|
+
parent: ['yourdomain.com']
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
### VODs (Video on Demand)
|
|
769
|
+
|
|
770
|
+
**Characteristics:**
|
|
771
|
+
- Full playback control
|
|
772
|
+
- Seeking available
|
|
773
|
+
- Has defined duration
|
|
774
|
+
- Start from specific timestamp
|
|
775
|
+
- No online/offline events
|
|
776
|
+
|
|
777
|
+
**Example:**
|
|
778
|
+
```javascript
|
|
779
|
+
plugins: {
|
|
780
|
+
twitch: {
|
|
781
|
+
video: '1234567890',
|
|
782
|
+
time: '1h30m0s', // Start at 1h30m
|
|
783
|
+
parent: ['yourdomain.com']
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
### Check Stream Type
|
|
791
|
+
|
|
792
|
+
```javascript
|
|
793
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
794
|
+
|
|
795
|
+
if (player.isTwitchLive()) {
|
|
796
|
+
console.log('Watching a live stream');
|
|
797
|
+
} else {
|
|
798
|
+
console.log('Watching a VOD');
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
---
|
|
803
|
+
|
|
804
|
+
## Examples
|
|
805
|
+
|
|
806
|
+
### Example 1: Channel Switcher
|
|
807
|
+
|
|
808
|
+
```html
|
|
809
|
+
<video id="myVideo" class="video-player"></video>
|
|
810
|
+
|
|
811
|
+
<div id="channel-switcher">
|
|
812
|
+
<button onclick="switchChannel('shroud')">Shroud</button>
|
|
813
|
+
<button onclick="switchChannel('ninja')">Ninja</button>
|
|
814
|
+
<button onclick="switchChannel('pokimane')">Pokimane</button>
|
|
815
|
+
</div>
|
|
816
|
+
|
|
817
|
+
<script>
|
|
818
|
+
const player = new MYETVPlayer('myVideo', {
|
|
819
|
+
plugins: {
|
|
820
|
+
twitch: {
|
|
821
|
+
parent: ['yourdomain.com']
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
827
|
+
|
|
828
|
+
function switchChannel(channel) {
|
|
829
|
+
twitchPlugin.loadChannel(channel).then(() => {
|
|
830
|
+
console.log('Switched to:', channel);
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
</script>
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
### Example 2: VOD Player with Controls
|
|
839
|
+
|
|
840
|
+
```html
|
|
841
|
+
<video id="myVideo" class="video-player"></video>
|
|
842
|
+
|
|
843
|
+
<div id="custom-controls">
|
|
844
|
+
<button id="playBtn">Play</button>
|
|
845
|
+
<button id="pauseBtn">Pause</button>
|
|
846
|
+
<input type="range" id="seekBar" min="0" max="100" value="0">
|
|
847
|
+
<span id="timeDisplay">0:00 / 0:00</span>
|
|
848
|
+
</div>
|
|
849
|
+
|
|
850
|
+
<script>
|
|
851
|
+
const player = new MYETVPlayer('myVideo', {
|
|
852
|
+
plugins: {
|
|
853
|
+
twitch: {
|
|
854
|
+
video: '1234567890',
|
|
855
|
+
parent: ['yourdomain.com']
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
861
|
+
|
|
862
|
+
// Play button
|
|
863
|
+
document.getElementById('playBtn').onclick = () => {
|
|
864
|
+
twitchPlugin.play();
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
// Pause button
|
|
868
|
+
document.getElementById('pauseBtn').onclick = () => {
|
|
869
|
+
twitchPlugin.pause();
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// Seek bar
|
|
873
|
+
document.getElementById('seekBar').oninput = (e) => {
|
|
874
|
+
twitchPlugin.getDuration().then(duration => {
|
|
875
|
+
const seekTo = (e.target.value / 100) * duration;
|
|
876
|
+
twitchPlugin.seek(seekTo);
|
|
877
|
+
});
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
// Update time display
|
|
881
|
+
setInterval(() => {
|
|
882
|
+
Promise.all([
|
|
883
|
+
twitchPlugin.getCurrentTime(),
|
|
884
|
+
twitchPlugin.getDuration()
|
|
885
|
+
]).then(([current, duration]) => {
|
|
886
|
+
const seekBar = document.getElementById('seekBar');
|
|
887
|
+
seekBar.value = (current / duration) * 100;
|
|
888
|
+
|
|
889
|
+
document.getElementById('timeDisplay').textContent =
|
|
890
|
+
`${formatTime(current)} / ${formatTime(duration)}`;
|
|
891
|
+
});
|
|
892
|
+
}, 1000);
|
|
893
|
+
|
|
894
|
+
function formatTime(seconds) {
|
|
895
|
+
const mins = Math.floor(seconds / 60);
|
|
896
|
+
const secs = Math.floor(seconds % 60);
|
|
897
|
+
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
898
|
+
}
|
|
899
|
+
</script>
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
---
|
|
903
|
+
|
|
904
|
+
### Example 3: Stream Status Indicator
|
|
905
|
+
|
|
906
|
+
```html
|
|
907
|
+
<video id="myVideo" class="video-player"></video>
|
|
908
|
+
|
|
909
|
+
<div id="status">
|
|
910
|
+
<span id="indicator" style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: gray;"></span>
|
|
911
|
+
<span id="status-text">Checking...</span>
|
|
912
|
+
</div>
|
|
913
|
+
|
|
914
|
+
<script>
|
|
915
|
+
const player = new MYETVPlayer('myVideo', {
|
|
916
|
+
plugins: {
|
|
917
|
+
twitch: {
|
|
918
|
+
channel: 'shroud',
|
|
919
|
+
parent: ['yourdomain.com']
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
const indicator = document.getElementById('indicator');
|
|
925
|
+
const statusText = document.getElementById('status-text');
|
|
926
|
+
|
|
927
|
+
// Stream went online
|
|
928
|
+
player.addEventListener('twitchplugin:online', () => {
|
|
929
|
+
indicator.style.background = '#00ff00';
|
|
930
|
+
statusText.textContent = 'LIVE';
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
// Stream went offline
|
|
934
|
+
player.addEventListener('twitchplugin:offline', () => {
|
|
935
|
+
indicator.style.background = '#ff0000';
|
|
936
|
+
statusText.textContent = 'OFFLINE';
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
// Player ready
|
|
940
|
+
player.addEventListener('twitchplugin:ready', () => {
|
|
941
|
+
indicator.style.background = '#00ff00';
|
|
942
|
+
statusText.textContent = 'LIVE';
|
|
943
|
+
});
|
|
944
|
+
</script>
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
---
|
|
948
|
+
|
|
949
|
+
### Example 4: Quality Selector
|
|
950
|
+
|
|
951
|
+
```html
|
|
952
|
+
<video id="myVideo" class="video-player"></video>
|
|
953
|
+
|
|
954
|
+
<div id="quality-selector"></div>
|
|
955
|
+
|
|
956
|
+
<script>
|
|
957
|
+
const player = new MYETVPlayer('myVideo', {
|
|
958
|
+
plugins: {
|
|
959
|
+
twitch: {
|
|
960
|
+
channel: 'shroud',
|
|
961
|
+
parent: ['yourdomain.com']
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
967
|
+
|
|
968
|
+
// Wait for player ready
|
|
969
|
+
player.addEventListener('twitchplugin:ready', () => {
|
|
970
|
+
// Get available qualities
|
|
971
|
+
twitchPlugin.getQualities().then(qualities => {
|
|
972
|
+
const selector = document.getElementById('quality-selector');
|
|
973
|
+
|
|
974
|
+
qualities.forEach(quality => {
|
|
975
|
+
const btn = document.createElement('button');
|
|
976
|
+
btn.textContent = quality;
|
|
977
|
+
btn.onclick = () => {
|
|
978
|
+
twitchPlugin.setQuality(quality).then(() => {
|
|
979
|
+
console.log('Quality set to:', quality);
|
|
980
|
+
});
|
|
981
|
+
};
|
|
982
|
+
selector.appendChild(btn);
|
|
983
|
+
});
|
|
984
|
+
});
|
|
985
|
+
});
|
|
986
|
+
</script>
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
---
|
|
990
|
+
|
|
991
|
+
### Example 5: Playback Stats Display
|
|
992
|
+
|
|
993
|
+
```html
|
|
994
|
+
<video id="myVideo" class="video-player"></video>
|
|
995
|
+
|
|
996
|
+
<div id="stats" style="font-family: monospace; font-size: 12px;"></div>
|
|
997
|
+
|
|
998
|
+
<script>
|
|
999
|
+
const player = new MYETVPlayer('myVideo', {
|
|
1000
|
+
plugins: {
|
|
1001
|
+
twitch: {
|
|
1002
|
+
channel: 'shroud',
|
|
1003
|
+
parent: ['yourdomain.com']
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
const twitchPlugin = player.getPlugin('twitch');
|
|
1009
|
+
|
|
1010
|
+
// Update stats every second
|
|
1011
|
+
setInterval(() => {
|
|
1012
|
+
twitchPlugin.getPlaybackStats().then(stats => {
|
|
1013
|
+
const statsDiv = document.getElementById('stats');
|
|
1014
|
+
statsDiv.innerHTML = `
|
|
1015
|
+
Resolution: ${stats.videoResolution}<br>
|
|
1016
|
+
FPS: ${stats.fps}<br>
|
|
1017
|
+
Codecs: ${stats.codecs}<br>
|
|
1018
|
+
Bitrate: ${(stats.bitrate / 1000).toFixed(2)} Mbps<br>
|
|
1019
|
+
Buffer: ${stats.bufferSize}s<br>
|
|
1020
|
+
Skipped Frames: ${stats.skippedFrames}
|
|
1021
|
+
`;
|
|
1022
|
+
});
|
|
1023
|
+
}, 1000);
|
|
1024
|
+
</script>
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
---
|
|
1028
|
+
|
|
1029
|
+
## FAQ
|
|
1030
|
+
|
|
1031
|
+
### Q: What's the difference between channel and video?
|
|
1032
|
+
|
|
1033
|
+
**A:**
|
|
1034
|
+
- `channel`: Live stream from a Twitch channel (e.g., 'shroud')
|
|
1035
|
+
- `video`: VOD (Video on Demand) with a specific ID (e.g., '1234567890')
|
|
1036
|
+
|
|
1037
|
+
---
|
|
1038
|
+
|
|
1039
|
+
### Q: Why do I see "This video is not available on this domain"?
|
|
1040
|
+
|
|
1041
|
+
**A:** Your `parent` domains are incorrect. Make sure to include the exact hostname where your page is hosted.
|
|
1042
|
+
|
|
1043
|
+
```javascript
|
|
1044
|
+
// Correct
|
|
1045
|
+
parent: ['mysite.com']
|
|
1046
|
+
|
|
1047
|
+
// Wrong
|
|
1048
|
+
parent: ['https://mysite.com'] // No protocol!
|
|
1049
|
+
parent: ['mysite.com/page'] // No path!
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
---
|
|
1053
|
+
|
|
1054
|
+
### Q: Can I seek in live streams?
|
|
1055
|
+
|
|
1056
|
+
**A:** No, seeking only works for VODs. Live streams are always "live" at the current moment.
|
|
1057
|
+
|
|
1058
|
+
---
|
|
1059
|
+
|
|
1060
|
+
### Q: How do I get a video ID from a Twitch URL?
|
|
1061
|
+
|
|
1062
|
+
**A:** The video ID is in the URL:
|
|
1063
|
+
- URL: `https://www.twitch.tv/videos/1234567890`
|
|
1064
|
+
- ID: `1234567890`
|
|
1065
|
+
|
|
1066
|
+
---
|
|
1067
|
+
|
|
1068
|
+
### Q: Can I hide Twitch branding?
|
|
1069
|
+
|
|
1070
|
+
**A:** No, Twitch requires their branding to remain visible as per their Terms of Service.
|
|
1071
|
+
|
|
1072
|
+
---
|
|
1073
|
+
|
|
1074
|
+
### Q: Does this work with Twitch clips?
|
|
1075
|
+
|
|
1076
|
+
**A:** The current version supports channels (live) and videos (VODs). Clips support may be added in a future update.
|
|
1077
|
+
|
|
1078
|
+
---
|
|
1079
|
+
|
|
1080
|
+
### Q: How do I handle autoplay restrictions?
|
|
1081
|
+
|
|
1082
|
+
**A:** Modern browsers block autoplay. Listen for the `playbackblocked` event:
|
|
1083
|
+
|
|
1084
|
+
```javascript
|
|
1085
|
+
player.addEventListener('twitchplugin:playbackblocked', () => {
|
|
1086
|
+
// Show a play button or prompt user
|
|
1087
|
+
alert('Click to play');
|
|
1088
|
+
});
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
---
|
|
1092
|
+
|
|
1093
|
+
## Troubleshooting
|
|
1094
|
+
|
|
1095
|
+
### Issue: Player not loading
|
|
1096
|
+
|
|
1097
|
+
**Solution:**
|
|
1098
|
+
1. Check `parent` domains are correct
|
|
1099
|
+
2. Verify channel name or video ID is valid
|
|
1100
|
+
3. Check browser console for errors
|
|
1101
|
+
4. Ensure Twitch isn't blocked by firewall/adblocker
|
|
1102
|
+
|
|
1103
|
+
---
|
|
1104
|
+
|
|
1105
|
+
### Issue: "This video is not available"
|
|
1106
|
+
|
|
1107
|
+
**Solution:**
|
|
1108
|
+
- Add correct parent domains
|
|
1109
|
+
- Include both `example.com` and `www.example.com` if needed
|
|
1110
|
+
- Don't include protocol or paths
|
|
1111
|
+
|
|
1112
|
+
---
|
|
1113
|
+
|
|
1114
|
+
### Issue: Seeking not working
|
|
1115
|
+
|
|
1116
|
+
**Solution:**
|
|
1117
|
+
- Seeking only works for VODs, not live streams
|
|
1118
|
+
- Check if `player.isTwitchLive()` returns `false`
|
|
1119
|
+
|
|
1120
|
+
---
|
|
1121
|
+
|
|
1122
|
+
### Issue: Autoplay not working
|
|
1123
|
+
|
|
1124
|
+
**Solution:**
|
|
1125
|
+
- Browsers block autoplay
|
|
1126
|
+
- Set `muted: true` for autoplay to work
|
|
1127
|
+
- Handle `playbackblocked` event
|
|
1128
|
+
|
|
1129
|
+
```javascript
|
|
1130
|
+
plugins: {
|
|
1131
|
+
twitch: {
|
|
1132
|
+
channel: 'shroud',
|
|
1133
|
+
parent: ['yourdomain.com'],
|
|
1134
|
+
autoplay: true,
|
|
1135
|
+
muted: true // Required for autoplay
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
---
|
|
1141
|
+
|
|
1142
|
+
### Debug Mode
|
|
1143
|
+
|
|
1144
|
+
Enable detailed logging:
|
|
1145
|
+
|
|
1146
|
+
```javascript
|
|
1147
|
+
const player = new MYETVPlayer('myVideo', {
|
|
1148
|
+
debug: true,
|
|
1149
|
+
plugins: {
|
|
1150
|
+
twitch: {
|
|
1151
|
+
channel: 'shroud',
|
|
1152
|
+
parent: ['yourdomain.com'],
|
|
1153
|
+
debug: true
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
Debug messages appear with `Twitch Plugin:` prefix.
|
|
1160
|
+
|
|
1161
|
+
---
|
|
1162
|
+
|
|
1163
|
+
## Resources
|
|
1164
|
+
|
|
1165
|
+
- **MYETV Player**: [https://www.myetv.tv](https://www.myetv.tv)
|
|
1166
|
+
- **Twitch Developers**: [https://dev.twitch.tv/docs/embed/](https://dev.twitch.tv/docs/embed/)
|
|
1167
|
+
- **Twitch Player SDK**: [Twitch Embed Documentation](https://dev.twitch.tv/docs/embed/video-and-clips/)
|
|
1168
|
+
- **GitHub**: [MYETV Video Player Open Source](https://github.com/OskarCosimo/myetv-video-player-opensource)
|
|
1169
|
+
- **Author**: [https://oskarcosimo.com](https://oskarcosimo.com)
|
|
1170
|
+
|
|
1171
|
+
---
|
|
1172
|
+
|
|
1173
|
+
## License
|
|
1174
|
+
|
|
1175
|
+
MIT License - See main project for details.
|
|
1176
|
+
|
|
1177
|
+
---
|
|
1178
|
+
|
|
1179
|
+
## Contributing
|
|
1180
|
+
|
|
1181
|
+
Contributions are welcome! Please submit pull requests or open issues on GitHub.
|
|
1182
|
+
|
|
1183
|
+
---
|
|
1184
|
+
|
|
1185
|
+
**Happy streaming!**
|