@grfzhl/vue-hls-player 1.1.25 → 1.1.27
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/README.md
CHANGED
|
@@ -207,6 +207,15 @@ At the moment the following attribute are supported:
|
|
|
207
207
|
```
|
|
208
208
|
|
|
209
209
|
### Last release:
|
|
210
|
+
v1.1.27
|
|
211
|
+
- Expose BasePlayer fullscreen control through wrapper components.
|
|
212
|
+
- Add support for forced fullscreen re-entry from parent integrations.
|
|
213
|
+
- Avoid fullscreen request errors when no user activation is available.
|
|
214
|
+
- Keep fullscreen state and emitted events in sync across native and document fullscreen modes.
|
|
215
|
+
v1.1.26
|
|
216
|
+
- Prevent HLS chunk preloading during player initialization.
|
|
217
|
+
- Start HLS loading only after user interaction.
|
|
218
|
+
- Fallback to the first video frame when no preview image is available.
|
|
210
219
|
v1.1.25
|
|
211
220
|
- Decouple audio language switching from subtitle selection.
|
|
212
221
|
- Preserve user-selected subtitle language across audio changes and HLS source reloads.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
</div>
|
|
9
9
|
<div class="media-overlay" v-if="initialPlayButton">
|
|
10
10
|
<div class="initial-play" :class="{'hide-playbutton': hideInitialPlayButton}">
|
|
11
|
-
<media-play-button mediapaused="" class="media-button" aria-label="play" tabindex="0" role="button" @click="
|
|
11
|
+
<media-play-button mediapaused="" class="media-button" aria-label="play" tabindex="0" role="button" @click="handleInitialPlay">
|
|
12
12
|
<svg slot="icon" viewBox="0 0 32 32">
|
|
13
13
|
<g>
|
|
14
14
|
<path id="icon-play" d="M20.7131 14.6976C21.7208 15.2735 21.7208 16.7265 20.7131 17.3024L12.7442 21.856C11.7442 22.4274 10.5 21.7054 10.5 20.5536L10.5 11.4464C10.5 10.2946 11.7442 9.57257 12.7442 10.144L20.7131 14.6976Z"></path>
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
ref="video"
|
|
32
32
|
:poster="previewImageLink"
|
|
33
33
|
:controls="false"
|
|
34
|
+
preload="none"
|
|
34
35
|
:title="title"
|
|
35
36
|
controlslist="nodownload"
|
|
36
37
|
playsinline
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
<track
|
|
45
46
|
v-if="subtitles.length"
|
|
46
47
|
v-for="(subtitle, i) in subtitles"
|
|
47
|
-
:key="subtitle.lang + '-' +
|
|
48
|
+
:key="subtitle.lang + '-' + currentAudioLang"
|
|
48
49
|
:src="subtitle.link"
|
|
49
50
|
kind="subtitles"
|
|
50
51
|
:srclang="subtitle.lang"
|
|
@@ -71,7 +72,7 @@
|
|
|
71
72
|
<slot name="between-video-and-transcript"></slot>
|
|
72
73
|
<slot name="before-transcripts"></slot>
|
|
73
74
|
<SubtitleBlock
|
|
74
|
-
:key="`${
|
|
75
|
+
:key="`${currentAudioLang}-${currentSubtitleLang}`"
|
|
75
76
|
ref="transcriptRef"
|
|
76
77
|
:subtitle="currentSubtitle"
|
|
77
78
|
:cursor="videoCursor"
|
|
@@ -215,6 +216,12 @@ const isUserInitiatedLangChange = ref(false)
|
|
|
215
216
|
|
|
216
217
|
let initialLoad = true;
|
|
217
218
|
let defaultApplied = false
|
|
219
|
+
const hlsInitialized = ref(false)
|
|
220
|
+
const hlsInitializing = ref(false)
|
|
221
|
+
const pendingPlayRequest = ref(false)
|
|
222
|
+
const pendingSeekTime = ref(null)
|
|
223
|
+
const previewFramePrimed = ref(false)
|
|
224
|
+
const previewFrameLoading = ref(false)
|
|
218
225
|
|
|
219
226
|
watch(
|
|
220
227
|
() => props.defaultLang,
|
|
@@ -348,8 +355,15 @@ function emitPointerUpdate() {
|
|
|
348
355
|
|
|
349
356
|
const videoElement = defineModel()
|
|
350
357
|
|
|
358
|
+
defineExpose({ startFullscreen })
|
|
359
|
+
|
|
351
360
|
onMounted(() => {
|
|
352
|
-
|
|
361
|
+
if (video.value) {
|
|
362
|
+
video.value.muted = mutedAttr.value
|
|
363
|
+
video.value.currentTime = props.progress
|
|
364
|
+
}
|
|
365
|
+
initVideo()
|
|
366
|
+
maybeLoadFirstFrame()
|
|
353
367
|
})
|
|
354
368
|
|
|
355
369
|
onUnmounted(() => {
|
|
@@ -384,75 +398,100 @@ const currentSubtitle = computed(() => {
|
|
|
384
398
|
return props.subtitles[0];
|
|
385
399
|
})
|
|
386
400
|
|
|
387
|
-
watch(() => props.autoplay, (
|
|
388
|
-
if(
|
|
389
|
-
|
|
390
|
-
a[1].muted = true
|
|
391
|
-
setTimeout(() => {
|
|
392
|
-
a[1].play().catch(err => console.warn("Autoplay-Error:", err));
|
|
393
|
-
}, 200)
|
|
401
|
+
watch(() => props.autoplay, (autoplay) => {
|
|
402
|
+
if (!autoplay || !video.value || !video.value.paused) {
|
|
403
|
+
return
|
|
394
404
|
}
|
|
405
|
+
|
|
406
|
+
video.value.muted = true
|
|
407
|
+
setTimeout(() => {
|
|
408
|
+
handleInitialPlay().catch(err => console.warn("Autoplay-Error:", err))
|
|
409
|
+
}, 200)
|
|
395
410
|
})
|
|
396
411
|
|
|
397
412
|
watch(
|
|
398
413
|
() => props.link,
|
|
399
414
|
(newLink, oldLink) => {
|
|
400
|
-
|
|
401
|
-
|
|
415
|
+
if (newLink !== oldLink) {
|
|
416
|
+
resetPlayer()
|
|
417
|
+
maybeLoadFirstFrame()
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
function updateFullscreenButtonState(isActive) {
|
|
423
|
+
if (!buttonElement) return
|
|
424
|
+
|
|
425
|
+
buttonElement.setAttribute(
|
|
426
|
+
'aria-label',
|
|
427
|
+
isActive ? 'Exit fullscreen mode' : 'Enter fullscreen mode'
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
if (isActive) {
|
|
431
|
+
buttonElement.setAttribute('mediaIsFullscreen', '')
|
|
432
|
+
} else {
|
|
433
|
+
buttonElement.removeAttribute('mediaIsFullscreen')
|
|
402
434
|
}
|
|
403
|
-
})
|
|
404
435
|
|
|
405
|
-
|
|
436
|
+
const tooltip = buttonElement.shadowRoot?.querySelector('media-tooltip')
|
|
437
|
+
const enterTooltip = tooltip?.querySelector('slot[name="tooltip-enter"]')
|
|
438
|
+
const exitTooltip = tooltip?.querySelector('slot[name="tooltip-exit"]')
|
|
439
|
+
|
|
440
|
+
if (enterTooltip) {
|
|
441
|
+
enterTooltip.style.display = isActive ? 'none' : 'block'
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (exitTooltip) {
|
|
445
|
+
exitTooltip.style.display = isActive ? 'block' : 'none'
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async function startFullscreen(forceEnter = false) {
|
|
406
450
|
let vpVideoBlock = document.getElementById(props.fullScreenElement);
|
|
451
|
+
const hasDocumentFullscreen = !!document.fullscreenElement;
|
|
452
|
+
const hasNativeVideoFullscreen = !!video.value?.webkitDisplayingFullscreen;
|
|
453
|
+
const hasUserActivation =
|
|
454
|
+
typeof navigator === 'undefined' ||
|
|
455
|
+
!navigator.userActivation ||
|
|
456
|
+
navigator.userActivation.isActive;
|
|
407
457
|
if(video.value) {
|
|
408
458
|
currentTime = video.value.currentTime
|
|
409
459
|
}
|
|
410
|
-
if (
|
|
460
|
+
if (forceEnter && (hasDocumentFullscreen || hasNativeVideoFullscreen)) {
|
|
461
|
+
isFullscreen.value = true;
|
|
462
|
+
emit('video-fullscreen-change', true)
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Browsers only allow fullscreen requests from a short-lived user interaction.
|
|
467
|
+
if (forceEnter && !hasUserActivation) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (hasDocumentFullscreen || hasNativeVideoFullscreen) {
|
|
411
472
|
if (screen.orientation && screen.orientation.unlock) {
|
|
412
473
|
screen.orientation.unlock();
|
|
413
474
|
}
|
|
414
|
-
|
|
475
|
+
if (document.fullscreenElement && typeof document.exitFullscreen === 'function') {
|
|
476
|
+
await document.exitFullscreen();
|
|
477
|
+
}
|
|
415
478
|
if (/iPhone|iPad|AppleWebKit/i.test(navigator.userAgent)) {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (tooltip) {
|
|
423
|
-
// Slots für Tooltip-Enter und Tooltip-Exit finden
|
|
424
|
-
const enterTooltip = tooltip.querySelector('slot[name="tooltip-enter"]');
|
|
425
|
-
const exitTooltip = tooltip.querySelector('slot[name="tooltip-exit"]');
|
|
426
|
-
|
|
427
|
-
if (enterTooltip && exitTooltip) {
|
|
428
|
-
enterTooltip.style.display = 'block';
|
|
429
|
-
exitTooltip.style.display = 'none';
|
|
430
|
-
} else {
|
|
431
|
-
console.warn("Tooltip-Slots nicht gefunden!");
|
|
479
|
+
if (typeof video.value?.webkitExitFullscreen === 'function') {
|
|
480
|
+
video.value.webkitExitFullscreen();
|
|
481
|
+
} else if (typeof video.value?.webkitExitFullScreen === 'function') {
|
|
482
|
+
video.value.webkitExitFullScreen();
|
|
483
|
+
} else if (typeof document.webkitExitFullscreen === 'function') {
|
|
484
|
+
document.webkitExitFullscreen();
|
|
432
485
|
}
|
|
433
|
-
} else {
|
|
434
|
-
console.warn("Kein media-tooltip gefunden!");
|
|
435
486
|
}
|
|
487
|
+
isFullscreen.value = false;
|
|
488
|
+
emit('video-fullscreen-change', false)
|
|
489
|
+
updateFullscreenButtonState(false)
|
|
436
490
|
} else {
|
|
437
491
|
isFullscreen.value = true;
|
|
492
|
+
emit('video-fullscreen-change', true)
|
|
438
493
|
try {
|
|
439
|
-
|
|
440
|
-
buttonElement.setAttribute('mediaIsFullscreen', '');
|
|
441
|
-
const tooltip = buttonElement.shadowRoot?.querySelector('media-tooltip');
|
|
442
|
-
if (tooltip) {
|
|
443
|
-
// Slots für Tooltip-Enter und Tooltip-Exit finden
|
|
444
|
-
const enterTooltip = tooltip.querySelector('slot[name="tooltip-enter"]');
|
|
445
|
-
const exitTooltip = tooltip.querySelector('slot[name="tooltip-exit"]');
|
|
446
|
-
|
|
447
|
-
if (enterTooltip && exitTooltip) {
|
|
448
|
-
enterTooltip.style.display = 'none';
|
|
449
|
-
exitTooltip.style.display = 'block';
|
|
450
|
-
} else {
|
|
451
|
-
console.warn("Tooltip-Slots nicht gefunden!");
|
|
452
|
-
}
|
|
453
|
-
} else {
|
|
454
|
-
console.warn("Kein media-tooltip gefunden!");
|
|
455
|
-
}
|
|
494
|
+
updateFullscreenButtonState(true)
|
|
456
495
|
|
|
457
496
|
if (vpVideoBlock.requestFullscreen) {
|
|
458
497
|
await vpVideoBlock.requestFullscreen();
|
|
@@ -465,6 +504,7 @@ async function startFullscreen() {
|
|
|
465
504
|
vpVideoBlock.style.height = "auto";
|
|
466
505
|
}, 100);
|
|
467
506
|
isFullscreen.value = false;
|
|
507
|
+
emit('video-fullscreen-change', false)
|
|
468
508
|
vpVideoBlock.removeEventListener("webkitendfullscreen")
|
|
469
509
|
});
|
|
470
510
|
} else if (vpVideoBlock.mozRequestFullScreen) {
|
|
@@ -476,14 +516,15 @@ async function startFullscreen() {
|
|
|
476
516
|
try {
|
|
477
517
|
await screen.orientation.lock("landscape");
|
|
478
518
|
} catch (error) {
|
|
479
|
-
|
|
519
|
+
// ignore unsupported mobile/browser orientation lock failures
|
|
480
520
|
}
|
|
481
|
-
} else {
|
|
482
|
-
console.warn("Orientation lock not supported.");
|
|
483
521
|
}
|
|
484
522
|
} catch (error) {
|
|
485
|
-
|
|
523
|
+
if (!forceEnter) {
|
|
524
|
+
console.error("Fullscreen could not be activated", error);
|
|
525
|
+
}
|
|
486
526
|
isFullscreen.value = false;
|
|
527
|
+
emit('video-fullscreen-change', false)
|
|
487
528
|
}
|
|
488
529
|
|
|
489
530
|
video.value.currentTime = currentTime;
|
|
@@ -505,6 +546,7 @@ function onFullscreenChange(e) {
|
|
|
505
546
|
autoHideIntroTitle.value = false;
|
|
506
547
|
}
|
|
507
548
|
isFullscreen.value = !!document.fullscreenElement;
|
|
549
|
+
emit('video-fullscreen-change', isFullscreen.value)
|
|
508
550
|
};
|
|
509
551
|
|
|
510
552
|
function onOrientationChange(e) {
|
|
@@ -547,13 +589,130 @@ function toggleTranscript() {
|
|
|
547
589
|
props.showTranscriptBlock = !props.showTranscriptBlock
|
|
548
590
|
}
|
|
549
591
|
|
|
550
|
-
function
|
|
551
|
-
|
|
552
|
-
video.value.play()
|
|
592
|
+
async function handleInitialPlay() {
|
|
593
|
+
await startPlayback()
|
|
553
594
|
}
|
|
554
595
|
|
|
555
|
-
function
|
|
556
|
-
if (!video.value) return
|
|
596
|
+
async function startPlayback() {
|
|
597
|
+
if (!video.value) return
|
|
598
|
+
|
|
599
|
+
pendingPlayRequest.value = true
|
|
600
|
+
pendingSeekTime.value = null
|
|
601
|
+
initialPlayButton.value = false
|
|
602
|
+
|
|
603
|
+
if (!hlsInitialized.value) {
|
|
604
|
+
initPlayer(props.link)
|
|
605
|
+
return
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (previewFrameLoading.value && !previewFramePrimed.value) {
|
|
609
|
+
return
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
resumePreviewFrameStream()
|
|
613
|
+
|
|
614
|
+
try {
|
|
615
|
+
await video.value.play()
|
|
616
|
+
pendingPlayRequest.value = false
|
|
617
|
+
} catch (err) {
|
|
618
|
+
console.warn('[HLS] Play start failed:', err)
|
|
619
|
+
initialPlayButton.value = true
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function initPlayer(src, { previewOnly = false } = {}) {
|
|
624
|
+
if (!video.value || !src || hlsInitialized.value || hlsInitializing.value) return
|
|
625
|
+
|
|
626
|
+
hlsInitializing.value = true
|
|
627
|
+
|
|
628
|
+
try {
|
|
629
|
+
prepareVideoPlayer(src, { previewOnly })
|
|
630
|
+
hlsInitialized.value = true
|
|
631
|
+
} finally {
|
|
632
|
+
hlsInitializing.value = false
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function maybeLoadFirstFrame() {
|
|
637
|
+
if (
|
|
638
|
+
props.previewImageLink ||
|
|
639
|
+
!props.link ||
|
|
640
|
+
!video.value ||
|
|
641
|
+
hlsInitialized.value ||
|
|
642
|
+
hlsInitializing.value
|
|
643
|
+
) {
|
|
644
|
+
return
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
initPlayer(props.link, { previewOnly: true })
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function resumePreviewFrameStream() {
|
|
651
|
+
if (!previewFramePrimed.value || !hls || !video.value) return
|
|
652
|
+
|
|
653
|
+
previewFramePrimed.value = false
|
|
654
|
+
hls.startLoad(video.value.currentTime || 0)
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function resetPlayer() {
|
|
658
|
+
hlsInitialized.value = false
|
|
659
|
+
hlsInitializing.value = false
|
|
660
|
+
pendingPlayRequest.value = false
|
|
661
|
+
pendingSeekTime.value = null
|
|
662
|
+
previewFramePrimed.value = false
|
|
663
|
+
previewFrameLoading.value = false
|
|
664
|
+
initialPlayButton.value = true
|
|
665
|
+
hideInitialPlayButton.value = false
|
|
666
|
+
|
|
667
|
+
if (hls) {
|
|
668
|
+
hls.detachMedia()
|
|
669
|
+
hls.destroy()
|
|
670
|
+
hls = null
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (!video.value) return
|
|
674
|
+
|
|
675
|
+
video.value.pause()
|
|
676
|
+
video.value.removeAttribute('src')
|
|
677
|
+
const source = video.value.querySelector('source')
|
|
678
|
+
if (source) {
|
|
679
|
+
source.removeAttribute('src')
|
|
680
|
+
}
|
|
681
|
+
video.value.load()
|
|
682
|
+
video.value.currentTime = props.progress
|
|
683
|
+
video.value.muted = mutedAttr.value
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
async function seekVideo(time) {
|
|
687
|
+
if (!video.value) return
|
|
688
|
+
|
|
689
|
+
if (!hlsInitialized.value) {
|
|
690
|
+
pendingSeekTime.value = time
|
|
691
|
+
pendingPlayRequest.value = true
|
|
692
|
+
initPlayer(props.link)
|
|
693
|
+
return
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (previewFrameLoading.value && !previewFramePrimed.value) {
|
|
697
|
+
pendingSeekTime.value = time
|
|
698
|
+
pendingPlayRequest.value = true
|
|
699
|
+
return
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
resumePreviewFrameStream()
|
|
703
|
+
video.value.currentTime = time
|
|
704
|
+
|
|
705
|
+
try {
|
|
706
|
+
await video.value.play()
|
|
707
|
+
pendingPlayRequest.value = false
|
|
708
|
+
pendingSeekTime.value = null
|
|
709
|
+
} catch (err) {
|
|
710
|
+
console.warn('[HLS] Seek play failed:', err)
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function prepareVideoPlayer(link, { previewOnly = false } = {}) {
|
|
715
|
+
if (!video.value || !link) return;
|
|
557
716
|
|
|
558
717
|
// Reset previous HLS instance
|
|
559
718
|
if (hls) {
|
|
@@ -561,15 +720,68 @@ function prepareVideoPlayer(link) {
|
|
|
561
720
|
hls.destroy();
|
|
562
721
|
}
|
|
563
722
|
|
|
723
|
+
const playerHlsConfig = {
|
|
724
|
+
...hlsConfig,
|
|
725
|
+
autoStartLoad: !previewOnly,
|
|
726
|
+
};
|
|
727
|
+
|
|
564
728
|
// Preparing video player with link: ${link}
|
|
565
|
-
hls = new Hls(
|
|
729
|
+
hls = new Hls(playerHlsConfig);
|
|
566
730
|
// Attach HLS
|
|
567
731
|
hls.loadSource(link);
|
|
568
732
|
hls.attachMedia(video.value);
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
733
|
+
hls.once(Hls.Events.MANIFEST_PARSED, async () => {
|
|
734
|
+
if (!video.value) return;
|
|
735
|
+
|
|
736
|
+
video.value.muted = mutedAttr.value;
|
|
737
|
+
video.value.currentTime = pendingSeekTime.value ?? props.progress;
|
|
738
|
+
|
|
739
|
+
if (previewOnly) {
|
|
740
|
+
previewFrameLoading.value = true;
|
|
741
|
+
video.value.addEventListener('loadeddata', async () => {
|
|
742
|
+
previewFrameLoading.value = false;
|
|
743
|
+
|
|
744
|
+
if (!video.value || !hls) return;
|
|
745
|
+
|
|
746
|
+
video.value.pause();
|
|
747
|
+
|
|
748
|
+
if (!pendingPlayRequest.value) {
|
|
749
|
+
previewFramePrimed.value = true;
|
|
750
|
+
hls.stopLoad();
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
previewFramePrimed.value = false;
|
|
755
|
+
hls.startLoad(video.value.currentTime || 0);
|
|
756
|
+
|
|
757
|
+
if (pendingSeekTime.value != null) {
|
|
758
|
+
video.value.currentTime = pendingSeekTime.value;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
try {
|
|
762
|
+
await video.value.play();
|
|
763
|
+
pendingPlayRequest.value = false;
|
|
764
|
+
pendingSeekTime.value = null;
|
|
765
|
+
} catch (err) {
|
|
766
|
+
console.warn('[HLS] Play after first frame failed:', err);
|
|
767
|
+
initialPlayButton.value = true;
|
|
768
|
+
}
|
|
769
|
+
}, { once: true });
|
|
770
|
+
|
|
771
|
+
hls.startLoad(0);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (!pendingPlayRequest.value) return;
|
|
776
|
+
|
|
777
|
+
try {
|
|
778
|
+
await video.value.play();
|
|
779
|
+
pendingPlayRequest.value = false;
|
|
780
|
+
pendingSeekTime.value = null;
|
|
781
|
+
} catch (err) {
|
|
782
|
+
console.warn('[HLS] Play after manifest failed:', err);
|
|
783
|
+
initialPlayButton.value = true;
|
|
784
|
+
}
|
|
573
785
|
});
|
|
574
786
|
// Native subtitle handling – without polling
|
|
575
787
|
Array.from(video.value?.textTracks || []).forEach(track => {
|
|
@@ -615,7 +827,6 @@ function prepareVideoPlayer(link) {
|
|
|
615
827
|
video.value.currentTime = props.progress;
|
|
616
828
|
// Chrome-like: update menu whenever track mode changes
|
|
617
829
|
video.value.textTracks.addEventListener('change', updateLangMenuState);
|
|
618
|
-
initVideo(); // Init controls etc.
|
|
619
830
|
}
|
|
620
831
|
|
|
621
832
|
|
|
@@ -118,7 +118,7 @@ function onFullscreenChange(data) {
|
|
|
118
118
|
function onLanguageChanged(data) {
|
|
119
119
|
emit('language-changed', data);
|
|
120
120
|
}
|
|
121
|
-
function startFullscreen() {
|
|
122
|
-
childRef.value
|
|
121
|
+
function startFullscreen(forceEnter = false) {
|
|
122
|
+
return childRef.value?.startFullscreen?.(forceEnter)
|
|
123
123
|
}
|
|
124
124
|
</script>
|
|
@@ -120,7 +120,7 @@ function onVideoFullScreenChange(data) {
|
|
|
120
120
|
function onVideoEnd(data) {
|
|
121
121
|
emit('video-ended', data);
|
|
122
122
|
}
|
|
123
|
-
function startFullscreen() {
|
|
124
|
-
childRef.value
|
|
123
|
+
function startFullscreen(forceEnter = false) {
|
|
124
|
+
return childRef.value?.startFullscreen?.(forceEnter)
|
|
125
125
|
}
|
|
126
126
|
</script>
|