stormcloud-video-player 0.2.32 → 0.2.34

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/lib/index.cjs CHANGED
@@ -289,7 +289,7 @@ function createImaController(video, options) {
289
289
  video.muted = true;
290
290
  video.volume = 0;
291
291
  contentVideoHidden = true;
292
- console.log("[IMA] Content video hidden and muted");
292
+ console.log("[DEBUG-LAYER] \u{1F534} Content video HIDDEN | muted=true, volume=0");
293
293
  }
294
294
  }
295
295
  function showContentVideo() {
@@ -302,7 +302,7 @@ function createImaController(video, options) {
302
302
  video.volume = originalVolume;
303
303
  contentVideoHidden = false;
304
304
  console.log(
305
- `[IMA] Content video restored (muted: ${originalMutedState}, volume: ${originalVolume})`
305
+ `[DEBUG-LAYER] \u{1F7E2} Content video RESTORED | muted=${originalMutedState}, volume=${originalVolume}`
306
306
  );
307
307
  }
308
308
  }
@@ -324,12 +324,12 @@ function createImaController(video, options) {
324
324
  "canplay",
325
325
  () => {
326
326
  adVideo.style.opacity = "1";
327
- console.log("[IMA] Ad video ready to play");
327
+ console.log("[DEBUG-LAYER] \u{1F4FA} Ad video element ready (canplay fired)");
328
328
  },
329
329
  { once: true }
330
330
  );
331
331
  console.log(
332
- `[IMA] Created dedicated ad video element with volume: ${adVideo.volume}, muted: ${adVideo.muted}`
332
+ `[DEBUG-AUDIO] \u{1F50A} Ad video created | volume=${adVideo.volume}, muted=${adVideo.muted}`
333
333
  );
334
334
  return adVideo;
335
335
  }
@@ -419,9 +419,6 @@ function createImaController(video, options) {
419
419
  const preloadedResponse = preloadedVast.get(vastTagUrl);
420
420
  if (preloadedResponse) {
421
421
  adsRequest.adsResponse = preloadedResponse;
422
- console.log(
423
- "[IMA] Using preloaded VAST response for immediate ad request"
424
- );
425
422
  } else {
426
423
  adsRequest.adTagUrl = vastTagUrl;
427
424
  }
@@ -448,7 +445,6 @@ function createImaController(video, options) {
448
445
  }
449
446
  }
450
447
  adsRequest.vastLoadTimeout = 5e3;
451
- console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
452
448
  adsLoader.requestAds(adsRequest);
453
449
  if (preloadedResponse) {
454
450
  preloadedVast.delete(vastTagUrl);
@@ -527,22 +523,24 @@ function createImaController(video, options) {
527
523
  });
528
524
  },
