@gcorevideo/player 2.22.27 → 2.22.29

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 (34) hide show
  1. package/assets/media-control/media-control.scss +2 -6
  2. package/assets/seek-time/seek-time.html +2 -2
  3. package/assets/seek-time/seek-time.scss +4 -4
  4. package/dist/core.js +1 -1
  5. package/dist/index.css +1408 -1411
  6. package/dist/index.js +100 -135
  7. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts.map +1 -1
  8. package/lib/plugins/clappr-nerd-stats/NerdStats.js +3 -7
  9. package/lib/plugins/clappr-nerd-stats/speedtest/Speedtest.d.ts.map +1 -1
  10. package/lib/plugins/clappr-nerd-stats/speedtest/Speedtest.js +2 -3
  11. package/lib/plugins/clappr-nerd-stats/speedtest/index.d.ts.map +1 -1
  12. package/lib/plugins/clappr-nerd-stats/speedtest/index.js +1 -8
  13. package/lib/plugins/clappr-stats/ClapprStats.d.ts.map +1 -1
  14. package/lib/plugins/clappr-stats/ClapprStats.js +8 -2
  15. package/lib/plugins/media-control/MediaControl.d.ts +0 -1
  16. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  17. package/lib/plugins/media-control/MediaControl.js +9 -23
  18. package/lib/plugins/seek-time/SeekTime.d.ts +15 -6
  19. package/lib/plugins/seek-time/SeekTime.d.ts.map +1 -1
  20. package/lib/plugins/seek-time/SeekTime.js +17 -32
  21. package/lib/testUtils.d.ts +1 -0
  22. package/lib/testUtils.d.ts.map +1 -1
  23. package/lib/testUtils.js +1 -0
  24. package/package.json +1 -1
  25. package/src/plugins/clappr-nerd-stats/NerdStats.ts +3 -7
  26. package/src/plugins/clappr-nerd-stats/speedtest/Speedtest.ts +2 -3
  27. package/src/plugins/clappr-nerd-stats/speedtest/index.ts +1 -9
  28. package/src/plugins/clappr-stats/ClapprStats.ts +10 -4
  29. package/src/plugins/media-control/MediaControl.ts +14 -25
  30. package/src/plugins/media-control/__tests__/MediaControl.test.ts +16 -0
  31. package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +70 -0
  32. package/src/plugins/seek-time/SeekTime.ts +37 -50
  33. package/src/testUtils.ts +1 -0
  34. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,3 @@
1
- import { trace } from '@gcorevideo/utils';
2
1
  import { type Server, type TestStatusInfo, Speedtest } from './Speedtest.js';
3
2
  import { SpeedtestMetrics } from './types.js';
4
3
 
@@ -7,7 +6,7 @@ const DEFAULT_DOWNLOAD_SPEED = '0.00';
7
6
 
8
7
  const DRAW_SIZE = 5;
9
8
 
10
- const T = 'plugins.clappr_nerd_stats.speedtest';
9
+ // const T = 'plugins.clappr_nerd_stats.speedtest';
11
10
 
