@gcorevideo/player 2.22.3 → 2.22.5

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 (39) hide show
  1. package/assets/audio-selector/style.scss +4 -2
  2. package/assets/audio-selector/track-selector.ejs +2 -2
  3. package/assets/level-selector/button.ejs +1 -1
  4. package/assets/level-selector/list.ejs +10 -4
  5. package/assets/level-selector/style.scss +8 -3
  6. package/dist/core.js +1 -1
  7. package/dist/index.css +1435 -1429
  8. package/dist/index.js +402 -419
  9. package/dist/plugins/index.css +1192 -1186
  10. package/dist/plugins/index.js +428 -438
  11. package/lib/index.plugins.d.ts +3 -1
  12. package/lib/index.plugins.d.ts.map +1 -1
  13. package/lib/index.plugins.js +3 -1
  14. package/lib/plugins/audio-selector/AudioSelector.d.ts +3 -9
  15. package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
  16. package/lib/plugins/audio-selector/AudioSelector.js +34 -57
  17. package/lib/plugins/level-selector/LevelSelector.d.ts +6 -5
  18. package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
  19. package/lib/plugins/level-selector/LevelSelector.js +11 -8
  20. package/lib/plugins/level-selector/QualityLevels.d.ts +112 -0
  21. package/lib/plugins/level-selector/QualityLevels.d.ts.map +1 -0
  22. package/lib/plugins/level-selector/QualityLevels.js +280 -0
  23. package/lib/plugins/vast-ads/VastAds.d.ts +1 -0
  24. package/lib/plugins/vast-ads/VastAds.d.ts.map +1 -1
  25. package/lib/plugins/vast-ads/VastAds.js +6 -3
  26. package/lib/testUtils.d.ts +2 -0
  27. package/lib/testUtils.d.ts.map +1 -1
  28. package/lib/testUtils.js +2 -0
  29. package/package.json +1 -1
  30. package/src/index.plugins.ts +3 -1
  31. package/src/plugins/audio-selector/AudioSelector.ts +36 -72
  32. package/src/plugins/audio-selector/__tests__/AudioSelector.test.ts +176 -0
  33. package/src/plugins/audio-selector/__tests__/__snapshots__/AudioSelector.test.ts.snap +67 -0
  34. package/src/plugins/level-selector/{LevelSelector.ts → QualityLevels.ts} +19 -13
  35. package/src/plugins/level-selector/__tests__/{LevelSelector.test.ts → QualityLevels.test.ts} +20 -6
  36. package/src/plugins/level-selector/__tests__/__snapshots__/{LevelSelector.test.ts.snap → QualityLevels.test.ts.snap} +58 -25
  37. package/src/plugins/vast-ads/VastAds.ts +8 -4
  38. package/src/testUtils.ts +2 -0
  39. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,280 @@