529
525
  async requestAds(vastTagUrl) {
530
- console.log("[IMA] Requesting ads:", vastTagUrl);
526
+ console.log("[IMA] \u{1F4E1} === requestAds() called ===");
527
+ console.log("[IMA] VAST URL:", vastTagUrl);
528
+ console.log("[IMA] This will fetch the ad from the server - no visual change yet");
531
529
  if (!vastTagUrl || vastTagUrl.trim() === "") {
532
530
  const error = new Error("VAST tag URL is empty or undefined");
533
- console.warn("[IMA]", error.message);
531
+ console.warn("[IMA] \u274C", error.message);
534
532
  return Promise.reject(error);
535
533
  }
536
534
  try {
537
535
  new URL(vastTagUrl);
538
536
  } catch (e) {
539
537
  const error = new Error(`Invalid VAST tag URL format: ${vastTagUrl}`);
540
- console.warn("[IMA]", error.message);
538
+ console.warn("[IMA] \u274C", error.message);
541
539
  return Promise.reject(error);
542
540
  }
543
541
  if (adPlaying) {
544
542
  console.warn(
545
- "[IMA] Cannot request new ads while an ad is playing. Call stop() first."
543
+ "[IMA] \u26A0\uFE0F Cannot request new ads while an ad is playing. Call stop() first."
546
544
  );
547
545
  return Promise.reject(
548
546
  new Error("Ad already playing - cannot request new ads")
@@ -632,20 +630,29 @@ function createImaController(video, options) {
632
630
  adsLoader.addEventListener(
633
631
  google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
634
632
  (evt) => {
635
- console.log(
636
- "[IMA] Ads manager loaded - enabling preloading for continuous playback"
637
- );
633
+ console.log("[DEBUG-FLOW] \u2705 ADS_MANAGER_LOADED - Setting up manager");
638
634
  try {
639
635
  const adsRenderingSettings = new google.ima.AdsRenderingSettings();
640
636
  adsRenderingSettings.enablePreloading = true;
641
637
  adsManager = evt.getAdsManager(video, adsRenderingSettings);
642
638
  const AdEvent = google.ima.AdEvent.Type;
643
639
  const AdErrorEvent = google.ima.AdErrorEvent.Type;
640
+ const keyEvents = ["STARTED", "COMPLETE", "CONTENT_PAUSE_REQUESTED", "CONTENT_RESUME_REQUESTED", "ALL_ADS_COMPLETED"];
641
+ keyEvents.forEach((eventType) => {
642
+ if (AdEvent[eventType]) {
643
+ adsManager.addEventListener(AdEvent[eventType], (e) => {
644
+ var _a, _b;
645
+ const ad = (_a = e.getAd) == null ? void 0 : _a.call(e);
646
+ console.log(`[DEBUG-FLOW] \u{1F3AC} ${eventType} | title=${((_b = ad == null ? void 0 : ad.getTitle) == null ? void 0 : _b.call(ad)) || "N/A"}`);
647
+ });
648
+ }
649
+ });
644
650
  adsManager.addEventListener(
645
651
  AdErrorEvent.AD_ERROR,
646
652
  (errorEvent) => {
647
- var _a;
648
- console.error("[IMA] Ad error:", errorEvent.getError());
653
+ var _a, _b;
654
+ const error = errorEvent.getError();
655
+ console.error("[DEBUG-ERROR] \u274C AD_ERROR:", (_a = error.getMessage) == null ? void 0 : _a.call(error));
649
656
  destroyAdsManager();
650
657
  adPlaying = false;
651
658
  setAdPlayingFlag(false);
@@ -656,7 +663,7 @@ function createImaController(video, options) {
656
663
  if (adContainerEl) {
657
664
  adContainerEl.style.pointerEvents = "none";
658
665
  adContainerEl.style.display = "none";
659
- console.log("[IMA] Ad container hidden after error");
666
+ console.log("[DEBUG-LAYER] \u274C Ad container HIDDEN (error)");
660
667
  }
661
668
  }, 300);
662
669
  }
@@ -668,9 +675,6 @@ function createImaController(video, options) {
668
675
  }
669
676
  if (lastAdTagUrl && retryAttempts < maxRetries) {
670
677
  const delay = backoffBaseMs * Math.pow(2, retryAttempts++);
671
- console.log(
672
- `[IMA] Retrying ad request in ${delay}ms (attempt ${retryAttempts})`
673
- );
674
678
  window.setTimeout(() => {
675
679
  try {
676
680
  makeAdsRequest(google, lastAdTagUrl);
@@ -678,16 +682,10 @@ function createImaController(video, options) {
678
682
  }
679
683
  }, delay);
680
684
  } else {
681
- console.log(
682
- "[IMA] Max retries reached, emitting ad_error"
683
- );
684
685
  emit("ad_error");
685
686
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
686
687
  if (video.paused) {
687
- console.log(
688
- "[IMA] Resuming paused video after ad error"
689
- );
690
- (_a = video.play()) == null ? void 0 : _a.catch(() => {
688
+ (_b = video.play()) == null ? void 0 : _b.catch(() => {
691
689
  });
692
690
  }
693
691
  }
@@ -697,14 +695,9 @@ function createImaController(video, options) {
697
695
  adsManager.addEventListener(
698
696
  AdEvent.CONTENT_PAUSE_REQUESTED,
699
697
  () => {
700
- console.log("[IMA] Content pause requested");
698
+ console.log("[DEBUG-FLOW] \u{1F3AF} CONTENT_PAUSE_REQUESTED - Ad starting");
701
699
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
702
700
  video.pause();
703
- console.log("[IMA] Content video paused (VOD mode)");
704
- } else {
705
- console.log(
706
- "[IMA] Content video continues in background (Live mode)"
707
- );
708
701
  }
709
702
  hideContentVideo();
710
703
  if (adContainerEl) {
@@ -713,7 +706,7 @@ function createImaController(video, options) {
713
706
  adContainerEl.style.backgroundColor = "#000";
714
707
  adContainerEl.offsetHeight;
715
708
  adContainerEl.style.opacity = "1";
716
- console.log("[IMA] Ad container shown on content pause");
709
+ console.log("[DEBUG-LAYER] \u{1F7E1} Ad container VISIBLE");
717
710
  }
718
711
  adPlaying = true;
719
712
  setAdPlayingFlag(true);
@@ -721,14 +714,14 @@ function createImaController(video, options) {
721
714
  }
722
715
  );
723
716
  adsManager.addEventListener(AdEvent.STARTED, () => {
724
- console.log("[IMA] Ad started - showing ad video");
717
+ console.log("[DEBUG-FLOW] \u25B6\uFE0F STARTED - Ad playing now");
725
718
  setAdPlayingFlag(true);
726
719
  hideContentVideo();
727
720
  if (adVideoElement) {
728
721
  adVideoElement.volume = originalMutedState ? 0 : originalVolume;
729
722
  adVideoElement.muted = originalMutedState;
730
723
  console.log(
731
- `[IMA] Ad video volume: ${adVideoElement.volume}, muted: ${adVideoElement.muted}`
724
+ `[DEBUG-AUDIO] \u{1F50A} Ad audio set | volume=${adVideoElement.volume}, muted=${adVideoElement.muted}`
732
725
  );
733
726
  }
734
727
  if (adContainerEl) {
@@ -737,20 +730,20 @@ function createImaController(video, options) {
737
730
  adContainerEl.style.backgroundColor = "#000";
738
731
  adContainerEl.offsetHeight;
739
732
  adContainerEl.style.opacity = "1";
740
- console.log("[IMA] Ad container now visible");
741
733
  }
742
734
  });
743
735
  adsManager.addEventListener(
744
736
  AdEvent.CONTENT_RESUME_REQUESTED,
745
737
  () => {
746
- console.log("[IMA] Content resume requested");
738
+ console.log("[DEBUG-FLOW] \u23F8\uFE0F CONTENT_RESUME - Single ad done");
747
739
  adPlaying = false;
748
740
  setAdPlayingFlag(false);
741
+ console.log("[DEBUG-LAYER] \u26A0\uFE0F Waiting for pod manager decision (more ads or done)");
749
742
  emit("content_resume");
750
743
  }
751
744
  );
752
745
  adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, () => {
753
- console.log("[IMA] All ads completed - restoring content");
746
+ console.log("[DEBUG-FLOW] \u{1F3C1} ALL_ADS_COMPLETED - Pod finished");
754
747
  adPlaying = false;
755
748
  setAdPlayingFlag(false);
756
749
  if (adContainerEl) {
@@ -760,15 +753,14 @@ function createImaController(video, options) {
760
753
  if (adContainerEl) {
761
754
  adContainerEl.style.pointerEvents = "none";
762
755
  adContainerEl.style.display = "none";
763
- console.log("[IMA] Ad container hidden");
756
+ console.log("[DEBUG-LAYER] \u26AB Ad container HIDDEN (pod done)");
764
757
  }
765
758
  }, 300);
766
759
  }
767
760
  showContentVideo();
768
761
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds) && video.paused) {
769
- console.log("[IMA] Resuming content video playback");
770
762
  video.play().catch((e) => {
771
- console.warn("[IMA] Failed to resume content video:", e);
763
+ console.warn("[DEBUG-ERROR] Failed to resume video:", e);
772
764
  });
773
765
  }
774
766
  emit("all_ads_completed");
@@ -790,18 +782,12 @@ function createImaController(video, options) {
790
782
  if (adContainerEl) {
791
783
  adContainerEl.style.pointerEvents = "none";
792
784
  adContainerEl.style.display = "none";
793
- console.log(
794
- "[IMA] Ad container hidden after setup error"
795
- );
796
785
  }
797
786
  }, 300);
798
787
  }
799
788
  showContentVideo();
800
789
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
801
790
  if (video.paused) {
802
- console.log(
803
- "[IMA] Resuming paused video after setup error"
804
- );
805
791
  video.play().catch(() => {
806
792
  });
807
793
  }
@@ -819,7 +805,9 @@ function createImaController(video, options) {
819
805
  adsLoader.addEventListener(
820
806
  google.ima.AdErrorEvent.Type.AD_ERROR,
821
807
  (adErrorEvent) => {
822
- console.error("[IMA] Ads loader error:", adErrorEvent.getError());
808
+ var _a;
809
+ const error = adErrorEvent.getError();
810
+ console.error("[DEBUG-ERROR] \u274C ADS_LOADER ERROR:", (_a = error.getMessage) == null ? void 0 : _a.call(error));
823
811
  adPlaying = false;
824
812
  setAdPlayingFlag(false);
825
813
  if (adContainerEl) {
@@ -829,14 +817,12 @@ function createImaController(video, options) {
829
817
  if (adContainerEl) {
830
818
  adContainerEl.style.pointerEvents = "none";
831
819
  adContainerEl.style.display = "none";
832
- console.log("[IMA] Ad container hidden after loader error");
833
820
  }
834
821
  }, 300);
835
822
  }
836
823
  showContentVideo();
837
824
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
838
825
  if (video.paused) {
839
- console.log("[IMA] Resuming paused video after loader error");
840
826
  video.play().catch(() => {
841
827
  });
842
828
  }
@@ -851,7 +837,6 @@ function createImaController(video, options) {
851
837
  false
852
838
  );
853
839
  }
854
- console.log("[IMA] Making ads request");
855
840
  makeAdsRequest(google, vastTagUrl);
856
841
  return adsLoadedPromise;
857
842
  } catch (error) {
@@ -890,20 +875,16 @@ function createImaController(video, options) {
890
875
  },
891
876
  async play() {
892
877
  var _a, _b;
878
+ console.log("[DEBUG-FLOW] \u25B6\uFE0F play() - Starting ad playback");
893
879
  if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
894
- console.warn(
895
- "[IMA] Cannot play ad: IMA SDK or ad container not available"
896
- );
897
880
  return Promise.reject(new Error("IMA SDK not available"));
898
881
  }
899
882
  if (!adsManager) {
900
- console.warn("[IMA] Cannot play ad: No ads manager available");
901
883
  return Promise.reject(new Error("No ads manager"));
902
884
  }
903
885
  try {
904
886
  const width = video.clientWidth || 640;
905
887
  const height = video.clientHeight || 360;
906
- console.log(`[IMA] Initializing ads manager (${width}x${height})`);
907
888
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
908
889
  adPlaying = true;
909
890
  const adVolume = originalMutedState ? 0 : originalVolume;
@@ -911,20 +892,18 @@ function createImaController(video, options) {
911
892
  adVideoElement.volume = adVolume;
912
893
  adVideoElement.muted = originalMutedState;
913
894
  console.log(
914
- `[IMA] Set dedicated ad video volume to ${adVolume}, muted: ${originalMutedState}`
895
+ `[DEBUG-AUDIO] \u{1F50A} Pre-start ad audio | volume=${adVolume}, muted=${originalMutedState}`
915
896
  );
916
897
  }
917
898
  try {
918
899
  adsManager.setVolume(adVolume);
919
- console.log(`[IMA] Set IMA manager volume to ${adVolume}`);
920
900
  } catch (error) {
921
- console.warn("[IMA] Failed to set IMA manager volume:", error);
901
+ console.warn("[DEBUG-ERROR] Failed to set IMA manager volume:", error);
922
902
  }
923
- console.log("[IMA] Starting ad playback");
924
903
  adsManager.start();
925
904
  return Promise.resolve();
926
905
  } catch (error) {
927
- console.error("[IMA] Error starting ad playback:", error);
906
+ console.error("[DEBUG-ERROR] \u274C Error starting ad:", error);
928
907
  adPlaying = false;
929
908
  setAdPlayingFlag(false);
930
909
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -936,7 +915,7 @@ function createImaController(video, options) {
936
915
  },
937
916
  async stop() {
938
917
  var _a;
939
- console.log("[IMA] Stopping ad playback");
918
+ console.log("[DEBUG-FLOW] \u23F9\uFE0F stop() - Stopping ad playback");
940
919
  adPlaying = false;
941
920
  setAdPlayingFlag(false);
942
921
  if (adContainerEl) {
@@ -946,7 +925,7 @@ function createImaController(video, options) {
946
925
  if (adContainerEl) {
947
926
  adContainerEl.style.pointerEvents = "none";
948
927
  adContainerEl.style.display = "none";
949
- console.log("[IMA] Ad container hidden after stop");
928
+ console.log("[DEBUG-LAYER] \u26AB Ad container HIDDEN (stop)");
950
929
  }
951
930
  }, 300);
952
931
  }
@@ -1017,7 +996,7 @@ function createImaController(video, options) {
1017
996
  updateOriginalMutedState(muted, volume) {
1018
997
  const nextVolume = typeof volume === "number" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;
1019
998
  console.log(
1020
- `[IMA] updateOriginalMutedState called: { muted: ${originalMutedState} -> ${muted}, volume: ${originalVolume} -> ${nextVolume} }`
999
+ `[DEBUG-AUDIO] \u{1F4BE} Saved original state | muted: ${originalMutedState}->${muted}, volume: ${originalVolume}->${nextVolume}`
1021
1000
  );
1022
1001
  originalMutedState = muted;
1023
1002
  originalVolume = nextVolume;
@@ -1034,14 +1013,14 @@ function createImaController(video, options) {
1034
1013
  adVideoElement.volume = clampedVolume;
1035
1014
  adVideoElement.muted = clampedVolume === 0;
1036
1015
  console.log(
1037
- `[IMA] Set dedicated ad video volume to ${clampedVolume}, muted: ${clampedVolume === 0}`
1016
+ `[DEBUG-AUDIO] \u{1F50A} Ad volume changed | volume=${clampedVolume}, muted=${clampedVolume === 0}`
1038
1017
  );
1039
1018
  }
1040
1019
  if (adsManager && adPlaying) {
1041
1020
  try {
1042
1021
  adsManager.setVolume(clampedVolume);
1043
1022
  } catch (error) {
1044
- console.warn("[IMA] Failed to set IMA manager volume:", error);
1023
+ console.warn("[DEBUG-ERROR] Failed to set IMA manager volume:", error);
1045
1024
  }
1046
1025
  }
1047
1026
  },
@@ -2252,6 +2231,10 @@ var StormcloudVideoPlayer = class {
2252
2231
  this.vastToMediaUrlMap = /* @__PURE__ */ new Map();
2253
2232
  this.preloadedMediaUrls = /* @__PURE__ */ new Set();
2254
2233
  this.preloadingMediaUrls = /* @__PURE__ */ new Set();
2234
+ this.adRequestTokenCounter = 0;
2235
+ this.activeAdRequestToken = null;
2236
+ this.adRequestWatchdogToken = null;
2237
+ this.adFailsafeToken = null;
2255
2238
  initializePolyfills();
2256
2239
  const browserOverrides = getBrowserConfigOverrides();
2257
2240
  this.config = { ...config, ...browserOverrides };
@@ -2565,29 +2548,21 @@ var StormcloudVideoPlayer = class {
2565
2548
  }
2566
2549
  });
2567
2550
  this.ima.on("content_pause", () => {
2568
- if (this.config.debugAdTiming) {
2569
- console.log("[StormcloudVideoPlayer] IMA content_pause event received");
2570
- }
2551
+ console.log(`[DEBUG-POD] \u{1F3AF} content_pause | ad ${this.currentAdIndex}/${this.totalAdsInBreak}, queue=${this.adPodQueue.length}`);
2571
2552
  this.clearAdFailsafeTimer();
2553
+ this.clearAdRequestWatchdog();
2554
+ this.activeAdRequestToken = null;
2555
+ this.showAds = true;
2572
2556
  this.enforceAdHoldState();
2573
2557
  });
2574
2558
  this.ima.on("content_resume", () => {
2575
- if (this.config.debugAdTiming) {
2576
- console.log(
2577
- "[StormcloudVideoPlayer] IMA content_resume event received",
2578
- {
2579
- inAdBreak: this.inAdBreak,
2580
- pendingAds: this.adPodQueue.length
2581
- }
2582
- );
2583
- }
2559
+ console.log(`[DEBUG-POD] \u23F8\uFE0F content_resume | ad ${this.currentAdIndex}/${this.totalAdsInBreak}, queue=${this.adPodQueue.length}, remaining=${this.getRemainingAdMs()}ms`);
2584
2560
  this.clearAdFailsafeTimer();
2561
+ this.clearAdRequestWatchdog();
2562
+ this.activeAdRequestToken = null;
2563
+ this.showAds = false;
2585
2564
  if (!this.inAdBreak) {
2586
- if (this.config.debugAdTiming) {
2587
- console.log(
2588
- "[StormcloudVideoPlayer] Not in ad break - this shouldn't happen during pod"
2589
- );
2590
- }
2565
+ console.warn("[DEBUG-POD] \u26A0\uFE0F Not in ad break - shouldn't happen");
2591
2566
  return;
2592
2567
  }
2593
2568
  const remaining = this.getRemainingAdMs();
@@ -2595,34 +2570,17 @@ var StormcloudVideoPlayer = class {
2595
2570
  const nextPreloaded = this.findNextPreloadedAd();
2596
2571
  if (nextPreloaded) {
2597
2572
  this.currentAdIndex++;
2598
- this.enforceAdHoldState();
2599
- if (this.config.debugAdTiming) {
2600
- console.log(
2601
- `[StormcloudVideoPlayer] Playing next preloaded ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
2602
- );
2603
- }
2573
+ console.log(`[DEBUG-POD] \u27A1\uFE0F Playing next ad ${this.currentAdIndex}/${this.totalAdsInBreak} (preloaded)`);
2604
2574
  this.playSingleAd(nextPreloaded).catch(() => {
2605
- if (this.config.debugAdTiming) {
2606
- console.error(
2607
- "[StormcloudVideoPlayer] Failed to play next ad in pod"
2608
- );
2609
- }
2575
+ console.error("[DEBUG-POD] \u274C Failed to play next ad");
2610
2576
  this.handleAdPodComplete();
2611
2577
  });
2612
2578
  } else {
2613
- if (this.config.debugAdTiming) {
2614
- console.log(
2615
- "[StormcloudVideoPlayer] No preloaded ads available - completing ad break"
2616
- );
2617
- }
2579
+ console.log("[DEBUG-POD] \u26A0\uFE0F No preloaded ads - ending pod");
2618
2580
  this.handleAdPodComplete();
2619
2581
  }
2620
2582
  } else {
2621
- if (this.config.debugAdTiming) {
2622
- console.log(
2623
- "[StormcloudVideoPlayer] No more ads in pod - completing ad break"
2624
- );
2625
- }
2583
+ console.log("[DEBUG-POD] \u2705 Pod complete (no more ads or time expired)");
2626
2584
  this.handleAdPodComplete();
2627
2585
  }
2628
2586
  });
@@ -3197,53 +3155,27 @@ var StormcloudVideoPlayer = class {
3197
3155
  let vastTagUrls = [];
3198
3156
  if (this.apiVastTagUrl) {
3199
3157
  vastTagUrls = [this.apiVastTagUrl];
3200
- if (this.config.debugAdTiming) {
3201
- console.log(
3202
- "[StormcloudVideoPlayer] Using VAST endpoint:",
3203
- this.apiVastTagUrl
3204
- );
3205
- }
3206
3158
  } else if (tags && tags.length > 0) {
3207
3159
  vastTagUrls = tags;
3208
- if (this.config.debugAdTiming) {
3209
- console.log(
3210
- "[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
3211
- tags
3212
- );
3213
- }
3214
3160
  } else {
3215
- if (this.config.debugAdTiming) {
3216
- console.log("[StormcloudVideoPlayer] No VAST tag available for ad");
3217
- }
3161
+ console.log("[DEBUG-POD] \u26A0\uFE0F No VAST tag available");
3218
3162
  return;
3219
3163
  }
3220
3164
  if (vastTagUrls.length > 0) {
3165
+ console.log(`[DEBUG-POD] \u{1F3AF} Starting ad break with ${vastTagUrls.length} ads`);
3221
3166
  this.adPodAllUrls = [...vastTagUrls];
3222
3167
  this.preloadingAdUrls.clear();
3223
3168
  this.vastToMediaUrlMap.clear();
3224
3169
  this.preloadedMediaUrls.clear();
3225
3170
  this.preloadingMediaUrls.clear();
3226
- this.logQueuedAdUrls(this.adPodAllUrls);
3227
- if (this.config.debugAdTiming) {
3228
- console.log(
3229
- `[StormcloudVideoPlayer] Capturing original audio state before ad break:`,
3230
- {
3231
- videoMuted: this.video.muted,
3232
- videoVolume: this.video.volume
3233
- }
3234
- );
3235
- }
3171
+ console.log(
3172
+ `[DEBUG-AUDIO] \u{1F4BE} Capturing original state | muted=${this.video.muted}, volume=${this.video.volume}`
3173
+ );
3236
3174
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3237
3175
  this.inAdBreak = true;
3238
3176
  this.currentAdIndex = 0;
3239
3177
  this.totalAdsInBreak = vastTagUrls.length;
3240
3178
  this.adPodQueue = [...vastTagUrls];
3241
- this.enforceAdHoldState();
3242
- if (this.config.debugAdTiming) {
3243
- console.log(
3244
- `[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - preloading all ads in parallel`
3245
- );
3246
- }
3247
3179
  this.preloadAllAdsInBackground().catch((error) => {
3248
3180
  if (this.config.debugAdTiming) {
3249
3181
  console.warn(
@@ -3255,12 +3187,7 @@ var StormcloudVideoPlayer = class {
3255
3187
  try {
3256
3188
  await this.playAdPod();
3257
3189
  } catch (error) {
3258
- if (this.config.debugAdTiming) {
3259
- console.error(
3260
- "[StormcloudVideoPlayer] Ad pod playback failed:",
3261
- error
3262
- );
3263
- }
3190
+ console.error("[DEBUG-POD] \u274C Pod playback failed:", error);
3264
3191
  this.handleAdFailure();
3265
3192
  }
3266
3193
  }
@@ -3272,19 +3199,13 @@ var StormcloudVideoPlayer = class {
3272
3199
  }
3273
3200
  async playAdPod() {
3274
3201
  if (this.adPodQueue.length === 0) {
3275
- if (this.config.debugAdTiming) {
3276
- console.log("[StormcloudVideoPlayer] No ads in pod to play");
3277
- }
3202
+ console.log("[DEBUG-POD] \u26A0\uFE0F No ads in pod");
3278
3203
  return;
3279
3204
  }
3280
3205
  await new Promise((resolve) => setTimeout(resolve, 500));
3281
3206
  const firstPreloaded = this.findNextPreloadedAd();
3282
3207
  if (!firstPreloaded) {
3283
- if (this.config.debugAdTiming) {
3284
- console.log(
3285
- "[StormcloudVideoPlayer] No preloaded ads available after waiting, trying first ad anyway"
3286
- );
3287
- }
3208
+ console.log("[DEBUG-POD] \u26A0\uFE0F No preloaded ads after wait, trying first ad");
3288
3209
  const firstAd = this.adPodQueue.shift();
3289
3210
  if (firstAd) {
3290
3211
  this.currentAdIndex++;
@@ -3293,11 +3214,7 @@ var StormcloudVideoPlayer = class {
3293
3214
  return;
3294
3215
  }
3295
3216
  this.currentAdIndex++;
3296
- if (this.config.debugAdTiming) {
3297
- console.log(
3298
- `[StormcloudVideoPlayer] Playing first preloaded ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
3299
- );
3300
- }
3217
+ console.log(`[DEBUG-POD] \u{1F680} Starting pod with ad ${this.currentAdIndex}/${this.totalAdsInBreak}`);
3301
3218
  await this.playSingleAd(firstPreloaded);
3302
3219
  }
3303
3220
  findCurrentOrNextBreak(nowMs) {
@@ -3332,7 +3249,6 @@ var StormcloudVideoPlayer = class {
3332
3249
  const rest = tags.slice(1);
3333
3250
  this.adPodQueue = rest;
3334
3251
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3335
- this.enforceAdHoldState();
3336
3252
  await this.playSingleAd(first);
3337
3253
  this.inAdBreak = true;
3338
3254
  this.expectedAdBreakDurationMs = remainingMs;
@@ -3435,63 +3351,56 @@ var StormcloudVideoPlayer = class {
3435
3351
  this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;
3436
3352
  }
3437
3353
  async playSingleAd(vastTagUrl) {
3438
- if (this.config.debugAdTiming) {
3439
- console.log("[StormcloudVideoPlayer] Attempting to play ad:", vastTagUrl);
3440
- }
3354
+ console.log(`[DEBUG-POD] \u{1F3AC} playSingleAd | url=${vastTagUrl.substring(0, 60)}...`);
3441
3355
  if (this.ima.isAdPlaying()) {
3442
- if (this.config.debugAdTiming) {
3443
- console.warn(
3444
- "[StormcloudVideoPlayer] Ad already playing - skipping new ad request"
3445
- );
3446
- }
3356
+ console.warn("[DEBUG-POD] \u26A0\uFE0F Ad already playing - skipping request");
3447
3357
  return;
3448
3358
  }
3359
+ const requestToken = ++this.adRequestTokenCounter;
3449
3360
  const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
3450
- if (wasPreloaded && this.config.debugAdTiming) {
3451
- console.log(
3452
- `[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
3453
- );
3454
- }
3455
- this.startAdFailsafeTimer();
3361
+ this.activeAdRequestToken = requestToken;
3362
+ console.log(`[DEBUG-POD] \u{1F4DD} Request token=${requestToken}, preloaded=${wasPreloaded}`);
3363
+ this.startAdRequestWatchdog(requestToken);
3456
3364
  try {
3457
3365
  await this.ima.requestAds(vastTagUrl);
3366
+ this.clearAdRequestWatchdog();
3367
+ if (this.activeAdRequestToken !== requestToken) {
3368
+ console.warn(`[DEBUG-POD] \u26A0\uFE0F Token mismatch after requestAds (stale request)`);
3369
+ return;
3370
+ }
3458
3371
  try {
3459
- if (this.config.debugAdTiming) {
3460
- console.log(
3461
- "[StormcloudVideoPlayer] Ad request completed, attempting playback"
3462
- );
3463
- }
3464
- this.enforceAdHoldState();
3372
+ this.startAdFailsafeTimer(requestToken);
3465
3373
  await this.ima.play();
3466
- this.showAds = true;
3467
- if (this.config.debugAdTiming) {
3468
- console.log(
3469
- "[StormcloudVideoPlayer] Ad playback started successfully, showAds = true"
3470
- );
3374
+ if (this.activeAdRequestToken === requestToken) {
3375
+ console.log(`[DEBUG-POD] \u2705 Ad play initiated (token=${requestToken})`);
3376
+ } else {
3377
+ console.warn(`[DEBUG-POD] \u26A0\uFE0F Token mismatch after play (stale request)`);
3471
3378
  }
3472
3379
  } catch (playError) {
3473
- if (this.config.debugAdTiming) {
3474
- console.log(
3475
- "[StormcloudVideoPlayer] No ads available, skipping playback"
3476
- );
3380
+ console.log("[DEBUG-POD] \u26A0\uFE0F No ads available from play()");
3381
+ this.clearAdFailsafeTimer();
3382
+ if (this.activeAdRequestToken === requestToken) {
3383
+ this.activeAdRequestToken = null;
3477
3384
  }
3478
3385
  this.handleAdFailure();
3479
3386
  return;
3480
3387
  }
3481
3388
  } catch (error) {
3482
- if (this.config.debugAdTiming) {
3483
- console.error("[StormcloudVideoPlayer] Ad playback failed:", error);
3389
+ console.error("[DEBUG-POD] \u274C Ad request failed:", error == null ? void 0 : error.message);
3390
+ this.clearAdRequestWatchdog();
3391
+ this.clearAdFailsafeTimer();
3392
+ if (this.activeAdRequestToken === requestToken) {
3393
+ this.activeAdRequestToken = null;
3484
3394
  }
3485
3395
  this.handleAdFailure();
3486
3396
  }
3487
3397
  }
3488
3398
  handleAdPodComplete() {
3489
3399
  var _a;
3490
- if (this.config.debugAdTiming) {
3491
- console.log(
3492
- "[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
3493
- );
3494
- }
3400
+ console.log("[DEBUG-POD] \u{1F3C1} handleAdPodComplete - Ending ad break, restoring content");
3401
+ this.clearAdRequestWatchdog();
3402
+ this.clearAdFailsafeTimer();
3403
+ this.activeAdRequestToken = null;
3495
3404
  this.releaseAdHoldState();
3496
3405
  this.preloadingAdUrls.clear();
3497
3406
  this.vastToMediaUrlMap.clear();
@@ -3502,7 +3411,6 @@ var StormcloudVideoPlayer = class {
3502
3411
  this.currentAdBreakStartWallClockMs = void 0;
3503
3412
  this.clearAdStartTimer();
3504
3413
  this.clearAdStopTimer();
3505
- this.clearAdFailsafeTimer();
3506
3414
  this.adPodQueue = [];
3507
3415
  this.adPodAllUrls = [];
3508
3416
  this.showAds = false;
@@ -3514,70 +3422,84 @@ var StormcloudVideoPlayer = class {
3514
3422
  const originalVolume = typeof this.ima.getOriginalVolume === "function" ? this.ima.getOriginalVolume() : this.video.volume;
3515
3423
  this.video.muted = originalMutedState;
3516
3424
  this.video.volume = originalVolume;
3517
- if (this.config.debugAdTiming) {
3518
- console.log(
3519
- `[StormcloudVideoPlayer] Restored main video - muted: ${originalMutedState}, volume: ${this.video.volume}`
3520
- );
3521
- }
3425
+ console.log(
3426
+ `[DEBUG-AUDIO] \u{1F50A} Main video restored | muted=${originalMutedState}, volume=${originalVolume}`
3427
+ );
3522
3428
  if (!this.shouldContinueLiveStreamDuringAds() && this.video.paused) {
3523
- if (this.config.debugAdTiming) {
3524
- console.log("[StormcloudVideoPlayer] Resuming paused video");
3525
- }
3429
+ console.log("[DEBUG-FLOW] \u25B6\uFE0F Resuming main video playback");
3526
3430
  (_a = this.video.play()) == null ? void 0 : _a.catch((error) => {
3527
- if (this.config.debugAdTiming) {
3528
- console.error(
3529
- "[StormcloudVideoPlayer] Failed to resume video:",
3530
- error
3531
- );
3532
- }
3431
+ console.error("[DEBUG-ERROR] Failed to resume video:", error);
3533
3432
  });
3534
3433
  }
3535
3434
  }
3536
3435
  handleAdFailure() {
3537
- if (this.config.debugAdTiming) {
3538
- console.log(
3539
- "[StormcloudVideoPlayer] Handling ad failure - resuming content",
3540
- {
3541
- inAdBreak: this.inAdBreak,
3542
- showAds: this.showAds,
3543
- videoPaused: this.video.paused,
3544
- adPlaying: this.ima.isAdPlaying()
3545
- }
3546
- );
3547
- }
3436
+ console.log(
3437
+ `[DEBUG-POD] \u274C handleAdFailure | inBreak=${this.inAdBreak}, showAds=${this.showAds}, paused=${this.video.paused}`
3438
+ );
3548
3439
  this.handleAdPodComplete();
3549
3440
  }
3550
- startAdFailsafeTimer() {
3441
+ startAdRequestWatchdog(token) {
3442
+ var _a;
3443
+ this.clearAdRequestWatchdog();
3444
+ const timeoutMs = (_a = this.config.adFailsafeTimeoutMs) != null ? _a : 1e4;
3445
+ this.adRequestWatchdogToken = token;
3446
+ this.adRequestWatchdogId = window.setTimeout(() => {
3447
+ if (this.adRequestWatchdogToken !== token) {
3448
+ return;
3449
+ }
3450
+ this.adRequestWatchdogId = void 0;
3451
+ this.adRequestWatchdogToken = null;
3452
+ if (this.activeAdRequestToken === token) {
3453
+ this.activeAdRequestToken = null;
3454
+ }
3455
+ this.logAdState("ad_request_timeout", { token, timeoutMs });
3456
+ this.handleAdFailure();
3457
+ }, timeoutMs);
3458
+ this.logAdState("ad_request_watchdog_started", { token, timeoutMs });
3459
+ }
3460
+ clearAdRequestWatchdog() {
3461
+ if (this.adRequestWatchdogId != null) {
3462
+ clearTimeout(this.adRequestWatchdogId);
3463
+ this.adRequestWatchdogId = void 0;
3464
+ }
3465
+ if (this.adRequestWatchdogToken != null) {
3466
+ this.logAdState("ad_request_watchdog_cleared", {
3467
+ token: this.adRequestWatchdogToken
3468
+ });
3469
+ this.adRequestWatchdogToken = null;
3470
+ }
3471
+ }
3472
+ startAdFailsafeTimer(token) {
3551
3473
  var _a;
3552
3474
  this.clearAdFailsafeTimer();
3553
3475
  const failsafeMs = (_a = this.config.adFailsafeTimeoutMs) != null ? _a : 1e4;
3554
- if (this.config.debugAdTiming) {
3555
- console.log(
3556
- `[StormcloudVideoPlayer] Starting failsafe timer (${failsafeMs}ms)`
3557
- );
3558
- }
3476
+ this.adFailsafeToken = token;
3559
3477
  this.adFailsafeTimerId = window.setTimeout(() => {
3560
- const shouldTrigger = this.video.paused || this.showAds && !this.ima.isAdPlaying();
3561
- if (shouldTrigger) {
3562
- if (this.config.debugAdTiming) {
3563
- console.warn(
3564
- "[StormcloudVideoPlayer] Failsafe timer triggered - forcing video resume",
3565
- {
3566
- paused: this.video.paused,
3567
- showAds: this.showAds,
3568
- adPlaying: this.ima.isAdPlaying()
3569
- }
3570
- );
3571
- }
3572
- this.handleAdFailure();
3478
+ if (this.adFailsafeToken !== token) {
3479
+ return;
3573
3480
  }
3481
+ this.adFailsafeTimerId = void 0;
3482
+ this.adFailsafeToken = null;
3483
+ if (this.activeAdRequestToken === token) {
3484
+ this.activeAdRequestToken = null;
3485
+ }
3486
+ this.logAdState("ad_failsafe_triggered", {
3487
+ token,
3488
+ failsafeMs,
3489
+ videoPaused: this.video.paused,
3490
+ imaAdPlaying: this.ima.isAdPlaying()
3491
+ });
3492
+ this.handleAdFailure();
3574
3493
  }, failsafeMs);
3494
+ this.logAdState("ad_failsafe_started", { token, failsafeMs });
3575
3495
  }
3576
3496
  clearAdFailsafeTimer() {
3577
3497
  if (this.adFailsafeTimerId != null) {
3578
3498
  clearTimeout(this.adFailsafeTimerId);
3499
+ this.logAdState("ad_failsafe_cleared", { token: this.adFailsafeToken });
3579
3500
  this.adFailsafeTimerId = void 0;
3580
3501
  }
3502
+ this.adFailsafeToken = null;
3581
3503
  }
3582
3504
  selectVastTagsForBreak(b) {
3583
3505
  if (!b || !b.vastTagUrl) return void 0;
@@ -3592,16 +3514,32 @@ var StormcloudVideoPlayer = class {
3592
3514
  }
3593
3515
  console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
3594
3516
  }
3517
+ logAdState(event, extra = {}) {
3518
+ if (!this.config.debugAdTiming) {
3519
+ return;
3520
+ }
3521
+ console.log("[StormcloudVideoPlayer][AdState]", {
3522
+ event,
3523
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3524
+ showAds: this.showAds,
3525
+ adPlaying: this.ima.isAdPlaying(),
3526
+ inAdBreak: this.inAdBreak,
3527
+ activeAdRequestToken: this.activeAdRequestToken,
3528
+ ...extra
3529
+ });
3530
+ }
3595
3531
  enforceAdHoldState() {
3596
3532
  this.video.dataset.stormcloudAdPlaying = "true";
3597
3533
  this.video.muted = true;
3598
3534
  this.video.volume = 0;
3535
+ console.log("[DEBUG-LAYER] \u{1F512} Enforced ad hold state (main video muted)");
3599
3536
  if (typeof this.ima.showPlaceholder === "function") {
3600
3537
  this.ima.showPlaceholder();
3601
3538
  }
3602
3539
  }
3603
3540
  releaseAdHoldState() {
3604
3541
  delete this.video.dataset.stormcloudAdPlaying;
3542
+ console.log("[DEBUG-LAYER] \u{1F513} Released ad hold state");
3605
3543
  if (typeof this.ima.hidePlaceholder === "function") {
3606
3544
  this.ima.hidePlaceholder();
3607
3545
  }