12
11
  function limitDigits(value: number): string {
13
12
  return value > DIGITS_THRESHOLD ? '> ' + DIGITS_THRESHOLD : value.toFixed(2);
@@ -38,7 +37,6 @@ const getColor = (speedValue: number): string => {
38
37
  };
39
38
 
40
39
  export function drawSpeedTestResults() {
41
- trace(`${T} drawSpeedTestResults`);
42
40
  const canvas = document.getElementById('nerd-stats-speed-test-canvas');
43
41
  if (!canvas) {
44
42
  return;
@@ -66,7 +64,6 @@ export const initSpeedTest = (customMetrics: SpeedtestMetrics): Promise<void> =>
66
64
  return inited;
67
65
  }
68
66
  inited = (async () => {
69
- trace(`${T} initSpeedTest run`);
70
67
  // TODO: fix server selection
71
68
  // const response = await fetch('https://iam.gcdn.co/info/json');
72
69
  // const data = await response.json();
@@ -130,8 +127,6 @@ export const initSpeedTest = (customMetrics: SpeedtestMetrics): Promise<void> =>
130
127
  await fetch('https://iam.gcdn.co/info/json')
131
128
  .then(r => r.json())
132
129
  .then(data => {
133
- trace(`${T} initSpeedTest fetched`);
134
-
135
130
  const country = data['Server Country code'].toLowerCase();
136
131
  const server = serversList.find(s => s.country === country) || serversList[0];
137
132
  if (!server) {
@@ -139,7 +134,6 @@ export const initSpeedTest = (customMetrics: SpeedtestMetrics): Promise<void> =>
139
134
  }
140
135
  speedTest.addTestPoint(server);
141
136
  speedTest.setSelectedServer(server);
142
- trace(`${T} initSpeedTest done`);
143
137
  });
144
138
  })();
145
139
 
@@ -153,14 +147,12 @@ export const stopSpeedtest = () => {
153
147
  };
154
148
 
155
149
  export const startSpeedtest = () => {
156
- trace(`${T} startSpeedtest`);
157
150
  if (speedTest.getState() !== 3) {
158
151
  speedTest.start();
159
152
  }
160
153
  };
161
154
 
162
155
  export const clearSpeedTestResults = () => {
163
- trace(`${T} clearSpeedTestResults`);
164
156
  speedtestResults.splice(0, speedtestResults.length);
165
157
  };
166
158
 
@@ -16,6 +16,9 @@ import {
16
16
  } from './types.js'
17
17
  export * from './types.js'
18
18
  import { newMetrics } from './utils.js'
19
+ import { isFullscreen } from '../utils/fullscreen.js'
20
+
21
+ // const T = 'plugins.clappr_stats'
19
22
 
20
23
  export type ClapprStatsSettings = {
21
24
  /**
@@ -134,9 +137,11 @@ export class ClapprStats extends ContainerPlugin {
134
137
  this.listenTo(this.container, CoreEvents.CONTAINER_ERROR, () =>
135
138
  this.inc(ClapprStatsCounter.Error),
136
139
  )
137
- this.listenTo(this.container, CoreEvents.CONTAINER_FULLSCREEN, () =>
138
- this.inc(ClapprStatsCounter.Fullscreen),
139
- )
140
+ this.listenTo(this.container, CoreEvents.CONTAINER_FULLSCREEN, () => {
141
+ if (isFullscreen(this.container.el)) {
142
+ this.inc(ClapprStatsCounter.Fullscreen)
143
+ }
144
+ })
140
145
  this.listenTo(
141
146
  this.container,
142
147
  CoreEvents.CONTAINER_PLAYBACKDVRSTATECHANGED,
@@ -251,8 +256,9 @@ export class ClapprStats extends ContainerPlugin {
251
256
  }
252
257
 
253
258
  private onSeek(e: number) {
259
+ const ms = e * 1000
254
260
  this.inc(ClapprStatsCounter.Seek)
255
- this.metrics.extra.watchHistory.push([e * 1000, e * 1000])
261
+ this.metrics.extra.watchHistory.push([ms, ms])
256
262
  }
257
263
 
258
264
  private onTimeUpdate(e: TimePosition) {
@@ -315,7 +315,7 @@ export class MediaControl extends UICorePlugin {
315
315
  'click [data-stop]': 'stop',
316
316
  'click [data-playstop]': 'togglePlayStop',
317
317
  'click [data-fullscreen]': 'handleFullScreenOnBtn',
318
- 'click .bar-container[data-seekbar]': 'seek',
318
+ // 'click .bar-container[data-seekbar]': 'seek', // This together with global window.bind causes duplicate seeks events
319
319
  'click .bar-container[data-volume]': 'onVolumeClick',
320
320
  'click .drawer-icon[data-volume]': 'toggleMute',
321
321
  'mouseenter .drawer-container[data-volume]': 'showVolumeBar',
@@ -731,12 +731,14 @@ export class MediaControl extends UICorePlugin {
731
731
  }
732
732
 
733
733
  private stopDrag = (event: MouseEvent) => {
734
- this.draggingSeekBar && this.seek(event)
734
+ if (this.draggingSeekBar) {
735
+ this.draggingSeekBar = false
736
+ this.seek(event)
737
+ }
735
738
  this.$el.removeClass('dragging')
736
739
  this.$seekBarLoaded?.removeClass('media-control-notransition')
737
740
  this.$seekBarPosition?.removeClass('media-control-notransition')
738
741
  this.$seekBarScrubber?.removeClass('media-control-notransition dragging')
739
- this.draggingSeekBar = false
740
742
  this.draggingVolumeBar = false
741
743
  }
742
744
 
@@ -752,7 +754,9 @@ export class MediaControl extends UICorePlugin {
752
754
  pos = Math.min(100, Math.max(pos, 0))
753
755
 
754
756
  this.setSeekPercentage(pos)
755
- } else if (this.draggingVolumeBar) {
757
+ return
758
+ }
759
+ if (this.draggingVolumeBar) {
756
760
  event.preventDefault()
757
761
  this.setVolume(this.getVolumeFromUIEvent(event))
758
762
  }
@@ -966,6 +970,7 @@ export class MediaControl extends UICorePlugin {
966
970
  if (!this.settings.seekEnabled) {
967
971
  return
968
972
  }
973
+ // TODO prevent double seek
969
974
 
970
975
  assert.ok(this.$seekBarContainer, 'seek bar container must be present')
971
976
  const offsetX =
@@ -976,8 +981,6 @@ export class MediaControl extends UICorePlugin {
976
981
  this.core.activeContainer && this.core.activeContainer.seekPercentage(pos)
977
982
 
978
983
  this.setSeekPercentage(pos)
979
-
980
- return false
981
984
  }
982
985
 
983
986
  private setUserKeepVisible() {
@@ -1010,7 +1013,10 @@ export class MediaControl extends UICorePlugin {
1010
1013
  }
1011
1014
  this.$el.show()
1012
1015
  this.trigger(Events.MEDIACONTROL_SHOW, this.name)
1013
- this.core.activeContainer?.trigger(Events.CONTAINER_MEDIACONTROL_SHOW, this.name)
1016
+ this.core.activeContainer?.trigger(
1017
+ Events.CONTAINER_MEDIACONTROL_SHOW,
1018
+ this.name,
1019
+ )
1014
1020
  this.$el.removeClass('media-control-hide')
1015
1021
  this.hideId = setTimeout(() => this.hide(), timeout)
1016
1022
  if (event) {
@@ -1067,7 +1073,6 @@ export class MediaControl extends UICorePlugin {
1067
1073
  }
1068
1074
 
1069
1075
  private updateSettings() {
1070
- trace(`${T} updateSettings`, { settings: this.settings })
1071
1076
  const newSettings = $.extend(
1072
1077
  true,
1073
1078
  {
@@ -1077,7 +1082,6 @@ export class MediaControl extends UICorePlugin {
1077
1082
  },
1078
1083
  this.core.activeContainer.settings,
1079
1084
  )
1080
- trace(`${T} updateSettings`, { newSettings })
1081
1085
 
1082
1086
  newSettings.left.push('clips') // TODO settings
1083
1087
  // TODO make order controlled via CSS
@@ -1099,11 +1103,6 @@ export class MediaControl extends UICorePlugin {
1099
1103
  (!this.fullScreenOnVideoTagSupported && !fullscreenEnabled()) ||
1100
1104
  this.options.fullscreenDisable
1101
1105
  ) {
1102
- trace(`${T} updateSettings removing fullscreen`, {
1103
- supported: this.fullScreenOnVideoTagSupported,
1104
- enabled: Fullscreen.fullscreenEnabled(),
1105
- optionsDisable: this.options.fullscreenDisable,
1106
- })
1107
1106
  // remove fullscreen from settings if it is not available
1108
1107
  removeArrayItem(newSettings.default, 'fullscreen')
1109
1108
  removeArrayItem(newSettings.left, 'fullscreen')
@@ -1183,7 +1182,6 @@ export class MediaControl extends UICorePlugin {
1183
1182
  */
1184
1183
  mount(name: MediaControlElement, element: ZeptoResult) {
1185
1184
  const panel = this.getElementLocation(name)
1186
- trace(`${T} mount`, { name, panel: !!panel })
1187
1185
  if (panel) {
1188
1186
  const current = panel.find(`[data-${name}]`)
1189
1187
  element.attr(`data-${name}`, '')
@@ -1415,15 +1413,12 @@ export class MediaControl extends UICorePlugin {
1415
1413
  * @internal
1416
1414
  */
1417
1415
  override render() {
1418
- trace(`${T} render`, {
1419
- needsUpdate: this.hasUpdate,
1420
- metadataLoaded: this.metadataLoaded,
1421
- })
1422
1416
  if (!this.hasUpdate || !this.metadataLoaded) {
1423
1417
  return this
1424
1418
  }
1425
1419
  const timeout = this.options.hideMediaControlDelay || 2000
1426
1420
 
1421
+ trace(`${T} render`, { settings: this.settings })
1427
1422
  this.$el.html(MediaControl.template({ settings: this.settings }))
1428
1423
  // const style = Styler.getStyleFor(mediaControlStyle, { baseUrl: this.options.baseUrl });
1429
1424
  // this.$el.append(style[0]);
@@ -1575,12 +1570,6 @@ export class MediaControl extends UICorePlugin {
1575
1570
  }
1576
1571
 
1577
1572
  private getElementLocation(name: MediaControlElement) {
1578
- trace(`${T} getElementLocation`, {
1579
- name,
1580
- right: this.settings.right,
1581
- left: this.settings.left,
1582
- default: this.settings.default,
1583
- })
1584
1573
  if (this.settings.right?.includes(name as MediaControlRightElement)) {
1585
1574
  return this.getRightPanel()
1586
1575
  }
@@ -298,6 +298,22 @@ describe('MediaControl', () => {
298
298
  })
299
299
  })
300
300
  })
301
+ describe('seekbar', () => {
302
+ beforeEach(async () => {
303
+ mediaControl = new MediaControl(core)
304
+ core.emit(Events.CORE_READY)
305
+ core.activeContainer.settings = {
306
+ seekEnabled: true,
307
+ default: ['seekbar'],
308
+ }
309
+ core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
310
+ await runMetadataLoaded(core)
311
+ core.activeContainer.emit(Events.CONTAINER_SETTINGSUPDATE)
312
+ })
313
+ it('should render', () => {
314
+ expect(mediaControl.el.innerHTML).toMatchSnapshot()
315
+ })
316
+ })
301
317
  })
302
318
 
303
319
  function arraySubtract<T extends string>(arr1: T[], arr2: T[]) {
@@ -296,6 +296,76 @@ exports[`MediaControl > rendering timing > once metadata is loaded > should wait
296
296
  <style>:root {}</style>"
297
297
  `;
298
298
 
299
+ exports[`MediaControl > seekbar > should render 1`] = `
300
+ "<div class="media-control-background" data-background=""></div>
301
+
302
+ <div class="media-control-layer gcore-skin-bg-color" data-controls="">
303
+
304
+
305
+
306
+
307
+
308
+
309
+
310
+
311
+
312
+
313
+
314
+
315
+ <div class="media-control-left-panel" data-media-control="">
316
+
317
+ <div class="drawer-container" data-volume="">
318
+ <div class="drawer-icon-container" data-volume="">
319
+ <div class="drawer-icon media-control-icon gcore-skin-button-color" data-volume="">/assets/icons/new/volume-max.svg</div>
320
+ <span class="drawer-text" data-volume=""></span>
321
+ </div>
322
+
323
+ <div class="bar-container" data-volume="">
324
+ <div class="bar-background" data-volume="">
325
+ <div class="bar-fill-1 gcore-skin-main-color" data-volume="" style="width: 100%;"></div>
326
+ </div>
327
+ <div class="bar-scrubber" data-volume="" style="left: 100%;">
328
+ <div class="bar-scrubber-icon gcore-skin-main-color" data-volume=""></div>
329
+ </div>
330
+ </div>
331
+
332
+ </div>
333
+
334
+ <div class="media-control-indicator gcore-skin-text-color" data-clips=""></div>
335
+
336
+ </div>
337
+
338
+
339
+ <div class="media-control-center-panel" data-media-control="">
340
+
341
+ <div class="bar-container" data-seekbar="">
342
+ <div class="bar-background" data-seekbar="">
343
+ <div class="bar-fill-1" data-seekbar=""></div>
344
+ <div class="bar-fill-2 gcore-skin-main-color" data-seekbar="" style="width: 0%;"></div>
345
+ <div class="bar-hover" data-seekbar=""></div>
346
+ </div>
347
+ </div>
348
+ <div class="bar-scrubber" data-seekbar="" style="left: 0%;">
349
+ <div class="bar-scrubber-icon gcore-skin-main-color" data-seekbar=""></div>
350
+ </div>
351
+
352
+ </div>
353
+
354
+
355
+ <div class="media-control-right-panel" data-media-control="">
356
+
357
+ <button type="button" class="media-control-button media-control-icon gcore-skin-button-color" data-fullscreen="" aria-label="fullscreen">/assets/icons/new/fullscreen-off.svg</button>
358
+
359
+ <div class="media-control-multicamera" data-multicamera=""></div>
360
+
361
+ <div class="media-control-vr" data-vr=""></div>
362
+
363
+ </div>
364
+
365
+ </div>
366
+ <style>:root {}</style>"
367
+ `;
368
+
299
369
  exports[`MediaControl > updateSettings > dvr > when disabled > should disable DVR controls 1`] = `
300
370
  "<div class="media-control-background" data-background=""></div>
301
371
 
@@ -3,20 +3,35 @@
3
3
  // license that can be found at https://github.com/clappr/clappr-plugins/blob/master/LICENSE
4
4
 
5
5
  import { Events, Playback, UICorePlugin, Utils, template } from '@clappr/core'
6
- import { TimePosition } from '../../playback.types.js'
6
+ import assert from 'assert'
7
7
 
8
+ import { TimePosition } from '../../playback.types.js'
8
9
  import { CLAPPR_VERSION } from '../../build.js'
9
10
 
10
11
  import seekTimeHTML from '../../../assets/seek-time/seek-time.html'
11
12
  import '../../../assets/seek-time/seek-time.scss'
12
- import { ZeptoResult } from '../../types.js'
13
- import assert from 'assert'
13
+
14
+ /**
15
+ * Configuration options for the SeekTime plugin.
16
+ * @beta
17
+ */
18
+ export type SeekTimeSettings = {
19
+ /**
20
+ * Whether to show the duration of the video. Applies only to the VOD streams.
21
+ * @beta
22
+ */
23
+ duration?: boolean
24
+ }
14
25
 
15
26
  const { formatTime } = Utils
16
27
 
28
+ // const T = 'plugins.seek_time'
29
+
17
30
  /**
18
- * `PLUGIN` that adds a seek time indicator to the media control UI.
31
+ * `PLUGIN` that adds a seek time indicator when the mouse pointer is over the seek bar.
19
32
  * @beta
33
+ * @remarks
34
+ * Configuration options - {@link SeekTimeSettings}
20
35
  */
21
36
  export class SeekTime extends UICorePlugin {
22
37
  get name() {
@@ -32,7 +47,6 @@ export class SeekTime extends UICorePlugin {
32
47
  override get attributes() {
33
48
  return {
34
49
  class: 'seek-time',
35
- 'data-seek-time': '',
36
50
  }
37
51
  }
38
52
 
@@ -44,8 +58,11 @@ export class SeekTime extends UICorePlugin {
44
58
  )
45
59
  }
46
60
 
47
- private get durationShown() {
48
- return !this.isLiveStreamWithDvr
61
+ private get showDuration() {
62
+ return (
63
+ this.core.options.seekTime?.duration === true &&
64
+ this.core.activeContainer?.getPlaybackType() !== Playback.LIVE
65
+ )
49
66
  }
50
67
 
51
68
  private hoveringOverSeekBar = false
@@ -57,19 +74,17 @@ export class SeekTime extends UICorePlugin {
57
74
  private displayedSeekTime: string | null = null
58
75
 
59
76
  private duration = 0
60
- // private firstFragDateTime = 0;
61
-
62
- private rendered = false
63
-
64
- private $durationEl: ZeptoResult | null = null
65
-
66
- private $seekTimeEl: ZeptoResult | null = null
67
77
 
68
78
  /**
69
79
  * @internal
70
80
  */
71
81
  override bindEvents() {
72
82
  this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
83
+ this.listenTo(
84
+ this.core,
85
+ Events.CORE_ACTIVE_CONTAINER_CHANGED,
86
+ this.onContainerChanged,
87
+ )
73
88
  }
74
89
 
75
90
  private onCoreReady() {
@@ -89,23 +104,6 @@ export class SeekTime extends UICorePlugin {
89
104
  Events.MEDIACONTROL_MOUSELEAVE_SEEKBAR,
90
105
  this.hideTime,
91
106
  )
92
- this.listenTo(
93
- mediaControl,
94
- Events.MEDIACONTROL_CONTAINERCHANGED,
95
- this.onContainerChanged,
96
- )
97
- if (this.core.activeContainer) {
98
- this.listenTo(
99
- this.core.activeContainer,
100
- Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
101
- this.update,
102
- )
103
- this.listenTo(
104
- this.core.activeContainer,
105
- Events.CONTAINER_TIMEUPDATE,
106
- this.onTimeUpdate,
107
- )
108
- }
109
107
  }
110
108
 
111
109
  private onContainerChanged() {
@@ -149,18 +147,12 @@ export class SeekTime extends UICorePlugin {
149
147
  }
150
148
 
151
149
  private getSeekTime() {
152
- const seekTime = this.isLiveStreamWithDvr
150
+ return this.isLiveStreamWithDvr
153
151
  ? this.duration - this.hoverPosition * this.duration
154
152
  : this.hoverPosition * this.duration
155
-
156
- return { seekTime }
157
153
  }
158
154
 
159
155
  private update() {
160
- if (!this.rendered) {
161
- // update() is always called after a render
162
- return
163
- }
164
156
  if (!this.shouldBeVisible()) {
165
157
  this.$el.hide()
166
158
  this.$el.css('left', '-100%')
@@ -168,7 +160,7 @@ export class SeekTime extends UICorePlugin {
168
160
  }
169
161
 
170
162
  const seekTime = this.getSeekTime()
171
- let currentSeekTime = formatTime(seekTime.seekTime, false)
163
+ let currentSeekTime = formatTime(seekTime, false)
172
164
 
173
165
  if (this.isLiveStreamWithDvr) {
174
166
  currentSeekTime = `-${currentSeekTime}`
@@ -176,20 +168,21 @@ export class SeekTime extends UICorePlugin {
176
168
 
177
169
  // only update dom if necessary, ie time actually changed
178
170
  if (currentSeekTime !== this.displayedSeekTime) {
179
- this.$seekTimeEl.text(currentSeekTime)
171
+ this.$el.find('#mc-seek-time').text(currentSeekTime)
180
172
  this.displayedSeekTime = currentSeekTime
181
173
  }
182
174
 
183
- if (this.durationShown) {
184
- this.$durationEl.show()
175
+ const $durationEl = this.$el.find('#mc-duration')
176
+ if (this.showDuration) {
177
+ $durationEl.show()
185
178
  const currentDuration = formatTime(this.duration, false)
186
179
 
187
180
  if (currentDuration !== this.displayedDuration) {
188
- this.$durationEl.text(currentDuration)
181
+ $durationEl.text(currentDuration)
189
182
  this.displayedDuration = currentDuration
190
183
  }
191
184
  } else {
192
- this.$durationEl.hide()
185
+ $durationEl.hide()
193
186
  }
194
187
 
195
188
  // the element must be unhidden before its width is requested, otherwise it's width will be reported as 0
@@ -218,16 +211,10 @@ export class SeekTime extends UICorePlugin {
218
211
  * @internal
219
212
  */
220
213
  override render() {
221
- this.rendered = true
222
214
  this.displayedDuration = null
223
215
  this.displayedSeekTime = null
224
216
  this.$el.html(SeekTime.template())
225
217
  this.$el.hide()
226
- // this.mediaControl.$el.append(this.el);
227
- this.$seekTimeEl = this.$el.find('#mc-seek-time')
228
- this.$durationEl = this.$el.find('#mc-duration')
229
- this.$durationEl.hide()
230
- this.update()
231
218
  return this
232
219
  }
233
220
 
package/src/testUtils.ts CHANGED
@@ -176,6 +176,7 @@ export function createMockContainer(
176
176
  isPlaying: vi.fn().mockReturnValue(false),
177
177
  play: vi.fn(),
178
178
  seek: vi.fn(),
179
+ seekPercentage: vi.fn(),
179
180
  switchAudioTrack: vi.fn(),
180
181
  trigger: emitter.emit,
181
182
  })