@gumlet/player.js 2.0.16 → 3.0.1

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/README.md CHANGED
@@ -6,67 +6,105 @@ Player.js
6
6
  )](https://www.npmjs.com/package/@gumlet/player.js)
7
7
 
8
8
 
9
- A JavaScript library for interacting with iframes that support Player.js
10
- spec.
9
+ A JavaScript library for interacting with iframes that support Player.js spec.
11
10
 
12
11
  ```js
13
12
  const player = new playerjs.Player('iframe');
14
13
 
15
- player.on('ready', () => {
14
+ player.on('ready', async () => {
16
15
  player.on('play', () => {
17
16
  console.log('play');
18
17
  });
19
18
 
20
- player.getDuration(duration => console.log(duration));
19
+ const duration = await player.getDuration();
20
+ console.log(duration);
21
21
 
22
22
  if (player.supports('method', 'mute')) {
23
- player.mute();
23
+ await player.mute();
24
24
  }
25
25
 
26
- player.play();
26
+ await player.play();
27
27
  });
28
28
  ```
29
29
 
30
30
  Install
31
31
  -------
32
32
 
33
- Player.js is hosted on JSDelivr's CDN. :
33
+ Player.js is hosted on JSDelivr's CDN:
34
34
 
35
35
  ```html
36
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@gumlet/player.js@2.0/dist/player.min.js"></script>
36
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@gumlet/player.js@3.0/dist/main.global.js"></script>
37
37
  ```
38
38
 
39
- install via npm :
39
+ Install via npm:
40
40
 
41
41
  ```sh
42
42
  npm install @gumlet/player.js
43
43
  ```
44
44
 
45
+ TypeScript Support
46
+ ------------------
47
+
48
+ Player.js v3.0.0+ includes full TypeScript support with type definitions included. The library is written in TypeScript and provides comprehensive type safety:
49
+
50
+ ```typescript
51
+ import playerjs from '@gumlet/player.js';
52
+
53
+ const player = new playerjs.Player('iframe');
54
+
55
+ player.on('ready', async () => {
56
+ try {
57
+ const duration = await player.getDuration();
58
+ console.log(`Duration: ${duration} seconds`);
59
+
60
+ if (player.supports('method', 'mute')) {
61
+ await player.mute();
62
+ }
63
+
64
+ await player.play();
65
+ } catch (error) {
66
+ console.error('Player error:', error);
67
+ }
68
+ });
69
+ ```
70
+
71
+ ### Promise-Based API
72
+
73
+ All player methods return promises, making it easier to work with async/await patterns:
74
+
75
+ ```typescript
76
+ // Get multiple values concurrently
77
+ const [duration, currentTime, volume] = await Promise.all([
78
+ player.getDuration(),
79
+ player.getCurrentTime(),
80
+ player.getVolume()
81
+ ]);
82
+
83
+ // Chain operations
84
+ await player.setCurrentTime(10);
85
+ await player.setVolume(75);
86
+ await player.play();
87
+ ```
88
+
45
89
  Ready
46
90
  -----
47
91
 
48
- Because of the dance that we need to do between both iframes, you should
49
- always wait till the `ready` events to fire before interacting with the
50
- player object. However, the player will internally queue messages until
51
- ready is called. :
92
+ Because of the dance that we need to do between both iframes, you should always wait till the `ready` event fires before interacting with the player object. However, the player will internally queue messages until ready is called:
52
93
 
53
94
  ```js
54
95
  const player = new playerjs.Player('iframe');
55
96
 
56
- player.on(playerjs.Events.PLAY, () => console.log('play'));
57
-
58
- player.on('ready', () => player.setCurrentTime(20));
97
+ player.on('ready', async () => {
98
+ await player.setCurrentTime(20);
99
+ });
59
100
  ```
60
101
 
61
102
  Timing
62
103
  ------
63
104
 
64
- The timing between when the iframe is added and when the ready event is
65
- fired is important. Sadly we cannot fire the ready event till the iframe
66
- is loaded, but there is no concrete way of telling when postmessage is
67
- available to us.
105
+ The timing between when the iframe is added and when the ready event is fired is important. Sadly we cannot fire the ready event till the iframe is loaded, but there is no concrete way of telling when postmessage is available to us.
68
106
 
69
- The best way is to do one of the following.
107
+ The best way is to do one of the following:
70
108
 
71
109
  ### Create the iframe via JavaScript
72
110
 
@@ -78,355 +116,393 @@ document.body.appendChild(iframe);
78
116
  const player = new playerjs.Player(iframe);
79
117
  ```
80
118
 
81
- In this case, Player.js will listen to the onload event of the iframe
82
- and only try to communicate when ready.
119
+ In this case, Player.js will listen to the onload event of the iframe and only try to communicate when ready.
83
120
 
84
- ### Wait for the document to be ready.
121
+ ### Wait for the document to be ready
85
122
 
86
123
  ```html
87
124
  <iframe src="//example.com/iframe"></iframe>
88
125
 
89
126
  <script>
90
127
  $(document).on('ready', () => {
91
- $('iframes').each(() => {
128
+ $('iframes').each(async () => {
92
129
  const player = new playerjs.Player(this);
93
- player.on('ready', () => player.play());
130
+ player.on('ready', async () => {
131
+ await player.play();
132
+ });
94
133
  });
95
134
  });
96
135
  </script>
97
136
  ```
98
137
 
99
- At this point we can reasonably assume that the iframe's been loaded and
100
- the ready. Player.js will take care of listening for ready events that
101
- were fired before the player is set up.
138
+ At this point we can reasonably assume that the iframe's been loaded and the ready. Player.js will take care of listening for ready events that were fired before the player is set up.
102
139
 
103
140
  Methods
104
141
  -------
105
142
 
106
- `play`: void
143
+ All methods return promises for modern async/await patterns:
144
+
145
+ ### `play(): Promise<void>`
107
146
  Play the media:
108
147
 
109
148
  ```js
110
- player.play();
149
+ await player.play();
111
150
  ```
112
151
 
113
- `pause`: void
152
+ ### `pause(): Promise<void>`
114
153
  Pause the media:
115
154
 
116
155
  ```js
117
- player.pause();
156
+ await player.pause();
118
157
  ```
119
158
 
120
- `getPaused`: boolean
159
+ ### `getPaused(): Promise<boolean>`
121
160
  Determine if the media is paused:
122
161
 
123
162
  ```js
124
- player.getPaused(function(value){
125
- console.log('paused:', value);
126
- });
163
+ const isPaused = await player.getPaused();
164
+ console.log('paused:', isPaused);
127
165
  ```
128
166
 
129
- `mute`: void
167
+ ### `mute(): Promise<void>`
130
168
  Mute the media:
131
169
 
132
170
  ```js
133
- player.mute();
171
+ await player.mute();
134
172
  ```
135
173
 
136
- `unmute`: void
174
+ ### `unmute(): Promise<void>`
137
175
  Unmute the media:
138
176
 
139
177
  ```js
140
- player.unmute();
178
+ await player.unmute();
141
179
  ```
142
180
 
143
- `getMuted`: boolean
181
+ ### `getMuted(): Promise<boolean>`
144
182
  Determine if the media is muted:
145
183
 
146
184
  ```js
147
- player.getMuted(value => console.log('muted:', value));
185
+ const isMuted = await player.getMuted();
186
+ console.log('muted:', isMuted);
148
187
  ```
149
188
 
150
- `setVolume`: void
189
+ ### `setVolume(volume: number): Promise<void>`
151
190
  Set the volume. Value needs to be between 0-100:
152
191
 
153
- ```
154
- player.setVolume(50);
192
+ ```js
193
+ await player.setVolume(50);
155
194
  ```
156
195
 
157
- `getVolume`: number
196
+ ### `getVolume(): Promise<number>`
158
197
  Get the volume. Value will be between 0-100:
159
198
 
160
199
  ```js
161
- player.getVolume(value => console.log('getVolume:', value));
200
+ const volume = await player.getVolume();
201
+ console.log('volume:', volume);
162
202
  ```
163
203
 
164
- `getDuration`: number
165
- Get the duration of the media is seconds:
204
+ ### `getDuration(): Promise<number>`
205
+ Get the duration of the media in seconds:
166
206
 
167
207
  ```js
168
- player.getDuration(value => console.log('getDuration:', value));
208
+ const duration = await player.getDuration();
209
+ console.log('duration:', duration);
169
210
  ```
170
211
 
171
- `setCurrentTime`: number
212
+ ### `setCurrentTime(time: number): Promise<void>`
172
213
  Perform a seek to a particular time in seconds:
173
214
 
174
215
  ```js
175
- player.setCurrentTime(50);
216
+ await player.setCurrentTime(50);
176
217
  ```
177
218
 
178
- `getCurrentTime`: number
219
+ ### `getCurrentTime(): Promise<number>`
179
220
  Get the current time in seconds of the video:
180
221
 
181
222
  ```js
182
- player.getCurrentTime(value => console.log('getCurrentTime:', value));
223
+ const currentTime = await player.getCurrentTime();
224
+ console.log('currentTime:', currentTime);
183
225
  ```
184
226
 
185
- `setPlaybackRate`: number
186
- Set the playback rate which are available in the player. Doesn't returns an error if the passed playback rate is not available.
227
+ ### `setPlaybackRate(rate: number): Promise<void>`
228
+ Set the playback rate which are available in the player. Doesn't return an error if the passed playback rate is not available:
187
229
 
188
230
  ```js
189
- player.setPlaybackRate(0.5);
231
+ await player.setPlaybackRate(0.5);
190
232
  ```
191
233
 
192
- `getPlaybackRate`: number
234
+ ### `getPlaybackRate(): Promise<number>`
193
235
  Get the current playback rate of the player:
194
236
 
195
237
  ```js
196
- player.getPlaybackRate(value => console.log('getPlaybackRate:', value));
238
+ const rate = await player.getPlaybackRate();
239
+ console.log('playbackRate:', rate);
197
240
  ```
198
241
 
199
- `off`: void
200
- Remove an event listener. If the listener is specified it should remove
201
- only that listener, otherwise remove all listeners:
242
+ ### `setLoop(loop: boolean): Promise<void>`
243
+ Set whether the media should loop:
202
244
 
203
245
  ```js
204
- player.off('play');
246
+ await player.setLoop(true);
247
+ ```
248
+
249
+ ### `getLoop(): Promise<boolean>`
250
+ Get whether the media is set to loop:
251
+
252
+ ```js
253
+ const isLooping = await player.getLoop();
254
+ console.log('looping:', isLooping);
255
+ ```
256
+
257
+ ### `off(event: string, callback?: Function): void`
258
+ Remove an event listener. If the listener is specified it should remove only that listener, otherwise remove all listeners:
205
259
 
260
+ ```js
261
+ player.off('play');
206
262
  player.off('play', playCallback);
207
263
  ```
208
264
 
209
- `on`: void
265
+ ### `on(event: string, callback: Function): void`
210
266
  Add an event listener:
211
267
 
212
268
  ```js
213
269
  player.on('play', () => console.log('play'));
214
270
  ```
215
271
 
216
- `supports`: \['method', 'event'\], methodOrEventName
217
- Determines if the player supports a given event or method.
272
+ ### `supports(type: 'method' | 'event', name: string | string[]): boolean`
273
+ Determines if the player supports a given event or method:
218
274
 
219
275
  ```js
220
276
  player.supports('method', 'getDuration');
221
277
  player.supports('event', 'ended');
278
+ player.supports('method', ['play', 'pause']);
222
279
  ```
223
280
 
224
281
  Events
225
282
  ------
226
283
 
227
- Events that can be listened to.
284
+ Player.js provides comprehensive event handling to monitor playback state and user interactions. All events can be listened to using the `on()` method.
228
285
 
229
- `ready`
230
- fired when the media is ready to receive commands. This is fired
231
- regardless of listening to the event. Note: As outlined in the PlayerJs
232
- Spec, you may run into inconsistencies if you have multiple players on
233
- the page with the same `src`. To get around this, simply append a UUID
234
- or a timestamp to the iframe's src to guarantee that all players on the
235
- page have a unique `src`.
286
+ ### Core Events
236
287
 
237
- `progress`
238
- fires when the media is loading additional media for playback:
288
+ #### `ready`
289
+ Fired when the media is ready to receive commands. Always wait for this event before calling player methods.
239
290
 
240
291
  ```js
241
- {
242
- percent: 0.8,
243
- }
292
+ player.on('ready', async () => {
293
+ console.log('Player is ready!');
294
+ // Safe to call player methods now
295
+ await player.play();
296
+ });
244
297
  ```
245
298
 
246
- `timeupdate`
247
- fires during playback:
299
+ **Note:** As outlined in the PlayerJs Spec, you may run into inconsistencies if you have multiple players on the page with the same `src`. To avoid this, append a UUID or timestamp to the iframe's src.
300
+
301
+ #### `play`
302
+ Fired when playback starts.
248
303
 
249
304
  ```js
250
- {
251
- seconds: 10,
252
- duration: 40
253
- }
305
+ player.on('play', () => {
306
+ console.log('Video started playing');
307
+ });
254
308
  ```
255
309
 
256
- `play`
257
- fires when the video starts to play.
258
-
259
- `pause`
260
- fires when the video is paused.
261
-
262
- `ended`
263
- fires when the video is finished.
264
-
265
- `fullscreenChange`
266
- fires when the video fullscreen is changed:
310
+ #### `pause`
311
+ Fired when playback is paused.
267
312
 
268
313
  ```js
269
- {
270
- isFullScreen: true // or false
271
- }
314
+ player.on('pause', () => {
315
+ console.log('Video paused');
316
+ });
272
317
  ```
273
318
 
274
- `pipChange`
275
- fires when the video is put to or brought back from picture-in-picture.
319
+ #### `ended`
320
+ Fired when playback reaches the end of the media.
276
321
 
277
322
  ```js
278
- {
279
- isPIP: true // or false
280
- }
323
+ player.on('ended', async () => {
324
+ console.log('Video finished');
325
+ // Reset to beginning if needed
326
+ await player.setCurrentTime(0);
327
+ });
281
328
  ```
282
329
 
283
- `playbackRateChange`
284
- fires when the video playback rate is changed by user.
285
-
286
- `audioChange`
287
- fires when the audio track of video is changed.
330
+ ### Progress Events
288
331
 
289
- `qualityChange`
290
- fires when the video quality is changed.
291
-
292
- `volumeChange`
293
- fires when the volume level of the player is changed. It also gets fired when the player is muted or unmuted, along with muted and unmuted events respectively.
332
+ #### `timeupdate`
333
+ Fired regularly during playback with current time information.
294
334
 
295
335
  ```js
296
- {
297
- quality: '720p'
336
+ player.on('timeupdate', (data) => {
337
+ const { seconds, duration } = data;
338
+ const progress = (seconds / duration) * 100;
339
+
340
+ console.log(`Progress: ${progress.toFixed(1)}%`);
341
+ console.log(`Current time: ${formatTime(seconds)} / ${formatTime(duration)}`);
342
+ });
343
+
344
+ function formatTime(seconds) {
345
+ const mins = Math.floor(seconds / 60);
346
+ const secs = Math.floor(seconds % 60);
347
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
298
348
  }
299
349
  ```
300
350
 
301
- `seeked`
302
- fires when the video has been seeked by the user. Gives seeked to time in seconds and total duration of video.
351
+ #### `progress`
352
+ Fired when the media is buffering/loading additional content.
303
353
 
304
354
  ```js
305
- {
306
- seconds: 10
307
- duration: 50
308
- }
355
+ player.on('progress', (data) => {
356
+ const { percent } = data;
357
+ console.log(`Buffered: ${(percent * 100).toFixed(1)}%`);
358
+ });
309
359
  ```
310
360
 
311
- `error`
312
- fires when an error occurs.
313
-
314
- Receiver
315
- --------
316
-
317
- If you are looking to implement the Player.js spec, we include a
318
- Receiver that will allow you to easily listen to events and takes care
319
- of the house keeping.
361
+ #### `seeked`
362
+ Fired when the user seeks to a different time position.
320
363
 
321
364
  ```js
322
- const receiver = new playerjs.Receiver();
323
-
324
- receiver.on('play', () => {
325
- video.play();
326
- receiver.emit('play');
327
- });
328
-
329
- receiver.on('pause', () => {
330
- video.pause();
331
- receiver.emit('pause');
365
+ player.on('seeked', (data) => {
366
+ const { seconds, duration } = data;
367
+ console.log(`Seeked to ${seconds}s of ${duration}s`);
332
368
  });
369
+ ```
333
370
 
334
- receiver.on('getDuration', callback => callback(video.duration));
371
+ ### Audio/Video Control Events
335
372
 
336
- receiver.on('getVolume', callback => callback(video.volume*100));
373
+ #### `volumeChange`
374
+ Fired when the volume level changes, including mute/unmute actions.
337
375
 
338
- receiver.on('setVolume', value => video.volume = (value/100));
376
+ ```js
377
+ player.on('volumeChange', async () => {
378
+ const volume = await player.getVolume();
379
+ const isMuted = await player.getMuted();
380
+
381
+ console.log(`Volume: ${volume}%, Muted: ${isMuted}`);
382
+ });
383
+ ```
339
384
 
340
- receiver.on('mute', () => video.mute = true)
385
+ #### `playbackRateChange`
386
+ Fired when playback speed is changed.
341
387
 
342
- receiver.on('unmute', () => video.mute = false);
388
+ ```js
389
+ player.on('playbackRateChange', async () => {
390
+ const rate = await player.getPlaybackRate();
391
+ console.log(`Playback rate: ${rate}x`);
392
+ });
393
+ ```
343
394
 
344
- receiver.on('getMuted', callback => callback(video.mute));
395
+ ### Display Events
345
396
 
346
- receiver.on('getLoop', callback => callback(video.loop));
397
+ #### `fullscreenChange`
398
+ Fired when fullscreen mode is toggled.
347
399
 
348
- receiver.on('setLoop', value => video.loop = value);
400
+ ```js
401
+ player.on('fullscreenChange', (data) => {
402
+ const { isFullScreen } = data;
403
+ console.log(`Fullscreen: ${isFullScreen}`);
404
+ });
405
+ ```
349
406
 
350
- video.addEventListener('ended', () => receiver.emit('ended'));
407
+ #### `pipChange`
408
+ Fired when Picture-in-Picture mode is toggled.
351
409
 
352
- video.addEventListener('timeupdate', () => {
353
- receiver.emit('timeupdate', {
354
- seconds: video.currentTime,
355
- duration: video.duration
356
- });
410
+ ```js
411
+ player.on('pipChange', (data) => {
412
+ const { isPIP } = data;
413
+ console.log(`Picture-in-Picture: ${isPIP}`);
357
414
  });
358
-
359
- receiver.ready();
360
415
  ```
361
416
 
362
- Methods
363
- -------
417
+ ### Quality Events
364
418
 
365
- `on`
366
- Requests an event from the video. The above player methods should be
367
- implemented. If the event expects a return value a callback will be
368
- passed into the function call:
419
+ #### `qualityChange`
420
+ Fired when video quality/resolution is changed.
369
421
 
370
422
  ```js
371
- receiver.on('getDuration', callback => callback(video.duration));
423
+ player.on('qualityChange', (data) => {
424
+ const { quality } = data;
425
+ console.log(`Quality changed to: ${quality}`);
426
+ });
372
427
  ```
373
428
 
374
- Otherwise you can safely ignore any inputs:
429
+ #### `audioChange`
430
+ Fired when the audio track is changed.
375
431
 
376
432
  ```js
377
- receiver.on('play', callback => video.play());
433
+ player.on('audioChange', (data) => {
434
+ console.log('Audio track changed:', data);
435
+ });
378
436
  ```
379
437
 
380
- `emit`
381
- Sends events to the parent as long as someone is listing. The above
382
- player events should be implemented. If a value is expected, it should
383
- be passed in as the second argument:
438
+ ### Error Handling
384
439
 
385
- receiver.emit('timeupdate', { seconds:20, duration: 40 });
386
-
387
- `ready`
388
- Once everything is in place and you are ready to start responding to
389
- events, call this method. It performs some house keeping, along with
390
- emitting `ready`:
440
+ #### `error`
441
+ Fired when an error occurs during playback.
391
442
 
392
443
  ```js
393
- receiver.ready();
444
+ player.on('error', (error) => {
445
+ console.error('Playback error:', error);
446
+ // Handle error appropriately for your application
447
+ });
394
448
  ```
395
- Adapters
396
- --------
397
-
398
- In order to make it super easy to add Player.js to any embed, we have
399
- written adapters for common video libraries. We currently have adapters
400
- for [Video.js](http://www.videojs.com/),
401
- [JWPlayer](https://www.jwplayer.com/) and [HTML5
402
- Video](http://dev.w3.org/html5/spec-author-view/video.html). An Adapter
403
- wraps the Receiver and wires up all the events so your iframe is
404
- Player.js compatible.
405
449
 
406
- ### VideoJSAdapter
450
+ ### Complete Example
407
451
 
408
- An adapter for [Video.js](http://www.videojs.com/). :
452
+ Here's a comprehensive example showing how to listen to multiple events:
409
453
 
410
454
  ```js
411
- videojs("video", {}, () => {
412
- const adapter = new playerjs.VideoJSAdapter(this);
413
- // ... Do other things to initialize your video.
455
+ const player = new playerjs.Player('video-iframe');
456
+
457
+ player.on('ready', async () => {
458
+ console.log('Player is ready!');
459
+
460
+ // Get initial player state
461
+ const duration = await player.getDuration();
462
+ const volume = await player.getVolume();
463
+ const isPaused = await player.getPaused();
464
+
465
+ console.log(`Duration: ${duration}s, Volume: ${volume}%, Paused: ${isPaused}`);
466
+ });
467
+
468
+ // Listen to playback events
469
+ player.on('play', () => console.log('Started playing'));
470
+ player.on('pause', () => console.log('Paused'));
471
+ player.on('ended', () => console.log('Playback finished'));
414
472
 
415
- // Start accepting events
416
- adapter.ready();
473
+ // Listen to progress events
474
+ player.on('timeupdate', (data) => {
475
+ const { seconds, duration } = data;
476
+ console.log(`${seconds.toFixed(1)}s / ${duration.toFixed(1)}s`);
417
477
  });
418
- ```
419
- ### HTML5Adapter
420
478
 
421
- An adapter for [HTML5
422
- Video](http://dev.w3.org/html5/spec-author-view/video.html). :
479
+ // Listen to user interaction events
480
+ player.on('volumeChange', async () => {
481
+ const volume = await player.getVolume();
482
+ const muted = await player.getMuted();
483
+ console.log(`Volume: ${volume}%, Muted: ${muted}`);
484
+ });
423
485
 
424
- ```js
425
- const video = document.getElementById('video');
426
- video.load();
486
+ player.on('seeked', (data) => {
487
+ console.log(`Seeked to: ${data.seconds}s`);
488
+ });
489
+
490
+ // Listen to display events
491
+ player.on('fullscreenChange', (data) => {
492
+ console.log(`Fullscreen: ${data.isFullScreen}`);
493
+ });
427
494
 
428
- const adapter = playerjs.HTML5Adapter(video);
495
+ player.on('pipChange', (data) => {
496
+ console.log(`Picture-in-Picture: ${data.isPIP}`);
497
+ });
429
498
 
430
- // Start accepting events
431
- adapter.ready();
499
+ // Handle errors
500
+ player.on('error', (error) => {
501
+ console.error('Player error:', error);
502
+ });
432
503
  ```
504
+
505
+ ## Related Documentation
506
+
507
+ - [Receiver Implementation Guide](./RECEIVER.md) - For implementing the Player.js spec in your video player
508
+ - [Legacy Callback API](./CALLBACK_API.md) - Documentation for backward-compatible callback-based methods