@gcorevideo/player 2.21.1 → 2.21.4

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 (97) 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/media-control/container.scss +1 -1
  5. package/assets/media-control/media-control.ejs +1 -11
  6. package/assets/media-control/media-control.scss +49 -57
  7. package/assets/media-control/width270.scss +1 -1
  8. package/assets/media-control/width370.scss +7 -9
  9. package/assets/playback-rate/button.ejs +2 -2
  10. package/assets/playback-rate/list.ejs +4 -4
  11. package/assets/subtitles/combobox.ejs +10 -12
  12. package/assets/subtitles/string.ejs +1 -1
  13. package/assets/subtitles/style.scss +9 -16
  14. package/dist/core.js +5 -1
  15. package/dist/index.css +782 -794
  16. package/dist/index.js +240 -244
  17. package/dist/player.d.ts +141 -119
  18. package/dist/plugins/index.css +862 -874
  19. package/dist/plugins/index.js +222 -238
  20. package/docs/api/player.bottomgear.getelement.md +2 -2
  21. package/docs/api/player.bottomgear.md +1 -1
  22. package/docs/api/{player.subtitles.hide.md → player.closedcaptions.hide.md} +2 -2
  23. package/docs/api/{player.subtitles.md → player.closedcaptions.md} +11 -11
  24. package/docs/api/{player.subtitles.show.md → player.closedcaptions.show.md} +2 -2
  25. package/docs/api/player.closedcaptionspluginsettings.md +13 -0
  26. package/docs/api/player.gearitemelement.md +6 -4
  27. package/docs/api/player.gearoptionsitem.md +16 -0
  28. package/docs/api/player.md +48 -12
  29. package/docs/api/player.mediacontrol.putelement.md +2 -2
  30. package/docs/api/player.mediacontrolelement.md +1 -1
  31. package/docs/api/player.playbackrate.md +1 -1
  32. package/docs/api/player.subtitlespluginsettings.md +18 -0
  33. package/docs/api/player.texttrackitem.id.md +11 -0
  34. package/docs/api/player.texttrackitem.md +87 -0
  35. package/docs/api/player.texttrackitem.name.md +11 -0
  36. package/docs/api/player.texttrackitem.track.md +11 -0
  37. package/lib/index.d.ts +1 -1
  38. package/lib/index.js +1 -1
  39. package/lib/index.plugins.d.ts +2 -1
  40. package/lib/index.plugins.d.ts.map +1 -1
  41. package/lib/index.plugins.js +2 -1
  42. package/lib/playback/BasePlayback.d.ts +1 -0
  43. package/lib/playback/BasePlayback.d.ts.map +1 -1
  44. package/lib/playback/BasePlayback.js +3 -0
  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/playback.types.d.ts +5 -0
  48. package/lib/playback.types.d.ts.map +1 -1
  49. package/lib/plugins/audio-selector/AudioSelector.d.ts +2 -3
  50. package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
  51. package/lib/plugins/audio-selector/AudioSelector.js +6 -7
  52. package/lib/plugins/bottom-gear/BottomGear.d.ts +7 -3
  53. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  54. package/lib/plugins/bottom-gear/BottomGear.js +4 -2
  55. package/lib/plugins/media-control/MediaControl.d.ts +5 -6
  56. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  57. package/lib/plugins/media-control/MediaControl.js +48 -39
  58. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts +1 -0
  59. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
  60. package/lib/plugins/picture-in-picture/PictureInPicture.js +4 -4
  61. package/lib/plugins/playback-rate/PlaybackRate.d.ts +1 -1
  62. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  63. package/lib/plugins/playback-rate/PlaybackRate.js +24 -14
  64. package/lib/plugins/subtitles/ClosedCaptions.d.ts +118 -0
  65. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -0
  66. package/lib/plugins/subtitles/ClosedCaptions.js +348 -0
  67. package/lib/plugins/subtitles/Subtitles.d.ts +31 -26
  68. package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
  69. package/lib/plugins/subtitles/Subtitles.js +138 -169
  70. package/lib/testUtils.d.ts +22 -18
  71. package/lib/testUtils.d.ts.map +1 -1
  72. package/lib/testUtils.js +22 -36
  73. package/package.json +1 -1
  74. package/src/index.plugins.ts +2 -1
  75. package/src/index.ts +1 -1
  76. package/src/playback/BasePlayback.ts +4 -0
  77. package/src/playback/dash-playback/DashPlayback.ts +1 -0
  78. package/src/playback.types.ts +6 -0
  79. package/src/plugins/audio-selector/AudioSelector.ts +9 -8
  80. package/src/plugins/bottom-gear/BottomGear.ts +14 -5
  81. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -1
  82. package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +2 -2
  83. package/src/plugins/media-control/MediaControl.ts +84 -60
  84. package/src/plugins/media-control/__tests__/MediaControl.test.ts +43 -0
  85. package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +175 -0
  86. package/src/plugins/picture-in-picture/PictureInPicture.ts +5 -5
  87. package/src/plugins/playback-rate/PlaybackRate.ts +143 -100
  88. package/src/plugins/playback-rate/__tests__/PlaybackRate.test.ts +65 -0
  89. package/src/plugins/playback-rate/__tests__/__snapshots__/PlaybackRate.test.ts.snap +11 -0
  90. package/src/plugins/subtitles/ClosedCaptions.ts +469 -0
  91. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +58 -0
  92. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +25 -0
  93. package/src/testUtils.ts +22 -36
  94. package/temp/player.api.json +269 -89
  95. package/tsconfig.tsbuildinfo +1 -1
  96. package/src/plugins/index.ts +0 -39
  97. package/src/plugins/subtitles/Subtitles.ts +0 -496
