vidply 1.0.26 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/dev/{vidply.HLSRenderer-X46P47LY.js → vidply.HLSRenderer-ENLZE4QS.js} +13 -8
  2. package/dist/dev/vidply.HLSRenderer-ENLZE4QS.js.map +7 -0
  3. package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js → vidply.HTML5Renderer-6SBDI6S2.js} +2 -2
  4. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js +280 -0
  5. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js.map +7 -0
  6. package/dist/dev/{vidply.VimeoRenderer-DCETT5IZ.js → vidply.VimeoRenderer-VPH4RNES.js} +17 -4
  7. package/dist/dev/vidply.VimeoRenderer-VPH4RNES.js.map +7 -0
  8. package/dist/dev/{vidply.YouTubeRenderer-QLMMD757.js → vidply.YouTubeRenderer-6MGKEFTZ.js} +14 -6
  9. package/dist/dev/vidply.YouTubeRenderer-6MGKEFTZ.js.map +7 -0
  10. package/dist/dev/{vidply.chunk-UEIJOJH6.js → vidply.chunk-BCOFCT6U.js} +4 -1
  11. package/dist/dev/vidply.chunk-BCOFCT6U.js.map +7 -0
  12. package/dist/dev/vidply.esm.js +288 -12
  13. package/dist/dev/vidply.esm.js.map +2 -2
  14. package/dist/legacy/vidply.js +609 -23
  15. package/dist/legacy/vidply.js.map +3 -3
  16. package/dist/legacy/vidply.min.js +1 -1
  17. package/dist/legacy/vidply.min.meta.json +26 -13
  18. package/dist/prod/vidply.HLSRenderer-CBXZ4RF2.min.js +6 -0
  19. package/dist/prod/{vidply.HTML5Renderer-XJCSUETP.min.js → vidply.HTML5Renderer-MY7XDV7R.min.js} +1 -1
  20. package/dist/prod/vidply.SoundCloudRenderer-MOR2CUFH.min.js +6 -0
  21. package/dist/prod/vidply.VimeoRenderer-3HBMM2WR.min.js +6 -0
  22. package/dist/prod/vidply.YouTubeRenderer-MFC2GMAC.min.js +6 -0
  23. package/dist/prod/vidply.chunk-OXXPY2XB.min.js +6 -0
  24. package/dist/prod/vidply.esm.min.js +6 -6
  25. package/dist/vidply.css +51 -0
  26. package/dist/vidply.esm.min.meta.json +56 -28
  27. package/dist/vidply.min.css +1 -1
  28. package/package.json +1 -1
  29. package/src/core/Player.js +117 -8
  30. package/src/features/PlaylistManager.js +312 -4
  31. package/src/renderers/HLSRenderer.js +17 -9
  32. package/src/renderers/HTML5Renderer.js +5 -0
  33. package/src/renderers/SoundCloudRenderer.js +355 -0
  34. package/src/renderers/VimeoRenderer.js +20 -4
  35. package/src/renderers/YouTubeRenderer.js +12 -6
  36. package/src/styles/vidply.css +51 -0
  37. package/dist/dev/vidply.HLSRenderer-X46P47LY.js.map +0 -7
  38. package/dist/dev/vidply.VimeoRenderer-DCETT5IZ.js.map +0 -7
  39. package/dist/dev/vidply.YouTubeRenderer-QLMMD757.js.map +0 -7
  40. package/dist/dev/vidply.chunk-UEIJOJH6.js.map +0 -7
  41. package/dist/prod/vidply.HLSRenderer-LDXSMWTI.min.js +0 -6
  42. package/dist/prod/vidply.VimeoRenderer-P3PU27S7.min.js +0 -6
  43. package/dist/prod/vidply.YouTubeRenderer-DGKKWB5M.min.js +0 -6
  44. package/dist/prod/vidply.chunk-BQBGEJF7.min.js +0 -6
  45. /package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js.map → vidply.HTML5Renderer-6SBDI6S2.js.map} +0 -0
