@gcorevideo/player 2.28.35 → 2.29.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 (61) hide show
  1. package/README.md +22 -1
  2. package/assets/{subtitles → cc}/style.scss +5 -0
  3. package/assets/media-control/media-control.scss +8 -6
  4. package/assets/multi-camera/multicamera.ejs +27 -23
  5. package/assets/multi-camera/style.scss +7 -34
  6. package/assets/style/main.scss +2 -2
  7. package/dist/core.js +24 -28
  8. package/dist/index.css +384 -402
  9. package/dist/index.embed.js +54 -84
  10. package/dist/index.js +122 -219
  11. package/docs/api/player.md +22 -9
  12. package/docs/api/player.mediacontrol.setkeepvisible.md +56 -0
  13. package/docs/api/player.multicamera.md +0 -28
  14. package/docs/api/player.multiccamerasourceinfo.md +27 -0
  15. package/docs/api/{player.multicamera.unbindevents.md → player.multisourcesmode.md} +4 -7
  16. package/docs/api/player.sourcecontroller.md +0 -37
  17. package/lib/playback/BasePlayback.d.ts +1 -0
  18. package/lib/playback/BasePlayback.d.ts.map +1 -1
  19. package/lib/playback/BasePlayback.js +3 -0
  20. package/lib/playback/dash-playback/DashPlayback.d.ts +3 -1
  21. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  22. package/lib/playback/dash-playback/DashPlayback.js +9 -22
  23. package/lib/playback/hls-playback/HlsPlayback.d.ts +2 -1
  24. package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
  25. package/lib/playback/hls-playback/HlsPlayback.js +4 -0
  26. package/lib/playback/types.d.ts +9 -0
  27. package/lib/playback/types.d.ts.map +1 -1
  28. package/lib/playback.types.d.ts +0 -6
  29. package/lib/playback.types.d.ts.map +1 -1
  30. package/lib/plugins/multi-camera/MultiCamera.d.ts +21 -4
  31. package/lib/plugins/multi-camera/MultiCamera.d.ts.map +1 -1
  32. package/lib/plugins/multi-camera/MultiCamera.js +70 -134
  33. package/lib/plugins/source-controller/SourceController.d.ts +0 -39
  34. package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
  35. package/lib/plugins/source-controller/SourceController.js +0 -39
  36. package/lib/plugins/subtitles/ClosedCaptions.d.ts +1 -1
  37. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
  38. package/lib/plugins/subtitles/ClosedCaptions.js +32 -22
  39. package/lib/testUtils.d.ts +1 -0
  40. package/lib/testUtils.d.ts.map +1 -1
  41. package/lib/testUtils.js +3 -0
  42. package/lib/utils/mediaSources.d.ts +4 -0
  43. package/lib/utils/mediaSources.d.ts.map +1 -1
  44. package/lib/utils/mediaSources.js +8 -6
  45. package/package.json +1 -1
  46. package/src/playback/BasePlayback.ts +4 -0
  47. package/src/playback/dash-playback/DashPlayback.ts +11 -29
  48. package/src/playback/hls-playback/HlsPlayback.ts +5 -1
  49. package/src/playback/types.ts +10 -0
  50. package/src/playback.types.ts +0 -6
  51. package/src/plugins/multi-camera/MultiCamera.ts +103 -166
  52. package/src/plugins/source-controller/SourceController.ts +0 -39
  53. package/src/plugins/subtitles/ClosedCaptions.ts +35 -21
  54. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +73 -112
  55. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +3 -3
  56. package/src/testUtils.ts +3 -0
  57. package/src/utils/mediaSources.ts +10 -6
  58. package/tsconfig.tsbuildinfo +1 -1
  59. package/docs/api/player.multicamera.activebyid.md +0 -67
  60. /package/assets/{subtitles → cc}/combobox.ejs +0 -0
  61. /package/assets/{subtitles → cc}/string.ejs +0 -0
@@ -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'
@@ -1,5 +1,5 @@
1
1
  import { UICorePlugin } from '@clappr/core';
