@gcorevideo/player 2.28.36 → 2.30.0

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 (60) hide show
  1. package/README.md +108 -0
  2. package/assets/media-control/media-control.scss +8 -6
  3. package/assets/multi-camera/multicamera.ejs +27 -23
  4. package/assets/multi-camera/style.scss +7 -34
  5. package/assets/style/main.scss +2 -2
  6. package/dist/core.js +24 -7
  7. package/dist/index.css +324 -346
  8. package/dist/index.embed.js +24 -46
  9. package/dist/index.js +471 -245
  10. package/docs/api/player.md +22 -9
  11. package/docs/api/player.mediacontrol.setkeepvisible.md +56 -0
  12. package/docs/api/player.multicamera.md +0 -28
  13. package/docs/api/player.multiccamerasourceinfo.md +27 -0
  14. package/docs/api/{player.multicamera.unbindevents.md → player.multisourcesmode.md} +4 -7
  15. package/docs/api/player.sourcecontroller.md +0 -37
  16. package/lib/Player.d.ts +9 -0
  17. package/lib/Player.d.ts.map +1 -1
  18. package/lib/Player.js +11 -0
  19. package/lib/index.plugins.d.ts +1 -0
  20. package/lib/index.plugins.d.ts.map +1 -1
  21. package/lib/index.plugins.js +1 -0
  22. package/lib/playback/dash-playback/DashPlayback.d.ts +2 -1
  23. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  24. package/lib/playback/dash-playback/DashPlayback.js +5 -1
  25. package/lib/playback/hls-playback/HlsPlayback.d.ts +2 -1
  26. package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
  27. package/lib/playback/types.d.ts +9 -0
  28. package/lib/playback/types.d.ts.map +1 -1
  29. package/lib/playback.types.d.ts +0 -6
  30. package/lib/playback.types.d.ts.map +1 -1
  31. package/lib/plugins/multi-camera/MultiCamera.d.ts +21 -4
  32. package/lib/plugins/multi-camera/MultiCamera.d.ts.map +1 -1
  33. package/lib/plugins/multi-camera/MultiCamera.js +70 -134
  34. package/lib/plugins/source-controller/SourceController.d.ts +0 -39
  35. package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
  36. package/lib/plugins/source-controller/SourceController.js +0 -39
  37. package/lib/plugins/token-refresh/TokenRefreshPlugin.d.ts +119 -0
  38. package/lib/plugins/token-refresh/TokenRefreshPlugin.d.ts.map +1 -0
  39. package/lib/plugins/token-refresh/TokenRefreshPlugin.js +318 -0
  40. package/lib/plugins/token-refresh/index.d.ts +2 -0
  41. package/lib/plugins/token-refresh/index.d.ts.map +1 -0
  42. package/lib/plugins/token-refresh/index.js +1 -0
  43. package/lib/utils/mediaSources.d.ts +4 -0
  44. package/lib/utils/mediaSources.d.ts.map +1 -1
  45. package/lib/utils/mediaSources.js +8 -6
  46. package/package.json +1 -1
  47. package/src/Player.ts +12 -0
  48. package/src/index.plugins.ts +1 -0
  49. package/src/playback/dash-playback/DashPlayback.ts +7 -3
  50. package/src/playback/hls-playback/HlsPlayback.ts +1 -1
  51. package/src/playback/types.ts +10 -0
  52. package/src/playback.types.ts +0 -6
  53. package/src/plugins/multi-camera/MultiCamera.ts +103 -166
  54. package/src/plugins/source-controller/SourceController.ts +0 -39
  55. package/src/plugins/subtitles/ClosedCaptions.ts +1 -1
  56. package/src/plugins/token-refresh/TokenRefreshPlugin.ts +425 -0
  57. package/src/plugins/token-refresh/index.ts +5 -0
  58. package/src/utils/mediaSources.ts +10 -6
  59. package/tsconfig.tsbuildinfo +1 -1
  60. package/docs/api/player.multicamera.activebyid.md +0 -67
