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
|
@@ -2082,6 +2082,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2082
2082
|
this.targetAdBreakDurationMs = null;
|
|
2083
2083
|
this.isAdaptiveMode = false;
|
|
2084
2084
|
this.failedVastUrls = /* @__PURE__ */ new Set();
|
|
2085
|
+
this.continuousFetchingActive = false;
|
|
2086
|
+
this.adRequestQueue = [];
|
|
2087
|
+
this.successfulAdRequests = [];
|
|
2088
|
+
this.maxPlaceholderDurationMs = 5e3;
|
|
2089
|
+
this.placeholderStartTimeMs = null;
|
|
2090
|
+
this.isShowingPlaceholder = false;
|
|
2085
2091
|
initializePolyfills();
|
|
2086
2092
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2087
2093
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2388,16 +2394,11 @@ var StormcloudVideoPlayer = class {
|
|
|
2388
2394
|
return;
|
|
2389
2395
|
}
|
|
2390
2396
|
const remaining = this.getRemainingAdMs();
|
|
2391
|
-
if (
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
this.handleAdPodComplete();
|
|
2397
|
-
});
|
|
2398
|
-
} else {
|
|
2399
|
-
this.handleAdPodComplete();
|
|
2400
|
-
}
|
|
2397
|
+
if (this.config.debugAdTiming) {
|
|
2398
|
+
console.log(`[CONTINUOUS-FETCH] content_resume event: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
2399
|
+
}
|
|
2400
|
+
if (remaining > 500) {
|
|
2401
|
+
this.tryNextAvailableAd();
|
|
2401
2402
|
} else {
|
|
2402
2403
|
this.handleAdPodComplete();
|
|
2403
2404
|
}
|
|
@@ -2997,155 +2998,251 @@ var StormcloudVideoPlayer = class {
|
|
|
2997
2998
|
return true;
|
|
2998
2999
|
}
|
|
2999
3000
|
async handleAdStart(_marker) {
|
|
3000
|
-
var _a;
|
|
3001
3001
|
const scheduled = this.findCurrentOrNextBreak(
|
|
3002
3002
|
this.video.currentTime * 1e3
|
|
3003
3003
|
);
|
|
3004
3004
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
3005
|
-
let
|
|
3005
|
+
let baseVastUrl;
|
|
3006
3006
|
if (this.apiVastTagUrl) {
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3007
|
+
baseVastUrl = this.apiVastTagUrl;
|
|
3008
|
+
} else if (tags && tags.length > 0 && tags[0]) {
|
|
3009
|
+
baseVastUrl = tags[0];
|
|
3010
|
+
} else {
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
|
|
3014
|
+
if (this.isLiveStream && adBreakDurationMs != null && adBreakDurationMs > 0) {
|
|
3015
|
+
this.isAdaptiveMode = true;
|
|
3016
|
+
this.targetAdBreakDurationMs = adBreakDurationMs;
|
|
3017
|
+
this.fetchedAdDurations.clear();
|
|
3018
|
+
if (this.config.debugAdTiming) {
|
|
3019
|
+
console.log(
|
|
3020
|
+
`[CONTINUOUS-FETCH] \u{1F4FA} LIVE MODE: Target duration=${adBreakDurationMs}ms | Will continuously fetch ads during break`
|
|
3021
|
+
);
|
|
3022
|
+
}
|
|
3023
|
+
} else {
|
|
3024
|
+
this.isAdaptiveMode = false;
|
|
3025
|
+
this.targetAdBreakDurationMs = null;
|
|
3026
|
+
this.fetchedAdDurations.clear();
|
|
3027
|
+
if (this.config.debugAdTiming) {
|
|
3028
|
+
console.log(
|
|
3029
|
+
`[CONTINUOUS-FETCH] \u{1F3AC} VOD MODE: Using fixed ad strategy`
|
|
3030
|
+
);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
this.adPodAllUrls = [];
|
|
3034
|
+
this.preloadingAdUrls.clear();
|
|
3035
|
+
this.vastToMediaUrlMap.clear();
|
|
3036
|
+
this.preloadedMediaUrls.clear();
|
|
3037
|
+
this.preloadingMediaUrls.clear();
|
|
3038
|
+
this.failedVastUrls.clear();
|
|
3039
|
+
this.adRequestQueue = [];
|
|
3040
|
+
this.successfulAdRequests = [];
|
|
3041
|
+
this.continuousFetchingActive = true;
|
|
3042
|
+
this.isShowingPlaceholder = false;
|
|
3043
|
+
this.placeholderStartTimeMs = null;
|
|
3044
|
+
const currentMuted = this.video.muted;
|
|
3045
|
+
const currentVolume = this.video.volume;
|
|
3046
|
+
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3047
|
+
this.inAdBreak = true;
|
|
3048
|
+
this.currentAdIndex = 0;
|
|
3049
|
+
this.totalAdsInBreak = 1;
|
|
3050
|
+
this.adPodQueue = [];
|
|
3051
|
+
if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
|
|
3052
|
+
this.expectedAdBreakDurationMs = adBreakDurationMs;
|
|
3053
|
+
this.currentAdBreakStartWallClockMs = Date.now();
|
|
3054
|
+
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
3055
|
+
}
|
|
3056
|
+
if (this.config.debugAdTiming) {
|
|
3057
|
+
console.log("[CONTINUOUS-FETCH] \u{1F680} Immediately requesting first ad...");
|
|
3058
|
+
}
|
|
3059
|
+
const firstAdUrlArray = this.generateVastUrlsWithCorrelators(baseVastUrl, 1);
|
|
3060
|
+
const firstAdUrl = firstAdUrlArray[0];
|
|
3061
|
+
if (!firstAdUrl) {
|
|
3062
|
+
if (this.config.debugAdTiming) {
|
|
3063
|
+
console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F Failed to generate first ad URL");
|
|
3064
|
+
}
|
|
3065
|
+
this.handleAdPodComplete();
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
3068
|
+
try {
|
|
3069
|
+
await this.ima.requestAds(firstAdUrl);
|
|
3070
|
+
if (this.config.debugAdTiming) {
|
|
3071
|
+
console.log("[CONTINUOUS-FETCH] \u2705 First ad request successful, starting playback");
|
|
3072
|
+
}
|
|
3073
|
+
this.successfulAdRequests.push(firstAdUrl);
|
|
3074
|
+
this.currentAdIndex++;
|
|
3075
|
+
this.startContinuousFetching(baseVastUrl);
|
|
3076
|
+
await this.ima.play();
|
|
3077
|
+
} catch (error) {
|
|
3078
|
+
if (this.config.debugAdTiming) {
|
|
3079
|
+
console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
|
|
3080
|
+
}
|
|
3081
|
+
this.failedVastUrls.add(firstAdUrl);
|
|
3082
|
+
this.startContinuousFetching(baseVastUrl);
|
|
3083
|
+
this.tryNextAvailableAd();
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
startContinuousFetching(baseVastUrl) {
|
|
3087
|
+
if (!this.continuousFetchingActive) {
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
3090
|
+
if (this.config.debugAdTiming) {
|
|
3091
|
+
console.log("[CONTINUOUS-FETCH] \u{1F504} Starting continuous ad fetching loop");
|
|
3092
|
+
}
|
|
3093
|
+
this.continuousFetchLoop(baseVastUrl);
|
|
3094
|
+
}
|
|
3095
|
+
async continuousFetchLoop(baseVastUrl) {
|
|
3096
|
+
while (this.continuousFetchingActive && this.inAdBreak) {
|
|
3097
|
+
const remaining = this.getRemainingAdMs();
|
|
3098
|
+
if (remaining <= 0) {
|
|
3099
|
+
if (this.config.debugAdTiming) {
|
|
3100
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F Ad break time expired, stopping fetch loop");
|
|
3026
3101
|
}
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
if (this.
|
|
3032
|
-
|
|
3102
|
+
break;
|
|
3103
|
+
}
|
|
3104
|
+
const maxQueueSize = 3;
|
|
3105
|
+
if (this.adRequestQueue.length >= maxQueueSize) {
|
|
3106
|
+
if (this.config.debugAdTiming) {
|
|
3107
|
+
console.log(`[CONTINUOUS-FETCH] \u23F8\uFE0F Queue full (${this.adRequestQueue.length}), pausing fetching...`);
|
|
3108
|
+
}
|
|
3109
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3110
|
+
continue;
|
|
3111
|
+
}
|
|
3112
|
+
const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
|
|
3113
|
+
if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
|
|
3114
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3115
|
+
continue;
|
|
3116
|
+
}
|
|
3117
|
+
if (this.config.debugAdTiming) {
|
|
3118
|
+
console.log(`[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch ad (${this.successfulAdRequests.length + this.adRequestQueue.length + 1} total)...`);
|
|
3119
|
+
}
|
|
3120
|
+
try {
|
|
3121
|
+
const response = await fetch(newAdUrl, { mode: "cors" });
|
|
3122
|
+
if (!response.ok) {
|
|
3123
|
+
throw new Error(`Failed to fetch VAST: ${response.status}`);
|
|
3124
|
+
}
|
|
3125
|
+
const xmlText = await response.text();
|
|
3126
|
+
const parser = new DOMParser();
|
|
3127
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
3128
|
+
const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
|
|
3129
|
+
if (mediaFiles.length === 0) {
|
|
3033
3130
|
if (this.config.debugAdTiming) {
|
|
3034
|
-
console.log(
|
|
3035
|
-
`[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
|
|
3036
|
-
);
|
|
3131
|
+
console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
|
|
3037
3132
|
}
|
|
3133
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3134
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3135
|
+
continue;
|
|
3038
3136
|
}
|
|
3039
|
-
}
|
|
3040
|
-
if (numberOfAds > 1) {
|
|
3041
|
-
vastTagUrls = this.generateVastUrlsWithCorrelators(
|
|
3042
|
-
this.apiVastTagUrl,
|
|
3043
|
-
numberOfAds
|
|
3044
|
-
);
|
|
3045
3137
|
if (this.config.debugAdTiming) {
|
|
3046
|
-
console.log(
|
|
3047
|
-
`[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
|
|
3048
|
-
);
|
|
3138
|
+
console.log(`[CONTINUOUS-FETCH] \u2705 Successfully fetched ad, adding to queue (queue size: ${this.adRequestQueue.length + 1})`);
|
|
3049
3139
|
}
|
|
3050
|
-
|
|
3051
|
-
|
|
3140
|
+
this.adRequestQueue.push(newAdUrl);
|
|
3141
|
+
this.totalAdsInBreak++;
|
|
3142
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3143
|
+
} catch (error) {
|
|
3144
|
+
if (this.config.debugAdTiming) {
|
|
3145
|
+
console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
|
|
3146
|
+
}
|
|
3147
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3148
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3052
3149
|
}
|
|
3053
|
-
}
|
|
3054
|
-
|
|
3055
|
-
|
|
3150
|
+
}
|
|
3151
|
+
if (this.config.debugAdTiming) {
|
|
3152
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
stopContinuousFetching() {
|
|
3156
|
+
this.continuousFetchingActive = false;
|
|
3157
|
+
if (this.config.debugAdTiming) {
|
|
3158
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
async tryNextAvailableAd(retryCount = 0) {
|
|
3162
|
+
const remaining = this.getRemainingAdMs();
|
|
3163
|
+
if (remaining <= 500) {
|
|
3164
|
+
if (this.config.debugAdTiming) {
|
|
3165
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
|
|
3166
|
+
}
|
|
3167
|
+
this.handleAdPodComplete();
|
|
3056
3168
|
return;
|
|
3057
3169
|
}
|
|
3058
|
-
if (
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
this.vastToMediaUrlMap.clear();
|
|
3062
|
-
this.preloadedMediaUrls.clear();
|
|
3063
|
-
this.preloadingMediaUrls.clear();
|
|
3064
|
-
this.failedVastUrls.clear();
|
|
3065
|
-
const currentMuted = this.video.muted;
|
|
3066
|
-
const currentVolume = this.video.volume;
|
|
3067
|
-
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3068
|
-
this.inAdBreak = true;
|
|
3069
|
-
this.currentAdIndex = 0;
|
|
3070
|
-
this.totalAdsInBreak = vastTagUrls.length;
|
|
3071
|
-
this.adPodQueue = [...vastTagUrls];
|
|
3072
|
-
if (this.isAdaptiveMode) {
|
|
3170
|
+
if (this.adRequestQueue.length > 0) {
|
|
3171
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3172
|
+
if (nextAdUrl) {
|
|
3073
3173
|
if (this.config.debugAdTiming) {
|
|
3074
|
-
console.log(
|
|
3174
|
+
console.log(`[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad (${this.currentAdIndex + 1}/${this.totalAdsInBreak}, ${this.adRequestQueue.length} remaining in queue)`);
|
|
3075
3175
|
}
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
if (url) {
|
|
3081
|
-
await this.preloadSingleAd(url);
|
|
3082
|
-
if (this.config.debugAdTiming) {
|
|
3083
|
-
console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
|
|
3084
|
-
}
|
|
3085
|
-
}
|
|
3086
|
-
}
|
|
3087
|
-
if (this.config.debugAdTiming) {
|
|
3088
|
-
console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
|
|
3089
|
-
}
|
|
3090
|
-
} catch (error) {
|
|
3091
|
-
if (this.config.debugAdTiming) {
|
|
3092
|
-
console.warn(
|
|
3093
|
-
"[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
|
|
3094
|
-
error
|
|
3095
|
-
);
|
|
3096
|
-
}
|
|
3097
|
-
}
|
|
3098
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3099
|
-
if (this.config.debugAdTiming) {
|
|
3100
|
-
console.warn(
|
|
3101
|
-
"[ADAPTIVE-POD] Error in background preloading:",
|
|
3102
|
-
error
|
|
3103
|
-
);
|
|
3104
|
-
}
|
|
3105
|
-
});
|
|
3106
|
-
await this.playAdPod();
|
|
3107
|
-
} else {
|
|
3108
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3109
|
-
if (this.config.debugAdTiming) {
|
|
3110
|
-
console.warn(
|
|
3111
|
-
"[StormcloudVideoPlayer] Error in background preloading:",
|
|
3112
|
-
error
|
|
3113
|
-
);
|
|
3114
|
-
}
|
|
3176
|
+
this.currentAdIndex++;
|
|
3177
|
+
this.successfulAdRequests.push(nextAdUrl);
|
|
3178
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3179
|
+
this.tryNextAvailableAd(0);
|
|
3115
3180
|
});
|
|
3116
|
-
|
|
3181
|
+
return;
|
|
3117
3182
|
}
|
|
3118
3183
|
}
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3184
|
+
const maxRetries = 5;
|
|
3185
|
+
if (this.continuousFetchingActive && retryCount < maxRetries && remaining > 2e3) {
|
|
3186
|
+
if (this.config.debugAdTiming) {
|
|
3187
|
+
console.log(`[CONTINUOUS-FETCH] \u23F3 Queue empty but fetching active, waiting... (retry ${retryCount + 1}/${maxRetries})`);
|
|
3188
|
+
}
|
|
3189
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3190
|
+
await this.tryNextAvailableAd(retryCount + 1);
|
|
3191
|
+
return;
|
|
3192
|
+
}
|
|
3193
|
+
if (!this.isShowingPlaceholder && remaining > 1e3) {
|
|
3194
|
+
this.showPlaceholderAndWaitForAds();
|
|
3195
|
+
} else {
|
|
3196
|
+
if (this.config.debugAdTiming) {
|
|
3197
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
|
|
3198
|
+
}
|
|
3199
|
+
this.handleAdPodComplete();
|
|
3123
3200
|
}
|
|
3124
3201
|
}
|
|
3125
|
-
async
|
|
3126
|
-
|
|
3202
|
+
async showPlaceholderAndWaitForAds() {
|
|
3203
|
+
const remaining = this.getRemainingAdMs();
|
|
3204
|
+
const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
|
|
3205
|
+
if (waitTime < 1e3) {
|
|
3206
|
+
this.handleAdPodComplete();
|
|
3127
3207
|
return;
|
|
3128
3208
|
}
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3209
|
+
if (this.config.debugAdTiming) {
|
|
3210
|
+
console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
|
|
3211
|
+
}
|
|
3212
|
+
this.isShowingPlaceholder = true;
|
|
3213
|
+
this.placeholderStartTimeMs = Date.now();
|
|
3214
|
+
this.ima.showPlaceholder();
|
|
3215
|
+
const checkInterval = 500;
|
|
3216
|
+
const maxChecks = Math.floor(waitTime / checkInterval);
|
|
3217
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
3218
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
3219
|
+
if (!this.inAdBreak) {
|
|
3220
|
+
return;
|
|
3221
|
+
}
|
|
3222
|
+
if (this.adRequestQueue.length > 0) {
|
|
3223
|
+
if (this.config.debugAdTiming) {
|
|
3224
|
+
console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
|
|
3225
|
+
}
|
|
3226
|
+
this.isShowingPlaceholder = false;
|
|
3227
|
+
this.placeholderStartTimeMs = null;
|
|
3228
|
+
this.ima.hidePlaceholder();
|
|
3229
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3230
|
+
if (nextAdUrl) {
|
|
3231
|
+
this.currentAdIndex++;
|
|
3232
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3233
|
+
this.tryNextAvailableAd();
|
|
3234
|
+
});
|
|
3140
3235
|
}
|
|
3236
|
+
return;
|
|
3141
3237
|
}
|
|
3142
|
-
return;
|
|
3143
3238
|
}
|
|
3144
|
-
this.
|
|
3145
|
-
|
|
3146
|
-
await this.playSingleAd(firstPreloaded);
|
|
3147
|
-
} catch (error) {
|
|
3239
|
+
if (this.config.debugAdTiming) {
|
|
3240
|
+
console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
|
|
3148
3241
|
}
|
|
3242
|
+
this.isShowingPlaceholder = false;
|
|
3243
|
+
this.placeholderStartTimeMs = null;
|
|
3244
|
+
this.ima.hidePlaceholder();
|
|
3245
|
+
this.handleAdPodComplete();
|
|
3149
3246
|
}
|
|
3150
3247
|
findCurrentOrNextBreak(nowMs) {
|
|
3151
3248
|
var _a;
|
|
@@ -3305,10 +3402,18 @@ var StormcloudVideoPlayer = class {
|
|
|
3305
3402
|
this.clearAdRequestWatchdog();
|
|
3306
3403
|
this.clearAdFailsafeTimer();
|
|
3307
3404
|
this.activeAdRequestToken = null;
|
|
3405
|
+
this.stopContinuousFetching();
|
|
3406
|
+
if (this.isShowingPlaceholder) {
|
|
3407
|
+
this.ima.hidePlaceholder();
|
|
3408
|
+
this.isShowingPlaceholder = false;
|
|
3409
|
+
this.placeholderStartTimeMs = null;
|
|
3410
|
+
}
|
|
3308
3411
|
this.preloadingAdUrls.clear();
|
|
3309
3412
|
this.vastToMediaUrlMap.clear();
|
|
3310
3413
|
this.preloadedMediaUrls.clear();
|
|
3311
3414
|
this.preloadingMediaUrls.clear();
|
|
3415
|
+
this.adRequestQueue = [];
|
|
3416
|
+
this.successfulAdRequests = [];
|
|
3312
3417
|
this.inAdBreak = false;
|
|
3313
3418
|
this.expectedAdBreakDurationMs = void 0;
|
|
3314
3419
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3335,61 +3440,14 @@ var StormcloudVideoPlayer = class {
|
|
|
3335
3440
|
}
|
|
3336
3441
|
}
|
|
3337
3442
|
handleAdFailure() {
|
|
3338
|
-
const remaining = this.getRemainingAdMs();
|
|
3339
|
-
const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
|
|
3340
|
-
if (remaining > 500 && availableAds > 0) {
|
|
3341
|
-
if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
|
|
3342
|
-
console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
|
|
3343
|
-
setTimeout(() => {
|
|
3344
|
-
this.tryNextAdWithRetry(0);
|
|
3345
|
-
}, 1500);
|
|
3346
|
-
return;
|
|
3347
|
-
}
|
|
3348
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3349
|
-
if (nextPreloaded) {
|
|
3350
|
-
this.currentAdIndex++;
|
|
3351
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3352
|
-
this.handleAdPodComplete();
|
|
3353
|
-
});
|
|
3354
|
-
return;
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
3357
|
-
console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
|
|
3358
|
-
this.handleAdPodComplete();
|
|
3359
|
-
}
|
|
3360
|
-
tryNextAdWithRetry(retryCount) {
|
|
3361
|
-
const maxRetries = 3;
|
|
3362
3443
|
const remaining = this.getRemainingAdMs();
|
|
3363
3444
|
if (this.config.debugAdTiming) {
|
|
3364
|
-
console.log(
|
|
3365
|
-
`[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
|
|
3366
|
-
);
|
|
3367
|
-
}
|
|
3368
|
-
if (remaining <= 500 || this.adPodQueue.length === 0) {
|
|
3369
|
-
console.log("[ADAPTIVE-POD] \u23F9\uFE0F No more time or ads available");
|
|
3370
|
-
this.handleAdPodComplete();
|
|
3371
|
-
return;
|
|
3445
|
+
console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
3372
3446
|
}
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
this.currentAdIndex++;
|
|
3376
|
-
console.log(
|
|
3377
|
-
`[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
3378
|
-
);
|
|
3379
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3380
|
-
this.handleAdPodComplete();
|
|
3381
|
-
});
|
|
3382
|
-
} else if (retryCount < maxRetries) {
|
|
3383
|
-
console.log(
|
|
3384
|
-
`[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
|
|
3385
|
-
);
|
|
3386
|
-
setTimeout(() => {
|
|
3387
|
-
this.tryNextAdWithRetry(retryCount + 1);
|
|
3388
|
-
}, 1e3);
|
|
3447
|
+
if (remaining > 500) {
|
|
3448
|
+
this.tryNextAvailableAd();
|
|
3389
3449
|
} else {
|
|
3390
|
-
console.
|
|
3391
|
-
`[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
|
|
3392
|
-
);
|
|
3450
|
+
console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
|
|
3393
3451
|
this.handleAdPodComplete();
|
|
3394
3452
|
}
|
|
3395
3453
|
}
|
|
@@ -3987,6 +4045,7 @@ var StormcloudVideoPlayer = class {
|
|
|
3987
4045
|
}
|
|
3988
4046
|
destroy() {
|
|
3989
4047
|
var _a, _b;
|
|
4048
|
+
this.stopContinuousFetching();
|
|
3990
4049
|
this.clearAdStartTimer();
|
|
3991
4050
|
this.clearAdStopTimer();
|
|
3992
4051
|
this.clearAdFailsafeTimer();
|
|
@@ -4001,6 +4060,8 @@ var StormcloudVideoPlayer = class {
|
|
|
4001
4060
|
this.preloadedMediaUrls.clear();
|
|
4002
4061
|
this.preloadingMediaUrls.clear();
|
|
4003
4062
|
this.adPodAllUrls = [];
|
|
4063
|
+
this.adRequestQueue = [];
|
|
4064
|
+
this.successfulAdRequests = [];
|
|
4004
4065
|
}
|
|
4005
4066
|
};
|
|
4006
4067
|
// Annotate the CommonJS export names for ESM import in node:
|