@gcorevideo/player 2.28.35 → 2.28.36

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 (31) hide show
  1. package/README.md +22 -1
  2. package/assets/{subtitles → cc}/style.scss +5 -0
  3. package/dist/core.js +17 -23
  4. package/dist/index.css +346 -342
  5. package/dist/index.embed.js +46 -39
  6. package/dist/index.js +46 -39
  7. package/lib/playback/BasePlayback.d.ts +1 -0
  8. package/lib/playback/BasePlayback.d.ts.map +1 -1
  9. package/lib/playback/BasePlayback.js +3 -0
  10. package/lib/playback/dash-playback/DashPlayback.d.ts +1 -0
  11. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  12. package/lib/playback/dash-playback/DashPlayback.js +9 -22
  13. package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
  14. package/lib/playback/hls-playback/HlsPlayback.js +4 -0
  15. package/lib/plugins/subtitles/ClosedCaptions.d.ts +1 -1
  16. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
  17. package/lib/plugins/subtitles/ClosedCaptions.js +32 -22
  18. package/lib/testUtils.d.ts +1 -0
  19. package/lib/testUtils.d.ts.map +1 -1
  20. package/lib/testUtils.js +3 -0
  21. package/package.json +1 -1
  22. package/src/playback/BasePlayback.ts +4 -0
  23. package/src/playback/dash-playback/DashPlayback.ts +10 -27
  24. package/src/playback/hls-playback/HlsPlayback.ts +4 -0
  25. package/src/plugins/subtitles/ClosedCaptions.ts +34 -20
  26. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +73 -112
  27. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +3 -3
  28. package/src/testUtils.ts +3 -0
  29. package/tsconfig.tsbuildinfo +1 -1
  30. /package/assets/{subtitles → cc}/combobox.ejs +0 -0
  31. /package/assets/{subtitles → cc}/string.ejs +0 -0
