@gcorevideo/player 2.21.3 → 2.21.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.
Files changed (98) hide show
  1. package/assets/audio-selector/style.scss +1 -1
  2. package/assets/audio-selector/track-selector.ejs +3 -3
  3. package/assets/bottom-gear/bottomgear.ejs +2 -2
  4. package/assets/dvr-controls/dvr_controls.scss +7 -25
  5. package/assets/dvr-controls/index.ejs +2 -2
  6. package/assets/media-control/container.scss +1 -1
  7. package/assets/media-control/media-control.ejs +1 -6
  8. package/assets/media-control/media-control.scss +14 -7
  9. package/assets/media-control/width270.scss +1 -1
  10. package/assets/media-control/width370.scss +5 -5
  11. package/assets/playback-rate/button.ejs +2 -2
  12. package/assets/playback-rate/list.ejs +4 -4
  13. package/assets/style/theme.scss +1 -1
  14. package/assets/subtitles/combobox.ejs +5 -5
  15. package/assets/subtitles/string.ejs +1 -1
  16. package/assets/subtitles/style.scss +2 -2
  17. package/dist/core.js +2 -1
  18. package/dist/index.css +993 -993
  19. package/dist/index.js +199 -178
  20. package/dist/player.d.ts +141 -119
  21. package/dist/plugins/index.css +1118 -1118
  22. package/dist/plugins/index.js +191 -173
  23. package/docs/api/player.bottomgear.getelement.md +2 -2
  24. package/docs/api/player.bottomgear.md +1 -1
  25. package/docs/api/{player.subtitles.hide.md → player.closedcaptions.hide.md} +2 -2
  26. package/docs/api/{player.subtitles.md → player.closedcaptions.md} +11 -11
  27. package/docs/api/{player.subtitles.show.md → player.closedcaptions.show.md} +2 -2
  28. package/docs/api/player.closedcaptionspluginsettings.md +13 -0
  29. package/docs/api/player.gearitemelement.md +6 -4
  30. package/docs/api/player.gearoptionsitem.md +16 -0
  31. package/docs/api/player.md +48 -12
  32. package/docs/api/player.mediacontrol.putelement.md +2 -2
  33. package/docs/api/player.mediacontrolelement.md +1 -1
  34. package/docs/api/player.playbackrate.md +1 -1
  35. package/docs/api/player.subtitlespluginsettings.md +18 -0
  36. package/docs/api/player.texttrackitem.id.md +11 -0
  37. package/docs/api/player.texttrackitem.md +87 -0
  38. package/docs/api/player.texttrackitem.name.md +11 -0
  39. package/docs/api/player.texttrackitem.track.md +11 -0
  40. package/lib/index.d.ts +1 -1
  41. package/lib/index.js +1 -1
  42. package/lib/index.plugins.d.ts +2 -1
  43. package/lib/index.plugins.d.ts.map +1 -1
  44. package/lib/index.plugins.js +2 -1
  45. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  46. package/lib/playback/dash-playback/DashPlayback.js +1 -0
  47. package/lib/plugins/audio-selector/AudioSelector.d.ts +2 -3
  48. package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
  49. package/lib/plugins/audio-selector/AudioSelector.js +6 -7
  50. package/lib/plugins/bottom-gear/BottomGear.d.ts +6 -2
  51. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  52. package/lib/plugins/bottom-gear/BottomGear.js +2 -1
  53. package/lib/plugins/dvr-controls/DvrControls.d.ts +0 -3
  54. package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
  55. package/lib/plugins/dvr-controls/DvrControls.js +13 -38
  56. package/lib/plugins/media-control/MediaControl.d.ts +14 -18
  57. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  58. package/lib/plugins/media-control/MediaControl.js +105 -72
  59. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts +1 -0
  60. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
  61. package/lib/plugins/picture-in-picture/PictureInPicture.js +4 -4
  62. package/lib/plugins/playback-rate/PlaybackRate.d.ts +0 -1
  63. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  64. package/lib/plugins/playback-rate/PlaybackRate.js +23 -14
  65. package/lib/plugins/subtitles/ClosedCaptions.d.ts +118 -0
  66. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -0
  67. package/lib/plugins/subtitles/ClosedCaptions.js +348 -0
  68. package/lib/plugins/subtitles/Subtitles.d.ts +12 -9
  69. package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
  70. package/lib/plugins/subtitles/Subtitles.js +31 -32
  71. package/lib/testUtils.d.ts +26 -19
  72. package/lib/testUtils.d.ts.map +1 -1
  73. package/lib/testUtils.js +30 -45
  74. package/package.json +1 -1
  75. package/src/index.plugins.ts +2 -1
  76. package/src/index.ts +1 -1
  77. package/src/playback/dash-playback/DashPlayback.ts +1 -0
  78. package/src/plugins/audio-selector/AudioSelector.ts +9 -8
  79. package/src/plugins/bottom-gear/BottomGear.ts +11 -4
  80. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -1
  81. package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +2 -2
  82. package/src/plugins/dvr-controls/DvrControls.ts +16 -44
  83. package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +18 -22
  84. package/src/plugins/dvr-controls/__tests__/__snapshots__/DvrControls.test.ts.snap +6 -30
  85. package/src/plugins/media-control/MediaControl.ts +130 -85
  86. package/src/plugins/media-control/__tests__/MediaControl.test.ts +132 -0
  87. package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +299 -0
  88. package/src/plugins/picture-in-picture/PictureInPicture.ts +5 -5
  89. package/src/plugins/playback-rate/PlaybackRate.ts +142 -100
  90. package/src/plugins/playback-rate/__tests__/PlaybackRate.test.ts +65 -0
  91. package/src/plugins/playback-rate/__tests__/__snapshots__/PlaybackRate.test.ts.snap +11 -0
  92. package/src/plugins/subtitles/{Subtitles.ts → ClosedCaptions.ts} +42 -34
  93. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +58 -0
  94. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +25 -0
  95. package/src/testUtils.ts +30 -45
  96. package/temp/player.api.json +269 -89
  97. package/tsconfig.tsbuildinfo +1 -1
  98. package/src/plugins/index.ts +0 -39