2
- import '../../../assets/subtitles/style.scss';
2
+ import '../../../assets/cc/style.scss';
3
3
  /**
4
4
  * Configuration options for the {@link ClosedCaptions} plugin.
5
5
  * @public
@@ -1 +1 @@
1
- {"version":3,"file":"ClosedCaptions.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/ClosedCaptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;AAmB7C;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAC3B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,iBAAiB,CAAQ;IAEjC,OAAO,CAAC,MAAM,CAAQ;IAEtB,OAAO,CAAC,IAAI,CAAQ;IAEpB,OAAO,CAAC,kBAAkB,CAAa;IAEvC,OAAO,CAAC,KAAK,CAA6B;IAE1C,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,KAAK,CAA2B;IAExC;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAyB;IAEhE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAuB;IAE3D;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAI9B;IAED,OAAO,CAAC,qBAAqB;IAO7B;;OAEG;IACM,UAAU;IAWnB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,kBAAkB;IAiD1B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,aAAa;IAmCrB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,IAAI;IAYJ;;OAEG;IACH,IAAI;IAiBJ,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACM,MAAM;IA+Bf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,sBAAsB;IAuB9B,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,KAAK;IAOb,OAAO,KAAK,kBAAkB,GAO7B;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,YAAY,QAEvB;IAED,OAAO,KAAK,aAAa,QAMxB;IAED,OAAO,CAAC,SAAS,CAA+C;CACjE"}
1
+ {"version":3,"file":"ClosedCaptions.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/ClosedCaptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,+BAA+B,CAAA;AAmBtC;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAC3B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,iBAAiB,CAAQ;IAEjC,OAAO,CAAC,MAAM,CAAQ;IAEtB,OAAO,CAAC,IAAI,CAAQ;IAEpB,OAAO,CAAC,kBAAkB,CAAa;IAEvC,OAAO,CAAC,KAAK,CAA6B;IAE1C,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,KAAK,CAA2B;IAExC;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAyB;IAEhE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAuB;IAE3D;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAI9B;IAED,OAAO,CAAC,qBAAqB;IAO7B;;OAEG;IACM,UAAU;IAWnB,OAAO,CAAC,WAAW;IAuBnB,OAAO,CAAC,kBAAkB;IAiD1B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,IAAI;IAcJ;;OAEG;IACH,IAAI;IAgBJ,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACM,MAAM;IAmCf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,sBAAsB;IAwB9B,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,KAAK;IAOb,OAAO,KAAK,kBAAkB,GAO7B;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,YAAY,QAEvB;IAED,OAAO,KAAK,aAAa,QAMxB;IAED,OAAO,CAAC,SAAS,CAA+C;CACjE"}
@@ -2,18 +2,15 @@ import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core';
2
2
  import { reportError } from '@gcorevideo/utils';
3
3
  import assert from 'assert';
4
4
  import { CLAPPR_VERSION } from '../../build.js';
5
- import '../../../assets/subtitles/style.scss';
5
+ import '../../../assets/cc/style.scss';
6
6
  import subtitlesOffIcon from '../../../assets/icons/new/subtitles-off.svg';
7
7
  import subtitlesOnIcon from '../../../assets/icons/new/subtitles-on.svg';
8
- import comboboxHTML from '../../../assets/subtitles/combobox.ejs';
9
- import stringHTML from '../../../assets/subtitles/string.ejs';
8
+ import comboboxHTML from '../../../assets/cc/combobox.ejs';
9
+ import stringHTML from '../../../assets/cc/string.ejs';
10
10
  import { isFullscreen } from '../utils/fullscreen.js';
11
11
  import { ExtendedEvents } from '../media-control/MediaControl.js';
12
12
  import { mediaControlClickaway } from '../../utils/clickaway.js';
13
13
  const VERSION = '2.19.14';
14
- // TODO review
15
- // const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected'
16
- const T = 'plugins.cc';
17
14
  /**
18
15
  * `PLUGIN` that provides a UI to select the subtitles when available.
19
16
  * @public
@@ -115,8 +112,12 @@ export class ClosedCaptions extends UICorePlugin {
115
112
  const mediaControl = this.core.getPlugin('media_control');
116
113
  assert(mediaControl, 'media_control plugin is required');
117
114
  this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.mount);
115
+ this.listenTo(mediaControl, Events.MEDIACONTROL_SHOW, () => {
116
+ this.$line?.removeClass('media-control-cc-pulled');
117
+ });
118
118
  this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, () => {
119
119
  this.hideMenu();
120
+ this.$line?.addClass('media-control-cc-pulled');
120
121
  });
121
122
  this.listenTo(mediaControl, ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, (from) => {
122
123
  if (from !== this.name) {
@@ -174,23 +175,27 @@ export class ClosedCaptions extends UICorePlugin {
174
175
  this.activateTrack(id);
175
176
  }
176
177
  activateTrack(id) {
177
- if (this.core.activePlayback && ['dash', 'hls'].includes(this.core.activePlayback.name)) {
178
- this.core.activePlayback.setTextTrack(id);
178
+ const isManaged = this.core.activePlayback?.name === 'hls';
179
+ this.core.activePlayback.setTextTrack(id);
180
+ if (isManaged) {
181
+ return;
182
+ }
183
+ if (!this.core.activePlayback?.el.textTracks) {
179
184
  return;
180
185
  }
181
- for (const track of this.currentTracks) {
182
- if (track.id === id) {
186
+ for (const [index, track] of Array.from(this.core.activePlayback?.el.textTracks ?? []).entries()) {
187
+ if (index === id) {
183
188
  if (this.useNativeSubtitles) {
184
- track.track.mode = 'showing';
189
+ track.mode = 'showing';
185
190
  }
186
191
  else {
187
- track.track.mode = 'hidden';
192
+ track.mode = 'hidden';
188
193
  }
189
- this.setSubtitleText(this.getSubtitleText(track.track));
190
- track.track.oncuechange = (e) => {
194
+ this.setSubtitleText(this.getSubtitleText(track));
195
+ track.oncuechange = () => {
191
196
  try {
192
- if (track.track.activeCues?.length) {
193
- const html = track.track.activeCues[0].getCueAsHTML();
197
+ if (track.activeCues?.length) {
198
+ const html = track.activeCues[0].getCueAsHTML();
194
199
  this.setSubtitleText(html);
195
200
  }
196
201
  else {
@@ -203,8 +208,8 @@ export class ClosedCaptions extends UICorePlugin {
203
208
  };
204
209
  }
205
210
  else {
206
- track.track.oncuechange = () => { };
207
- track.track.mode = 'disabled';
211
+ track.oncuechange = () => { };
212
+ track.mode = 'disabled';
208
213
  }
209
214
  }
210
215
  }
@@ -247,8 +252,10 @@ export class ClosedCaptions extends UICorePlugin {
247
252
  this.$el.find('#gplayer-cc-menu').hide();
248
253
  this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false');
249
254
  this.$line.hide();
250
- for (const track of this.currentTracks) {
251
- track.track.mode = 'hidden';
255
+ for (const track of this.core.activePlayback.el.textTracks) {
256
+ if (track.mode === 'showing') {
257
+ track.mode = 'hidden';
258
+ }
252
259
  }
253
260
  }
254
261
  /**
@@ -260,7 +267,6 @@ export class ClosedCaptions extends UICorePlugin {
260
267
  if (this.core.activeContainer &&
261
268
  isFullscreen(this.core.activeContainer.el) &&
262
269
  this.currentTrack &&
263
- // this.currentTrack.track.mode &&
264
270
  (Browser.isiOS || this.useNativeSubtitles)) {
265
271
  this.$line.hide();
266
272
  this.currentTrack.track.mode = 'showing';
@@ -302,6 +308,10 @@ export class ClosedCaptions extends UICorePlugin {
302
308
  this.resizeFont();
303
309
  this.clampPopup();
304
310
  this.core.activeContainer.$el.append(this.$line);
311
+ const mc = this.core.getPlugin('media_control');
312
+ if (!mc?.isVisible()) {
313
+ this.$line?.addClass('media-control-cc-pulled');
314
+ }
305
315
  this.updateSelection();
306
316
  this.renderIcon();
307
317
  return this;
@@ -407,7 +417,7 @@ export class ClosedCaptions extends UICorePlugin {
407
417
  this.setSubtitleText('');
408
418
  }
409
419
  updateSelection() {
410
- if (!this.currentTrack) {
420
+ if (this.core.activePlayback.closedCaptionsTrackId === -1) {
411
421
  this.hide();
412
422
  }
413
423
  else {
@@ -65,6 +65,7 @@ export declare function createMockPlayback(name?: string, options?: Record<strin
65
65
  canAutoPlay: import("vitest").Mock<(...args: any[]) => any>;
66
66
  onResize: import("vitest").Mock<(...args: any[]) => any>;
67
67
  setPlaybackRate: import("vitest").Mock<(...args: any[]) => any>;
68
+ setTextTrack: import("vitest").Mock<(...args: any[]) => any>;
68
69
  switchAudioTrack: import("vitest").Mock<(...args: any[]) => any>;
69
70
  trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
70
71
  };
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;;;EAuB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,SAAS,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCtC;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAyB/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;;;EAuB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,SAAS,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCtC;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBA2B/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
package/lib/testUtils.js CHANGED
@@ -71,6 +71,7 @@ export function createMockPlayback(name = 'mock', options = {}) {
71
71
  canAutoPlay: vi.fn().mockImplementation(() => true),
72
72
  onResize: vi.fn().mockImplementation(() => true),
73
73
  setPlaybackRate: vi.fn(),
74
+ setTextTrack: vi.fn(),
74
75
  switchAudioTrack: vi.fn(),
75
76
  trigger: emitter.emit,
76
77
  });
@@ -122,6 +123,8 @@ export function createMockMediaControl(core) {
122
123
  // @ts-ignore
123
124
  mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(286);
124
125
  // @ts-ignore
126
+ mediaControl.isVisible = vi.fn().mockReturnValue(true);
127
+ // @ts-ignore
125
128
  mediaControl.toggleElement = vi.fn();
126
129
  // @ts-ignore
127
130
  mediaControl.setKeepVisible = vi.fn();
@@ -1,7 +1,11 @@
1
1
  import type { PlayerMediaSource, PlayerMediaSourceDesc, TransportPreference } from '../types';
2
+ export declare const MIME_TYPES_HLS: string[];
3
+ export declare const MIME_TYPE_HLS: string;
4
+ export declare const MIME_TYPE_DASH = "application/dash+xml";
2
5
  export declare function buildMediaSourcesList(sources: PlayerMediaSourceDesc[], priorityTransport?: TransportPreference): PlayerMediaSourceDesc[];
3
6
  export declare function unwrapSource(s: PlayerMediaSource): string;
4
7
  export declare function wrapSource(s: PlayerMediaSource): PlayerMediaSourceDesc;
8
+ export declare function guessMimeType(s: string): string | undefined;
5
9
  export declare function isDashSource(source: string, mimeType?: string): boolean;
6
10
  export declare function isHlsSource(source: string, mimeType?: string): boolean;
7
11
  //# sourceMappingURL=mediaSources.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mediaSources.d.ts","sourceRoot":"","sources":["../../src/utils/mediaSources.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,UAAU,CAAA;AAIjB,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,qBAAqB,EAAE,EAChC,iBAAiB,GAAE,mBAA4B,GAC9C,qBAAqB,EAAE,CAqCzB;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAEzD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,iBAAiB,GAAG,qBAAqB,CAEtE;AAYD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,WAK7D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,WAO5D"}
1
+ {"version":3,"file":"mediaSources.d.ts","sourceRoot":"","sources":["../../src/utils/mediaSources.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,UAAU,CAAA;AAGjB,eAAO,MAAM,cAAc,UAA6D,CAAA;AACxF,eAAO,MAAM,aAAa,QAAoB,CAAA;AAC9C,eAAO,MAAM,cAAc,yBAAyB,CAAA;AAGpD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,qBAAqB,EAAE,EAChC,iBAAiB,GAAE,mBAA4B,GAC9C,qBAAqB,EAAE,CAqCzB;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAEzD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,iBAAiB,GAAG,qBAAqB,CAEtE;AAGD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO3D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,WAK7D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,WAO5D"}
@@ -1,5 +1,8 @@
1
1
  import { Loader } from '@clappr/core';
2
2
  import { trace } from '@gcorevideo/utils';
3
+ export const MIME_TYPES_HLS = ['application/x-mpegurl', 'application/vnd.apple.mpegurl'];
4
+ export const MIME_TYPE_HLS = MIME_TYPES_HLS[0];
5
+ export const MIME_TYPE_DASH = 'application/dash+xml';
3
6
  // TODO rewrite using the Playback classes and canPlay static methods
4
7
  export function buildMediaSourcesList(sources, priorityTransport = 'dash') {
5
8
  const playbacks = Loader.registeredPlaybacks;
@@ -40,24 +43,23 @@ export function unwrapSource(s) {
40
43
  export function wrapSource(s) {
41
44
  return typeof s === 'string' ? { source: s, mimeType: guessMimeType(s) } : s;
42
45
  }
43
- function guessMimeType(s) {
46
+ export function guessMimeType(s) {
44
47
  if (s.endsWith('.mpd')) {
45
- return 'application/dash+xml';
48
+ return MIME_TYPE_DASH;
46
49
  }
47
50
  if (s.endsWith('.m3u8')) {
48
- // return 'application/vnd.apple.mpegurl'
49
- return 'application/x-mpegurl';
51
+ return MIME_TYPE_HLS;
50
52
  }
51
53
  }
52
54
  export function isDashSource(source, mimeType) {
53
55
  if (mimeType) {
54
- return mimeType === 'application/dash+xml'; // TODO consider video/mp4
56
+ return mimeType === MIME_TYPE_DASH; // TODO consider video/mp4
55
57
  }
56
58
  return source.endsWith('.mpd');
57
59
  }
58
60
  export function isHlsSource(source, mimeType) {
59
61
  if (mimeType) {
60
- return ['application/vnd.apple.mpegurl', 'application/x-mpegurl'].includes(mimeType.toLowerCase());
62
+ return MIME_TYPES_HLS.includes(mimeType.toLowerCase());
61
63
  }
62
64
  return source.endsWith('.m3u8');
63
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.28.35",
3
+ "version": "2.29.0",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -50,4 +50,8 @@ export class BasePlayback extends HTML5Video {
50
50
  super._onPlaying()
51
51
  this.trigger(Events.PLAYBACK_MEDIACONTROL_ENABLE)
52
52
  }
53
+
54
+ setTextTrack(id: number) {
55
+ // noop
56
+ }
53
57
  }