stormcloud-video-player 0.2.31 → 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 +293 -69
- 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 +293 -69
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +293 -69
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +9 -1
- package/lib/players/HlsPlayer.cjs +293 -69
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +293 -69
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/ima.cjs +9 -0
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +293 -69
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +2 -2
|
@@ -28,6 +28,9 @@ declare class StormcloudVideoPlayer {
|
|
|
28
28
|
private hasInitialBufferCompleted;
|
|
29
29
|
private adPodAllUrls;
|
|
30
30
|
private preloadingAdUrls;
|
|
31
|
+
private vastToMediaUrlMap;
|
|
32
|
+
private preloadedMediaUrls;
|
|
33
|
+
private preloadingMediaUrls;
|
|
31
34
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
32
35
|
private createAdPlayer;
|
|
33
36
|
load(): Promise<void>;
|
|
@@ -73,7 +76,12 @@ declare class StormcloudVideoPlayer {
|
|
|
73
76
|
private logQueuedAdUrls;
|
|
74
77
|
private enforceAdHoldState;
|
|
75
78
|
private releaseAdHoldState;
|
|
76
|
-
private
|
|
79
|
+
private fetchAndParseVastXml;
|
|
80
|
+
private extractMediaUrlsFromVast;
|
|
81
|
+
private preloadMediaFile;
|
|
82
|
+
private preloadAllAdsInBackground;
|
|
83
|
+
private preloadSingleAd;
|
|
84
|
+
private findNextPreloadedAd;
|
|
77
85
|
private getRemainingAdMs;
|
|
78
86
|
private findBreakForTime;
|
|
79
87
|
toggleMute(): void;
|
|
@@ -642,6 +642,15 @@ function createImaController(video, options) {
|
|
|
642
642
|
"[IMA] Content video continues in background (Live mode)"
|
|
643
643
|
);
|
|
644
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
|
+
}
|
|
645
654
|
adPlaying = true;
|
|
646
655
|
setAdPlayingFlag(true);
|
|
647
656
|
emit("content_pause");
|
|
@@ -2176,6 +2185,9 @@ var StormcloudVideoPlayer = class {
|
|
|
2176
2185
|
this.hasInitialBufferCompleted = false;
|
|
2177
2186
|
this.adPodAllUrls = [];
|
|
2178
2187
|
this.preloadingAdUrls = /* @__PURE__ */ new Set();
|
|
2188
|
+
this.vastToMediaUrlMap = /* @__PURE__ */ new Map();
|
|
2189
|
+
this.preloadedMediaUrls = /* @__PURE__ */ new Set();
|
|
2190
|
+
this.preloadingMediaUrls = /* @__PURE__ */ new Set();
|
|
2179
2191
|
initializePolyfills();
|
|
2180
2192
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2181
2193
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2448,27 +2460,44 @@ var StormcloudVideoPlayer = class {
|
|
|
2448
2460
|
});
|
|
2449
2461
|
this.ima.on("ad_error", () => {
|
|
2450
2462
|
if (this.config.debugAdTiming) {
|
|
2451
|
-
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
|
+
});
|
|
2452
2468
|
}
|
|
2453
|
-
if (this.
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
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) {
|
|
2458
2474
|
this.currentAdIndex++;
|
|
2459
|
-
this.
|
|
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();
|
|
2460
2482
|
});
|
|
2461
2483
|
} else {
|
|
2484
|
+
if (this.config.debugAdTiming) {
|
|
2485
|
+
console.log(
|
|
2486
|
+
"[StormcloudVideoPlayer] No preloaded ads available, ending ad break"
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2462
2489
|
this.handleAdFailure();
|
|
2463
2490
|
}
|
|
2464
2491
|
} else {
|
|
2465
|
-
if (this.config.debugAdTiming) {
|
|
2466
|
-
console.log(
|
|
2467
|
-
"[StormcloudVideoPlayer] Ad error before ad break established - cleaning up"
|
|
2468
|
-
);
|
|
2469
|
-
}
|
|
2470
2492
|
this.handleAdFailure();
|
|
2471
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();
|
|
2472
2501
|
}
|
|
2473
2502
|
});
|
|
2474
2503
|
this.ima.on("content_pause", () => {
|
|
@@ -2499,22 +2528,31 @@ var StormcloudVideoPlayer = class {
|
|
|
2499
2528
|
}
|
|
2500
2529
|
const remaining = this.getRemainingAdMs();
|
|
2501
2530
|
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
console.log(
|
|
2507
|
-
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
|
|
2508
|
-
);
|
|
2509
|
-
}
|
|
2510
|
-
this.playSingleAd(next).catch(() => {
|
|
2531
|
+
const nextPreloaded = this.findNextPreloadedAd();
|
|
2532
|
+
if (nextPreloaded) {
|
|
2533
|
+
this.currentAdIndex++;
|
|
2534
|
+
this.enforceAdHoldState();
|
|
2511
2535
|
if (this.config.debugAdTiming) {
|
|
2512
|
-
console.
|
|
2513
|
-
|
|
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"
|
|
2514
2552
|
);
|
|
2515
2553
|
}
|
|
2516
2554
|
this.handleAdPodComplete();
|
|
2517
|
-
}
|
|
2555
|
+
}
|
|
2518
2556
|
} else {
|
|
2519
2557
|
if (this.config.debugAdTiming) {
|
|
2520
2558
|
console.log(
|
|
@@ -2759,6 +2797,9 @@ var StormcloudVideoPlayer = class {
|
|
|
2759
2797
|
const first = tags[0];
|
|
2760
2798
|
const rest = tags.slice(1);
|
|
2761
2799
|
this.adPodQueue = rest;
|
|
2800
|
+
if (!this.showAds) {
|
|
2801
|
+
this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
|
|
2802
|
+
}
|
|
2762
2803
|
this.playSingleAd(first).catch(() => {
|
|
2763
2804
|
});
|
|
2764
2805
|
}
|
|
@@ -3115,19 +3156,38 @@ var StormcloudVideoPlayer = class {
|
|
|
3115
3156
|
if (vastTagUrls.length > 0) {
|
|
3116
3157
|
this.adPodAllUrls = [...vastTagUrls];
|
|
3117
3158
|
this.preloadingAdUrls.clear();
|
|
3159
|
+
this.vastToMediaUrlMap.clear();
|
|
3160
|
+
this.preloadedMediaUrls.clear();
|
|
3161
|
+
this.preloadingMediaUrls.clear();
|
|
3118
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);
|
|
3119
3173
|
this.inAdBreak = true;
|
|
3120
|
-
this.showAds = true;
|
|
3121
3174
|
this.currentAdIndex = 0;
|
|
3122
3175
|
this.totalAdsInBreak = vastTagUrls.length;
|
|
3123
3176
|
this.adPodQueue = [...vastTagUrls];
|
|
3124
3177
|
this.enforceAdHoldState();
|
|
3125
|
-
this.preloadUpcomingAds();
|
|
3126
3178
|
if (this.config.debugAdTiming) {
|
|
3127
3179
|
console.log(
|
|
3128
|
-
`[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads -
|
|
3180
|
+
`[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - preloading all ads in parallel`
|
|
3129
3181
|
);
|
|
3130
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
|
+
});
|
|
3131
3191
|
try {
|
|
3132
3192
|
await this.playAdPod();
|
|
3133
3193
|
} catch (error) {
|
|
@@ -3153,14 +3213,28 @@ var StormcloudVideoPlayer = class {
|
|
|
3153
3213
|
}
|
|
3154
3214
|
return;
|
|
3155
3215
|
}
|
|
3156
|
-
|
|
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
|
+
}
|
|
3157
3231
|
this.currentAdIndex++;
|
|
3158
3232
|
if (this.config.debugAdTiming) {
|
|
3159
3233
|
console.log(
|
|
3160
|
-
`[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
|
|
3234
|
+
`[StormcloudVideoPlayer] Playing first preloaded ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
|
|
3161
3235
|
);
|
|
3162
3236
|
}
|
|
3163
|
-
await this.playSingleAd(
|
|
3237
|
+
await this.playSingleAd(firstPreloaded);
|
|
3164
3238
|
}
|
|
3165
3239
|
findCurrentOrNextBreak(nowMs) {
|
|
3166
3240
|
var _a;
|
|
@@ -3193,6 +3267,7 @@ var StormcloudVideoPlayer = class {
|
|
|
3193
3267
|
const first = tags[0];
|
|
3194
3268
|
const rest = tags.slice(1);
|
|
3195
3269
|
this.adPodQueue = rest;
|
|
3270
|
+
this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
|
|
3196
3271
|
this.enforceAdHoldState();
|
|
3197
3272
|
await this.playSingleAd(first);
|
|
3198
3273
|
this.inAdBreak = true;
|
|
@@ -3313,27 +3388,9 @@ var StormcloudVideoPlayer = class {
|
|
|
3313
3388
|
`[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
|
|
3314
3389
|
);
|
|
3315
3390
|
}
|
|
3316
|
-
if (!this.showAds) {
|
|
3317
|
-
if (this.config.debugAdTiming) {
|
|
3318
|
-
console.log(
|
|
3319
|
-
`[StormcloudVideoPlayer] Capturing original state before ad request:`,
|
|
3320
|
-
{
|
|
3321
|
-
videoMuted: this.video.muted,
|
|
3322
|
-
videoVolume: this.video.volume,
|
|
3323
|
-
showAds: this.showAds
|
|
3324
|
-
}
|
|
3325
|
-
);
|
|
3326
|
-
}
|
|
3327
|
-
this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
|
|
3328
|
-
} else if (this.config.debugAdTiming) {
|
|
3329
|
-
console.log(
|
|
3330
|
-
`[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
|
|
3331
|
-
);
|
|
3332
|
-
}
|
|
3333
3391
|
this.startAdFailsafeTimer();
|
|
3334
3392
|
try {
|
|
3335
3393
|
await this.ima.requestAds(vastTagUrl);
|
|
3336
|
-
this.preloadUpcomingAds();
|
|
3337
3394
|
try {
|
|
3338
3395
|
if (this.config.debugAdTiming) {
|
|
3339
3396
|
console.log(
|
|
@@ -3342,9 +3399,10 @@ var StormcloudVideoPlayer = class {
|
|
|
3342
3399
|
}
|
|
3343
3400
|
this.enforceAdHoldState();
|
|
3344
3401
|
await this.ima.play();
|
|
3402
|
+
this.showAds = true;
|
|
3345
3403
|
if (this.config.debugAdTiming) {
|
|
3346
3404
|
console.log(
|
|
3347
|
-
"[StormcloudVideoPlayer] Ad playback started successfully"
|
|
3405
|
+
"[StormcloudVideoPlayer] Ad playback started successfully, showAds = true"
|
|
3348
3406
|
);
|
|
3349
3407
|
}
|
|
3350
3408
|
} catch (playError) {
|
|
@@ -3372,6 +3430,9 @@ var StormcloudVideoPlayer = class {
|
|
|
3372
3430
|
}
|
|
3373
3431
|
this.releaseAdHoldState();
|
|
3374
3432
|
this.preloadingAdUrls.clear();
|
|
3433
|
+
this.vastToMediaUrlMap.clear();
|
|
3434
|
+
this.preloadedMediaUrls.clear();
|
|
3435
|
+
this.preloadingMediaUrls.clear();
|
|
3375
3436
|
this.inAdBreak = false;
|
|
3376
3437
|
this.expectedAdBreakDurationMs = void 0;
|
|
3377
3438
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3481,44 +3542,204 @@ var StormcloudVideoPlayer = class {
|
|
|
3481
3542
|
this.ima.hidePlaceholder();
|
|
3482
3543
|
}
|
|
3483
3544
|
}
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
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 [];
|
|
3487
3561
|
}
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
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
|
+
}
|
|
3494
3578
|
}
|
|
3495
|
-
if (this.
|
|
3496
|
-
|
|
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
|
+
);
|
|
3497
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 {
|
|
3498
3604
|
if (this.config.debugAdTiming) {
|
|
3499
3605
|
console.log(
|
|
3500
|
-
`[StormcloudVideoPlayer]
|
|
3606
|
+
`[StormcloudVideoPlayer] Preloading video file: ${mediaUrl}`
|
|
3501
3607
|
);
|
|
3502
3608
|
}
|
|
3503
|
-
|
|
3504
|
-
|
|
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);
|
|
3505
3618
|
if (this.config.debugAdTiming) {
|
|
3506
3619
|
console.log(
|
|
3507
|
-
`[StormcloudVideoPlayer]
|
|
3620
|
+
`[StormcloudVideoPlayer] Successfully preloaded video file: ${mediaUrl}`
|
|
3508
3621
|
);
|
|
3509
3622
|
}
|
|
3510
|
-
}
|
|
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) => {
|
|
3511
3646
|
if (this.config.debugAdTiming) {
|
|
3512
3647
|
console.warn(
|
|
3513
|
-
`[StormcloudVideoPlayer]
|
|
3648
|
+
`[StormcloudVideoPlayer] Preload failed for ${vastTagUrl}:`,
|
|
3514
3649
|
error
|
|
3515
3650
|
);
|
|
3516
3651
|
}
|
|
3517
|
-
})
|
|
3518
|
-
|
|
3519
|
-
|
|
3652
|
+
})
|
|
3653
|
+
);
|
|
3654
|
+
await Promise.all(preloadPromises);
|
|
3655
|
+
if (this.config.debugAdTiming) {
|
|
3656
|
+
console.log(
|
|
3657
|
+
`[StormcloudVideoPlayer] Background preloading completed for all ads`
|
|
3658
|
+
);
|
|
3520
3659
|
}
|
|
3521
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
|
+
}
|
|
3522
3743
|
getRemainingAdMs() {
|
|
3523
3744
|
if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
|
|
3524
3745
|
return 0;
|
|
@@ -3687,6 +3908,9 @@ var StormcloudVideoPlayer = class {
|
|
|
3687
3908
|
(_b = this.ima) == null ? void 0 : _b.destroy();
|
|
3688
3909
|
this.releaseAdHoldState();
|
|
3689
3910
|
this.preloadingAdUrls.clear();
|
|
3911
|
+
this.vastToMediaUrlMap.clear();
|
|
3912
|
+
this.preloadedMediaUrls.clear();
|
|
3913
|
+
this.preloadingMediaUrls.clear();
|
|
3690
3914
|
this.adPodAllUrls = [];
|
|
3691
3915
|
}
|
|
3692
3916
|
};
|