@@ -9,8 +9,8 @@ import comboboxHTML from '../../../assets/subtitles/combobox.ejs';
9
9
  import stringHTML from '../../../assets/subtitles/string.ejs';
10
10
  import { isFullscreen } from '../utils.js';
11
11
  const VERSION = '2.19.14';
12
- const LOCAL_STORAGE_SUBTITLES_ID = 'gplayer.plugins.subtitles.selected';
13
- const T = 'plugins.subtitles';
12
+ const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
13
+ const T = 'plugins.cc';
14
14
  /**
15
15
  * `PLUGIN` that provides a UI to select the subtitles when available.
16
16
  * @beta
@@ -20,16 +20,16 @@ const T = 'plugins.subtitles';
20
20
  *
21
21
  * - {@link MediaControl}
22
22
  *
23
- * Configuration options - {@link SubtitlesPluginSettings}
23
+ * Configuration options - {@link ClosedCaptionsPluginSettings}
24
24
  * @example
25
25
  * ```ts
26
- * import { Subtitles } from '@gcorevideo/player'
26
+ * import { ClosedCaptions } from '@gcorevideo/player'
27
27
  *
28
- * Player.registerPlugin(Subtitles)
28
+ * Player.registerPlugin(ClosedCaptions)
29
29
  *
30
30
  * new Player({
31
31
  * ...
32
- * subtitles: {
32
+ * cc: {
33
33
  * language: 'en',
34
34
  * },
35
35
  * })
@@ -40,12 +40,12 @@ export class Subtitles extends UICorePlugin {
40
40
  isShowing = false;
41
41
  track = null;
42
42
  tracks = [];
43
- $string = null;
43
+ $line = null;
44
44
  /**
45
45
  * @internal
46
46
  */
47
47
  get name() {
48
- return 'subtitles';
48
+ return 'subtitles'; // TODO rename to 'cc'
49
49
  }
50
50
  /**
51
51
  * @internal
@@ -66,8 +66,7 @@ export class Subtitles extends UICorePlugin {
66
66
  */
67
67
  get attributes() {
68
68
  return {
69
- class: 'media-control-subtitles',
70
- 'data-subtitles': '',
69
+ class: 'media-control-cc',
71
70
  };
72
71
  }
73
72
  /**
@@ -75,12 +74,12 @@ export class Subtitles extends UICorePlugin {
75
74
  */
76
75
  get events() {
77
76
  return {
78
- 'click [data-subtitles-select]': 'onItemSelect',
79
- 'click [data-subtitles-button]': 'toggleMenu',
77
+ 'click [data-cc-select]': 'onItemSelect',
78
+ 'click [data-cc-button]': 'toggleMenu',
80
79
  };
81
80
  }