@@ -0,0 +1,355 @@
1
+ /**
2
+ * SoundCloud Renderer
3
+ * Uses SoundCloud Widget API for embedded track playback
4
+ */
5
+
6
+ export class SoundCloudRenderer {
7
+ constructor(player) {
8
+ this.player = player;
9
+ this.widget = null;
10
+ this.trackUrl = null;
11
+ this.isReady = false;
12
+ this.iframe = null;
13
+ this.iframeId = null;
14
+ }
15
+
16
+ async init() {
17
+ // Extract track URL - use currentSource which works for external renderers
18
+ this.trackUrl = this.player.currentSource || this.player.element.src || this.player.element.querySelector('source')?.src;
19
+
20
+ if (!this.trackUrl || !this.isValidSoundCloudUrl(this.trackUrl)) {
21
+ throw new Error('Invalid SoundCloud URL');
22
+ }
23
+
24
+ // Load SoundCloud Widget API
25
+ await this.loadSoundCloudAPI();
26
+
27
+ // Create iframe
28
+ this.createIframe();
29
+
30
+ // Initialize widget
31
+ await this.initializeWidget();
32
+ }
33
+
34
+ /**
35
+ * Validate SoundCloud URL
36
+ * @param {string} url
37
+ * @returns {boolean}
38
+ */
39
+ isValidSoundCloudUrl(url) {
40
+ return url.includes('soundcloud.com') || url.includes('api.soundcloud.com');
41
+ }
42
+
43
+ /**
44
+ * Check if URL is a playlist/set
45
+ */
46
+ isPlaylist() {
47
+ return this.trackUrl && this.trackUrl.includes('/sets/');
48
+ }
49
+
50
+ /**
51
+ * Extract track/playlist info from URL for embed
52
+ * SoundCloud URLs can be:
53
+ * - https://soundcloud.com/artist/track
54
+ * - https://soundcloud.com/artist/sets/playlist
55
+ * - https://api.soundcloud.com/tracks/123456
56
+ */
57
+ getEmbedUrl() {
58
+ // SoundCloud widget needs the track URL encoded
59
+ const encodedUrl = encodeURIComponent(this.trackUrl);
60
+
61
+ // Build widget URL with parameters
62
+ const params = new URLSearchParams({
63
+ url: this.trackUrl,
64
+ auto_play: this.player.options.autoplay ? 'true' : 'false',
65
+ hide_related: 'true',
66
+ show_comments: 'false',
67
+ show_user: 'true',
68
+ show_reposts: 'false',
69
+ show_teaser: 'false',
70
+ visual: 'false', // Use classic player for better control
71
+ color: '%23007bff'
72
+ });
73
+
74
+ return `https://w.soundcloud.com/player/?${params.toString()}`;
75
+ }
76
+
77
+ async loadSoundCloudAPI() {
78
+ // Check if API is already loaded
79
+ if (window.SC && window.SC.Widget) {
80
+ return Promise.resolve();
81
+ }
82
+
83
+ return new Promise((resolve, reject) => {
84
+ const script = document.createElement('script');
85
+ script.src = 'https://w.soundcloud.com/player/api.js';
86
+ script.onload = () => {
87
+ // Wait a bit for SC.Widget to be fully available
88
+ setTimeout(() => {
89
+ if (window.SC && window.SC.Widget) {
90
+ resolve();
91
+ } else {
92
+ reject(new Error('SoundCloud Widget API not available'));
93
+ }
94
+ }, 100);
95
+ };
96
+ script.onerror = () => reject(new Error('Failed to load SoundCloud Widget API'));
97
+ document.head.appendChild(script);
98
+ });
99
+ }
100
+
101
+ createIframe() {
102
+ // Hide original element and remove poster (SoundCloud has its own visual widget)
103
+ this.player.element.style.display = 'none';
104
+ this.player.element.removeAttribute('poster');
105
+
106
+ // Remove poster overlay from video wrapper if present
107
+ if (this.player.videoWrapper) {
108
+ this.player.videoWrapper.classList.remove('vidply-forced-poster');
109
+ this.player.videoWrapper.style.removeProperty('--vidply-poster-image');
110
+ }
111
+
112
+ // Generate unique ID for iframe
113
+ this.iframeId = `soundcloud-player-${Math.random().toString(36).substr(2, 9)}`;
114
+
115
+ // Create iframe for SoundCloud widget
116
+ this.iframe = document.createElement('iframe');
117
+ this.iframe.id = this.iframeId;
118
+ this.iframe.scrolling = 'no';
119
+ this.iframe.frameBorder = 'no';
120
+ this.iframe.allow = 'autoplay';
121
+ this.iframe.src = this.getEmbedUrl();
122
+ this.iframe.style.width = '100%';
123
+ this.iframe.style.display = 'block';
124
+
125
+ // Use different aspect ratio for playlists vs single tracks
126
+ // Playlists need more height to show the track list
127
+ if (this.isPlaylist()) {
128
+ this.iframe.style.aspectRatio = '16 / 9'; // More height for playlist
129
+ this.iframe.classList.add('vidply-soundcloud-iframe', 'vidply-soundcloud-playlist');
130
+ } else {
131
+ this.iframe.style.aspectRatio = '16 / 3'; // Banner-like for single track
132
+ this.iframe.classList.add('vidply-soundcloud-iframe');
133
+ }
134
+ this.iframe.style.maxHeight = '100%';
135
+
136
+ this.player.element.parentNode.insertBefore(this.iframe, this.player.element);
137
+ }
138
+
139
+ async initializeWidget() {
140
+ return new Promise((resolve, reject) => {
141
+ // Wait for iframe to load
142
+ this.iframe.addEventListener('load', () => {
143
+ try {
144
+ this.widget = window.SC.Widget(this.iframe);
145
+
146
+ this.widget.bind(window.SC.Widget.Events.READY, () => {
147
+ this.isReady = true;
148
+ this.attachEvents();
149
+
150
+ // Hide VidPly controls - SoundCloud has its own
151
+ if (this.player.container) {
152
+ this.player.container.classList.add('vidply-external-controls');
153
+ }
154
+
155
+ // Get initial sound info
156
+ this.widget.getCurrentSound((sound) => {
157
+ if (sound) {
158
+ this.player.state.duration = sound.duration / 1000; // Convert ms to seconds
159
+ this.player.emit('loadedmetadata');
160
+ }
161
+ });
162
+
163
+ resolve();
164
+ });
165
+
166
+ this.widget.bind(window.SC.Widget.Events.ERROR, (error) => {
167
+ this.player.handleError(new Error(`SoundCloud error: ${error.message || 'Unknown error'}`));
168
+ });
169
+ } catch (error) {
170
+ reject(error);
171
+ }
172
+ });
173
+
174
+ // Timeout after 10 seconds
175
+ setTimeout(() => {
176
+ if (!this.isReady) {
177
+ reject(new Error('SoundCloud widget initialization timeout'));
178
+ }
179
+ }, 10000);
180
+ });
181
+ }
182
+
183
+ attachEvents() {
184
+ if (!this.widget) return;
185
+
186
+ const Events = window.SC.Widget.Events;
187
+
188
+ this.widget.bind(Events.PLAY, () => {
189
+ this.player.state.playing = true;
190
+ this.player.state.paused = false;
191
+ this.player.state.ended = false;
192
+ this.player.emit('play');
193
+
194
+ if (this.player.options.onPlay) {
195
+ this.player.options.onPlay.call(this.player);
196
+ }
197
+ });
198
+
199
+ this.widget.bind(Events.PAUSE, () => {
200
+ this.player.state.playing = false;
201
+ this.player.state.paused = true;
202
+ this.player.emit('pause');
203
+
204
+ if (this.player.options.onPause) {
205
+ this.player.options.onPause.call(this.player);
206
+ }
207
+ });
208
+
209
+ this.widget.bind(Events.FINISH, () => {
210
+ this.player.state.playing = false;
211
+ this.player.state.paused = true;
212
+ this.player.state.ended = true;
213
+ this.player.emit('ended');
214
+
215
+ if (this.player.options.onEnded) {
216
+ this.player.options.onEnded.call(this.player);
217
+ }
218
+
219
+ if (this.player.options.loop) {
220
+ this.seek(0);
221
+ this.play();
222
+ }
223
+ });
224
+
225
+ this.widget.bind(Events.PLAY_PROGRESS, (data) => {
226
+ // data.currentPosition is in milliseconds
227
+ const currentTime = data.currentPosition / 1000;
228
+ this.player.state.currentTime = currentTime;
229
+ this.player.emit('timeupdate', currentTime);
230
+
231
+ if (this.player.options.onTimeUpdate) {
232
+ this.player.options.onTimeUpdate.call(this.player, currentTime);
233
+ }
234
+ });
235
+
236
+ this.widget.bind(Events.SEEK, (data) => {
237
+ this.player.state.currentTime = data.currentPosition / 1000;
238
+ this.player.emit('seeked');
239
+ });
240
+
241
+ this.widget.bind(Events.LOAD_PROGRESS, (data) => {
242
+ // data.loadedProgress is 0-1
243
+ if (this.player.state.duration) {
244
+ const buffered = data.loadedProgress * this.player.state.duration;
245
+ this.player.emit('progress', buffered);
246
+ }
247
+ });
248
+ }
249
+
250
+ play() {
251
+ if (this.isReady && this.widget) {
252
+ // Save scroll position to prevent browser from scrolling
253
+ const scrollX = window.scrollX;
254
+ const scrollY = window.scrollY;
255
+
256
+ this.widget.play();
257
+
258
+ // Restore scroll position
259
+ window.scrollTo(scrollX, scrollY);
260
+ }
261
+ }
262
+
263
+ pause() {
264
+ if (this.isReady && this.widget) {
265
+ this.widget.pause();
266
+ }
267
+ }
268
+
269
+ seek(time) {
270
+ if (this.isReady && this.widget) {
271
+ // SoundCloud seekTo uses milliseconds
272
+ this.widget.seekTo(time * 1000);
273
+ this.player.state.currentTime = time;
274
+ }
275
+ }
276
+
277
+ setVolume(volume) {
278
+ if (this.isReady && this.widget) {
279
+ // SoundCloud setVolume expects 0-100
280
+ this.widget.setVolume(volume * 100);
281
+ this.player.state.volume = volume;
282
+ }
283
+ }
284
+
285
+ setMuted(muted) {
286
+ if (this.isReady && this.widget) {
287
+ // SoundCloud doesn't have a native mute, use volume instead
288
+ if (muted) {
289
+ // Store current volume before muting
290
+ this.widget.getVolume((vol) => {
291
+ this._previousVolume = vol;
292
+ this.widget.setVolume(0);
293
+ });
294
+ } else {
295
+ this.widget.setVolume(this._previousVolume || 100);
296
+ }
297
+ this.player.state.muted = muted;
298
+ }
299
+ }
300
+
301
+ setPlaybackSpeed(speed) {
302
+ // SoundCloud Widget API doesn't support playback speed
303
+ this.player.log('SoundCloud does not support playback speed control', 'warn');
304
+ }
305
+
306
+ /**
307
+ * Get current track info
308
+ * @returns {Promise<Object>}
309
+ */
310
+ getCurrentSound() {
311
+ return new Promise((resolve) => {
312
+ if (this.isReady && this.widget) {
313
+ this.widget.getCurrentSound((sound) => {
314
+ resolve(sound);
315
+ });
316
+ } else {
317
+ resolve(null);
318
+ }
319
+ });
320
+ }
321
+
322
+ destroy() {
323
+ // Unbind all events
324
+ if (this.widget) {
325
+ const Events = window.SC.Widget.Events;
326
+ try {
327
+ this.widget.unbind(Events.READY);
328
+ this.widget.unbind(Events.PLAY);
329
+ this.widget.unbind(Events.PAUSE);
330
+ this.widget.unbind(Events.FINISH);
331
+ this.widget.unbind(Events.PLAY_PROGRESS);
332
+ this.widget.unbind(Events.SEEK);
333
+ this.widget.unbind(Events.LOAD_PROGRESS);
334
+ this.widget.unbind(Events.ERROR);
335
+ } catch (e) {
336
+ // Ignore unbind errors
337
+ }
338
+ }
339
+
340
+ if (this.iframe && this.iframe.parentNode) {
341
+ this.iframe.parentNode.removeChild(this.iframe);
342
+ }
343
+
344
+ // Show original element
345
+ if (this.player.element) {
346
+ this.player.element.style.display = '';
347
+ }
348
+
349
+ this.widget = null;
350
+ this.isReady = false;
351
+ }
352
+ }
353
+
354
+ export default SoundCloudRenderer;
355
+
@@ -12,8 +12,9 @@ export class VimeoRenderer {
12
12
  }
