vidply 1.0.4 → 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.
@@ -1,274 +1,274 @@
1
- /**
2
- * YouTube Renderer
3
- */
4
-
5
- export class YouTubeRenderer {
6
- constructor(player) {
7
- this.player = player;
8
- this.youtube = null;
9
- this.videoId = null;
10
- this.isReady = false;
11
- this.iframe = null;
12
- }
13
-
14
- async init() {
15
- // Extract video ID from URL
16
- this.videoId = this.extractVideoId(this.player.element.src);
17
-
18
- if (!this.videoId) {
19
- throw new Error('Invalid YouTube URL');
20
- }
21
-
22
- // Load YouTube IFrame API
23
- await this.loadYouTubeAPI();
24
-
25
- // Create iframe
26
- this.createIframe();
27
-
28
- // Initialize player
29
- await this.initializePlayer();
30
- }
31
-
32
- extractVideoId(url) {
33
- const patterns = [
34
- /(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\s]+)/,
35
- /youtube\.com\/embed\/([^&\s]+)/
36
- ];
37
-
38
- for (const pattern of patterns) {
39
- const match = url.match(pattern);
40
- if (match && match[1]) {
41
- return match[1];
42
- }
43
- }
44
-
45
- return null;
46
- }
47
-
48
- async loadYouTubeAPI() {
49
- // Check if API is already loaded
50
- if (window.YT && window.YT.Player) {
51
- return Promise.resolve();
52
- }
53
-
54
- return new Promise((resolve, reject) => {
55
- // Check if script is already being loaded
56
- if (window.onYouTubeIframeAPIReady) {
57
- const originalCallback = window.onYouTubeIframeAPIReady;
58
- window.onYouTubeIframeAPIReady = () => {
59
- originalCallback();
60
- resolve();
61
- };
62
- return;
63
- }
64
-
65
- // Load the API script
66
- const tag = document.createElement('script');
67
- tag.src = 'https://www.youtube.com/iframe_api';
68
-
69
- window.onYouTubeIframeAPIReady = () => {
70
- resolve();
71
- };
72
-
73
- tag.onerror = () => reject(new Error('Failed to load YouTube API'));
74
-
75
- const firstScriptTag = document.getElementsByTagName('script')[0];
76
- firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
77
- });
78
- }
79
-
80
- createIframe() {
81
- // Hide original element
82
- this.player.element.style.display = 'none';
83
-
84
- // Create container for iframe
85
- this.iframe = document.createElement('div');
86
- this.iframe.id = `youtube-player-${Math.random().toString(36).substr(2, 9)}`;
87
- this.iframe.style.width = '100%';
88
- this.iframe.style.height = '100%';
89
-
90
- this.player.element.parentNode.insertBefore(this.iframe, this.player.element);
91
- }
92
-
93
- async initializePlayer() {
94
- return new Promise((resolve) => {
95
- this.youtube = new window.YT.Player(this.iframe.id, {
96
- videoId: this.videoId,
97
- width: '100%',
98
- height: '100%',
99
- playerVars: {
100
- controls: 0,
101
- disablekb: 1,
102
- fs: 0,
103
- modestbranding: 1,
104
- rel: 0,
105
- showinfo: 0,
106
- iv_load_policy: 3,
107
- autoplay: this.player.options.autoplay ? 1 : 0,
108
- mute: this.player.options.muted ? 1 : 0,
109
- start: this.player.options.startTime || 0
110
- },
111
- events: {
112
- onReady: (event) => {
113
- this.isReady = true;
114
- this.attachEvents();
115
- resolve();
116
- },
117
- onStateChange: (event) => this.handleStateChange(event),
118
- onError: (event) => this.handleError(event)
119
- }
120
- });
121
- });
122
- }
123
-
124
- attachEvents() {
125
- // Set up polling for time updates (YouTube doesn't provide timeupdate events)
126
- this.timeUpdateInterval = setInterval(() => {
127
- if (this.isReady && this.youtube) {
128
- const currentTime = this.youtube.getCurrentTime();
129
- const duration = this.youtube.getDuration();
130
-
131
- this.player.state.currentTime = currentTime;
132
- this.player.state.duration = duration;
133
-
134
- this.player.emit('timeupdate', currentTime);
135
- }
136
- }, 250);
137
-
138
- // Initial metadata
139
- if (this.youtube.getDuration) {
140
- this.player.state.duration = this.youtube.getDuration();
141
- this.player.emit('loadedmetadata');
142
- }
143
- }
144
-
145
- handleStateChange(event) {
146
- const states = window.YT.PlayerState;
147
-
148
- switch (event.data) {
149
- case states.PLAYING:
150
- this.player.state.playing = true;
151
- this.player.state.paused = false;
152
- this.player.state.ended = false;
153
- this.player.state.buffering = false;
154
- this.player.emit('play');
155
- this.player.emit('playing');
156
-
157
- if (this.player.options.onPlay) {
158
- this.player.options.onPlay.call(this.player);
159
- }
160
- break;
161
-
162
- case states.PAUSED:
163
- this.player.state.playing = false;
164
- this.player.state.paused = true;
165
- this.player.emit('pause');
166
-
167
- if (this.player.options.onPause) {
168
- this.player.options.onPause.call(this.player);
169
- }
170
- break;
171
-
172
- case states.ENDED:
173
- this.player.state.playing = false;
174
- this.player.state.paused = true;
175
- this.player.state.ended = true;
176
- this.player.emit('ended');
177
-
178
- if (this.player.options.onEnded) {
179
- this.player.options.onEnded.call(this.player);
180
- }
181
-
182
- if (this.player.options.loop) {
183
- this.youtube.seekTo(0);
184
- this.youtube.playVideo();
185
- }
186
- break;
187
-
188
- case states.BUFFERING:
189
- this.player.state.buffering = true;
190
- this.player.emit('waiting');
191
- break;
192
-
193
- case states.CUED:
194
- this.player.emit('loadedmetadata');
195
- break;
196
- }
197
- }
198
-
199
- handleError(event) {
200
- const errors = {
201
- 2: 'Invalid video ID',
202
- 5: 'HTML5 player error',
203
- 100: 'Video not found',
204
- 101: 'Video not allowed to be played in embedded players',
205
- 150: 'Video not allowed to be played in embedded players'
206
- };
207
-
208
- const error = new Error(errors[event.data] || 'YouTube player error');
209
- this.player.handleError(error);
210
- }
211
-
212
- play() {
213
- if (this.isReady && this.youtube) {
214
- this.youtube.playVideo();
215
- }
216
- }
217
-
218
- pause() {
219
- if (this.isReady && this.youtube) {
220
- this.youtube.pauseVideo();
221
- }
222
- }
223
-
224
- seek(time) {
225
- if (this.isReady && this.youtube) {
226
- this.youtube.seekTo(time, true);
227
- }
228
- }
229
-
230
- setVolume(volume) {
231
- if (this.isReady && this.youtube) {
232
- this.youtube.setVolume(volume * 100);
233
- this.player.state.volume = volume;
234
- }
235
- }
236
-
237
- setMuted(muted) {
238
- if (this.isReady && this.youtube) {
239
- if (muted) {
240
- this.youtube.mute();
241
- } else {
242
- this.youtube.unMute();
243
- }
244
- this.player.state.muted = muted;
245
- }
246
- }
247
-
248
- setPlaybackSpeed(speed) {
249
- if (this.isReady && this.youtube) {
250
- this.youtube.setPlaybackRate(speed);
251
- this.player.state.playbackSpeed = speed;
252
- }
253
- }
254
-
255
- destroy() {
256
- if (this.timeUpdateInterval) {
257
- clearInterval(this.timeUpdateInterval);
258
- }
259
-
260
- if (this.youtube && this.youtube.destroy) {
261
- this.youtube.destroy();
262
- }
263
-
264
- if (this.iframe && this.iframe.parentNode) {
265
- this.iframe.parentNode.removeChild(this.iframe);
266
- }
267
-
268
- // Show original element
269
- if (this.player.element) {
270
- this.player.element.style.display = '';
271
- }
272
- }
273
- }
274
-
1
+ /**
2
+ * YouTube Renderer
3
+ */
4
+
5
+ export class YouTubeRenderer {
6
+ constructor(player) {
7
+ this.player = player;
8
+ this.youtube = null;
9
+ this.videoId = null;
10
+ this.isReady = false;
11
+ this.iframe = null;
12
+ }
13
+
14
+ async init() {
15
+ // Extract video ID from URL
16
+ this.videoId = this.extractVideoId(this.player.element.src);
17
+
18
+ if (!this.videoId) {
19
+ throw new Error('Invalid YouTube URL');
20
+ }
21
+
22
+ // Load YouTube IFrame API
23
+ await this.loadYouTubeAPI();
24
+
25
+ // Create iframe
26
+ this.createIframe();
27
+
28
+ // Initialize player
29
+ await this.initializePlayer();
30
+ }
31
+
32
+ extractVideoId(url) {
33
+ const patterns = [
34
+ /(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\s]+)/,
35
+ /youtube\.com\/embed\/([^&\s]+)/
36
+ ];
37
+
38
+ for (const pattern of patterns) {
39
+ const match = url.match(pattern);
40
+ if (match && match[1]) {
41
+ return match[1];
42
+ }
43
+ }
44
+
45
+ return null;
46
+ }
47
+
48
+ async loadYouTubeAPI() {
49
+ // Check if API is already loaded
50
+ if (window.YT && window.YT.Player) {
51
+ return Promise.resolve();
52
+ }
53
+
54
+ return new Promise((resolve, reject) => {
55
+ // Check if script is already being loaded
56
+ if (window.onYouTubeIframeAPIReady) {
57
+ const originalCallback = window.onYouTubeIframeAPIReady;
58
+ window.onYouTubeIframeAPIReady = () => {
59
+ originalCallback();
60
+ resolve();
61
+ };
62
+ return;
63
+ }
64
+
65
+ // Load the API script
66
+ const tag = document.createElement('script');
67
+ tag.src = 'https://www.youtube.com/iframe_api';
68
+
69
+ window.onYouTubeIframeAPIReady = () => {
70
+ resolve();
71
+ };
72
+
73
+ tag.onerror = () => reject(new Error('Failed to load YouTube API'));
74
+
75
+ const firstScriptTag = document.getElementsByTagName('script')[0];
76
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
77
+ });
78
+ }
79
+
80
+ createIframe() {
81
+ // Hide original element
82
+ this.player.element.style.display = 'none';
83
+
84
+ // Create container for iframe
85
+ this.iframe = document.createElement('div');
86
+ this.iframe.id = `youtube-player-${Math.random().toString(36).substr(2, 9)}`;
87
+ this.iframe.style.width = '100%';
88
+ this.iframe.style.height = '100%';
89
+
90
+ this.player.element.parentNode.insertBefore(this.iframe, this.player.element);
91
+ }
92
+
93
+ async initializePlayer() {
94
+ return new Promise((resolve) => {
95
+ this.youtube = new window.YT.Player(this.iframe.id, {
96
+ videoId: this.videoId,
97
+ width: '100%',
98
+ height: '100%',
99
+ playerVars: {
100
+ controls: 0,
101
+ disablekb: 1,
102
+ fs: 0,
103
+ modestbranding: 1,
104
+ rel: 0,
105
+ showinfo: 0,
106
+ iv_load_policy: 3,
107
+ autoplay: this.player.options.autoplay ? 1 : 0,
108
+ mute: this.player.options.muted ? 1 : 0,
109
+ start: this.player.options.startTime || 0
110
+ },
111
+ events: {
112
+ onReady: (event) => {
113
+ this.isReady = true;
114
+ this.attachEvents();
115
+ resolve();
116
+ },
117
+ onStateChange: (event) => this.handleStateChange(event),
118
+ onError: (event) => this.handleError(event)
119
+ }
120
+ });
121
+ });
122
+ }
123
+
124
+ attachEvents() {
125
+ // Set up polling for time updates (YouTube doesn't provide timeupdate events)
126
+ this.timeUpdateInterval = setInterval(() => {
127
+ if (this.isReady && this.youtube) {
128
+ const currentTime = this.youtube.getCurrentTime();
129
+ const duration = this.youtube.getDuration();
130
+
131
+ this.player.state.currentTime = currentTime;
132
+ this.player.state.duration = duration;
133
+
134
+ this.player.emit('timeupdate', currentTime);
135
+ }
136
+ }, 250);
137
+
138
+ // Initial metadata
139
+ if (this.youtube.getDuration) {
140
+ this.player.state.duration = this.youtube.getDuration();
141
+ this.player.emit('loadedmetadata');
142
+ }
143
+ }
144
+
145
+ handleStateChange(event) {
146
+ const states = window.YT.PlayerState;
147
+
148
+ switch (event.data) {
149
+ case states.PLAYING:
150
+ this.player.state.playing = true;
151
+ this.player.state.paused = false;
152
+ this.player.state.ended = false;
153
+ this.player.state.buffering = false;
154
+ this.player.emit('play');
155
+ this.player.emit('playing');
156
+
157
+ if (this.player.options.onPlay) {
158
+ this.player.options.onPlay.call(this.player);
159
+ }
160
+ break;
161
+
162
+ case states.PAUSED:
163
+ this.player.state.playing = false;
164
+ this.player.state.paused = true;
165
+ this.player.emit('pause');
166
+
167
+ if (this.player.options.onPause) {
168
+ this.player.options.onPause.call(this.player);
169
+ }
170
+ break;
171
+
172
+ case states.ENDED:
173
+ this.player.state.playing = false;
174
+ this.player.state.paused = true;
175
+ this.player.state.ended = true;
176
+ this.player.emit('ended');
177
+
178
+ if (this.player.options.onEnded) {
179
+ this.player.options.onEnded.call(this.player);
180
+ }
181
+
182
+ if (this.player.options.loop) {
183
+ this.youtube.seekTo(0);
184
+ this.youtube.playVideo();
185
+ }
186
+ break;
187
+
188
+ case states.BUFFERING:
189
+ this.player.state.buffering = true;
190
+ this.player.emit('waiting');
191
+ break;
192
+
193
+ case states.CUED:
194
+ this.player.emit('loadedmetadata');
195
+ break;
196
+ }
197
+ }
198
+
199
+ handleError(event) {
200
+ const errors = {
201
+ 2: 'Invalid video ID',
202
+ 5: 'HTML5 player error',
203
+ 100: 'Video not found',
204
+ 101: 'Video not allowed to be played in embedded players',
205
+ 150: 'Video not allowed to be played in embedded players'
206
+ };
207
+
208
+ const error = new Error(errors[event.data] || 'YouTube player error');
209
+ this.player.handleError(error);
210
+ }
211
+
212
+ play() {
213
+ if (this.isReady && this.youtube) {
214
+ this.youtube.playVideo();
215
+ }
216
+ }
217
+
218
+ pause() {
219
+ if (this.isReady && this.youtube) {
220
+ this.youtube.pauseVideo();
221
+ }
222
+ }
223
+
224
+ seek(time) {
225
+ if (this.isReady && this.youtube) {
226
+ this.youtube.seekTo(time, true);
227
+ }
228
+ }
229
+
230
+ setVolume(volume) {
231
+ if (this.isReady && this.youtube) {
232
+ this.youtube.setVolume(volume * 100);
233
+ this.player.state.volume = volume;
234
+ }
235
+ }
236
+
237
+ setMuted(muted) {
238
+ if (this.isReady && this.youtube) {
239
+ if (muted) {
240
+ this.youtube.mute();
241
+ } else {
242
+ this.youtube.unMute();
243
+ }
244
+ this.player.state.muted = muted;
245
+ }
246
+ }
247
+
248
+ setPlaybackSpeed(speed) {
249
+ if (this.isReady && this.youtube) {
250
+ this.youtube.setPlaybackRate(speed);
251
+ this.player.state.playbackSpeed = speed;
252
+ }
253
+ }
254
+
255
+ destroy() {
256
+ if (this.timeUpdateInterval) {
257
+ clearInterval(this.timeUpdateInterval);
258
+ }
259
+
260
+ if (this.youtube && this.youtube.destroy) {
261
+ this.youtube.destroy();
262
+ }
263
+
264
+ if (this.iframe && this.iframe.parentNode) {
265
+ this.iframe.parentNode.removeChild(this.iframe);
266
+ }
267
+
268
+ // Show original element
269
+ if (this.player.element) {
270
+ this.player.element.style.display = '';
271
+ }
272
+ }
273
+ }
274
+