@edm-webplayer/webplayer-angular 0.1.30 → 0.1.32
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.
|
@@ -78,10 +78,18 @@ class PlyrPlayerComponent {
|
|
|
78
78
|
recommendationBlocker;
|
|
79
79
|
recommendationBlockerActiveZone;
|
|
80
80
|
topClickBlocker;
|
|
81
|
+
gestureOverlay;
|
|
81
82
|
menuObserver;
|
|
82
83
|
playbackEnded = false;
|
|
83
84
|
overlayBlockAll = false;
|
|
84
|
-
|
|
85
|
+
endedPosterOverlay;
|
|
86
|
+
fullscreenCleanup;
|
|
87
|
+
interactionUnmuteCleanup;
|
|
88
|
+
pendingGesturePlay = false;
|
|
89
|
+
onResize = () => {
|
|
90
|
+
this.updateRecommendationBlockerSafeZone();
|
|
91
|
+
this.updateGestureOverlaySafeZone();
|
|
92
|
+
};
|
|
85
93
|
onTopBlockerPointerDown = (event) => {
|
|
86
94
|
try {
|
|
87
95
|
event.preventDefault();
|
|
@@ -105,7 +113,8 @@ class PlyrPlayerComponent {
|
|
|
105
113
|
}
|
|
106
114
|
this.togglePlayback();
|
|
107
115
|
};
|
|
108
|
-
|
|
116
|
+
controlsSafeZonePxDesktop = 96;
|
|
117
|
+
controlsSafeZonePxTouch = 144;
|
|
109
118
|
constructor(progressService, document) {
|
|
110
119
|
this.progressService = progressService;
|
|
111
120
|
this.document = document;
|
|
@@ -119,8 +128,9 @@ class PlyrPlayerComponent {
|
|
|
119
128
|
getControlsSafeZone() {
|
|
120
129
|
const controls = (this.plyr?.elements?.controls ?? null);
|
|
121
130
|
const menuHeight = this.getOpenMenuHeight();
|
|
131
|
+
const baseSafeZone = this.isTouchDevice() ? this.controlsSafeZonePxTouch : this.controlsSafeZonePxDesktop;
|
|
122
132
|
if (!controls) {
|
|
123
|
-
return Math.max(
|
|
133
|
+
return Math.max(baseSafeZone, menuHeight + 5);
|
|
124
134
|
}
|
|
125
135
|
let controlsHeight = 0;
|
|
126
136
|
try {
|
|
@@ -133,7 +143,7 @@ class PlyrPlayerComponent {
|
|
|
133
143
|
if (!controlsHeight) {
|
|
134
144
|
controlsHeight = controls.offsetHeight || controls.clientHeight || 0;
|
|
135
145
|
}
|
|
136
|
-
return Math.max(
|
|
146
|
+
return Math.max(baseSafeZone, Math.ceil(controlsHeight + menuHeight + 24));
|
|
137
147
|
}
|
|
138
148
|
getOverlaySafeZone() {
|
|
139
149
|
const host = this.config?.video_host;
|
|
@@ -336,13 +346,12 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
336
346
|
this.updateTopClickBlockerSafeZone();
|
|
337
347
|
}
|
|
338
348
|
updateRecommendationBlockerSafeZone() {
|
|
339
|
-
|
|
340
|
-
return;
|
|
341
|
-
const safeZone = this.getOverlaySafeZone();
|
|
349
|
+
const overlaySafeZone = this.getOverlaySafeZone();
|
|
342
350
|
if (this.recommendationBlockerActiveZone) {
|
|
343
|
-
this.recommendationBlockerActiveZone.style.bottom = `${
|
|
351
|
+
this.recommendationBlockerActiveZone.style.bottom = `${overlaySafeZone}px`;
|
|
344
352
|
}
|
|
345
|
-
this.updateTopClickBlockerSafeZone(
|
|
353
|
+
this.updateTopClickBlockerSafeZone(overlaySafeZone);
|
|
354
|
+
this.updateGestureOverlaySafeZone(this.getControlsSafeZone());
|
|
346
355
|
}
|
|
347
356
|
updateTopClickBlockerSafeZone(precomputed) {
|
|
348
357
|
if (!this.topClickBlocker)
|
|
@@ -351,6 +360,13 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
351
360
|
const safeZone = Math.max(0, safeZoneRaw);
|
|
352
361
|
this.topClickBlocker.style.bottom = `${safeZone}px`;
|
|
353
362
|
}
|
|
363
|
+
updateGestureOverlaySafeZone(precomputed) {
|
|
364
|
+
if (!this.gestureOverlay)
|
|
365
|
+
return;
|
|
366
|
+
const safeZoneRaw = typeof precomputed === 'number' ? precomputed : this.getControlsSafeZone();
|
|
367
|
+
const safeZone = Math.max(0, safeZoneRaw);
|
|
368
|
+
this.gestureOverlay.style.bottom = `${safeZone}px`;
|
|
369
|
+
}
|
|
354
370
|
togglePlayback(force) {
|
|
355
371
|
if (!this.plyr)
|
|
356
372
|
return;
|
|
@@ -382,6 +398,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
382
398
|
this.playbackEnded = false;
|
|
383
399
|
this.overlayBlockAll = false;
|
|
384
400
|
this.updateRecommendationBlockerSafeZone();
|
|
401
|
+
this.hideGestureOverlay();
|
|
385
402
|
try {
|
|
386
403
|
const result = this.plyr.play?.();
|
|
387
404
|
if (result && typeof result.catch === 'function') {
|
|
@@ -443,6 +460,19 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
443
460
|
});
|
|
444
461
|
this.menuObserver = observer;
|
|
445
462
|
}
|
|
463
|
+
isIOSDevice() {
|
|
464
|
+
if (typeof navigator === 'undefined')
|
|
465
|
+
return false;
|
|
466
|
+
const ua = navigator.userAgent || '';
|
|
467
|
+
const iOS = /iPad|iPhone|iPod/.test(ua);
|
|
468
|
+
const iPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1;
|
|
469
|
+
return iOS || iPadOS;
|
|
470
|
+
}
|
|
471
|
+
isAndroidDevice() {
|
|
472
|
+
if (typeof navigator === 'undefined')
|
|
473
|
+
return false;
|
|
474
|
+
return /Android/i.test(navigator.userAgent || '');
|
|
475
|
+
}
|
|
446
476
|
isTouchDevice() {
|
|
447
477
|
if (typeof window === 'undefined') {
|
|
448
478
|
return false;
|
|
@@ -460,6 +490,333 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
460
490
|
}
|
|
461
491
|
return 'ontouchstart' in window;
|
|
462
492
|
}
|
|
493
|
+
isIframeProvider() {
|
|
494
|
+
return this.config?.video_host === 'youtube' || this.config?.video_host === 'vimeo';
|
|
495
|
+
}
|
|
496
|
+
shouldAutoplay() {
|
|
497
|
+
return !!(this.config?.autoplay || this.config?.is_live);
|
|
498
|
+
}
|
|
499
|
+
requiresMutedAutoplay() {
|
|
500
|
+
return this.isIOSDevice();
|
|
501
|
+
}
|
|
502
|
+
setPlayerMutedState(muted, volume = 1, target) {
|
|
503
|
+
if (this.plyr) {
|
|
504
|
+
try {
|
|
505
|
+
this.plyr.muted = muted;
|
|
506
|
+
}
|
|
507
|
+
catch { }
|
|
508
|
+
if (!muted) {
|
|
509
|
+
try {
|
|
510
|
+
this.plyr.volume = volume;
|
|
511
|
+
}
|
|
512
|
+
catch { }
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const media = target ?? this.videoRef?.nativeElement ?? null;
|
|
516
|
+
if (media) {
|
|
517
|
+
try {
|
|
518
|
+
media.muted = muted;
|
|
519
|
+
}
|
|
520
|
+
catch { }
|
|
521
|
+
if (!muted && typeof media.volume === 'number') {
|
|
522
|
+
try {
|
|
523
|
+
media.volume = volume;
|
|
524
|
+
}
|
|
525
|
+
catch { }
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
clearAutoplayUnlockListener() {
|
|
530
|
+
if (this.interactionUnmuteCleanup) {
|
|
531
|
+
try {
|
|
532
|
+
this.interactionUnmuteCleanup();
|
|
533
|
+
}
|
|
534
|
+
catch { }
|
|
535
|
+
this.interactionUnmuteCleanup = undefined;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
ensureAutoplayUnlockListener() {
|
|
539
|
+
if (typeof window === 'undefined' ||
|
|
540
|
+
this.interactionUnmuteCleanup ||
|
|
541
|
+
!this.shouldAutoplay()) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const capture = true;
|
|
545
|
+
const handler = () => {
|
|
546
|
+
this.setPlayerMutedState(false);
|
|
547
|
+
try {
|
|
548
|
+
this.plyr?.play();
|
|
549
|
+
}
|
|
550
|
+
catch { }
|
|
551
|
+
this.clearAutoplayUnlockListener();
|
|
552
|
+
};
|
|
553
|
+
window.addEventListener('touchend', handler, capture);
|
|
554
|
+
window.addEventListener('pointerup', handler, capture);
|
|
555
|
+
window.addEventListener('click', handler, capture);
|
|
556
|
+
this.interactionUnmuteCleanup = () => {
|
|
557
|
+
window.removeEventListener('touchend', handler, capture);
|
|
558
|
+
window.removeEventListener('pointerup', handler, capture);
|
|
559
|
+
window.removeEventListener('click', handler, capture);
|
|
560
|
+
this.interactionUnmuteCleanup = undefined;
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
scheduleUserInteractionUnmute(video) {
|
|
564
|
+
this.unmuteAfterDelay(video || undefined);
|
|
565
|
+
this.ensureAutoplayUnlockListener();
|
|
566
|
+
}
|
|
567
|
+
applyStartTimeToCurrentSource(start, opts = {}) {
|
|
568
|
+
if (!this.plyr || !(start > 0)) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const video = opts.video ?? this.videoRef?.nativeElement ?? null;
|
|
572
|
+
let attempts = Math.max(1, opts.attempts ?? 6);
|
|
573
|
+
const delayMs = opts.delayMs ?? 250;
|
|
574
|
+
const tolerance = 0.35;
|
|
575
|
+
const scheduleRetry = () => {
|
|
576
|
+
attempts -= 1;
|
|
577
|
+
if (attempts > 0) {
|
|
578
|
+
setTimeout(trySeek, delayMs);
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
const verifyAfterAttempt = () => {
|
|
582
|
+
const current = this.plyr?.currentTime || 0;
|
|
583
|
+
if (Math.abs(current - start) <= tolerance) {
|
|
584
|
+
attempts = 0;
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
scheduleRetry();
|
|
588
|
+
};
|
|
589
|
+
const trySeek = () => {
|
|
590
|
+
if (!this.plyr)
|
|
591
|
+
return;
|
|
592
|
+
let maybePromise = null;
|
|
593
|
+
try {
|
|
594
|
+
const result = this.seekUsingHostAPI(start, video);
|
|
595
|
+
if (result && typeof result.then === 'function') {
|
|
596
|
+
maybePromise = result;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
scheduleRetry();
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (maybePromise) {
|
|
604
|
+
maybePromise
|
|
605
|
+
.then(() => verifyAfterAttempt())
|
|
606
|
+
.catch(() => scheduleRetry());
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
verifyAfterAttempt();
|
|
610
|
+
};
|
|
611
|
+
trySeek();
|
|
612
|
+
}
|
|
613
|
+
seekUsingHostAPI(target, video) {
|
|
614
|
+
if (!Number.isFinite(target) || target < 0) {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
if (this.config.video_host === 'vimeo') {
|
|
618
|
+
const embed = this.plyr?.embed;
|
|
619
|
+
if (embed && typeof embed.setCurrentTime === 'function') {
|
|
620
|
+
try {
|
|
621
|
+
return embed.setCurrentTime(target);
|
|
622
|
+
}
|
|
623
|
+
catch {
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (video) {
|
|
629
|
+
try {
|
|
630
|
+
video.currentTime = target;
|
|
631
|
+
}
|
|
632
|
+
catch { }
|
|
633
|
+
}
|
|
634
|
+
try {
|
|
635
|
+
this.plyr.currentTime = target;
|
|
636
|
+
}
|
|
637
|
+
catch { }
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
ensureGestureOverlay() {
|
|
641
|
+
if (this.gestureOverlay && this.gestureOverlay.isConnected) {
|
|
642
|
+
return this.gestureOverlay;
|
|
643
|
+
}
|
|
644
|
+
const wrapper = this.getVideoWrapper();
|
|
645
|
+
if (!wrapper) {
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
const overlay = this.document.createElement('button');
|
|
649
|
+
overlay.type = 'button';
|
|
650
|
+
overlay.className = 'plyr-gesture-overlay';
|
|
651
|
+
overlay.style.position = 'absolute';
|
|
652
|
+
overlay.style.top = '0';
|
|
653
|
+
overlay.style.left = '0';
|
|
654
|
+
overlay.style.right = '0';
|
|
655
|
+
overlay.style.bottom = '0';
|
|
656
|
+
overlay.style.width = '100%';
|
|
657
|
+
overlay.style.height = '100%';
|
|
658
|
+
overlay.style.display = 'none';
|
|
659
|
+
overlay.style.alignItems = 'center';
|
|
660
|
+
overlay.style.justifyContent = 'center';
|
|
661
|
+
overlay.style.padding = '0 16px';
|
|
662
|
+
overlay.style.background = 'rgba(0,0,0,0.35)';
|
|
663
|
+
overlay.style.backdropFilter = 'blur(1px)';
|
|
664
|
+
overlay.style.border = '0';
|
|
665
|
+
overlay.style.zIndex = '16';
|
|
666
|
+
overlay.style.color = 'var(--theme-text-color, #fff)';
|
|
667
|
+
overlay.style.fontSize = '14px';
|
|
668
|
+
overlay.style.fontWeight = '600';
|
|
669
|
+
overlay.style.textAlign = 'center';
|
|
670
|
+
overlay.style.cursor = 'pointer';
|
|
671
|
+
overlay.style.touchAction = 'manipulation';
|
|
672
|
+
overlay.style.pointerEvents = 'none';
|
|
673
|
+
overlay.textContent = 'Toque para reproduzir';
|
|
674
|
+
wrapper.appendChild(overlay);
|
|
675
|
+
this.gestureOverlay = overlay;
|
|
676
|
+
this.updateGestureOverlaySafeZone();
|
|
677
|
+
return overlay;
|
|
678
|
+
}
|
|
679
|
+
hideGestureOverlay() {
|
|
680
|
+
if (this.gestureOverlay) {
|
|
681
|
+
this.gestureOverlay.style.display = 'none';
|
|
682
|
+
this.gestureOverlay.style.pointerEvents = 'none';
|
|
683
|
+
}
|
|
684
|
+
this.pendingGesturePlay = false;
|
|
685
|
+
}
|
|
686
|
+
requestGestureToPlay(video) {
|
|
687
|
+
if (!this.isIframeProvider()) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
if (this.pendingGesturePlay) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const overlay = this.ensureGestureOverlay();
|
|
694
|
+
if (!overlay) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
this.pendingGesturePlay = true;
|
|
698
|
+
const media = video ?? this.videoRef?.nativeElement ?? null;
|
|
699
|
+
const onInteraction = (event) => {
|
|
700
|
+
try {
|
|
701
|
+
event.preventDefault();
|
|
702
|
+
}
|
|
703
|
+
catch { }
|
|
704
|
+
try {
|
|
705
|
+
event.stopPropagation();
|
|
706
|
+
}
|
|
707
|
+
catch { }
|
|
708
|
+
overlay.removeEventListener('click', onInteraction);
|
|
709
|
+
overlay.removeEventListener('touchend', onInteraction);
|
|
710
|
+
overlay.style.display = 'none';
|
|
711
|
+
this.pendingGesturePlay = false;
|
|
712
|
+
this.clearAutoplayUnlockListener();
|
|
713
|
+
this.setPlayerMutedState(this.requiresMutedAutoplay(), 1, media);
|
|
714
|
+
try {
|
|
715
|
+
const result = this.plyr?.play();
|
|
716
|
+
if (result && typeof result.catch === 'function') {
|
|
717
|
+
result.catch(() => {
|
|
718
|
+
this.requestGestureToPlay(media);
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
catch {
|
|
723
|
+
this.requestGestureToPlay(media);
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
overlay.addEventListener('click', onInteraction, { once: true });
|
|
727
|
+
overlay.addEventListener('touchend', onInteraction, { once: true });
|
|
728
|
+
this.updateGestureOverlaySafeZone();
|
|
729
|
+
overlay.style.pointerEvents = 'auto';
|
|
730
|
+
overlay.style.display = 'flex';
|
|
731
|
+
}
|
|
732
|
+
shouldShowGestureOverlayForError(error) {
|
|
733
|
+
if (!this.isIframeProvider()) {
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
if (!error) {
|
|
737
|
+
return true;
|
|
738
|
+
}
|
|
739
|
+
const err = error;
|
|
740
|
+
const name = typeof err.name === 'string' ? err.name.toLowerCase() : '';
|
|
741
|
+
const message = typeof err.message === 'string' ? err.message.toLowerCase() : '';
|
|
742
|
+
if (!name && !message) {
|
|
743
|
+
return true;
|
|
744
|
+
}
|
|
745
|
+
return (name.includes('notallowed') ||
|
|
746
|
+
name.includes('notallowederror') ||
|
|
747
|
+
name.includes('gesture') ||
|
|
748
|
+
message.includes('gesture') ||
|
|
749
|
+
message.includes('user interaction') ||
|
|
750
|
+
message.includes('user activation') ||
|
|
751
|
+
message.includes('without user') ||
|
|
752
|
+
message.includes('play() failed'));
|
|
753
|
+
}
|
|
754
|
+
startAutoplayFlow(video) {
|
|
755
|
+
if (!this.shouldAutoplay() || !this.plyr)
|
|
756
|
+
return;
|
|
757
|
+
const media = video ?? this.videoRef?.nativeElement ?? null;
|
|
758
|
+
const tryPlay = (muted) => {
|
|
759
|
+
this.setPlayerMutedState(muted, 1, media);
|
|
760
|
+
let playResult;
|
|
761
|
+
try {
|
|
762
|
+
playResult = this.plyr.play();
|
|
763
|
+
}
|
|
764
|
+
catch (error) {
|
|
765
|
+
if (!muted) {
|
|
766
|
+
tryPlay(true);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
if (media) {
|
|
770
|
+
try {
|
|
771
|
+
const nativePlay = media.play();
|
|
772
|
+
if (nativePlay && typeof nativePlay.catch === 'function') {
|
|
773
|
+
nativePlay.catch(() => { });
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
catch { }
|
|
777
|
+
}
|
|
778
|
+
this.scheduleUserInteractionUnmute(media);
|
|
779
|
+
if (this.shouldShowGestureOverlayForError(error)) {
|
|
780
|
+
this.requestGestureToPlay(media);
|
|
781
|
+
}
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
if (playResult && typeof playResult.catch === 'function') {
|
|
785
|
+
playResult.catch((error) => {
|
|
786
|
+
if (!muted) {
|
|
787
|
+
tryPlay(true);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
if (media) {
|
|
791
|
+
try {
|
|
792
|
+
const nativePlay = media.play();
|
|
793
|
+
if (nativePlay && typeof nativePlay.catch === 'function') {
|
|
794
|
+
nativePlay.catch(() => { });
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
catch { }
|
|
798
|
+
}
|
|
799
|
+
this.scheduleUserInteractionUnmute(media);
|
|
800
|
+
if (this.shouldShowGestureOverlayForError(error)) {
|
|
801
|
+
this.requestGestureToPlay(media);
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (muted) {
|
|
807
|
+
this.scheduleUserInteractionUnmute(media);
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
this.clearAutoplayUnlockListener();
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
if (this.requiresMutedAutoplay()) {
|
|
814
|
+
tryPlay(true);
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
tryPlay(false);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
463
820
|
setupControlsVisibility() {
|
|
464
821
|
const container = this.plyr?.elements?.container;
|
|
465
822
|
if (!container) {
|
|
@@ -570,19 +927,104 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
570
927
|
container.classList.remove('plyr--auto-hide-controls');
|
|
571
928
|
};
|
|
572
929
|
}
|
|
930
|
+
bindFullscreenBehavior() {
|
|
931
|
+
this.fullscreenCleanup?.();
|
|
932
|
+
this.fullscreenCleanup = undefined;
|
|
933
|
+
if (!this.plyr)
|
|
934
|
+
return;
|
|
935
|
+
if (this.isIOSDevice() || !this.isAndroidDevice()) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
if (typeof window === 'undefined' || typeof screen === 'undefined') {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
const orientation = screen.orientation;
|
|
942
|
+
const canLockOrientation = orientation && typeof orientation.lock === 'function' && typeof orientation.unlock === 'function';
|
|
943
|
+
if (!canLockOrientation) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
const isPortrait = () => {
|
|
947
|
+
if (typeof window.matchMedia === 'function') {
|
|
948
|
+
try {
|
|
949
|
+
return window.matchMedia('(orientation: portrait)').matches;
|
|
950
|
+
}
|
|
951
|
+
catch { }
|
|
952
|
+
}
|
|
953
|
+
return (window.innerHeight || 0) >= (window.innerWidth || 0);
|
|
954
|
+
};
|
|
955
|
+
let orientationLocked = false;
|
|
956
|
+
const lockLandscape = async () => {
|
|
957
|
+
if (!orientation)
|
|
958
|
+
return;
|
|
959
|
+
try {
|
|
960
|
+
await orientation.lock('landscape');
|
|
961
|
+
orientationLocked = true;
|
|
962
|
+
}
|
|
963
|
+
catch { }
|
|
964
|
+
};
|
|
965
|
+
const unlockOrientation = () => {
|
|
966
|
+
if (orientationLocked && orientation) {
|
|
967
|
+
try {
|
|
968
|
+
orientation.unlock();
|
|
969
|
+
}
|
|
970
|
+
catch { }
|
|
971
|
+
}
|
|
972
|
+
orientationLocked = false;
|
|
973
|
+
};
|
|
974
|
+
const onEnterFullscreen = () => {
|
|
975
|
+
if (isPortrait()) {
|
|
976
|
+
lockLandscape();
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
const onExitFullscreen = () => {
|
|
980
|
+
unlockOrientation();
|
|
981
|
+
};
|
|
982
|
+
const onOrientationChange = () => {
|
|
983
|
+
if (!this.plyr?.fullscreen?.active) {
|
|
984
|
+
unlockOrientation();
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
this.plyr.on('enterfullscreen', onEnterFullscreen);
|
|
988
|
+
this.plyr.on('exitfullscreen', onExitFullscreen);
|
|
989
|
+
window.addEventListener('orientationchange', onOrientationChange);
|
|
990
|
+
this.fullscreenCleanup = () => {
|
|
991
|
+
unlockOrientation();
|
|
992
|
+
this.plyr?.off('enterfullscreen', onEnterFullscreen);
|
|
993
|
+
this.plyr?.off('exitfullscreen', onExitFullscreen);
|
|
994
|
+
window.removeEventListener('orientationchange', onOrientationChange);
|
|
995
|
+
};
|
|
996
|
+
}
|
|
573
997
|
setupPlayer() {
|
|
574
998
|
if (!this.videoRef)
|
|
575
999
|
return;
|
|
576
1000
|
this.hls?.destroy();
|
|
577
1001
|
this.controlsVisibilityCleanup?.();
|
|
578
1002
|
this.controlsVisibilityCleanup = undefined;
|
|
1003
|
+
this.fullscreenCleanup?.();
|
|
1004
|
+
this.fullscreenCleanup = undefined;
|
|
579
1005
|
this.plyr?.destroy();
|
|
1006
|
+
this.clearAutoplayUnlockListener();
|
|
1007
|
+
this.hideGestureOverlay();
|
|
580
1008
|
this.recommendationBlocker = null;
|
|
581
1009
|
const speedOptions = [1, 1.25, 1.5, 2];
|
|
582
1010
|
const locale = this.resolveLocale();
|
|
583
1011
|
const captionsLanguage = this.resolveCaptionsLanguage(locale) ?? 'pt';
|
|
584
1012
|
const hideVimeoRecommendations = this.shouldHideVimeoRecommendations();
|
|
585
1013
|
const vimeoPremium = Boolean(this.config?.vimeo_premium);
|
|
1014
|
+
const shouldAutoplay = this.shouldAutoplay();
|
|
1015
|
+
const startMuted = this.requiresMutedAutoplay();
|
|
1016
|
+
try {
|
|
1017
|
+
this.videoRef.nativeElement.muted = startMuted;
|
|
1018
|
+
}
|
|
1019
|
+
catch { }
|
|
1020
|
+
try {
|
|
1021
|
+
this.videoRef.nativeElement.playsInline = true;
|
|
1022
|
+
}
|
|
1023
|
+
catch { }
|
|
1024
|
+
try {
|
|
1025
|
+
this.videoRef.nativeElement.autoplay = shouldAutoplay;
|
|
1026
|
+
}
|
|
1027
|
+
catch { }
|
|
586
1028
|
const vimeoOptions = {
|
|
587
1029
|
byline: false,
|
|
588
1030
|
portrait: false,
|
|
@@ -594,6 +1036,9 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
594
1036
|
quality: "auto",
|
|
595
1037
|
transparent: false,
|
|
596
1038
|
};
|
|
1039
|
+
vimeoOptions.autoplay = shouldAutoplay;
|
|
1040
|
+
vimeoOptions.muted = startMuted;
|
|
1041
|
+
vimeoOptions.playsinline = true;
|
|
597
1042
|
if (hideVimeoRecommendations) {
|
|
598
1043
|
vimeoOptions.controls = false;
|
|
599
1044
|
vimeoOptions.sidedock = 0;
|
|
@@ -609,6 +1054,9 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
609
1054
|
youtubePlayerVars.playerVars = {
|
|
610
1055
|
hl: locale,
|
|
611
1056
|
cc_lang_pref: captionsLanguage || locale.split('-')[0]?.toLowerCase(),
|
|
1057
|
+
autoplay: shouldAutoplay ? 1 : 0,
|
|
1058
|
+
mute: startMuted ? 1 : 0,
|
|
1059
|
+
playsinline: 1,
|
|
612
1060
|
};
|
|
613
1061
|
if (captionsLanguage) {
|
|
614
1062
|
youtubePlayerVars.playerVars.cc_load_policy = 1;
|
|
@@ -630,7 +1078,12 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
630
1078
|
],
|
|
631
1079
|
youtube: youtubePlayerVars,
|
|
632
1080
|
vimeo: vimeoOptions,
|
|
633
|
-
fullscreen: {
|
|
1081
|
+
fullscreen: {
|
|
1082
|
+
enabled: true,
|
|
1083
|
+
fallback: true,
|
|
1084
|
+
iosNative: true,
|
|
1085
|
+
container: null,
|
|
1086
|
+
},
|
|
634
1087
|
i18n: {
|
|
635
1088
|
speed: 'Velocidade',
|
|
636
1089
|
},
|
|
@@ -641,13 +1094,15 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
641
1094
|
clickToPlay: true,
|
|
642
1095
|
hideControls: false,
|
|
643
1096
|
keyboard: { focused: true, global: false },
|
|
644
|
-
|
|
1097
|
+
autoplay: shouldAutoplay,
|
|
1098
|
+
muted: startMuted,
|
|
645
1099
|
};
|
|
646
1100
|
plyrOptions.hl = locale;
|
|
647
1101
|
if (captionsLanguage) {
|
|
648
1102
|
plyrOptions.captions = { language: captionsLanguage };
|
|
649
1103
|
}
|
|
650
1104
|
this.plyr = new Plyr.default(this.videoRef.nativeElement, plyrOptions);
|
|
1105
|
+
this.bindFullscreenBehavior();
|
|
651
1106
|
this.setupControlsVisibility();
|
|
652
1107
|
this.ensureTopClickBlocker();
|
|
653
1108
|
this.observeMenuChanges();
|
|
@@ -668,8 +1123,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
668
1123
|
const apply = () => {
|
|
669
1124
|
const dur = this.plyr.duration || 0;
|
|
670
1125
|
const start = this.resolveStartTime(this.config.last_time, this.config.last_percent, dur);
|
|
671
|
-
|
|
672
|
-
this.plyr.currentTime = start;
|
|
1126
|
+
this.applyStartTimeToCurrentSource(start);
|
|
673
1127
|
this.plyr.off("ready", apply);
|
|
674
1128
|
};
|
|
675
1129
|
this.plyr.on("ready", apply);
|
|
@@ -698,12 +1152,14 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
698
1152
|
});
|
|
699
1153
|
};
|
|
700
1154
|
this.plyr?.on?.("play", () => {
|
|
1155
|
+
this.hideGestureOverlay();
|
|
701
1156
|
this.clearVimeoEndedState();
|
|
702
1157
|
this.playbackEnded = false;
|
|
703
1158
|
this.overlayBlockAll = false;
|
|
704
1159
|
this.updateRecommendationBlockerSafeZone();
|
|
705
1160
|
this.toggleRecommendationBlocker(false);
|
|
706
1161
|
parent.postMessage('playing_video', "*");
|
|
1162
|
+
console.log('event: playing_video');
|
|
707
1163
|
this.postCastEvent({ event: 'play', currentTime: this.plyr.currentTime || 0 });
|
|
708
1164
|
});
|
|
709
1165
|
this.plyr?.on?.("timeupdate", onTimeUpdate);
|
|
@@ -721,6 +1177,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
721
1177
|
this.playbackEnded = true;
|
|
722
1178
|
this.overlayBlockAll = true;
|
|
723
1179
|
this.updateRecommendationBlockerSafeZone();
|
|
1180
|
+
console.log('event: ended');
|
|
724
1181
|
parent.postMessage('event: ended', "*");
|
|
725
1182
|
this.postCastEvent({ event: 'ended', currentTime: this.plyr.currentTime || 0 });
|
|
726
1183
|
this.progressService.ended$.next();
|
|
@@ -729,7 +1186,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
729
1186
|
});
|
|
730
1187
|
}
|
|
731
1188
|
unmuteAfterDelay(video, delayMs = 2000, volume = 1) {
|
|
732
|
-
if (!this.
|
|
1189
|
+
if (!this.shouldAutoplay())
|
|
733
1190
|
return;
|
|
734
1191
|
setTimeout(() => {
|
|
735
1192
|
try {
|
|
@@ -784,13 +1241,8 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
784
1241
|
const onReady = () => {
|
|
785
1242
|
this.plyr.off("ready", onReady);
|
|
786
1243
|
const start = this.resolveStartTime(this.config.last_time, this.config.last_percent, this.plyr.duration);
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (this.config.autoplay || this.config.is_live) {
|
|
790
|
-
setTimeout(() => {
|
|
791
|
-
this.plyr.play();
|
|
792
|
-
}, 1500);
|
|
793
|
-
}
|
|
1244
|
+
this.applyStartTimeToCurrentSource(start);
|
|
1245
|
+
this.startAutoplayFlow();
|
|
794
1246
|
parent.postMessage('playerIsReadyToPlay', "*");
|
|
795
1247
|
parent.postMessage('duration:' + this.plyr.duration, "*");
|
|
796
1248
|
console.log('event: current_time ' + this.plyr.currentTime);
|
|
@@ -852,35 +1304,8 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
852
1304
|
const onLoadedMeta = () => {
|
|
853
1305
|
const dur = this.plyr.duration || video.duration || 0;
|
|
854
1306
|
const start = this.resolveStartTime(this.config.last_time, this.config.last_percent, dur);
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
this.plyr.currentTime = start;
|
|
858
|
-
}
|
|
859
|
-
catch {
|
|
860
|
-
try {
|
|
861
|
-
video.currentTime = start;
|
|
862
|
-
}
|
|
863
|
-
catch { }
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
if (this.config.autoplay) {
|
|
867
|
-
try {
|
|
868
|
-
video.muted = true;
|
|
869
|
-
}
|
|
870
|
-
catch { }
|
|
871
|
-
setTimeout(() => {
|
|
872
|
-
try {
|
|
873
|
-
this.plyr.play();
|
|
874
|
-
}
|
|
875
|
-
catch {
|
|
876
|
-
try {
|
|
877
|
-
video.play();
|
|
878
|
-
}
|
|
879
|
-
catch { }
|
|
880
|
-
}
|
|
881
|
-
this.unmuteAfterDelay(video);
|
|
882
|
-
}, 250);
|
|
883
|
-
}
|
|
1307
|
+
this.applyStartTimeToCurrentSource(start, { video });
|
|
1308
|
+
this.startAutoplayFlow(video);
|
|
884
1309
|
video.removeEventListener("loadedmetadata", onLoadedMeta);
|
|
885
1310
|
};
|
|
886
1311
|
video.addEventListener("loadedmetadata", onLoadedMeta);
|
|
@@ -894,17 +1319,8 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
894
1319
|
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
|
895
1320
|
const dur = video.duration || 0;
|
|
896
1321
|
const start = this.resolveStartTime(this.config.last_time, this.config.last_percent, dur);
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
video.currentTime = start;
|
|
900
|
-
}
|
|
901
|
-
catch { }
|
|
902
|
-
}
|
|
903
|
-
if (this.config.autoplay) {
|
|
904
|
-
video.muted = true;
|
|
905
|
-
video.play().catch(() => { });
|
|
906
|
-
this.unmuteAfterDelay(video);
|
|
907
|
-
}
|
|
1322
|
+
this.applyStartTimeToCurrentSource(start, { video });
|
|
1323
|
+
this.startAutoplayFlow(video);
|
|
908
1324
|
});
|
|
909
1325
|
this.hls.on(Hls.Events.ERROR, (_evt, data) => {
|
|
910
1326
|
if (data?.fatal) {
|
|
@@ -993,6 +1409,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
993
1409
|
this.hls?.destroy();
|
|
994
1410
|
this.controlsVisibilityCleanup?.();
|
|
995
1411
|
this.controlsVisibilityCleanup = undefined;
|
|
1412
|
+
this.clearAutoplayUnlockListener();
|
|
996
1413
|
const container = this.plyr?.elements?.container;
|
|
997
1414
|
container?.classList.remove("plyr--vimeo-ended");
|
|
998
1415
|
if (this.recommendationBlocker?.parentElement) {
|
|
@@ -1019,9 +1436,19 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
|
|
|
1019
1436
|
catch { }
|
|
1020
1437
|
}
|
|
1021
1438
|
this.topClickBlocker = null;
|
|
1439
|
+
if (this.gestureOverlay?.parentElement) {
|
|
1440
|
+
try {
|
|
1441
|
+
this.gestureOverlay.parentElement.removeChild(this.gestureOverlay);
|
|
1442
|
+
}
|
|
1443
|
+
catch { }
|
|
1444
|
+
}
|
|
1445
|
+
this.gestureOverlay = null;
|
|
1446
|
+
this.pendingGesturePlay = false;
|
|
1022
1447
|
this.menuObserver?.disconnect();
|
|
1023
1448
|
this.menuObserver = undefined;
|
|
1024
1449
|
window.removeEventListener('resize', this.onResize);
|
|
1450
|
+
this.fullscreenCleanup?.();
|
|
1451
|
+
this.fullscreenCleanup = undefined;
|
|
1025
1452
|
this.plyr?.destroy();
|
|
1026
1453
|
window.removeEventListener('message', this.onCastMessage);
|
|
1027
1454
|
}
|