@@ -1,11 +1,10 @@
1
1
  import { Browser, Events, Playback, template, UICorePlugin, } from '@clappr/core';
2
2
  import { reportError, trace } from '@gcorevideo/utils';
3
+ import { guessMimeType, MIME_TYPE_DASH } from '../../utils/mediaSources.js';
3
4
  import { CLAPPR_VERSION } from '../../build.js';
4
5
  import pluginHtml from '../../../assets/multi-camera/multicamera.ejs';
5
6
  import '../../../assets/multi-camera/style.scss';
6
7
  import streamsIcon from '../../../assets/icons/old/streams.svg';
7
- import streamsMomentoIcon from '../../../assets/icons/old/language.svg';
8
- import streamsWhiteNightsIcon from '../../../assets/icons/old/wn.svg';
9
8
  const VERSION = '0.0.1';
10
9
  const T = 'plugins.multicamera';
11
10
  /**
@@ -53,6 +52,8 @@ export class MultiCamera extends UICorePlugin {
53
52
  // Don't mutate the options, TODO check if some plugin observes the options.multicamera
54
53
  this.multicamera = this.options.multisources.map((item) => ({ ...item }));
55
54
  this.noActiveStreams = this.multicamera.every((item) => !item.live);
55
+ // TODO filter out non-live
56
+ this.core.options.sources = expandMediaSource(this.multicamera[0]);
56
57
  }
57
58
  bindEvents() {
58
59
  this.listenTo(this.core, Events.CORE_READY, this.bindPlaybackEvents);
@@ -61,15 +62,10 @@ export class MultiCamera extends UICorePlugin {
61
62
  this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
62
63
  }
63
64
  unBindEvents() {
64
- // @ts-ignore
65
- this.stopListening(this.core, Events.CORE_READY);
66
- // @ts-ignore
67
- this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED);
68
- // @ts-ignore
69
- this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_RENDERED);
70
- // @ts-ignore
71
- this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_HIDE);
72
- // @ts-ignore
65
+ this.stopListening(this.core, Events.CORE_READY, this.bindPlaybackEvents);
66
+ this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED, this.reload);
67
+ this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
68
+ this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
73
69
  this.stopListening(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onPlay);
74
70
  }
75
71
  onPlay() {
@@ -85,80 +81,53 @@ export class MultiCamera extends UICorePlugin {
85
81
  this.bindPlaybackEvents();
86
82
  }
87
83
  shouldRender() {
88
- if (!this.core.activeContainer || this.noActiveStreams) {
89
- return false;
90
- }
91
- if (!this.core.activePlayback) {
84
+ if (this.noActiveStreams) {
92
85
  return false;
93
86
  }
94
87
  return this.multicamera.length >= 2;
95
88
  }
96
89
  render() {
97
- if (this.shouldRender()) {
98
- let numActiveSources = 0;
99
- // const currentSource = this.core.options.source
100
- const currentSource = this.core.activePlayback?.sourceMedia;
101
- for (const item of this.multicamera) {
102
- if (item.live) {
103
- numActiveSources++;
104
- }
105
- if (!this.currentCamera && item.source === currentSource) {
106
- this.currentCamera = item;
107
- }
108
- }
109
- // const mediaControl = this.core.getPlugin('media_control')
110
- if (this.currentTime &&
111
- // TODO check the last active playback type instead
112
- // !mediaControl.$el.hasClass('live') &&
113
- this.core.getPlaybackType() !== Playback.LIVE) {
114
- if (this.currentTime < this.core.activePlayback.getDuration()) {
115
- this.core.activePlayback.seek(this.currentTime);
116
- }
117
- this.currentTime = 0;
118
- // if (mediaControl.$el.hasClass('dvr')) {
119
- // this.core.activeContainer.dvrInUse = true;
120
- // }
121
- }
122
- // TODO current source
123
- this.$el.html(this.template({
124
- streams: this.multicamera,
125
- multisources_mode: this.options.multisourcesMode,
126
- }));
127
- if ((numActiveSources <= 1 &&
128
- this.options.multisourcesMode !== 'show_all') ||
129
- this.options.multisourcesMode === 'one_first') {
130
- this.$el.hide();
131
- }
132
- else {
133
- this.$el.show();
134
- }
135
- if (this.core.mediaControl.$multiCameraSelector &&
136
- this.core.mediaControl.$multiCameraSelector.length > 0) {
137
- this.core.mediaControl.$multiCameraSelector.append(this.el);
90
+ if (!this.core.activeContainer || !this.core.activePlayback) {
91
+ return this;
92
+ }
93
+ if (!this.shouldRender()) {
94
+ return this;
95
+ }
96
+ let numActiveSources = 0;
97
+ const currentSource = this.core.activePlayback?.sourceMedia;
98
+ for (const item of this.multicamera) {
99
+ if (item.live) {
100
+ numActiveSources++;
138
101
  }
139
- else {
140
- this.core.mediaControl.$('.media-control-right-panel').append(this.el);
102
+ if (!this.currentCamera && item.source === currentSource) {
103
+ this.currentCamera = item;
141
104
  }
142
- if (Object.prototype.hasOwnProperty.call(this.core.mediaControl, '$multiCameraSelector') &&
143
- this.core.mediaControl.$multiCameraSelector.find('span.multicamera-icon').length > 0) {
144
- if (~window.location.href.indexOf('whitenights.gcdn.co')) {
145
- this.core.mediaControl.$multiCameraSelector
146
- .find('span.multicamera-icon')
147
- .append(streamsWhiteNightsIcon);
148
- }
149
- else if (~window.location.href.indexOf('momentosolutions.gcdn.co')) {
150
- this.core.mediaControl.$multiCameraSelector
151
- .find('span.multicamera-icon')
152
- .append(streamsMomentoIcon);
153
- }
154
- else {
155
- this.core.mediaControl.$multiCameraSelector
156
- .find('span.multicamera-icon')
157
- .append(streamsIcon);
158
- }
105
+ }
106
+ if (this.currentTime &&
107
+ this.core.getPlaybackType() !== Playback.LIVE) {
108
+ if (this.currentTime < this.core.activePlayback.getDuration()) {
109
+ this.core.activePlayback.seek(this.currentTime);
159
110
  }
160
- this.highlightCurrentLevel();
111
+ this.currentTime = 0;
161
112
  }
113
+ this.$el.html(this.template({
114
+ streams: this.multicamera,
115
+ multisources_mode: this.options.multisourcesMode,
116
+ }));
117
+ if ((numActiveSources < 2 &&
118
+ this.options.multisourcesMode !== 'show_all') ||
119
+ this.options.multisourcesMode === 'one_first') {
120
+ this.$el.hide();
121
+ }
122
+ else {
123
+ this.$el.show();
124
+ }
125
+ const mediaControl = this.core.getPlugin('media_control');
126
+ mediaControl.slot('multicamera', this.$el);
127
+ this.$el
128
+ .find('span.multicamera-icon')
129
+ .html(streamsIcon);
130
+ this.highlightCurrentLevel();
162
131
  return this;
163
132
  }
164
133
  onCameraSelect(event) {
@@ -171,33 +140,6 @@ export class MultiCamera extends UICorePlugin {
171
140
  event.stopPropagation();
172
141
  return false;
173
142
  }
174
- activeById(id, active) {
175
- this.setLiveStatus(id, active);
176
- if (!this.currentCamera && !this.noActiveStreams) {
177
- return;
178
- }
179
- if (this.noActiveStreams && !active) {
180
- return;
181
- }
182
- if (this.currentCamera) {
183
- if (this.options.multisourcesMode === 'only_live') {
184
- this.behaviorLive(id, active);
185
- }
186
- if (this.options.multisourcesMode === 'one_first') {
187
- this.behaviorOne(id, active);
188
- }
189
- if (this.options.multisourcesMode === 'show_all') {
190
- this.behaviorAll(id, active);
191
- }
192
- }
193
- else {
194
- if (this.noActiveStreams && active) {
195
- this.changeById(id);
196
- this.noActiveStreams = false;
197
- }
198
- }
199
- this.render();
200
- }
201
143
  setLiveStatus(id, active) {
202
144
  try {
203
145
  const index = this.findIndexById(id);
@@ -260,7 +202,6 @@ export class MultiCamera extends UICorePlugin {
260
202
  this.currentCamera = null;
261
203
  this.noActiveStreams = true;
262
204
  this.core.trigger('core:multicamera:no_active_translation');
263
- // this.changeById(this.multicamera[nextIndex].id);
264
205
  }
265
206
  showError() {
266
207
  this.core.activePlayback.pause();
@@ -283,7 +224,7 @@ export class MultiCamera extends UICorePlugin {
283
224
  }
284
225
  hideError() {
285
226
  try {
286
- this.core.mediaControl.enableControlButton();
227
+ this.core.getPlugin('media_control')?.enableControlButton();
287
228
  }
288
229
  catch (error) {
289
230
  reportError(error);
@@ -293,14 +234,9 @@ export class MultiCamera extends UICorePlugin {
293
234
  trace(`${T} changeById`, { id });
294
235
  queueMicrotask(() => {
295
236
  const playbackOptions = this.core.options.playback || {};
296
- // TODO figure out what this does
237
+ // TODO figure out if it's needed
297
238
  playbackOptions.recycleVideo = Browser.isMobile;
298
- this.currentCamera = this.findElementById(id) ?? null;
299
- trace(`${T} changeById`, {
300
- id,
301
- currentCamera: this.currentCamera,
302
- multicamera: this.multicamera,
303
- });
239
+ this.currentCamera = this.findElementById(id);
304
240
  if (!this.currentCamera) {
305
241
  return;
306
242
  }
@@ -322,26 +258,16 @@ export class MultiCamera extends UICorePlugin {
322
258
  this.core.configure({
323
259
  playback: playbackOptions,
324
260
  source: this.currentCamera.source, // TODO ensure that the preferred transport is used
325
- video360: {
326
- // TODO
327
- projection: this.currentCamera.projection,
328
- },
329
261
  fullscreenDisable,
330
262
  autoPlay: this.playing,
331
263
  disableCanAutoPlay: true,
332
264
  });
333
- this.core.activeContainer.mediaControlDisabled = false;
265
+ this.core.activeContainer?.enableMediaControl();
334
266
  });
335
267
  this.toggleContextMenu();
336
268
  }
337
- getCamerasList() {
338
- return this.multicamera;
339
- }
340
- getCurrentCamera() {
341
- return this.currentCamera;
342
- }
343
269
  findElementById(id) {
344
- return this.multicamera.find((element) => element.id === id);
270
+ return this.multicamera.find((element) => element.id === id) ?? null;
345
271
  }
346
272
  findIndexById(id) {
347
273
  return this.multicamera.findIndex((element) => element.id === id);
@@ -351,20 +277,14 @@ export class MultiCamera extends UICorePlugin {
351
277
  }
352
278
  hideSelectLevelMenu() {
353
279
  ;
354
- this.$('.multicamera ul').hide();
280
+ this.$('ul').hide();
355
281
  }
356
282
  toggleContextMenu() {
357
283
  ;
358
- this.$('.multicamera ul').toggle();
359
- }
360
- // private buttonElement(): ZeptoResult {
361
- // return this.$('.multicamera button');
362
- // }
363
- // private buttonElementText(): ZeptoResult {
364
- // return this.$('.multicamera button .quality-text');
365
- // }
284
+ this.$('ul').toggle();
285
+ }
366
286
  levelElement(id) {
367
- return this.$('.multicamera ul li > div' +
287
+ return this.$('ul .multicamera-item' +
368
288
  (id !== undefined
369
289
  ? '[data-multicamera-selector-select="' + id + '"]'
370
290
  : ''));
@@ -376,3 +296,19 @@ export class MultiCamera extends UICorePlugin {
376
296
  this.levelElement(this.currentCamera.id).addClass('multicamera-active');
377
297
  }
378
298
  }
299
+ function expandMediaSource(source) {
300
+ const result = [{
301
+ source: source.source,
302
+ mimeType: guessMimeType(source.source),
303
+ }];
304
+ if (source.source_dash) {
305
+ result.push({
306
+ source: source.source_dash,
307
+ mimeType: MIME_TYPE_DASH,
308
+ });
309
+ }
310
+ if (source.hls_mpegts_url) {
311
+ result.push(source.hls_mpegts_url);
312
+ }
313
+ return result;
314
+ }
@@ -4,45 +4,6 @@ import { type PlayerMediaSourceDesc } from '../../types.js';
4
4
  * `PLUGIN` that is managing the automatic failover between media sources.
5
5
  * @public
6
6
  * @remarks
7
- * Have a look at the {@link https://miro.com/app/board/uXjVLiN15tY=/?share_link_id=390327585787 | source failover diagram} for the details
8
- * on how sources ordering and selection works. Below is a simplified diagram:
9
- *
10
- * ```markdown
11
- * sources_list:
12
- * - a.mpd | +--------------------+
13
- * - b.m3u8 |--->| init |
14
- * - ... | |--------------------|
15
- * | current_source = 0 |
16
- * +--------------------+
17
- * |
18
- * | source = a.mpd
19
- * | playback = dash.js
20
- * v
21
- * +------------------+
22
- * +-->| load source |
23
- * | +---------|--------+
24
- * | v
25
- * | +------------------+
26
- * | | play |
27
- * | +---------|--------+
28
- * | |
29
- * | v
30
- * | +-----------------------+
31
- * | | on playback_error |
32
- * | |-----------------------|
33
- * | | current_source = |
34
- * | | (current_source + 1) |
35
- * | | % len sources_list |
36
- * | | |
37
- * | | delay 1..3s |
38
- * | +---------------|-------+
39
- * | |
40
- * | source=b.m3u8 |
41
- * | playback=hls.js |
42
- * +-------------------+
43
- *
44
- * ```
45
- *
46
7
  * @example
47
8
  * ```ts
48
9
  * import { SourceController } from '@gcorevideo/player'
@@ -1 +1 @@
1
- {"version":3,"file":"SourceController.d.ts","sourceRoot":"","sources":["../../../src/plugins/source-controller/SourceController.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,KAAK,IAAI,IAAI,UAAU,EACxB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAsB3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,gBAAiB,SAAQ,UAAU;IAwC9C,OAAO,CAAC,WAAW,CAA8B;IAEjD,OAAO,CAAC,kBAAkB,CAAI;IAE9B,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,MAAM,CAAQ;IAEtB,OAAO,CAAC,QAAQ,CAAQ;IAExB,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,IAAI,CAAiB;IAE7B;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;gBACS,IAAI,EAAE,UAAU;IAY5B;;;;;;;OAOG;IACH,cAAc,CAAC,WAAW,EAAE,qBAAqB,EAAE;IAQnD;;OAEG;IACM,UAAU;IAWnB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,wBAAwB;IAgBhC,OAAO,CAAC,2BAA2B;IAiDnC,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;CACF"}
1
+ {"version":3,"file":"SourceController.d.ts","sourceRoot":"","sources":["../../../src/plugins/source-controller/SourceController.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,KAAK,IAAI,IAAI,UAAU,EACxB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAsB3D;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,SAAQ,UAAU;IAwC9C,OAAO,CAAC,WAAW,CAA8B;IAEjD,OAAO,CAAC,kBAAkB,CAAI;IAE9B,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,MAAM,CAAQ;IAEtB,OAAO,CAAC,QAAQ,CAAQ;IAExB,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,IAAI,CAAiB;IAE7B;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;gBACS,IAAI,EAAE,UAAU;IAY5B;;;;;;;OAOG;IACH,cAAc,CAAC,WAAW,EAAE,qBAAqB,EAAE;IAQnD;;OAEG;IACM,UAAU;IAWnB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,wBAAwB;IAgBhC,OAAO,CAAC,2BAA2B;IAiDnC,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;CACF"}
@@ -15,45 +15,6 @@ function noSync(cb) {
15
15
  * `PLUGIN` that is managing the automatic failover between media sources.
16
16
  * @public
17
17
  * @remarks
18
- * Have a look at the {@link https://miro.com/app/board/uXjVLiN15tY=/?share_link_id=390327585787 | source failover diagram} for the details
19
- * on how sources ordering and selection works. Below is a simplified diagram:
20
- *
21
- * ```markdown
22
- * sources_list:
23
- * - a.mpd | +--------------------+
24
- * - b.m3u8 |--->| init |
25
- * - ... | |--------------------|
26
- * | current_source = 0 |
27
- * +--------------------+
28
- * |
29
- * | source = a.mpd
30
- * | playback = dash.js
31
- * v
32
- * +------------------+
33
- * +-->| load source |
34
- * | +---------|--------+
35
- * | v
36
- * | +------------------+
37
- * | | play |
38
- * | +---------|--------+
39
- * | |
40
- * | v
41
- * | +-----------------------+
42
- * | | on playback_error |
43
- * | |-----------------------|
44
- * | | current_source = |
45
- * | | (current_source + 1) |
46
- * | | % len sources_list |
47
- * | | |
48
- * | | delay 1..3s |
49
- * | +---------------|-------+
50
- * | |
51
- * | source=b.m3u8 |
52
- * | playback=hls.js |
53
- * +-------------------+
54
- *
55
- * ```
56
- *
57
18
  * @example
58
19
  * ```ts
59
20
  * import { SourceController } from '@gcorevideo/player'
@@ -0,0 +1,119 @@
1
+ import { CorePlugin } from '@clappr/core';
2
+ /**
3
+ * Response shape expected from your token-refresh API endpoint.
4
+ * @public
5
+ */
6
+ export interface TokenResponse {
7
+ /** Plain (non-IP-bound) secure token */
8
+ token: string;
9
+ /** IP-bound secure token */
10
+ token_ip: string;
11
+ /** Client IP address (informational) */
12
+ client_ip: string;
13
+ /** Unix timestamp (seconds) when both tokens expire */
14
+ expires: number;
15
+ /** Ready-to-use HLS master playlist URL with plain token embedded */
16
+ url: string;
17
+ /** Ready-to-use HLS master playlist URL with IP-bound token embedded */
18
+ url_ip: string;
19
+ }
20
+ /**
21
+ * Configuration options for {@link TokenRefreshPlugin}.
22
+ * @public
23
+ */
24
+ export interface TokenRefreshOptions {
25
+ /**
26
+ * Async function called each time a fresh token is needed.
27
+ * Must return a {@link TokenResponse}.
28
+ */
29
+ getToken: () => Promise<TokenResponse>;
30
+ /**
31
+ * When `true`, the IP-bound variant (`token_ip` / `url_ip`) is used.
32
+ * Defaults to `false`.
33
+ */
34
+ ipBound?: boolean;
35
+ /**
36
+ * Seconds before the token expiry timestamp to request a fresh token.
37
+ * Defaults to `5`.
38
+ */
39
+ refreshLeadSeconds?: number;
40
+ /**
41
+ * Optional callback invoked after every successful token refresh.
42
+ */
43
+ onTokenRefreshed?: (data: TokenResponse) => void;
44
+ }
45
+ /**
46
+ * `PLUGIN` — automatic token refresh for Gcore protected-content streams.
47
+ *
48
+ * Supports all three playback engines:
49
+ *
50
+ * | Engine | Mechanism | Interruption |
51
+ * |--------|-----------|--------------|
52
+ * | **hls.js** | Custom loader rewrites every request URL | None |
53
+ * | **dash.js** | `addRequestInterceptor` rewrites every request URL | None |
54
+ * | **Native `<video>`** (Safari ≤ iOS 14.4) | Source reload + seek restore | Brief |
55
+ *
56
+ * @public
57
+ * @remarks
58
+ * Register the plugin once before creating any player instance:
59
+ * ```ts
60
+ * import { Player, TokenRefreshPlugin } from '@gcorevideo/player'
61
+ * Player.registerPlugin(TokenRefreshPlugin)
62
+ * ```
63
+ *
64
+ * Then pass `tokenRefresh` in `PlayerConfig`:
65
+ * ```ts
66
+ * const player = new Player({
67
+ * sources: [{ source: initialUrl, mimeType: 'application/x-mpegURL' }],
68
+ * tokenRefresh: {
69
+ * getToken: () => fetch('https://…/token').then(r => r.json()),
70
+ * ipBound: false,
71
+ * refreshLeadSeconds: 5,
72
+ * onTokenRefreshed: (data) => console.log('new token expires', data.expires),
73
+ * },
74
+ * })
75
+ * ```
76
+ *
77
+ * @example
78
+ * Safari native — opt-in Service Worker for fully seamless refresh:
79
+ * ```js
80
+ * // Register token-refresh-sw.js (see example/ directory)
81
+ * // and omit tokenRefresh config — the SW handles rewriting.
82
+ * ```
83
+ */
84
+ export declare class TokenRefreshPlugin extends CorePlugin {
85
+ /** @internal */
86
+ static get type(): 'core';
87
+ /** @internal */
88
+ get name(): string;
89
+ /** @internal */
90
+ get supportedVersion(): {
91
+ min: string;
92
+ };
93
+ /** Token state extracted from the currently-managed source URL */
94
+ private originalState;
95
+ /** Latest token state (updated after each refresh) */
96
+ private currentState;
97
+ /** Scheduled refresh timer handle */
98
+ private refreshTimer;
99
+ /** Playback time (seconds) to restore after a native-video source reload */
100
+ private savedPosition;
101
+ /** True when using native HTML5 Video playback (no request interception) */
102
+ private isNativePlayback;
103
+ /** Set in destroy(); short-circuits late timer callbacks and getToken() resolutions */
104
+ private destroyed;
105
+ /** @internal */
106
+ bindEvents(): void;
107
+ /** @internal */
108
+ destroy(): void;
109
+ private onContainersCreated;
110
+ private injectHlsLoader;
111
+ private injectDashInterceptor;
112
+ private reloadNativeSource;
113
+ private onActiveContainerChangedForNative;
114
+ private scheduleRefresh;
115
+ private performRefresh;
116
+ private get opts();
117
+ private clearTimer;
118
+ }
119
+ //# sourceMappingURL=TokenRefreshPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenRefreshPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/token-refresh/TokenRefreshPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,UAAU,EAAU,MAAM,cAAc,CAAA;AAQrE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAA;IACX,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;OAEG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAA;CACjD;AAgED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBAAa,kBAAmB,SAAQ,UAAU;IAChD,gBAAgB;IAChB,MAAM,KAAK,IAAI,IAAI,MAAM,CAExB;IAED,gBAAgB;IAChB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,gBAAgB;IAChB,IAAI,gBAAgB;;MAEnB;IAED,kEAAkE;IAClE,OAAO,CAAC,aAAa,CAA0B;IAC/C,sDAAsD;IACtD,OAAO,CAAC,YAAY,CAA0B;IAC9C,qCAAqC;IACrC,OAAO,CAAC,YAAY,CAA6C;IACjE,4EAA4E;IAC5E,OAAO,CAAC,aAAa,CAAsB;IAC3C,4EAA4E;IAC5E,OAAO,CAAC,gBAAgB,CAAQ;IAChC,uFAAuF;IACvF,OAAO,CAAC,SAAS,CAAQ;IAEzB,gBAAgB;IACP,UAAU,IAAI,IAAI;IAQ3B,gBAAgB;IACP,OAAO,IAAI,IAAI;IAMxB,OAAO,CAAC,mBAAmB;IA8D3B,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,qBAAqB;YAmBf,kBAAkB;IA+ChC,OAAO,CAAC,iCAAiC;IAiBzC,OAAO,CAAC,eAAe;YAmBT,cAAc;IAmC5B,OAAO,KAAK,IAAI,GAEf;IAED,OAAO,CAAC,UAAU;CAMnB"}