82
81
  get preselectedLanguage() {
83
- return this.core.options.subtitles?.language ?? '';
82
+ return this.core.options.cc?.language ?? this.core.options.subtitles?.language ?? '';
84
83
  }
85
84
  /**
86
85
  * @internal
@@ -195,7 +194,7 @@ export class Subtitles extends UICorePlugin {
195
194
  hide() {
196
195
  this.isShowing = false;
197
196
  this.renderIcon();
198
- this.$string.hide();
197
+ this.$line.hide();
199
198
  if (this.tracks) {
200
199
  for (const t of this.tracks) {
201
200
  t.track.mode = 'hidden';
@@ -213,22 +212,22 @@ export class Subtitles extends UICorePlugin {
213
212
  this.track &&
214
213
  this.track.track.mode &&
215
214
  Browser.isiOS) {
216
- this.$string.hide();
215
+ this.$line.hide();
217
216
  this.track.track.mode = 'showing';
218
217
  }
219
218
  else {
220
- this.$string.show();
219
+ this.$line.show();
221
220
  }
222
221
  }
223
222
  shouldRender() {
224
- return this.tracks.length > 0;
223
+ return this.tracks?.length > 0;
225
224
  }
226
225
  resizeFont() {
227
- if (!this.$string) {
226
+ if (!this.$line) {
228
227
  return;
229
228
  }
230
229
  const skinWidth = this.core.activeContainer.$el.width();
231
- this.$string.find('p').css('font-size', skinWidth * 0.03);
230
+ this.$line.find('p').css('font-size', skinWidth * 0.03);
232
231
  }
233
232
  /**
234
233
  * @internal
@@ -242,11 +241,11 @@ export class Subtitles extends UICorePlugin {
242
241
  }
243
242
  const mediaControl = this.core.getPlugin('media_control');
244
243
  this.$el.html(Subtitles.template({ tracks: this.tracks }));
245
- this.core.activeContainer.$el.find('.subtitle-string').remove();
246
- this.$string = $(Subtitles.templateString());
244
+ this.core.activeContainer.$el.find('#cc-line').remove();
245
+ this.$line = $(Subtitles.templateString());
247
246
  this.resizeFont();
248
- this.core.activeContainer.$el.append(this.$string);
249
- mediaControl.putElement('subtitlesSelector', this.$el);
247
+ this.core.activeContainer.$el.append(this.$line);
248
+ mediaControl.putElement('cc', this.el);
250
249
  this.updateSelection();
251
250
  this.renderIcon();
252
251
  return this;
@@ -261,9 +260,9 @@ export class Subtitles extends UICorePlugin {
261
260
  this.updateSelection();
262
261
  }
263
262
  onItemSelect(event) {
264
- const id = event.target.dataset.subtitlesSelect ?? '-1';
263
+ const id = event.target.dataset.ccSelect ?? '-1';
265
264
  trace(`${T} onItemSelect`, { id });
266
- localStorage.setItem(LOCAL_STORAGE_SUBTITLES_ID, id);
265
+ localStorage.setItem(LOCAL_STORAGE_CC_ID, id);
267
266
  this.selectItem(this.findById(Number(id)));
268
267
  return false;
269
268
  }
@@ -280,17 +279,17 @@ export class Subtitles extends UICorePlugin {
280
279
  }
281
280
  hideMenu() {
282
281
  ;
283
- this.$('[data-subtitles] ul').hide();
282
+ this.$('[data-cc] ul').hide();
284
283
  }
285
284
  toggleMenu() {
286
- ;
287
- this.$('[data-subtitles] ul').toggle();
285
+ trace(`${T} toggleMenu`);
286
+ this.$('[data-cc] ul').toggle();
288
287
  }
289
288
  itemElement(id) {
290
- return this.$(`ul li a[data-subtitles-select="${id}"]`).parent();
289
+ return this.$(`ul li a[data-cc-select="${id}"]`).parent();
291
290
  }
292
291
  allItemElements() {
293
- return this.$('[data-subtitles] li');
292
+ return this.$('[data-cc] li');
294
293
  }
295
294
  selectSubtitles() {
296
295
  const trackId = this.track ? this.track.id : -1;
@@ -310,7 +309,7 @@ export class Subtitles extends UICorePlugin {
310
309
  return lines.join('\n');
311
310
  }
312
311
  setSubtitleText(text) {
313
- this.$string.find('p').html(text);
312
+ this.$line.find('p').html(text);
314
313
  }
315
314
  clearSubtitleText() {
316
315
  this.setSubtitleText('');
@@ -341,6 +340,6 @@ export class Subtitles extends UICorePlugin {
341
340
  }
342
341
  renderIcon() {
343
342
  const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
344
- this.$el.find('span.subtitle-text').html(icon);
343
+ this.$el.find('span.cc-text').html(icon);
345
344
  }
346
345
  }
@@ -65,36 +65,43 @@ export declare function createSpinnerPlugin(): Events<string | symbol, any> & {
65
65
  export declare function createMockPlayback(name?: string): Events<string | symbol, any> & {
66
66
  name: string;
67
67
  currentLevel: number;
68
+ el: HTMLVideoElement;
69
+ dvrEnabled: boolean;
70
+ dvrInUse: boolean;
68
71
  levels: never[];
69
72
  consent(): void;
70
73
  play(): void;
71
74
  pause(): void;
72
75
  stop(): void;
73
- destroy(): void;
74
- seek(): void;
75
- seekPercentage(): void;
76
- getDuration(): 100;
77
- enterPiP(): void;
78
- exitPiP(): void;
79
- getPlaybackType(): "live";
80
- getStartTimeOffset(): 0;
81
- getCurrentTime(): 0;
82
- isHighDefinitionInUse(): false;
83
- mute(): void;
84
- unmute(): void;
85
- volume(): void;
86
- configure(): void;
87
- attemptAutoPlay(): true;
88
- canAutoPlay(): true;
89
- onResize(): true;
90
- trigger(event: string, ...args: any[]): void;
76
+ destroy: import("vitest").Mock<(...args: any[]) => any>;
77
+ seek: import("vitest").Mock<(...args: any[]) => any>;
78
+ seekPercentage: import("vitest").Mock<(...args: any[]) => any>;
79
+ getDuration: import("vitest").Mock<(...args: any[]) => any>;
80
+ enterPiP: import("vitest").Mock<(...args: any[]) => any>;
81
+ exitPiP: import("vitest").Mock<(...args: any[]) => any>;
82
+ getPlaybackType: import("vitest").Mock<(...args: any[]) => any>;
83
+ getStartTimeOffset: import("vitest").Mock<(...args: any[]) => any>;
84
+ getCurrentTime: import("vitest").Mock<(...args: any[]) => any>;
85
+ isHighDefinitionInUse: import("vitest").Mock<(...args: any[]) => any>;
86
+ mute: import("vitest").Mock<(...args: any[]) => any>;
87
+ unmute: import("vitest").Mock<(...args: any[]) => any>;
88
+ volume: import("vitest").Mock<(...args: any[]) => any>;
89
+ configure: import("vitest").Mock<(...args: any[]) => any>;
90
+ attemptAutoPlay: import("vitest").Mock<(...args: any[]) => any>;
91
+ canAutoPlay: import("vitest").Mock<(...args: any[]) => any>;
92
+ onResize: import("vitest").Mock<(...args: any[]) => any>;
93
+ setPlaybackRate: import("vitest").Mock<(...args: any[]) => any>;
94
+ trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
91
95
  };
92
96
  export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
93
- el: HTMLDivElement;
97
+ el: any;
94
98
  playback: any;
95
99
  $el: any;
96
100
  getDuration: import("vitest").Mock<(...args: any[]) => any>;
97
101
  getPlugin: import("vitest").Mock<(...args: any[]) => any>;
102
+ getPlaybackType: import("vitest").Mock<(...args: any[]) => any>;
103
+ isDvrInUse: import("vitest").Mock<(...args: any[]) => any>;
104
+ isDvrEnabled: import("vitest").Mock<(...args: any[]) => any>;
98
105
  isPlaying: import("vitest").Mock<(...args: any[]) => any>;
99
106
  play: import("vitest").Mock<(...args: any[]) => any>;
100
107
  seek: import("vitest").Mock<(...args: any[]) => any>;
@@ -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;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAA2B;;;;;;;;;;;;;;;;EAqBvC;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;mBA2C7B,MAAM,WAAW,GAAG,EAAE;EAIxC;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,GAA0B;;;;;;;;;;EAcvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAqB/C"}
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAA2B;;;;;;;;;;;;;;;;EAqBvC;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiC/C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;EAiBvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAiB/C"}
package/lib/testUtils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $, UICorePlugin } from '@clappr/core';
1
+ import { $, Playback, UICorePlugin } from '@clappr/core';
2
2
  import Events from 'eventemitter3';
3
3
  import { vi } from 'vitest';
4
4
  /**
@@ -32,7 +32,7 @@ export class _MockPlayback extends Events {
32
32
  enterPiP() { }
33
33
  exitPiP() { }
34
34
  getPlaybackType() {
35
- return 'live';
35
+ return Playback.LIVE;
36
36
  }
37
37
  getStartTimeOffset() {
38
38
  return 0;
@@ -75,7 +75,7 @@ export function createMockCore(options = {}, container = createMockContainer())
75
75
  ...options,
76
76
  },
77
77
  configure: vi.fn(),
78
- getPlaybackType: vi.fn(),
78
+ getPlaybackType: vi.fn().mockReturnValue(Playback.LIVE),
79
79
  getPlugin: vi.fn(),
80
80
  load: vi.fn(),
81
81
  trigger: emitter.emit,
@@ -98,51 +98,37 @@ export function createMockPlayback(name = 'mock') {
98
98
  return Object.assign(emitter, {
99
99
  name,
100
100
  currentLevel: -1,
101
+ el: document.createElement('video'),
102
+ dvrEnabled: false,
103
+ dvrInUse: false,
101
104
  levels: [],
102
105
  consent() { },
103
106
  play() { },
104
107
  pause() { },
105
108
  stop() { },
106
- destroy() { },
107
- seek() { },
108
- seekPercentage() { },
109
- getDuration() {
110
- return 100;
111
- },
112
- enterPiP() { },
113
- exitPiP() { },
114
- getPlaybackType() {
115
- return 'live';
116
- },
117
- getStartTimeOffset() {
118
- return 0;
119
- },
120
- getCurrentTime() {
121
- return 0;
122
- },
123
- isHighDefinitionInUse() {
124
- return false;
125
- },
126
- mute() { },
127
- unmute() { },
128
- volume() { },
129
- configure() { },
130
- attemptAutoPlay() {
131
- return true;
132
- },
133
- canAutoPlay() {
134
- return true;
135
- },
136
- onResize() {
137
- return true;
138
- },
139
- trigger(event, ...args) {
140
- emitter.emit(event, ...args);
141
- },
109
+ destroy: vi.fn(),
110
+ seek: vi.fn(),
111
+ seekPercentage: vi.fn(),
112
+ getDuration: vi.fn().mockImplementation(() => 100),
113
+ enterPiP: vi.fn(),
114
+ exitPiP: vi.fn(),
115
+ getPlaybackType: vi.fn().mockImplementation(() => Playback.LIVE),
116
+ getStartTimeOffset: vi.fn().mockImplementation(() => 0),
117
+ getCurrentTime: vi.fn().mockImplementation(() => 0),
118
+ isHighDefinitionInUse: vi.fn().mockImplementation(() => false),
119
+ mute: vi.fn(),
120
+ unmute: vi.fn(),
121
+ volume: vi.fn(),
122
+ configure: vi.fn(),
123
+ attemptAutoPlay: vi.fn().mockImplementation(() => true),
124
+ canAutoPlay: vi.fn().mockImplementation(() => true),
125
+ onResize: vi.fn().mockImplementation(() => true),
126
+ setPlaybackRate: vi.fn(),
127
+ trigger: emitter.emit,
142
128
  });
143
129
  }
144
130
  export function createMockContainer(playback = createMockPlayback()) {
145
- const el = document.createElement('div');
131
+ const el = playback.el;
146
132
  const emitter = new Events();
147
133
  return Object.assign(emitter, {
148
134
  el,
@@ -150,6 +136,9 @@ export function createMockContainer(playback = createMockPlayback()) {
150
136
  $el: $(el),
151
137
  getDuration: vi.fn().mockReturnValue(0),
152
138
  getPlugin: vi.fn(),
139
+ getPlaybackType: vi.fn().mockReturnValue(Playback.LIVE),
140
+ isDvrInUse: vi.fn().mockReturnValue(false),
141
+ isDvrEnabled: vi.fn().mockReturnValue(false),
153
142
  isPlaying: vi.fn().mockReturnValue(false),
154
143
  play: vi.fn(),
155
144
  seek: vi.fn(),
@@ -169,10 +158,6 @@ export function createMockMediaControl(core) {
169
158
  // @ts-ignore
170
159
  mediaControl.putElement = vi.fn();
171
160
  // @ts-ignore
172
- mediaControl.getLeftPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-left-panel'));
173
- // @ts-ignore
174
- mediaControl.getRightPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-right-panel'));
175
- // @ts-ignore
176
- mediaControl.getCenterPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-center-panel'));
161
+ mediaControl.toggleElement = vi.fn();
177
162
  return mediaControl;
178
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.21.3",
3
+ "version": "2.21.6",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -25,7 +25,8 @@ export * from "./plugins/share/Share.js";
25
25
  export * from "./plugins/skip-time/SkipTime.js";
26
26
  export * from "./plugins/spinner-three-bounce/SpinnerThreeBounce.js";
27
27
  export * from "./plugins/source-controller/SourceController.js";
28
- export * from "./plugins/subtitles/Subtitles.js";
28
+ export * from "./plugins/subtitles/ClosedCaptions.js";
29
+ export { ClosedCaptions as Subtitles } from "./plugins/subtitles/ClosedCaptions.js"; // TODO remove in future versions
29
30
  export * from "./plugins/telemetry/Telemetry.js";
30
31
  export * from "./plugins/thumbnails/Thumbnails.js";
31
32
  // _ vast-ads
package/src/index.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * It is built on top of the {@link https://github.com/clappr/clappr | Clappr} library and provides a framework for building custom integrations.
7
7
  * Start with {@link Player} for more information.
8
8
  *
9
- * Various plugins (marked with `PLUGIN` keyword) are available to extend the player with additional features.
9
+ * Various plugins (marked with `PLUGIN` keyword) are available to extend the core functionality with additional features.
10
10
  * @example
11
11
  * ```ts
12
12
  * import { Player, MediaControl, ErrorScreen } from '@gcorevideo/player'
@@ -416,6 +416,7 @@ export default class DashPlayback extends BasePlayback {
416
416
  this.trigger(Events.PLAYBACK_STATS_ADD, { dvr: status })
417
417
  }
418
418
 
419
+ // TODO move to the base class
419
420
  override _updateSettings() {
420
421
  if (this._playbackType === Playback.VOD) {
421
422
  // @ts-expect-error
@@ -9,6 +9,7 @@ import pluginHtml from '../../../assets/audio-selector/track-selector.ejs'
9
9
  import '../../../assets/audio-selector/style.scss'
10
10
  import audioArrow from '../../../assets/icons/old/quality-arrow.svg'
11
11
  import { ZeptoResult } from '../../types.js'
12
+ import { MediaControl } from '../media-control/MediaControl.js'
12
13
 
13
14
  const VERSION: string = '0.0.1'
14
15
 
@@ -57,8 +58,8 @@ export class AudioSelector extends UICorePlugin {
57
58
  */