13
13
 
14
14
  async init() {
15
- // Extract video ID from URL
16
- this.videoId = this.extractVideoId(this.player.element.src);
15
+ // Extract video ID from URL - use currentSource which works for external renderers
16
+ const src = this.player.currentSource || this.player.element.src;
17
+ this.videoId = this.extractVideoId(src);
17
18
 
18
19
  if (!this.videoId) {
19
20
  throw new Error('Invalid Vimeo URL');
@@ -69,7 +70,8 @@ export class VimeoRenderer {
69
70
  this.iframe = document.createElement('div');
70
71
  this.iframe.id = `vimeo-player-${Math.random().toString(36).substr(2, 9)}`;
71
72
  this.iframe.style.width = '100%';
72
- this.iframe.style.height = '100%';
73
+ this.iframe.style.aspectRatio = '16 / 9';
74
+ this.iframe.style.maxHeight = '100%';
73
75
 
74
76
  this.player.element.parentNode.insertBefore(this.iframe, this.player.element);
75
77
  }
@@ -79,7 +81,7 @@ export class VimeoRenderer {
79
81
  id: this.videoId,
80
82
  width: '100%',
81
83
  height: '100%',
82
- controls: false,
84
+ controls: true, // Use Vimeo native controls
83
85
  autoplay: this.player.options.autoplay,
84
86
  muted: this.player.options.muted,
85
87
  loop: this.player.options.loop,
@@ -95,6 +97,20 @@ export class VimeoRenderer {
95
97
  // Wait for player to be ready
96
98
  await this.vimeo.ready();
97
99
  this.isReady = true;
100
+
101
+ // Ensure the iframe has 100% width and height
102
+ const vimeoIframe = this.iframe.querySelector('iframe');
103
+ if (vimeoIframe) {
104
+ vimeoIframe.style.width = '100%';
105
+ vimeoIframe.style.height = '100%';
106
+ vimeoIframe.setAttribute('width', '100%');
107
+ vimeoIframe.setAttribute('height', '100%');
108
+ }
109
+
110
+ // Hide VidPly controls - Vimeo has its own
111
+ if (this.player.container) {
112
+ this.player.container.classList.add('vidply-external-controls');
113
+ }
98
114
 
99
115
  this.attachEvents();
100
116
 
@@ -12,8 +12,9 @@ export class YouTubeRenderer {
12
12
  }
13
13
 
14
14
  async init() {
15
- // Extract video ID from URL
16
- this.videoId = this.extractVideoId(this.player.element.src);
15
+ // Extract video ID from URL - use currentSource which works for external renderers
16
+ const src = this.player.currentSource || this.player.element.src;
17
+ this.videoId = this.extractVideoId(src);
17
18
 
18
19
  if (!this.videoId) {
19
20
  throw new Error('Invalid YouTube URL');
@@ -85,7 +86,8 @@ export class YouTubeRenderer {
85
86
  this.iframe = document.createElement('div');
86
87
  this.iframe.id = `youtube-player-${Math.random().toString(36).substr(2, 9)}`;
87
88
  this.iframe.style.width = '100%';
88
- this.iframe.style.height = '100%';
89
+ this.iframe.style.aspectRatio = '16 / 9';
90
+ this.iframe.style.maxHeight = '100%';
89
91
 
90
92
  this.player.element.parentNode.insertBefore(this.iframe, this.player.element);
91
93
  }
@@ -97,9 +99,9 @@ export class YouTubeRenderer {
97
99
  width: '100%',
98
100
  height: '100%',
99
101
  playerVars: {
100
- controls: 0,
101
- disablekb: 1,
102
- fs: 0,
102
+ controls: 1, // Use YouTube native controls
103
+ disablekb: 0, // Allow keyboard controls
104
+ fs: 1, // Allow fullscreen
103
105
  modestbranding: 1,
104
106
  rel: 0,
105
107
  showinfo: 0,
@@ -112,6 +114,10 @@ export class YouTubeRenderer {
112
114
  onReady: (event) => {
113
115
  this.isReady = true;
114
116
  this.attachEvents();
117
+ // Hide VidPly controls - YouTube has its own
118
+ if (this.player.container) {
119
+ this.player.container.classList.add('vidply-external-controls');
120
+ }
115
121
  resolve();
116
122
  },
117
123
  onStateChange: (event) => this.handleStateChange(event),
@@ -513,6 +513,57 @@
513
513
  opacity: 0;
514
514
  }
515
515
 
516
+ /* Audio content in video player - uses 16:3 aspect ratio for a banner-like appearance */
517
+ /* When audio files are played in a video element, we use CSS poster overlay for better control */
518
+ .vidply-player.vidply-video.vidply-audio-content .vidply-video-wrapper {
519
+ aspect-ratio: 16 / 3 !important;
520
+ height: auto !important;
521
+ min-height: 0 !important;
522
+ overflow: hidden;
523
+ }
524
+
525
+ .vidply-player.vidply-video.vidply-audio-content .vidply-video-wrapper.vidply-forced-poster {
526
+ background-size: cover;
527
+ background-position: center;
528
+ }
529
+
530
+ /* Hide the video element completely when playing audio - let the wrapper show the poster */
531
+ .vidply-player.vidply-video.vidply-audio-content video {
532
+ display: none !important;
533
+ }
534
+
535
+ /* YouTube and Vimeo iframe containers - ensure 16:9 aspect ratio */
536
+ .vidply-video-wrapper > div[id^="youtube-player-"],
537
+ .vidply-video-wrapper > div[id^="vimeo-player-"] {
538
+ width: 100% !important;
539
+ aspect-ratio: 16 / 9;
540
+ max-height: 100%;
541
+ }
542
+
543
+ .vidply-video-wrapper > div[id^="youtube-player-"] iframe,
544
+ .vidply-video-wrapper > div[id^="vimeo-player-"] iframe {
545
+ width: 100% !important;
546
+ height: 100% !important;
547
+ }
548
+
549
+ /* SoundCloud iframe - uses 16:3 aspect ratio for single track audio banner appearance */
550
+ .vidply-video-wrapper > iframe.vidply-soundcloud-iframe {
551
+ width: 100% !important;
552
+ aspect-ratio: 16 / 3;
553
+ max-height: 100%;
554
+ }
555
+
556
+ /* SoundCloud playlist - uses 16:9 aspect ratio to show track list */
557
+ .vidply-video-wrapper > iframe.vidply-soundcloud-iframe.vidply-soundcloud-playlist {
558
+ aspect-ratio: 16 / 9;
559
+ }
560
+
561
+ /* Hide VidPly controls when external renderer (YouTube, Vimeo, SoundCloud) is active */
562
+ /* These services have their own native controls */
563
+ .vidply-player.vidply-external-controls .vidply-controls {
564
+ display: none !important;
565
+ }
566
+
516
567
  /* Mobile: Simplify video wrapper but keep captions contained */
517
568
  @media (width < 48rem) {
518
569
  .vidply-video-wrapper {
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/renderers/HLSRenderer.js"],
4
- "sourcesContent": ["/**\r\n * HLS Streaming Renderer\r\n * Uses hls.js for browsers that don't natively support HLS\r\n */\r\n\r\nexport class HLSRenderer {\r\n constructor(player) {\r\n this.player = player;\r\n this.media = player.element;\r\n this.hls = null;\r\n }\r\n\r\n async init() {\r\n // Check if browser natively supports HLS (Safari)\r\n if (this.canPlayNatively()) {\r\n this.player.log('Using native HLS support');\r\n await this.initNative();\r\n } else {\r\n this.player.log('Using hls.js for HLS support');\r\n await this.initHlsJs();\r\n }\r\n }\r\n\r\n canPlayNatively() {\r\n // Only use native HLS on Safari/iOS where it actually works properly\r\n // Chrome reports it can play HLS but doesn't have proper quality switching\r\n const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\r\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\r\n \r\n if (!isSafari && !isIOS) {\r\n // Force hls.js on non-Safari browsers for proper quality switching\r\n return false;\r\n }\r\n \r\n const video = document.createElement('video');\r\n return video.canPlayType('application/vnd.apple.mpegurl') !== '';\r\n }\r\n\r\n async initNative() {\r\n // Use HTML5 renderer for native HLS support\r\n const HTML5Renderer = (await import('./HTML5Renderer.js')).HTML5Renderer;\r\n const renderer = new HTML5Renderer(this.player);\r\n await renderer.init();\r\n \r\n // Copy methods\r\n Object.getOwnPropertyNames(Object.getPrototypeOf(renderer)).forEach(method => {\r\n if (method !== 'constructor' && typeof renderer[method] === 'function') {\r\n this[method] = renderer[method].bind(renderer);\r\n }\r\n });\r\n }\r\n\r\n async initHlsJs() {\r\n // Hide native controls\r\n this.media.controls = false;\r\n this.media.removeAttribute('controls');\r\n \r\n // Load hls.js if not already loaded\r\n if (!window.Hls) {\r\n await this.loadHlsJs();\r\n }\r\n\r\n if (!window.Hls.isSupported()) {\r\n throw new Error('HLS is not supported in this browser');\r\n }\r\n\r\n // Create hls.js instance with better error recovery\r\n this.hls = new window.Hls({\r\n debug: this.player.options.debug,\r\n enableWorker: true,\r\n lowLatencyMode: false,\r\n backBufferLength: 90,\r\n maxBufferLength: 30,\r\n maxMaxBufferLength: 600,\r\n maxBufferSize: 60 * 1000 * 1000,\r\n maxBufferHole: 0.5,\r\n // Network retry settings\r\n manifestLoadingTimeOut: 10000,\r\n manifestLoadingMaxRetry: 4,\r\n manifestLoadingRetryDelay: 1000,\r\n manifestLoadingMaxRetryTimeout: 64000,\r\n levelLoadingTimeOut: 10000,\r\n levelLoadingMaxRetry: 4,\r\n levelLoadingRetryDelay: 1000,\r\n levelLoadingMaxRetryTimeout: 64000,\r\n fragLoadingTimeOut: 20000,\r\n fragLoadingMaxRetry: 6,\r\n fragLoadingRetryDelay: 1000,\r\n fragLoadingMaxRetryTimeout: 64000\r\n });\r\n\r\n // Attach media element\r\n this.hls.attachMedia(this.media);\r\n\r\n // Load source - Get from attribute to avoid blob URL conversion\r\n let src;\r\n const sourceElement = this.player.element.querySelector('source');\r\n if (sourceElement) {\r\n // Use getAttribute to get the original URL, not the blob-converted one\r\n src = sourceElement.getAttribute('src');\r\n } else {\r\n // Fallback to element's src attribute\r\n src = this.player.element.getAttribute('src') || this.player.element.src;\r\n }\r\n \r\n this.player.log(`Loading HLS source: ${src}`, 'log');\r\n \r\n if (!src) {\r\n throw new Error('No HLS source found');\r\n }\r\n \r\n this.hls.loadSource(src);\r\n\r\n // Attach events\r\n this.attachHlsEvents();\r\n this.attachMediaEvents();\r\n }\r\n\r\n async loadHlsJs() {\r\n return new Promise((resolve, reject) => {\r\n const script = document.createElement('script');\r\n script.src = 'https://cdn.jsdelivr.net/npm/hls.js@latest';\r\n script.onload = () => resolve();\r\n script.onerror = () => reject(new Error('Failed to load hls.js'));\r\n document.head.appendChild(script);\r\n });\r\n }\r\n\r\n attachHlsEvents() {\r\n this.hls.on(window.Hls.Events.MANIFEST_PARSED, (event, data) => {\r\n this.player.log('HLS manifest loaded, found ' + data.levels.length + ' quality levels');\r\n this.player.emit('hlsmanifestparsed', data);\r\n });\r\n\r\n this.hls.on(window.Hls.Events.LEVEL_SWITCHED, (event, data) => {\r\n this.player.log('HLS level switched to ' + data.level);\r\n this.player.emit('hlslevelswitched', data);\r\n });\r\n\r\n this.hls.on(window.Hls.Events.ERROR, (event, data) => {\r\n this.handleHlsError(data);\r\n });\r\n\r\n this.hls.on(window.Hls.Events.FRAG_BUFFERED, () => {\r\n this.player.state.buffering = false;\r\n });\r\n }\r\n\r\n attachMediaEvents() {\r\n // Use same events as HTML5 renderer\r\n this.media.addEventListener('loadedmetadata', () => {\r\n this.player.state.duration = this.media.duration;\r\n this.player.emit('loadedmetadata');\r\n });\r\n\r\n this.media.addEventListener('play', () => {\r\n this.player.state.playing = true;\r\n this.player.state.paused = false;\r\n this.player.state.ended = false;\r\n this.player.emit('play');\r\n \r\n if (this.player.options.onPlay) {\r\n this.player.options.onPlay.call(this.player);\r\n }\r\n });\r\n\r\n this.media.addEventListener('pause', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.emit('pause');\r\n \r\n if (this.player.options.onPause) {\r\n this.player.options.onPause.call(this.player);\r\n }\r\n });\r\n\r\n this.media.addEventListener('ended', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.state.ended = true;\r\n this.player.emit('ended');\r\n \r\n if (this.player.options.onEnded) {\r\n this.player.options.onEnded.call(this.player);\r\n }\r\n \r\n if (this.player.options.loop) {\r\n this.player.seek(0);\r\n this.player.play();\r\n }\r\n });\r\n\r\n this.media.addEventListener('timeupdate', () => {\r\n this.player.state.currentTime = this.media.currentTime;\r\n this.player.emit('timeupdate', this.media.currentTime);\r\n \r\n if (this.player.options.onTimeUpdate) {\r\n this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);\r\n }\r\n });\r\n\r\n this.media.addEventListener('volumechange', () => {\r\n this.player.state.volume = this.media.volume;\r\n this.player.state.muted = this.media.muted;\r\n this.player.emit('volumechange', this.media.volume);\r\n });\r\n\r\n this.media.addEventListener('waiting', () => {\r\n this.player.state.buffering = true;\r\n this.player.emit('waiting');\r\n });\r\n\r\n this.media.addEventListener('canplay', () => {\r\n this.player.state.buffering = false;\r\n this.player.emit('canplay');\r\n });\r\n\r\n this.media.addEventListener('error', () => {\r\n this.player.handleError(this.media.error);\r\n });\r\n }\r\n\r\n handleHlsError(data) {\r\n // Log detailed error info\r\n this.player.log(`HLS Error - Type: ${data.type}, Details: ${data.details}, Fatal: ${data.fatal}`, 'warn');\r\n if (data.response) {\r\n this.player.log(`Response code: ${data.response.code}, URL: ${data.response.url}`, 'warn');\r\n }\r\n \r\n if (data.fatal) {\r\n switch (data.type) {\r\n case window.Hls.ErrorTypes.NETWORK_ERROR:\r\n this.player.log('Fatal network error, trying to recover...', 'error');\r\n this.player.log(`Network error details: ${data.details}`, 'error');\r\n setTimeout(() => {\r\n this.hls.startLoad();\r\n }, 1000);\r\n break;\r\n \r\n case window.Hls.ErrorTypes.MEDIA_ERROR:\r\n this.player.log('Fatal media error, trying to recover...', 'error');\r\n this.hls.recoverMediaError();\r\n break;\r\n \r\n default:\r\n this.player.log('Fatal error, cannot recover', 'error');\r\n this.player.handleError(new Error(`HLS Error: ${data.type} - ${data.details}`));\r\n this.hls.destroy();\r\n break;\r\n }\r\n } else {\r\n this.player.log('Non-fatal HLS error: ' + data.details, 'warn');\r\n }\r\n }\r\n\r\n play() {\r\n // Save scroll position to prevent browser from scrolling to video\r\n const scrollX = window.scrollX;\r\n const scrollY = window.scrollY;\r\n \r\n const promise = this.media.play();\r\n \r\n // Restore scroll position immediately to prevent auto-scroll\r\n window.scrollTo(scrollX, scrollY);\r\n \r\n if (promise !== undefined) {\r\n promise.catch(error => {\r\n this.player.log('Play failed:', error, 'warn');\r\n });\r\n }\r\n }\r\n\r\n pause() {\r\n this.media.pause();\r\n }\r\n\r\n seek(time) {\r\n this.media.currentTime = time;\r\n }\r\n\r\n setVolume(volume) {\r\n this.media.volume = volume;\r\n }\r\n\r\n setMuted(muted) {\r\n this.media.muted = muted;\r\n }\r\n\r\n setPlaybackSpeed(speed) {\r\n this.media.playbackRate = speed;\r\n }\r\n\r\n switchQuality(levelIndex) {\r\n if (this.hls) {\r\n this.hls.currentLevel = levelIndex;\r\n }\r\n }\r\n\r\n getQualities() {\r\n if (this.hls && this.hls.levels) {\r\n return this.hls.levels.map((level, index) => ({\r\n index,\r\n height: level.height,\r\n width: level.width,\r\n bitrate: level.bitrate,\r\n name: `${level.height}p`\r\n }));\r\n }\r\n return [];\r\n }\r\n\r\n getCurrentQuality() {\r\n if (this.hls) {\r\n return this.hls.currentLevel;\r\n }\r\n return -1;\r\n }\r\n\r\n destroy() {\r\n if (this.hls) {\r\n this.hls.destroy();\r\n this.hls = null;\r\n }\r\n }\r\n}\r\n\r\n"],
5
- "mappings": ";;;;;;;AAKO,IAAM,cAAN,MAAkB;AAAA,EACvB,YAAY,QAAQ;AAClB,SAAK,SAAS;AACd,SAAK,QAAQ,OAAO;AACpB,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,MAAM,OAAO;AAEX,QAAI,KAAK,gBAAgB,GAAG;AAC1B,WAAK,OAAO,IAAI,0BAA0B;AAC1C,YAAM,KAAK,WAAW;AAAA,IACxB,OAAO;AACL,WAAK,OAAO,IAAI,8BAA8B;AAC9C,YAAM,KAAK,UAAU;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,kBAAkB;AAGhB,UAAM,WAAW,iCAAiC,KAAK,UAAU,SAAS;AAC1E,UAAM,QAAQ,mBAAmB,KAAK,UAAU,SAAS,KAAK,CAAC,OAAO;AAEtE,QAAI,CAAC,YAAY,CAAC,OAAO;AAEvB,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,WAAO,MAAM,YAAY,+BAA+B,MAAM;AAAA,EAChE;AAAA,EAEA,MAAM,aAAa;AAEjB,UAAM,iBAAiB,MAAM,OAAO,oCAAoB,GAAG;AAC3D,UAAM,WAAW,IAAI,cAAc,KAAK,MAAM;AAC9C,UAAM,SAAS,KAAK;AAGpB,WAAO,oBAAoB,OAAO,eAAe,QAAQ,CAAC,EAAE,QAAQ,YAAU;AAC5E,UAAI,WAAW,iBAAiB,OAAO,SAAS,MAAM,MAAM,YAAY;AACtE,aAAK,MAAM,IAAI,SAAS,MAAM,EAAE,KAAK,QAAQ;AAAA,MAC/C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YAAY;AAEhB,SAAK,MAAM,WAAW;AACtB,SAAK,MAAM,gBAAgB,UAAU;AAGrC,QAAI,CAAC,OAAO,KAAK;AACf,YAAM,KAAK,UAAU;AAAA,IACvB;AAEA,QAAI,CAAC,OAAO,IAAI,YAAY,GAAG;AAC7B,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AAGA,SAAK,MAAM,IAAI,OAAO,IAAI;AAAA,MACxB,OAAO,KAAK,OAAO,QAAQ;AAAA,MAC3B,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB,kBAAkB;AAAA,MAClB,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,eAAe,KAAK,MAAO;AAAA,MAC3B,eAAe;AAAA;AAAA,MAEf,wBAAwB;AAAA,MACxB,yBAAyB;AAAA,MACzB,2BAA2B;AAAA,MAC3B,gCAAgC;AAAA,MAChC,qBAAqB;AAAA,MACrB,sBAAsB;AAAA,MACtB,wBAAwB;AAAA,MACxB,6BAA6B;AAAA,MAC7B,oBAAoB;AAAA,MACpB,qBAAqB;AAAA,MACrB,uBAAuB;AAAA,MACvB,4BAA4B;AAAA,IAC9B,CAAC;AAGD,SAAK,IAAI,YAAY,KAAK,KAAK;AAG/B,QAAI;AACJ,UAAM,gBAAgB,KAAK,OAAO,QAAQ,cAAc,QAAQ;AAChE,QAAI,eAAe;AAEjB,YAAM,cAAc,aAAa,KAAK;AAAA,IACxC,OAAO;AAEL,YAAM,KAAK,OAAO,QAAQ,aAAa,KAAK,KAAK,KAAK,OAAO,QAAQ;AAAA,IACvE;AAEA,SAAK,OAAO,IAAI,uBAAuB,GAAG,IAAI,KAAK;AAEnD,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AAEA,SAAK,IAAI,WAAW,GAAG;AAGvB,SAAK,gBAAgB;AACrB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,MAAM,YAAY;AAChB,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,MAAM;AACb,aAAO,SAAS,MAAM,QAAQ;AAC9B,aAAO,UAAU,MAAM,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAChE,eAAS,KAAK,YAAY,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB;AAChB,SAAK,IAAI,GAAG,OAAO,IAAI,OAAO,iBAAiB,CAAC,OAAO,SAAS;AAC9D,WAAK,OAAO,IAAI,gCAAgC,KAAK,OAAO,SAAS,iBAAiB;AACtF,WAAK,OAAO,KAAK,qBAAqB,IAAI;AAAA,IAC5C,CAAC;AAED,SAAK,IAAI,GAAG,OAAO,IAAI,OAAO,gBAAgB,CAAC,OAAO,SAAS;AAC7D,WAAK,OAAO,IAAI,2BAA2B,KAAK,KAAK;AACrD,WAAK,OAAO,KAAK,oBAAoB,IAAI;AAAA,IAC3C,CAAC;AAED,SAAK,IAAI,GAAG,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,SAAS;AACpD,WAAK,eAAe,IAAI;AAAA,IAC1B,CAAC;AAED,SAAK,IAAI,GAAG,OAAO,IAAI,OAAO,eAAe,MAAM;AACjD,WAAK,OAAO,MAAM,YAAY;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,oBAAoB;AAElB,SAAK,MAAM,iBAAiB,kBAAkB,MAAM;AAClD,WAAK,OAAO,MAAM,WAAW,KAAK,MAAM;AACxC,WAAK,OAAO,KAAK,gBAAgB;AAAA,IACnC,CAAC;AAED,SAAK,MAAM,iBAAiB,QAAQ,MAAM;AACxC,WAAK,OAAO,MAAM,UAAU;AAC5B,WAAK,OAAO,MAAM,SAAS;AAC3B,WAAK,OAAO,MAAM,QAAQ;AAC1B,WAAK,OAAO,KAAK,MAAM;AAEvB,UAAI,KAAK,OAAO,QAAQ,QAAQ;AAC9B,aAAK,OAAO,QAAQ,OAAO,KAAK,KAAK,MAAM;AAAA,MAC7C;AAAA,IACF,CAAC;AAED,SAAK,MAAM,iBAAiB,SAAS,MAAM;AACzC,WAAK,OAAO,MAAM,UAAU;AAC5B,WAAK,OAAO,MAAM,SAAS;AAC3B,WAAK,OAAO,KAAK,OAAO;AAExB,UAAI,KAAK,OAAO,QAAQ,SAAS;AAC/B,aAAK,OAAO,QAAQ,QAAQ,KAAK,KAAK,MAAM;AAAA,MAC9C;AAAA,IACF,CAAC;AAED,SAAK,MAAM,iBAAiB,SAAS,MAAM;AACzC,WAAK,OAAO,MAAM,UAAU;AAC5B,WAAK,OAAO,MAAM,SAAS;AAC3B,WAAK,OAAO,MAAM,QAAQ;AAC1B,WAAK,OAAO,KAAK,OAAO;AAExB,UAAI,KAAK,OAAO,QAAQ,SAAS;AAC/B,aAAK,OAAO,QAAQ,QAAQ,KAAK,KAAK,MAAM;AAAA,MAC9C;AAEA,UAAI,KAAK,OAAO,QAAQ,MAAM;AAC5B,aAAK,OAAO,KAAK,CAAC;AAClB,aAAK,OAAO,KAAK;AAAA,MACnB;AAAA,IACF,CAAC;AAED,SAAK,MAAM,iBAAiB,cAAc,MAAM;AAC9C,WAAK,OAAO,MAAM,cAAc,KAAK,MAAM;AAC3C,WAAK,OAAO,KAAK,cAAc,KAAK,MAAM,WAAW;AAErD,UAAI,KAAK,OAAO,QAAQ,cAAc;AACpC,aAAK,OAAO,QAAQ,aAAa,KAAK,KAAK,QAAQ,KAAK,MAAM,WAAW;AAAA,MAC3E;AAAA,IACF,CAAC;AAED,SAAK,MAAM,iBAAiB,gBAAgB,MAAM;AAChD,WAAK,OAAO,MAAM,SAAS,KAAK,MAAM;AACtC,WAAK,OAAO,MAAM,QAAQ,KAAK,MAAM;AACrC,WAAK,OAAO,KAAK,gBAAgB,KAAK,MAAM,MAAM;AAAA,IACpD,CAAC;AAED,SAAK,MAAM,iBAAiB,WAAW,MAAM;AAC3C,WAAK,OAAO,MAAM,YAAY;AAC9B,WAAK,OAAO,KAAK,SAAS;AAAA,IAC5B,CAAC;AAED,SAAK,MAAM,iBAAiB,WAAW,MAAM;AAC3C,WAAK,OAAO,MAAM,YAAY;AAC9B,WAAK,OAAO,KAAK,SAAS;AAAA,IAC5B,CAAC;AAED,SAAK,MAAM,iBAAiB,SAAS,MAAM;AACzC,WAAK,OAAO,YAAY,KAAK,MAAM,KAAK;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,MAAM;AAEnB,SAAK,OAAO,IAAI,qBAAqB,KAAK,IAAI,cAAc,KAAK,OAAO,YAAY,KAAK,KAAK,IAAI,MAAM;AACxG,QAAI,KAAK,UAAU;AACjB,WAAK,OAAO,IAAI,kBAAkB,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,GAAG,IAAI,MAAM;AAAA,IAC3F;AAEA,QAAI,KAAK,OAAO;AACd,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK,OAAO,IAAI,WAAW;AACzB,eAAK,OAAO,IAAI,6CAA6C,OAAO;AACpE,eAAK,OAAO,IAAI,0BAA0B,KAAK,OAAO,IAAI,OAAO;AACjE,qBAAW,MAAM;AACf,iBAAK,IAAI,UAAU;AAAA,UACrB,GAAG,GAAI;AACP;AAAA,QAEF,KAAK,OAAO,IAAI,WAAW;AACzB,eAAK,OAAO,IAAI,2CAA2C,OAAO;AAClE,eAAK,IAAI,kBAAkB;AAC3B;AAAA,QAEF;AACE,eAAK,OAAO,IAAI,+BAA+B,OAAO;AACtD,eAAK,OAAO,YAAY,IAAI,MAAM,cAAc,KAAK,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;AAC9E,eAAK,IAAI,QAAQ;AACjB;AAAA,MACJ;AAAA,IACF,OAAO;AACL,WAAK,OAAO,IAAI,0BAA0B,KAAK,SAAS,MAAM;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,OAAO;AAEL,UAAM,UAAU,OAAO;AACvB,UAAM,UAAU,OAAO;AAEvB,UAAM,UAAU,KAAK,MAAM,KAAK;AAGhC,WAAO,SAAS,SAAS,OAAO;AAEhC,QAAI,YAAY,QAAW;AACzB,cAAQ,MAAM,WAAS;AACrB,aAAK,OAAO,IAAI,gBAAgB,OAAO,MAAM;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEA,KAAK,MAAM;AACT,SAAK,MAAM,cAAc;AAAA,EAC3B;AAAA,EAEA,UAAU,QAAQ;AAChB,SAAK,MAAM,SAAS;AAAA,EACtB;AAAA,EAEA,SAAS,OAAO;AACd,SAAK,MAAM,QAAQ;AAAA,EACrB;AAAA,EAEA,iBAAiB,OAAO;AACtB,SAAK,MAAM,eAAe;AAAA,EAC5B;AAAA,EAEA,cAAc,YAAY;AACxB,QAAI,KAAK,KAAK;AACZ,WAAK,IAAI,eAAe;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,eAAe;AACb,QAAI,KAAK,OAAO,KAAK,IAAI,QAAQ;AAC/B,aAAO,KAAK,IAAI,OAAO,IAAI,CAAC,OAAO,WAAW;AAAA,QAC5C;AAAA,QACA,QAAQ,MAAM;AAAA,QACd,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,QACf,MAAM,GAAG,MAAM,MAAM;AAAA,MACvB,EAAE;AAAA,IACJ;AACA,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,oBAAoB;AAClB,QAAI,KAAK,KAAK;AACZ,aAAO,KAAK,IAAI;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,UAAU;AACR,QAAI,KAAK,KAAK;AACZ,WAAK,IAAI,QAAQ;AACjB,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/renderers/VimeoRenderer.js"],
4
- "sourcesContent": ["/**\r\n * Vimeo Renderer\r\n */\r\n\r\nexport class VimeoRenderer {\r\n constructor(player) {\r\n this.player = player;\r\n this.vimeo = null;\r\n this.videoId = null;\r\n this.isReady = false;\r\n this.iframe = null;\r\n }\r\n\r\n async init() {\r\n // Extract video ID from URL\r\n this.videoId = this.extractVideoId(this.player.element.src);\r\n \r\n if (!this.videoId) {\r\n throw new Error('Invalid Vimeo URL');\r\n }\r\n\r\n // Load Vimeo Player API\r\n await this.loadVimeoAPI();\r\n\r\n // Create iframe\r\n this.createIframe();\r\n\r\n // Initialize player\r\n await this.initializePlayer();\r\n }\r\n\r\n extractVideoId(url) {\r\n const patterns = [\r\n /vimeo\\.com\\/(\\d+)/,\r\n /vimeo\\.com\\/video\\/(\\d+)/,\r\n /player\\.vimeo\\.com\\/video\\/(\\d+)/\r\n ];\r\n\r\n for (const pattern of patterns) {\r\n const match = url.match(pattern);\r\n if (match && match[1]) {\r\n return match[1];\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n async loadVimeoAPI() {\r\n // Check if API is already loaded\r\n if (window.Vimeo && window.Vimeo.Player) {\r\n return Promise.resolve();\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const script = document.createElement('script');\r\n script.src = 'https://player.vimeo.com/api/player.js';\r\n script.onload = () => resolve();\r\n script.onerror = () => reject(new Error('Failed to load Vimeo API'));\r\n document.head.appendChild(script);\r\n });\r\n }\r\n\r\n createIframe() {\r\n // Hide original element\r\n this.player.element.style.display = 'none';\r\n\r\n // Create container for iframe\r\n this.iframe = document.createElement('div');\r\n this.iframe.id = `vimeo-player-${Math.random().toString(36).substr(2, 9)}`;\r\n this.iframe.style.width = '100%';\r\n this.iframe.style.height = '100%';\r\n \r\n this.player.element.parentNode.insertBefore(this.iframe, this.player.element);\r\n }\r\n\r\n async initializePlayer() {\r\n const options = {\r\n id: this.videoId,\r\n width: '100%',\r\n height: '100%',\r\n controls: false,\r\n autoplay: this.player.options.autoplay,\r\n muted: this.player.options.muted,\r\n loop: this.player.options.loop,\r\n keyboard: false\r\n };\r\n\r\n if (this.player.options.startTime > 0) {\r\n options.startTime = this.player.options.startTime;\r\n }\r\n\r\n this.vimeo = new window.Vimeo.Player(this.iframe.id, options);\r\n\r\n // Wait for player to be ready\r\n await this.vimeo.ready();\r\n this.isReady = true;\r\n\r\n this.attachEvents();\r\n\r\n // Get initial duration\r\n try {\r\n const duration = await this.vimeo.getDuration();\r\n this.player.state.duration = duration;\r\n this.player.emit('loadedmetadata');\r\n } catch (error) {\r\n this.player.log('Error getting duration:', error, 'warn');\r\n }\r\n }\r\n\r\n attachEvents() {\r\n this.vimeo.on('play', () => {\r\n this.player.state.playing = true;\r\n this.player.state.paused = false;\r\n this.player.state.ended = false;\r\n this.player.emit('play');\r\n \r\n if (this.player.options.onPlay) {\r\n this.player.options.onPlay.call(this.player);\r\n }\r\n });\r\n\r\n this.vimeo.on('pause', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.emit('pause');\r\n \r\n if (this.player.options.onPause) {\r\n this.player.options.onPause.call(this.player);\r\n }\r\n });\r\n\r\n this.vimeo.on('ended', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.state.ended = true;\r\n this.player.emit('ended');\r\n \r\n if (this.player.options.onEnded) {\r\n this.player.options.onEnded.call(this.player);\r\n }\r\n });\r\n\r\n this.vimeo.on('timeupdate', (data) => {\r\n this.player.state.currentTime = data.seconds;\r\n this.player.state.duration = data.duration;\r\n this.player.emit('timeupdate', data.seconds);\r\n \r\n if (this.player.options.onTimeUpdate) {\r\n this.player.options.onTimeUpdate.call(this.player, data.seconds);\r\n }\r\n });\r\n\r\n this.vimeo.on('volumechange', (data) => {\r\n this.player.state.volume = data.volume;\r\n this.player.emit('volumechange', data.volume);\r\n });\r\n\r\n this.vimeo.on('bufferstart', () => {\r\n this.player.state.buffering = true;\r\n this.player.emit('waiting');\r\n });\r\n\r\n this.vimeo.on('bufferend', () => {\r\n this.player.state.buffering = false;\r\n this.player.emit('canplay');\r\n });\r\n\r\n this.vimeo.on('seeking', () => {\r\n this.player.state.seeking = true;\r\n this.player.emit('seeking');\r\n });\r\n\r\n this.vimeo.on('seeked', () => {\r\n this.player.state.seeking = false;\r\n this.player.emit('seeked');\r\n });\r\n\r\n this.vimeo.on('playbackratechange', (data) => {\r\n this.player.state.playbackSpeed = data.playbackRate;\r\n this.player.emit('ratechange', data.playbackRate);\r\n });\r\n\r\n this.vimeo.on('error', (error) => {\r\n this.player.handleError(new Error(`Vimeo error: ${error.message}`));\r\n });\r\n }\r\n\r\n play() {\r\n if (this.isReady && this.vimeo) {\r\n // Save scroll position to prevent browser from scrolling to video\r\n const scrollX = window.scrollX;\r\n const scrollY = window.scrollY;\r\n \r\n this.vimeo.play().catch(error => {\r\n this.player.log('Play error:', error, 'warn');\r\n });\r\n \r\n // Restore scroll position immediately to prevent auto-scroll\r\n window.scrollTo(scrollX, scrollY);\r\n }\r\n }\r\n\r\n pause() {\r\n if (this.isReady && this.vimeo) {\r\n this.vimeo.pause().catch(error => {\r\n this.player.log('Pause error:', error, 'warn');\r\n });\r\n }\r\n }\r\n\r\n seek(time) {\r\n if (this.isReady && this.vimeo) {\r\n this.vimeo.setCurrentTime(time).catch(error => {\r\n this.player.log('Seek error:', error, 'warn');\r\n });\r\n }\r\n }\r\n\r\n setVolume(volume) {\r\n if (this.isReady && this.vimeo) {\r\n this.vimeo.setVolume(volume).catch(error => {\r\n this.player.log('Volume error:', error, 'warn');\r\n });\r\n this.player.state.volume = volume;\r\n }\r\n }\r\n\r\n setMuted(muted) {\r\n if (this.isReady && this.vimeo) {\r\n if (muted) {\r\n this.vimeo.setVolume(0);\r\n } else {\r\n this.vimeo.setVolume(this.player.state.volume);\r\n }\r\n this.player.state.muted = muted;\r\n }\r\n }\r\n\r\n setPlaybackSpeed(speed) {\r\n if (this.isReady && this.vimeo) {\r\n this.vimeo.setPlaybackRate(speed).catch(error => {\r\n this.player.log('Playback rate error:', error, 'warn');\r\n });\r\n this.player.state.playbackSpeed = speed;\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.vimeo && this.vimeo.destroy) {\r\n this.vimeo.destroy();\r\n }\r\n\r\n if (this.iframe && this.iframe.parentNode) {\r\n this.iframe.parentNode.removeChild(this.iframe);\r\n }\r\n\r\n // Show original element\r\n if (this.player.element) {\r\n this.player.element.style.display = '';\r\n }\r\n }\r\n}\r\n\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/renderers/YouTubeRenderer.js"],
4
- "sourcesContent": ["/**\r\n * YouTube Renderer\r\n */\r\n\r\nexport class YouTubeRenderer {\r\n constructor(player) {\r\n this.player = player;\r\n this.youtube = null;\r\n this.videoId = null;\r\n this.isReady = false;\r\n this.iframe = null;\r\n }\r\n\r\n async init() {\r\n // Extract video ID from URL\r\n this.videoId = this.extractVideoId(this.player.element.src);\r\n \r\n if (!this.videoId) {\r\n throw new Error('Invalid YouTube URL');\r\n }\r\n\r\n // Load YouTube IFrame API\r\n await this.loadYouTubeAPI();\r\n\r\n // Create iframe\r\n this.createIframe();\r\n\r\n // Initialize player\r\n await this.initializePlayer();\r\n }\r\n\r\n extractVideoId(url) {\r\n const patterns = [\r\n /(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/)([^&\\s]+)/,\r\n /youtube\\.com\\/embed\\/([^&\\s]+)/\r\n ];\r\n\r\n for (const pattern of patterns) {\r\n const match = url.match(pattern);\r\n if (match && match[1]) {\r\n return match[1];\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n async loadYouTubeAPI() {\r\n // Check if API is already loaded\r\n if (window.YT && window.YT.Player) {\r\n return Promise.resolve();\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n // Check if script is already being loaded\r\n if (window.onYouTubeIframeAPIReady) {\r\n const originalCallback = window.onYouTubeIframeAPIReady;\r\n window.onYouTubeIframeAPIReady = () => {\r\n originalCallback();\r\n resolve();\r\n };\r\n return;\r\n }\r\n\r\n // Load the API script\r\n const tag = document.createElement('script');\r\n tag.src = 'https://www.youtube.com/iframe_api';\r\n \r\n window.onYouTubeIframeAPIReady = () => {\r\n resolve();\r\n };\r\n\r\n tag.onerror = () => reject(new Error('Failed to load YouTube API'));\r\n \r\n const firstScriptTag = document.getElementsByTagName('script')[0];\r\n firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\r\n });\r\n }\r\n\r\n createIframe() {\r\n // Hide original element\r\n this.player.element.style.display = 'none';\r\n\r\n // Create container for iframe\r\n this.iframe = document.createElement('div');\r\n this.iframe.id = `youtube-player-${Math.random().toString(36).substr(2, 9)}`;\r\n this.iframe.style.width = '100%';\r\n this.iframe.style.height = '100%';\r\n \r\n this.player.element.parentNode.insertBefore(this.iframe, this.player.element);\r\n }\r\n\r\n async initializePlayer() {\r\n return new Promise((resolve) => {\r\n this.youtube = new window.YT.Player(this.iframe.id, {\r\n videoId: this.videoId,\r\n width: '100%',\r\n height: '100%',\r\n playerVars: {\r\n controls: 0,\r\n disablekb: 1,\r\n fs: 0,\r\n modestbranding: 1,\r\n rel: 0,\r\n showinfo: 0,\r\n iv_load_policy: 3,\r\n autoplay: this.player.options.autoplay ? 1 : 0,\r\n mute: this.player.options.muted ? 1 : 0,\r\n start: this.player.options.startTime || 0\r\n },\r\n events: {\r\n onReady: (event) => {\r\n this.isReady = true;\r\n this.attachEvents();\r\n resolve();\r\n },\r\n onStateChange: (event) => this.handleStateChange(event),\r\n onError: (event) => this.handleError(event)\r\n }\r\n });\r\n });\r\n }\r\n\r\n attachEvents() {\r\n // Set up polling for time updates (YouTube doesn't provide timeupdate events)\r\n this.timeUpdateInterval = setInterval(() => {\r\n if (this.isReady && this.youtube) {\r\n const currentTime = this.youtube.getCurrentTime();\r\n const duration = this.youtube.getDuration();\r\n \r\n this.player.state.currentTime = currentTime;\r\n this.player.state.duration = duration;\r\n \r\n this.player.emit('timeupdate', currentTime);\r\n }\r\n }, 250);\r\n\r\n // Initial metadata\r\n if (this.youtube.getDuration) {\r\n this.player.state.duration = this.youtube.getDuration();\r\n this.player.emit('loadedmetadata');\r\n }\r\n }\r\n\r\n handleStateChange(event) {\r\n const states = window.YT.PlayerState;\r\n\r\n switch (event.data) {\r\n case states.PLAYING:\r\n this.player.state.playing = true;\r\n this.player.state.paused = false;\r\n this.player.state.ended = false;\r\n this.player.state.buffering = false;\r\n this.player.emit('play');\r\n this.player.emit('playing');\r\n \r\n if (this.player.options.onPlay) {\r\n this.player.options.onPlay.call(this.player);\r\n }\r\n break;\r\n\r\n case states.PAUSED:\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.emit('pause');\r\n \r\n if (this.player.options.onPause) {\r\n this.player.options.onPause.call(this.player);\r\n }\r\n break;\r\n\r\n case states.ENDED:\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.state.ended = true;\r\n this.player.emit('ended');\r\n \r\n if (this.player.options.onEnded) {\r\n this.player.options.onEnded.call(this.player);\r\n }\r\n \r\n if (this.player.options.loop) {\r\n this.youtube.seekTo(0);\r\n this.youtube.playVideo();\r\n }\r\n break;\r\n\r\n case states.BUFFERING:\r\n this.player.state.buffering = true;\r\n this.player.emit('waiting');\r\n break;\r\n\r\n case states.CUED:\r\n this.player.emit('loadedmetadata');\r\n break;\r\n }\r\n }\r\n\r\n handleError(event) {\r\n const errors = {\r\n 2: 'Invalid video ID',\r\n 5: 'HTML5 player error',\r\n 100: 'Video not found',\r\n 101: 'Video not allowed to be played in embedded players',\r\n 150: 'Video not allowed to be played in embedded players'\r\n };\r\n\r\n const error = new Error(errors[event.data] || 'YouTube player error');\r\n this.player.handleError(error);\r\n }\r\n\r\n play() {\r\n if (this.isReady && this.youtube) {\r\n // Save scroll position to prevent browser from scrolling to video\r\n const scrollX = window.scrollX;\r\n const scrollY = window.scrollY;\r\n \r\n this.youtube.playVideo();\r\n \r\n // Restore scroll position immediately to prevent auto-scroll\r\n window.scrollTo(scrollX, scrollY);\r\n }\r\n }\r\n\r\n pause() {\r\n if (this.isReady && this.youtube) {\r\n this.youtube.pauseVideo();\r\n }\r\n }\r\n\r\n seek(time) {\r\n if (this.isReady && this.youtube) {\r\n this.youtube.seekTo(time, true);\r\n }\r\n }\r\n\r\n setVolume(volume) {\r\n if (this.isReady && this.youtube) {\r\n this.youtube.setVolume(volume * 100);\r\n this.player.state.volume = volume;\r\n }\r\n }\r\n\r\n setMuted(muted) {\r\n if (this.isReady && this.youtube) {\r\n if (muted) {\r\n this.youtube.mute();\r\n } else {\r\n this.youtube.unMute();\r\n }\r\n this.player.state.muted = muted;\r\n }\r\n }\r\n\r\n setPlaybackSpeed(speed) {\r\n if (this.isReady && this.youtube) {\r\n this.youtube.setPlaybackRate(speed);\r\n this.player.state.playbackSpeed = speed;\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.timeUpdateInterval) {\r\n clearInterval(this.timeUpdateInterval);\r\n }\r\n\r\n if (this.youtube && this.youtube.destroy) {\r\n this.youtube.destroy();\r\n }\r\n\r\n if (this.iframe && this.iframe.parentNode) {\r\n this.iframe.parentNode.removeChild(this.iframe);\r\n }\r\n\r\n // Show original element\r\n if (this.player.element) {\r\n this.player.element.style.display = '';\r\n }\r\n }\r\n}\r\n\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }