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.
- package/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +387 -102
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +9 -1
- package/lib/index.d.ts +9 -1
- package/lib/index.js +387 -102
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +387 -102
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +9 -1
- package/lib/players/HlsPlayer.cjs +387 -102
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +387 -102
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/ima.cjs +103 -33
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +387 -102
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +2 -2
|
@@ -214,7 +214,11 @@ function createImaController(video, options) {
|
|
|
214
214
|
}
|
|
215
215
|
function hideContentVideo() {
|
|
216
216
|
if (!contentVideoHidden) {
|
|
217
|
-
video.style.
|
|
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 = "
|
|
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 = "
|
|
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.
|
|
577
|
-
adContainerEl.style.
|
|
578
|
-
|
|
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.
|
|
663
|
-
adContainerEl.style.
|
|
664
|
-
|
|
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.
|
|
687
|
-
adContainerEl.style.
|
|
688
|
-
|
|
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.
|
|
718
|
-
adContainerEl.style.
|
|
719
|
-
|
|
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.
|
|
829
|
-
adContainerEl.style.
|
|
830
|
-
|
|
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.
|
|
846
|
-
adContainerEl.style.
|
|
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.
|
|
944
|
-
adContainerEl.style.
|
|
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.
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
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.
|
|
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
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
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.
|
|
2449
|
-
|
|
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 -
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
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
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
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.
|
|
3432
|
-
|
|
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]
|
|
3603
|
+
`[StormcloudVideoPlayer] Preloading video file: ${mediaUrl}`
|
|
3437
3604
|
);
|
|
3438
3605
|
}
|
|
3439
|
-
|
|
3440
|
-
|
|
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]
|
|
3617
|
+
`[StormcloudVideoPlayer] Successfully preloaded video file: ${mediaUrl}`
|
|
3444
3618
|
);
|
|
3445
3619
|
}
|
|
3446
|
-
}
|
|
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]
|
|
3645
|
+
`[StormcloudVideoPlayer] Preload failed for ${vastTagUrl}:`,
|
|
3450
3646
|
error
|
|
3451
3647
|
);
|
|
3452
3648
|
}
|
|
3453
|
-
})
|
|
3454
|
-
|
|
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
|
};
|