@gcorevideo/player 2.21.1 → 2.21.3

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 (35) hide show
  1. package/assets/media-control/media-control.ejs +0 -5
  2. package/assets/media-control/media-control.scss +44 -54
  3. package/assets/media-control/width370.scss +3 -5
  4. package/assets/subtitles/combobox.ejs +7 -9
  5. package/assets/subtitles/style.scss +8 -15
  6. package/dist/core.js +4 -1
  7. package/dist/index.css +733 -750
  8. package/dist/index.js +135 -159
  9. package/dist/plugins/index.css +1401 -1418
  10. package/dist/plugins/index.js +124 -155
  11. package/lib/playback/BasePlayback.d.ts +1 -0
  12. package/lib/playback/BasePlayback.d.ts.map +1 -1
  13. package/lib/playback/BasePlayback.js +3 -0
  14. package/lib/playback.types.d.ts +5 -0
  15. package/lib/playback.types.d.ts.map +1 -1
  16. package/lib/plugins/bottom-gear/BottomGear.d.ts +1 -1
  17. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  18. package/lib/plugins/bottom-gear/BottomGear.js +2 -1
  19. package/lib/plugins/media-control/MediaControl.d.ts +0 -1
  20. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  21. package/lib/plugins/media-control/MediaControl.js +7 -5
  22. package/lib/plugins/playback-rate/PlaybackRate.d.ts +1 -0
  23. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  24. package/lib/plugins/playback-rate/PlaybackRate.js +1 -0
  25. package/lib/plugins/subtitles/Subtitles.d.ts +21 -19
  26. package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
  27. package/lib/plugins/subtitles/Subtitles.js +121 -151
  28. package/package.json +1 -1
  29. package/src/playback/BasePlayback.ts +4 -0
  30. package/src/playback.types.ts +6 -0
  31. package/src/plugins/bottom-gear/BottomGear.ts +3 -1
  32. package/src/plugins/media-control/MediaControl.ts +37 -20
  33. package/src/plugins/playback-rate/PlaybackRate.ts +1 -0
  34. package/src/plugins/subtitles/Subtitles.ts +144 -179
  35. package/tsconfig.tsbuildinfo +1 -1
