@gcorevideo/player 2.28.28 → 2.28.30
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.
- package/dist/core.js +128 -62
- package/dist/index.css +211 -211
- package/dist/index.embed.js +270 -190
- package/dist/index.js +241 -168
- package/lib/playback/BasePlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.d.ts +22 -3
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +50 -5
- package/lib/playback/hls-playback/HlsPlayback.d.ts +32 -6
- package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/playback/hls-playback/HlsPlayback.js +78 -57
- package/lib/playback.types.d.ts +6 -0
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.d.ts +5 -6
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +40 -38
- package/lib/plugins/subtitles/ClosedCaptions.d.ts +5 -0
- package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
- package/lib/plugins/subtitles/ClosedCaptions.js +56 -54
- package/lib/plugins/utils/mobile.d.ts +2 -0
- package/lib/plugins/utils/mobile.d.ts.map +1 -0
- package/lib/plugins/utils/mobile.js +4 -0
- package/lib/testUtils.d.ts +3 -0
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +3 -0
- package/package.json +1 -1
- package/src/playback/BasePlayback.ts +2 -1
- package/src/playback/dash-playback/DashPlayback.ts +68 -13
- package/src/playback/hls-playback/HlsPlayback.ts +89 -80
- package/src/playback.types.ts +7 -0
- package/src/plugins/media-control/MediaControl.ts +45 -43
- package/src/plugins/media-control/__tests__/MediaControl.test.ts +63 -35
- package/src/plugins/multi-camera/MultiCamera.ts +5 -5
- package/src/plugins/subtitles/ClosedCaptions.ts +64 -57
- package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +195 -196
- package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +13 -1
- package/src/plugins/utils/mobile.ts +5 -0
- package/src/testUtils.ts +3 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -26,6 +26,8 @@ import { CLAPPR_VERSION } from '../../build.js'
|
|
|
26
26
|
import { ZeptoResult } from '../../types.js'
|
|
27
27
|
import { getPageX } from '../utils.js'
|
|
28
28
|
import { fullscreenEnabled, isFullscreen } from '../utils/fullscreen.js'
|
|
29
|
+
import { isMobile } from '../utils/mobile.js'
|
|
30
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
29
31
|
|
|
30
32
|
import '../../../assets/media-control/media-control.scss'
|
|
31
33
|
|
|
@@ -37,7 +39,6 @@ import volumeMaxIcon from '../../../assets/icons/new/volume-max.svg'
|
|
|
37
39
|
import volumeOffIcon from '../../../assets/icons/new/volume-off.svg'
|
|
38
40
|
import fullscreenOffIcon from '../../../assets/icons/new/fullscreen-off.svg'
|
|
39
41
|
import fullscreenOnIcon from '../../../assets/icons/new/fullscreen-on.svg'
|
|
40
|
-
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
41
42
|
|
|
42
43
|
const STANDARD_MEDIA_CONTROL_ELEMENTS: string[] = [
|
|
43
44
|
'duration',
|
|
@@ -352,8 +353,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
352
353
|
'touchmove .bar-container[data-seekbar]': 'mousemoveOnSeekBar',
|
|
353
354
|
'mouseleave .bar-container[data-seekbar]': 'mouseleaveOnSeekBar',
|
|
354
355
|
'touchend .bar-container[data-seekbar]': 'mouseleaveOnSeekBar',
|
|
355
|
-
'mouseenter .media-control-layer[data-controls]': 'setUserKeepVisible',
|
|
356
|
-
'mouseleave .media-control-layer[data-controls]': 'resetUserKeepVisible',
|
|
357
356
|
}
|
|
358
357
|
}
|
|
359
358
|
|
|
@@ -470,9 +469,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
470
469
|
Events.CONTAINER_DBLCLICK,
|
|
471
470
|
this.toggleFullscreen,
|
|
472
471
|
)
|
|
473
|
-
this.listenTo(this.core.activeContainer, Events.CONTAINER_CLICK, () =>
|
|
474
|
-
this.clickaway(this.core.activeContainer.$el[0]),
|
|
475
|
-
)
|
|
476
472
|
this.listenTo(
|
|
477
473
|
this.core.activeContainer,
|
|
478
474
|
Events.CONTAINER_TIMEUPDATE,
|
|
@@ -526,6 +522,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
526
522
|
)
|
|
527
523
|
this.listenTo(this.core, Events.CONTAINER_DESTROYED, () => {
|
|
528
524
|
this.cancelRenderTimer()
|
|
525
|
+
this.setKeepVisible(false)
|
|
529
526
|
})
|
|
530
527
|
this.listenTo(
|
|
531
528
|
this.core.activeContainer,
|
|
@@ -537,10 +534,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
537
534
|
Events.CONTAINER_MOUSE_LEAVE,
|
|
538
535
|
this.delayHide,
|
|
539
536
|
)
|
|
540
|
-
|
|
541
|
-
this.listenTo(this.core.activeContainer, Events.CONTAINER_DESTROYED, () => {
|
|
542
|
-
this.clickaway(null)
|
|
543
|
-
})
|
|
544
537
|
}
|
|
545
538
|
|
|
546
539
|
/**
|
|
@@ -692,7 +685,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
692
685
|
this.$playPauseToggle?.append(playIcon)
|
|
693
686
|
this.$playStopToggle?.append(playIcon)
|
|
694
687
|
this.trigger(Events.MEDIACONTROL_NOTPLAYING)
|
|
695
|
-
if (
|
|
688
|
+
if (isMobile()) {
|
|
696
689
|
this.show()
|
|
697
690
|
}
|
|
698
691
|
}
|
|
@@ -745,7 +738,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
745
738
|
width: this.container.$el.width(),
|
|
746
739
|
height: this.container.$el.height(),
|
|
747
740
|
hideVolumeBar: this.options.hideVolumeBar,
|
|
748
|
-
isMobile:
|
|
741
|
+
isMobile: isMobile(),
|
|
749
742
|
})
|
|
750
743
|
|
|
751
744
|
try {
|
|
@@ -754,7 +747,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
754
747
|
this.$el.addClass('w370')
|
|
755
748
|
}
|
|
756
749
|
|
|
757
|
-
if (skinWidth <= 270 && !
|
|
750
|
+
if (skinWidth <= 270 && !isMobile()) {
|
|
758
751
|
this.verticalVolume = true
|
|
759
752
|
this.$el.addClass('w270')
|
|
760
753
|
}
|
|
@@ -769,6 +762,18 @@ export class MediaControl extends UICorePlugin {
|
|
|
769
762
|
return false
|
|
770
763
|
}
|
|
771
764
|
|
|
765
|
+
private play() {
|
|
766
|
+
this.container && this.container.play()
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
private pause() {
|
|
770
|
+
this.container && this.container.pause()
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
private stop() {
|
|
774
|
+
this.container && this.container.stop()
|
|
775
|
+
}
|
|
776
|
+
|
|
772
777
|
private togglePlayStop() {
|
|
773
778
|
this.container.isPlaying()
|
|
774
779
|
? this.container.stop({ ui: true })
|
|
@@ -893,11 +898,11 @@ export class MediaControl extends UICorePlugin {
|
|
|
893
898
|
}
|
|
894
899
|
|
|
895
900
|
private toggleFullscreen() {
|
|
896
|
-
if (!
|
|
901
|
+
if (!isMobile()) {
|
|
897
902
|
this.trigger(Events.MEDIACONTROL_FULLSCREEN, this.name)
|
|
898
903
|
this.core.activeContainer.fullscreen()
|
|
899
904
|
this.core.toggleFullscreen()
|
|
900
|
-
this.resetUserKeepVisible()
|
|
905
|
+
// this.resetUserKeepVisible()
|
|
901
906
|
}
|
|
902
907
|
}
|
|
903
908
|
|
|
@@ -1048,15 +1053,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
1048
1053
|
this.setSeekPercentage(pos)
|
|
1049
1054
|
}
|
|
1050
1055
|
|
|
1051
|
-
private setUserKeepVisible(e?: MouseEvent) {
|
|
1052
|
-
this.userKeepVisible = true
|
|
1053
|
-
this.clickaway(this.core.activeContainer.$el[0])
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
private resetUserKeepVisible = (e?: MouseEvent) => {
|
|
1057
|
-
this.userKeepVisible = false
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
1056
|
private isVisible() {
|
|
1061
1057
|
return !this.$el.hasClass('media-control-hide')
|
|
1062
1058
|
}
|
|
@@ -1066,7 +1062,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
1066
1062
|
return
|
|
1067
1063
|
}
|
|
1068
1064
|
|
|
1069
|
-
const timeout = DEFAULT_HIDE_DELAY
|
|
1070
1065
|
const mousePointerMoved =
|
|
1071
1066
|
event &&
|
|
1072
1067
|
event.clientX !== this.lastMouseX &&
|
|
@@ -1077,6 +1072,8 @@ export class MediaControl extends UICorePlugin {
|
|
|
1077
1072
|
clearTimeout(this.hideId)
|
|
1078
1073
|
this.hideId = null
|
|
1079
1074
|
}
|
|
1075
|
+
this.hideId = setTimeout(() => this.hide(), DEFAULT_HIDE_DELAY)
|
|
1076
|
+
|
|
1080
1077
|
this.$el.show()
|
|
1081
1078
|
this.trigger(Events.MEDIACONTROL_SHOW, this.name)
|
|
1082
1079
|
this.core.activeContainer?.trigger(
|
|
@@ -1084,15 +1081,13 @@ export class MediaControl extends UICorePlugin {
|
|
|
1084
1081
|
this.name,
|
|
1085
1082
|
)
|
|
1086
1083
|
this.$el.removeClass('media-control-hide')
|
|
1087
|
-
this.hideId = setTimeout(() => this.hide(), timeout)
|
|
1088
1084
|
if (event) {
|
|
1089
1085
|
this.lastMouseX = event.clientX
|
|
1090
1086
|
this.lastMouseY = event.clientY
|
|
1091
1087
|
}
|
|
1092
1088
|
}
|
|
1093
|
-
const showing = true
|
|
1094
1089
|
|
|
1095
|
-
this.updateCursorStyle(
|
|
1090
|
+
this.updateCursorStyle(true)
|
|
1096
1091
|
}
|
|
1097
1092
|
|
|
1098
1093
|
private hide(delay = 0) {
|
|
@@ -1100,10 +1095,9 @@ export class MediaControl extends UICorePlugin {
|
|
|
1100
1095
|
return
|
|
1101
1096
|
}
|
|
1102
1097
|
|
|
1103
|
-
const timeout = delay || 2000
|
|
1104
|
-
|
|
1105
1098
|
if (this.hideId !== null) {
|
|
1106
1099
|
clearTimeout(this.hideId)
|
|
1100
|
+
this.hideId = null
|
|
1107
1101
|
}
|
|
1108
1102
|
|
|
1109
1103
|
if (!this.disabled && this.options.hideMediaControl === false) {
|
|
@@ -1117,7 +1111,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1117
1111
|
!this.disabled &&
|
|
1118
1112
|
(delay || hasKeepVisibleRequested || hasDraggingAction)
|
|
1119
1113
|
) {
|
|
1120
|
-
this.hideId = setTimeout(() => this.hide(),
|
|
1114
|
+
this.hideId = setTimeout(() => this.hide(), delay || 2000)
|
|
1121
1115
|
} else {
|
|
1122
1116
|
if (!this.options.controlsDontHide || isFullscreen(this.container.el)) {
|
|
1123
1117
|
this.trigger(Events.MEDIACONTROL_HIDE, this.name)
|
|
@@ -1278,18 +1272,13 @@ export class MediaControl extends UICorePlugin {
|
|
|
1278
1272
|
/**
|
|
1279
1273
|
* Set or reset the keep visibility state
|
|
1280
1274
|
*
|
|
1281
|
-
* Keep visibility state controls whether the media control is hidden automatically after a delay.
|
|
1282
|
-
* Keep visibility prevents the the auto-hide behaviour
|
|
1275
|
+
* Keep visibility state controls whether the media control is hidden automatically after a delay, which is a default behaviour.
|
|
1283
1276
|
*
|
|
1284
1277
|
* @param keepVisible - The state
|
|
1285
1278
|
*/
|
|
1286
1279
|
setKeepVisible(keepVisible: boolean) {
|
|
1287
1280
|
this.keepVisible = keepVisible
|
|
1288
|
-
|
|
1289
|
-
this.clickaway(this.core.activeContainer.$el[0])
|
|
1290
|
-
} else {
|
|
1291
|
-
this.clickaway(null)
|
|
1292
|
-
}
|
|
1281
|
+
this.clickaway(keepVisible ? this.core.activeContainer.$el[0] : null)
|
|
1293
1282
|
}
|
|
1294
1283
|
|
|
1295
1284
|
private getMountParent(name: MediaControlSlotMountPoint): ZeptoResult {
|
|
@@ -1390,7 +1379,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1390
1379
|
}
|
|
1391
1380
|
|
|
1392
1381
|
private bindKeyEvents() {
|
|
1393
|
-
if (
|
|
1382
|
+
if (isMobile() || this.options.disableKeyboardShortcuts) {
|
|
1394
1383
|
return
|
|
1395
1384
|
}
|
|
1396
1385
|
|
|
@@ -1491,6 +1480,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1491
1480
|
* @internal
|
|
1492
1481
|
*/
|
|
1493
1482
|
override destroy() {
|
|
1483
|
+
this.cancelTimers()
|
|
1494
1484
|
this.cancelRenderTimer()
|
|
1495
1485
|
$(document).unbind('mouseup', this.stopDrag)
|
|
1496
1486
|
$(document).unbind('mousemove', this.updateDrag)
|
|
@@ -1500,6 +1490,18 @@ export class MediaControl extends UICorePlugin {
|
|
|
1500
1490
|
return super.destroy()
|
|
1501
1491
|
}
|
|
1502
1492
|
|
|
1493
|
+
private cancelTimers() {
|
|
1494
|
+
if (this.hideId !== null) {
|
|
1495
|
+
clearTimeout(this.hideId)
|
|
1496
|
+
this.hideId = null
|
|
1497
|
+
}
|
|
1498
|
+
if (this.hideVolumeId !== null) {
|
|
1499
|
+
clearTimeout(this.hideVolumeId)
|
|
1500
|
+
this.hideVolumeId = null
|
|
1501
|
+
}
|
|
1502
|
+
this.cancelRenderTimer()
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1503
1505
|
private cancelRenderTimer() {
|
|
1504
1506
|
if (this.renderTimerId) {
|
|
1505
1507
|
clearTimeout(this.renderTimerId)
|
|
@@ -1537,7 +1539,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1537
1539
|
|
|
1538
1540
|
// Video volume cannot be changed with Safari on mobile devices
|
|
1539
1541
|
// Display mute/unmute icon only if Safari version >= 10
|
|
1540
|
-
if (Browser.isSafari &&
|
|
1542
|
+
if (Browser.isSafari && isMobile()) {
|
|
1541
1543
|
if (Browser.version < 10) {
|
|
1542
1544
|
this.$volumeContainer?.css({ display: 'none' })
|
|
1543
1545
|
} else {
|
|
@@ -1557,7 +1559,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1557
1559
|
setTimeout(() => {
|
|
1558
1560
|
!this.settings.seekEnabled &&
|
|
1559
1561
|
this.$seekBarContainer?.addClass('seek-disabled')
|
|
1560
|
-
!
|
|
1562
|
+
!isMobile() &&
|
|
1561
1563
|
!this.options.disableKeyboardShortcuts &&
|
|
1562
1564
|
this.bindKeyEvents()
|
|
1563
1565
|
this.playerResize({
|
|
@@ -1587,6 +1589,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1587
1589
|
this.container.fullscreen()
|
|
1588
1590
|
// TODO: fix after it full screen will be fixed on iOS
|
|
1589
1591
|
if (Browser.isiOS) {
|
|
1592
|
+
// TODO use isFullscreen utility function
|
|
1590
1593
|
if (this.core.isFullscreen()) {
|
|
1591
1594
|
Fullscreen.cancelFullscreen(this.core.el)
|
|
1592
1595
|
} else {
|
|
@@ -1595,7 +1598,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
1595
1598
|
} else {
|
|
1596
1599
|
this.core.toggleFullscreen()
|
|
1597
1600
|
}
|
|
1598
|
-
this.resetUserKeepVisible()
|
|
1599
1601
|
}
|
|
1600
1602
|
|
|
1601
1603
|
private static getPageX(event: MouseEvent | TouchEvent): number {
|
|
@@ -1653,7 +1655,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1653
1655
|
this.hide(this.options.hideMediaControlDelay || DEFAULT_HIDE_DELAY)
|
|
1654
1656
|
}
|
|
1655
1657
|
|
|
1656
|
-
private clickaway = mediaControlClickaway(() => this.
|
|
1658
|
+
private clickaway = mediaControlClickaway(() => this.setKeepVisible(false))
|
|
1657
1659
|
}
|
|
1658
1660
|
|
|
1659
1661
|
MediaControl.extend = function (properties) {
|
|
@@ -237,41 +237,38 @@ describe('MediaControl', () => {
|
|
|
237
237
|
)
|
|
238
238
|
expect(el.length).toEqual(0)
|
|
239
239
|
})
|
|
240
|
-
it(`should ${
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
expect(fullscreen.length).toEqual(0)
|
|
273
|
-
}
|
|
274
|
-
})
|
|
240
|
+
it(`should ${settings.seekEnabled ? '' : 'not '
|
|
241
|
+
}render the seek bar`, () => {
|
|
242
|
+
const seekbar = mediaControl.$el.find(
|
|
243
|
+
'.media-control-center-panel [data-seekbar]',
|
|
244
|
+
)
|
|
245
|
+
expect(seekbar.length).toBeGreaterThan(1)
|
|
246
|
+
if (settings.seekEnabled) {
|
|
247
|
+
expect(seekbar.hasClass('seek-disabled')).toBe(false)
|
|
248
|
+
} else {
|
|
249
|
+
expect(seekbar.hasClass('seek-disabled')).toBe(true)
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
it(`should ${settings.left.includes('volume') ? '' : 'not '
|
|
253
|
+
}render the volume control`, () => {
|
|
254
|
+
const volume = mediaControl.$el.find('.drawer-container[data-volume]')
|
|
255
|
+
if (settings.left.includes('volume')) {
|
|
256
|
+
expect(volume.length).toEqual(1)
|
|
257
|
+
} else {
|
|
258
|
+
expect(volume.length).toEqual(0)
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
it(`should ${settings.right.includes('fullscreen') ? '' : 'not '
|
|
262
|
+
}render the fullscreen control`, () => {
|
|
263
|
+
const fullscreen = mediaControl.$el.find(
|
|
264
|
+
'.media-control-right-panel [data-fullscreen]',
|
|
265
|
+
)
|
|
266
|
+
if (settings.right.includes('fullscreen')) {
|
|
267
|
+
expect(fullscreen.length).toEqual(1)
|
|
268
|
+
} else {
|
|
269
|
+
expect(fullscreen.length).toEqual(0)
|
|
270
|
+
}
|
|
271
|
+
})
|
|
275
272
|
})
|
|
276
273
|
describe('basically', () => {
|
|
277
274
|
let handler: MockedFunction<() => void>
|
|
@@ -338,6 +335,37 @@ describe('MediaControl', () => {
|
|
|
338
335
|
expect(mediaControl.el.innerHTML).toMatchSnapshot()
|
|
339
336
|
})
|
|
340
337
|
})
|
|
338
|
+
describe('auto-hide', () => {
|
|
339
|
+
beforeEach(async () => {
|
|
340
|
+
mediaControl = new MediaControl(core)
|
|
341
|
+
core.emit(Events.CORE_READY)
|
|
342
|
+
core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
|
|
343
|
+
await runMetadataLoaded(core)
|
|
344
|
+
})
|
|
345
|
+
describe('when rendered', () => {
|
|
346
|
+
it('should auto-hide', async () => {
|
|
347
|
+
expect(mediaControl.$el.hasClass('media-control-hide')).toBe(false)
|
|
348
|
+
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
349
|
+
expect(mediaControl.$el.hasClass('media-control-hide')).toBe(true)
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
describe('after rendered', () => {
|
|
353
|
+
beforeEach(async () => {
|
|
354
|
+
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
355
|
+
})
|
|
356
|
+
describe('after user interaction', () => {
|
|
357
|
+
beforeEach(async () => {
|
|
358
|
+
core.activeContainer.trigger(Events.CONTAINER_MOUSE_ENTER)
|
|
359
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
360
|
+
})
|
|
361
|
+
it('should auto-hide', async () => {
|
|
362
|
+
expect(mediaControl.$el.hasClass('media-control-hide')).toBe(false)
|
|
363
|
+
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
364
|
+
expect(mediaControl.$el.hasClass('media-control-hide')).toBe(true)
|
|
365
|
+
})
|
|
366
|
+
})
|
|
367
|
+
})
|
|
368
|
+
})
|
|
341
369
|
})
|
|
342
370
|
|
|
343
371
|
function arraySubtract<T extends string>(arr1: T[], arr2: T[]) {
|
|
@@ -457,11 +457,11 @@ export class MultiCamera extends UICorePlugin {
|
|
|
457
457
|
}
|
|
458
458
|
|
|
459
459
|
private hideSelectLevelMenu() {
|
|
460
|
-
;(this.$('.multicamera ul') as ZeptoResult).hide()
|
|
460
|
+
; (this.$('.multicamera ul') as ZeptoResult).hide()
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
private toggleContextMenu() {
|
|
464
|
-
;(this.$('.multicamera ul') as ZeptoResult).toggle()
|
|
464
|
+
; (this.$('.multicamera ul') as ZeptoResult).toggle()
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
// private buttonElement(): ZeptoResult {
|
|
@@ -475,9 +475,9 @@ export class MultiCamera extends UICorePlugin {
|
|
|
475
475
|
private levelElement(id?: number): ZeptoResult {
|
|
476
476
|
return this.$(
|
|
477
477
|
'.multicamera ul li > div' +
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
478
|
+
(id !== undefined
|
|
479
|
+
? '[data-multicamera-selector-select="' + id + '"]'
|
|
480
|
+
: ''),
|
|
481
481
|
)
|
|
482
482
|
}
|
|
483
483
|
|
|
@@ -15,6 +15,7 @@ import { isFullscreen } from '../utils/fullscreen.js'
|
|
|
15
15
|
import type { ZeptoResult } from '../../types.js'
|
|
16
16
|
import { ExtendedEvents } from '../media-control/MediaControl.js'
|
|
17
17
|
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
18
|
+
import { VTTCueInfo } from '../../playback.types.js'
|
|
18
19
|
|
|
19
20
|
const VERSION: string = '2.19.14'
|
|
20
21
|
|
|
@@ -153,6 +154,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
153
154
|
Events.CORE_ACTIVE_CONTAINER_CHANGED,
|
|
154
155
|
this.onContainerChanged,
|
|
155
156
|
)
|
|
157
|
+
this.listenTo(this.core, Events.PLAYBACK_READY, this.onPlaybackReady)
|
|
158
|
+
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
private onCoreReady() {
|
|
@@ -171,9 +174,11 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
171
174
|
}
|
|
172
175
|
},
|
|
173
176
|
)
|
|
177
|
+
this.onPlaybackReady()
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
private onContainerChanged() {
|
|
181
|
+
this.tracks = []
|
|
177
182
|
this.listenTo(
|
|
178
183
|
this.core.activeContainer,
|
|
179
184
|
Events.CONTAINER_FULLSCREEN,
|
|
@@ -187,11 +192,6 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
187
192
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_DESTROYED, () => {
|
|
188
193
|
this.clickaway(null)
|
|
189
194
|
})
|
|
190
|
-
// this.listenTo(
|
|
191
|
-
// this.core.activeContainer,
|
|
192
|
-
// 'container:advertisement:start',
|
|
193
|
-
// this.onStartAd,
|
|
194
|
-
// )
|
|
195
195
|
this.listenTo(
|
|
196
196
|
this.core.activePlayback,
|
|
197
197
|
Events.PLAYBACK_SUBTITLE_AVAILABLE,
|
|
@@ -226,21 +226,24 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
226
226
|
this.isPreselectedApplied = false
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
private onPlaybackReady() {
|
|
230
|
+
trace(`${T} onPlaybackReady`)
|
|
231
|
+
this.core.activePlayback.oncueenter = (e: VTTCueInfo) => {
|
|
232
|
+
this.setSubtitleText(e.text)
|
|
233
|
+
}
|
|
234
|
+
this.core.activePlayback.oncueexit = () => {
|
|
235
|
+
this.clearSubtitleText()
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
229
239
|
private onSubtitleAvailable() {
|
|
230
|
-
trace(`${T} onSubtitleAvailable`, {
|
|
231
|
-
tracks: this.core.activePlayback.closedCaptionsTracks.length,
|
|
232
|
-
})
|
|
233
240
|
this.applyTracks()
|
|
234
241
|
this.mount()
|
|
235
242
|
}
|
|
236
243
|
|
|
237
244
|
private onSubtitleChanged({ id: changedId }: { id: number }) {
|
|
238
245
|
// ignoring the subtitle selected by the playback engine or user agent
|
|
239
|
-
const id = this.
|
|
240
|
-
trace(`${T} onSubtitleChanged`, {
|
|
241
|
-
changedId,
|
|
242
|
-
id,
|
|
243
|
-
})
|
|
246
|
+
const id = this.currentTrack?.id ?? -1
|
|
244
247
|
if (id === -1) {
|
|
245
248
|
this.clearSubtitleText()
|
|
246
249
|
}
|
|
@@ -248,7 +251,11 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
248
251
|
}
|
|
249
252
|
|
|
250
253
|
private activateTrack(id: number) {
|
|
251
|
-
|
|
254
|
+
if (['dash', 'hls'].includes(this.core.activePlayback?.name)) {
|
|
255
|
+
this.core.activePlayback.setTextTrack(id)
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
for (const track of this.currentTracks) {
|
|
252
259
|
if (track.id === id) {
|
|
253
260
|
if (this.useNativeSubtitles) {
|
|
254
261
|
track.track.mode = 'showing'
|
|
@@ -272,7 +279,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
272
279
|
}
|
|
273
280
|
}
|
|
274
281
|
} else {
|
|
275
|
-
track.track.oncuechange =
|
|
282
|
+
track.track.oncuechange = () => { }
|
|
276
283
|
track.track.mode = 'disabled'
|
|
277
284
|
}
|
|
278
285
|
}
|
|
@@ -280,7 +287,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
280
287
|
|
|
281
288
|
private applyTracks() {
|
|
282
289
|
try {
|
|
283
|
-
|
|
290
|
+
// TODO ensure to apply only once
|
|
291
|
+
this.currentTracks = this.core.activePlayback.closedCaptionsTracks
|
|
284
292
|
this.applyPreselectedSubtitles()
|
|
285
293
|
this.render()
|
|
286
294
|
} catch (error) {
|
|
@@ -288,32 +296,12 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
288
296
|
}
|
|
289
297
|
}
|
|
290
298
|
|
|
291
|
-
// private onStartAd() {
|
|
292
|
-
// if (this.active && this.core.activeContainer) {
|
|
293
|
-
// this.hide()
|
|
294
|
-
// this.listenTo(
|
|
295
|
-
// this.core.activeContainer,
|
|
296
|
-
// 'container:advertisement:finish',
|
|
297
|
-
// this.onFinishAd,
|
|
298
|
-
// )
|
|
299
|
-
// }
|
|
300
|
-
// }
|
|
301
|
-
|
|
302
|
-
// private onFinishAd() {
|
|
303
|
-
// this.show()
|
|
304
|
-
// this.stopListening(
|
|
305
|
-
// this.core.activeContainer,
|
|
306
|
-
// 'container:advertisement:finish',
|
|
307
|
-
// this.onFinishAd,
|
|
308
|
-
// )
|
|
309
|
-
// }
|
|
310
|
-
|
|
311
299
|
private onContainerResize() {
|
|
312
300
|
const shouldShow =
|
|
313
301
|
this.core.activeContainer &&
|
|
314
302
|
isFullscreen(this.core.activeContainer.el) &&
|
|
315
|
-
this.
|
|
316
|
-
this.
|
|
303
|
+
this.currentTrack &&
|
|
304
|
+
this.currentTrack.track.mode &&
|
|
317
305
|
Browser.isiOS &&
|
|
318
306
|
this.active
|
|
319
307
|
|
|
@@ -339,10 +327,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
339
327
|
this.$el.find('#gplayer-cc-menu').hide()
|
|
340
328
|
this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false')
|
|
341
329
|
this.$line.hide()
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
t.track.mode = 'hidden'
|
|
345
|
-
}
|
|
330
|
+
for (const track of this.currentTracks) {
|
|
331
|
+
track.track.mode = 'hidden'
|
|
346
332
|
}
|
|
347
333
|
}
|
|
348
334
|
|
|
@@ -355,19 +341,20 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
355
341
|
if (
|
|
356
342
|
this.core.activeContainer &&
|
|
357
343
|
isFullscreen(this.core.activeContainer.el) &&
|
|
358
|
-
this.
|
|
359
|
-
this.
|
|
344
|
+
this.currentTrack &&
|
|
345
|
+
// this.currentTrack.track.mode &&
|
|
360
346
|
(Browser.isiOS || this.useNativeSubtitles)
|
|
361
347
|
) {
|
|
362
348
|
this.$line.hide()
|
|
363
|
-
this.
|
|
349
|
+
this.currentTrack.track.mode = 'showing'
|
|
364
350
|
} else {
|
|
365
351
|
this.$line.show()
|
|
366
352
|
}
|
|
367
353
|
}
|
|
368
354
|
|
|
369
355
|
private shouldRender() {
|
|
370
|
-
|
|
356
|
+
// this might not have been fully initialized yet since `render` is called from the parent class constructor
|
|
357
|
+
return this.currentTracks?.length > 0
|
|
371
358
|
}
|
|
372
359
|
|
|
373
360
|
private resizeFont() {
|
|
@@ -384,15 +371,18 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
384
371
|
* @internal
|
|
385
372
|
*/
|
|
386
373
|
override render() {
|
|
374
|
+
if (!this.shouldRender()) {
|
|
375
|
+
return this
|
|
376
|
+
}
|
|
387
377
|
if (!this.core.activeContainer) {
|
|
388
378
|
return this
|
|
389
379
|
}
|
|
390
380
|
|
|
391
381
|
this.$el.html(
|
|
392
382
|
ClosedCaptions.templateControl({
|
|
393
|
-
tracks: this.
|
|
383
|
+
tracks: this.currentTracks,
|
|
394
384
|
i18n: this.core.i18n,
|
|
395
|
-
current: this.
|
|
385
|
+
current: this.currentTrack?.id ?? -1,
|
|
396
386
|
}),
|
|
397
387
|
)
|
|
398
388
|
this.$el.find('#gplayer-cc-menu').hide()
|
|
@@ -411,13 +401,13 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
411
401
|
return this
|
|
412
402
|
}
|
|
413
403
|
|
|
414
|
-
private findById(id: number) {
|
|
415
|
-
return this.
|
|
404
|
+
private findById(id: number): TextTrackItem | null {
|
|
405
|
+
return this.currentTracks.find((track) => track.id === id) || null
|
|
416
406
|
}
|
|
417
407
|
|
|
418
408
|
private selectItem(item: TextTrackItem | null) {
|
|
419
409
|
this.clearSubtitleText()
|
|
420
|
-
this.
|
|
410
|
+
this.currentTrack = item
|
|
421
411
|
const trackId = item?.id ?? -1
|
|
422
412
|
this.core.activePlayback.closedCaptionsTrackId = trackId
|
|
423
413
|
|
|
@@ -489,7 +479,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
489
479
|
}
|
|
490
480
|
|
|
491
481
|
private selectSubtitles() {
|
|
492
|
-
const trackId = this.
|
|
482
|
+
const trackId = this.currentTrack?.id ?? -1
|
|
493
483
|
|
|
494
484
|
// TODO find out if this is needed
|
|
495
485
|
this.core.activePlayback.closedCaptionsTrackId = trackId
|
|
@@ -522,7 +512,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
522
512
|
}
|
|
523
513
|
|
|
524
514
|
private updateSelection() {
|
|
525
|
-
if (!this.
|
|
515
|
+
if (!this.currentTrack) {
|
|
526
516
|
this.hide()
|
|
527
517
|
} else {
|
|
528
518
|
this.show()
|
|
@@ -539,7 +529,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
539
529
|
.attr('aria-checked', 'false')
|
|
540
530
|
|
|
541
531
|
const currentLevelElement = this.itemElement(
|
|
542
|
-
this.
|
|
532
|
+
this.currentTrack?.id ?? -1,
|
|
543
533
|
)
|
|
544
534
|
currentLevelElement
|
|
545
535
|
.addClass('current')
|
|
@@ -569,9 +559,6 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
569
559
|
}
|
|
570
560
|
|
|
571
561
|
private get useNativeSubtitles() {
|
|
572
|
-
if (this.core.activePlayback?.name === 'dash') {
|
|
573
|
-
return true
|
|
574
|
-
}
|
|
575
562
|
const mode =
|
|
576
563
|
this.core.options.cc?.mode ??
|
|
577
564
|
this.core.options.subtitles?.mode ??
|
|
@@ -580,5 +567,25 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
580
567
|
return mode === 'native'
|
|
581
568
|
}
|
|
582
569
|
|
|
570
|
+
private get currentTracks(): TextTrackItem[] {
|
|
571
|
+
return this.tracks
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
private get currentTrack(): TextTrackItem | null {
|
|
575
|
+
return this.track
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
private set currentTrack(track: TextTrackItem | null) {
|
|
579
|
+
this.track = track
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private set currentTracks(tracks: TextTrackItem[]) {
|
|
583
|
+
this.tracks = tracks.map(track => ({
|
|
584
|
+
id: track.id,
|
|
585
|
+
name: !track.name || track.name === "null" ? track.track.language : track.name,
|
|
586
|
+
track: track.track,
|
|
587
|
+
}))
|
|
588
|
+
}
|
|
589
|
+
|
|
583
590
|
private clickaway = mediaControlClickaway(() => this.hideMenu())
|
|
584
591
|
}
|