stormcloud-video-player 0.2.30 → 0.2.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.
@@ -217,7 +217,11 @@ function createImaController(video, options) {
217
217
  }
218
218
  function hideContentVideo() {
219
219
  if (!contentVideoHidden) {
220
- video.style.visibility = "hidden";
220
+ video.style.transition = "opacity 0.3s ease-in-out";
221
+ video.style.opacity = "0";
222
+ setTimeout(() => {
223
+ video.style.visibility = "hidden";
224
+ }, 300);
221
225
  video.muted = true;
222
226
  video.volume = 0;
223
227
  contentVideoHidden = true;
@@ -227,6 +231,9 @@ function createImaController(video, options) {
227
231
  function showContentVideo() {
228
232
  if (contentVideoHidden) {
229
233
  video.style.visibility = "visible";
234
+ video.style.transition = "opacity 0.3s ease-in-out";
235
+ video.offsetHeight;
236
+ video.style.opacity = "1";
230
237
  video.muted = originalMutedState;
231
238
  video.volume = originalVolume;
232
239
  contentVideoHidden = false;
@@ -399,7 +406,9 @@ function createImaController(video, options) {
399
406
  container.style.justifyContent = "center";
400
407
  container.style.pointerEvents = "none";
401
408
  container.style.zIndex = "10";
402
- container.style.backgroundColor = "#000";
409
+ container.style.backgroundColor = "transparent";
410
+ container.style.transition = "opacity 0.3s ease-in-out, background-color 0.3s ease-in-out";
411
+ container.style.opacity = "0";
403
412
  (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
404
413
  adContainerEl = container;
405
414
  }
@@ -509,7 +518,9 @@ function createImaController(video, options) {
509
518
  container.style.justifyContent = "center";
510
519
  container.style.pointerEvents = "none";
511
520
  container.style.zIndex = "10";
512
- container.style.backgroundColor = "#000";
521
+ container.style.backgroundColor = "transparent";
522
+ container.style.transition = "opacity 0.3s ease-in-out, background-color 0.3s ease-in-out";
523
+ container.style.opacity = "0";
513
524
  if (!video.parentElement) {
514
525
  throw new Error("Video element has no parent for ad container");
515
526
  }
@@ -573,13 +584,19 @@ function createImaController(video, options) {
573
584
  console.error("[IMA] Ad error:", errorEvent.getError());
574
585
  destroyAdsManager();
575
586
  adPlaying = false;
576
- showContentVideo();
577
587
  setAdPlayingFlag(false);
578
588
  if (adContainerEl) {
579
- adContainerEl.style.pointerEvents = "none";
580
- adContainerEl.style.display = "none";
581
- console.log("[IMA] Ad container hidden after error");
589
+ adContainerEl.style.opacity = "0";
590
+ adContainerEl.style.backgroundColor = "transparent";
591
+ setTimeout(() => {
592
+ if (adContainerEl) {
593
+ adContainerEl.style.pointerEvents = "none";
594
+ adContainerEl.style.display = "none";
595
+ console.log("[IMA] Ad container hidden after error");
596
+ }
597
+ }, 300);
582
598
  }
599
+ showContentVideo();
583
600
  if (adsLoadedReject) {
584
601
  adsLoadedReject(new Error("Ad playback error"));
585
602
  adsLoadedReject = void 0;
@@ -625,6 +642,15 @@ function createImaController(video, options) {
625
642
  "[IMA] Content video continues in background (Live mode)"
626
643
  );
627
644
  }
645
+ hideContentVideo();
646
+ if (adContainerEl) {
647
+ adContainerEl.style.pointerEvents = "auto";
648
+ adContainerEl.style.display = "flex";
649
+ adContainerEl.style.backgroundColor = "#000";
650
+ adContainerEl.offsetHeight;
651
+ adContainerEl.style.opacity = "1";
652
+ console.log("[IMA] Ad container shown on content pause");
653
+ }
628
654
  adPlaying = true;
629
655
  setAdPlayingFlag(true);
630
656
  emit("content_pause");
@@ -644,6 +670,9 @@ function createImaController(video, options) {
644
670
  if (adContainerEl) {
645
671
  adContainerEl.style.pointerEvents = "auto";
646
672
  adContainerEl.style.display = "flex";
673
+ adContainerEl.style.backgroundColor = "#000";
674
+ adContainerEl.offsetHeight;
675
+ adContainerEl.style.opacity = "1";
647
676
  console.log("[IMA] Ad container now visible");
648
677
  }
649
678
  });
@@ -660,12 +689,18 @@ function createImaController(video, options) {
660
689
  console.log("[IMA] All ads completed - restoring content");
661
690
  adPlaying = false;
662
691
  setAdPlayingFlag(false);
663
- showContentVideo();
664
692
  if (adContainerEl) {
665
- adContainerEl.style.pointerEvents = "none";
666
- adContainerEl.style.display = "none";
667
- console.log("[IMA] Ad container hidden");
693
+ adContainerEl.style.opacity = "0";
694
+ adContainerEl.style.backgroundColor = "transparent";
695
+ setTimeout(() => {
696
+ if (adContainerEl) {
697
+ adContainerEl.style.pointerEvents = "none";
698
+ adContainerEl.style.display = "none";
699
+ console.log("[IMA] Ad container hidden");
700
+ }
701
+ }, 300);
668
702
  }
703
+ showContentVideo();
669
704
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds) && video.paused) {
670
705
  console.log("[IMA] Resuming content video playback");
671
706
  video.play().catch((e) => {
@@ -683,13 +718,21 @@ function createImaController(video, options) {
683
718
  } catch (e) {
684
719
  console.error("[IMA] Error setting up ads manager:", e);
685
720
  adPlaying = false;
686
- showContentVideo();
687
721
  setAdPlayingFlag(false);
688
722
  if (adContainerEl) {
689
- adContainerEl.style.pointerEvents = "none";
690
- adContainerEl.style.display = "none";
691
- console.log("[IMA] Ad container hidden after setup error");
723
+ adContainerEl.style.opacity = "0";
724
+ adContainerEl.style.backgroundColor = "transparent";
725
+ setTimeout(() => {
726
+ if (adContainerEl) {
727
+ adContainerEl.style.pointerEvents = "none";
728
+ adContainerEl.style.display = "none";
729
+ console.log(
730
+ "[IMA] Ad container hidden after setup error"
731
+ );
732
+ }
733
+ }, 300);
692
734
  }
735
+ showContentVideo();
693
736
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
694
737
  if (video.paused) {
695
738
  console.log(
@@ -714,13 +757,19 @@ function createImaController(video, options) {
714
757
  (adErrorEvent) => {
715
758
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
716
759
  adPlaying = false;
717
- showContentVideo();
718
760
  setAdPlayingFlag(false);
719
761
  if (adContainerEl) {
720
- adContainerEl.style.pointerEvents = "none";
721
- adContainerEl.style.display = "none";
722
- console.log("[IMA] Ad container hidden after loader error");
762
+ adContainerEl.style.opacity = "0";
763
+ adContainerEl.style.backgroundColor = "transparent";
764
+ setTimeout(() => {
765
+ if (adContainerEl) {
766
+ adContainerEl.style.pointerEvents = "none";
767
+ adContainerEl.style.display = "none";
768
+ console.log("[IMA] Ad container hidden after loader error");
769
+ }
770
+ }, 300);
723
771
  }
772
+ showContentVideo();
724
773
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
725
774
  if (video.paused) {
726
775
  console.log("[IMA] Resuming paused video after loader error");
@@ -826,12 +875,18 @@ function createImaController(video, options) {
826
875
  console.log("[IMA] Stopping ad playback");
827
876
  adPlaying = false;
828
877
  setAdPlayingFlag(false);
829
- showContentVideo();
830
878
  if (adContainerEl) {
831
- adContainerEl.style.pointerEvents = "none";
832
- adContainerEl.style.display = "none";
833
- console.log("[IMA] Ad container hidden after stop");
879
+ adContainerEl.style.opacity = "0";
880
+ adContainerEl.style.backgroundColor = "transparent";
881
+ setTimeout(() => {
882
+ if (adContainerEl) {
883
+ adContainerEl.style.pointerEvents = "none";
884
+ adContainerEl.style.display = "none";
885
+ console.log("[IMA] Ad container hidden after stop");
886
+ }
887
+ }, 300);
834
888
  }
889
+ showContentVideo();
835
890
  try {
836
891
  (_a = adsManager == null ? void 0 : adsManager.stop) == null ? void 0 : _a.call(adsManager);
837
892
  } catch {
@@ -842,23 +897,29 @@ function createImaController(video, options) {
842
897
  var _a;
843
898
  destroyAdsManager();
844
899
  adPlaying = false;
845
- showContentVideo();
846
900
  setAdPlayingFlag(false);
847
901
  if (adContainerEl) {
848
- adContainerEl.style.pointerEvents = "none";
849
- adContainerEl.style.display = "none";
902
+ adContainerEl.style.opacity = "0";
903
+ adContainerEl.style.backgroundColor = "transparent";
904
+ setTimeout(() => {
905
+ if (adContainerEl) {
906
+ adContainerEl.style.pointerEvents = "none";
907
+ adContainerEl.style.display = "none";
908
+ if (adContainerEl.parentElement) {
909
+ adContainerEl.parentElement.removeChild(adContainerEl);
910
+ }
911
+ adContainerEl = void 0;
912
+ adVideoElement = void 0;
913
+ }
914
+ }, 300);
850
915
  }
916
+ showContentVideo();
851
917
  try {
852
918
  (_a = adsLoader == null ? void 0 : adsLoader.destroy) == null ? void 0 : _a.call(adsLoader);
853
919
  } catch {
854
920
  }
855
- if (adContainerEl == null ? void 0 : adContainerEl.parentElement) {
856
- adContainerEl.parentElement.removeChild(adContainerEl);
857
- }
858
- adContainerEl = void 0;
859
921
  adDisplayContainer = void 0;
860
922
  adsLoader = void 0;
861
- adVideoElement = void 0;
862
923
  contentVideoHidden = false;
863
924
  preloadedVast.clear();
864
925
  preloadingVast.clear();
@@ -938,13 +999,22 @@ function createImaController(video, options) {
938
999
  ensurePlaceholderContainer();
939
1000
  if (adContainerEl) {
940
1001
  adContainerEl.style.display = "flex";
1002
+ adContainerEl.style.backgroundColor = "#000";
1003
+ adContainerEl.offsetHeight;
1004
+ adContainerEl.style.opacity = "1";
941
1005
  adContainerEl.style.pointerEvents = "auto";
942
1006
  }
943
1007
  },
944
1008
  hidePlaceholder() {
945
1009
  if (adContainerEl) {
946
- adContainerEl.style.display = "none";
947
- adContainerEl.style.pointerEvents = "none";
1010
+ adContainerEl.style.opacity = "0";
1011
+ adContainerEl.style.backgroundColor = "transparent";
1012
+ setTimeout(() => {
1013
+ if (adContainerEl) {
1014
+ adContainerEl.style.display = "none";
1015
+ adContainerEl.style.pointerEvents = "none";
1016
+ }
1017
+ }, 300);
948
1018
  }
949
1019
  }
950
1020
  };
@@ -2115,6 +2185,9 @@ var StormcloudVideoPlayer = class {
2115
2185
  this.hasInitialBufferCompleted = false;
2116
2186
  this.adPodAllUrls = [];
2117
2187
  this.preloadingAdUrls = /* @__PURE__ */ new Set();
2188
+ this.vastToMediaUrlMap = /* @__PURE__ */ new Map();
2189
+ this.preloadedMediaUrls = /* @__PURE__ */ new Set();
2190
+ this.preloadingMediaUrls = /* @__PURE__ */ new Set();
2118
2191
  initializePolyfills();
2119
2192
  const browserOverrides = getBrowserConfigOverrides();
2120
2193
  this.config = { ...config, ...browserOverrides };
@@ -2387,27 +2460,44 @@ var StormcloudVideoPlayer = class {
2387
2460
  });
2388
2461
  this.ima.on("ad_error", () => {
2389
2462
  if (this.config.debugAdTiming) {
2390
- console.log("[StormcloudVideoPlayer] IMA ad_error event received");
2463
+ console.log("[StormcloudVideoPlayer] IMA ad_error event received", {
2464
+ showAds: this.showAds,
2465
+ inAdBreak: this.inAdBreak,
2466
+ remainingAds: this.adPodQueue.length
2467
+ });
2391
2468
  }
2392
- if (this.showAds) {
2393
- if (this.inAdBreak) {
2394
- const remaining = this.getRemainingAdMs();
2395
- if (remaining > 500 && this.adPodQueue.length > 0) {
2396
- const next = this.adPodQueue.shift();
2469
+ if (this.inAdBreak) {
2470
+ const remaining = this.getRemainingAdMs();
2471
+ if (remaining > 500 && this.adPodQueue.length > 0) {
2472
+ const nextPreloaded = this.findNextPreloadedAd();
2473
+ if (nextPreloaded) {
2397
2474
  this.currentAdIndex++;
2398
- this.playSingleAd(next).catch(() => {
2475
+ if (this.config.debugAdTiming) {
2476
+ console.log(
2477
+ `[StormcloudVideoPlayer] Skipping to next preloaded ad after error`
2478
+ );
2479
+ }
2480
+ this.playSingleAd(nextPreloaded).catch(() => {
2481
+ this.handleAdFailure();
2399
2482
  });
2400
2483
  } else {
2484
+ if (this.config.debugAdTiming) {
2485
+ console.log(
2486
+ "[StormcloudVideoPlayer] No preloaded ads available, ending ad break"
2487
+ );
2488
+ }
2401
2489
  this.handleAdFailure();
2402
2490
  }
2403
2491
  } else {
2404
- if (this.config.debugAdTiming) {
2405
- console.log(
2406
- "[StormcloudVideoPlayer] Ad error before ad break established - cleaning up"
2407
- );
2408
- }
2409
2492
  this.handleAdFailure();
2410
2493
  }
2494
+ } else {
2495
+ if (this.config.debugAdTiming) {
2496
+ console.log(
2497
+ "[StormcloudVideoPlayer] Ad error before ad break established - cleaning up"
2498
+ );
2499
+ }
2500
+ this.handleAdFailure();
2411
2501
  }
2412
2502
  });
2413
2503
  this.ima.on("content_pause", () => {
@@ -2438,22 +2528,31 @@ var StormcloudVideoPlayer = class {
2438
2528
  }
2439
2529
  const remaining = this.getRemainingAdMs();
2440
2530
  if (remaining > 500 && this.adPodQueue.length > 0) {
2441
- const next = this.adPodQueue.shift();
2442
- this.currentAdIndex++;
2443
- this.enforceAdHoldState();
2444
- if (this.config.debugAdTiming) {
2445
- console.log(
2446
- `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
2447
- );
2448
- }
2449
- this.playSingleAd(next).catch(() => {
2531
+ const nextPreloaded = this.findNextPreloadedAd();
2532
+ if (nextPreloaded) {
2533
+ this.currentAdIndex++;
2534
+ this.enforceAdHoldState();
2450
2535
  if (this.config.debugAdTiming) {
2451
- console.error(
2452
- "[StormcloudVideoPlayer] Failed to play next ad in pod"
2536
+ console.log(
2537
+ `[StormcloudVideoPlayer] Playing next preloaded ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
2538
+ );
2539
+ }
2540
+ this.playSingleAd(nextPreloaded).catch(() => {
2541
+ if (this.config.debugAdTiming) {
2542
+ console.error(
2543
+ "[StormcloudVideoPlayer] Failed to play next ad in pod"
2544
+ );
2545
+ }
2546
+ this.handleAdPodComplete();
2547
+ });
2548
+ } else {
2549
+ if (this.config.debugAdTiming) {
2550
+ console.log(
2551
+ "[StormcloudVideoPlayer] No preloaded ads available - completing ad break"
2453
2552
  );
2454
2553
  }
2455
2554
  this.handleAdPodComplete();
2456
- });
2555
+ }
2457
2556
  } else {
2458
2557
  if (this.config.debugAdTiming) {
2459
2558
  console.log(
@@ -2698,6 +2797,9 @@ var StormcloudVideoPlayer = class {
2698
2797
  const first = tags[0];
2699
2798
  const rest = tags.slice(1);
2700
2799
  this.adPodQueue = rest;
2800
+ if (!this.showAds) {
2801
+ this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
2802
+ }
2701
2803
  this.playSingleAd(first).catch(() => {
2702
2804
  });
2703
2805
  }
@@ -3054,19 +3156,38 @@ var StormcloudVideoPlayer = class {
3054
3156
  if (vastTagUrls.length > 0) {
3055
3157
  this.adPodAllUrls = [...vastTagUrls];
3056
3158
  this.preloadingAdUrls.clear();
3159
+ this.vastToMediaUrlMap.clear();
3160
+ this.preloadedMediaUrls.clear();
3161
+ this.preloadingMediaUrls.clear();
3057
3162
  this.logQueuedAdUrls(this.adPodAllUrls);
3163
+ if (this.config.debugAdTiming) {
3164
+ console.log(
3165
+ `[StormcloudVideoPlayer] Capturing original audio state before ad break:`,
3166
+ {
3167
+ videoMuted: this.video.muted,
3168
+ videoVolume: this.video.volume
3169
+ }
3170
+ );
3171
+ }
3172
+ this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3058
3173
  this.inAdBreak = true;
3059
- this.showAds = true;
3060
3174
  this.currentAdIndex = 0;
3061
3175
  this.totalAdsInBreak = vastTagUrls.length;
3062
3176
  this.adPodQueue = [...vastTagUrls];
3063
3177
  this.enforceAdHoldState();
3064
- this.preloadUpcomingAds();
3065
3178
  if (this.config.debugAdTiming) {
3066
3179
  console.log(
3067
- `[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
3180
+ `[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - preloading all ads in parallel`
3068
3181
  );
3069
3182
  }
3183
+ this.preloadAllAdsInBackground().catch((error) => {
3184
+ if (this.config.debugAdTiming) {
3185
+ console.warn(
3186
+ "[StormcloudVideoPlayer] Error in background preloading:",
3187
+ error
3188
+ );
3189
+ }
3190
+ });
3070
3191
  try {
3071
3192
  await this.playAdPod();
3072
3193
  } catch (error) {
@@ -3092,14 +3213,28 @@ var StormcloudVideoPlayer = class {
3092
3213
  }
3093
3214
  return;
3094
3215
  }
3095
- const firstAd = this.adPodQueue.shift();
3216
+ await new Promise((resolve) => setTimeout(resolve, 500));
3217
+ const firstPreloaded = this.findNextPreloadedAd();
3218
+ if (!firstPreloaded) {
3219
+ if (this.config.debugAdTiming) {
3220
+ console.log(
3221
+ "[StormcloudVideoPlayer] No preloaded ads available after waiting, trying first ad anyway"
3222
+ );
3223
+ }
3224
+ const firstAd = this.adPodQueue.shift();
3225
+ if (firstAd) {
3226
+ this.currentAdIndex++;
3227
+ await this.playSingleAd(firstAd);
3228
+ }
3229
+ return;
3230
+ }
3096
3231
  this.currentAdIndex++;
3097
3232
  if (this.config.debugAdTiming) {
3098
3233
  console.log(
3099
- `[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
3234
+ `[StormcloudVideoPlayer] Playing first preloaded ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
3100
3235
  );
3101
3236
  }
3102
- await this.playSingleAd(firstAd);
3237
+ await this.playSingleAd(firstPreloaded);
3103
3238
  }
3104
3239
  findCurrentOrNextBreak(nowMs) {
3105
3240
  var _a;
@@ -3132,6 +3267,7 @@ var StormcloudVideoPlayer = class {
3132
3267
  const first = tags[0];
3133
3268
  const rest = tags.slice(1);
3134
3269
  this.adPodQueue = rest;
3270
+ this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3135
3271
  this.enforceAdHoldState();
3136
3272
  await this.playSingleAd(first);
3137
3273
  this.inAdBreak = true;
@@ -3252,27 +3388,9 @@ var StormcloudVideoPlayer = class {
3252
3388
  `[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
3253
3389
  );
3254
3390
  }
3255
- if (!this.showAds) {
3256
- if (this.config.debugAdTiming) {
3257
- console.log(
3258
- `[StormcloudVideoPlayer] Capturing original state before ad request:`,
3259
- {
3260
- videoMuted: this.video.muted,
3261
- videoVolume: this.video.volume,
3262
- showAds: this.showAds
3263
- }
3264
- );
3265
- }
3266
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3267
- } else if (this.config.debugAdTiming) {
3268
- console.log(
3269
- `[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
3270
- );
3271
- }
3272
3391
  this.startAdFailsafeTimer();
3273
3392
  try {
3274
3393
  await this.ima.requestAds(vastTagUrl);
3275
- this.preloadUpcomingAds();
3276
3394
  try {
3277
3395
  if (this.config.debugAdTiming) {
3278
3396
  console.log(
@@ -3281,9 +3399,10 @@ var StormcloudVideoPlayer = class {
3281
3399
  }
3282
3400
  this.enforceAdHoldState();
3283
3401
  await this.ima.play();
3402
+ this.showAds = true;
3284
3403
  if (this.config.debugAdTiming) {
3285
3404
  console.log(
3286
- "[StormcloudVideoPlayer] Ad playback started successfully"
3405
+ "[StormcloudVideoPlayer] Ad playback started successfully, showAds = true"
3287
3406
  );
3288
3407
  }
3289
3408
  } catch (playError) {
@@ -3311,6 +3430,9 @@ var StormcloudVideoPlayer = class {
3311
3430
  }
3312
3431
  this.releaseAdHoldState();
3313
3432
  this.preloadingAdUrls.clear();
3433
+ this.vastToMediaUrlMap.clear();
3434
+ this.preloadedMediaUrls.clear();
3435
+ this.preloadingMediaUrls.clear();
3314
3436
  this.inAdBreak = false;
3315
3437
  this.expectedAdBreakDurationMs = void 0;
3316
3438
  this.currentAdBreakStartWallClockMs = void 0;
@@ -3420,44 +3542,204 @@ var StormcloudVideoPlayer = class {
3420
3542
  this.ima.hidePlaceholder();
3421
3543
  }
3422
3544
  }
3423
- preloadUpcomingAds() {
3424
- if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
3425
- return;
3545
+ async fetchAndParseVastXml(vastTagUrl) {
3546
+ try {
3547
+ const response = await fetch(vastTagUrl, { mode: "cors" });
3548
+ if (!response.ok) {
3549
+ throw new Error(`Failed to fetch VAST: ${response.status}`);
3550
+ }
3551
+ const xmlText = await response.text();
3552
+ return this.extractMediaUrlsFromVast(xmlText);
3553
+ } catch (error) {
3554
+ if (this.config.debugAdTiming) {
3555
+ console.warn(
3556
+ `[StormcloudVideoPlayer] Failed to fetch/parse VAST XML: ${vastTagUrl}`,
3557
+ error
3558
+ );
3559
+ }
3560
+ return [];
3426
3561
  }
3427
- const upcoming = this.adPodQueue.slice(0, 2);
3428
- for (const url of upcoming) {
3429
- if (!url) continue;
3430
- if (this.ima.hasPreloadedAd(url)) {
3431
- this.preloadingAdUrls.delete(url);
3432
- continue;
3562
+ }
3563
+ extractMediaUrlsFromVast(xmlText) {
3564
+ var _a;
3565
+ const mediaUrls = [];
3566
+ try {
3567
+ const parser = new DOMParser();
3568
+ const xmlDoc = parser.parseFromString(xmlText, "text/xml");
3569
+ const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
3570
+ for (const mediaFile of Array.from(mediaFileElements)) {
3571
+ const url = (_a = mediaFile.textContent) == null ? void 0 : _a.trim();
3572
+ if (url) {
3573
+ const lowerUrl = url.toLowerCase();
3574
+ if (lowerUrl.endsWith(".mp4") || lowerUrl.endsWith(".webm") || lowerUrl.endsWith(".mov") || lowerUrl.endsWith(".avi") || lowerUrl.includes(".mp4?") || lowerUrl.includes(".webm?") || lowerUrl.includes("/mp4/") || lowerUrl.includes("type=video")) {
3575
+ mediaUrls.push(url);
3576
+ }
3577
+ }
3433
3578
  }
3434
- if (this.preloadingAdUrls.has(url)) {
3435
- continue;
3579
+ if (this.config.debugAdTiming && mediaUrls.length > 0) {
3580
+ console.log(
3581
+ `[StormcloudVideoPlayer] Extracted ${mediaUrls.length} media URLs from VAST:`,
3582
+ mediaUrls
3583
+ );
3584
+ }
3585
+ } catch (error) {
3586
+ if (this.config.debugAdTiming) {
3587
+ console.warn(
3588
+ "[StormcloudVideoPlayer] Failed to parse VAST XML:",
3589
+ error
3590
+ );
3436
3591
  }
3592
+ }
3593
+ return mediaUrls;
3594
+ }
3595
+ async preloadMediaFile(mediaUrl) {
3596
+ if (this.preloadedMediaUrls.has(mediaUrl)) {
3597
+ return;
3598
+ }
3599
+ if (this.preloadingMediaUrls.has(mediaUrl)) {
3600
+ return;
3601
+ }
3602
+ this.preloadingMediaUrls.add(mediaUrl);
3603
+ try {
3437
3604
  if (this.config.debugAdTiming) {
3438
3605
  console.log(
3439
- `[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
3606
+ `[StormcloudVideoPlayer] Preloading video file: ${mediaUrl}`
3440
3607
  );
3441
3608
  }
3442
- this.preloadingAdUrls.add(url);
3443
- this.ima.preloadAds(url).then(() => {
3609
+ const response = await fetch(mediaUrl, {
3610
+ mode: "cors",
3611
+ method: "GET",
3612
+ headers: {
3613
+ Range: "bytes=0-1048576"
3614
+ }
3615
+ });
3616
+ if (response.ok || response.status === 206) {
3617
+ this.preloadedMediaUrls.add(mediaUrl);
3444
3618
  if (this.config.debugAdTiming) {
3445
3619
  console.log(
3446
- `[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
3620
+ `[StormcloudVideoPlayer] Successfully preloaded video file: ${mediaUrl}`
3447
3621
  );
3448
3622
  }
3449
- }).catch((error) => {
3623
+ }
3624
+ } catch (error) {
3625
+ if (this.config.debugAdTiming) {
3626
+ console.warn(
3627
+ `[StormcloudVideoPlayer] Failed to preload video file: ${mediaUrl}`,
3628
+ error
3629
+ );
3630
+ }
3631
+ } finally {
3632
+ this.preloadingMediaUrls.delete(mediaUrl);
3633
+ }
3634
+ }
3635
+ async preloadAllAdsInBackground() {
3636
+ if (this.adPodAllUrls.length === 0) {
3637
+ return;
3638
+ }
3639
+ if (this.config.debugAdTiming) {
3640
+ console.log(
3641
+ `[StormcloudVideoPlayer] Starting parallel preload of ${this.adPodAllUrls.length} ads`
3642
+ );
3643
+ }
3644
+ const preloadPromises = this.adPodAllUrls.map(
3645
+ (vastTagUrl) => this.preloadSingleAd(vastTagUrl).catch((error) => {
3450
3646
  if (this.config.debugAdTiming) {
3451
3647
  console.warn(
3452
- `[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
3648
+ `[StormcloudVideoPlayer] Preload failed for ${vastTagUrl}:`,
3453
3649
  error
3454
3650
  );
3455
3651
  }
3456
- }).finally(() => {
3457
- this.preloadingAdUrls.delete(url);
3458
- });
3652
+ })
3653
+ );
3654
+ await Promise.all(preloadPromises);
3655
+ if (this.config.debugAdTiming) {
3656
+ console.log(
3657
+ `[StormcloudVideoPlayer] Background preloading completed for all ads`
3658
+ );
3459
3659
  }
3460
3660
  }
3661
+ async preloadSingleAd(vastTagUrl) {
3662
+ if (!vastTagUrl) return;
3663
+ try {
3664
+ if (this.ima.preloadAds && !this.ima.hasPreloadedAd(vastTagUrl)) {
3665
+ if (!this.preloadingAdUrls.has(vastTagUrl)) {
3666
+ if (this.config.debugAdTiming) {
3667
+ console.log(
3668
+ `[StormcloudVideoPlayer] Preloading VAST: ${vastTagUrl}`
3669
+ );
3670
+ }
3671
+ this.preloadingAdUrls.add(vastTagUrl);
3672
+ await this.ima.preloadAds(vastTagUrl).then(() => {
3673
+ if (this.config.debugAdTiming) {
3674
+ console.log(
3675
+ `[StormcloudVideoPlayer] IMA VAST preload complete: ${vastTagUrl}`
3676
+ );
3677
+ }
3678
+ }).catch((error) => {
3679
+ if (this.config.debugAdTiming) {
3680
+ console.warn(
3681
+ `[StormcloudVideoPlayer] IMA VAST preload failed: ${vastTagUrl}`,
3682
+ error
3683
+ );
3684
+ }
3685
+ }).finally(() => {
3686
+ this.preloadingAdUrls.delete(vastTagUrl);
3687
+ });
3688
+ }
3689
+ }
3690
+ let mediaUrls = this.vastToMediaUrlMap.get(vastTagUrl);
3691
+ if (!mediaUrls) {
3692
+ if (this.config.debugAdTiming) {
3693
+ console.log(
3694
+ `[StormcloudVideoPlayer] Fetching and parsing VAST to extract media URLs: ${vastTagUrl}`
3695
+ );
3696
+ }
3697
+ mediaUrls = await this.fetchAndParseVastXml(vastTagUrl);
3698
+ if (mediaUrls.length > 0) {
3699
+ this.vastToMediaUrlMap.set(vastTagUrl, mediaUrls);
3700
+ }
3701
+ }
3702
+ if (mediaUrls && mediaUrls.length > 0) {
3703
+ const primaryMediaUrl = mediaUrls[0];
3704
+ if (primaryMediaUrl && !this.preloadedMediaUrls.has(primaryMediaUrl)) {
3705
+ await this.preloadMediaFile(primaryMediaUrl);
3706
+ }
3707
+ }
3708
+ } catch (error) {
3709
+ if (this.config.debugAdTiming) {
3710
+ console.warn(
3711
+ `[StormcloudVideoPlayer] Failed to preload ad: ${vastTagUrl}`,
3712
+ error
3713
+ );
3714
+ }
3715
+ }
3716
+ }
3717
+ findNextPreloadedAd() {
3718
+ var _a, _b, _c;
3719
+ for (let i = 0; i < this.adPodQueue.length; i++) {
3720
+ const vastTagUrl = this.adPodQueue[i];
3721
+ if (!vastTagUrl) continue;
3722
+ const hasImaPreload = (_c = (_b = (_a = this.ima).hasPreloadedAd) == null ? void 0 : _b.call(_a, vastTagUrl)) != null ? _c : false;
3723
+ const mediaUrls = this.vastToMediaUrlMap.get(vastTagUrl);
3724
+ const hasMediaPreload = mediaUrls && mediaUrls.length > 0 ? this.preloadedMediaUrls.has(mediaUrls[0]) : false;
3725
+ if (hasImaPreload || hasMediaPreload) {
3726
+ if (this.config.debugAdTiming) {
3727
+ console.log(
3728
+ `[StormcloudVideoPlayer] Found preloaded ad at index ${i}: ${vastTagUrl}`,
3729
+ { hasImaPreload, hasMediaPreload }
3730
+ );
3731
+ }
3732
+ this.adPodQueue.splice(0, i + 1);
3733
+ return vastTagUrl;
3734
+ }
3735
+ }
3736
+ if (this.config.debugAdTiming) {
3737
+ console.log(
3738
+ "[StormcloudVideoPlayer] No preloaded ads found in queue"
3739
+ );
3740
+ }
3741
+ return void 0;
3742
+ }
3461
3743
  getRemainingAdMs() {
3462
3744
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
3463
3745
  return 0;
@@ -3626,6 +3908,9 @@ var StormcloudVideoPlayer = class {
3626
3908
  (_b = this.ima) == null ? void 0 : _b.destroy();
3627
3909
  this.releaseAdHoldState();
3628
3910
  this.preloadingAdUrls.clear();
3911
+ this.vastToMediaUrlMap.clear();
3912
+ this.preloadedMediaUrls.clear();
3913
+ this.preloadingMediaUrls.clear();
3629
3914
  this.adPodAllUrls = [];
3630
3915
  }
3631
3916
  };