@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
@@ -0,0 +1,469 @@
1
+ import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core'
2
+ import { reportError, trace } from '@gcorevideo/utils'
3
+ import assert from 'assert'
4
+
5
+ import { CLAPPR_VERSION } from '../../build.js'
6
+ import type { TextTrackItem } from '../../playback.types.js'
7
+
8
+ import '../../../assets/subtitles/style.scss'
9
+ import subtitlesOffIcon from '../../../assets/icons/new/subtitles-off.svg'
10
+ import subtitlesOnIcon from '../../../assets/icons/new/subtitles-on.svg'
11
+ import comboboxHTML from '../../../assets/subtitles/combobox.ejs'
12
+ import stringHTML from '../../../assets/subtitles/string.ejs'
13
+
14
+ import { isFullscreen } from '../utils.js'
15
+ import type { ZeptoResult } from '../../types.js'
16
+
17
+ const VERSION: string = '2.19.14'
18
+
19
+ const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected'
20
+
21
+ const T = 'plugins.cc'
22
+
23
+ export type ClosedCaptionsPluginSettings = {
24
+ /**
25
+ * Initially selected subtitles language
26
+ */
27
+ language?: string
28
+ }
29
+
30
+ /**
31
+ * @deprecated Use {@link ClosedCaptionsPluginSettings} instead.
32
+ */
33
+ export type SubtitlesPluginSettings = ClosedCaptionsPluginSettings;
34
+
35
+ /**
36
+ * `PLUGIN` that provides a UI to select the subtitles when available.
37
+ * @beta
38
+ *
39
+ * @remarks
40
+ * The plugin is activated when closed captions tracks are provided with the media source.
41
+ * It shows a familiar "CC" button with a dropdown menu to select the subtitles language.
42
+ *
43
+ * Depends on:
44
+ *
45
+ * - {@link MediaControl}
46
+ *
47
+ * Configuration options - {@link ClosedCaptionsPluginSettings}
48
+ * @example
49
+ * ```ts
50
+ * import { ClosedCaptions } from '@gcorevideo/player'
51
+ *
52
+ * Player.registerPlugin(ClosedCaptions)
53
+ *
54
+ * new Player({
55
+ * ...
56
+ * cc: {
57
+ * language: 'en',
58
+ * },
59
+ * })
60
+ * ```
61
+ */
62
+ export class ClosedCaptions extends UICorePlugin {
63
+ private isPreselectedApplied = false
64
+
65
+ private isShowing = false
66
+
67
+ private track: TextTrackItem | null = null
68
+
69
+ private tracks: TextTrackItem[] = []
70
+
71
+ private $line: ZeptoResult | null = null
72
+
73
+ /**
74
+ * @internal
75
+ */
76
+ get name() {
77
+ return 'cc'
78
+ }
79
+
80
+ /**
81
+ * @internal
82
+ */
83
+ get supportedVersion() {
84
+ return { min: CLAPPR_VERSION }
85
+ }
86
+
87
+ /**
88
+ * @internal
89
+ */
90
+ static get version() {
91
+ return VERSION
92
+ }
93
+
94
+ private static readonly template = template(comboboxHTML)
95
+
96
+ private static readonly templateString = template(stringHTML)
97
+
98
+ /**
99
+ * @internal
100
+ */
101
+ override get attributes() {
102
+ return {
103
+ class: 'media-control-cc',
104
+ }
105
+ }
106
+
107
+ /**
108
+ * @internal
109
+ */
110
+ override get events() {
111
+ return {
112
+ 'click [data-cc-select]': 'onItemSelect',
113
+ 'click [data-cc-button]': 'toggleMenu',
114
+ }
115
+ }
116
+
117
+ private get preselectedLanguage(): string {
118
+ return this.core.options.cc?.language ?? this.core.options.subtitles?.language ?? ''
119
+ }
120
+
121
+ /**
122
+ * @internal
123
+ */
124
+ override bindEvents() {
125
+ this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
126
+ this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize)
127
+ this.listenTo(
128
+ this.core,
129
+ Events.CORE_ACTIVE_CONTAINER_CHANGED,
130
+ this.onContainerChanged,
131
+ )
132
+ }
133
+
134
+ private onCoreReady() {
135
+ trace(`${T} onCoreReady`)
136
+ const mediaControl = this.core.getPlugin('media_control')
137
+ assert(mediaControl, 'media_control plugin is required')
138
+ this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render)
139
+ this.listenTo(
140
+ mediaControl,
141
+ Events.MEDIACONTROL_HIDE,
142
+ this.hideMenu,
143
+ )
144
+ }
145
+
146
+ private onContainerChanged() {
147
+ trace(`${T} onContainerChanged`)
148
+ this.listenTo(
149
+ this.core.activeContainer,
150
+ Events.CONTAINER_FULLSCREEN,
151
+ this.playerResize,
152
+ )
153
+ this.listenTo(
154
+ this.core.activeContainer,
155
+ 'container:advertisement:start',
156
+ this.onStartAd,
157
+ )
158
+ this.listenTo(
159
+ this.core.activePlayback,
160
+ Events.PLAYBACK_SUBTITLE_AVAILABLE,
161
+ this.onSubtitleAvailable,
162
+ )
163
+ this.listenTo(
164
+ this.core.activePlayback,
165
+ Events.PLAYBACK_SUBTITLE_CHANGED,
166
+ this.onSubtitleChanged,
167
+ )
168
+
169
+ // fix for iOS
170
+ const video = this.core.activePlayback.el
171
+ assert(video, 'video element is required')
172
+
173
+ video.addEventListener('webkitbeginfullscreen', () => {
174
+ if (Browser.isiOS) {
175
+ video.classList.add('ios-fullscreen')
176
+ }
177
+ })
178
+
179
+ video.addEventListener('webkitendfullscreen', () => {
180
+ if (Browser.isiOS) {
181
+ video.classList.remove('ios-fullscreen')
182
+ }
183
+ })
184
+ }
185
+
186
+ private onSubtitleAvailable() {
187
+ trace(`${T} onSubtitleAvailable`)
188
+ this.applyTracks()
189
+ }
190
+
191
+ private onSubtitleChanged({ id }: { id: number }) {
192
+ trace(`${T} onSubtitleChanged`, { id })
193
+ if (id === -1) {
194
+ this.clearSubtitleText()
195
+ }
196
+ for (const track of this.tracks) {
197
+ if (track.id === id) {
198
+ track.track.mode = 'showing'
199
+
200
+ this.setSubtitleText(this.getSubtitleText(track.track))
201
+
202
+ track.track.oncuechange = (e) => {
203
+ try {
204
+ if (track.track.activeCues?.length) {
205
+ const html = (track.track.activeCues[0] as VTTCue).getCueAsHTML()
206
+
207
+ this.setSubtitleText(html)
208
+ } else {
209
+ this.clearSubtitleText()
210
+ }
211
+ } catch (error) {
212
+ reportError(error)
213
+ }
214
+ }
215
+ } else {
216
+ track.track.oncuechange = null
217
+ track.track.mode = 'hidden'
218
+ }
219
+ }
220
+ }
221
+
222
+ private applyTracks() {
223
+ try {
224
+ this.tracks = this.core.activePlayback.closedCaptionsTracks
225
+ this.applyPreselectedSubtitles()
226
+ this.render()
227
+ } catch (error) {
228
+ reportError(error)
229
+ }
230
+ }
231
+
232
+ private onStartAd() {
233
+ if (this.isShowing && this.core.activeContainer) {
234
+ this.hide()
235
+ this.listenTo(
236
+ this.core.activeContainer,
237
+ 'container:advertisement:finish',
238
+ this.onFinishAd,
239
+ )
240
+ }
241
+ }
242
+
243
+ private onFinishAd() {
244
+ this.show()
245
+ this.stopListening(
246
+ this.core.activeContainer,
247
+ 'container:advertisement:finish',
248
+ this.onFinishAd,
249
+ )
250
+ }
251
+
252
+ private playerResize() {
253
+ trace(`${T} playerResize`)
254
+ const shouldShow =
255
+ this.core.activeContainer &&
256
+ isFullscreen(this.core.activeContainer.el) &&
257
+ this.track &&
258
+ this.track.track.mode &&
259
+ Browser.isiOS &&
260
+ this.isShowing
261
+
262
+ if (shouldShow) {
263
+ this.show()
264
+ }
265
+
266
+ try {
267
+ this.resizeFont()
268
+ } catch (error) {
269
+ reportError(error)
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Hides the subtitles menu and the subtitles.
275
+ */
276
+ hide() {
277
+ this.isShowing = false
278
+ this.renderIcon()
279
+ this.$line.hide()
280
+ if (this.tracks) {
281
+ for (const t of this.tracks) {
282
+ t.track.mode = 'hidden'
283
+ }
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Shows the subtitles menu and the subtitles.
289
+ */
290
+ show() {
291
+ this.isShowing = true
292
+ this.renderIcon()
293
+ if (
294
+ this.core.activeContainer &&
295
+ isFullscreen(this.core.activeContainer.el) &&
296
+ this.track &&
297
+ this.track.track.mode &&
298
+ Browser.isiOS
299
+ ) {
300
+ this.$line.hide()
301
+ this.track.track.mode = 'showing'
302
+ } else {
303
+ this.$line.show()
304
+ }
305
+ }
306
+
307
+ private shouldRender() {
308
+ return this.tracks?.length > 0
309
+ }
310
+
311
+ private resizeFont() {
312
+ if (!this.$line) {
313
+ return
314
+ }
315
+
316
+ const skinWidth = this.core.activeContainer.$el.width()
317
+
318
+ this.$line.find('p').css('font-size', skinWidth * 0.03)
319
+ }
320
+
321
+ /**
322
+ * @internal
323
+ */
324
+ override render() {
325
+ if (!this.core.activeContainer) {
326
+ return this
327
+ }
328
+
329
+ if (!this.shouldRender()) {
330
+ return this
331
+ }
332
+
333
+ const mediaControl = this.core.getPlugin('media_control')
334
+
335
+ this.$el.html(ClosedCaptions.template({ tracks: this.tracks }))
336
+ this.core.activeContainer.$el.find('#cc-line').remove()
337
+ this.$line = $(ClosedCaptions.templateString())
338
+ this.resizeFont()
339
+
340
+ this.core.activeContainer.$el.append(this.$line)
341
+ mediaControl.putElement('cc', this.el)
342
+
343
+ this.updateSelection()
344
+
345
+ this.renderIcon()
346
+
347
+ return this
348
+ }
349
+
350
+ private findById(id: number) {
351
+ return this.tracks.find((track) => track.id === id) ?? null
352
+ }
353
+
354
+ private selectItem(item: TextTrackItem | null) {
355
+ this.clearSubtitleText()
356
+ this.track = item
357
+
358
+ this.hideMenu()
359
+ this.updateSelection()
360
+ }
361
+
362
+ private onItemSelect(event: MouseEvent) {
363
+ const id = (event.target as HTMLElement).dataset.ccSelect ?? '-1'
364
+
365
+ trace(`${T} onItemSelect`, { id })
366
+
367
+ localStorage.setItem(LOCAL_STORAGE_CC_ID, id)
368
+ this.selectItem(this.findById(Number(id)))
369
+
370
+ return false
371
+ }
372
+
373
+ private applyPreselectedSubtitles() {
374
+ if (!this.isPreselectedApplied) {
375
+ this.isPreselectedApplied = true
376
+ if (!this.preselectedLanguage) {
377
+ return
378
+ }
379
+ setTimeout(() => {
380
+ this.selectItem(
381
+ this.tracks.find(
382
+ (t) => t.track.language === this.preselectedLanguage,
383
+ ) ?? null,
384
+ )
385
+ }, 300) // TODO why delay?
386
+ }
387
+ }
388
+
389
+ private hideMenu() {
390
+ ;(this.$('[data-cc] ul') as ZeptoResult).hide()
391
+ }
392
+
393
+ private toggleMenu() {
394
+ trace(`${T} toggleMenu`)
395
+ ;(this.$('[data-cc] ul') as ZeptoResult).toggle()
396
+ }
397
+
398
+ private itemElement(id: number): ZeptoResult {
399
+ return (
400
+ this.$(`ul li a[data-cc-select="${id}"]`) as ZeptoResult
401
+ ).parent()
402
+ }
403
+
404
+ private allItemElements(): ZeptoResult {
405
+ return this.$('[data-cc] li')
406
+ }
407
+
408
+ private selectSubtitles() {
409
+ const trackId = this.track ? this.track.id : -1
410
+
411
+ this.core.activePlayback.closedCaptionsTrackId = trackId
412
+ }
413
+
414
+ private getSubtitleText(track: TextTrack) {
415
+ const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0
416
+ const cues = track.cues
417
+ const lines = []
418
+
419
+ if (cues && cues.length) {
420
+ for (const cue of cues) {
421
+ if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
422
+ lines.push((cue as VTTCue).getCueAsHTML().textContent)
423
+ }
424
+ }
425
+ }
426
+
427
+ return lines.join('\n')
428
+ }
429
+
430
+ private setSubtitleText(text: string | DocumentFragment) {
431
+ this.$line.find('p').html(text)
432
+ }
433
+
434
+ private clearSubtitleText() {
435
+ this.setSubtitleText('')
436
+ }
437
+
438
+ private updateSelection() {
439
+ if (!this.track) {
440
+ this.hide()
441
+ } else {
442
+ this.show()
443
+ }
444
+ this.selectSubtitles()
445
+ this.highlightCurrentSubtitles()
446
+ }
447
+
448
+ private highlightCurrentSubtitles() {
449
+ this.allItemElements()
450
+ .removeClass('current')
451
+ .find('a')
452
+ .removeClass('gcore-skin-active')
453
+
454
+ trace(`${T} highlightCurrentSubtitles`, {
455
+ track: this.track?.id,
456
+ })
457
+ const currentLevelElement = this.itemElement(this.track ? this.track.id : -1)
458
+ currentLevelElement
459
+ .addClass('current')
460
+ .find('a')
461
+ .addClass('gcore-skin-active')
462
+ }
463
+
464
+ private renderIcon() {
465
+ const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon
466
+
467
+ this.$el.find('span.cc-text').html(icon)
468
+ }
469
+ }
@@ -0,0 +1,58 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { ClosedCaptions } from '../ClosedCaptions.js'
3
+ import { createMockCore, createMockMediaControl } from '../../../testUtils.js';
4
+
5
+ describe('ClosedCaptions', () => {
6
+ let core: any;
7
+ let mediaControl: any;
8
+ let cc: ClosedCaptions;
9
+ beforeEach(() => {
10
+ core = createMockCore()
11
+ mediaControl = createMockMediaControl(core)
12
+ core.getPlugin = vi.fn().mockImplementation((name) => {
13
+ if (name === 'media_control') {
14
+ return mediaControl
15
+ }
16
+ return null
17
+ })
18
+ cc = new ClosedCaptions(core)
19
+ })
20
+ describe('basically', () => {
21
+ beforeEach(() => {
22
+ core.emit('core:ready')
23
+ core.activePlayback.el = document.createElement('video')
24
+ core.emit('core:active:container:changed', core.activeContainer)
25
+ core.activePlayback.closedCaptionsTracks = [
26
+ {
27
+ id: 1,
28
+ name: 'English',
29
+ track: {
30
+ language: 'en',
31
+ kind: 'subtitles',
32
+ label: 'English',
33
+ mode: 'hidden',
34
+ cues: [],
35
+ }
36
+ },
37
+ {
38
+ id: 2,
39
+ name: 'Spanish',
40
+ track: {
41
+ language: 'es',
42
+ kind: 'subtitles',
43
+ label: 'Spanish',
44
+ mode: 'hidden',
45
+ cues: [],
46
+ }
47
+ }
48
+ ]
49
+ core.activePlayback.emit('playback:subtitle:available')
50
+ core.activeContainer.emit('container:subtitle:available')
51
+ })
52
+ it('should render', () => {
53
+ expect(cc.el.innerHTML).toMatchSnapshot()
54
+ expect(cc.$el.find('[data-cc-button]').length).toEqual(1)
55
+ expect(mediaControl.putElement).toHaveBeenCalledWith('cc', cc.el)
56
+ })
57
+ })
58
+ })
@@ -0,0 +1,25 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ClosedCaptions > basically > should render 1`] = `
4
+ "<button data-cc-button="" class="media-control-button media-control-icon gcore-skin-button-color" id="cc-button">
5
+ <span class="cc-text">/assets/icons/new/subtitles-off.svg</span>
6
+ </button>
7
+
8
+ <ul class="gcore-skin-bg-color" id="cc-select">
9
+
10
+ <li>
11
+ <a href="#" class="gcore-skin-text-color" data-cc-select="1">
12
+ English
13
+ </a>
14
+ </li>
15
+
16
+ <li>
17
+ <a href="#" class="gcore-skin-text-color" data-cc-select="2">
18
+ Spanish
19
+ </a>
20
+ </li>
21
+
22
+ <li class="current"><a href="#" class="gcore-skin-text-color gcore-skin-active" data-cc-select="-1">Off</a></li>
23
+ </ul>
24
+ "
25
+ `;
package/src/testUtils.ts CHANGED
@@ -126,47 +126,31 @@ export function createMockPlayback(name = 'mock') {
126
126
  return Object.assign(emitter, {
127
127
  name,
128
128
  currentLevel: -1,
129
+ dvrEnabled: false,
129
130
  levels: [],
130
131
  consent() {},
131
132
  play() {},
132
133
  pause() {},
133
134
  stop() {},
134
- destroy() {},
135
- seek() {},
136
- seekPercentage() {},
137
- getDuration() {
138
- return 100
139
- },
140
- enterPiP() {},
141
- exitPiP() {},
142
- getPlaybackType() {
143
- return 'live'
144
- },
145
- getStartTimeOffset() {
146
- return 0
147
- },
148
- getCurrentTime() {
149
- return 0
150
- },
151
- isHighDefinitionInUse() {
152
- return false
153
- },
154
- mute() {},
155
- unmute() {},
156
- volume() {},
157
- configure() {},
158
- attemptAutoPlay() {
159
- return true
160
- },
161
- canAutoPlay() {
162
- return true
163
- },
164
- onResize() {
165
- return true
166
- },
167
- trigger(event: string, ...args: any[]) {
168
- emitter.emit(event, ...args)
169
- },
135
+ destroy: vi.fn(),
136
+ seek: vi.fn(),
137
+ seekPercentage: vi.fn(),
138
+ getDuration: vi.fn().mockImplementation(() => 100),
139
+ enterPiP: vi.fn(),
140
+ exitPiP: vi.fn(),
141
+ getPlaybackType: vi.fn().mockImplementation(() => 'live'),
142
+ getStartTimeOffset: vi.fn().mockImplementation(() => 0),
143
+ getCurrentTime: vi.fn().mockImplementation(() => 0),
144
+ isHighDefinitionInUse: vi.fn().mockImplementation(() => false),
145
+ mute: vi.fn(),
146
+ unmute: vi.fn(),
147
+ volume: vi.fn(),
148
+ configure: vi.fn(),
149
+ attemptAutoPlay: vi.fn().mockImplementation(() => true),
150
+ canAutoPlay: vi.fn().mockImplementation(() => true),
151
+ onResize: vi.fn().mockImplementation(() => true),
152
+ setPlaybackRate: vi.fn(),
153
+ trigger: emitter.emit,
170
154
  })
171
155
  }
172
156
 
@@ -179,6 +163,8 @@ export function createMockContainer(playback: any = createMockPlayback()) {
179
163
  $el: $(el),
180
164
  getDuration: vi.fn().mockReturnValue(0),
181
165
  getPlugin: vi.fn(),
166
+ getPlaybackType: vi.fn().mockReturnValue('live'),
167
+ isDvrInUse: vi.fn().mockReturnValue(false),
182
168
  isPlaying: vi.fn().mockReturnValue(false),
183
169
  play: vi.fn(),
184
170
  seek: vi.fn(),