@@ -16,6 +16,7 @@ describe('ClosedCaptions', () => {
16
16
  let mediaControl: any
17
17
  let cc: ClosedCaptions
18
18
  beforeEach(() => {
19
+ vi.useFakeTimers()
19
20
  core = createMockCore()
20
21
  mediaControl = createMockMediaControl(core)
21
22
  mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(211)
@@ -27,8 +28,12 @@ describe('ClosedCaptions', () => {
27
28
  })
28
29
  cc = new ClosedCaptions(core)
29
30
  })
31
+ afterEach(() => {
32
+ vi.useRealTimers()
33
+ })
30
34
  describe('basically', () => {
31
35
  beforeEach(() => {
36
+ core.options.cc = { language: 'none' }
32
37
  core.emit(Events.CORE_READY)
33
38
  core.activePlayback.el = document.createElement('video')
34
39
  core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
@@ -53,6 +58,7 @@ describe('ClosedCaptions', () => {
53
58
  describe("when subtitle tracks are available", () => {
54
59
  beforeEach(() => {
55
60
  emitSubtitleAvailable(core)
61
+ vi.advanceTimersByTime(1)
56
62
  })
57
63
  it('should render', () => {
58
64
  expect(cc.el.innerHTML).toMatchSnapshot()
@@ -64,7 +70,6 @@ describe('ClosedCaptions', () => {
64
70
  width: 320,
65
71
  height: 260,
66
72
  })
67
- // core.emit(Events.CORE_RESIZE, { width: 320, height: 260 })
68
73
  })
69
74
  it('should clamp popup height', () => {
70
75
  expect(cc.$el.find('#gplayer-cc-menu').css('max-height')).toBe('197px')
@@ -131,9 +136,9 @@ describe('ClosedCaptions', () => {
131
136
  })
132
137
  })
133
138
  describe('when subtitle is changed', () => {
134
- beforeEach(async () => {
139
+ beforeEach(() => {
135
140
  cc.$el.find('#gplayer-cc-button').click()
136
- await new Promise((resolve) => setTimeout(resolve, 100))
141
+ vi.advanceTimersByTime(100)
137
142
  core.activePlayback.getCurrentTime = vi.fn().mockReturnValue(7)
138
143
  core.activeContainer.getCurrentTime = vi.fn().mockReturnValue(7)
139
144
  core.activePlayback.closedCaptionsTracks[1].track.cues = [
@@ -169,10 +174,10 @@ describe('ClosedCaptions', () => {
169
174
  },
170
175
  ]
171
176
  cc.$el.find('#gplayer-cc-menu li:nth-child(2) a').click()
172
- await new Promise((resolve) => setTimeout(resolve, 100))
177
+ vi.advanceTimersByTime(100)
173
178
  // TODO test explicitly that PLAYBACK_SUBTITLE_CHANGED event does not cause track switch
174
179
  core.activePlayback.emit(Events.PLAYBACK_SUBTITLE_CHANGED, { id: 2 })
175
- await new Promise((resolve) => setTimeout(resolve, 100))
180
+ vi.advanceTimersByTime(100)
176
181
  })
177
182
  it('should activate selected track', () => {
178
183
  expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe(
@@ -193,7 +198,8 @@ describe('ClosedCaptions', () => {
193
198
  cc.$el.find('#gplayer-cc-menu li:nth-child(2) a').click()
194
199
  })
195
200
  it('should activate native subtitles track', () => {
196
- expect(core.activePlayback.closedCaptionsTrackId).toEqual(2)
201
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(1)
202
+ expect(core.activePlayback.closedCaptionsTrackId).toEqual(1)
197
203
  })
198
204
  it('should highlight selected menu item', () => {
199
205
  expect(
@@ -257,7 +263,6 @@ describe('ClosedCaptions', () => {
257
263
  describe('when language is configured', () => {
258
264
  describe("and is set to 'none'", () => {
259
265
  beforeEach(() => {
260
- vi.useFakeTimers()
261
266
  core.options.cc = { language: 'none' }
262
267
  emitSubtitleAvailable(core)
263
268
  vi.advanceTimersByTime(1)
@@ -281,47 +286,37 @@ describe('ClosedCaptions', () => {
281
286
  })
282
287
  })
283
288
  describe('when language is undefined', () => {
284
- // let spyClosedCaptionsTrackId: any // TODO
285
289
  beforeEach(() => {
286
- // spyClosedCaptionsTrackId = vi.spyOn(core.activePlayback, 'closedCaptionsTrackId')
287
290
  core.options.cc = {}
288
291
  core.activePlayback.closedCaptionsTrackId = undefined
289
292
  emitSubtitleAvailable(core, 1)
293
+ vi.advanceTimersByTime(1)
290
294
  })
291
295
  // The native engine will decide
292
296
  it('should not automatically select any track', () => {
293
297
  expect(core.activePlayback.closedCaptionsTrackId).toEqual(undefined)
298
+ expect(core.activePlayback.setTextTrack).not.toHaveBeenCalled()
294
299
  })
295
- it('should not activate any tracks', () => {
296
- expect(core.activePlayback.closedCaptionsTracks[0].track.mode).toBe(
297
- 'hidden', // showing is reset to hidden since the plugin manages rendition
298
- )
299
- expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe(
300
- 'hidden',
301
- )
300
+ it('should not touch any tracks', () => {
301
+ expect(core.activePlayback.el.textTracks[0].mode).toBe('hidden')
302
+ // Track #1 is set active (as if selected by the engine), @see {emitSubtitleAvailable}()
303
+ expect(core.activePlayback.el.textTracks[1].mode).toBe('showing')
302
304
  })
303
305
  })
304
306
  describe('when language matches a track', () => {
305
307
  beforeEach(() => {
306
- vi.useFakeTimers()
307
308
  core.options.cc = { language: 'en' }
308
309
  emitSubtitleAvailable(core)
309
310
  vi.advanceTimersByTime(1)
310
311
  })
311
- // afterEach(() => {
312
- // vi.useRealTimers()
313
- // })
314
312
  it('should activate the matching track', () => {
315
- expect(core.activePlayback.closedCaptionsTrackId).toEqual(1)
313
+ expect(core.activePlayback.closedCaptionsTrackId).toEqual(0)
314
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(0)
316
315
  })
316
+ // TODO with options.cc.mode='native' the selected track's mode should be 'showing'
317
317
  it('should set the matching track mode appropriately', () => {
318
- // The matching track should be activated
319
- expect(core.activePlayback.closedCaptionsTracks[0].track.mode).toBe(
320
- 'hidden',
321
- )
322
- expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe(
323
- 'disabled',
324
- )
318
+ expect(core.activePlayback.el.textTracks[0].mode).toBe('hidden')
319
+ expect(core.activePlayback.el.textTracks[1].mode).toBe('disabled')
325
320
  })
326
321
  it('should highlight the matching track in menu', () => {
327
322
  expect(
@@ -331,18 +326,13 @@ describe('ClosedCaptions', () => {
331
326
  })
332
327
  describe('when language does not match any track', () => {
333
328
  beforeEach(() => {
334
- vi.useFakeTimers()
335
329
  core.options.cc = { language: 'fr' }
336
- cc = new ClosedCaptions(core)
337
330
  core.emit(Events.CORE_READY)
338
331
  core.activePlayback.el = document.createElement('video')
339
332
  core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
340
333
  emitSubtitleAvailable(core)
341
334
  vi.advanceTimersByTime(1)
342
335
  })
343
- afterEach(() => {
344
- vi.useRealTimers()
345
- })
346
336
  it('should disable subtitles', () => {
347
337
  expect(core.activePlayback.closedCaptionsTrackId).toEqual(-1)
348
338
  })
@@ -364,7 +354,6 @@ describe('ClosedCaptions', () => {
364
354
  describe('when subtitle available event occurs after user selection', () => {
365
355
  describe('if user selected track before event', () => {
366
356
  beforeEach(() => {
367
- vi.useFakeTimers()
368
357
  core.options.cc = { language: 'en' }
369
358
  // First subtitle available event
370
359
  emitSubtitleAvailable(core)
@@ -382,12 +371,10 @@ describe('ClosedCaptions', () => {
382
371
  emitSubtitleAvailable(core)
383
372
  vi.advanceTimersByTime(1)
384
373
  })
385
- afterEach(() => {
386
- vi.useRealTimers()
387
- })
388
374
  it('should run preselected language matching algorithm', () => {
389
375
  // Should activate track selected by user
390
- expect(core.activePlayback.closedCaptionsTrackId).toEqual(2)
376
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(1)
377
+ expect(core.activePlayback.closedCaptionsTrackId).toEqual(1)
391
378
  })
392
379
  it('should select track based on configured language', () => {
393
380
  expect(
@@ -406,18 +393,10 @@ describe('ClosedCaptions', () => {
406
393
  })
407
394
  describe('when multiple subtitle available events occur', () => {
408
395
  beforeEach(() => {
409
- vi.useFakeTimers()
410
396
  core.options.cc = { language: 'en' }
411
- // cc = new ClosedCaptions(core)
412
- // core.emit(Events.CORE_READY)
413
- // core.activePlayback.el = document.createElement('video')
414
- // core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
415
397
  // First subtitle available event
416
398
  emitSubtitleAvailable(core)
417
399
  vi.advanceTimersByTime(1)
418
- // User changes selection
419
- // cc.$el.find('#gplayer-cc-menu li:nth-child(2) a').click()
420
- // Container changed (simulating source switch)
421
400
  core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
422
401
  vi.advanceTimersByTime(1)
423
402
  core.activePlayback.closedCaptionsTrackId = undefined
@@ -425,68 +404,59 @@ describe('ClosedCaptions', () => {
425
404
  emitSubtitleAvailable(core)
426
405
  vi.advanceTimersByTime(1)
427
406
  })
428
- afterEach(() => {
429
- vi.useRealTimers()
430
- })
431
- it('should reapply preselected language matching', () => {
432
- expect(core.activePlayback.closedCaptionsTrackId).toEqual(1)
433
- // Should select English track based on configured language
407
+ it('should reapply preselected language matching and activate the matching track', () => {
408
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(0)
409
+ expect(core.activePlayback.closedCaptionsTrackId).toEqual(0)
434
410
  expect(
435
411
  cc.$el.find('#gplayer-cc-menu li:nth-child(1)').hasClass('current'),
436
412
  ).toBe(true)
437
413
  })
438
414
  it('should activate the matching track', () => {
439
- expect(core.activePlayback.closedCaptionsTracks[0].track.mode).toBe(
415
+ expect(core.activePlayback.el.textTracks[0].mode).toBe(
440
416
  'hidden',
441
417
  )
442
- expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe(
418
+ expect(core.activePlayback.el.textTracks[1].mode).toBe(
443
419
  'disabled',
444
420
  )
445
421
  })
446
422
  })
447
423
  })
448
- describe.each(['dash', 'hls'] as const)(
424
+ describe.each([['html5_video', false], ['dash', false], ['hls', true]] as const)(
449
425
  'when playback engine is %s',
450
- (playbackEngine) => {
426
+ (playbackEngine, isManaged) => {
451
427
  beforeEach(() => {
452
- // core.emit(Events.CORE_READY)
453
428
  core.activePlayback.el = document.createElement('video')
454
429
  core.activePlayback.name = playbackEngine
455
- core.activePlayback.setTextTrack = vi.fn()
456
- // core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
457
430
  })
458
431
  describe('when language is configured and matches a track', () => {
459
432
  beforeEach(() => {
460
- vi.useFakeTimers()
461
433
  core.options.cc = { language: 'en' }
462
- // cc = new ClosedCaptions(core)
463
- // core.emit(Events.CORE_READY)
464
- // core.activePlayback.el = document.createElement('video')
465
- // core.activePlayback.name = playbackEngine
466
- // core.activePlayback.setTextTrack = vi.fn()
467
- // core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
468
434
  emitSubtitleAvailable(core)
469
435
  vi.advanceTimersByTime(1)
470
436
  })
471
- afterEach(() => {
472
- vi.useRealTimers()
473
- })
474
437
  it('should call setTextTrack with matching track id', () => {
475
- expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(1)
438
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(0)
476
439
  })
477
440
  it('should set closedCaptionsTrackId to matching track id', () => {
478
- expect(core.activePlayback.closedCaptionsTrackId).toEqual(1)
479
- })
480
- it('should not touch native tracks', () => {
481
- expect(core.activePlayback.closedCaptionsTracks[0].track.mode).toBe('hidden')
482
- expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe('hidden')
441
+ expect(core.activePlayback.closedCaptionsTrackId).toEqual(0)
483
442
  })
443
+ if (isManaged) {
444
+ it('should not touch native tracks', () => {
445
+ expect(core.activePlayback.el.textTracks[0].mode).toBe('hidden')
446
+ expect(core.activePlayback.el.textTracks[1].mode).toBe('hidden')
447
+ })
448
+ } else {
449
+ it('should disable inactive native track', () => {
450
+ expect(core.activePlayback.el.textTracks[1].mode).toBe('disabled')
451
+ })
452
+ it('should keep active native track hidden', () => {
453
+ expect(core.activePlayback.el.textTracks[0].mode).toBe('hidden')
454
+ })
455
+ }
484
456
  })
485
457
  describe('when language is configured but does not match any track', () => {
486
458
  beforeEach(() => {
487
- vi.useFakeTimers()
488
459
  core.options.cc = { language: 'fr' }
489
- cc = new ClosedCaptions(core)
490
460
  core.emit(Events.CORE_READY)
491
461
  core.activePlayback.el = document.createElement('video')
492
462
  core.activePlayback.name = playbackEngine
@@ -495,9 +465,6 @@ describe('ClosedCaptions', () => {
495
465
  emitSubtitleAvailable(core)
496
466
  vi.advanceTimersByTime(1)
497
467
  })
498
- afterEach(() => {
499
- vi.useRealTimers()
500
- })
501
468
  it('should disable subtitles', () => {
502
469
  expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(-1)
503
470
  expect(core.activePlayback.closedCaptionsTrackId).toEqual(-1)
@@ -507,22 +474,20 @@ describe('ClosedCaptions', () => {
507
474
  beforeEach(() => {
508
475
  core.activePlayback.setTextTrack = vi.fn()
509
476
  emitSubtitleAvailable(core)
477
+ vi.advanceTimersByTime(1)
510
478
  cc.$el.find('#gplayer-cc-menu li:nth-child(2) a').click()
479
+ vi.advanceTimersByTime(1)
511
480
  })
512
481
  it('should call setTextTrack with selected track id', () => {
513
- // TODO: Implement assertion
514
- // expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(2)
482
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(1)
515
483
  })
516
484
  it('should update closedCaptionsTrackId', () => {
517
- // TODO: Implement assertion
518
- // expect(core.activePlayback.closedCaptionsTrackId).toEqual(2)
485
+ expect(core.activePlayback.closedCaptionsTrackId).toEqual(1)
519
486
  })
520
487
  })
521
488
  describe('when language is set to none', () => {
522
489
  beforeEach(() => {
523
- vi.useFakeTimers()
524
490
  core.options.cc = { language: 'none' }
525
- cc = new ClosedCaptions(core)
526
491
  core.emit(Events.CORE_READY)
527
492
  core.activePlayback.el = document.createElement('video')
528
493
  core.activePlayback.name = playbackEngine
@@ -531,12 +496,8 @@ describe('ClosedCaptions', () => {
531
496
  emitSubtitleAvailable(core)
532
497
  vi.advanceTimersByTime(1)
533
498
  })
534
- afterEach(() => {
535
- vi.useRealTimers()
536
- })
537
- it('should call setTextTrack with -1 to disable subtitles', () => {
538
- // TODO: Implement assertion
539
- // expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(-1)
499
+ it('should disable subtitles', () => {
500
+ expect(core.activePlayback.setTextTrack).toHaveBeenCalledWith(-1)
540
501
  })
541
502
  })
542
503
  },
@@ -545,30 +506,30 @@ describe('ClosedCaptions', () => {
545
506
  })
546
507
 
547
508
  function emitSubtitleAvailable(core: any, selectedTrackId?: number) {
548
- core.activePlayback.closedCaptionsTracks = [
509
+ const domTracks = [
549
510
  {
550
- id: 1,
551
- name: 'English',
552
- track: {
553
- language: 'en',
554
- kind: 'subtitles',
555
- label: 'English',
556
- mode: selectedTrackId === 1 ? 'showing' : 'hidden',
557
- cues: [],
558
- },
511
+ language: 'en',
512
+ kind: 'subtitles',
513
+ label: 'English',
514
+ mode: selectedTrackId === 0 ? 'showing' : 'hidden',
515
+ cues: [],
516
+ id: "01en"
559
517
  },
560
518
  {
561
- id: 2,
562
- name: 'Spanish',
563
- track: {
564
- language: 'es',
565
- kind: 'subtitles',
566
- label: 'Español',
567
- mode: selectedTrackId === 2 ? 'showing' : 'hidden',
568
- cues: [],
569
- },
570
- },
519
+ language: 'es',
520
+ kind: 'subtitles',
521
+ label: 'Español',
522
+ mode: selectedTrackId === 1 ? 'showing' : 'hidden',
523
+ cues: [],
524
+ id: "02es"
525
+ }
571
526
  ]
527
+ core.activePlayback.closedCaptionsTracks = domTracks.map((t, index) => ({
528
+ id: index,
529
+ name: t.label,
530
+ track: t,
531
+ }))
532
+ vi.spyOn(core.activePlayback.el, 'textTracks', 'get').mockReturnValue(domTracks)
572
533
  core.activePlayback.emit(Events.PLAYBACK_SUBTITLE_AVAILABLE)
573
534
  core.activeContainer.emit(Events.CONTAINER_SUBTITLE_AVAILABLE)
574
535
  }
@@ -6,14 +6,14 @@ exports[`ClosedCaptions > basically > when subtitle tracks are available > shoul
6
6
  <ul class="gcore-skin-bg-color media-control-dd__popup" id="gplayer-cc-menu" role="menu" style="display: none; max-height: 211px;">
7
7
 
8
8
  <li class="">
9
- <a href="#" class="gcore-skin-text-color" data-item="1" role="menuitemradio" aria-checked="false">
9
+ <a href="#" class="gcore-skin-text-color" data-item="0" role="menuitemradio" aria-checked="false">
10
10
  English
11
11
  </a>
12
12
  </li>
13
13
 
14
14
  <li class="">
15
- <a href="#" class="gcore-skin-text-color" data-item="2" role="menuitemradio" aria-checked="false">
16
- Spanish
15
+ <a href="#" class="gcore-skin-text-color" data-item="1" role="menuitemradio" aria-checked="false">
16
+ Español
17
17
  </a>
18
18
  </li>
19
19
 
package/src/testUtils.ts CHANGED
@@ -81,6 +81,7 @@ export function createMockPlayback(
81
81
  canAutoPlay: vi.fn().mockImplementation(() => true),
82
82
  onResize: vi.fn().mockImplementation(() => true),
83
83
  setPlaybackRate: vi.fn(),
84
+ setTextTrack: vi.fn(),
84
85
  switchAudioTrack: vi.fn(),
85
86
  trigger: emitter.emit,
86
87
  })
@@ -139,6 +140,8 @@ export function createMockMediaControl(core: any) {
139
140
  // @ts-ignore
140
141
  mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(286)
141
142
  // @ts-ignore
143
+ mediaControl.isVisible = vi.fn().mockReturnValue(true)
144
+ // @ts-ignore
142
145
  mediaControl.toggleElement = vi.fn()
143
146
  // @ts-ignore
144
147
  mediaControl.setKeepVisible = vi.fn()