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