@@ -43,6 +43,8 @@ export class PictureInPicture extends UICorePlugin {
43
43
  return VERSION;
44
44
  }
45
45
 
46
+ private static buttonTemplate = template(buttonHtml);
47
+
46
48
  /**
47
49
  * @internal
48
50
  */
@@ -71,8 +73,8 @@ export class PictureInPicture extends UICorePlugin {
71
73
 
72
74
  private isPiPSupported() {
73
75
  trace(`${T} isPiPSupported`, {
74
- pictureInPictureEnabled: document.pictureInPictureEnabled,
75
- requestPictureInPicture: HTMLVideoElement.prototype.requestPictureInPicture,
76
+ pictureInPictureEnabled: !!document.pictureInPictureEnabled,
77
+ requestPictureInPicture: !!HTMLVideoElement.prototype.requestPictureInPicture,
76
78
  });
77
79
 
78
80
  return document.pictureInPictureEnabled && !!HTMLVideoElement.prototype.requestPictureInPicture;
@@ -86,9 +88,7 @@ export class PictureInPicture extends UICorePlugin {
86
88
  return this;
87
89
  }
88
90
 
89
- const t = template(buttonHtml);
90
-
91
- this.$el.html(t({ pipIcon }));
91
+ this.$el.html(PictureInPicture.buttonTemplate({ pipIcon }));
92
92
 
93
93
  const mediaControl = this.core.getPlugin('media_control');
94
94
  if (mediaControl) {
@@ -1,23 +1,26 @@
1
- import { Events, UICorePlugin, Playback, template, Core } from '@clappr/core';
2
- import { trace } from '@gcorevideo/utils';
3
- import assert from 'assert';
4
-
5
- import { CLAPPR_VERSION } from '../../build.js';
6
- import type { ZeptoResult } from '../../types.js';
7
-
8
- import buttonHtml from '../../../assets/playback-rate/button.ejs';
9
- import listHtml from '../../../assets/playback-rate/list.ejs';
10
- import speedIcon from '../../../assets/icons/new/speed.svg';
11
- import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg';
12
- import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg';
13
- import checkIcon from '../../../assets/icons/new/check.svg';
14
- import { BottomGear } from '../bottom-gear/BottomGear.js';
15
- import { PlaybackEvents } from '../../playback/types.js';
16
- import { MediaControl, MediaControlEvents } from '../media-control/MediaControl.js';
1
+ import { Events, UICorePlugin, Playback, template, Core } from '@clappr/core'
2
+ import { trace } from '@gcorevideo/utils'
3
+ import assert from 'assert'
4
+
5
+ import { CLAPPR_VERSION } from '../../build.js'
6
+ import type { ZeptoResult } from '../../types.js'
7
+
8
+ import buttonHtml from '../../../assets/playback-rate/button.ejs'
9
+ import listHtml from '../../../assets/playback-rate/list.ejs'
10
+ import speedIcon from '../../../assets/icons/new/speed.svg'
11
+ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg'
12
+ import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg'
13
+ import checkIcon from '../../../assets/icons/new/check.svg'
14
+ import { BottomGear } from '../bottom-gear/BottomGear.js'
15
+ import { PlaybackEvents } from '../../playback/types.js'
16
+ import {
17
+ MediaControl,
18
+ MediaControlEvents,
19
+ } from '../media-control/MediaControl.js'
17
20
 
18
21
  type PlaybackRateOption = {
19
- value: string;
20
- label: string;
22
+ value: string
23
+ label: string
21
24
  }
22
25
 
23
26
  const DEFAULT_PLAYBACK_RATES = [
@@ -27,12 +30,12 @@ const DEFAULT_PLAYBACK_RATES = [
27
30
  { value: '1.25', label: '1.25x' },
28
31
  { value: '1.5', label: '1.5x' },
29
32
  { value: '1.75', label: '1.75x' },
30
- { value: '2.0', label: '2x' }
31
- ];
33
+ { value: '2.0', label: '2x' },
34
+ ]
32
35
 
33
- const DEFAULT_PLAYBACK_RATE = '1.0';
36
+ const DEFAULT_PLAYBACK_RATE = '1.0'
34
37
 
35
- const T = 'plugins.playback_rate';
38
+ const T = 'plugins.playback_rate'
36
39
 
37
40
  /**
38
41
  * `PLUGIN` that allows changing the playback speed of the video.
@@ -46,39 +49,42 @@ const T = 'plugins.playback_rate';
46
49
  * - {@link BottomGear | bottom_gear}
47
50
  *
48
51
  * It renders a button in the gear menu, which opens a dropdown with the options to change the playback rate.
52
+ * Note that the playback rate change is supported only for VOD or DVR enabled live streams.
49
53
  */
50
54
  export class PlaybackRate extends UICorePlugin {
51
- private playbackRates: PlaybackRateOption[] = DEFAULT_PLAYBACK_RATES;
55
+ private playbackRates: PlaybackRateOption[] = DEFAULT_PLAYBACK_RATES
52
56
 
53
57
  // Saved when an ad starts to restore after it finishes
54
- private prevSelectedRate: string | undefined;
58
+ private prevSelectedRate: string | undefined
55
59
 
56
- private rendered = false;
60
+ private rendered = false
57
61
 
58
- private selectedRate: string = DEFAULT_PLAYBACK_RATE;
62
+ private selectedRate: string = DEFAULT_PLAYBACK_RATE
59
63
 
60
64
  /**
61
65
  * @internal
62
66
  */
63
67
  get name() {
64
- return 'playback_rate';
68
+ return 'playback_rate'
65
69
  }
66
70
 
67
71
  /**
68
72
  * @internal
69
73
  */
70
74
  get supportedVersion() {
71
- return { min: CLAPPR_VERSION };
75
+ return { min: CLAPPR_VERSION }
72
76
  }
73
77
 
74
- private static readonly buttonTemplate = template(buttonHtml);
78
+ private static readonly buttonTemplate = template(buttonHtml)
75
79
 
76
- private static readonly listTemplate = template(listHtml);
80
+ private static readonly listTemplate = template(listHtml)
77
81
 
78
82
  constructor(core: Core) {
79
- super(core);
80
- this.playbackRates = core.options.playbackRate?.options || DEFAULT_PLAYBACK_RATES;
81
- this.selectedRate = core.options.playbackRate?.defaultValue || DEFAULT_PLAYBACK_RATE;
83
+ super(core)
84
+ this.playbackRates =
85
+ core.options.playbackRate?.options || DEFAULT_PLAYBACK_RATES
86
+ this.selectedRate =
87
+ core.options.playbackRate?.defaultValue || DEFAULT_PLAYBACK_RATE
82
88
  }
83
89
 
84
90
  /**
@@ -86,9 +92,8 @@ export class PlaybackRate extends UICorePlugin {
86
92
  */
87
93
  override get attributes() {
88
94
  return {
89
- 'class': this.name,
90
- 'data-playback-rate-select': ''
91
- };
95
+ class: 'media-control-playbackrate',
96
+ }
92
97
  }
93
98
 
94
99
  /**
@@ -99,38 +104,56 @@ export class PlaybackRate extends UICorePlugin {
99
104
  'click .gear-sub-menu_btn': 'onRateSelect',
100
105
  'click .gear-option': 'onShowMenu',
101
106
  'click .go-back': 'goBack',
102
- };
107
+ }
103
108
  }
104
109
 
105
110
  /**
106
111
  * @internal
107
112
  */
108
113
  override bindEvents() {
109
- this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
110
- this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
114
+ this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
115
+ this.listenTo(
116
+ this.core,
117
+ Events.CORE_ACTIVE_CONTAINER_CHANGED,
118
+ this.onActiveContainerChange,
119
+ )
111
120
  }
112
121
 
113
122
  private onCoreReady() {
114
- const mediaControl = this.core.getPlugin('media_control');
115
- assert(mediaControl, 'media_control plugin is required');
116
- const gear = this.core.getPlugin('bottom_gear') as BottomGear;
117
- assert(gear, 'bottom_gear plugin is required');
118
- this.listenTo(mediaControl, MediaControlEvents.MEDIACONTROL_GEAR_RENDERED, this.onGearRendered);
123
+ trace(`${T} onCoreReady`)
124
+ const mediaControl = this.core.getPlugin('media_control')
125
+ assert(mediaControl, 'media_control plugin is required')
126
+ const gear = this.core.getPlugin('bottom_gear') as BottomGear
127
+ assert(gear, 'bottom_gear plugin is required')
128
+ this.listenTo(
129
+ mediaControl,
130
+ MediaControlEvents.MEDIACONTROL_GEAR_RENDERED,
131
+ this.onGearRendered,
132
+ )
119
133
  }
120
134
 
121
135
  private onActiveContainerChange() {
122
- this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop);
123
- this.listenTo(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onPlay);
124
- this.listenTo(this.core.activePlayback, PlaybackEvents.PLAYBACK_RATE_CHANGED, this.onPlaybackRateChange);
125
- this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.onDvrStateChanged);
136
+ trace(`${T} onActiveContainerChange`)
137
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop)
138
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onPlay)
139
+ this.listenTo(
140
+ this.core.activePlayback,
141
+ PlaybackEvents.PLAYBACK_RATE_CHANGED,
142
+ this.onPlaybackRateChange,
143
+ )
144
+ this.listenTo(
145
+ this.core.activeContainer,
146
+ Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
147
+ this.onDvrStateChanged,
148
+ )
126
149
  }
