@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
@@ -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;;;;;;;;;;;;;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"}
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,CAAA;AAuC7E;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,aAAa,CAA+C;IAGpE,OAAO,CAAC,gBAAgB,CAAoB;IAE5C,OAAO,CAAC,QAAQ,CAAQ;IAExB,OAAO,CAAC,YAAY,CAAgC;IAEpD;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAqB;gBAE7C,IAAI,EAAE,IAAI;IAQtB;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;;MAMlB;IAED;;OAEG;IACM,UAAU;IASnB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,YAAY;IAepB;;OAEG;IACM,MAAM;IAgCf,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,oBAAoB;CAS7B"}
@@ -9,7 +9,7 @@ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg';
9
9
  import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg';
10
10
  import checkIcon from '../../../assets/icons/new/check.svg';
11
11
  import { PlaybackEvents } from '../../playback/types.js';
12
- import { MediaControlEvents } from '../media-control/MediaControl.js';
12
+ import { MediaControlEvents, } from '../media-control/MediaControl.js';
13
13
  const DEFAULT_PLAYBACK_RATES = [
14
14
  { value: '0.5', label: '0.5x' },
15
15
  { value: '0.75', label: '0.75x' },
@@ -17,7 +17,7 @@ const DEFAULT_PLAYBACK_RATES = [
17
17
  { value: '1.25', label: '1.25x' },
18
18
  { value: '1.5', label: '1.5x' },
19
19
  { value: '1.75', label: '1.75x' },
20
- { value: '2.0', label: '2x' }
20
+ { value: '2.0', label: '2x' },
21
21
  ];
22
22
  const DEFAULT_PLAYBACK_RATE = '1.0';
23
23
  const T = 'plugins.playback_rate';
@@ -57,16 +57,17 @@ export class PlaybackRate extends UICorePlugin {
57
57
  static listTemplate = template(listHtml);
58
58
  constructor(core) {
59
59
  super(core);
60
- this.playbackRates = core.options.playbackRate?.options || DEFAULT_PLAYBACK_RATES;
61
- this.selectedRate = core.options.playbackRate?.defaultValue || DEFAULT_PLAYBACK_RATE;
60
+ this.playbackRates =
61
+ core.options.playbackRate?.options || DEFAULT_PLAYBACK_RATES;
62
+ this.selectedRate =
63
+ core.options.playbackRate?.defaultValue || DEFAULT_PLAYBACK_RATE;
62
64
  }
63
65
  /**
64
66
  * @internal
65
67
  */
66
68
  get attributes() {
67
69
  return {
68
- 'class': this.name,
69
- 'data-playback-rate-select': ''
70
+ class: 'media-control-playbackrate',
70
71
  };
71
72
  }
72
73
  /**
@@ -87,6 +88,7 @@ export class PlaybackRate extends UICorePlugin {
87
88
  this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
88
89
  }
89
90
  onCoreReady() {
91
+ trace(`${T} onCoreReady`);
90
92
  const mediaControl = this.core.getPlugin('media_control');
91
93
  assert(mediaControl, 'media_control plugin is required');
92
94
  const gear = this.core.getPlugin('bottom_gear');
@@ -94,6 +96,7 @@ export class PlaybackRate extends UICorePlugin {
94
96
  this.listenTo(mediaControl, MediaControlEvents.MEDIACONTROL_GEAR_RENDERED, this.onGearRendered);
95
97
  }
96
98
  onActiveContainerChange() {
99
+ trace(`${T} onActiveContainerChange`);
97
100
  this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop);
98
101
  this.listenTo(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onPlay);
99
102
  this.listenTo(this.core.activePlayback, PlaybackEvents.PLAYBACK_RATE_CHANGED, this.onPlaybackRateChange);
@@ -117,7 +120,7 @@ export class PlaybackRate extends UICorePlugin {
117
120
  allRateElements() {
118
121
  return this.$('ul.gear-sub-menu li');
119
122
  }
120
- rateElement(rate = "1") {
123
+ rateElement(rate = '1') {
121
124
  return this.$(`ul.gear-sub-menu a[data-rate="${rate}"]`).parent();
122
125
  }
123
126
  onPlaybackRateChange(playbackRate) {
@@ -132,10 +135,11 @@ export class PlaybackRate extends UICorePlugin {
132
135
  }
133
136
  }
134
137
  shouldRender() {
135
- if (!this.core.activeContainer) {
138
+ if (!this.core.activePlayback) {
136
139
  return false;
137
140
  }
138
- if (this.core.getPlaybackType() === Playback.LIVE && !this.core.activePlayback.dvrEnabled) {
141
+ if (this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
142
+ !this.core.activePlayback.dvrEnabled) {
139
143
  return false;
140
144
  }
141
145
  return 'setPlaybackRate' in this.core.activePlayback;
@@ -158,9 +162,12 @@ export class PlaybackRate extends UICorePlugin {
158
162
  title: this.getTitle(),
159
163
  speedIcon,
160
164
  arrowRightIcon,
165
+ i18n: this.core.i18n,
161
166
  });
162
167
  this.$el.html(button);
163
- this.core.getPlugin('bottom_gear')?.getElement('rate')?.html(this.el);
168
+ this.core.getPlugin('bottom_gear')
169
+ ?.getElement('rate')
170
+ ?.html(this.el);
164
171
  this.rendered = true;
165
172
  return this;
166
173
  }
@@ -175,7 +182,8 @@ export class PlaybackRate extends UICorePlugin {
175
182
  }
176
183
  }
177
184
  onPlay() {
178
- if (this.core.getPlaybackType() === Playback.LIVE && !this.core.activePlayback.dvrEnabled) {
185
+ if (this.core.getPlaybackType() === Playback.LIVE &&
186
+ !this.core.activePlayback.dvrEnabled) {
179
187
  this.resetPlaybackRate();
180
188
  }
181
189
  else {
@@ -185,8 +193,7 @@ export class PlaybackRate extends UICorePlugin {
185
193
  resetPlaybackRate() {
186
194
  this.setSelectedRate(DEFAULT_PLAYBACK_RATE);
187
195
  }
188
- onStop() {
189
- }
196
+ onStop() { }
190
197
  onRateSelect(event) {
191
198
  event.stopPropagation();
192
199
  const rate = event.currentTarget.dataset.rate;
@@ -201,6 +208,7 @@ export class PlaybackRate extends UICorePlugin {
201
208
  playbackRates: this.playbackRates,
202
209
  arrowLeftIcon,
203
210
  checkIcon,
211
+ i18n: this.core.i18n,
204
212
  }));
205
213
  this.core.getPlugin('bottom_gear')?.setContent(this.el);
206
214
  this.highlightCurrentRate();
@@ -216,7 +224,8 @@ export class PlaybackRate extends UICorePlugin {
216
224
  this.selectedRate = rate;
217
225
  }
218
226
  getTitle() {
219
- return this.playbackRates.find((r) => r.value === this.selectedRate)?.label || this.selectedRate;
227
+ return (this.playbackRates.find((r) => r.value === this.selectedRate)?.label ||
228
+ this.selectedRate);
220
229
  }
221
230
  highlightCurrentRate() {
222
231
  this.allRateElements().removeClass('current');
@@ -0,0 +1,118 @@
1
+ import { UICorePlugin } from '@clappr/core';
2
+ import '../../../assets/subtitles/style.scss';
3
+ export type ClosedCaptionsPluginSettings = {
4
+ /**
5
+ * Initially selected subtitles language
6
+ */
7
+ language?: string;
8
+ };
9
+ /**
10
+ * @deprecated Use {@link ClosedCaptionsPluginSettings} instead.
11
+ */
12
+ export type SubtitlesPluginSettings = ClosedCaptionsPluginSettings;
13
+ /**
14
+ * `PLUGIN` that provides a UI to select the subtitles when available.
15
+ * @beta
16
+ *
17
+ * @remarks
18
+ * The plugin is activated when closed captions tracks are provided with the media source.
19
+ * It shows a familiar "CC" button with a dropdown menu to select the subtitles language.
20
+ *
21
+ * Depends on:
22
+ *
23
+ * - {@link MediaControl}
24
+ *
25
+ * Configuration options - {@link ClosedCaptionsPluginSettings}
26
+ * @example
27
+ * ```ts
28
+ * import { ClosedCaptions } from '@gcorevideo/player'
29
+ *
30
+ * Player.registerPlugin(ClosedCaptions)
31
+ *
32
+ * new Player({
33
+ * ...
34
+ * cc: {
35
+ * language: 'en',
36
+ * },
37
+ * })
38
+ * ```
39
+ */
40
+ export declare class ClosedCaptions extends UICorePlugin {
41
+ private isPreselectedApplied;
42
+ private isShowing;
43
+ private track;
44
+ private tracks;
45
+ private $line;
46
+ /**
47
+ * @internal
48
+ */
49
+ get name(): string;
50
+ /**
51
+ * @internal
52
+ */
53
+ get supportedVersion(): {
54
+ min: string;
55
+ };
56
+ /**
57
+ * @internal
58
+ */
59
+ static get version(): string;
60
+ private static readonly template;
61
+ private static readonly templateString;
62
+ /**
63
+ * @internal
64
+ */
65
+ get attributes(): {
66
+ class: string;
67
+ };
68
+ /**
69
+ * @internal
70
+ */
71
+ get events(): {
72
+ 'click [data-cc-select]': string;
73
+ 'click [data-cc-button]': string;
74
+ };
75
+ private get preselectedLanguage();
76
+ /**
77
+ * @internal
78
+ */
79
+ bindEvents(): void;
80
+ private onCoreReady;
81
+ private onContainerChanged;
82
+ private onSubtitleAvailable;
83
+ private onSubtitleChanged;
84
+ private applyTracks;
85
+ private onStartAd;
86
+ private onFinishAd;
87
+ private playerResize;
88
+ /**
89
+ * Hides the subtitles menu and the subtitles.
90
+ */
91
+ hide(): void;
92
+ /**
93
+ * Shows the subtitles menu and the subtitles.
94
+ */
95
+ show(): void;
96
+ private shouldRender;
97
+ private resizeFont;
98
+ /**
99
+ * @internal
100
+ */
101
+ render(): this;
102
+ private findById;
103
+ private selectItem;
104
+ private onItemSelect;
105
+ private applyPreselectedSubtitles;
106
+ private hideMenu;
107
+ private toggleMenu;
108
+ private itemElement;
109
+ private allItemElements;
110
+ private selectSubtitles;
111
+ private getSubtitleText;
112
+ private setSubtitleText;
113
+ private clearSubtitleText;
114
+ private updateSelection;
115
+ private highlightCurrentSubtitles;
116
+ private renderIcon;
117
+ }
118
+ //# sourceMappingURL=ClosedCaptions.d.ts.map
@@ -0,0 +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;AAe7C,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,oBAAoB,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAAQ;IAEzB,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,QAAQ,CAAyB;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D;;OAEG;IACH,IAAa,UAAU;;MAItB;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;IAKlB,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"}
@@ -0,0 +1,348 @@
1
+ import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core';
2
+ import { reportError, trace } from '@gcorevideo/utils';
3
+ import assert from 'assert';
4
+ import { CLAPPR_VERSION } from '../../build.js';
5
+ import '../../../assets/subtitles/style.scss';
6
+ import subtitlesOffIcon from '../../../assets/icons/new/subtitles-off.svg';
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';
10
+ import { isFullscreen } from '../utils.js';
11
+ const VERSION = '2.19.14';
12
+ const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
13
+ const T = 'plugins.cc';
14
+ /**
15
+ * `PLUGIN` that provides a UI to select the subtitles when available.
16
+ * @beta
17
+ *
18
+ * @remarks
19
+ * The plugin is activated when closed captions tracks are provided with the media source.
20
+ * It shows a familiar "CC" button with a dropdown menu to select the subtitles language.
21
+ *
22
+ * Depends on:
23
+ *
24
+ * - {@link MediaControl}
25
+ *
26
+ * Configuration options - {@link ClosedCaptionsPluginSettings}
27
+ * @example
28
+ * ```ts
29
+ * import { ClosedCaptions } from '@gcorevideo/player'
30
+ *
31
+ * Player.registerPlugin(ClosedCaptions)
32
+ *
33
+ * new Player({
34
+ * ...
35
+ * cc: {
36
+ * language: 'en',
37
+ * },
38
+ * })
39
+ * ```
40
+ */
41
+ export class ClosedCaptions extends UICorePlugin {
42
+ isPreselectedApplied = false;
43
+ isShowing = false;
44
+ track = null;
45
+ tracks = [];
46
+ $line = null;
47
+ /**
48
+ * @internal
49
+ */
50
+ get name() {
51
+ return 'cc';
52
+ }
53
+ /**
54
+ * @internal
55
+ */
56
+ get supportedVersion() {
57
+ return { min: CLAPPR_VERSION };
58
+ }
59
+ /**
60
+ * @internal
61
+ */
62
+ static get version() {
63
+ return VERSION;
64
+ }
65
+ static template = template(comboboxHTML);
66
+ static templateString = template(stringHTML);
67
+ /**
68
+ * @internal
69
+ */
70
+ get attributes() {
71
+ return {
72
+ class: 'media-control-cc',
73
+ };
74
+ }
75
+ /**
76
+ * @internal
77
+ */
78
+ get events() {
79
+ return {
80
+ 'click [data-cc-select]': 'onItemSelect',
81
+ 'click [data-cc-button]': 'toggleMenu',
82
+ };
83
+ }
84
+ get preselectedLanguage() {
85
+ return this.core.options.cc?.language ?? this.core.options.subtitles?.language ?? '';
86
+ }
87
+ /**
88
+ * @internal
89
+ */
90
+ bindEvents() {
91
+ this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
92
+ this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
93
+ this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onContainerChanged);
94
+ }
95
+ onCoreReady() {
96
+ trace(`${T} onCoreReady`);
97
+ const mediaControl = this.core.getPlugin('media_control');
98
+ assert(mediaControl, 'media_control plugin is required');
99
+ this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
100
+ this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu);
101
+ }
102
+ onContainerChanged() {
103
+ trace(`${T} onContainerChanged`);
104
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_FULLSCREEN, this.playerResize);
105
+ this.listenTo(this.core.activeContainer, 'container:advertisement:start', this.onStartAd);
106
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_AVAILABLE, this.onSubtitleAvailable);
107
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_CHANGED, this.onSubtitleChanged);
108
+ // fix for iOS
109
+ const video = this.core.activePlayback.el;
110
+ assert(video, 'video element is required');
111
+ video.addEventListener('webkitbeginfullscreen', () => {
112
+ if (Browser.isiOS) {
113
+ video.classList.add('ios-fullscreen');
114
+ }
115
+ });
116
+ video.addEventListener('webkitendfullscreen', () => {
117
+ if (Browser.isiOS) {
118
+ video.classList.remove('ios-fullscreen');
119
+ }
120
+ });
121
+ }
122
+ onSubtitleAvailable() {
123
+ trace(`${T} onSubtitleAvailable`);
124
+ this.applyTracks();
125
+ }
126
+ onSubtitleChanged({ id }) {
127
+ trace(`${T} onSubtitleChanged`, { id });
128
+ if (id === -1) {
129
+ this.clearSubtitleText();
130
+ }
131
+ for (const track of this.tracks) {
132
+ if (track.id === id) {
133
+ track.track.mode = 'showing';
134
+ this.setSubtitleText(this.getSubtitleText(track.track));
135
+ track.track.oncuechange = (e) => {
136
+ try {
137
+ if (track.track.activeCues?.length) {
138
+ const html = track.track.activeCues[0].getCueAsHTML();
139
+ this.setSubtitleText(html);
140
+ }
141
+ else {
142
+ this.clearSubtitleText();
143
+ }
144
+ }
145
+ catch (error) {
146
+ reportError(error);
147
+ }
148
+ };
149
+ }
150
+ else {
151
+ track.track.oncuechange = null;
152
+ track.track.mode = 'hidden';
153
+ }
154
+ }
155
+ }
156
+ applyTracks() {
157
+ try {
158
+ this.tracks = this.core.activePlayback.closedCaptionsTracks;
159
+ this.applyPreselectedSubtitles();
160
+ this.render();
161
+ }
162
+ catch (error) {
163
+ reportError(error);
164
+ }
165
+ }
166
+ onStartAd() {
167
+ if (this.isShowing && this.core.activeContainer) {
168
+ this.hide();
169
+ this.listenTo(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
170
+ }
171
+ }
172
+ onFinishAd() {
173
+ this.show();
174
+ this.stopListening(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
175
+ }
176
+ playerResize() {
177
+ trace(`${T} playerResize`);
178
+ const shouldShow = this.core.activeContainer &&
179
+ isFullscreen(this.core.activeContainer.el) &&
180
+ this.track &&
181
+ this.track.track.mode &&
182
+ Browser.isiOS &&
183
+ this.isShowing;
184
+ if (shouldShow) {
185
+ this.show();
186
+ }
187
+ try {
188
+ this.resizeFont();
189
+ }
190
+ catch (error) {
191
+ reportError(error);
192
+ }
193
+ }
194
+ /**
195
+ * Hides the subtitles menu and the subtitles.
196
+ */
197
+ hide() {
198
+ this.isShowing = false;
199
+ this.renderIcon();
200
+ this.$line.hide();
201
+ if (this.tracks) {
202
+ for (const t of this.tracks) {
203
+ t.track.mode = 'hidden';
204
+ }
205
+ }
206
+ }
207
+ /**
208
+ * Shows the subtitles menu and the subtitles.
209
+ */
210
+ show() {
211
+ this.isShowing = true;
212
+ this.renderIcon();
213
+ if (this.core.activeContainer &&
214
+ isFullscreen(this.core.activeContainer.el) &&
215
+ this.track &&
216
+ this.track.track.mode &&
217
+ Browser.isiOS) {
218
+ this.$line.hide();
219
+ this.track.track.mode = 'showing';
220
+ }
221
+ else {
222
+ this.$line.show();
223
+ }
224
+ }
225
+ shouldRender() {
226
+ return this.tracks?.length > 0;
227
+ }
228
+ resizeFont() {
229
+ if (!this.$line) {
230
+ return;
231
+ }
232
+ const skinWidth = this.core.activeContainer.$el.width();
233
+ this.$line.find('p').css('font-size', skinWidth * 0.03);
234
+ }
235
+ /**
236
+ * @internal
237
+ */
238
+ render() {
239
+ if (!this.core.activeContainer) {
240
+ return this;
241
+ }
242
+ if (!this.shouldRender()) {
243
+ return this;
244
+ }
245
+ const mediaControl = this.core.getPlugin('media_control');
246
+ this.$el.html(ClosedCaptions.template({ tracks: this.tracks }));
247
+ this.core.activeContainer.$el.find('#cc-line').remove();
248
+ this.$line = $(ClosedCaptions.templateString());
249
+ this.resizeFont();
250
+ this.core.activeContainer.$el.append(this.$line);
251
+ mediaControl.putElement('cc', this.el);
252
+ this.updateSelection();
253
+ this.renderIcon();
254
+ return this;
255
+ }
256
+ findById(id) {
257
+ return this.tracks.find((track) => track.id === id) ?? null;
258
+ }
259
+ selectItem(item) {
260
+ this.clearSubtitleText();
261
+ this.track = item;
262
+ this.hideMenu();
263
+ this.updateSelection();
264
+ }
265
+ onItemSelect(event) {
266
+ const id = event.target.dataset.ccSelect ?? '-1';
267
+ trace(`${T} onItemSelect`, { id });
268
+ localStorage.setItem(LOCAL_STORAGE_CC_ID, id);
269
+ this.selectItem(this.findById(Number(id)));
270
+ return false;
271
+ }
272
+ applyPreselectedSubtitles() {
273
+ if (!this.isPreselectedApplied) {
274
+ this.isPreselectedApplied = true;
275
+ if (!this.preselectedLanguage) {
276
+ return;
277
+ }
278
+ setTimeout(() => {
279
+ this.selectItem(this.tracks.find((t) => t.track.language === this.preselectedLanguage) ?? null);
280
+ }, 300); // TODO why delay?
281
+ }
282
+ }
283
+ hideMenu() {
284
+ ;
285
+ this.$('[data-cc] ul').hide();
286
+ }
287
+ toggleMenu() {
288
+ trace(`${T} toggleMenu`);
289
+ this.$('[data-cc] ul').toggle();
290
+ }
291
+ itemElement(id) {
292
+ return this.$(`ul li a[data-cc-select="${id}"]`).parent();
293
+ }
294
+ allItemElements() {
295
+ return this.$('[data-cc] li');
296
+ }
297
+ selectSubtitles() {
298
+ const trackId = this.track ? this.track.id : -1;
299
+ this.core.activePlayback.closedCaptionsTrackId = trackId;
300
+ }
301
+ getSubtitleText(track) {
302
+ const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
303
+ const cues = track.cues;
304
+ const lines = [];
305
+ if (cues && cues.length) {
306
+ for (const cue of cues) {
307
+ if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
308
+ lines.push(cue.getCueAsHTML().textContent);
309
+ }
310
+ }
311
+ }
312
+ return lines.join('\n');
313
+ }
314
+ setSubtitleText(text) {
315
+ this.$line.find('p').html(text);
316
+ }
317
+ clearSubtitleText() {
318
+ this.setSubtitleText('');
319
+ }
320
+ updateSelection() {
321
+ if (!this.track) {
322
+ this.hide();
323
+ }
324
+ else {
325
+ this.show();
326
+ }
327
+ this.selectSubtitles();
328
+ this.highlightCurrentSubtitles();
329
+ }
330
+ highlightCurrentSubtitles() {
331
+ this.allItemElements()
332
+ .removeClass('current')
333
+ .find('a')
334
+ .removeClass('gcore-skin-active');
335
+ trace(`${T} highlightCurrentSubtitles`, {
336
+ track: this.track?.id,
337
+ });
338
+ const currentLevelElement = this.itemElement(this.track ? this.track.id : -1);
339
+ currentLevelElement
340
+ .addClass('current')
341
+ .find('a')
342
+ .addClass('gcore-skin-active');
343
+ }
344
+ renderIcon() {
345
+ const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
346
+ this.$el.find('span.cc-text').html(icon);
347
+ }
348
+ }
@@ -1,11 +1,15 @@
1
1
  import { UICorePlugin } from '@clappr/core';
