stormcloud-video-player 0.3.9 → 0.3.11
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 +244 -183
- 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 +244 -183
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +244 -183
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +11 -2
- package/lib/players/HlsPlayer.cjs +244 -183
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +244 -183
- package/lib/players/index.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +244 -183
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -2149,6 +2149,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2149
2149
|
this.targetAdBreakDurationMs = null;
|
|
2150
2150
|
this.isAdaptiveMode = false;
|
|
2151
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;
|
|
2152
2158
|
initializePolyfills();
|
|
2153
2159
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2154
2160
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2455,16 +2461,11 @@ var StormcloudVideoPlayer = class {
|
|
|
2455
2461
|
return;
|
|
2456
2462
|
}
|
|
2457
2463
|
const remaining = this.getRemainingAdMs();
|
|
2458
|
-
if (
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
this.handleAdPodComplete();
|
|
2464
|
-
});
|
|
2465
|
-
} else {
|
|
2466
|
-
this.handleAdPodComplete();
|
|
2467
|
-
}
|
|
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();
|
|
2468
2469
|
} else {
|
|
2469
2470
|
this.handleAdPodComplete();
|
|
2470
2471
|
}
|
|
@@ -3064,155 +3065,251 @@ var StormcloudVideoPlayer = class {
|
|
|
3064
3065
|
return true;
|
|
3065
3066
|
}
|
|
3066
3067
|
async handleAdStart(_marker) {
|
|
3067
|
-
var _a;
|
|
3068
3068
|
const scheduled = this.findCurrentOrNextBreak(
|
|
3069
3069
|
this.video.currentTime * 1e3
|
|
3070
3070
|
);
|
|
3071
3071
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
3072
|
-
let
|
|
3072
|
+
let baseVastUrl;
|
|
3073
3073
|
if (this.apiVastTagUrl) {
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
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");
|
|
3093
3168
|
}
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
if (this.
|
|
3099
|
-
|
|
3169
|
+
break;
|
|
3170
|
+
}
|
|
3171
|
+
const maxQueueSize = 3;
|
|
3172
|
+
if (this.adRequestQueue.length >= maxQueueSize) {
|
|
3173
|
+
if (this.config.debugAdTiming) {
|
|
3174
|
+
console.log(`[CONTINUOUS-FETCH] \u23F8\uFE0F Queue full (${this.adRequestQueue.length}), pausing fetching...`);
|
|
3175
|
+
}
|
|
3176
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3177
|
+
continue;
|
|
3178
|
+
}
|
|
3179
|
+
const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
|
|
3180
|
+
if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
|
|
3181
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3182
|
+
continue;
|
|
3183
|
+
}
|
|
3184
|
+
if (this.config.debugAdTiming) {
|
|
3185
|
+
console.log(`[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch ad (${this.successfulAdRequests.length + this.adRequestQueue.length + 1} total)...`);
|
|
3186
|
+
}
|
|
3187
|
+
try {
|
|
3188
|
+
const response = await fetch(newAdUrl, { mode: "cors" });
|
|
3189
|
+
if (!response.ok) {
|
|
3190
|
+
throw new Error(`Failed to fetch VAST: ${response.status}`);
|
|
3191
|
+
}
|
|
3192
|
+
const xmlText = await response.text();
|
|
3193
|
+
const parser = new DOMParser();
|
|
3194
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
3195
|
+
const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
|
|
3196
|
+
if (mediaFiles.length === 0) {
|
|
3100
3197
|
if (this.config.debugAdTiming) {
|
|
3101
|
-
console.log(
|
|
3102
|
-
`[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
|
|
3103
|
-
);
|
|
3198
|
+
console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
|
|
3104
3199
|
}
|
|
3200
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3201
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3202
|
+
continue;
|
|
3105
3203
|
}
|
|
3106
|
-
}
|
|
3107
|
-
if (numberOfAds > 1) {
|
|
3108
|
-
vastTagUrls = this.generateVastUrlsWithCorrelators(
|
|
3109
|
-
this.apiVastTagUrl,
|
|
3110
|
-
numberOfAds
|
|
3111
|
-
);
|
|
3112
3204
|
if (this.config.debugAdTiming) {
|
|
3113
|
-
console.log(
|
|
3114
|
-
`[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
|
|
3115
|
-
);
|
|
3205
|
+
console.log(`[CONTINUOUS-FETCH] \u2705 Successfully fetched ad, adding to queue (queue size: ${this.adRequestQueue.length + 1})`);
|
|
3116
3206
|
}
|
|
3117
|
-
|
|
3118
|
-
|
|
3207
|
+
this.adRequestQueue.push(newAdUrl);
|
|
3208
|
+
this.totalAdsInBreak++;
|
|
3209
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3210
|
+
} catch (error) {
|
|
3211
|
+
if (this.config.debugAdTiming) {
|
|
3212
|
+
console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
|
|
3213
|
+
}
|
|
3214
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3215
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3119
3216
|
}
|
|
3120
|
-
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3217
|
+
}
|
|
3218
|
+
if (this.config.debugAdTiming) {
|
|
3219
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
stopContinuousFetching() {
|
|
3223
|
+
this.continuousFetchingActive = false;
|
|
3224
|
+
if (this.config.debugAdTiming) {
|
|
3225
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
async tryNextAvailableAd(retryCount = 0) {
|
|
3229
|
+
const remaining = this.getRemainingAdMs();
|
|
3230
|
+
if (remaining <= 500) {
|
|
3231
|
+
if (this.config.debugAdTiming) {
|
|
3232
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
|
|
3233
|
+
}
|
|
3234
|
+
this.handleAdPodComplete();
|
|
3123
3235
|
return;
|
|
3124
3236
|
}
|
|
3125
|
-
if (
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
this.vastToMediaUrlMap.clear();
|
|
3129
|
-
this.preloadedMediaUrls.clear();
|
|
3130
|
-
this.preloadingMediaUrls.clear();
|
|
3131
|
-
this.failedVastUrls.clear();
|
|
3132
|
-
const currentMuted = this.video.muted;
|
|
3133
|
-
const currentVolume = this.video.volume;
|
|
3134
|
-
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3135
|
-
this.inAdBreak = true;
|
|
3136
|
-
this.currentAdIndex = 0;
|
|
3137
|
-
this.totalAdsInBreak = vastTagUrls.length;
|
|
3138
|
-
this.adPodQueue = [...vastTagUrls];
|
|
3139
|
-
if (this.isAdaptiveMode) {
|
|
3237
|
+
if (this.adRequestQueue.length > 0) {
|
|
3238
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3239
|
+
if (nextAdUrl) {
|
|
3140
3240
|
if (this.config.debugAdTiming) {
|
|
3141
|
-
console.log(
|
|
3241
|
+
console.log(`[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad (${this.currentAdIndex + 1}/${this.totalAdsInBreak}, ${this.adRequestQueue.length} remaining in queue)`);
|
|
3142
3242
|
}
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
if (url) {
|
|
3148
|
-
await this.preloadSingleAd(url);
|
|
3149
|
-
if (this.config.debugAdTiming) {
|
|
3150
|
-
console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
|
|
3151
|
-
}
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
if (this.config.debugAdTiming) {
|
|
3155
|
-
console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
|
|
3156
|
-
}
|
|
3157
|
-
} catch (error) {
|
|
3158
|
-
if (this.config.debugAdTiming) {
|
|
3159
|
-
console.warn(
|
|
3160
|
-
"[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
|
|
3161
|
-
error
|
|
3162
|
-
);
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3166
|
-
if (this.config.debugAdTiming) {
|
|
3167
|
-
console.warn(
|
|
3168
|
-
"[ADAPTIVE-POD] Error in background preloading:",
|
|
3169
|
-
error
|
|
3170
|
-
);
|
|
3171
|
-
}
|
|
3172
|
-
});
|
|
3173
|
-
await this.playAdPod();
|
|
3174
|
-
} else {
|
|
3175
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3176
|
-
if (this.config.debugAdTiming) {
|
|
3177
|
-
console.warn(
|
|
3178
|
-
"[StormcloudVideoPlayer] Error in background preloading:",
|
|
3179
|
-
error
|
|
3180
|
-
);
|
|
3181
|
-
}
|
|
3243
|
+
this.currentAdIndex++;
|
|
3244
|
+
this.successfulAdRequests.push(nextAdUrl);
|
|
3245
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3246
|
+
this.tryNextAvailableAd(0);
|
|
3182
3247
|
});
|
|
3183
|
-
|
|
3248
|
+
return;
|
|
3184
3249
|
}
|
|
3185
3250
|
}
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3251
|
+
const maxRetries = 5;
|
|
3252
|
+
if (this.continuousFetchingActive && retryCount < maxRetries && remaining > 2e3) {
|
|
3253
|
+
if (this.config.debugAdTiming) {
|
|
3254
|
+
console.log(`[CONTINUOUS-FETCH] \u23F3 Queue empty but fetching active, waiting... (retry ${retryCount + 1}/${maxRetries})`);
|
|
3255
|
+
}
|
|
3256
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3257
|
+
await this.tryNextAvailableAd(retryCount + 1);
|
|
3258
|
+
return;
|
|
3259
|
+
}
|
|
3260
|
+
if (!this.isShowingPlaceholder && remaining > 1e3) {
|
|
3261
|
+
this.showPlaceholderAndWaitForAds();
|
|
3262
|
+
} else {
|
|
3263
|
+
if (this.config.debugAdTiming) {
|
|
3264
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
|
|
3265
|
+
}
|
|
3266
|
+
this.handleAdPodComplete();
|
|
3190
3267
|
}
|
|
3191
3268
|
}
|
|
3192
|
-
async
|
|
3193
|
-
|
|
3269
|
+
async showPlaceholderAndWaitForAds() {
|
|
3270
|
+
const remaining = this.getRemainingAdMs();
|
|
3271
|
+
const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
|
|
3272
|
+
if (waitTime < 1e3) {
|
|
3273
|
+
this.handleAdPodComplete();
|
|
3194
3274
|
return;
|
|
3195
3275
|
}
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3276
|
+
if (this.config.debugAdTiming) {
|
|
3277
|
+
console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
|
|
3278
|
+
}
|
|
3279
|
+
this.isShowingPlaceholder = true;
|
|
3280
|
+
this.placeholderStartTimeMs = Date.now();
|
|
3281
|
+
this.ima.showPlaceholder();
|
|
3282
|
+
const checkInterval = 500;
|
|
3283
|
+
const maxChecks = Math.floor(waitTime / checkInterval);
|
|
3284
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
3285
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
3286
|
+
if (!this.inAdBreak) {
|
|
3287
|
+
return;
|
|
3288
|
+
}
|
|
3289
|
+
if (this.adRequestQueue.length > 0) {
|
|
3290
|
+
if (this.config.debugAdTiming) {
|
|
3291
|
+
console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
|
|
3292
|
+
}
|
|
3293
|
+
this.isShowingPlaceholder = false;
|
|
3294
|
+
this.placeholderStartTimeMs = null;
|
|
3295
|
+
this.ima.hidePlaceholder();
|
|
3296
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3297
|
+
if (nextAdUrl) {
|
|
3298
|
+
this.currentAdIndex++;
|
|
3299
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3300
|
+
this.tryNextAvailableAd();
|
|
3301
|
+
});
|
|
3207
3302
|
}
|
|
3303
|
+
return;
|
|
3208
3304
|
}
|
|
3209
|
-
return;
|
|
3210
3305
|
}
|
|
3211
|
-
this.
|
|
3212
|
-
|
|
3213
|
-
await this.playSingleAd(firstPreloaded);
|
|
3214
|
-
} catch (error) {
|
|
3306
|
+
if (this.config.debugAdTiming) {
|
|
3307
|
+
console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
|
|
3215
3308
|
}
|
|
3309
|
+
this.isShowingPlaceholder = false;
|
|
3310
|
+
this.placeholderStartTimeMs = null;
|
|
3311
|
+
this.ima.hidePlaceholder();
|
|
3312
|
+
this.handleAdPodComplete();
|
|
3216
3313
|
}
|
|
3217
3314
|
findCurrentOrNextBreak(nowMs) {
|
|
3218
3315
|
var _a;
|
|
@@ -3372,10 +3469,18 @@ var StormcloudVideoPlayer = class {
|
|
|
3372
3469
|
this.clearAdRequestWatchdog();
|
|
3373
3470
|
this.clearAdFailsafeTimer();
|
|
3374
3471
|
this.activeAdRequestToken = null;
|
|
3472
|
+
this.stopContinuousFetching();
|
|
3473
|
+
if (this.isShowingPlaceholder) {
|
|
3474
|
+
this.ima.hidePlaceholder();
|
|
3475
|
+
this.isShowingPlaceholder = false;
|
|
3476
|
+
this.placeholderStartTimeMs = null;
|
|
3477
|
+
}
|
|
3375
3478
|
this.preloadingAdUrls.clear();
|
|
3376
3479
|
this.vastToMediaUrlMap.clear();
|
|
3377
3480
|
this.preloadedMediaUrls.clear();
|
|
3378
3481
|
this.preloadingMediaUrls.clear();
|
|
3482
|
+
this.adRequestQueue = [];
|
|
3483
|
+
this.successfulAdRequests = [];
|
|
3379
3484
|
this.inAdBreak = false;
|
|
3380
3485
|
this.expectedAdBreakDurationMs = void 0;
|
|
3381
3486
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3402,61 +3507,14 @@ var StormcloudVideoPlayer = class {
|
|
|
3402
3507
|
}
|
|
3403
3508
|
}
|
|
3404
3509
|
handleAdFailure() {
|
|
3405
|
-
const remaining = this.getRemainingAdMs();
|
|
3406
|
-
const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
|
|
3407
|
-
if (remaining > 500 && availableAds > 0) {
|
|
3408
|
-
if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
|
|
3409
|
-
console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
|
|
3410
|
-
setTimeout(() => {
|
|
3411
|
-
this.tryNextAdWithRetry(0);
|
|
3412
|
-
}, 1500);
|
|
3413
|
-
return;
|
|
3414
|
-
}
|
|
3415
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3416
|
-
if (nextPreloaded) {
|
|
3417
|
-
this.currentAdIndex++;
|
|
3418
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3419
|
-
this.handleAdPodComplete();
|
|
3420
|
-
});
|
|
3421
|
-
return;
|
|
3422
|
-
}
|
|
3423
|
-
}
|
|
3424
|
-
console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
|
|
3425
|
-
this.handleAdPodComplete();
|
|
3426
|
-
}
|
|
3427
|
-
tryNextAdWithRetry(retryCount) {
|
|
3428
|
-
const maxRetries = 3;
|
|
3429
3510
|
const remaining = this.getRemainingAdMs();
|
|
3430
3511
|
if (this.config.debugAdTiming) {
|
|
3431
|
-
console.log(
|
|
3432
|
-
`[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
|
|
3433
|
-
);
|
|
3434
|
-
}
|
|
3435
|
-
if (remaining <= 500 || this.adPodQueue.length === 0) {
|
|
3436
|
-
console.log("[ADAPTIVE-POD] \u23F9\uFE0F No more time or ads available");
|
|
3437
|
-
this.handleAdPodComplete();
|
|
3438
|
-
return;
|
|
3512
|
+
console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
3439
3513
|
}
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
this.currentAdIndex++;
|
|
3443
|
-
console.log(
|
|
3444
|
-
`[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
3445
|
-
);
|
|
3446
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3447
|
-
this.handleAdPodComplete();
|
|
3448
|
-
});
|
|
3449
|
-
} else if (retryCount < maxRetries) {
|
|
3450
|
-
console.log(
|
|
3451
|
-
`[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
|
|
3452
|
-
);
|
|
3453
|
-
setTimeout(() => {
|
|
3454
|
-
this.tryNextAdWithRetry(retryCount + 1);
|
|
3455
|
-
}, 1e3);
|
|
3514
|
+
if (remaining > 500) {
|
|
3515
|
+
this.tryNextAvailableAd();
|
|
3456
3516
|
} else {
|
|
3457
|
-
console.
|
|
3458
|
-
`[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
|
|
3459
|
-
);
|
|
3517
|
+
console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
|
|
3460
3518
|
this.handleAdPodComplete();
|
|
3461
3519
|
}
|
|
3462
3520
|
}
|
|
@@ -4054,6 +4112,7 @@ var StormcloudVideoPlayer = class {
|
|
|
4054
4112
|
}
|
|
4055
4113
|
destroy() {
|
|
4056
4114
|
var _a, _b;
|
|
4115
|
+
this.stopContinuousFetching();
|
|
4057
4116
|
this.clearAdStartTimer();
|
|
4058
4117
|
this.clearAdStopTimer();
|
|
4059
4118
|
this.clearAdFailsafeTimer();
|
|
@@ -4068,6 +4127,8 @@ var StormcloudVideoPlayer = class {
|
|
|
4068
4127
|
this.preloadedMediaUrls.clear();
|
|
4069
4128
|
this.preloadingMediaUrls.clear();
|
|
4070
4129
|
this.adPodAllUrls = [];
|
|
4130
|
+
this.adRequestQueue = [];
|
|
4131
|
+
this.successfulAdRequests = [];
|
|
4071
4132
|
}
|
|
4072
4133
|
};
|
|
4073
4134
|
|