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,640 @@
|
|
|
1
|
+
/* Vimeo Plugin for MYETV Video Player
|
|
2
|
+
* Integrates Vimeo videos with ID or URL support
|
|
3
|
+
* Supports quality selection and full Vimeo Player API
|
|
4
|
+
* Created by https://www.myetv.tv https://oskarcosimo.com
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ===================================================================
|
|
8
|
+
// GLOBAL CODE - Will be placed OUTSIDE the class by build script
|
|
9
|
+
// ===================================================================
|
|
10
|
+
|
|
11
|
+
/* GLOBAL_START */
|
|
12
|
+
(function () {
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Vimeo Plugin
|
|
17
|
+
* Embeds and controls Vimeo videos
|
|
18
|
+
*/
|
|
19
|
+
class VimeoPlugin {
|
|
20
|
+
constructor(player, options = {}) {
|
|
21
|
+
this.player = player;
|
|
22
|
+
this.options = {
|
|
23
|
+
// Video source (can be ID, URL, or full Vimeo URL)
|
|
24
|
+
videoId: options.videoId || null,
|
|
25
|
+
videoUrl: options.videoUrl || null,
|
|
26
|
+
|
|
27
|
+
// Vimeo embed options
|
|
28
|
+
width: options.width || null,
|
|
29
|
+
height: options.height || null,
|
|
30
|
+
autopause: options.autopause !== false,
|
|
31
|
+
autoplay: options.autoplay || false,
|
|
32
|
+
background: options.background || false,
|
|
33
|
+
byline: options.byline !== false,
|
|
34
|
+
color: options.color || null,
|
|
35
|
+
controls: options.controls !== false,
|
|
36
|
+
dnt: options.dnt || false, // Do Not Track
|
|
37
|
+
loop: options.loop || false,
|
|
38
|
+
muted: options.muted || false,
|
|
39
|
+
pip: options.pip !== false, // Picture-in-Picture
|
|
40
|
+
playsinline: options.playsinline !== false,
|
|
41
|
+
portrait: options.portrait !== false,
|
|
42
|
+
quality: options.quality || 'auto', // auto, 360p, 540p, 720p, 1080p, 2k, 4k
|
|
43
|
+
responsive: options.responsive !== false,
|
|
44
|
+
speed: options.speed || false,
|
|
45
|
+
texttrack: options.texttrack || null,
|
|
46
|
+
title: options.title !== false,
|
|
47
|
+
transparent: options.transparent !== false,
|
|
48
|
+
|
|
49
|
+
// Plugin options
|
|
50
|
+
debug: options.debug || false,
|
|
51
|
+
replaceNativePlayer: options.replaceNativePlayer !== false,
|
|
52
|
+
syncControls: options.syncControls !== false,
|
|
53
|
+
...options
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
this.vimeoPlayer = null;
|
|
57
|
+
this.vimeoContainer = null;
|
|
58
|
+
this.isVimeoLoaded = false;
|
|
59
|
+
this.availableQualities = [];
|
|
60
|
+
|
|
61
|
+
// Check if video source is provided
|
|
62
|
+
if (!this.options.videoId && !this.options.videoUrl) {
|
|
63
|
+
console.error('🎬 Vimeo Plugin: videoId or videoUrl is required');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Setup plugin
|
|
70
|
+
*/
|
|
71
|
+
setup() {
|
|
72
|
+
this.loadVimeoSDK().then(() => {
|
|
73
|
+
this.createVimeoPlayer();
|
|
74
|
+
if (this.options.replaceNativePlayer) {
|
|
75
|
+
this.hideNativePlayer();
|
|
76
|
+
}
|
|
77
|
+
}).catch(error => {
|
|
78
|
+
console.error('🎬 Vimeo Plugin: Failed to load SDK', error);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (this.options.debug) {
|
|
82
|
+
console.log('🎬 Vimeo Plugin initialized');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Load Vimeo Player SDK
|
|
88
|
+
*/
|
|
89
|
+
loadVimeoSDK() {
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
// Check if already loaded
|
|
92
|
+
if (window.Vimeo && window.Vimeo.Player) {
|
|
93
|
+
resolve();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Load SDK
|
|
98
|
+
const script = document.createElement('script');
|
|
99
|
+
script.src = 'https://player.vimeo.com/api/player.js';
|
|
100
|
+
script.async = true;
|
|
101
|
+
script.onload = () => {
|
|
102
|
+
if (this.options.debug) {
|
|
103
|
+
console.log('🎬 Vimeo SDK loaded');
|
|
104
|
+
}
|
|
105
|
+
resolve();
|
|
106
|
+
};
|
|
107
|
+
script.onerror = () => reject(new Error('Failed to load Vimeo SDK'));
|
|
108
|
+
document.head.appendChild(script);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create Vimeo player
|
|
114
|
+
*/
|
|
115
|
+
createVimeoPlayer() {
|
|
116
|
+
// Create container for Vimeo player
|
|
117
|
+
this.vimeoContainer = document.createElement('div');
|
|
118
|
+
this.vimeoContainer.className = 'vimeo-player-container';
|
|
119
|
+
this.vimeoContainer.style.cssText = `
|
|
120
|
+
position: absolute;
|
|
121
|
+
top: 0;
|
|
122
|
+
left: 0;
|
|
123
|
+
width: 100%;
|
|
124
|
+
height: 100%;
|
|
125
|
+
z-index: 100;
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
this.player.container.appendChild(this.vimeoContainer);
|
|
129
|
+
|
|
130
|
+
// Prepare Vimeo options
|
|
131
|
+
const vimeoOptions = this.prepareVimeoOptions();
|
|
132
|
+
|
|
133
|
+
// Create Vimeo Player instance
|
|
134
|
+
this.vimeoPlayer = new Vimeo.Player(this.vimeoContainer, vimeoOptions);
|
|
135
|
+
|
|
136
|
+
// Setup event listeners
|
|
137
|
+
this.setupEventListeners();
|
|
138
|
+
|
|
139
|
+
// Load available qualities
|
|
140
|
+
this.loadQualities();
|
|
141
|
+
|
|
142
|
+
// Sync with native player controls if requested
|
|
143
|
+
if (this.options.syncControls) {
|
|
144
|
+
this.syncWithNativeControls();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.isVimeoLoaded = true;
|
|
148
|
+
|
|
149
|
+
if (this.options.debug) {
|
|
150
|
+
console.log('🎬 Vimeo player created');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Prepare Vimeo options object
|
|
156
|
+
*/
|
|
157
|
+
prepareVimeoOptions() {
|
|
158
|
+
const vimeoOptions = {};
|
|
159
|
+
|
|
160
|
+
// Set video source
|
|
161
|
+
if (this.options.videoUrl) {
|
|
162
|
+
vimeoOptions.url = this.extractVimeoUrl(this.options.videoUrl);
|
|
163
|
+
} else if (this.options.videoId) {
|
|
164
|
+
vimeoOptions.id = this.extractVimeoId(this.options.videoId);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Set dimensions
|
|
168
|
+
if (this.options.width) vimeoOptions.width = this.options.width;
|
|
169
|
+
if (this.options.height) vimeoOptions.height = this.options.height;
|
|
170
|
+
|
|
171
|
+
// Set embed options
|
|
172
|
+
if (this.options.autopause !== undefined) vimeoOptions.autopause = this.options.autopause;
|
|
173
|
+
if (this.options.autoplay) vimeoOptions.autoplay = this.options.autoplay;
|
|
174
|
+
if (this.options.background) vimeoOptions.background = this.options.background;
|
|
175
|
+
if (this.options.byline !== undefined) vimeoOptions.byline = this.options.byline;
|
|
176
|
+
if (this.options.color) vimeoOptions.color = this.options.color;
|
|
177
|
+
if (this.options.controls !== undefined) vimeoOptions.controls = this.options.controls;
|
|
178
|
+
if (this.options.dnt) vimeoOptions.dnt = this.options.dnt;
|
|
179
|
+
if (this.options.loop) vimeoOptions.loop = this.options.loop;
|
|
180
|
+
if (this.options.muted) vimeoOptions.muted = this.options.muted;
|
|
181
|
+
if (this.options.pip !== undefined) vimeoOptions.pip = this.options.pip;
|
|
182
|
+
if (this.options.playsinline !== undefined) vimeoOptions.playsinline = this.options.playsinline;
|
|
183
|
+
if (this.options.portrait !== undefined) vimeoOptions.portrait = this.options.portrait;
|
|
184
|
+
if (this.options.quality && this.options.quality !== 'auto') vimeoOptions.quality = this.options.quality;
|
|
185
|
+
if (this.options.responsive) vimeoOptions.responsive = this.options.responsive;
|
|
186
|
+
if (this.options.speed) vimeoOptions.speed = this.options.speed;
|
|
187
|
+
if (this.options.texttrack) vimeoOptions.texttrack = this.options.texttrack;
|
|
188
|
+
if (this.options.title !== undefined) vimeoOptions.title = this.options.title;
|
|
189
|
+
if (this.options.transparent) vimeoOptions.transparent = this.options.transparent;
|
|
190
|
+
|
|
191
|
+
return vimeoOptions;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Extract Vimeo ID from various formats
|
|
196
|
+
*/
|
|
197
|
+
extractVimeoId(input) {
|
|
198
|
+
// Already a number
|
|
199
|
+
if (typeof input === 'number') return input;
|
|
200
|
+
|
|
201
|
+
// Extract from URL
|
|
202
|
+
const match = input.match(/vimeo\.com\/(\d+)/);
|
|
203
|
+
if (match) return parseInt(match[1]);
|
|
204
|
+
|
|
205
|
+
// Try parsing as number
|
|
206
|
+
const parsed = parseInt(input);
|
|
207
|
+
if (!isNaN(parsed)) return parsed;
|
|
208
|
+
|
|
209
|
+
return input;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Extract full Vimeo URL
|
|
214
|
+
*/
|
|
215
|
+
extractVimeoUrl(input) {
|
|
216
|
+
// Already a full URL
|
|
217
|
+
if (input.startsWith('http')) return input;
|
|
218
|
+
|
|
219
|
+
// Build URL from ID
|
|
220
|
+
return `https://vimeo.com/${input}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Setup event listeners
|
|
225
|
+
*/
|
|
226
|
+
setupEventListeners() {
|
|
227
|
+
// Play event
|
|
228
|
+
this.vimeoPlayer.on('play', (data) => {
|
|
229
|
+
this.player.triggerEvent('play', data);
|
|
230
|
+
if (this.options.debug) console.log('🎬 Vimeo: play', data);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Playing event
|
|
234
|
+
this.vimeoPlayer.on('playing', (data) => {
|
|
235
|
+
this.player.triggerEvent('playing', data);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Pause event
|
|
239
|
+
this.vimeoPlayer.on('pause', (data) => {
|
|
240
|
+
this.player.triggerEvent('pause', data);
|
|
241
|
+
if (this.options.debug) console.log('🎬 Vimeo: pause', data);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Ended event
|
|
245
|
+
this.vimeoPlayer.on('ended', (data) => {
|
|
246
|
+
this.player.triggerEvent('ended', data);
|
|
247
|
+
if (this.options.debug) console.log('🎬 Vimeo: ended', data);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Time update event
|
|
251
|
+
this.vimeoPlayer.on('timeupdate', (data) => {
|
|
252
|
+
this.player.triggerEvent('timeupdate', {
|
|
253
|
+
currentTime: data.seconds,
|
|
254
|
+
duration: data.duration,
|
|
255
|
+
percent: data.percent
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Progress event (buffering)
|
|
260
|
+
this.vimeoPlayer.on('progress', (data) => {
|
|
261
|
+
this.player.triggerEvent('progress', data);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Seeking event
|
|
265
|
+
this.vimeoPlayer.on('seeking', (data) => {
|
|
266
|
+
this.player.triggerEvent('seeking', data);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Seeked event
|
|
270
|
+
this.vimeoPlayer.on('seeked', (data) => {
|
|
271
|
+
this.player.triggerEvent('seeked', data);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Volume change event
|
|
275
|
+
this.vimeoPlayer.on('volumechange', (data) => {
|
|
276
|
+
this.player.triggerEvent('volumechange', data);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Playback rate change event
|
|
280
|
+
this.vimeoPlayer.on('playbackratechange', (data) => {
|
|
281
|
+
this.player.triggerEvent('playbackratechange', data);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Buffer start event
|
|
285
|
+
this.vimeoPlayer.on('bufferstart', () => {
|
|
286
|
+
this.player.triggerEvent('waiting');
|
|
287
|
+
if (this.options.debug) console.log('🎬 Vimeo: bufferstart');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Buffer end event
|
|
291
|
+
this.vimeoPlayer.on('bufferend', () => {
|
|
292
|
+
this.player.triggerEvent('canplay');
|
|
293
|
+
if (this.options.debug) console.log('🎬 Vimeo: bufferend');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Quality change event
|
|
297
|
+
this.vimeoPlayer.on('qualitychange', (data) => {
|
|
298
|
+
this.player.triggerEvent('qualitychange', data);
|
|
299
|
+
if (this.options.debug) console.log('🎬 Vimeo: quality changed to', data.quality);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Fullscreen change event
|
|
303
|
+
this.vimeoPlayer.on('fullscreenchange', (data) => {
|
|
304
|
+
this.player.triggerEvent('fullscreenchange', data);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Error event
|
|
308
|
+
this.vimeoPlayer.on('error', (data) => {
|
|
309
|
+
console.error('🎬 Vimeo error:', data);
|
|
310
|
+
this.player.triggerEvent('error', data);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Loaded event
|
|
314
|
+
this.vimeoPlayer.on('loaded', (data) => {
|
|
315
|
+
this.player.triggerEvent('loadedmetadata', data);
|
|
316
|
+
if (this.options.debug) console.log('🎬 Vimeo: loaded', data);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Text track change
|
|
320
|
+
this.vimeoPlayer.on('texttrackchange', (data) => {
|
|
321
|
+
this.player.triggerEvent('texttrackchange', data);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Chapter change
|
|
325
|
+
this.vimeoPlayer.on('chapterchange', (data) => {
|
|
326
|
+
this.player.triggerEvent('chapterchange', data);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Picture-in-Picture events
|
|
330
|
+
this.vimeoPlayer.on('enterpictureinpicture', () => {
|
|
331
|
+
this.player.triggerEvent('enterpictureinpicture');
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
this.vimeoPlayer.on('leavepictureinpicture', () => {
|
|
335
|
+
this.player.triggerEvent('leavepictureinpicture');
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Load available qualities
|
|
341
|
+
*/
|
|
342
|
+
loadQualities() {
|
|
343
|
+
this.vimeoPlayer.getQualities().then(qualities => {
|
|
344
|
+
this.availableQualities = qualities;
|
|
345
|
+
|
|
346
|
+
// Trigger custom event with qualities
|
|
347
|
+
this.player.triggerEvent('qualitiesloaded', { qualities });
|
|
348
|
+
|
|
349
|
+
if (this.options.debug) {
|
|
350
|
+
console.log('🎬 Vimeo: Available qualities', qualities);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Set initial quality if specified
|
|
354
|
+
if (this.options.quality && this.options.quality !== 'auto') {
|
|
355
|
+
this.setQuality(this.options.quality);
|
|
356
|
+
}
|
|
357
|
+
}).catch(error => {
|
|
358
|
+
if (this.options.debug) {
|
|
359
|
+
console.warn('🎬 Vimeo: Could not load qualities', error);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Get available qualities
|
|
366
|
+
*/
|
|
367
|
+
getQualities() {
|
|
368
|
+
return this.availableQualities;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get current quality
|
|
373
|
+
*/
|
|
374
|
+
getCurrentQuality() {
|
|
375
|
+
return this.vimeoPlayer.getQuality();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Set quality
|
|
380
|
+
*/
|
|
381
|
+
setQuality(quality) {
|
|
382
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
383
|
+
|
|
384
|
+
return this.vimeoPlayer.setQuality(quality).then(selectedQuality => {
|
|
385
|
+
if (this.options.debug) {
|
|
386
|
+
console.log('🎬 Vimeo: Quality set to', selectedQuality);
|
|
387
|
+
}
|
|
388
|
+
return selectedQuality;
|
|
389
|
+
}).catch(error => {
|
|
390
|
+
console.error('🎬 Vimeo: Failed to set quality', error);
|
|
391
|
+
throw error;
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Hide native player
|
|
397
|
+
*/
|
|
398
|
+
hideNativePlayer() {
|
|
399
|
+
if (this.player.video) {
|
|
400
|
+
this.player.video.style.opacity = '0';
|
|
401
|
+
this.player.video.style.pointerEvents = 'none';
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Sync with native player controls
|
|
407
|
+
*/
|
|
408
|
+
syncWithNativeControls() {
|
|
409
|
+
// This would integrate with your custom player controls
|
|
410
|
+
// Example: sync play/pause buttons
|
|
411
|
+
const playButton = this.player.container.querySelector('.play-button');
|
|
412
|
+
if (playButton) {
|
|
413
|
+
playButton.addEventListener('click', () => {
|
|
414
|
+
this.vimeoPlayer.getPaused().then(paused => {
|
|
415
|
+
if (paused) {
|
|
416
|
+
this.vimeoPlayer.play();
|
|
417
|
+
} else {
|
|
418
|
+
this.vimeoPlayer.pause();
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Load new video
|
|
427
|
+
*/
|
|
428
|
+
loadVideo(videoIdOrUrl) {
|
|
429
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
430
|
+
|
|
431
|
+
const videoId = this.extractVimeoId(videoIdOrUrl);
|
|
432
|
+
|
|
433
|
+
return this.vimeoPlayer.loadVideo(videoId).then(id => {
|
|
434
|
+
if (this.options.debug) {
|
|
435
|
+
console.log('🎬 Vimeo: Video loaded', id);
|
|
436
|
+
}
|
|
437
|
+
this.loadQualities();
|
|
438
|
+
return id;
|
|
439
|
+
}).catch(error => {
|
|
440
|
+
console.error('🎬 Vimeo: Failed to load video', error);
|
|
441
|
+
throw error;
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Get video metadata via oEmbed API
|
|
447
|
+
*/
|
|
448
|
+
async getVideoMetadata(videoIdOrUrl) {
|
|
449
|
+
const videoUrl = this.extractVimeoUrl(videoIdOrUrl);
|
|
450
|
+
const oembedUrl = `https://vimeo.com/api/oembed.json?url=${encodeURIComponent(videoUrl)}`;
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
const response = await fetch(oembedUrl);
|
|
454
|
+
const data = await response.json();
|
|
455
|
+
|
|
456
|
+
if (this.options.debug) {
|
|
457
|
+
console.log('🎬 Vimeo: Video metadata', data);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
title: data.title,
|
|
462
|
+
description: data.description,
|
|
463
|
+
thumbnail: data.thumbnail_url,
|
|
464
|
+
thumbnailLarge: data.thumbnail_url.replace(/_\d+x\d+/, '_1280x720'),
|
|
465
|
+
duration: data.duration,
|
|
466
|
+
author: data.author_name,
|
|
467
|
+
authorUrl: data.author_url,
|
|
468
|
+
width: data.width,
|
|
469
|
+
height: data.height,
|
|
470
|
+
html: data.html
|
|
471
|
+
};
|
|
472
|
+
} catch (error) {
|
|
473
|
+
console.error('🎬 Vimeo: Failed to fetch metadata', error);
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Play video
|
|
480
|
+
*/
|
|
481
|
+
play() {
|
|
482
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
483
|
+
return this.vimeoPlayer.play();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Pause video
|
|
488
|
+
*/
|
|
489
|
+
pause() {
|
|
490
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
491
|
+
return this.vimeoPlayer.pause();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Get current time
|
|
496
|
+
*/
|
|
497
|
+
getCurrentTime() {
|
|
498
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
499
|
+
return this.vimeoPlayer.getCurrentTime();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Set current time
|
|
504
|
+
*/
|
|
505
|
+
setCurrentTime(seconds) {
|
|
506
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
507
|
+
return this.vimeoPlayer.setCurrentTime(seconds);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Get duration
|
|
512
|
+
*/
|
|
513
|
+
getDuration() {
|
|
514
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
515
|
+
return this.vimeoPlayer.getDuration();
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Get volume
|
|
520
|
+
*/
|
|
521
|
+
getVolume() {
|
|
522
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
523
|
+
return this.vimeoPlayer.getVolume();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Set volume
|
|
528
|
+
*/
|
|
529
|
+
setVolume(volume) {
|
|
530
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
531
|
+
return this.vimeoPlayer.setVolume(volume);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Get muted state
|
|
536
|
+
*/
|
|
537
|
+
getMuted() {
|
|
538
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
539
|
+
return this.vimeoPlayer.getMuted();
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Set muted state
|
|
544
|
+
*/
|
|
545
|
+
setMuted(muted) {
|
|
546
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
547
|
+
return this.vimeoPlayer.setMuted(muted);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Get playback rate
|
|
552
|
+
*/
|
|
553
|
+
getPlaybackRate() {
|
|
554
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
555
|
+
return this.vimeoPlayer.getPlaybackRate();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Set playback rate
|
|
560
|
+
*/
|
|
561
|
+
setPlaybackRate(rate) {
|
|
562
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
563
|
+
return this.vimeoPlayer.setPlaybackRate(rate);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Request fullscreen
|
|
568
|
+
*/
|
|
569
|
+
requestFullscreen() {
|
|
570
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
571
|
+
return this.vimeoPlayer.requestFullscreen();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Exit fullscreen
|
|
576
|
+
*/
|
|
577
|
+
exitFullscreen() {
|
|
578
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
579
|
+
return this.vimeoPlayer.exitFullscreen();
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Get text tracks
|
|
584
|
+
*/
|
|
585
|
+
getTextTracks() {
|
|
586
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
587
|
+
return this.vimeoPlayer.getTextTracks();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Enable text track
|
|
592
|
+
*/
|
|
593
|
+
enableTextTrack(language, kind) {
|
|
594
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
595
|
+
return this.vimeoPlayer.enableTextTrack(language, kind);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Disable text track
|
|
600
|
+
*/
|
|
601
|
+
disableTextTrack() {
|
|
602
|
+
if (!this.vimeoPlayer) return Promise.reject('Player not initialized');
|
|
603
|
+
return this.vimeoPlayer.disableTextTrack();
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Dispose plugin
|
|
608
|
+
*/
|
|
609
|
+
dispose() {
|
|
610
|
+
if (this.vimeoPlayer) {
|
|
611
|
+
this.vimeoPlayer.destroy().then(() => {
|
|
612
|
+
if (this.options.debug) {
|
|
613
|
+
console.log('🎬 Vimeo player destroyed');
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (this.vimeoContainer) {
|
|
619
|
+
this.vimeoContainer.remove();
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Restore native player
|
|
623
|
+
if (this.player.video && this.options.replaceNativePlayer) {
|
|
624
|
+
this.player.video.style.opacity = '1';
|
|
625
|
+
this.player.video.style.pointerEvents = 'auto';
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if (this.options.debug) {
|
|
629
|
+
console.log('🎬 Vimeo Plugin disposed');
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Register plugin globally
|
|
635
|
+
if (typeof window.registerMYETVPlugin === 'function') {
|
|
636
|
+
window.registerMYETVPlugin('vimeo', VimeoPlugin);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
})();
|
|
640
|
+
/* GLOBAL_END */
|