stormcloud-video-player 0.3.8 → 0.3.10
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 +242 -193
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +11 -2
- package/lib/index.d.ts +11 -2
- package/lib/index.js +242 -193
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +242 -193
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +11 -2
- package/lib/players/HlsPlayer.cjs +242 -193
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +242 -193
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/ima.cjs +3 -10
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +242 -193
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -408,12 +408,8 @@ function createImaController(video, options) {
|
|
|
408
408
|
let adsLoadedReject;
|
|
409
409
|
function makeAdsRequest(google, vastTagUrl) {
|
|
410
410
|
const adsRequest = new google.ima.AdsRequest();
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
adsRequest.adsResponse = preloadedResponse;
|
|
414
|
-
} else {
|
|
415
|
-
adsRequest.adTagUrl = vastTagUrl;
|
|
416
|
-
}
|
|
411
|
+
console.log("[IMA] \u{1F4E1} Requesting VAST from URL (letting IMA fetch fresh)");
|
|
412
|
+
adsRequest.adTagUrl = vastTagUrl;
|
|
417
413
|
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
418
414
|
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
419
415
|
adsRequest.linearAdSlotWidth = videoWidth;
|
|
@@ -436,11 +432,8 @@ function createImaController(video, options) {
|
|
|
436
432
|
console.warn("[IMA] Failed to call setAdWillPlayMuted:", error);
|
|
437
433
|
}
|
|
438
434
|
}
|
|
439
|
-
adsRequest.vastLoadTimeout =
|
|
435
|
+
adsRequest.vastLoadTimeout = 1e4;
|
|
440
436
|
adsLoader.requestAds(adsRequest);
|
|
441
|
-
if (preloadedResponse) {
|
|
442
|
-
preloadedVast.delete(vastTagUrl);
|
|
443
|
-
}
|
|
444
437
|
}
|
|
445
438
|
function ensurePlaceholderContainer() {
|
|
446
439
|
var _a;
|
|
@@ -2156,6 +2149,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2156
2149
|
this.targetAdBreakDurationMs = null;
|
|
2157
2150
|
this.isAdaptiveMode = false;
|
|
2158
2151
|
this.failedVastUrls = /* @__PURE__ */ new Set();
|
|
2152
|
+
this.continuousFetchingActive = false;
|
|
2153
|
+
this.adRequestQueue = [];
|
|
2154
|
+
this.successfulAdRequests = [];
|
|
2155
|
+
this.maxPlaceholderDurationMs = 5e3;
|
|
2156
|
+
this.placeholderStartTimeMs = null;
|
|
2157
|
+
this.isShowingPlaceholder = false;
|
|
2159
2158
|
initializePolyfills();
|
|
2160
2159
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2161
2160
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2462,16 +2461,11 @@ var StormcloudVideoPlayer = class {
|
|
|
2462
2461
|
return;
|
|
2463
2462
|
}
|
|
2464
2463
|
const remaining = this.getRemainingAdMs();
|
|
2465
|
-
if (
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
this.handleAdPodComplete();
|
|
2471
|
-
});
|
|
2472
|
-
} else {
|
|
2473
|
-
this.handleAdPodComplete();
|
|
2474
|
-
}
|
|
2464
|
+
if (this.config.debugAdTiming) {
|
|
2465
|
+
console.log(`[CONTINUOUS-FETCH] content_resume event: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
2466
|
+
}
|
|
2467
|
+
if (remaining > 500) {
|
|
2468
|
+
this.tryNextAvailableAd();
|
|
2475
2469
|
} else {
|
|
2476
2470
|
this.handleAdPodComplete();
|
|
2477
2471
|
}
|
|
@@ -3071,155 +3065,240 @@ var StormcloudVideoPlayer = class {
|
|
|
3071
3065
|
return true;
|
|
3072
3066
|
}
|
|
3073
3067
|
async handleAdStart(_marker) {
|
|
3074
|
-
var _a;
|
|
3075
3068
|
const scheduled = this.findCurrentOrNextBreak(
|
|
3076
3069
|
this.video.currentTime * 1e3
|
|
3077
3070
|
);
|
|
3078
3071
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
3079
|
-
let
|
|
3072
|
+
let baseVastUrl;
|
|
3080
3073
|
if (this.apiVastTagUrl) {
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3074
|
+
baseVastUrl = this.apiVastTagUrl;
|
|
3075
|
+
} else if (tags && tags.length > 0 && tags[0]) {
|
|
3076
|
+
baseVastUrl = tags[0];
|
|
3077
|
+
} else {
|
|
3078
|
+
return;
|
|
3079
|
+
}
|
|
3080
|
+
const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
|
|
3081
|
+
if (this.isLiveStream && adBreakDurationMs != null && adBreakDurationMs > 0) {
|
|
3082
|
+
this.isAdaptiveMode = true;
|
|
3083
|
+
this.targetAdBreakDurationMs = adBreakDurationMs;
|
|
3084
|
+
this.fetchedAdDurations.clear();
|
|
3085
|
+
if (this.config.debugAdTiming) {
|
|
3086
|
+
console.log(
|
|
3087
|
+
`[CONTINUOUS-FETCH] \u{1F4FA} LIVE MODE: Target duration=${adBreakDurationMs}ms | Will continuously fetch ads during break`
|
|
3088
|
+
);
|
|
3089
|
+
}
|
|
3090
|
+
} else {
|
|
3091
|
+
this.isAdaptiveMode = false;
|
|
3092
|
+
this.targetAdBreakDurationMs = null;
|
|
3093
|
+
this.fetchedAdDurations.clear();
|
|
3094
|
+
if (this.config.debugAdTiming) {
|
|
3095
|
+
console.log(
|
|
3096
|
+
`[CONTINUOUS-FETCH] \u{1F3AC} VOD MODE: Using fixed ad strategy`
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
this.adPodAllUrls = [];
|
|
3101
|
+
this.preloadingAdUrls.clear();
|
|
3102
|
+
this.vastToMediaUrlMap.clear();
|
|
3103
|
+
this.preloadedMediaUrls.clear();
|
|
3104
|
+
this.preloadingMediaUrls.clear();
|
|
3105
|
+
this.failedVastUrls.clear();
|
|
3106
|
+
this.adRequestQueue = [];
|
|
3107
|
+
this.successfulAdRequests = [];
|
|
3108
|
+
this.continuousFetchingActive = true;
|
|
3109
|
+
this.isShowingPlaceholder = false;
|
|
3110
|
+
this.placeholderStartTimeMs = null;
|
|
3111
|
+
const currentMuted = this.video.muted;
|
|
3112
|
+
const currentVolume = this.video.volume;
|
|
3113
|
+
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3114
|
+
this.inAdBreak = true;
|
|
3115
|
+
this.currentAdIndex = 0;
|
|
3116
|
+
this.totalAdsInBreak = 1;
|
|
3117
|
+
this.adPodQueue = [];
|
|
3118
|
+
if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
|
|
3119
|
+
this.expectedAdBreakDurationMs = adBreakDurationMs;
|
|
3120
|
+
this.currentAdBreakStartWallClockMs = Date.now();
|
|
3121
|
+
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
3122
|
+
}
|
|
3123
|
+
if (this.config.debugAdTiming) {
|
|
3124
|
+
console.log("[CONTINUOUS-FETCH] \u{1F680} Immediately requesting first ad...");
|
|
3125
|
+
}
|
|
3126
|
+
const firstAdUrlArray = this.generateVastUrlsWithCorrelators(baseVastUrl, 1);
|
|
3127
|
+
const firstAdUrl = firstAdUrlArray[0];
|
|
3128
|
+
if (!firstAdUrl) {
|
|
3129
|
+
if (this.config.debugAdTiming) {
|
|
3130
|
+
console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F Failed to generate first ad URL");
|
|
3131
|
+
}
|
|
3132
|
+
this.handleAdPodComplete();
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
try {
|
|
3136
|
+
await this.ima.requestAds(firstAdUrl);
|
|
3137
|
+
if (this.config.debugAdTiming) {
|
|
3138
|
+
console.log("[CONTINUOUS-FETCH] \u2705 First ad request successful, starting playback");
|
|
3139
|
+
}
|
|
3140
|
+
this.successfulAdRequests.push(firstAdUrl);
|
|
3141
|
+
this.currentAdIndex++;
|
|
3142
|
+
this.startContinuousFetching(baseVastUrl);
|
|
3143
|
+
await this.ima.play();
|
|
3144
|
+
} catch (error) {
|
|
3145
|
+
if (this.config.debugAdTiming) {
|
|
3146
|
+
console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
|
|
3147
|
+
}
|
|
3148
|
+
this.failedVastUrls.add(firstAdUrl);
|
|
3149
|
+
this.startContinuousFetching(baseVastUrl);
|
|
3150
|
+
this.tryNextAvailableAd();
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
startContinuousFetching(baseVastUrl) {
|
|
3154
|
+
if (!this.continuousFetchingActive) {
|
|
3155
|
+
return;
|
|
3156
|
+
}
|
|
3157
|
+
if (this.config.debugAdTiming) {
|
|
3158
|
+
console.log("[CONTINUOUS-FETCH] \u{1F504} Starting continuous ad fetching loop");
|
|
3159
|
+
}
|
|
3160
|
+
this.continuousFetchLoop(baseVastUrl);
|
|
3161
|
+
}
|
|
3162
|
+
async continuousFetchLoop(baseVastUrl) {
|
|
3163
|
+
while (this.continuousFetchingActive && this.inAdBreak) {
|
|
3164
|
+
const remaining = this.getRemainingAdMs();
|
|
3165
|
+
if (remaining <= 0) {
|
|
3166
|
+
if (this.config.debugAdTiming) {
|
|
3167
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F Ad break time expired, stopping fetch loop");
|
|
3100
3168
|
}
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
this.
|
|
3105
|
-
|
|
3106
|
-
|
|
3169
|
+
break;
|
|
3170
|
+
}
|
|
3171
|
+
if (this.adRequestQueue.length > 0) {
|
|
3172
|
+
if (this.config.debugAdTiming) {
|
|
3173
|
+
console.log(`[CONTINUOUS-FETCH] \u23F3 Already have ${this.adRequestQueue.length} ads queued, waiting...`);
|
|
3174
|
+
}
|
|
3175
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3176
|
+
continue;
|
|
3177
|
+
}
|
|
3178
|
+
const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
|
|
3179
|
+
if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
|
|
3180
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3181
|
+
continue;
|
|
3182
|
+
}
|
|
3183
|
+
if (this.config.debugAdTiming) {
|
|
3184
|
+
console.log("[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch additional ad...");
|
|
3185
|
+
}
|
|
3186
|
+
try {
|
|
3187
|
+
const response = await fetch(newAdUrl, { mode: "cors" });
|
|
3188
|
+
if (!response.ok) {
|
|
3189
|
+
throw new Error(`Failed to fetch VAST: ${response.status}`);
|
|
3190
|
+
}
|
|
3191
|
+
const xmlText = await response.text();
|
|
3192
|
+
const parser = new DOMParser();
|
|
3193
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
3194
|
+
const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
|
|
3195
|
+
if (mediaFiles.length === 0) {
|
|
3107
3196
|
if (this.config.debugAdTiming) {
|
|
3108
|
-
console.log(
|
|
3109
|
-
`[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
|
|
3110
|
-
);
|
|
3197
|
+
console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
|
|
3111
3198
|
}
|
|
3199
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3200
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3201
|
+
continue;
|
|
3112
3202
|
}
|
|
3113
|
-
}
|
|
3114
|
-
if (numberOfAds > 1) {
|
|
3115
|
-
vastTagUrls = this.generateVastUrlsWithCorrelators(
|
|
3116
|
-
this.apiVastTagUrl,
|
|
3117
|
-
numberOfAds
|
|
3118
|
-
);
|
|
3119
3203
|
if (this.config.debugAdTiming) {
|
|
3120
|
-
console.log(
|
|
3121
|
-
`[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
|
|
3122
|
-
);
|
|
3204
|
+
console.log("[CONTINUOUS-FETCH] \u2705 Successfully fetched new ad, adding to queue");
|
|
3123
3205
|
}
|
|
3124
|
-
|
|
3125
|
-
|
|
3206
|
+
this.adRequestQueue.push(newAdUrl);
|
|
3207
|
+
this.totalAdsInBreak++;
|
|
3208
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3209
|
+
} catch (error) {
|
|
3210
|
+
if (this.config.debugAdTiming) {
|
|
3211
|
+
console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
|
|
3212
|
+
}
|
|
3213
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3214
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3126
3215
|
}
|
|
3127
|
-
}
|
|
3128
|
-
|
|
3129
|
-
|
|
3216
|
+
}
|
|
3217
|
+
if (this.config.debugAdTiming) {
|
|
3218
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
stopContinuousFetching() {
|
|
3222
|
+
this.continuousFetchingActive = false;
|
|
3223
|
+
if (this.config.debugAdTiming) {
|
|
3224
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
async tryNextAvailableAd() {
|
|
3228
|
+
const remaining = this.getRemainingAdMs();
|
|
3229
|
+
if (remaining <= 500) {
|
|
3230
|
+
if (this.config.debugAdTiming) {
|
|
3231
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
|
|
3232
|
+
}
|
|
3233
|
+
this.handleAdPodComplete();
|
|
3130
3234
|
return;
|
|
3131
3235
|
}
|
|
3132
|
-
if (
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
this.vastToMediaUrlMap.clear();
|
|
3136
|
-
this.preloadedMediaUrls.clear();
|
|
3137
|
-
this.preloadingMediaUrls.clear();
|
|
3138
|
-
this.failedVastUrls.clear();
|
|
3139
|
-
const currentMuted = this.video.muted;
|
|
3140
|
-
const currentVolume = this.video.volume;
|
|
3141
|
-
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3142
|
-
this.inAdBreak = true;
|
|
3143
|
-
this.currentAdIndex = 0;
|
|
3144
|
-
this.totalAdsInBreak = vastTagUrls.length;
|
|
3145
|
-
this.adPodQueue = [...vastTagUrls];
|
|
3146
|
-
if (this.isAdaptiveMode) {
|
|
3236
|
+
if (this.adRequestQueue.length > 0) {
|
|
3237
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3238
|
+
if (nextAdUrl) {
|
|
3147
3239
|
if (this.config.debugAdTiming) {
|
|
3148
|
-
console.log("[
|
|
3240
|
+
console.log("[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad");
|
|
3149
3241
|
}
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
const url = this.adPodAllUrls[i];
|
|
3154
|
-
if (url) {
|
|
3155
|
-
await this.preloadSingleAd(url);
|
|
3156
|
-
if (this.config.debugAdTiming) {
|
|
3157
|
-
console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
|
|
3158
|
-
}
|
|
3159
|
-
}
|
|
3160
|
-
}
|
|
3161
|
-
if (this.config.debugAdTiming) {
|
|
3162
|
-
console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
|
|
3163
|
-
}
|
|
3164
|
-
} catch (error) {
|
|
3165
|
-
if (this.config.debugAdTiming) {
|
|
3166
|
-
console.warn(
|
|
3167
|
-
"[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
|
|
3168
|
-
error
|
|
3169
|
-
);
|
|
3170
|
-
}
|
|
3171
|
-
}
|
|
3172
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3173
|
-
if (this.config.debugAdTiming) {
|
|
3174
|
-
console.warn(
|
|
3175
|
-
"[ADAPTIVE-POD] Error in background preloading:",
|
|
3176
|
-
error
|
|
3177
|
-
);
|
|
3178
|
-
}
|
|
3179
|
-
});
|
|
3180
|
-
await this.playAdPod();
|
|
3181
|
-
} else {
|
|
3182
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3183
|
-
if (this.config.debugAdTiming) {
|
|
3184
|
-
console.warn(
|
|
3185
|
-
"[StormcloudVideoPlayer] Error in background preloading:",
|
|
3186
|
-
error
|
|
3187
|
-
);
|
|
3188
|
-
}
|
|
3242
|
+
this.currentAdIndex++;
|
|
3243
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3244
|
+
this.tryNextAvailableAd();
|
|
3189
3245
|
});
|
|
3190
|
-
|
|
3246
|
+
return;
|
|
3191
3247
|
}
|
|
3192
3248
|
}
|
|
3193
|
-
if (this.
|
|
3194
|
-
this.
|
|
3195
|
-
|
|
3196
|
-
|
|
3249
|
+
if (!this.isShowingPlaceholder && remaining > 1e3) {
|
|
3250
|
+
this.showPlaceholderAndWaitForAds();
|
|
3251
|
+
} else {
|
|
3252
|
+
if (this.config.debugAdTiming) {
|
|
3253
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
|
|
3254
|
+
}
|
|
3255
|
+
this.handleAdPodComplete();
|
|
3197
3256
|
}
|
|
3198
3257
|
}
|
|
3199
|
-
async
|
|
3200
|
-
|
|
3258
|
+
async showPlaceholderAndWaitForAds() {
|
|
3259
|
+
const remaining = this.getRemainingAdMs();
|
|
3260
|
+
const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
|
|
3261
|
+
if (waitTime < 1e3) {
|
|
3262
|
+
this.handleAdPodComplete();
|
|
3201
3263
|
return;
|
|
3202
3264
|
}
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3265
|
+
if (this.config.debugAdTiming) {
|
|
3266
|
+
console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
|
|
3267
|
+
}
|
|
3268
|
+
this.isShowingPlaceholder = true;
|
|
3269
|
+
this.placeholderStartTimeMs = Date.now();
|
|
3270
|
+
this.ima.showPlaceholder();
|
|
3271
|
+
const checkInterval = 500;
|
|
3272
|
+
const maxChecks = Math.floor(waitTime / checkInterval);
|
|
3273
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
3274
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
3275
|
+
if (!this.inAdBreak) {
|
|
3276
|
+
return;
|
|
3277
|
+
}
|
|
3278
|
+
if (this.adRequestQueue.length > 0) {
|
|
3279
|
+
if (this.config.debugAdTiming) {
|
|
3280
|
+
console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
|
|
3281
|
+
}
|
|
3282
|
+
this.isShowingPlaceholder = false;
|
|
3283
|
+
this.placeholderStartTimeMs = null;
|
|
3284
|
+
this.ima.hidePlaceholder();
|
|
3285
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3286
|
+
if (nextAdUrl) {
|
|
3287
|
+
this.currentAdIndex++;
|
|
3288
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3289
|
+
this.tryNextAvailableAd();
|
|
3290
|
+
});
|
|
3214
3291
|
}
|
|
3292
|
+
return;
|
|
3215
3293
|
}
|
|
3216
|
-
return;
|
|
3217
3294
|
}
|
|
3218
|
-
this.
|
|
3219
|
-
|
|
3220
|
-
await this.playSingleAd(firstPreloaded);
|
|
3221
|
-
} catch (error) {
|
|
3295
|
+
if (this.config.debugAdTiming) {
|
|
3296
|
+
console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
|
|
3222
3297
|
}
|
|
3298
|
+
this.isShowingPlaceholder = false;
|
|
3299
|
+
this.placeholderStartTimeMs = null;
|
|
3300
|
+
this.ima.hidePlaceholder();
|
|
3301
|
+
this.handleAdPodComplete();
|
|
3223
3302
|
}
|
|
3224
3303
|
findCurrentOrNextBreak(nowMs) {
|
|
3225
3304
|
var _a;
|
|
@@ -3379,10 +3458,18 @@ var StormcloudVideoPlayer = class {
|
|
|
3379
3458
|
this.clearAdRequestWatchdog();
|
|
3380
3459
|
this.clearAdFailsafeTimer();
|
|
3381
3460
|
this.activeAdRequestToken = null;
|
|
3461
|
+
this.stopContinuousFetching();
|
|
3462
|
+
if (this.isShowingPlaceholder) {
|
|
3463
|
+
this.ima.hidePlaceholder();
|
|
3464
|
+
this.isShowingPlaceholder = false;
|
|
3465
|
+
this.placeholderStartTimeMs = null;
|
|
3466
|
+
}
|
|
3382
3467
|
this.preloadingAdUrls.clear();
|
|
3383
3468
|
this.vastToMediaUrlMap.clear();
|
|
3384
3469
|
this.preloadedMediaUrls.clear();
|
|
3385
3470
|
this.preloadingMediaUrls.clear();
|
|
3471
|
+
this.adRequestQueue = [];
|
|
3472
|
+
this.successfulAdRequests = [];
|
|
3386
3473
|
this.inAdBreak = false;
|
|
3387
3474
|
this.expectedAdBreakDurationMs = void 0;
|
|
3388
3475
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3409,61 +3496,14 @@ var StormcloudVideoPlayer = class {
|
|
|
3409
3496
|
}
|
|
3410
3497
|
}
|
|
3411
3498
|
handleAdFailure() {
|
|
3412
|
-
const remaining = this.getRemainingAdMs();
|
|
3413
|
-
const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
|
|
3414
|
-
if (remaining > 500 && availableAds > 0) {
|
|
3415
|
-
if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
|
|
3416
|
-
console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
|
|
3417
|
-
setTimeout(() => {
|
|
3418
|
-
this.tryNextAdWithRetry(0);
|
|
3419
|
-
}, 1500);
|
|
3420
|
-
return;
|
|
3421
|
-
}
|
|
3422
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3423
|
-
if (nextPreloaded) {
|
|
3424
|
-
this.currentAdIndex++;
|
|
3425
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3426
|
-
this.handleAdPodComplete();
|
|
3427
|
-
});
|
|
3428
|
-
return;
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
|
|
3432
|
-
this.handleAdPodComplete();
|
|
3433
|
-
}
|
|
3434
|
-
tryNextAdWithRetry(retryCount) {
|
|
3435
|
-
const maxRetries = 3;
|
|
3436
3499
|
const remaining = this.getRemainingAdMs();
|
|
3437
3500
|
if (this.config.debugAdTiming) {
|
|
3438
|
-
console.log(
|
|
3439
|
-
`[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
|
|
3440
|
-
);
|
|
3501
|
+
console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
3441
3502
|
}
|
|
3442
|
-
if (remaining
|
|
3443
|
-
|
|
3444
|
-
this.handleAdPodComplete();
|
|
3445
|
-
return;
|
|
3446
|
-
}
|
|
3447
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3448
|
-
if (nextPreloaded) {
|
|
3449
|
-
this.currentAdIndex++;
|
|
3450
|
-
console.log(
|
|
3451
|
-
`[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
3452
|
-
);
|
|
3453
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3454
|
-
this.handleAdPodComplete();
|
|
3455
|
-
});
|
|
3456
|
-
} else if (retryCount < maxRetries) {
|
|
3457
|
-
console.log(
|
|
3458
|
-
`[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
|
|
3459
|
-
);
|
|
3460
|
-
setTimeout(() => {
|
|
3461
|
-
this.tryNextAdWithRetry(retryCount + 1);
|
|
3462
|
-
}, 1e3);
|
|
3503
|
+
if (remaining > 500) {
|
|
3504
|
+
this.tryNextAvailableAd();
|
|
3463
3505
|
} else {
|
|
3464
|
-
console.
|
|
3465
|
-
`[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
|
|
3466
|
-
);
|
|
3506
|
+
console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
|
|
3467
3507
|
this.handleAdPodComplete();
|
|
3468
3508
|
}
|
|
3469
3509
|
}
|
|
@@ -3860,6 +3900,12 @@ var StormcloudVideoPlayer = class {
|
|
|
3860
3900
|
);
|
|
3861
3901
|
}
|
|
3862
3902
|
mediaUrls = await this.fetchAndParseVastXml(vastTagUrl);
|
|
3903
|
+
if (this.config.debugAdTiming) {
|
|
3904
|
+
console.log(
|
|
3905
|
+
`[StormcloudVideoPlayer] Extracted ${mediaUrls.length} media URLs:`,
|
|
3906
|
+
mediaUrls
|
|
3907
|
+
);
|
|
3908
|
+
}
|
|
3863
3909
|
if (mediaUrls.length > 0) {
|
|
3864
3910
|
this.vastToMediaUrlMap.set(vastTagUrl, mediaUrls);
|
|
3865
3911
|
}
|
|
@@ -4055,6 +4101,7 @@ var StormcloudVideoPlayer = class {
|
|
|
4055
4101
|
}
|
|
4056
4102
|
destroy() {
|
|
4057
4103
|
var _a, _b;
|
|
4104
|
+
this.stopContinuousFetching();
|
|
4058
4105
|
this.clearAdStartTimer();
|
|
4059
4106
|
this.clearAdStopTimer();
|
|
4060
4107
|
this.clearAdFailsafeTimer();
|
|
@@ -4069,6 +4116,8 @@ var StormcloudVideoPlayer = class {
|
|
|
4069
4116
|
this.preloadedMediaUrls.clear();
|
|
4070
4117
|
this.preloadingMediaUrls.clear();
|
|
4071
4118
|
this.adPodAllUrls = [];
|
|
4119
|
+
this.adRequestQueue = [];
|
|
4120
|
+
this.successfulAdRequests = [];
|
|
4072
4121
|
}
|
|
4073
4122
|
};
|
|
4074
4123
|
|