stormcloud-video-player 0.3.9 → 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/lib/index.d.cts CHANGED
@@ -142,6 +142,12 @@ declare class StormcloudVideoPlayer {
142
142
  private targetAdBreakDurationMs;
143
143
  private isAdaptiveMode;
144
144
  private failedVastUrls;
145
+ private continuousFetchingActive;
146
+ private adRequestQueue;
147
+ private successfulAdRequests;
148
+ private maxPlaceholderDurationMs;
149
+ private placeholderStartTimeMs;
150
+ private isShowingPlaceholder;
145
151
  constructor(config: StormcloudVideoPlayerConfig);
146
152
  private createAdPlayer;
147
153
  load(): Promise<void>;
@@ -169,7 +175,11 @@ declare class StormcloudVideoPlayer {
169
175
  shouldShowNativeControls(): boolean;
170
176
  private shouldContinueLiveStreamDuringAds;
171
177
  private handleAdStart;
172
- private playAdPod;
178
+ private startContinuousFetching;
179
+ private continuousFetchLoop;
180
+ private stopContinuousFetching;
181
+ private tryNextAvailableAd;
182
+ private showPlaceholderAndWaitForAds;
173
183
  private findCurrentOrNextBreak;
174
184
  private onTimeUpdate;
175
185
  private handleMidAdJoin;
@@ -182,7 +192,6 @@ declare class StormcloudVideoPlayer {
182
192
  private playSingleAd;
183
193
  private handleAdPodComplete;
184
194
  private handleAdFailure;
185
- private tryNextAdWithRetry;
186
195
  private startAdRequestWatchdog;
187
196
  private clearAdRequestWatchdog;
188
197
  private startAdFailsafeTimer;
package/lib/index.d.ts CHANGED
@@ -142,6 +142,12 @@ declare class StormcloudVideoPlayer {
142
142
  private targetAdBreakDurationMs;
143
143
  private isAdaptiveMode;
144
144
  private failedVastUrls;
145
+ private continuousFetchingActive;
146
+ private adRequestQueue;
147
+ private successfulAdRequests;
148
+ private maxPlaceholderDurationMs;
149
+ private placeholderStartTimeMs;
150
+ private isShowingPlaceholder;
145
151
  constructor(config: StormcloudVideoPlayerConfig);
146
152
  private createAdPlayer;
147
153
  load(): Promise<void>;
@@ -169,7 +175,11 @@ declare class StormcloudVideoPlayer {
169
175
  shouldShowNativeControls(): boolean;
170
176
  private shouldContinueLiveStreamDuringAds;
171
177
  private handleAdStart;
172
- private playAdPod;
178
+ private startContinuousFetching;
179
+ private continuousFetchLoop;
180
+ private stopContinuousFetching;
181
+ private tryNextAvailableAd;
182
+ private showPlaceholderAndWaitForAds;
173
183
  private findCurrentOrNextBreak;
174
184
  private onTimeUpdate;
175
185
  private handleMidAdJoin;
@@ -182,7 +192,6 @@ declare class StormcloudVideoPlayer {
182
192
  private playSingleAd;
183
193
  private handleAdPodComplete;
184
194
  private handleAdFailure;
185
- private tryNextAdWithRetry;
186
195
  private startAdRequestWatchdog;
187
196
  private clearAdRequestWatchdog;
188
197
  private startAdFailsafeTimer;
package/lib/index.js CHANGED
@@ -2080,6 +2080,12 @@ var StormcloudVideoPlayer = class {
2080
2080
  this.targetAdBreakDurationMs = null;
2081
2081
  this.isAdaptiveMode = false;
2082
2082
  this.failedVastUrls = /* @__PURE__ */ new Set();
2083
+ this.continuousFetchingActive = false;
2084
+ this.adRequestQueue = [];
2085
+ this.successfulAdRequests = [];
2086
+ this.maxPlaceholderDurationMs = 5e3;
2087
+ this.placeholderStartTimeMs = null;
2088
+ this.isShowingPlaceholder = false;
2083
2089
  initializePolyfills();
2084
2090
  const browserOverrides = getBrowserConfigOverrides();
2085
2091
  this.config = { ...config, ...browserOverrides };
@@ -2386,16 +2392,11 @@ var StormcloudVideoPlayer = class {
2386
2392
  return;
2387
2393
  }
2388
2394
  const remaining = this.getRemainingAdMs();
2389
- if (remaining > 500 && this.adPodQueue.length > 0) {
2390
- const nextPreloaded = this.findNextPreloadedAd();
2391
- if (nextPreloaded) {
2392
- this.currentAdIndex++;
2393
- this.playSingleAd(nextPreloaded).catch(() => {
2394
- this.handleAdPodComplete();
2395
- });
2396
- } else {
2397
- this.handleAdPodComplete();
2398
- }
2395
+ if (this.config.debugAdTiming) {
2396
+ console.log(`[CONTINUOUS-FETCH] content_resume event: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
2397
+ }
2398
+ if (remaining > 500) {
2399
+ this.tryNextAvailableAd();
2399
2400
  } else {
2400
2401
  this.handleAdPodComplete();
2401
2402
  }
@@ -2995,155 +2996,240 @@ var StormcloudVideoPlayer = class {
2995
2996
  return true;
2996
2997
  }
2997
2998
  async handleAdStart(_marker) {
2998
- var _a;
2999
2999
  const scheduled = this.findCurrentOrNextBreak(
3000
3000
  this.video.currentTime * 1e3
3001
3001
  );
3002
3002
  const tags = this.selectVastTagsForBreak(scheduled);
3003
- let vastTagUrls = [];
3003
+ let baseVastUrl;
3004
3004
  if (this.apiVastTagUrl) {
3005
- let numberOfAds = 1;
3006
- if (this.isLiveStream) {
3007
- const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
3008
- if (adBreakDurationMs != null && adBreakDurationMs > 0) {
3009
- this.isAdaptiveMode = true;
3010
- this.targetAdBreakDurationMs = adBreakDurationMs;
3011
- this.fetchedAdDurations.clear();
3012
- numberOfAds = 2;
3013
- if (this.config.debugAdTiming) {
3014
- console.log(
3015
- `[ADAPTIVE-POD] \u{1F4FA} LIVE MODE (ADAPTIVE): Target duration=${adBreakDurationMs}ms | Starting with ${numberOfAds} ads, will fetch actual durations and add more dynamically`
3016
- );
3017
- }
3018
- } else {
3019
- if (this.config.debugAdTiming) {
3020
- console.warn(
3021
- "[DEBUG-POD] \u26A0\uFE0F LIVE MODE: No duration available, defaulting to 1 ad"
3022
- );
3023
- }
3005
+ baseVastUrl = this.apiVastTagUrl;
3006
+ } else if (tags && tags.length > 0 && tags[0]) {
3007
+ baseVastUrl = tags[0];
3008
+ } else {
3009
+ return;
3010
+ }
3011
+ const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
3012
+ if (this.isLiveStream && adBreakDurationMs != null && adBreakDurationMs > 0) {
3013
+ this.isAdaptiveMode = true;
3014
+ this.targetAdBreakDurationMs = adBreakDurationMs;
3015
+ this.fetchedAdDurations.clear();
3016
+ if (this.config.debugAdTiming) {
3017
+ console.log(
3018
+ `[CONTINUOUS-FETCH] \u{1F4FA} LIVE MODE: Target duration=${adBreakDurationMs}ms | Will continuously fetch ads during break`
3019
+ );
3020
+ }
3021
+ } else {
3022
+ this.isAdaptiveMode = false;
3023
+ this.targetAdBreakDurationMs = null;
3024
+ this.fetchedAdDurations.clear();
3025
+ if (this.config.debugAdTiming) {
3026
+ console.log(
3027
+ `[CONTINUOUS-FETCH] \u{1F3AC} VOD MODE: Using fixed ad strategy`
3028
+ );
3029
+ }
3030
+ }
3031
+ this.adPodAllUrls = [];
3032
+ this.preloadingAdUrls.clear();
3033
+ this.vastToMediaUrlMap.clear();
3034
+ this.preloadedMediaUrls.clear();
3035
+ this.preloadingMediaUrls.clear();
3036
+ this.failedVastUrls.clear();
3037
+ this.adRequestQueue = [];
3038
+ this.successfulAdRequests = [];
3039
+ this.continuousFetchingActive = true;
3040
+ this.isShowingPlaceholder = false;
3041
+ this.placeholderStartTimeMs = null;
3042
+ const currentMuted = this.video.muted;
3043
+ const currentVolume = this.video.volume;
3044
+ this.ima.updateOriginalMutedState(currentMuted, currentVolume);
3045
+ this.inAdBreak = true;
3046
+ this.currentAdIndex = 0;
3047
+ this.totalAdsInBreak = 1;
3048
+ this.adPodQueue = [];
3049
+ if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
3050
+ this.expectedAdBreakDurationMs = adBreakDurationMs;
3051
+ this.currentAdBreakStartWallClockMs = Date.now();
3052
+ this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
3053
+ }
3054
+ if (this.config.debugAdTiming) {
3055
+ console.log("[CONTINUOUS-FETCH] \u{1F680} Immediately requesting first ad...");
3056
+ }
3057
+ const firstAdUrlArray = this.generateVastUrlsWithCorrelators(baseVastUrl, 1);
3058
+ const firstAdUrl = firstAdUrlArray[0];
3059
+ if (!firstAdUrl) {
3060
+ if (this.config.debugAdTiming) {
3061
+ console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F Failed to generate first ad URL");
3062
+ }
3063
+ this.handleAdPodComplete();
3064
+ return;
3065
+ }
3066
+ try {
3067
+ await this.ima.requestAds(firstAdUrl);
3068
+ if (this.config.debugAdTiming) {
3069
+ console.log("[CONTINUOUS-FETCH] \u2705 First ad request successful, starting playback");
3070
+ }
3071
+ this.successfulAdRequests.push(firstAdUrl);
3072
+ this.currentAdIndex++;
3073
+ this.startContinuousFetching(baseVastUrl);
3074
+ await this.ima.play();
3075
+ } catch (error) {
3076
+ if (this.config.debugAdTiming) {
3077
+ console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
3078
+ }
3079
+ this.failedVastUrls.add(firstAdUrl);
3080
+ this.startContinuousFetching(baseVastUrl);
3081
+ this.tryNextAvailableAd();
3082
+ }
3083
+ }
3084
+ startContinuousFetching(baseVastUrl) {
3085
+ if (!this.continuousFetchingActive) {
3086
+ return;
3087
+ }
3088
+ if (this.config.debugAdTiming) {
3089
+ console.log("[CONTINUOUS-FETCH] \u{1F504} Starting continuous ad fetching loop");
3090
+ }
3091
+ this.continuousFetchLoop(baseVastUrl);
3092
+ }
3093
+ async continuousFetchLoop(baseVastUrl) {
3094
+ while (this.continuousFetchingActive && this.inAdBreak) {
3095
+ const remaining = this.getRemainingAdMs();
3096
+ if (remaining <= 0) {
3097
+ if (this.config.debugAdTiming) {
3098
+ console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F Ad break time expired, stopping fetch loop");
3024
3099
  }
3025
- } else {
3026
- this.isAdaptiveMode = false;
3027
- this.targetAdBreakDurationMs = null;
3028
- this.fetchedAdDurations.clear();
3029
- if (this.apiNumberAds && this.apiNumberAds > 1) {
3030
- numberOfAds = this.apiNumberAds;
3100
+ break;
3101
+ }
3102
+ if (this.adRequestQueue.length > 0) {
3103
+ if (this.config.debugAdTiming) {
3104
+ console.log(`[CONTINUOUS-FETCH] \u23F3 Already have ${this.adRequestQueue.length} ads queued, waiting...`);
3105
+ }
3106
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3107
+ continue;
3108
+ }
3109
+ const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
3110
+ if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
3111
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3112
+ continue;
3113
+ }
3114
+ if (this.config.debugAdTiming) {
3115
+ console.log("[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch additional ad...");
3116
+ }
3117
+ try {
3118
+ const response = await fetch(newAdUrl, { mode: "cors" });
3119
+ if (!response.ok) {
3120
+ throw new Error(`Failed to fetch VAST: ${response.status}`);
3121
+ }
3122
+ const xmlText = await response.text();
3123
+ const parser = new DOMParser();
3124
+ const xmlDoc = parser.parseFromString(xmlText, "text/xml");
3125
+ const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
3126
+ if (mediaFiles.length === 0) {
3031
3127
  if (this.config.debugAdTiming) {
3032
- console.log(
3033
- `[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
3034
- );
3128
+ console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
3035
3129
  }
3130
+ this.failedVastUrls.add(newAdUrl);
3131
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3132
+ continue;
3036
3133
  }
3037
- }
3038
- if (numberOfAds > 1) {
3039
- vastTagUrls = this.generateVastUrlsWithCorrelators(
3040
- this.apiVastTagUrl,
3041
- numberOfAds
3042
- );
3043
3134
  if (this.config.debugAdTiming) {
3044
- console.log(
3045
- `[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
3046
- );
3135
+ console.log("[CONTINUOUS-FETCH] \u2705 Successfully fetched new ad, adding to queue");
3047
3136
  }
3048
- } else {
3049
- vastTagUrls = [this.apiVastTagUrl];
3137
+ this.adRequestQueue.push(newAdUrl);
3138
+ this.totalAdsInBreak++;
3139
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3140
+ } catch (error) {
3141
+ if (this.config.debugAdTiming) {
3142
+ console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
3143
+ }
3144
+ this.failedVastUrls.add(newAdUrl);
3145
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
3050
3146
  }
3051
- } else if (tags && tags.length > 0) {
3052
- vastTagUrls = tags;
3053
- } else {
3147
+ }
3148
+ if (this.config.debugAdTiming) {
3149
+ console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
3150
+ }
3151
+ }
3152
+ stopContinuousFetching() {
3153
+ this.continuousFetchingActive = false;
3154
+ if (this.config.debugAdTiming) {
3155
+ console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
3156
+ }
3157
+ }
3158
+ async tryNextAvailableAd() {
3159
+ const remaining = this.getRemainingAdMs();
3160
+ if (remaining <= 500) {
3161
+ if (this.config.debugAdTiming) {
3162
+ console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
3163
+ }
3164
+ this.handleAdPodComplete();
3054
3165
  return;
3055
3166
  }
3056
- if (vastTagUrls.length > 0) {
3057
- this.adPodAllUrls = [...vastTagUrls];
3058
- this.preloadingAdUrls.clear();
3059
- this.vastToMediaUrlMap.clear();
3060
- this.preloadedMediaUrls.clear();
3061
- this.preloadingMediaUrls.clear();
3062
- this.failedVastUrls.clear();
3063
- const currentMuted = this.video.muted;
3064
- const currentVolume = this.video.volume;
3065
- this.ima.updateOriginalMutedState(currentMuted, currentVolume);
3066
- this.inAdBreak = true;
3067
- this.currentAdIndex = 0;
3068
- this.totalAdsInBreak = vastTagUrls.length;
3069
- this.adPodQueue = [...vastTagUrls];
3070
- if (this.isAdaptiveMode) {
3167
+ if (this.adRequestQueue.length > 0) {
3168
+ const nextAdUrl = this.adRequestQueue.shift();
3169
+ if (nextAdUrl) {
3071
3170
  if (this.config.debugAdTiming) {
3072
- console.log("[ADAPTIVE-POD] \u{1F680} Preloading first 2 ads before starting playback...");
3073
- }
3074
- try {
3075
- const adsToPreloadBeforeStart = Math.min(2, this.adPodAllUrls.length);
3076
- for (let i = 0; i < adsToPreloadBeforeStart; i++) {
3077
- const url = this.adPodAllUrls[i];
3078
- if (url) {
3079
- await this.preloadSingleAd(url);
3080
- if (this.config.debugAdTiming) {
3081
- console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
3082
- }
3083
- }
3084
- }
3085
- if (this.config.debugAdTiming) {
3086
- console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
3087
- }
3088
- } catch (error) {
3089
- if (this.config.debugAdTiming) {
3090
- console.warn(
3091
- "[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
3092
- error
3093
- );
3094
- }
3171
+ console.log("[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad");
3095
3172
  }
3096
- this.preloadAllAdsInBackground().catch((error) => {
3097
- if (this.config.debugAdTiming) {
3098
- console.warn(
3099
- "[ADAPTIVE-POD] Error in background preloading:",
3100
- error
3101
- );
3102
- }
3103
- });
3104
- await this.playAdPod();
3105
- } else {
3106
- this.preloadAllAdsInBackground().catch((error) => {
3107
- if (this.config.debugAdTiming) {
3108
- console.warn(
3109
- "[StormcloudVideoPlayer] Error in background preloading:",
3110
- error
3111
- );
3112
- }
3173
+ this.currentAdIndex++;
3174
+ await this.playSingleAd(nextAdUrl).catch(() => {
3175
+ this.tryNextAvailableAd();
3113
3176
  });
3114
- await this.playAdPod();
3177
+ return;
3115
3178
  }
3116
3179
  }
3117
- if (this.expectedAdBreakDurationMs == null && (scheduled == null ? void 0 : scheduled.durationMs) != null) {
3118
- this.expectedAdBreakDurationMs = scheduled.durationMs;
3119
- this.currentAdBreakStartWallClockMs = (_a = this.currentAdBreakStartWallClockMs) != null ? _a : Date.now();
3120
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
3180
+ if (!this.isShowingPlaceholder && remaining > 1e3) {
3181
+ this.showPlaceholderAndWaitForAds();
3182
+ } else {
3183
+ if (this.config.debugAdTiming) {
3184
+ console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
3185
+ }
3186
+ this.handleAdPodComplete();
3121
3187
  }
3122
3188
  }
3123
- async playAdPod() {
3124
- if (this.adPodQueue.length === 0) {
3189
+ async showPlaceholderAndWaitForAds() {
3190
+ const remaining = this.getRemainingAdMs();
3191
+ const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
3192
+ if (waitTime < 1e3) {
3193
+ this.handleAdPodComplete();
3125
3194
  return;
3126
3195
  }
3127
- const waitTime = this.isAdaptiveMode ? 50 : 500;
3128
- await new Promise((resolve) => setTimeout(resolve, waitTime));
3129
- const firstPreloaded = this.findNextPreloadedAd();
3130
- if (!firstPreloaded) {
3131
- const firstAd = this.adPodQueue.shift();
3132
- if (firstAd) {
3133
- this.currentAdIndex++;
3134
- try {
3135
- await this.playSingleAd(firstAd);
3136
- } catch (error) {
3137
- return;
3196
+ if (this.config.debugAdTiming) {
3197
+ console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
3198
+ }
3199
+ this.isShowingPlaceholder = true;
3200
+ this.placeholderStartTimeMs = Date.now();
3201
+ this.ima.showPlaceholder();
3202
+ const checkInterval = 500;
3203
+ const maxChecks = Math.floor(waitTime / checkInterval);
3204
+ for (let i = 0; i < maxChecks; i++) {
3205
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
3206
+ if (!this.inAdBreak) {
3207
+ return;
3208
+ }
3209
+ if (this.adRequestQueue.length > 0) {
3210
+ if (this.config.debugAdTiming) {
3211
+ console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
3212
+ }
3213
+ this.isShowingPlaceholder = false;
3214
+ this.placeholderStartTimeMs = null;
3215
+ this.ima.hidePlaceholder();
3216
+ const nextAdUrl = this.adRequestQueue.shift();
3217
+ if (nextAdUrl) {
3218
+ this.currentAdIndex++;
3219
+ await this.playSingleAd(nextAdUrl).catch(() => {
3220
+ this.tryNextAvailableAd();
3221
+ });
3138
3222
  }
3223
+ return;
3139
3224
  }
3140
- return;
3141
3225
  }
3142
- this.currentAdIndex++;
3143
- try {
3144
- await this.playSingleAd(firstPreloaded);
3145
- } catch (error) {
3226
+ if (this.config.debugAdTiming) {
3227
+ console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
3146
3228
  }
3229
+ this.isShowingPlaceholder = false;
3230
+ this.placeholderStartTimeMs = null;
3231
+ this.ima.hidePlaceholder();
3232
+ this.handleAdPodComplete();
3147
3233
  }
3148
3234
  findCurrentOrNextBreak(nowMs) {
3149
3235
  var _a;
@@ -3303,10 +3389,18 @@ var StormcloudVideoPlayer = class {
3303
3389
  this.clearAdRequestWatchdog();
3304
3390
  this.clearAdFailsafeTimer();
3305
3391
  this.activeAdRequestToken = null;
3392
+ this.stopContinuousFetching();
3393
+ if (this.isShowingPlaceholder) {
3394
+ this.ima.hidePlaceholder();
3395
+ this.isShowingPlaceholder = false;
3396
+ this.placeholderStartTimeMs = null;
3397
+ }
3306
3398
  this.preloadingAdUrls.clear();
3307
3399
  this.vastToMediaUrlMap.clear();
3308
3400
  this.preloadedMediaUrls.clear();
3309
3401
  this.preloadingMediaUrls.clear();
3402
+ this.adRequestQueue = [];
3403
+ this.successfulAdRequests = [];
3310
3404
  this.inAdBreak = false;
3311
3405
  this.expectedAdBreakDurationMs = void 0;
3312
3406
  this.currentAdBreakStartWallClockMs = void 0;
@@ -3333,61 +3427,14 @@ var StormcloudVideoPlayer = class {
3333
3427
  }
3334
3428
  }
3335
3429
  handleAdFailure() {
3336
- const remaining = this.getRemainingAdMs();
3337
- const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
3338
- if (remaining > 500 && availableAds > 0) {
3339
- if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
3340
- console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
3341
- setTimeout(() => {
3342
- this.tryNextAdWithRetry(0);
3343
- }, 1500);
3344
- return;
3345
- }
3346
- const nextPreloaded = this.findNextPreloadedAd();
3347
- if (nextPreloaded) {
3348
- this.currentAdIndex++;
3349
- this.playSingleAd(nextPreloaded).catch(() => {
3350
- this.handleAdPodComplete();
3351
- });
3352
- return;
3353
- }
3354
- }
3355
- console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
3356
- this.handleAdPodComplete();
3357
- }
3358
- tryNextAdWithRetry(retryCount) {
3359
- const maxRetries = 3;
3360
3430
  const remaining = this.getRemainingAdMs();
3361
3431
  if (this.config.debugAdTiming) {
3362
- console.log(
3363
- `[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
3364
- );
3365
- }
3366
- if (remaining <= 500 || this.adPodQueue.length === 0) {
3367
- console.log("[ADAPTIVE-POD] \u23F9\uFE0F No more time or ads available");
3368
- this.handleAdPodComplete();
3369
- return;
3432
+ console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
3370
3433
  }
3371
- const nextPreloaded = this.findNextPreloadedAd();
3372
- if (nextPreloaded) {
3373
- this.currentAdIndex++;
3374
- console.log(
3375
- `[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
3376
- );
3377
- this.playSingleAd(nextPreloaded).catch(() => {
3378
- this.handleAdPodComplete();
3379
- });
3380
- } else if (retryCount < maxRetries) {
3381
- console.log(
3382
- `[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
3383
- );
3384
- setTimeout(() => {
3385
- this.tryNextAdWithRetry(retryCount + 1);
3386
- }, 1e3);
3434
+ if (remaining > 500) {
3435
+ this.tryNextAvailableAd();
3387
3436
  } else {
3388
- console.log(
3389
- `[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
3390
- );
3437
+ console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
3391
3438
  this.handleAdPodComplete();
3392
3439
  }
3393
3440
  }
@@ -3985,6 +4032,7 @@ var StormcloudVideoPlayer = class {
3985
4032
  }
3986
4033
  destroy() {
3987
4034
  var _a, _b;
4035
+ this.stopContinuousFetching();
3988
4036
  this.clearAdStartTimer();
3989
4037
  this.clearAdStopTimer();
3990
4038
  this.clearAdFailsafeTimer();
@@ -3999,6 +4047,8 @@ var StormcloudVideoPlayer = class {
3999
4047
  this.preloadedMediaUrls.clear();
4000
4048
  this.preloadingMediaUrls.clear();
4001
4049
  this.adPodAllUrls = [];
4050
+ this.adRequestQueue = [];
4051
+ this.successfulAdRequests = [];
4002
4052
  }
4003
4053
  };
4004
4054