@@ -95,7 +95,6 @@ export class MediaControl extends UICorePlugin {
95
95
  $seekBarLoaded = null;
96
96
  $seekBarPosition = null;
97
97
  $seekBarScrubber = null;
98
- $subtitlesSelector = null;
99
98
  $volumeBarContainer = null;
100
99
  $volumeBarBackground = null;
101
100
  $volumeBarFill = null;
@@ -116,7 +115,8 @@ export class MediaControl extends UICorePlugin {
116
115
  return { min: CLAPPR_VERSION };
117
116
  }
118
117
  get disabled() {
119
- const playbackIsNOOP = this.core.activeContainer && this.core.activeContainer.getPlaybackType() === Playback.NO_OP;
118
+ const playbackIsNOOP = this.core.activeContainer &&
119
+ this.core.activeContainer.getPlaybackType() === Playback.NO_OP;
120
120
  return this.userDisabled || playbackIsNOOP;
121
121
  }
122
122
  /**
@@ -776,7 +776,6 @@ export class MediaControl extends UICorePlugin {
776
776
  this.$volumeBarBackground = this.$el.find('.bar-background[data-volume]');
777
777
  this.$volumeBarFill = this.$el.find('.bar-fill-1[data-volume]');
778
778
  this.$volumeBarScrubber = this.$el.find('.bar-scrubber[data-volume]');
779
- this.$subtitlesSelector = this.$el.find('.media-control-subtitles[data-subtitles]');
780
779
  this.$playbackRate = this.$el.find('.media-control-playbackrate[data-playbackrate]');
781
780
  this.$multiCameraSelector = this.$el.find('.media-control-multicamera[data-multicamera]');
782
781
  this.$clipText = this.$el.find('.media-clip-text[data-clipstext]');
@@ -818,7 +817,7 @@ export class MediaControl extends UICorePlugin {
818
817
  case 'seekBarContainer':
819
818
  return this.$seekBarContainer;
820
819
  case 'subtitlesSelector':
821
- return this.$subtitlesSelector;
820
+ return null;
822
821
  }
823
822
  }
824
823
  putElement(name, element) {
@@ -826,10 +825,13 @@ export class MediaControl extends UICorePlugin {
826
825
  case 'audioTracksSelector':
827
826
  this.getRightPanel().append(element);
828
827
  break;
828
+ case 'gear':
829
+ this.getRightPanel().append(element);
830
+ break;
829
831
  case 'pip':
830
832
  this.getRightPanel().append(element);
831
833
  break;
832
- case 'gear':
834
+ case 'subtitlesSelector':
833
835
  this.getRightPanel().append(element);
834
836
  break;
835
837
  }
@@ -11,6 +11,7 @@ import { UICorePlugin, Core } from '@clappr/core';
11
11
  * - {@link BottomGear | bottom_gear}
12
12
  *
13
13
  * It renders a button in the gear menu, which opens a dropdown with the options to change the playback rate.
14
+ * Note that the playback rate change is supported only for VOD or DVR enabled live streams.
14
15
  */
15
16
  export declare class PlaybackRate extends UICorePlugin {
16
17
  private playbackRates;
@@ -1 +1 @@
1
- {"version":3,"file":"PlaybackRate.d.ts","sourceRoot":"","sources":["../../../src/plugins/playback-rate/PlaybackRate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAsB,IAAI,EAAE,MAAM,cAAc,CAAC;AAoC9E;;;;;;;;;;;;GAYG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,aAAa,CAAgD;IAGrE,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,YAAY,CAAiC;IAErD;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAwB;IAE9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAsB;gBAE9C,IAAI,EAAE,IAAI;IAMtB;;OAEG;IACH,IAAa,UAAU;;;MAKtB;IAED;;OAEG;IACH,IAAa,MAAM;;;;MAMlB;IAED;;OAEG;IACM,UAAU;IAKnB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACM,MAAM;IA6Bf,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,MAAM;IAGd,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,oBAAoB;CAS7B"}
1
+ {"version":3,"file":"PlaybackRate.d.ts","sourceRoot":"","sources":["../../../src/plugins/playback-rate/PlaybackRate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAsB,IAAI,EAAE,MAAM,cAAc,CAAC;AAoC9E;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,aAAa,CAAgD;IAGrE,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,YAAY,CAAiC;IAErD;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAwB;IAE9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAsB;gBAE9C,IAAI,EAAE,IAAI;IAMtB;;OAEG;IACH,IAAa,UAAU;;;MAKtB;IAED;;OAEG;IACH,IAAa,MAAM;;;;MAMlB;IAED;;OAEG;IACM,UAAU;IAKnB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACM,MAAM;IA6Bf,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,MAAM;IAGd,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,oBAAoB;CAS7B"}
@@ -33,6 +33,7 @@ const T = 'plugins.playback_rate';
33
33
  * - {@link BottomGear | bottom_gear}
34
34
  *
35
35
  * It renders a button in the gear menu, which opens a dropdown with the options to change the playback rate.
36
+ * Note that the playback rate change is supported only for VOD or DVR enabled live streams.
36
37
  */
37
38
  export class PlaybackRate extends UICorePlugin {
38
39
  playbackRates = DEFAULT_PLAYBACK_RATES;
@@ -1,5 +1,11 @@
1
1
  import { UICorePlugin } from '@clappr/core';
2
2
  import '../../../assets/subtitles/style.scss';
3
+ export type SubtitlesPluginSettings = {
4
+ /**
5
+ * Initially selected subtitles language
6
+ */
7
+ language?: string;
8
+ };
3
9
  /**
4
10
  * `PLUGIN` that provides a UI to select the subtitles when available.
5
11
  * @beta
@@ -9,10 +15,7 @@ import '../../../assets/subtitles/style.scss';
9
15
  *
10
16
  * - {@link MediaControl}
11
17
  *
12
- * Configuration options:
13
- *
14
- * - subtitles.language - The language of the subtitles to select by default.
15
- *
18
+ * Configuration options - {@link SubtitlesPluginSettings}
16
19
  * @example
17
20
  * ```ts
18
21
  * import { Subtitles } from '@gcorevideo/player'
@@ -28,7 +31,6 @@ import '../../../assets/subtitles/style.scss';
28
31
  * ```
29
32
  */
30
33
  export declare class Subtitles extends UICorePlugin {
31
- private currentLevel;
32
34
  private isPreselectedApplied;
33
35
  private isShowing;
34
36
  private track;
@@ -69,8 +71,11 @@ export declare class Subtitles extends UICorePlugin {
69
71
  * @internal
70
72
  */
71
73
  bindEvents(): void;
72
- private bindPlaybackEvents;
73
- private getTracks;
74
+ private onCoreReady;
75
+ private onContainerChanged;
76
+ private onSubtitleAvailable;
77
+ private onSubtitleChanged;
78
+ private applyTracks;
74
79
  private onStartAd;
75
80
  private onFinishAd;
76
81
  private playerResize;
@@ -88,22 +93,19 @@ export declare class Subtitles extends UICorePlugin {
88
93
  * @internal
89
94
  */
90
95
  render(): this;
91
- private setTracks;
92
- private findLevelBy;
93
- private selectLevel;
94
- private onLevelSelect;
96
+ private findById;
97
+ private selectItem;
98
+ private onItemSelect;
95
99
  private applyPreselectedSubtitles;
96
- private onShowLevelSelectMenu;
97
- private hideSelectLevelMenu;
98
- private toggleContextMenu;
99
- private buttonElement;
100
- private levelElement;
101
- private startLevelSwitch;
102
- private stopLevelSwitch;
100
+ private hideMenu;
101
+ private toggleMenu;
102
+ private itemElement;
103
+ private allItemElements;
103
104
  private selectSubtitles;
105
+ private getSubtitleText;
104
106
  private setSubtitleText;
105
107
  private clearSubtitleText;
106
- private updateCurrentLevel;
108
+ private updateSelection;
107
109
  private highlightCurrentSubtitles;
108
110
  private renderIcon;
109
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Subtitles.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/Subtitles.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAIb,MAAM,cAAc,CAAA;AAMrB,OAAO,sCAAsC,CAAA;AAuB7C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,oBAAoB,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,KAAK,CAAiC;IAE9C,OAAO,CAAC,MAAM,CAA6B;IAE3C,OAAO,CAAC,OAAO,CAA2B;IAE1C;;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,QAAQ,CAAyB;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D;;OAEG;IACH,IAAa,UAAU;;;MAKtB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAE9B;IAED;;OAEG;IACM,UAAU;IAiBnB,OAAO,CAAC,kBAAkB;IAkC1B,OAAO,CAAC,SAAS;IAcjB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,IAAI;IAWJ;;OAEG;IACH,IAAI;IAiBJ,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,UAAU;IAclB;;OAEG;IACM,MAAM;IAwCf,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,yBAAyB;IASjC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAgDvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,yBAAyB;IAYjC,OAAO,CAAC,UAAU;CASnB"}
1
+ {"version":3,"file":"Subtitles.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/Subtitles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;AAe7C,MAAM,MAAM,uBAAuB,GAAG;IACpC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,oBAAoB,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,KAAK,CAA6B;IAE1C,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,OAAO,CAA2B;IAE1C;;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,QAAQ,CAAyB;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D;;OAEG;IACH,IAAa,UAAU;;;MAKtB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAE9B;IAED;;OAEG;IACM,UAAU;IAUnB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,kBAAkB;IAwC1B,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAqBpB;;OAEG;IACH,IAAI;IAWJ;;OAEG;IACH,IAAI;IAiBJ,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACM,MAAM;IA0Bf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,UAAU;CAKnB"}
@@ -1,4 +1,4 @@
1
- import { Events, UICorePlugin, Browser, template, $, } from '@clappr/core';
1
+ import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core';
2
2
  import { reportError, trace } from '@gcorevideo/utils';
3
3
  import assert from 'assert';
4
4
  import { CLAPPR_VERSION } from '../../build.js';
@@ -11,7 +11,6 @@ import { isFullscreen } from '../utils.js';
11
11
  const VERSION = '2.19.14';
12
12
  const LOCAL_STORAGE_SUBTITLES_ID = 'gplayer.plugins.subtitles.selected';
13
13
  const T = 'plugins.subtitles';
14
- const NO_TRACK = { language: 'off' };
15
14
  /**
16
15
  * `PLUGIN` that provides a UI to select the subtitles when available.
17
16
  * @beta
@@ -21,10 +20,7 @@ const NO_TRACK = { language: 'off' };
21
20
  *
22
21
  * - {@link MediaControl}
23
22
  *
24
- * Configuration options:
25
- *
26
- * - subtitles.language - The language of the subtitles to select by default.
27
- *
23
+ * Configuration options - {@link SubtitlesPluginSettings}
28
24
  * @example
29
25
  * ```ts
30
26
  * import { Subtitles } from '@gcorevideo/player'
@@ -40,11 +36,10 @@ const NO_TRACK = { language: 'off' };
40
36
  * ```
41
37
  */
42
38
  export class Subtitles extends UICorePlugin {
43
- currentLevel = null;
44
39
  isPreselectedApplied = false;
45
40
  isShowing = false;
46
- track = { ...NO_TRACK };
47
- tracks = null;
41
+ track = null;
42
+ tracks = [];
48
43
  $string = null;
49
44
  /**
50
45
  * @internal
@@ -71,7 +66,7 @@ export class Subtitles extends UICorePlugin {
71
66
  */
72
67
  get attributes() {
73
68
  return {
74
- class: this.name,
69
+ class: 'media-control-subtitles',
75
70
  'data-subtitles': '',
76
71
  };
77
72
  }
@@ -80,28 +75,34 @@ export class Subtitles extends UICorePlugin {
80
75
  */
81
76
  get events() {
82
77
  return {
83
- 'click [data-subtitles-select]': 'onLevelSelect',
84
- 'click [data-subtitles-button]': 'onShowLevelSelectMenu',
78
+ 'click [data-subtitles-select]': 'onItemSelect',
79
+ 'click [data-subtitles-button]': 'toggleMenu',
85
80
  };
86
81
  }
87
82
  get preselectedLanguage() {
88
- return this.core.options.subtitles?.language ?? 'off';
83
+ return this.core.options.subtitles?.language ?? '';
89
84
  }
90
85
  /**
91
86
  * @internal
92
87
  */
93
88
  bindEvents() {
89
+ this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
90
+ this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
91
+ this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onContainerChanged);
92
+ }
93
+ onCoreReady() {
94
+ trace(`${T} onCoreReady`);
94
95
  const mediaControl = this.core.getPlugin('media_control');
95
96
  assert(mediaControl, 'media_control plugin is required');
96
- this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
97
- this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.bindPlaybackEvents);
98
97
  this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
99
- this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
98
+ this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu);
100
99
  }
101
- bindPlaybackEvents() {
100
+ onContainerChanged() {
101
+ trace(`${T} onContainerChanged`);
102
102
  this.listenTo(this.core.activeContainer, Events.CONTAINER_FULLSCREEN, this.playerResize);
103
- this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, this.getTracks);
104
103
  this.listenTo(this.core.activeContainer, 'container:advertisement:start', this.onStartAd);
104
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_AVAILABLE, this.onSubtitleAvailable);
105
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_CHANGED, this.onSubtitleChanged);
105
106
  // fix for iOS
106
107
  const video = this.core.activePlayback.el;
107
108
  assert(video, 'video element is required');
@@ -116,20 +117,50 @@ export class Subtitles extends UICorePlugin {
116
117
  }
117
118
  });
118
119
  }
119
- getTracks() {
120
- if (this.core.activePlayback) {
121
- try {
122
- const tracks = this.core.activePlayback.el
123
- .textTracks;
124
- if (tracks.length > 0) {
125
- this.setTracks(tracks);
126
- }
120
+ onSubtitleAvailable() {
121
+ trace(`${T} onSubtitleAvailable`);
122
+ this.applyTracks();
123
+ }
124
+ onSubtitleChanged({ id }) {
125
+ trace(`${T} onSubtitleChanged`, { id });
126
+ if (id === -1) {
127
+ this.clearSubtitleText();
128
+ }
129
+ for (const track of this.tracks) {
130
+ if (track.id === id) {
131
+ track.track.mode = 'showing';
132
+ this.setSubtitleText(this.getSubtitleText(track.track));
133
+ track.track.oncuechange = (e) => {
134
+ try {
135
+ if (track.track.activeCues?.length) {
136
+ const html = track.track.activeCues[0].getCueAsHTML();
137
+ this.setSubtitleText(html);
138
+ }
139
+ else {
140
+ this.clearSubtitleText();
141
+ }
142
+ }
143
+ catch (error) {
144
+ reportError(error);
145
+ }
146
+ };
127
147
  }
128
- catch (error) {
129
- reportError(error);
148
+ else {
149
+ track.track.oncuechange = null;
150
+ track.track.mode = 'hidden';
130
151
  }
131
152
  }
132
153
  }
154
+ applyTracks() {
155
+ try {
156
+ this.tracks = this.core.activePlayback.closedCaptionsTracks;
157
+ this.applyPreselectedSubtitles();
158
+ this.render();
159
+ }
160
+ catch (error) {
161
+ reportError(error);
162
+ }
163
+ }
133
164
  onStartAd() {
134
165
  if (this.isShowing && this.core.activeContainer) {
135
166
  this.hide();
@@ -141,10 +172,11 @@ export class Subtitles extends UICorePlugin {
141
172
  this.stopListening(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
142
173
  }
143
174
  playerResize() {
175
+ trace(`${T} playerResize`);
144
176
  const shouldShow = this.core.activeContainer &&
145
177
  isFullscreen(this.core.activeContainer.el) &&
146
- this.currentLevel &&
147
- this.currentLevel.mode &&
178
+ this.track &&
179
+ this.track.track.mode &&
148
180
  Browser.isiOS &&
149
181
  this.isShowing;
150
182
  if (shouldShow) {
@@ -166,7 +198,7 @@ export class Subtitles extends UICorePlugin {
166
198
  this.$string.hide();
167
199
  if (this.tracks) {
168
200
  for (const t of this.tracks) {
169
- t.mode = 'hidden';
201
+ t.track.mode = 'hidden';
170
202
  }
171
203
  }
172
204
  }
@@ -178,23 +210,20 @@ export class Subtitles extends UICorePlugin {
178
210
  this.renderIcon();
179
211
  if (this.core.activeContainer &&
180
212
  isFullscreen(this.core.activeContainer.el) &&
181
- this.currentLevel &&
182
- this.currentLevel.mode &&
213
+ this.track &&
214
+ this.track.track.mode &&
183
215
  Browser.isiOS) {
184
216
  this.$string.hide();
185
- this.currentLevel.mode = 'showing';
217
+ this.track.track.mode = 'showing';
186
218
  }
187
219
  else {
188
220
  this.$string.show();
189
221
  }
190
222
  }
191
223
  shouldRender() {
192
- return !!(this.tracks && this.tracks.length > 0);
224
+ return this.tracks.length > 0;
193
225
  }
194
226
  resizeFont() {
195
- if (!this.core.activeContainer) {
196
- return;
197
- }
198
227
  if (!this.$string) {
199
228
  return;
200
229
  }
@@ -211,133 +240,74 @@ export class Subtitles extends UICorePlugin {
211
240
  if (!this.shouldRender()) {
212
241
  return this;
213
242
  }
214
- trace(`${T} render`, {
215
- tracks: this.tracks?.length,
216
- track: this.track?.language,
217
- });
218
243
  const mediaControl = this.core.getPlugin('media_control');
219
- assert(mediaControl, 'media_control plugin is required');
220
244
  this.$el.html(Subtitles.template({ tracks: this.tracks }));
221
245
  this.core.activeContainer.$el.find('.subtitle-string').remove();
222
246
  this.$string = $(Subtitles.templateString());
223
247
  this.resizeFont();
224
- this.core.activeContainer.$el.append(this.$string[0]);
225
- const ss = mediaControl.getElement('subtitlesSelector');
226
- if (ss && ss.length > 0) {
227
- ss.append(this.el);
228
- }
229
- else {
230
- mediaControl.getRightPanel().append(this.el);
231
- }
232
- this.updateCurrentLevel(this.track);
233
- this.highlightCurrentSubtitles();
234
- this.applyPreselectedSubtitles();
248
+ this.core.activeContainer.$el.append(this.$string);
249
+ mediaControl.putElement('subtitlesSelector', this.$el);
250
+ this.updateSelection();
235
251
  this.renderIcon();
236
252
  return this;
237
253
  }
238
- setTracks(tracks) {
239
- this.tracks = tracks;
240
- this.render();
254
+ findById(id) {
255
+ return this.tracks.find((track) => track.id === id) ?? null;
241
256
  }
242
- findLevelBy(id) {
243
- if (this.tracks) {
244
- for (const track of this.tracks) {
245
- if (track.language === id) {
246
- return track; // TODO TrackInfo?
247
- }
248
- }
249
- }
250
- }
251
- selectLevel(id) {
257
+ selectItem(item) {
252
258
  this.clearSubtitleText();
253
- this.track = this.findLevelBy(id) || { ...NO_TRACK };
254
- this.hideSelectLevelMenu();
255
- if (!this.track) {
256
- this.track = { language: 'off' };
257
- }
258
- this.updateCurrentLevel(this.track);
259
- }
260
- onLevelSelect(event) {
261
- const id = event.target.dataset.subtitlesSelect;
262
- if (id) {
263
- localStorage.setItem(LOCAL_STORAGE_SUBTITLES_ID, id);
264
- this.selectLevel(id);
265
- }
259
+ this.track = item;
260
+ this.hideMenu();
261
+ this.updateSelection();
262
+ }
263
+ onItemSelect(event) {
264
+ const id = event.target.dataset.subtitlesSelect ?? '-1';
265
+ trace(`${T} onItemSelect`, { id });
266
+ localStorage.setItem(LOCAL_STORAGE_SUBTITLES_ID, id);
267
+ this.selectItem(this.findById(Number(id)));
266
268
  return false;
267
269
  }
268
270
  applyPreselectedSubtitles() {
269
271
  if (!this.isPreselectedApplied) {
270
272
  this.isPreselectedApplied = true;
273
+ if (!this.preselectedLanguage) {
274
+ return;
275
+ }
271
276
  setTimeout(() => {
272
- this.selectLevel(this.preselectedLanguage);
273
- }, 300);
277
+ this.selectItem(this.tracks.find((t) => t.track.language === this.preselectedLanguage) ?? null);
278
+ }, 300); // TODO why delay?
274
279
  }
275
280
  }
276
- onShowLevelSelectMenu() {
277
- trace(`${T} onShowLevelSelectMenu`);
278
- this.toggleContextMenu();
279
- }
280
- hideSelectLevelMenu() {
281
+ hideMenu() {
281
282
  ;
282
283
  this.$('[data-subtitles] ul').hide();
283
284
  }
284
- toggleContextMenu() {
285
+ toggleMenu() {
286
+ ;
285
287
  this.$('[data-subtitles] ul').toggle();
286
288
  }
287
- buttonElement() {
288
- return this.$('[data-subtitles] button');
289
+ itemElement(id) {
290
+ return this.$(`ul li a[data-subtitles-select="${id}"]`).parent();
289
291
  }
290
- levelElement(id) {
291
- return this.$('[data-subtitles] ul a' + (id ? '[data-subtitles-select="' + id + '"]' : '')).parent();
292
- }
293
- startLevelSwitch() {
294
- this.buttonElement().addClass('changing');
295
- }
296
- stopLevelSwitch() {
297
- this.buttonElement().removeClass('changing');
292
+ allItemElements() {
293
+ return this.$('[data-subtitles] li');
298
294
  }
299
295
  selectSubtitles() {
300
- if (!this.currentLevel) {
301
- return;
302
- }
303
- if (this.tracks) {
304
- for (let i = 0; i < this.tracks.length; i++) {
305
- const track = this.tracks[i];
306
- if (track.language === this.currentLevel.language) {
307
- track.mode = 'showing';
308
- const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
309
- const cues = track.cues;
310
- let subtitleText = '';
311
- if (cues && cues.length) {
312
- for (const cue of cues) {
313
- if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
314
- subtitleText +=
315
- cue.getCueAsHTML().textContent + '\n';
316
- }
317
- }
318
- }
319
- this.setSubtitleText(subtitleText);
320
- track.oncuechange = (e) => {
321
- try {
322
- if (track.activeCues?.length) {
323
- const html = track.activeCues[0].getCueAsHTML();
324
- this.setSubtitleText(html);
325
- }
326
- else {
327
- this.clearSubtitleText();
328
- }
329
- }
330
- catch (error) {
331
- // console.error(error);
332
- reportError(error);
333
- }
334
- };
335
- continue;
296
+ const trackId = this.track ? this.track.id : -1;
297
+ this.core.activePlayback.closedCaptionsTrackId = trackId;
298
+ }
299
+ getSubtitleText(track) {
300
+ const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
301
+ const cues = track.cues;
302
+ const lines = [];
303
+ if (cues && cues.length) {
304
+ for (const cue of cues) {
305
+ if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
306
+ lines.push(cue.getCueAsHTML().textContent);
336
307
  }
337
- this.tracks[i].oncuechange = null;
338
- this.tracks[i].mode = 'hidden';
339
308
  }
340
309
  }
310
+ return lines.join('\n');
341
311
  }
342
312
  setSubtitleText(text) {
343
313
  this.$string.find('p').html(text);
@@ -345,9 +315,8 @@ export class Subtitles extends UICorePlugin {
345
315
  clearSubtitleText() {
346
316
  this.setSubtitleText('');
347
317
  }
348
- updateCurrentLevel(track) {
349
- this.currentLevel = track;
350
- if (track.language === 'off') {
318
+ updateSelection() {
319
+ if (!this.track) {
351
320
  this.hide();
352
321
  }
353
322
  else {
@@ -357,20 +326,21 @@ export class Subtitles extends UICorePlugin {
357
326
  this.highlightCurrentSubtitles();
358
327
  }
359
328
  highlightCurrentSubtitles() {
360
- this.levelElement().removeClass('current');
361
- this.levelElement().find('a').removeClass('gcore-skin-active');
362
- if (this.currentLevel) {
363
- const currentLevelElement = this.levelElement(this.currentLevel.language);
364
- currentLevelElement.addClass('current');
365
- currentLevelElement.find('a').addClass('gcore-skin-active');
366
- }
329
+ this.allItemElements()
330
+ .removeClass('current')
331
+ .find('a')
332
+ .removeClass('gcore-skin-active');
333
+ trace(`${T} highlightCurrentSubtitles`, {
334
+ track: this.track?.id,
335
+ });
336
+ const currentLevelElement = this.itemElement(this.track ? this.track.id : -1);
337
+ currentLevelElement
338
+ .addClass('current')
339
+ .find('a')
340
+ .addClass('gcore-skin-active');
367
341
  }
368
342
  renderIcon() {
369
343
  const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
370
- this.core
371
- .getPlugin('media_control')
372
- .getElement('subtitlesSelector')
373
- ?.find('span.subtitle-text')
374
- .html(icon);
344
+ this.$el.find('span.subtitle-text').html(icon);
375
345
  }
376
346
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.21.1",
3
+ "version": "2.21.3",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -7,6 +7,10 @@ import { PlaybackErrorCode } from '../playback.types.js'
7
7
  * @internal
8
8
  */
9
9
  export class BasePlayback extends HTML5Video {
10
+ get isHTML5Video() {
11
+ return true
12
+ }
13
+
10
14
  createError(errorData: any, options?: ErrorOptions) {
11
15
  const i18n =
12
16
  this.i18n ||
@@ -130,3 +130,9 @@ export interface PlaybackError {
130
130
  icon?: string
131
131
  }
132
132
  }
133
+
134
+ export interface TextTrackItem {
135
+ id: number
136
+ name: string
137
+ track: TextTrack
138
+ }
@@ -22,6 +22,8 @@ const T = 'plugins.bottom_gear';
22
22
  */
23
23
  export type GearItemElement = 'quality' | 'rate' | 'nerd';
24
24
 
25
+ // TODO disabled if no items added
26
+
25
27
  /**
26
28
  * `PLUGIN` that adds the gear button with an extra options menu on the right side of the {@link MediaControl | media control} UI
27
29
  * @beta
@@ -30,7 +32,7 @@ export type GearItemElement = 'quality' | 'rate' | 'nerd';
30
32
  *
31
33
  * Depends on:
32
34
  *
33
- * - {@link MediaControl | media_control}
35
+ * - {@link MediaControl}
34
36
  */
35
37
  export class BottomGear extends UICorePlugin {
36
38
  private isHd = false;