2
2
  import '../../../assets/subtitles/style.scss';
3
- export type SubtitlesPluginSettings = {
3
+ export type ClosedCaptionsPluginSettings = {
4
4
  /**
5
5
  * Initially selected subtitles language
6
6
  */
7
7
  language?: string;
8
8
  };
9
+ /**
10
+ * @deprecated Use {@link ClosedCaptionsPluginSettings} instead.
11
+ */
12
+ export type SubtitlesPluginSettings = ClosedCaptionsPluginSettings;
9
13
  /**
10
14
  * `PLUGIN` that provides a UI to select the subtitles when available.
11
15
  * @beta
@@ -15,16 +19,16 @@ export type SubtitlesPluginSettings = {
15
19
  *
16
20
  * - {@link MediaControl}
17
21
  *
18
- * Configuration options - {@link SubtitlesPluginSettings}
22
+ * Configuration options - {@link ClosedCaptionsPluginSettings}
19
23
  * @example
20
24
  * ```ts
21
- * import { Subtitles } from '@gcorevideo/player'
25
+ * import { ClosedCaptions } from '@gcorevideo/player'
22
26
  *
23
- * Player.registerPlugin(Subtitles)
27
+ * Player.registerPlugin(ClosedCaptions)
24
28
  *
25
29
  * new Player({
26
30
  * ...
27
- * subtitles: {
31
+ * cc: {
28
32
  * language: 'en',
29
33
  * },
30
34
  * })
@@ -35,7 +39,7 @@ export declare class Subtitles extends UICorePlugin {
35
39
  private isShowing;
36
40
  private track;
37
41
  private tracks;
38
- private $string;
42
+ private $line;
39
43
  /**
40
44
  * @internal
41
45
  */
@@ -57,14 +61,13 @@ export declare class Subtitles extends UICorePlugin {
57
61
  */
58
62
  get attributes(): {
59
63
  class: string;
60
- 'data-subtitles': string;
61
64
  };
62
65
  /**
63
66
  * @internal
64
67
  */
65
68
  get events(): {
66
- 'click [data-subtitles-select]': string;
67
- 'click [data-subtitles-button]': string;
69
+ 'click [data-cc-select]': string;
70
+ 'click [data-cc-button]': string;
68
71
  };
69
72
  private get preselectedLanguage();
70
73
  /**
@@ -1 +1 @@
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
+ {"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,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;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,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,QAAQ,CAAyB;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D;;OAEG;IACH,IAAa,UAAU;;MAItB;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;IAKlB,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"}