1
+ import { Events, template, UICorePlugin } from '@clappr/core';
2
+ import { trace } from '@gcorevideo/utils';
3
+ import assert from 'assert';
4
+ import { CLAPPR_VERSION } from '../../build.js';
5
+ import { GearEvents } from '../bottom-gear/BottomGear.js';
6
+ import buttonHtml from '../../../assets/level-selector/button.ejs';
7
+ import listHtml from '../../../assets/level-selector/list.ejs';
8
+ import hdIcon from '../../../assets/icons/new/hd.svg';
9
+ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg';
10
+ import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg';
11
+ import checkIcon from '../../../assets/icons/new/check.svg';
12
+ import '../../../assets/level-selector/style.scss';
13
+ const T = 'plugins.quality_levels';
14
+ const VERSION = 'v2.22.5';
15
+ /**
16
+ * `PLUGIN` that provides a UI to select the desired quality level of the playback.
17
+ * @beta
18
+ *
19
+ * @remarks
20
+ * Depends on:
21
+ *
22
+ * - {@link MediaControl}
23
+ *
24
+ * - {@link BottomGear}
25
+ *
26
+ * The plugin is rendered as an item in the gear menu, which, when clicked, shows a list of quality levels to choose from.
27
+ *
28
+ * Configuration options - {@link QualityLevelsPluginSettings}
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * new Player({
33
+ * qualityLevels: {
34
+ * restrictResolution: 360,
35
+ * labels: { 360: 'SD', 720: 'HD' },
36
+ * },
37
+ * })
38
+ * ```
39
+ */
40
+ export class QualityLevels extends UICorePlugin {
41
+ levels = [];
42
+ levelLabels = [];
43
+ removeAuto = false;
44
+ isHd = false;
45
+ currentText = '';
46
+ selectedLevelId = -1;
47
+ static buttonTemplate = template(buttonHtml);
48
+ static listTemplate = template(listHtml);
49
+ /**
50
+ * @internal
51
+ */
52
+ get name() {
53
+ return 'level_selector';
54
+ }
55
+ /**
56
+ * @internal
57
+ */
58
+ get supportedVersion() {
59
+ return { min: CLAPPR_VERSION };
60
+ }
61
+ /**
62
+ * @internal
63
+ */
64
+ static get version() {
65
+ return VERSION;
66
+ }
67
+ /**
68
+ * @internal
69
+ */
70
+ get attributes() {
71
+ return {
72
+ class: 'level-selector',
73
+ 'data-level-selector': '',
74
+ };
75
+ }
76
+ get events() {
77
+ return {
78
+ 'click .gear-sub-menu_btn': 'onSelect',
79
+ 'click .go-back': 'goBack',
80
+ };
81
+ }
82
+ /**
83
+ * @internal
84
+ */
85
+ bindEvents() {
86
+ this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady);
87
+ this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
88
+ }
89
+ onCoreReady() {
90
+ trace(`${T} onCoreReady`);
91
+ const gear = this.core.getPlugin('bottom_gear');
92
+ assert(gear, 'bottom_gear plugin is required');
93
+ this.currentText = this.core.i18n.t('auto');
94
+ this.listenTo(gear, GearEvents.RENDERED, this.onGearRendered);
95
+ }
96
+ onGearRendered() {
97
+ trace(`${T} onGearRendered`);
98
+ this.render();
99
+ }
100
+ onActiveContainerChange() {
101
+ this.removeAuto = false;
102
+ this.isHd = false;
103
+ const activePlayback = this.core.activePlayback;
104
+ this.listenTo(activePlayback, Events.PLAYBACK_LEVELS_AVAILABLE, this.onLevelsAvailable);
105
+ this.listenTo(activePlayback, Events.PLAYBACK_LEVEL_SWITCH_START, this.onLevelSwitchStart);
106
+ this.listenTo(activePlayback, Events.PLAYBACK_LEVEL_SWITCH_END, this.onLevelSwitchEnd);
107
+ this.listenTo(activePlayback, Events.PLAYBACK_BITRATE, this.onBitrate);
108
+ this.listenTo(activePlayback, Events.PLAYBACK_STOP, this.onStop);
109
+ this.listenTo(activePlayback, Events.PLAYBACK_HIGHDEFINITIONUPDATE, (isHd) => {
110
+ this.isHd = isHd;
111
+ this.updateHd();
112
+ });
113
+ if (activePlayback.levels?.length > 0) {
114
+ this.onLevelsAvailable(activePlayback.levels);
115
+ }
116
+ }
117
+ updateHd() {
118
+ if (this.isHd) {
119
+ this.$el.find('.gear-option_hd-icon').removeClass('hidden');
120
+ }
121
+ else {
122
+ this.$el.find('.gear-option_hd-icon').addClass('hidden');
123
+ }
124
+ }
125
+ onStop() {
126
+ trace(`${T} onStop`);
127
+ this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, () => {
128
+ if (this.core.activePlayback.getPlaybackType() === 'live') {
129
+ if (this.selectedLevelId !== -1) {
130
+ this.core.activePlayback.currentLevel = this.selectedLevelId;
131
+ }
132
+ }
133
+ });
134
+ }
135
+ shouldRender() {
136
+ const activePlayback = this.core.activePlayback;
137
+ if (!activePlayback) {
138
+ return false;
139
+ }
140
+ const supportsCurrentLevel = 'currentLevel' in activePlayback;
141
+ if (!supportsCurrentLevel) {
142
+ return false;
143
+ }
144
+ // Only care if we have at least 2 to choose from
145
+ return !!(this.levels && this.levels.length > 1);
146
+ }
147
+ /**
148
+ * @internal
149
+ */
150
+ render() {
151
+ if (!this.shouldRender()) {
152
+ return this;
153
+ }
154
+ this.renderDropdown();
155
+ this.updateButton();
156
+ return this;
157
+ }
158
+ renderDropdown() {
159
+ this.$el.html(QualityLevels.listTemplate({
160
+ arrowLeftIcon,
161
+ checkIcon,
162
+ current: this.selectedLevelId,
163
+ labels: this.levelLabels,
164
+ levels: this.levels,
165
+ maxLevel: this.maxLevel,
166
+ removeAuto: this.removeAuto,
167
+ i18n: this.core.i18n,
168
+ }));
169
+ }
170
+ updateButton() {
171
+ ;
172
+ this.core.getPlugin('bottom_gear')
173
+ ?.addItem('quality', this.$el)
174
+ .html(QualityLevels.buttonTemplate({
175
+ arrowRightIcon,
176
+ currentText: this.currentText,
177
+ isHd: this.isHd,
178
+ hdIcon,
179
+ i18n: this.core.i18n,
180
+ }));
181
+ }
182
+ get pluginOptions() {
183
+ return (this.core.options.qualityLevels || this.core.options.levelSelector || {});
184
+ }
185
+ get maxLevel() {
186
+ const maxRes = this.pluginOptions.restrictResolution;
187
+ return maxRes
188
+ ? this.levels.find((level) => (level.height > level.width ? level.width : level.height) ===
189
+ maxRes)?.level ?? -1
190
+ : -1;
191
+ }
192
+ onLevelsAvailable(levels) {
193
+ const maxResolution = this.pluginOptions.restrictResolution;
194
+ this.levels = levels;
195
+ this.makeLevelsLabels();
196
+ if (maxResolution) {
197
+ this.removeAuto = true;
198
+ const initialLevel = levels
199
+ .filter((level) => (level.width > level.height ? level.height : level.width) <=
200
+ maxResolution)
201
+ .pop();
202
+ this.setLevel(initialLevel?.level ?? 0);
203
+ }
204
+ this.render();
205
+ }
206
+ makeLevelsLabels() {
207
+ const labels = this.pluginOptions.labels ?? {};
208
+ this.levelLabels = [];
209
+ for (const level of this.levels) {
210
+ const ll = level.width > level.height ? level.height : level.width;
211
+ const label = labels[ll] || `${ll}p`;
212
+ this.levelLabels.push(label);
213
+ }
214
+ }
215
+ onSelect(event) {
216
+ const selectedLevel = parseInt(event.currentTarget?.dataset?.id ?? '-1', 10);
217
+ this.setLevel(selectedLevel);
218
+ event.stopPropagation();
219
+ event.preventDefault();
220
+ return false;
221
+ }
222
+ goBack() {
223
+ trace(`${T} goBack`);
224
+ this.core.getPlugin('bottom_gear').refresh();
225
+ }
226
+ setLevel(index) {
227
+ this.selectedLevelId = index;
228
+ this.core.activePlayback.currentLevel = this.selectedLevelId;
229
+ this.highlightCurrentLevel();
230
+ }
231
+ allLevelElements() {
232
+ return this.$('#level-selector-menu li');
233
+ }
234
+ levelElement(id = -1) {
235
+ return this.$(`#level-selector-menu a[data-id="${id}"]`).parent();
236
+ }
237
+ onLevelSwitchStart() {
238
+ this.levelElement(this.selectedLevelId).addClass('changing');
239
+ }
240
+ onLevelSwitchEnd() {
241
+ this.levelElement(this.selectedLevelId).removeClass('changing');
242
+ }
243
+ updateText(level) {
244
+ this.currentText = this.getLevelLabel(level);
245
+ this.updateButton();
246
+ }
247
+ getLevelLabel(id) {
248
+ if (id < 0) {
249
+ return this.core.i18n.t('auto');
250
+ }
251
+ const index = this.levels.findIndex((l) => l.level === id);
252
+ if (index < 0) {
253
+ return this.core.i18n.t('auto');
254
+ }
255
+ return this.levelLabels[index] ?? formatLevelLabel(this.levels[index]);
256
+ }
257
+ onBitrate(info) {
258
+ trace(`${T} updateCurrentLevel`, { info });
259
+ this.highlightCurrentLevel();
260
+ }
261
+ highlightCurrentLevel() {
262
+ trace(`${T} highlightCurrentLevel`, {
263
+ selectedLevelId: this.selectedLevelId,
264
+ });
265
+ this.allLevelElements()
266
+ .removeClass('current')
267
+ .find('a')
268
+ .removeClass('gcore-skin-active');
269
+ const currentLevelElement = this.levelElement(this.selectedLevelId);
270
+ currentLevelElement
271
+ .addClass('current')
272
+ .find('a')
273
+ .addClass('gcore-skin-active');
274
+ this.updateText(this.selectedLevelId);
275
+ }
276
+ }
277
+ function formatLevelLabel(level) {
278
+ const h = level.width > level.height ? level.height : level.width;
279
+ return `${h}p`;
280
+ }
@@ -52,6 +52,7 @@ export declare class VastAds extends UICorePlugin {
52
52
  private _validateData;
53
53
  private playerResize;
54
54
  private _stopPauserollListeners;
55
+ private get pluginOptions();
55
56
  private _pauserollListeners;
56
57
  unBindEvents(): void;
57
58
  private containerChanged;
@@ -1 +1 @@
1
- {"version":3,"file":"VastAds.d.ts","sourceRoot":"","sources":["../../../src/plugins/vast-ads/VastAds.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,IAAI,EAIJ,QAAQ,EAER,YAAY,EAEb,MAAM,cAAc,CAAA;AAarB,OAAO,qCAAqC,CAAA;AAQ5C,qBAAa,OAAQ,SAAQ,YAAY;IACvC,OAAO,CAAC,mBAAmB,CAAiC;IAE5D,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,oBAAoB,CAAwC;IAEpE,OAAO,CAAC,eAAe,CAAI;IAE3B,OAAO,CAAC,mBAAmB,CAAI;IAE/B,OAAO,CAAC,UAAU,CAAyB;IAE3C,OAAO,CAAC,SAAS,CAAyB;IAE1C,OAAO,CAAC,eAAe,CAA2B;IAElD,OAAO,CAAC,gBAAgB,CAAI;IAE5B,OAAO,CAAC,YAAY,CAAY;IAEhC,OAAO,CAAC,YAAY,CAAQ;IAE5B,OAAO,CAAC,cAAc,CAAQ;IAE9B,OAAO,CAAC,aAAa,CAAuB;IAE5C,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO,CAAC,cAAc,CAAQ;IAE9B,OAAO,CAAC,mBAAmB,CAA2B;IAEtD,OAAO,CAAC,aAAa,CAAiC;IAEtD,OAAO,CAAC,gBAAgB,CAAI;IAE5B,OAAO,CAAC,IAAI,CAA2B;IAEvC,OAAO,CAAC,OAAO,CAAK;IAEpB,OAAO,CAAC,uBAAuB,CAAI;IAEnC,OAAO,CAAC,0BAA0B,CAAI;IAEtC,OAAO,CAAC,YAAY,CAAoB;IAExC,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO,CAAC,SAAS,CAA2B;IAE5C,OAAO,CAAC,UAAU,CAA2B;IAE7C,OAAO,CAAC,aAAa,CAA2B;IAEhD,OAAO,CAAC,YAAY,CAA2B;IAE/C,IAAI,IAAI,WAEP;IAED,IAAI,gBAAgB;;MAEnB;IAED,MAAM,KAAK,OAAO,WAEjB;IAED,IAAI,YAAY,QAEf;IAED,IAAa,UAAU;;;MAKtB;gBAEW,IAAI,EAAE,IAAI;IAqEb,UAAU;IA8FnB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,oBAAoB;IAkE5B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,qBAAqB;IAwD7B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,uBAAuB;IAuC/B,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,mBAAmB;IAiD3B,YAAY;IASZ,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IA6BpB,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAG3B;IAED,IAAI,QAAQ,IAAI,QAAQ,GAAG,IAAI,CAE9B;IAED,OAAO,CAAC,kBAAkB;IAU1B,gBAAgB,CAAC,CAAC,EAAE,MAAM;IAQ1B,cAAc;IAsBd,eAAe;IAkBf,WAAW;IAiBX,OAAO,CAAC,UAAU;IA+ClB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,iBAAiB;IAiHhB,MAAM;IAqBf,OAAO,CAAC,QAAQ;CAGjB"}
1
+ {"version":3,"file":"VastAds.d.ts","sourceRoot":"","sources":["../../../src/plugins/vast-ads/VastAds.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,IAAI,EAIJ,QAAQ,EAER,YAAY,EAEb,MAAM,cAAc,CAAA;AAarB,OAAO,qCAAqC,CAAA;AAQ5C,qBAAa,OAAQ,SAAQ,YAAY;IACvC,OAAO,CAAC,mBAAmB,CAAiC;IAE5D,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,oBAAoB,CAAwC;IAEpE,OAAO,CAAC,eAAe,CAAI;IAE3B,OAAO,CAAC,mBAAmB,CAAI;IAE/B,OAAO,CAAC,UAAU,CAAyB;IAE3C,OAAO,CAAC,SAAS,CAAyB;IAE1C,OAAO,CAAC,eAAe,CAA2B;IAElD,OAAO,CAAC,gBAAgB,CAAI;IAE5B,OAAO,CAAC,YAAY,CAAY;IAEhC,OAAO,CAAC,YAAY,CAAQ;IAE5B,OAAO,CAAC,cAAc,CAAQ;IAE9B,OAAO,CAAC,aAAa,CAAuB;IAE5C,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO,CAAC,cAAc,CAAQ;IAE9B,OAAO,CAAC,mBAAmB,CAA2B;IAEtD,OAAO,CAAC,aAAa,CAAiC;IAEtD,OAAO,CAAC,gBAAgB,CAAI;IAE5B,OAAO,CAAC,IAAI,CAA2B;IAEvC,OAAO,CAAC,OAAO,CAAK;IAEpB,OAAO,CAAC,uBAAuB,CAAI;IAEnC,OAAO,CAAC,0BAA0B,CAAI;IAEtC,OAAO,CAAC,YAAY,CAAoB;IAExC,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO,CAAC,SAAS,CAA2B;IAE5C,OAAO,CAAC,UAAU,CAA2B;IAE7C,OAAO,CAAC,aAAa,CAA2B;IAEhD,OAAO,CAAC,YAAY,CAA2B;IAE/C,IAAI,IAAI,WAEP;IAED,IAAI,gBAAgB;;MAEnB;IAED,MAAM,KAAK,OAAO,WAEjB;IAED,IAAI,YAAY,QAEf;IAED,IAAa,UAAU;;;MAKtB;gBAEW,IAAI,EAAE,IAAI;IAqEb,UAAU;IA8FnB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,oBAAoB;IAkE5B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,qBAAqB;IAwD7B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,uBAAuB;IAuC/B,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,uBAAuB;IAO/B,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,mBAAmB;IAiD3B,YAAY;IASZ,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IA6BpB,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAG3B;IAED,IAAI,QAAQ,IAAI,QAAQ,GAAG,IAAI,CAE9B;IAED,OAAO,CAAC,kBAAkB;IAU1B,gBAAgB,CAAC,CAAC,EAAE,MAAM;IAQ1B,cAAc;IAsBd,eAAe;IAkBf,WAAW;IAiBX,OAAO,CAAC,UAAU;IA+ClB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,iBAAiB;IAiHhB,MAAM;IAqBf,OAAO,CAAC,QAAQ;CAGjB"}
@@ -345,8 +345,11 @@ export class VastAds extends UICorePlugin {
345
345
  // @ts-ignore
346
346
  this.stopListening(this.playback, Events.PLAYBACK_PAUSE);
347
347
  }
348
+ get pluginOptions() {
349
+ return this.options.vastAds;
350
+ }
348
351
  _pauserollListeners() {
349
- if (!this._validateData(this._options.VastAds.pauseroll)) {
352
+ if (!this._validateData(this.pluginOptions.pauseroll)) {
350
353
  return;
351
354
  }
352
355
  this._stopPauserollListeners();
@@ -571,11 +574,11 @@ export class VastAds extends UICorePlugin {
571
574
  // const currentRoll = type;
572
575
  this.destroyRoll();
573
576
  if (currentRoll === 'preroll') {
574
- this.options.vastAds[currentRoll] = [];
577
+ this.pluginOptions[currentRoll] = [];
575
578
  }
576
579
  this.currentState = '';
577
580
  this.$el.hide();
578
- if (!this.options.disableClickOnPause) {
581
+ if (!this.options.disableClickOnPause) { // TODO sort out
579
582
  this._clickToPausePlugin?.enable();
580
583
  }
581
584
  try {
@@ -91,6 +91,7 @@ export declare function createMockPlayback(name?: string): Events<string | symbo
91
91
  canAutoPlay: import("vitest").Mock<(...args: any[]) => any>;
92
92
  onResize: import("vitest").Mock<(...args: any[]) => any>;
93
93
  setPlaybackRate: import("vitest").Mock<(...args: any[]) => any>;
94
+ switchAudioTrack: import("vitest").Mock<(...args: any[]) => any>;
94
95
  trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
95
96
  };
96
97
  export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
@@ -105,6 +106,7 @@ export declare function createMockContainer(playback?: any): Events<string | sym
105
106
  isPlaying: import("vitest").Mock<(...args: any[]) => any>;
106
107
  play: import("vitest").Mock<(...args: any[]) => any>;
107
108
  seek: import("vitest").Mock<(...args: any[]) => any>;
109
+ switchAudioTrack: import("vitest").Mock<(...args: any[]) => any>;
108
110
  trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
109
111
  };
110
112
  export declare function createMockMediaControl(core: any): UICorePlugin;
@@ -1 +1 @@
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;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAY7C"}
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC/C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;;EAkBvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAiB/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAY7C"}
package/lib/testUtils.js CHANGED
@@ -124,6 +124,7 @@ export function createMockPlayback(name = 'mock') {
124
124
  canAutoPlay: vi.fn().mockImplementation(() => true),
125
125
  onResize: vi.fn().mockImplementation(() => true),
126
126
  setPlaybackRate: vi.fn(),
127
+ switchAudioTrack: vi.fn(),
127
128
  trigger: emitter.emit,
128
129
  });
129
130
  }
@@ -142,6 +143,7 @@ export function createMockContainer(playback = createMockPlayback()) {
142
143
  isPlaying: vi.fn().mockReturnValue(false),
143
144
  play: vi.fn(),
144
145
  seek: vi.fn(),
146
+ switchAudioTrack: vi.fn(),
145
147
  trigger: emitter.emit,
146
148
  });
147
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.22.3",
3
+ "version": "2.22.5",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,6 +1,7 @@
1
1
  import '../assets/style/main.scss';
2
2
 
3
3
  export * from "./plugins/audio-selector/AudioSelector.js";
4
+ export { AudioTracks as AudioSelector } from "./plugins/audio-selector/AudioSelector.js";
4
5
  export * from "./plugins/big-mute-button/BigMuteButton.js";
5
6
  export * from "./plugins/bottom-gear/BottomGear.js";
6
7
  export * from "./plugins/clappr-nerd-stats/ClapprNerdStats.js";
@@ -13,13 +14,14 @@ export * from "./plugins/error-screen/ErrorScreen.js";
13
14
  export * from "./plugins/favicon/Favicon.js";
14
15
  // _ ga-events
15
16
  export * from "./plugins/google-analytics/GoogleAnalytics.js";
16
- export * from "./plugins/level-selector/LevelSelector.js";
17
17
  export * from "./plugins/logo/Logo.js";
18
18
  export * from "./plugins/media-control/MediaControl.js";
19
19
  export * from "./plugins/multi-camera/MultiCamera.js";
20
20
  export * from "./plugins/picture-in-picture/PictureInPicture.js";
21
21
  export * from "./plugins/playback-rate/PlaybackRate.js";
22
22
  export * from "./plugins/poster/Poster.js";
23
+ export * from "./plugins/level-selector/QualityLevels.js";
24
+ export { QualityLevels as LevelSelector } from "./plugins/level-selector/QualityLevels.js";
23
25
  export * from "./plugins/seek-time/SeekTime.js";
24
26
  export * from "./plugins/share/Share.js";
25
27
  export * from "./plugins/skip-time/SkipTime.js";
@@ -1,6 +1,5 @@
1
1
  import { Events, UICorePlugin, template } from '@clappr/core'
2
2
  import { AudioTrack } from '@clappr/core/types/base/playback/playback.js'
3
- import { trace } from '@gcorevideo/utils'
4
3
  import assert from 'assert'
5
4
 
6
5
  import { CLAPPR_VERSION } from '../../build.js'
@@ -11,9 +10,9 @@ import audioArrow from '../../../assets/icons/old/quality-arrow.svg'
11
10
  import { ZeptoResult } from '../../types.js'
12
11
  import { MediaControl } from '../media-control/MediaControl.js'
13
12
 
14
- const VERSION: string = '0.0.1'
13
+ const VERSION: string = '2.22.4'
15
14
 
16
- const T = 'plugins.audio_selector'
15
+ // const T = 'plugins.audiotracks'
17
16
 
18
17
  /**
19
18
  * `PLUGIN` that makes possible to switch audio tracks via the media control UI.
@@ -25,7 +24,7 @@ const T = 'plugins.audio_selector'
25
24
  *
26
25
  * - {@link MediaControl}
27
26
  */
28
- export class AudioSelector extends UICorePlugin {
27
+ export class AudioTracks extends UICorePlugin {
29
28
  private currentTrack: AudioTrack | null = null
30
29
 
31
30
  private tracks: AudioTrack[] = []
@@ -34,7 +33,7 @@ export class AudioSelector extends UICorePlugin {
34
33
  * @internal
35
34
  */
36
35
  get name() {
37
- return 'audio_selector'
36
+ return 'audio_selector' // TODO rename to audiotracks
38
37
  }
39
38
 
40
39
  /**
@@ -59,7 +58,6 @@ export class AudioSelector extends UICorePlugin {
59
58
  override get attributes() {
60
59
  return {
61
60
  class: 'media-control-audiotracks',
62
-
63
61
  }
64
62
  }
65
63
 
@@ -69,7 +67,7 @@ export class AudioSelector extends UICorePlugin {
69
67
  override get events() {
70
68
  return {
71
69
  'click [data-audiotracks-select]': 'onTrackSelect',
72
- 'click [data-audiotracks-button]': 'onShowLevelSelectMenu',
70
+ 'click #audiotracks-button': 'toggleContextMenu',
73
71
  }
74
72
  }
75
73
 
@@ -77,7 +75,7 @@ export class AudioSelector extends UICorePlugin {
77
75
  * @internal
78
76
  */
79
77
  override bindEvents() {
80
- this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
78
+ this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady)
81
79
  this.listenTo(
82
80
  this.core,
83
81
  Events.CORE_ACTIVE_CONTAINER_CHANGED,
@@ -86,41 +84,30 @@ export class AudioSelector extends UICorePlugin {
86
84
  }
87
85
 
88
86
  private onCoreReady() {
89
- trace(`${T} onCoreReady`)
90
87
  const mediaControl = this.core.getPlugin('media_control')
91
88
  assert(mediaControl, 'media_control plugin is required')
92
- this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render)
93
- this.listenTo(
94
- mediaControl,
95
- Events.MEDIACONTROL_HIDE,
96
- this.hideSelectTrackMenu,
97
- )
89
+ this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, () => {
90
+ mediaControl.putElement('audiotracks', this.$el)
91
+ })
92
+ this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu)
98
93
  }
99
94
 
100
- private bindPlaybackEvents() {
101
- trace(`${T} bindPlaybackEvents`)
95
+ private onActiveContainerChanged() {
102
96
  this.currentTrack = null
103
- this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop)
104
- this.setupAudioTrackListeners()
105
- }
106
-
107
- private setupAudioTrackListeners() {
108
97
  this.listenTo(
109
- this.core.activePlayback,
110
- Events.PLAYBACK_AUDIO_AVAILABLE,
98
+ this.core.activeContainer,
99
+ Events.CONTAINER_AUDIO_AVAILABLE,
111
100
  (tracks: AudioTrack[]) => {
112
- trace(`${T} on PLAYBACK_AUDIO_AVAILABLE`, { audioTracks: tracks })
113
101
  this.currentTrack =
114
- tracks.find((track) => track.kind === 'main') ?? null
115
- this.fillTracks(tracks)
102
+ tracks.find((track) => track.kind === 'main') ?? null // TODO test
103
+ this.tracks = tracks
104
+ this.render()
116
105
  },
117
106
  )
118
-
119
107
  this.listenTo(
120
- this.core.activePlayback,
121
- Events.PLAYBACK_AUDIO_CHANGED,
108
+ this.core.activeContainer,
109
+ Events.CONTAINER_AUDIO_CHANGED,
122
110
  (track: AudioTrack) => {
123
- trace(`${T} PLAYBACK_AUDIO_CHANGED`, { audioTrack: track })
124
111
  this.currentTrack = track
125
112
  this.highlightCurrentTrack()
126
113
  this.buttonElement().removeClass('changing')
@@ -129,24 +116,10 @@ export class AudioSelector extends UICorePlugin {
129
116
  )
130
117
  }
131
118
 
132
- private onStop() {
133
- trace(`${T} onStop`)
134
- }
135
-
136
- private onActiveContainerChanged() {
137
- trace(`${T} onActiveContainerChanged`)
138
- this.bindPlaybackEvents()
139
- }
140
-
141
119
  private shouldRender() {
142
- if (!this.core.activePlayback) {
143
- return false
144
- }
145
-
146
- this.tracks = this.core.activePlayback.audioTracks
147
-
120
+ // Render is called from the parent class constructor so tracks aren't available
148
121
  // Only care if we have at least 2 to choose from
149
- return this.tracks && this.tracks.length > 1
122
+ return this.tracks?.length > 1
150
123
  }
151
124
 
152
125
  /**
@@ -159,52 +132,40 @@ export class AudioSelector extends UICorePlugin {
159
132
 
160
133
  const mediaControl = this.core.getPlugin('media_control') as MediaControl
161
134
  this.$el.html(
162
- AudioSelector.template({ tracks: this.tracks, title: this.getTitle() }),
135
+ AudioTracks.template({
136
+ tracks: this.tracks,
137
+ title: this.getTitle(),
138
+ icon: audioArrow,
139
+ }),
163
140
  )
164
- this.$('.audio-arrow').append(audioArrow)
165
- mediaControl.putElement('audiotracks', this.el)
166
-
167
141
  this.updateText()
168
142
  this.highlightCurrentTrack()
169
143
 
170
144
  return this
171
145
  }
172
146
 
173
- private fillTracks(tracks: AudioTrack[]) {
174
- this.tracks = tracks
175
- this.render()
176
- }
177
-
178
- private findTrackBy(id: string) {
179
- return this.tracks.find((track) => track.id === id)
180
- }
181
-
182
147
  private onTrackSelect(event: MouseEvent) {
183
148
  const id = (event.target as HTMLElement)?.dataset?.audiotracksSelect
184
149
  if (id) {
185
150
  this.selectAudioTrack(id)
186
151
  }
187
- this.toggleContextMenu()
152
+ this.hideMenu()
188
153
  event.stopPropagation()
189
154
  return false
190
155
  }
191
156
 
192
157
  private selectAudioTrack(id: string) {
193
158
  this.startTrackSwitch()
194
- this.core.activePlayback.switchAudioTrack(id)
159
+ this.core.activeContainer.switchAudioTrack(id)
195
160
  this.updateText()
196
161
  }
197
162
 
198
- private onShowLevelSelectMenu() {
199
- this.toggleContextMenu()
200
- }
201
-
202
- private hideSelectTrackMenu() {
203
- ;(this.$('ul') as ZeptoResult).hide()
163
+ private hideMenu() {
164
+ this.$el.find('#audiotracks-select').addClass('hidden')
204
165
  }
205
166
 
206
167
  private toggleContextMenu() {
207
- ;(this.$('ul') as ZeptoResult).toggle()
168
+ this.$el.find('#audiotracks-select').toggleClass('hidden')
208
169
  }
209
170
 
210
171
  private buttonElement(): ZeptoResult {
@@ -218,14 +179,17 @@ export class AudioSelector extends UICorePlugin {
218
179
  private trackElement(id?: string): ZeptoResult {
219
180
  return (
220
181
  this.$(
221
- 'ul a' +
222
- (id !== undefined ? '[data-audiotracks-select="' + id + '"]' : ''),
182
+ '#audiotracks-select a' +
183
+ (id !== undefined ? `[data-audiotracks-select="${id}"]` : ''),
223
184
  ) as ZeptoResult
224
185
  ).parent()
225
186
  }
226
187
 
227
188
  private getTitle(): string {
228
- return this.currentTrack?.label || ''
189
+ if (!this.currentTrack) {
190
+ return ''
191
+ }
192
+ return this.currentTrack.label || this.currentTrack.language
229
193
  }
230
194
 
231
195
  private startTrackSwitch() {