@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
- onResize = () => this.updateRecommendationBlockerSafeZone();
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
- controlsSafeZonePx = 96;
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(this.controlsSafeZonePx, menuHeight + 5);
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(this.controlsSafeZonePx, Math.ceil(controlsHeight + menuHeight + 24));
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
- if (!this.recommendationBlockerActiveZone && !this.topClickBlocker)
340
- return;
341
- const safeZone = this.getOverlaySafeZone();
349
+ const overlaySafeZone = this.getOverlaySafeZone();
342
350
  if (this.recommendationBlockerActiveZone) {
343
- this.recommendationBlockerActiveZone.style.bottom = `${safeZone}px`;
351
+ this.recommendationBlockerActiveZone.style.bottom = `${overlaySafeZone}px`;
344
352
  }
345
- this.updateTopClickBlockerSafeZone(safeZone);
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: { enabled: true, fallback: true, iosNative: true, container: null },
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
- muted: false,
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
- if (start > 0)
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.config.autoplay)
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
- if (start > 0)
788
- this.plyr.currentTime = start;
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
- if (start > 0) {
856
- try {
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
- if (start > 0) {
898
- try {
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
  }