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/players/index.cjs
CHANGED
|
@@ -383,12 +383,8 @@ function createImaController(video, options) {
|
|
|
383
383
|
let adsLoadedReject;
|
|
384
384
|
function makeAdsRequest(google, vastTagUrl) {
|
|
385
385
|
const adsRequest = new google.ima.AdsRequest();
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
adsRequest.adsResponse = preloadedResponse;
|
|
389
|
-
} else {
|
|
390
|
-
adsRequest.adTagUrl = vastTagUrl;
|
|
391
|
-
}
|
|
386
|
+
console.log("[IMA] \u{1F4E1} Requesting VAST from URL (letting IMA fetch fresh)");
|
|
387
|
+
adsRequest.adTagUrl = vastTagUrl;
|
|
392
388
|
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
393
389
|
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
394
390
|
adsRequest.linearAdSlotWidth = videoWidth;
|
|
@@ -411,11 +407,8 @@ function createImaController(video, options) {
|
|
|
411
407
|
console.warn("[IMA] Failed to call setAdWillPlayMuted:", error);
|
|
412
408
|
}
|
|
413
409
|
}
|
|
414
|
-
adsRequest.vastLoadTimeout =
|
|
410
|
+
adsRequest.vastLoadTimeout = 1e4;
|
|
415
411
|
adsLoader.requestAds(adsRequest);
|
|
416
|
-
if (preloadedResponse) {
|
|
417
|
-
preloadedVast.delete(vastTagUrl);
|
|
418
|
-
}
|
|
419
412
|
}
|
|
420
413
|
function ensurePlaceholderContainer() {
|
|
421
414
|
var _a;
|
|
@@ -2131,6 +2124,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2131
2124
|
this.targetAdBreakDurationMs = null;
|
|
2132
2125
|
this.isAdaptiveMode = false;
|
|
2133
2126
|
this.failedVastUrls = /* @__PURE__ */ new Set();
|
|
2127
|
+
this.continuousFetchingActive = false;
|
|
2128
|
+
this.adRequestQueue = [];
|
|
2129
|
+
this.successfulAdRequests = [];
|
|
2130
|
+
this.maxPlaceholderDurationMs = 5e3;
|
|
2131
|
+
this.placeholderStartTimeMs = null;
|
|
2132
|
+
this.isShowingPlaceholder = false;
|
|
2134
2133
|
initializePolyfills();
|
|
2135
2134
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2136
2135
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2437,16 +2436,11 @@ var StormcloudVideoPlayer = class {
|
|
|
2437
2436
|
return;
|
|
2438
2437
|
}
|
|
2439
2438
|
const remaining = this.getRemainingAdMs();
|
|
2440
|
-
if (
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
this.handleAdPodComplete();
|
|
2446
|
-
});
|
|
2447
|
-
} else {
|
|
2448
|
-
this.handleAdPodComplete();
|
|
2449
|
-
}
|
|
2439
|
+
if (this.config.debugAdTiming) {
|
|
2440
|
+
console.log(`[CONTINUOUS-FETCH] content_resume event: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
2441
|
+
}
|
|
2442
|
+
if (remaining > 500) {
|
|
2443
|
+
this.tryNextAvailableAd();
|
|
2450
2444
|
} else {
|
|
2451
2445
|
this.handleAdPodComplete();
|
|
2452
2446
|
}
|
|
@@ -3046,155 +3040,240 @@ var StormcloudVideoPlayer = class {
|
|
|
3046
3040
|
return true;
|
|
3047
3041
|
}
|
|
3048
3042
|
async handleAdStart(_marker) {
|
|
3049
|
-
var _a;
|
|
3050
3043
|
const scheduled = this.findCurrentOrNextBreak(
|
|
3051
3044
|
this.video.currentTime * 1e3
|
|
3052
3045
|
);
|
|
3053
3046
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
3054
|
-
let
|
|
3047
|
+
let baseVastUrl;
|
|
3055
3048
|
if (this.apiVastTagUrl) {
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3049
|
+
baseVastUrl = this.apiVastTagUrl;
|
|
3050
|
+
} else if (tags && tags.length > 0 && tags[0]) {
|
|
3051
|
+
baseVastUrl = tags[0];
|
|
3052
|
+
} else {
|
|
3053
|
+
return;
|
|
3054
|
+
}
|
|
3055
|
+
const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
|
|
3056
|
+
if (this.isLiveStream && adBreakDurationMs != null && adBreakDurationMs > 0) {
|
|
3057
|
+
this.isAdaptiveMode = true;
|
|
3058
|
+
this.targetAdBreakDurationMs = adBreakDurationMs;
|
|
3059
|
+
this.fetchedAdDurations.clear();
|
|
3060
|
+
if (this.config.debugAdTiming) {
|
|
3061
|
+
console.log(
|
|
3062
|
+
`[CONTINUOUS-FETCH] \u{1F4FA} LIVE MODE: Target duration=${adBreakDurationMs}ms | Will continuously fetch ads during break`
|
|
3063
|
+
);
|
|
3064
|
+
}
|
|
3065
|
+
} else {
|
|
3066
|
+
this.isAdaptiveMode = false;
|
|
3067
|
+
this.targetAdBreakDurationMs = null;
|
|
3068
|
+
this.fetchedAdDurations.clear();
|
|
3069
|
+
if (this.config.debugAdTiming) {
|
|
3070
|
+
console.log(
|
|
3071
|
+
`[CONTINUOUS-FETCH] \u{1F3AC} VOD MODE: Using fixed ad strategy`
|
|
3072
|
+
);
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
this.adPodAllUrls = [];
|
|
3076
|
+
this.preloadingAdUrls.clear();
|
|
3077
|
+
this.vastToMediaUrlMap.clear();
|
|
3078
|
+
this.preloadedMediaUrls.clear();
|
|
3079
|
+
this.preloadingMediaUrls.clear();
|
|
3080
|
+
this.failedVastUrls.clear();
|
|
3081
|
+
this.adRequestQueue = [];
|
|
3082
|
+
this.successfulAdRequests = [];
|
|
3083
|
+
this.continuousFetchingActive = true;
|
|
3084
|
+
this.isShowingPlaceholder = false;
|
|
3085
|
+
this.placeholderStartTimeMs = null;
|
|
3086
|
+
const currentMuted = this.video.muted;
|
|
3087
|
+
const currentVolume = this.video.volume;
|
|
3088
|
+
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3089
|
+
this.inAdBreak = true;
|
|
3090
|
+
this.currentAdIndex = 0;
|
|
3091
|
+
this.totalAdsInBreak = 1;
|
|
3092
|
+
this.adPodQueue = [];
|
|
3093
|
+
if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
|
|
3094
|
+
this.expectedAdBreakDurationMs = adBreakDurationMs;
|
|
3095
|
+
this.currentAdBreakStartWallClockMs = Date.now();
|
|
3096
|
+
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
3097
|
+
}
|
|
3098
|
+
if (this.config.debugAdTiming) {
|
|
3099
|
+
console.log("[CONTINUOUS-FETCH] \u{1F680} Immediately requesting first ad...");
|
|
3100
|
+
}
|
|
3101
|
+
const firstAdUrlArray = this.generateVastUrlsWithCorrelators(baseVastUrl, 1);
|
|
3102
|
+
const firstAdUrl = firstAdUrlArray[0];
|
|
3103
|
+
if (!firstAdUrl) {
|
|
3104
|
+
if (this.config.debugAdTiming) {
|
|
3105
|
+
console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F Failed to generate first ad URL");
|
|
3106
|
+
}
|
|
3107
|
+
this.handleAdPodComplete();
|
|
3108
|
+
return;
|
|
3109
|
+
}
|
|
3110
|
+
try {
|
|
3111
|
+
await this.ima.requestAds(firstAdUrl);
|
|
3112
|
+
if (this.config.debugAdTiming) {
|
|
3113
|
+
console.log("[CONTINUOUS-FETCH] \u2705 First ad request successful, starting playback");
|
|
3114
|
+
}
|
|
3115
|
+
this.successfulAdRequests.push(firstAdUrl);
|
|
3116
|
+
this.currentAdIndex++;
|
|
3117
|
+
this.startContinuousFetching(baseVastUrl);
|
|
3118
|
+
await this.ima.play();
|
|
3119
|
+
} catch (error) {
|
|
3120
|
+
if (this.config.debugAdTiming) {
|
|
3121
|
+
console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
|
|
3122
|
+
}
|
|
3123
|
+
this.failedVastUrls.add(firstAdUrl);
|
|
3124
|
+
this.startContinuousFetching(baseVastUrl);
|
|
3125
|
+
this.tryNextAvailableAd();
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
startContinuousFetching(baseVastUrl) {
|
|
3129
|
+
if (!this.continuousFetchingActive) {
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
if (this.config.debugAdTiming) {
|
|
3133
|
+
console.log("[CONTINUOUS-FETCH] \u{1F504} Starting continuous ad fetching loop");
|
|
3134
|
+
}
|
|
3135
|
+
this.continuousFetchLoop(baseVastUrl);
|
|
3136
|
+
}
|
|
3137
|
+
async continuousFetchLoop(baseVastUrl) {
|
|
3138
|
+
while (this.continuousFetchingActive && this.inAdBreak) {
|
|
3139
|
+
const remaining = this.getRemainingAdMs();
|
|
3140
|
+
if (remaining <= 0) {
|
|
3141
|
+
if (this.config.debugAdTiming) {
|
|
3142
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F Ad break time expired, stopping fetch loop");
|
|
3075
3143
|
}
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
this.
|
|
3080
|
-
|
|
3081
|
-
|
|
3144
|
+
break;
|
|
3145
|
+
}
|
|
3146
|
+
if (this.adRequestQueue.length > 0) {
|
|
3147
|
+
if (this.config.debugAdTiming) {
|
|
3148
|
+
console.log(`[CONTINUOUS-FETCH] \u23F3 Already have ${this.adRequestQueue.length} ads queued, waiting...`);
|
|
3149
|
+
}
|
|
3150
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3151
|
+
continue;
|
|
3152
|
+
}
|
|
3153
|
+
const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
|
|
3154
|
+
if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
|
|
3155
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3156
|
+
continue;
|
|
3157
|
+
}
|
|
3158
|
+
if (this.config.debugAdTiming) {
|
|
3159
|
+
console.log("[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch additional ad...");
|
|
3160
|
+
}
|
|
3161
|
+
try {
|
|
3162
|
+
const response = await fetch(newAdUrl, { mode: "cors" });
|
|
3163
|
+
if (!response.ok) {
|
|
3164
|
+
throw new Error(`Failed to fetch VAST: ${response.status}`);
|
|
3165
|
+
}
|
|
3166
|
+
const xmlText = await response.text();
|
|
3167
|
+
const parser = new DOMParser();
|
|
3168
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
3169
|
+
const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
|
|
3170
|
+
if (mediaFiles.length === 0) {
|
|
3082
3171
|
if (this.config.debugAdTiming) {
|
|
3083
|
-
console.log(
|
|
3084
|
-
`[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
|
|
3085
|
-
);
|
|
3172
|
+
console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
|
|
3086
3173
|
}
|
|
3174
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3175
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3176
|
+
continue;
|
|
3087
3177
|
}
|
|
3088
|
-
}
|
|
3089
|
-
if (numberOfAds > 1) {
|
|
3090
|
-
vastTagUrls = this.generateVastUrlsWithCorrelators(
|
|
3091
|
-
this.apiVastTagUrl,
|
|
3092
|
-
numberOfAds
|
|
3093
|
-
);
|
|
3094
3178
|
if (this.config.debugAdTiming) {
|
|
3095
|
-
console.log(
|
|
3096
|
-
`[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
|
|
3097
|
-
);
|
|
3179
|
+
console.log("[CONTINUOUS-FETCH] \u2705 Successfully fetched new ad, adding to queue");
|
|
3098
3180
|
}
|
|
3099
|
-
|
|
3100
|
-
|
|
3181
|
+
this.adRequestQueue.push(newAdUrl);
|
|
3182
|
+
this.totalAdsInBreak++;
|
|
3183
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3184
|
+
} catch (error) {
|
|
3185
|
+
if (this.config.debugAdTiming) {
|
|
3186
|
+
console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
|
|
3187
|
+
}
|
|
3188
|
+
this.failedVastUrls.add(newAdUrl);
|
|
3189
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3101
3190
|
}
|
|
3102
|
-
}
|
|
3103
|
-
|
|
3104
|
-
|
|
3191
|
+
}
|
|
3192
|
+
if (this.config.debugAdTiming) {
|
|
3193
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
stopContinuousFetching() {
|
|
3197
|
+
this.continuousFetchingActive = false;
|
|
3198
|
+
if (this.config.debugAdTiming) {
|
|
3199
|
+
console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
async tryNextAvailableAd() {
|
|
3203
|
+
const remaining = this.getRemainingAdMs();
|
|
3204
|
+
if (remaining <= 500) {
|
|
3205
|
+
if (this.config.debugAdTiming) {
|
|
3206
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
|
|
3207
|
+
}
|
|
3208
|
+
this.handleAdPodComplete();
|
|
3105
3209
|
return;
|
|
3106
3210
|
}
|
|
3107
|
-
if (
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
this.vastToMediaUrlMap.clear();
|
|
3111
|
-
this.preloadedMediaUrls.clear();
|
|
3112
|
-
this.preloadingMediaUrls.clear();
|
|
3113
|
-
this.failedVastUrls.clear();
|
|
3114
|
-
const currentMuted = this.video.muted;
|
|
3115
|
-
const currentVolume = this.video.volume;
|
|
3116
|
-
this.ima.updateOriginalMutedState(currentMuted, currentVolume);
|
|
3117
|
-
this.inAdBreak = true;
|
|
3118
|
-
this.currentAdIndex = 0;
|
|
3119
|
-
this.totalAdsInBreak = vastTagUrls.length;
|
|
3120
|
-
this.adPodQueue = [...vastTagUrls];
|
|
3121
|
-
if (this.isAdaptiveMode) {
|
|
3211
|
+
if (this.adRequestQueue.length > 0) {
|
|
3212
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3213
|
+
if (nextAdUrl) {
|
|
3122
3214
|
if (this.config.debugAdTiming) {
|
|
3123
|
-
console.log("[
|
|
3215
|
+
console.log("[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad");
|
|
3124
3216
|
}
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
const url = this.adPodAllUrls[i];
|
|
3129
|
-
if (url) {
|
|
3130
|
-
await this.preloadSingleAd(url);
|
|
3131
|
-
if (this.config.debugAdTiming) {
|
|
3132
|
-
console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
|
|
3133
|
-
}
|
|
3134
|
-
}
|
|
3135
|
-
}
|
|
3136
|
-
if (this.config.debugAdTiming) {
|
|
3137
|
-
console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
|
|
3138
|
-
}
|
|
3139
|
-
} catch (error) {
|
|
3140
|
-
if (this.config.debugAdTiming) {
|
|
3141
|
-
console.warn(
|
|
3142
|
-
"[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
|
|
3143
|
-
error
|
|
3144
|
-
);
|
|
3145
|
-
}
|
|
3146
|
-
}
|
|
3147
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3148
|
-
if (this.config.debugAdTiming) {
|
|
3149
|
-
console.warn(
|
|
3150
|
-
"[ADAPTIVE-POD] Error in background preloading:",
|
|
3151
|
-
error
|
|
3152
|
-
);
|
|
3153
|
-
}
|
|
3154
|
-
});
|
|
3155
|
-
await this.playAdPod();
|
|
3156
|
-
} else {
|
|
3157
|
-
this.preloadAllAdsInBackground().catch((error) => {
|
|
3158
|
-
if (this.config.debugAdTiming) {
|
|
3159
|
-
console.warn(
|
|
3160
|
-
"[StormcloudVideoPlayer] Error in background preloading:",
|
|
3161
|
-
error
|
|
3162
|
-
);
|
|
3163
|
-
}
|
|
3217
|
+
this.currentAdIndex++;
|
|
3218
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3219
|
+
this.tryNextAvailableAd();
|
|
3164
3220
|
});
|
|
3165
|
-
|
|
3221
|
+
return;
|
|
3166
3222
|
}
|
|
3167
3223
|
}
|
|
3168
|
-
if (this.
|
|
3169
|
-
this.
|
|
3170
|
-
|
|
3171
|
-
|
|
3224
|
+
if (!this.isShowingPlaceholder && remaining > 1e3) {
|
|
3225
|
+
this.showPlaceholderAndWaitForAds();
|
|
3226
|
+
} else {
|
|
3227
|
+
if (this.config.debugAdTiming) {
|
|
3228
|
+
console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
|
|
3229
|
+
}
|
|
3230
|
+
this.handleAdPodComplete();
|
|
3172
3231
|
}
|
|
3173
3232
|
}
|
|
3174
|
-
async
|
|
3175
|
-
|
|
3233
|
+
async showPlaceholderAndWaitForAds() {
|
|
3234
|
+
const remaining = this.getRemainingAdMs();
|
|
3235
|
+
const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
|
|
3236
|
+
if (waitTime < 1e3) {
|
|
3237
|
+
this.handleAdPodComplete();
|
|
3176
3238
|
return;
|
|
3177
3239
|
}
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3240
|
+
if (this.config.debugAdTiming) {
|
|
3241
|
+
console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
|
|
3242
|
+
}
|
|
3243
|
+
this.isShowingPlaceholder = true;
|
|
3244
|
+
this.placeholderStartTimeMs = Date.now();
|
|
3245
|
+
this.ima.showPlaceholder();
|
|
3246
|
+
const checkInterval = 500;
|
|
3247
|
+
const maxChecks = Math.floor(waitTime / checkInterval);
|
|
3248
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
3249
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
3250
|
+
if (!this.inAdBreak) {
|
|
3251
|
+
return;
|
|
3252
|
+
}
|
|
3253
|
+
if (this.adRequestQueue.length > 0) {
|
|
3254
|
+
if (this.config.debugAdTiming) {
|
|
3255
|
+
console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
|
|
3256
|
+
}
|
|
3257
|
+
this.isShowingPlaceholder = false;
|
|
3258
|
+
this.placeholderStartTimeMs = null;
|
|
3259
|
+
this.ima.hidePlaceholder();
|
|
3260
|
+
const nextAdUrl = this.adRequestQueue.shift();
|
|
3261
|
+
if (nextAdUrl) {
|
|
3262
|
+
this.currentAdIndex++;
|
|
3263
|
+
await this.playSingleAd(nextAdUrl).catch(() => {
|
|
3264
|
+
this.tryNextAvailableAd();
|
|
3265
|
+
});
|
|
3189
3266
|
}
|
|
3267
|
+
return;
|
|
3190
3268
|
}
|
|
3191
|
-
return;
|
|
3192
3269
|
}
|
|
3193
|
-
this.
|
|
3194
|
-
|
|
3195
|
-
await this.playSingleAd(firstPreloaded);
|
|
3196
|
-
} catch (error) {
|
|
3270
|
+
if (this.config.debugAdTiming) {
|
|
3271
|
+
console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
|
|
3197
3272
|
}
|
|
3273
|
+
this.isShowingPlaceholder = false;
|
|
3274
|
+
this.placeholderStartTimeMs = null;
|
|
3275
|
+
this.ima.hidePlaceholder();
|
|
3276
|
+
this.handleAdPodComplete();
|
|
3198
3277
|
}
|
|
3199
3278
|
findCurrentOrNextBreak(nowMs) {
|
|
3200
3279
|
var _a;
|
|
@@ -3354,10 +3433,18 @@ var StormcloudVideoPlayer = class {
|
|
|
3354
3433
|
this.clearAdRequestWatchdog();
|
|
3355
3434
|
this.clearAdFailsafeTimer();
|
|
3356
3435
|
this.activeAdRequestToken = null;
|
|
3436
|
+
this.stopContinuousFetching();
|
|
3437
|
+
if (this.isShowingPlaceholder) {
|
|
3438
|
+
this.ima.hidePlaceholder();
|
|
3439
|
+
this.isShowingPlaceholder = false;
|
|
3440
|
+
this.placeholderStartTimeMs = null;
|
|
3441
|
+
}
|
|
3357
3442
|
this.preloadingAdUrls.clear();
|
|
3358
3443
|
this.vastToMediaUrlMap.clear();
|
|
3359
3444
|
this.preloadedMediaUrls.clear();
|
|
3360
3445
|
this.preloadingMediaUrls.clear();
|
|
3446
|
+
this.adRequestQueue = [];
|
|
3447
|
+
this.successfulAdRequests = [];
|
|
3361
3448
|
this.inAdBreak = false;
|
|
3362
3449
|
this.expectedAdBreakDurationMs = void 0;
|
|
3363
3450
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3384,61 +3471,14 @@ var StormcloudVideoPlayer = class {
|
|
|
3384
3471
|
}
|
|
3385
3472
|
}
|
|
3386
3473
|
handleAdFailure() {
|
|
3387
|
-
const remaining = this.getRemainingAdMs();
|
|
3388
|
-
const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
|
|
3389
|
-
if (remaining > 500 && availableAds > 0) {
|
|
3390
|
-
if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
|
|
3391
|
-
console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
|
|
3392
|
-
setTimeout(() => {
|
|
3393
|
-
this.tryNextAdWithRetry(0);
|
|
3394
|
-
}, 1500);
|
|
3395
|
-
return;
|
|
3396
|
-
}
|
|
3397
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3398
|
-
if (nextPreloaded) {
|
|
3399
|
-
this.currentAdIndex++;
|
|
3400
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3401
|
-
this.handleAdPodComplete();
|
|
3402
|
-
});
|
|
3403
|
-
return;
|
|
3404
|
-
}
|
|
3405
|
-
}
|
|
3406
|
-
console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
|
|
3407
|
-
this.handleAdPodComplete();
|
|
3408
|
-
}
|
|
3409
|
-
tryNextAdWithRetry(retryCount) {
|
|
3410
|
-
const maxRetries = 3;
|
|
3411
3474
|
const remaining = this.getRemainingAdMs();
|
|
3412
3475
|
if (this.config.debugAdTiming) {
|
|
3413
|
-
console.log(
|
|
3414
|
-
`[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
|
|
3415
|
-
);
|
|
3476
|
+
console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
|
|
3416
3477
|
}
|
|
3417
|
-
if (remaining
|
|
3418
|
-
|
|
3419
|
-
this.handleAdPodComplete();
|
|
3420
|
-
return;
|
|
3421
|
-
}
|
|
3422
|
-
const nextPreloaded = this.findNextPreloadedAd();
|
|
3423
|
-
if (nextPreloaded) {
|
|
3424
|
-
this.currentAdIndex++;
|
|
3425
|
-
console.log(
|
|
3426
|
-
`[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
3427
|
-
);
|
|
3428
|
-
this.playSingleAd(nextPreloaded).catch(() => {
|
|
3429
|
-
this.handleAdPodComplete();
|
|
3430
|
-
});
|
|
3431
|
-
} else if (retryCount < maxRetries) {
|
|
3432
|
-
console.log(
|
|
3433
|
-
`[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
|
|
3434
|
-
);
|
|
3435
|
-
setTimeout(() => {
|
|
3436
|
-
this.tryNextAdWithRetry(retryCount + 1);
|
|
3437
|
-
}, 1e3);
|
|
3478
|
+
if (remaining > 500) {
|
|
3479
|
+
this.tryNextAvailableAd();
|
|
3438
3480
|
} else {
|
|
3439
|
-
console.
|
|
3440
|
-
`[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
|
|
3441
|
-
);
|
|
3481
|
+
console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
|
|
3442
3482
|
this.handleAdPodComplete();
|
|
3443
3483
|
}
|
|
3444
3484
|
}
|
|
@@ -3835,6 +3875,12 @@ var StormcloudVideoPlayer = class {
|
|
|
3835
3875
|
);
|
|
3836
3876
|
}
|
|
3837
3877
|
mediaUrls = await this.fetchAndParseVastXml(vastTagUrl);
|
|
3878
|
+
if (this.config.debugAdTiming) {
|
|
3879
|
+
console.log(
|
|
3880
|
+
`[StormcloudVideoPlayer] Extracted ${mediaUrls.length} media URLs:`,
|
|
3881
|
+
mediaUrls
|
|
3882
|
+
);
|
|
3883
|
+
}
|
|
3838
3884
|
if (mediaUrls.length > 0) {
|
|
3839
3885
|
this.vastToMediaUrlMap.set(vastTagUrl, mediaUrls);
|
|
3840
3886
|
}
|
|
@@ -4030,6 +4076,7 @@ var StormcloudVideoPlayer = class {
|
|
|
4030
4076
|
}
|
|
4031
4077
|
destroy() {
|
|
4032
4078
|
var _a, _b;
|
|
4079
|
+
this.stopContinuousFetching();
|
|
4033
4080
|
this.clearAdStartTimer();
|
|
4034
4081
|
this.clearAdStopTimer();
|
|
4035
4082
|
this.clearAdFailsafeTimer();
|
|
@@ -4044,6 +4091,8 @@ var StormcloudVideoPlayer = class {
|
|
|
4044
4091
|
this.preloadedMediaUrls.clear();
|
|
4045
4092
|
this.preloadingMediaUrls.clear();
|
|
4046
4093
|
this.adPodAllUrls = [];
|
|
4094
|
+
this.adRequestQueue = [];
|
|
4095
|
+
this.successfulAdRequests = [];
|
|
4047
4096
|
}
|
|
4048
4097
|
};
|
|
4049
4098
|
|