127
150
 
128
151
  private onGearRendered() {
129
152
  trace(`${T} onGearRendered`, {
130
153
  rendered: this.rendered,
131
- });
132
- this.rendered = false;
133
- this.render();
154
+ })
155
+ this.rendered = false
156
+ this.render()
134
157
  }
135
158
 
136
159
  private onDvrStateChanged(dvrEnabled: boolean) {
@@ -138,40 +161,45 @@ export class PlaybackRate extends UICorePlugin {
138
161
  dvrEnabled,
139
162
  })
140
163
  if (dvrEnabled) {
141
- this.render();
164
+ this.render()
142
165
  }
143
166
  }
144
167
 
145
168
  private allRateElements(): ZeptoResult {
146
- return this.$('ul.gear-sub-menu li');
169
+ return this.$('ul.gear-sub-menu li')
147
170
  }
148
171
 
149
- private rateElement(rate = "1"): ZeptoResult {
150
- return (this.$(`ul.gear-sub-menu a[data-rate="${rate}"]`) as ZeptoResult).parent();
172
+ private rateElement(rate = '1'): ZeptoResult {
173
+ return (
174
+ this.$(`ul.gear-sub-menu a[data-rate="${rate}"]`) as ZeptoResult
175
+ ).parent()
151
176
  }
152
177
 
153
178
  private onPlaybackRateChange(playbackRate: number) {
154
- const selectedRate = parseInt(this.selectedRate, 10);
179
+ const selectedRate = parseInt(this.selectedRate, 10)
155
180
  // TODO check it doesn't interfere with the DASH.js or HLS.js playback live catchup
156
181
  if (Math.abs(playbackRate - selectedRate) > 0.1) {
157
182
  trace(`${T} onPlaybackRateChange setting target rate`, {
158
183
  playbackRate,
159
184
  selectedRate,
160
185
  })
161
- this.core.activePlayback?.setPlaybackRate(selectedRate);
186
+ this.core.activePlayback?.setPlaybackRate(selectedRate)
162
187
  }
163
188
  }
164
189
 
165
190
  private shouldRender() {
166
- if (!this.core.activeContainer) {
167
- return false;
191
+ if (!this.core.activePlayback) {
192
+ return false
168
193
  }
169
194
 
170
- if (this.core.getPlaybackType() === Playback.LIVE && !this.core.activePlayback.dvrEnabled) {
171
- return false;
195
+ if (
196
+ this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
197
+ !this.core.activePlayback.dvrEnabled
198
+ ) {
199
+ return false
172
200
  }
173
201
 
174
- return 'setPlaybackRate' in this.core.activePlayback;
202
+ return 'setPlaybackRate' in this.core.activePlayback
175
203
  }
176
204
 
177
205
  /**
@@ -184,99 +212,114 @@ export class PlaybackRate extends UICorePlugin {
184
212
  })
185
213
 
186
214
  if (!this.shouldRender()) {
187
- return this;
215
+ return this
188
216
  }
189
217
 
190
218
  if (this.rendered) {
191
- return this;
219
+ return this
192
220
  }
193
221
 
194
222
  const button = PlaybackRate.buttonTemplate({
195
223
  title: this.getTitle(),
196
224
  speedIcon,
197
225
  arrowRightIcon,
198
- });
226
+ i18n: this.core.i18n,
227
+ })
199
228
 
200
- this.$el.html(button);
229
+ this.$el.html(button)
201
230
 
202
- (this.core.getPlugin('bottom_gear') as BottomGear)?.getElement('rate')?.html(this.el);
231
+ ;(this.core.getPlugin('bottom_gear') as BottomGear)
232
+ ?.getElement('rate')
233
+ ?.html(this.el)
203
234
 
204
- this.rendered = true;
235
+ this.rendered = true
205
236
 
206
- return this;
237
+ return this
207
238
  }
208
239
 
209
240
  private onStartAd() {
210
- this.prevSelectedRate = this.selectedRate;
211
- this.resetPlaybackRate();
212
- this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onFinishAd);
241
+ this.prevSelectedRate = this.selectedRate
242
+ this.resetPlaybackRate()
243
+ this.listenToOnce(
244
+ this.core.activePlayback,
245
+ Events.PLAYBACK_PLAY,
246
+ this.onFinishAd,
247
+ )
213
248
  }
214
249
 
215
250
  private onFinishAd() {
216
251
  if (this.prevSelectedRate) {
217
- this.setSelectedRate(this.prevSelectedRate);
252
+ this.setSelectedRate(this.prevSelectedRate)
218
253
  }
219
254
  }
220
255
 
221
256
  private onPlay() {
222
- if (this.core.getPlaybackType() === Playback.LIVE && !this.core.activePlayback.dvrEnabled) {
223
- this.resetPlaybackRate();
257
+ if (
258
+ this.core.getPlaybackType() === Playback.LIVE &&
259
+ !this.core.activePlayback.dvrEnabled
260
+ ) {
261
+ this.resetPlaybackRate()
224
262
  } else {
225
- this.setSelectedRate(this.selectedRate);
263
+ this.setSelectedRate(this.selectedRate)
226
264
  }
227
265
  }
228
266
 
229
267
  private resetPlaybackRate() {
230
- this.setSelectedRate(DEFAULT_PLAYBACK_RATE);
268
+ this.setSelectedRate(DEFAULT_PLAYBACK_RATE)
231
269
  }
232
270
 
233
- private onStop() {
234
- }
271
+ private onStop() {}
235
272
 
236
273
  private onRateSelect(event: MouseEvent) {
237
- event.stopPropagation();
238
- const rate = (event.currentTarget as HTMLElement).dataset.rate;
274
+ event.stopPropagation()
275
+ const rate = (event.currentTarget as HTMLElement).dataset.rate
239
276
  if (rate) {
240
- this.setSelectedRate(rate);
241
- this.highlightCurrentRate();
277
+ this.setSelectedRate(rate)
278
+ this.highlightCurrentRate()
242
279
  }
243
280
 
244
- return false;
281
+ return false
245
282
  }
246
283
 
247
284
  private onShowMenu() {
248
- this.$el.html(PlaybackRate.listTemplate({
249
- playbackRates: this.playbackRates,
250
- arrowLeftIcon,
251
- checkIcon,
252
- }));
253
- (this.core.getPlugin('bottom_gear') as BottomGear)?.setContent(this.el);
254
- this.highlightCurrentRate();
285
+ this.$el.html(
286
+ PlaybackRate.listTemplate({
287
+ playbackRates: this.playbackRates,
288
+ arrowLeftIcon,
289
+ checkIcon,
290
+ i18n: this.core.i18n,
291
+ }),
292
+ )
293
+ ;(this.core.getPlugin('bottom_gear') as BottomGear)?.setContent(this.el)
294
+ this.highlightCurrentRate()
255
295
  }
256
296
 
257
297
  private goBack() {
258
298
  setTimeout(() => {
259
299
  this.core.getPlugin('bottom_gear').refresh()
260
- }, 0);
300
+ }, 0)
261
301
  }
262
302
 
263
303
  private setSelectedRate(rate: string) {
264
304
  // Set <video playbackRate="..."
265
- this.core.activePlayback?.setPlaybackRate(rate);
266
- this.selectedRate = rate;
305
+ this.core.activePlayback?.setPlaybackRate(rate)
306
+ this.selectedRate = rate
267
307
  }
268
308
 
269
309
  private getTitle() {
270
- return this.playbackRates.find((r) => r.value === this.selectedRate)?.label || this.selectedRate;
310
+ return (
311
+ this.playbackRates.find((r) => r.value === this.selectedRate)?.label ||
312
+ this.selectedRate
313
+ )
271
314
  }
272
315
 
273
316
  private highlightCurrentRate() {
274
- this.allRateElements().removeClass('current');
275
- this.allRateElements().find('a').removeClass('gcore-skin-active');
317
+ this.allRateElements().removeClass('current')
318
+ this.allRateElements().find('a').removeClass('gcore-skin-active')
276
319
 
277
- const currentLevelElement = this.rateElement(this.selectedRate);
320
+ const currentLevelElement = this.rateElement(this.selectedRate)
278
321
 
279
- currentLevelElement.addClass('current');
280
- currentLevelElement.find('a').addClass('gcore-skin-active');
322
+ currentLevelElement.addClass('current')
323
+ currentLevelElement.find('a').addClass('gcore-skin-active')
281
324
  }
282
325
  }
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest'
2
+ import { PlaybackRate } from '../PlaybackRate'
3
+ import {
4
+ createMockCore,
5
+ createMockMediaControl,
6
+ createMockPlugin,
7
+ } from '../../../testUtils'
8
+ import { $ } from '@clappr/core'
9
+ import { Logger, LogTracer, setTracer } from '@gcorevideo/utils'
10
+
11
+ Logger.enable('*')
12
+ setTracer(new LogTracer('PlaybackRate.test'))
13
+
14
+ describe('PlaybackRate', () => {
15
+ let core: any
16
+ let bottomGear: any
17
+ beforeEach(() => {
18
+ core = createMockCore()
19
+ const mediaControl = createMockMediaControl(core)
20
+ bottomGear = createMockGearPlugin()
21
+ core.getPlugin.mockImplementation((name: string) => {
22
+ if (name === 'bottom_gear') {
23
+ return bottomGear
24
+ }
25
+ if (name === 'media_control') {
26
+ return mediaControl
27
+ }
28
+ return null
29
+ })
30
+ })
31
+ it('should render', () => {
32
+ const playbackRate = new PlaybackRate(core)
33
+ core.emit('core:ready')
34
+ core.activePlayback.getPlaybackType.mockReturnValue('live')
35
+ core.emit('core:active:container:changed')
36
+ core.activePlayback.dvrEnabled = true
37
+ core.activeContainer.emit('container:dvr', true)
38
+ expect(playbackRate.el.innerHTML).toMatchSnapshot()
39
+ expect(bottomGear.getElement).toHaveBeenCalledWith('rate')
40
+ expect(
41
+ bottomGear.$el
42
+ .find('[data-rate]')
43
+ .text()
44
+ .replace(/\/assets.*\.svg/g, '')
45
+ .replace(/\s+/g, ' ')
46
+ .trim(),
47
+ ).toEqual('playback_rate 1x')
48
+ })
49
+ })
50
+
51
+ function createMockGearPlugin() {
52
+ const elements = {
53
+ nerd: $(document.createElement('li')).attr('data-nerd', 'nerd'),
54
+ quality: $(document.createElement('li')).attr('data-quality', 'quality'),
55
+ rate: $(document.createElement('li')).attr('data-rate', 'rate'),
56
+ }
57
+ const $el = $(document.createElement('ul'))
58
+ $el.append(elements.nerd, elements.quality, elements.rate)
59
+ const plugin = Object.assign(createMockPlugin(), {
60
+ setContent: vi.fn(),
61
+ getElement: vi.fn((name: string) => elements[name]),
62
+ $el,
63
+ })
64
+ return plugin
65
+ }
@@ -0,0 +1,11 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`PlaybackRate > should render 1`] = `
4
+ "<button class="gplayer-lite-btn gcore-skin-text-color gear-option" id="playback-rate-button">
5
+ <span class="gear-option_speed-icon">/assets/icons/new/speed.svg</span>
6
+ <span class="gear-option_label">playback_rate</span>
7
+ <span class="gear-option_arrow-right-icon">/assets/icons/new/arrow-right.svg</span>
8
+ <span class="gear-option_value">1x</span>
9
+ </button>
10
+ "
11
+ `;