58
59
  override get attributes() {
59
60
  return {
60
- class: 'media-control-audio-tracks',
61
- 'data-track-selector': '',
61
+ class: 'media-control-audiotracks',
62
+
62
63
  }
63
64
  }
64
65
 
@@ -67,8 +68,8 @@ export class AudioSelector extends UICorePlugin {
67
68
  */
68
69
  override get events() {
69
70
  return {
70
- 'click [data-track-selector-select]': 'onTrackSelect',
71
- 'click [data-track-selector-button]': 'onShowLevelSelectMenu',
71
+ 'click [data-audiotracks-select]': 'onTrackSelect',
72
+ 'click [data-audiotracks-button]': 'onShowLevelSelectMenu',
72
73
  }
73
74
  }
74
75
 
@@ -156,12 +157,12 @@ export class AudioSelector extends UICorePlugin {
156
157
  return this
157
158
  }
158
159
 
159
- const mediaControl = this.core.getPlugin('media_control')
160
+ const mediaControl = this.core.getPlugin('media_control') as MediaControl
160
161
  this.$el.html(
161
162
  AudioSelector.template({ tracks: this.tracks, title: this.getTitle() }),
162
163
  )
163
164
  this.$('.audio-arrow').append(audioArrow)
164
- mediaControl.putElement('audioTracksSelector', this.$el)
165
+ mediaControl.putElement('audiotracks', this.el)
165
166
 
166
167
  this.updateText()
167
168
  this.highlightCurrentTrack()
@@ -179,7 +180,7 @@ export class AudioSelector extends UICorePlugin {
179
180
  }
180
181
 
181
182
  private onTrackSelect(event: MouseEvent) {
182
- const id = (event.target as HTMLElement)?.dataset?.trackSelectorSelect
183
+ const id = (event.target as HTMLElement)?.dataset?.audiotracksSelect
183
184
  if (id) {
184
185
  this.selectAudioTrack(id)
185
186
  }
@@ -218,7 +219,7 @@ export class AudioSelector extends UICorePlugin {
218
219
  return (
219
220
  this.$(
220
221
  'ul a' +
221
- (id !== undefined ? '[data-track-selector-select="' + id + '"]' : ''),
222
+ (id !== undefined ? '[data-audiotracks-select="' + id + '"]' : ''),
222
223
  ) as ZeptoResult
223
224
  ).parent()
224
225
  }
@@ -20,7 +20,12 @@ const T = 'plugins.bottom_gear';
20
20
  * An element inside the gear menu
21
21
  * @beta
22
22
  */
23
- export type GearItemElement = 'quality' | 'rate' | 'nerd';
23
+ export type GearOptionsItem = 'quality' | 'rate' | 'nerd';
24
+
25
+ /**
26
+ * @deprecated Use {@link GearOptionsItem} instead
27
+ */
28
+ export type GearItemElement = GearOptionsItem;
24
29
 
25
30
  // TODO disabled if no items added
26
31
 
@@ -90,10 +95,12 @@ export class BottomGear extends UICorePlugin {
90
95
  * @param name - Name of a gear menu placeholder item to attach custom UI
91
96
  * @returns Zepto result of the element
92
97
  */
93
- getElement(name: GearItemElement): ZeptoResult | null {
98
+ getElement(name: GearOptionsItem): ZeptoResult | null {
94
99
  return this.$el.find(`.gear-options-list [data-${name}]`);
95
100
  }
96
101
 
102
+ // TODO implement putElement/addElement method
103
+
97
104
  /**
98
105
  * Replaces the content of the gear menu
99
106
  * @param content - Zepto result of the element
@@ -125,7 +132,7 @@ export class BottomGear extends UICorePlugin {
125
132
  const mediaControl = this.core.getPlugin('media_control');
126
133
 
127
134
  // TODO use options.mediaControl.gear.items
128
- const items: GearItemElement[] = [
135
+ const items: GearOptionsItem[] = [
129
136
  'quality',
130
137
  'rate',
131
138
  'nerd',
@@ -133,7 +140,7 @@ export class BottomGear extends UICorePlugin {
133
140
  const icon = this.isHd ? gearHdIcon : gearIcon;
134
141
  this.$el.html(BottomGear.template({ icon, items }));
135
142
 
136
- mediaControl.putElement('gear', this.$el);
143
+ mediaControl.putElement('gear', this.el);
137
144
  mediaControl.trigger(MediaControlEvents.MEDIACONTROL_GEAR_RENDERED);
138
145
  return this;
139
146
  }
@@ -26,7 +26,7 @@ describe('BottomGear', () => {
26
26
  expect(bottomGear.el.innerHTML).toMatchSnapshot()
27
27
  })
28
28
  it('should attach to media control', () => {
29
- expect(mediaControl.putElement).toHaveBeenCalledWith('gear', bottomGear.$el)
29
+ expect(mediaControl.putElement).toHaveBeenCalledWith('gear', bottomGear.el)
30
30
  })
31
31
  it('should emit event', () => {
32
32
  expect(onGearRendered).toHaveBeenCalled()
@@ -1,11 +1,11 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`BottomGear > should render 1`] = `
4
- "<button type="button" class="button-gear media-control-button gplayer-lite-btn gcore-skin-button-color gear-icon" data-gear-button="-1">
4
+ "<button type="button" class="button-gear media-control-button gplayer-lite-btn gcore-skin-button-color gear-icon" data-gear-button="-1" id="gear-button">
5
5
  /assets/icons/new/gear.svg
6
6
  </button>
7
7
  <div class="gear-wrapper gcore-skin-bg-color">
8
- <ul class="gear-options-list">
8
+ <ul class="gear-options-list" id="gear-options">
9
9
 
10
10
  <li data-quality=""></li>
11
11
 
@@ -56,7 +56,6 @@ export class DvrControls extends UICorePlugin {
56
56
  override get attributes() {
57
57
  return {
58
58
  class: 'dvr-controls',
59
- 'data-dvr-controls': '',
60
59
  }
61
60
  }
62
61
 
@@ -65,7 +64,6 @@ export class DvrControls extends UICorePlugin {
65
64
  */
66
65
  override bindEvents() {
67
66
  this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
68
- this.listenTo(this.core, Events.CORE_OPTIONS_CHANGE, this.render)
69
67
  this.listenTo(
70
68
  this.core,
71
69
  Events.CORE_ACTIVE_CONTAINER_CHANGED,
@@ -76,48 +74,23 @@ export class DvrControls extends UICorePlugin {
76
74
  private onCoreReady() {
77
75
  const mediaControl = this.core.getPlugin('media_control')
78
76
  assert(mediaControl, 'media_control plugin is required')
77
+
79
78
  this.listenTo(
80
79
  mediaControl,
81
80
  Events.MEDIACONTROL_RENDERED,
82
- this.settingsUpdate,
81
+ this.render,
83
82
  )
84
- this.settingsUpdate()
83
+ // MediaControl has been rendered
84
+ this.render()
85
85
  }
86
86
 
87
87
  private bindContainerEvents() {
88
+ trace(`${T} bindContainerEvents`)
88
89
  this.listenToOnce(
89
90
  this.core.activeContainer,
90
91
  Events.CONTAINER_TIMEUPDATE,
91
92
  this.render,
92
93
  )
93
- this.listenTo(
94
- this.core.activeContainer,
95
- Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
96
- this.onDvrChanged,
97
- )
98
- }
99
-
100
- private onDvrChanged(dvrInUse: boolean) {
101
- trace(`${T} onDvrChanged`, {
102
- dvrInUse,
103
- })
104
- if (this.core.getPlaybackType() !== Playback.LIVE) {
105
- return
106
- }
107
- this.render()
108
- const mediaControl = this.core.getPlugin('media_control')
109
- mediaControl.$el.addClass('live')
110
- if (dvrInUse) {
111
- mediaControl.$el
112
- .addClass('dvr')
113
- .find(
114
- // TODO add API, test
115
- '.media-control-indicator[data-position], .media-control-indicator[data-duration]',
116
- )
117
- .hide()
118
- } else {
119
- mediaControl.$el.removeClass('dvr')
120
- }
121
94
  }
122
95
 
123
96
  private click() {
@@ -128,14 +101,8 @@ export class DvrControls extends UICorePlugin {
128
101
  container.seek(container.getDuration())
129
102
  }
130
103
 
131
- private settingsUpdate() {
132
- this.core.getPlugin('media_control').$el.removeClass('live')
133
- this.render()
134
- }
135
-
136
104
  private shouldRender() {
137
- const useDvrControls = this.core.options.useDvrControls !== false
138
- return useDvrControls && this.core.getPlaybackType() === Playback.LIVE
105
+ return this.core.getPlaybackType() === Playback.LIVE
139
106
  }
140
107
 
141
108
  /**
@@ -146,18 +113,23 @@ export class DvrControls extends UICorePlugin {
146
113
  dvrEnabled: this.core.activePlayback?.dvrEnabled,
147
114
  playbackType: this.core.getPlaybackType(),
148
115
  })
116
+ const mediaControl = this.core.getPlugin('media_control') as MediaControl
117
+ if (!mediaControl) {
118
+ return this
119
+ }
149
120
  if (!this.shouldRender()) {
150
121
  return this
151
122
  }
123
+
124
+ mediaControl.toggleElement('duration', false)
125
+ mediaControl.toggleElement('position', false)
126
+
152
127
  this.$el.html(
153
128
  DvrControls.template({
154
- live: this.core.i18n.t('live'),
155
- backToLive: this.core.i18n.t('back_to_live'),
129
+ i18n: this.core.i18n,
156
130
  }),
157
131
  )
158
- const mediaControl = this.core.getPlugin('media_control') as MediaControl
159
- mediaControl.$el.addClass('live')
160
- mediaControl.getLeftPanel().append(this.$el)
132
+ mediaControl.putElement('dvr', this.el)
161
133
 
162
134
  return this
163
135
  }