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
|
@@ -341,12 +341,8 @@ function createImaController(video, options) {
|
|
|
341
341
|
let adsLoadedReject;
|
|
342
342
|
function makeAdsRequest(google, vastTagUrl) {
|
|
343
343
|
const adsRequest = new google.ima.AdsRequest();
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
adsRequest.adsResponse = preloadedResponse;
|
|
347
|
-
} else {
|
|
348
|
-
adsRequest.adTagUrl = vastTagUrl;
|
|
349
|
-
}
|
|
344
|
+
console.log("[IMA] \u{1F4E1} Requesting VAST from URL (letting IMA fetch fresh)");
|
|
345
|
+
adsRequest.adTagUrl = vastTagUrl;
|
|
350
346
|
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
351
347
|
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
352
348
|
adsRequest.linearAdSlotWidth = videoWidth;
|
|
@@ -369,11 +365,8 @@ function createImaController(video, options) {
|
|
|
369
365
|
console.warn("[IMA] Failed to call setAdWillPlayMuted:", error);
|
|
370
366
|
}
|
|
371
367
|
}
|
|
372
|
-
adsRequest.vastLoadTimeout =
|
|
368
|
+
adsRequest.vastLoadTimeout = 1e4;
|
|
373
369
|
adsLoader.requestAds(adsRequest);
|
|
374
|
-
if (preloadedResponse) {
|
|
375
|
-
preloadedVast.delete(vastTagUrl);
|
|
376
|
-
}
|
|
377
370
|
}
|
|
378
371
|
function ensurePlaceholderContainer() {
|
|
379
372
|
var _a;
|
|
@@ -2089,6 +2082,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2089
2082
|
this.targetAdBreakDurationMs = null;
|
|
2090
2083
|
this.isAdaptiveMode = false;
|
|
2091
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;
|
|
2092
2091
|
initializePolyfills();
|
|
2093
2092
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2094
2093
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2395,16 +2394,11 @@ var StormcloudVideoPlayer = class {
|
|
|
2395
2394
|
return;
|
|
2396
2395
|
}
|
|
2397
2396
|
const remaining = this.getRemainingAdMs();
|
|
2398
|
-
if (
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
this.handleAdPodComplete();
|
|
2404
|
-
});
|
|
2405
|
-
} else {
|
|
2406
|
-
this.handleAdPodComplete();
|
|
2407
|
-
}
|
|
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();
|
|
2408
2402
|
} else {
|
|
2409
2403
|
this.handleAdPodComplete();
|
|
2410
2404
|
}
|
|
@@ -3004,155 +2998,240 @@ var StormcloudVideoPlayer = class {
|
|
|
3004
2998
|
return true;
|
|
3005
2999
|
}
|
|
3006
3000
|
async handleAdStart(_marker) {
|
|
3007
|
-
var _a;
|
|
3008
3001
|
const scheduled = this.findCurrentOrNextBreak(
|
|
3009
3002
|
this.video.currentTime * 1e3
|
|
3010
3003
|
);
|
|
3011
3004
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
3012
|
-
let
|
|
3005
|
+
let baseVastUrl;
|
|
3013
3006
|
if (this.apiVastTagUrl) {
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
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");
|
|
3033
3101
|
}
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
this.
|
|
3038
|
-
|
|
3039
|
-
|
|
3102
|
+
break;
|
|
3103
|
+
}
|
|
3104
|
+
if (this.adRequestQueue.length > 0) {
|
|
3105
|
+
if (this.config.debugAdTiming) {
|
|
3106
|
+
console.log(`[CONTINUOUS-FETCH] \u23F3 Already have ${this.adRequestQueue.length} ads queued, waiting...`);
|
|
3107
|
+
}
|
|
3108
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3109
|
+
continue;
|
|
3110
|
+
}
|
|
3111
|
+
const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
|
|
3112
|
+
if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
|
|
3113
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3114
|
+
continue;
|
|
3115
|
+
}
|
|
3116
|
+
if (this.config.debugAdTiming) {
|
|
3117
|
+
console.log("[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch additional ad...");
|
|
3118
|
+
}
|
|
3119
|
+
try {
|
|
3120
|
+
const response = await fetch(newAdUrl, { mode: "cors" });
|
|
3121
|
+
if (!response.ok) {
|
|
3122
|
+
throw new Error(`Failed to fetch VAST: ${response.status}`);
|
|
3123
|
+
}
|
|
3124
|
+
const xmlText = await response.text();
|
|
3125
|
+
const parser = new DOMParser();
|
|
3126
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
3127
|
+
const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
|
|
3128
|
+
if (mediaFiles.length === 0) {
|
|
3040
3129
|
if (this.config.debugAdTiming) {
|
|
3041
|
-
console.log(
|
|
3042
|
-
`[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
|
|
3043
|
-
);
|
|
3130
|
+
console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
|
|
3044
3131
|
}
|
|
3132
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3133
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3134
|
+
continue;
|
|
3045
3135
|
}
|
|
3046
|
-
}
|
|
3047
|
-
if (numberOfAds > 1) {
|
|
3048
|
-
vastTagUrls = this.generateVastUrlsWithCorrelators(
|
|
3049
|
-
this.apiVastTagUrl,
|
|
3050
|
-
numberOfAds
|
|
3051
|
-
);
|
|
3052
3136
|
if (this.config.debugAdTiming) {
|
|
3053
|
-
console.log(
|
|
3054
|
-
`[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
|
|
3055
|
-
);
|
|
3137
|
+
console.log("[CONTINUOUS-FETCH] \u2705 Successfully fetched new ad, adding to queue");
|
|
3056
3138
|
}
|
|
3057
|
-
|
|
3058
|
-
|
|
3139
|
+
this.adRequestQueue.push(newAdUrl);
|
|
3140
|
+
this.totalAdsInBreak++;
|
|
3141
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3142
|
+
} catch (error) {
|
|
3143
|
+
if (this.config.debugAdTiming) {
|
|
3144
|
+
console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
|
|
3145
|
+
}
|
|
3146
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3147
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3059
3148
|
}
|
|
3060
|
-
}
|
|
3061
|
-
|
|
3062
|
-
|
|
3149
|
+
}
|
|
3150
|
+
if (this.config.debugAdTiming) {
|
|
3151
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
stopContinuousFetching() {
|
|
3155
|
+
this.continuousFetchingActive = false;
|
|
3156
|
+
if (this.config.debugAdTiming) {
|
|
3157
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
async tryNextAvailableAd() {
|
|
3161
|
+
const remaining = this.getRemainingAdMs();
|
|
3162
|
+
if (remaining <= 500) {
|
|
3163
|
+
if (this.config.debugAdTiming) {
|
|
3164
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
|
|
3165
|
+
}
|
|
3166
|
+
this.handleAdPodComplete();
|
|
3063
3167
|
return;
|
|
3064
3168
|
}
|
|
3065
|
-
if (
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
this.vastToMediaUrlMap.clear();
|
|
3069
|
-
this.preloadedMediaUrls.clear();
|
|
3070
|
-
this.preloadingMediaUrls.clear();
|
|
3071
|
-
this.failedVastUrls.clear();
|
|
3072
|
-
const currentMuted = this.video.muted;
|
|
3073
|
-
const currentVolume = this.video.volume;
|
|
3074
|
-
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3075
|
-
this.inAdBreak = true;
|
|
3076
|
-
this.currentAdIndex = 0;
|
|
3077
|
-
this.totalAdsInBreak = vastTagUrls.length;
|
|
3078
|
-
this.adPodQueue = [...vastTagUrls];
|
|
3079
|
-
if (this.isAdaptiveMode) {
|
|
3169
|
+
if (this.adRequestQueue.length > 0) {
|
|
3170
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3171
|
+
if (nextAdUrl) {
|
|
3080
3172
|
if (this.config.debugAdTiming) {
|
|
3081
|
-
console.log("[
|
|
3173
|
+
console.log("[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad");
|
|
3082
3174
|
}
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
const url = this.adPodAllUrls[i];
|
|
3087
|
-
if (url) {
|
|
3088
|
-
await this.preloadSingleAd(url);
|
|
3089
|
-
if (this.config.debugAdTiming) {
|
|
3090
|
-
console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
|
|
3091
|
-
}
|
|
3092
|
-
}
|
|
3093
|
-
}
|
|
3094
|
-
if (this.config.debugAdTiming) {
|
|
3095
|
-
console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
|
|
3096
|
-
}
|
|
3097
|
-
} catch (error) {
|
|
3098
|
-
if (this.config.debugAdTiming) {
|
|
3099
|
-
console.warn(
|
|
3100
|
-
"[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
|
|
3101
|
-
error
|
|
3102
|
-
);
|
|
3103
|
-
}
|
|
3104
|
-
}
|
|
3105
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3106
|
-
if (this.config.debugAdTiming) {
|
|
3107
|
-
console.warn(
|
|
3108
|
-
"[ADAPTIVE-POD] Error in background preloading:",
|
|
3109
|
-
error
|
|
3110
|
-
);
|
|
3111
|
-
}
|
|
3112
|
-
});
|
|
3113
|
-
await this.playAdPod();
|
|
3114
|
-
} else {
|
|
3115
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3116
|
-
if (this.config.debugAdTiming) {
|
|
3117
|
-
console.warn(
|
|
3118
|
-
"[StormcloudVideoPlayer] Error in background preloading:",
|
|
3119
|
-
error
|
|
3120
|
-
);
|
|
3121
|
-
}
|
|
3175
|
+
this.currentAdIndex++;
|
|
3176
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3177
|
+
this.tryNextAvailableAd();
|
|
3122
3178
|
});
|
|
3123
|
-
|
|
3179
|
+
return;
|
|
3124
3180
|
}
|
|
3125
3181
|
}
|
|
3126
|
-
if (this.
|
|
3127
|
-
this.
|
|
3128
|
-
|
|
3129
|
-
|
|
3182
|
+
if (!this.isShowingPlaceholder && remaining > 1e3) {
|
|
3183
|
+
this.showPlaceholderAndWaitForAds();
|
|
3184
|
+
} else {
|
|
3185
|
+
if (this.config.debugAdTiming) {
|
|
3186
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
|
|
3187
|
+
}
|
|
3188
|
+
this.handleAdPodComplete();
|
|
3130
3189
|
}
|
|
3131
3190
|
}
|
|
3132
|
-
async
|
|
3133
|
-
|
|
3191
|
+
async showPlaceholderAndWaitForAds() {
|
|
3192
|
+
const remaining = this.getRemainingAdMs();
|
|
3193
|
+
const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
|
|
3194
|
+
if (waitTime < 1e3) {
|
|
3195
|
+
this.handleAdPodComplete();
|
|
3134
3196
|
return;
|
|
3135
3197
|
}
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3198
|
+
if (this.config.debugAdTiming) {
|
|
3199
|
+
console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
|
|
3200
|
+
}
|
|
3201
|
+
this.isShowingPlaceholder = true;
|
|
3202
|
+
this.placeholderStartTimeMs = Date.now();
|
|
3203
|
+
this.ima.showPlaceholder();
|
|
3204
|
+
const checkInterval = 500;
|
|
3205
|
+
const maxChecks = Math.floor(waitTime / checkInterval);
|
|
3206
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
3207
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
3208
|
+
if (!this.inAdBreak) {
|
|
3209
|
+
return;
|
|
3210
|
+
}
|
|
3211
|
+
if (this.adRequestQueue.length > 0) {
|
|
3212
|
+
if (this.config.debugAdTiming) {
|
|
3213
|
+
console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
|
|
3214
|
+
}
|
|
3215
|
+
this.isShowingPlaceholder = false;
|
|
3216
|
+
this.placeholderStartTimeMs = null;
|
|
3217
|
+
this.ima.hidePlaceholder();
|
|
3218
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3219
|
+
if (nextAdUrl) {
|
|
3220
|
+
this.currentAdIndex++;
|
|
3221
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3222
|
+
this.tryNextAvailableAd();
|
|
3223
|
+
});
|
|
3147
3224
|
}
|
|
3225
|
+
return;
|
|
3148
3226
|
}
|
|
3149
|
-
return;
|
|
3150
3227
|
}
|
|
3151
|
-
this.
|
|
3152
|
-
|
|
3153
|
-
await this.playSingleAd(firstPreloaded);
|
|
3154
|
-
} catch (error) {
|
|
3228
|
+
if (this.config.debugAdTiming) {
|
|
3229
|
+
console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
|
|
3155
3230
|
}
|
|
3231
|
+
this.isShowingPlaceholder = false;
|
|
3232
|
+
this.placeholderStartTimeMs = null;
|
|
3233
|
+
this.ima.hidePlaceholder();
|
|
3234
|
+
this.handleAdPodComplete();
|
|
3156
3235
|
}
|
|
3157
3236
|
findCurrentOrNextBreak(nowMs) {
|
|
3158
3237
|
var _a;
|
|
@@ -3312,10 +3391,18 @@ var StormcloudVideoPlayer = class {
|
|
|
3312
3391
|
this.clearAdRequestWatchdog();
|
|
3313
3392
|
this.clearAdFailsafeTimer();
|
|
3314
3393
|
this.activeAdRequestToken = null;
|
|
3394
|
+
this.stopContinuousFetching();
|
|
3395
|
+
if (this.isShowingPlaceholder) {
|
|
3396
|
+
this.ima.hidePlaceholder();
|
|
3397
|
+
this.isShowingPlaceholder = false;
|
|
3398
|
+
this.placeholderStartTimeMs = null;
|
|
3399
|
+
}
|
|
3315
3400
|
this.preloadingAdUrls.clear();
|
|
3316
3401
|
this.vastToMediaUrlMap.clear();
|
|
3317
3402
|
this.preloadedMediaUrls.clear();
|
|
3318
3403
|
this.preloadingMediaUrls.clear();
|
|
3404
|
+
this.adRequestQueue = [];
|
|
3405
|
+
this.successfulAdRequests = [];
|
|
3319
3406
|
this.inAdBreak = false;
|
|
3320
3407
|
this.expectedAdBreakDurationMs = void 0;
|
|
3321
3408
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3342,61 +3429,14 @@ var StormcloudVideoPlayer = class {
|
|
|
3342
3429
|
}
|
|
3343
3430
|
}
|
|
3344
3431
|
handleAdFailure() {
|
|
3345
|
-
const remaining = this.getRemainingAdMs();
|
|
3346
|
-
const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
|
|
3347
|
-
if (remaining > 500 && availableAds > 0) {
|
|
3348
|
-
if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
|
|
3349
|
-
console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
|
|
3350
|
-
setTimeout(() => {
|
|
3351
|
-
this.tryNextAdWithRetry(0);
|
|
3352
|
-
}, 1500);
|
|
3353
|
-
return;
|
|
3354
|
-
}
|
|
3355
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3356
|
-
if (nextPreloaded) {
|
|
3357
|
-
this.currentAdIndex++;
|
|
3358
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3359
|
-
this.handleAdPodComplete();
|
|
3360
|
-
});
|
|
3361
|
-
return;
|
|
3362
|
-
}
|
|
3363
|
-
}
|
|
3364
|
-
console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
|
|
3365
|
-
this.handleAdPodComplete();
|
|
3366
|
-
}
|
|
3367
|
-
tryNextAdWithRetry(retryCount) {
|
|
3368
|
-
const maxRetries = 3;
|
|
3369
3432
|
const remaining = this.getRemainingAdMs();
|
|
3370
3433
|
if (this.config.debugAdTiming) {
|
|
3371
|
-
console.log(
|
|
3372
|
-
`[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
|
|
3373
|
-
);
|
|
3434
|
+
console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
3374
3435
|
}
|
|
3375
|
-
if (remaining
|
|
3376
|
-
|
|
3377
|
-
this.handleAdPodComplete();
|
|
3378
|
-
return;
|
|
3379
|
-
}
|
|
3380
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3381
|
-
if (nextPreloaded) {
|
|
3382
|
-
this.currentAdIndex++;
|
|
3383
|
-
console.log(
|
|
3384
|
-
`[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
3385
|
-
);
|
|
3386
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3387
|
-
this.handleAdPodComplete();
|
|
3388
|
-
});
|
|
3389
|
-
} else if (retryCount < maxRetries) {
|
|
3390
|
-
console.log(
|
|
3391
|
-
`[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
|
|
3392
|
-
);
|
|
3393
|
-
setTimeout(() => {
|
|
3394
|
-
this.tryNextAdWithRetry(retryCount + 1);
|
|
3395
|
-
}, 1e3);
|
|
3436
|
+
if (remaining > 500) {
|
|
3437
|
+
this.tryNextAvailableAd();
|
|
3396
3438
|
} else {
|
|
3397
|
-
console.
|
|
3398
|
-
`[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
|
|
3399
|
-
);
|
|
3439
|
+
console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
|
|
3400
3440
|
this.handleAdPodComplete();
|
|
3401
3441
|
}
|
|
3402
3442
|
}
|
|
@@ -3793,6 +3833,12 @@ var StormcloudVideoPlayer = class {
|
|
|
3793
3833
|
);
|
|
3794
3834
|
}
|
|
3795
3835
|
mediaUrls = await this.fetchAndParseVastXml(vastTagUrl);
|
|
3836
|
+
if (this.config.debugAdTiming) {
|
|
3837
|
+
console.log(
|
|
3838
|
+
`[StormcloudVideoPlayer] Extracted ${mediaUrls.length} media URLs:`,
|
|
3839
|
+
mediaUrls
|
|
3840
|
+
);
|
|
3841
|
+
}
|
|
3796
3842
|
if (mediaUrls.length > 0) {
|
|
3797
3843
|
this.vastToMediaUrlMap.set(vastTagUrl, mediaUrls);
|
|
3798
3844
|
}
|
|
@@ -3988,6 +4034,7 @@ var StormcloudVideoPlayer = class {
|
|
|
3988
4034
|
}
|
|
3989
4035
|
destroy() {
|
|
3990
4036
|
var _a, _b;
|
|
4037
|
+
this.stopContinuousFetching();
|
|
3991
4038
|
this.clearAdStartTimer();
|
|
3992
4039
|
this.clearAdStopTimer();
|
|
3993
4040
|
this.clearAdFailsafeTimer();
|
|
@@ -4002,6 +4049,8 @@ var StormcloudVideoPlayer = class {
|
|
|
4002
4049
|
this.preloadedMediaUrls.clear();
|
|
4003
4050
|
this.preloadingMediaUrls.clear();
|
|
4004
4051
|
this.adPodAllUrls = [];
|
|
4052
|
+
this.adRequestQueue = [];
|
|
4053
|
+
this.successfulAdRequests = [];
|
|
4005
4054
|
}
|
|
4006
4055
|
};
|
|
4007
4056
|
// Annotate the CommonJS export names for ESM import in node:
|