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/lib/index.cjs CHANGED
@@ -408,12 +408,8 @@ function createImaController(video, options) {
408
408
  let adsLoadedReject;
409
409
  function makeAdsRequest(google, vastTagUrl) {
410
410
  const adsRequest = new google.ima.AdsRequest();
411
- const preloadedResponse = preloadedVast.get(vastTagUrl);
412
- if (preloadedResponse) {
413
- adsRequest.adsResponse = preloadedResponse;
414
- } else {
415
- adsRequest.adTagUrl = vastTagUrl;
416
- }
411
+ console.log("[IMA] \u{1F4E1} Requesting VAST from URL (letting IMA fetch fresh)");
412
+ adsRequest.adTagUrl = vastTagUrl;
417
413
  const videoWidth = video.offsetWidth || video.clientWidth || 640;
418
414
  const videoHeight = video.offsetHeight || video.clientHeight || 360;
419
415
  adsRequest.linearAdSlotWidth = videoWidth;
@@ -436,11 +432,8 @@ function createImaController(video, options) {
436
432
  console.warn("[IMA] Failed to call setAdWillPlayMuted:", error);
437
433
  }
438
434
  }
439
- adsRequest.vastLoadTimeout = 5e3;
435
+ adsRequest.vastLoadTimeout = 1e4;
440
436
  adsLoader.requestAds(adsRequest);
441
- if (preloadedResponse) {
442
- preloadedVast.delete(vastTagUrl);
443
- }
444
437
  }
445
438
  function ensurePlaceholderContainer() {
446
439
  var _a;
@@ -2156,6 +2149,12 @@ var StormcloudVideoPlayer = class {
2156
2149
  this.targetAdBreakDurationMs = null;
2157
2150
  this.isAdaptiveMode = false;
2158
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;
2159
2158
  initializePolyfills();
2160
2159
  const browserOverrides = getBrowserConfigOverrides();
2161
2160
  this.config = { ...config, ...browserOverrides };
@@ -2462,16 +2461,11 @@ var StormcloudVideoPlayer = class {
2462
2461
  return;
2463
2462
  }
2464
2463
  const remaining = this.getRemainingAdMs();
2465
- if (remaining > 500 && this.adPodQueue.length > 0) {
2466
- const nextPreloaded = this.findNextPreloadedAd();
2467
- if (nextPreloaded) {
2468
- this.currentAdIndex++;
2469
- this.playSingleAd(nextPreloaded).catch(() => {
2470
- this.handleAdPodComplete();
2471
- });
2472
- } else {
2473
- this.handleAdPodComplete();
2474
- }
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();
2475
2469
  } else {
2476
2470
  this.handleAdPodComplete();
2477
2471
  }
@@ -3071,155 +3065,240 @@ var StormcloudVideoPlayer = class {
3071
3065
  return true;
3072
3066
  }
3073
3067
  async handleAdStart(_marker) {
3074
- var _a;
3075
3068
  const scheduled = this.findCurrentOrNextBreak(
3076
3069
  this.video.currentTime * 1e3
3077
3070
  );
3078
3071
  const tags = this.selectVastTagsForBreak(scheduled);
3079
- let vastTagUrls = [];
3072
+ let baseVastUrl;
3080
3073
  if (this.apiVastTagUrl) {
3081
- let numberOfAds = 1;
3082
- if (this.isLiveStream) {
3083
- const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
3084
- if (adBreakDurationMs != null && adBreakDurationMs > 0) {
3085
- this.isAdaptiveMode = true;
3086
- this.targetAdBreakDurationMs = adBreakDurationMs;
3087
- this.fetchedAdDurations.clear();
3088
- numberOfAds = 2;
3089
- if (this.config.debugAdTiming) {
3090
- console.log(
3091
- `[ADAPTIVE-POD] \u{1F4FA} LIVE MODE (ADAPTIVE): Target duration=${adBreakDurationMs}ms | Starting with ${numberOfAds} ads, will fetch actual durations and add more dynamically`
3092
- );
3093
- }
3094
- } else {
3095
- if (this.config.debugAdTiming) {
3096
- console.warn(
3097
- "[DEBUG-POD] \u26A0\uFE0F LIVE MODE: No duration available, defaulting to 1 ad"
3098
- );
3099
- }
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");
3100
3168
  }
3101
- } else {
3102
- this.isAdaptiveMode = false;
3103
- this.targetAdBreakDurationMs = null;
3104
- this.fetchedAdDurations.clear();
3105
- if (this.apiNumberAds && this.apiNumberAds > 1) {
3106
- numberOfAds = this.apiNumberAds;
3169
+ break;
3170
+ }
3171
+ if (this.adRequestQueue.length > 0) {
3172
+ if (this.config.debugAdTiming) {
3173
+ console.log(`[CONTINUOUS-FETCH] \u23F3 Already have ${this.adRequestQueue.length} ads queued, waiting...`);
3174
+ }
3175
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3176
+ continue;
3177
+ }
3178
+ const newAdUrl = this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
3179
+ if (!newAdUrl || this.failedVastUrls.has(newAdUrl)) {
3180
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3181
+ continue;
3182
+ }
3183
+ if (this.config.debugAdTiming) {
3184
+ console.log("[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch additional ad...");
3185
+ }
3186
+ try {
3187
+ const response = await fetch(newAdUrl, { mode: "cors" });
3188
+ if (!response.ok) {
3189
+ throw new Error(`Failed to fetch VAST: ${response.status}`);
3190
+ }
3191
+ const xmlText = await response.text();
3192
+ const parser = new DOMParser();
3193
+ const xmlDoc = parser.parseFromString(xmlText, "text/xml");
3194
+ const mediaFiles = xmlDoc.querySelectorAll("MediaFile");
3195
+ if (mediaFiles.length === 0) {
3107
3196
  if (this.config.debugAdTiming) {
3108
- console.log(
3109
- `[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
3110
- );
3197
+ console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
3111
3198
  }
3199
+ this.failedVastUrls.add(newAdUrl);
3200
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3201
+ continue;
3112
3202
  }
3113
- }
3114
- if (numberOfAds > 1) {
3115
- vastTagUrls = this.generateVastUrlsWithCorrelators(
3116
- this.apiVastTagUrl,
3117
- numberOfAds
3118
- );
3119
3203
  if (this.config.debugAdTiming) {
3120
- console.log(
3121
- `[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
3122
- );
3204
+ console.log("[CONTINUOUS-FETCH] \u2705 Successfully fetched new ad, adding to queue");
3123
3205
  }
3124
- } else {
3125
- vastTagUrls = [this.apiVastTagUrl];
3206
+ this.adRequestQueue.push(newAdUrl);
3207
+ this.totalAdsInBreak++;
3208
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3209
+ } catch (error) {
3210
+ if (this.config.debugAdTiming) {
3211
+ console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
3212
+ }
3213
+ this.failedVastUrls.add(newAdUrl);
3214
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
3126
3215
  }
3127
- } else if (tags && tags.length > 0) {
3128
- vastTagUrls = tags;
3129
- } else {
3216
+ }
3217
+ if (this.config.debugAdTiming) {
3218
+ console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
3219
+ }
3220
+ }
3221
+ stopContinuousFetching() {
3222
+ this.continuousFetchingActive = false;
3223
+ if (this.config.debugAdTiming) {
3224
+ console.log("[CONTINUOUS-FETCH] \u{1F6D1} Stopping continuous ad fetching");
3225
+ }
3226
+ }
3227
+ async tryNextAvailableAd() {
3228
+ const remaining = this.getRemainingAdMs();
3229
+ if (remaining <= 500) {
3230
+ if (this.config.debugAdTiming) {
3231
+ console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No time remaining, ending ad break");
3232
+ }
3233
+ this.handleAdPodComplete();
3130
3234
  return;
3131
3235
  }
3132
- if (vastTagUrls.length > 0) {
3133
- this.adPodAllUrls = [...vastTagUrls];
3134
- this.preloadingAdUrls.clear();
3135
- this.vastToMediaUrlMap.clear();
3136
- this.preloadedMediaUrls.clear();
3137
- this.preloadingMediaUrls.clear();
3138
- this.failedVastUrls.clear();
3139
- const currentMuted = this.video.muted;
3140
- const currentVolume = this.video.volume;
3141
- this.ima.updateOriginalMutedState(currentMuted, currentVolume);
3142
- this.inAdBreak = true;
3143
- this.currentAdIndex = 0;
3144
- this.totalAdsInBreak = vastTagUrls.length;
3145
- this.adPodQueue = [...vastTagUrls];
3146
- if (this.isAdaptiveMode) {
3236
+ if (this.adRequestQueue.length > 0) {
3237
+ const nextAdUrl = this.adRequestQueue.shift();
3238
+ if (nextAdUrl) {
3147
3239
  if (this.config.debugAdTiming) {
3148
- console.log("[ADAPTIVE-POD] \u{1F680} Preloading first 2 ads before starting playback...");
3240
+ console.log("[CONTINUOUS-FETCH] \u{1F3AC} Playing next queued ad");
3149
3241
  }
3150
- try {
3151
- const adsToPreloadBeforeStart = Math.min(2, this.adPodAllUrls.length);
3152
- for (let i = 0; i < adsToPreloadBeforeStart; i++) {
3153
- const url = this.adPodAllUrls[i];
3154
- if (url) {
3155
- await this.preloadSingleAd(url);
3156
- if (this.config.debugAdTiming) {
3157
- console.log(`[ADAPTIVE-POD] \u2705 Preloaded ad ${i + 1}/${adsToPreloadBeforeStart}`);
3158
- }
3159
- }
3160
- }
3161
- if (this.config.debugAdTiming) {
3162
- console.log("[ADAPTIVE-POD] \u{1F3AC} First ads preloaded, starting playback immediately");
3163
- }
3164
- } catch (error) {
3165
- if (this.config.debugAdTiming) {
3166
- console.warn(
3167
- "[ADAPTIVE-POD] \u26A0\uFE0F Error preloading initial ads:",
3168
- error
3169
- );
3170
- }
3171
- }
3172
- this.preloadAllAdsInBackground().catch((error) => {
3173
- if (this.config.debugAdTiming) {
3174
- console.warn(
3175
- "[ADAPTIVE-POD] Error in background preloading:",
3176
- error
3177
- );
3178
- }
3179
- });
3180
- await this.playAdPod();
3181
- } else {
3182
- this.preloadAllAdsInBackground().catch((error) => {
3183
- if (this.config.debugAdTiming) {
3184
- console.warn(
3185
- "[StormcloudVideoPlayer] Error in background preloading:",
3186
- error
3187
- );
3188
- }
3242
+ this.currentAdIndex++;
3243
+ await this.playSingleAd(nextAdUrl).catch(() => {
3244
+ this.tryNextAvailableAd();
3189
3245
  });
3190
- await this.playAdPod();
3246
+ return;
3191
3247
  }
3192
3248
  }
3193
- if (this.expectedAdBreakDurationMs == null && (scheduled == null ? void 0 : scheduled.durationMs) != null) {
3194
- this.expectedAdBreakDurationMs = scheduled.durationMs;
3195
- this.currentAdBreakStartWallClockMs = (_a = this.currentAdBreakStartWallClockMs) != null ? _a : Date.now();
3196
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
3249
+ if (!this.isShowingPlaceholder && remaining > 1e3) {
3250
+ this.showPlaceholderAndWaitForAds();
3251
+ } else {
3252
+ if (this.config.debugAdTiming) {
3253
+ console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
3254
+ }
3255
+ this.handleAdPodComplete();
3197
3256
  }
3198
3257
  }
3199
- async playAdPod() {
3200
- if (this.adPodQueue.length === 0) {
3258
+ async showPlaceholderAndWaitForAds() {
3259
+ const remaining = this.getRemainingAdMs();
3260
+ const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
3261
+ if (waitTime < 1e3) {
3262
+ this.handleAdPodComplete();
3201
3263
  return;
3202
3264
  }
3203
- const waitTime = this.isAdaptiveMode ? 50 : 500;
3204
- await new Promise((resolve) => setTimeout(resolve, waitTime));
3205
- const firstPreloaded = this.findNextPreloadedAd();
3206
- if (!firstPreloaded) {
3207
- const firstAd = this.adPodQueue.shift();
3208
- if (firstAd) {
3209
- this.currentAdIndex++;
3210
- try {
3211
- await this.playSingleAd(firstAd);
3212
- } catch (error) {
3213
- return;
3265
+ if (this.config.debugAdTiming) {
3266
+ console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
3267
+ }
3268
+ this.isShowingPlaceholder = true;
3269
+ this.placeholderStartTimeMs = Date.now();
3270
+ this.ima.showPlaceholder();
3271
+ const checkInterval = 500;
3272
+ const maxChecks = Math.floor(waitTime / checkInterval);
3273
+ for (let i = 0; i < maxChecks; i++) {
3274
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
3275
+ if (!this.inAdBreak) {
3276
+ return;
3277
+ }
3278
+ if (this.adRequestQueue.length > 0) {
3279
+ if (this.config.debugAdTiming) {
3280
+ console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
3281
+ }
3282
+ this.isShowingPlaceholder = false;
3283
+ this.placeholderStartTimeMs = null;
3284
+ this.ima.hidePlaceholder();
3285
+ const nextAdUrl = this.adRequestQueue.shift();
3286
+ if (nextAdUrl) {
3287
+ this.currentAdIndex++;
3288
+ await this.playSingleAd(nextAdUrl).catch(() => {
3289
+ this.tryNextAvailableAd();
3290
+ });
3214
3291
  }
3292
+ return;
3215
3293
  }
3216
- return;
3217
3294
  }
3218
- this.currentAdIndex++;
3219
- try {
3220
- await this.playSingleAd(firstPreloaded);
3221
- } catch (error) {
3295
+ if (this.config.debugAdTiming) {
3296
+ console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
3222
3297
  }
3298
+ this.isShowingPlaceholder = false;
3299
+ this.placeholderStartTimeMs = null;
3300
+ this.ima.hidePlaceholder();
3301
+ this.handleAdPodComplete();
3223
3302
  }
3224
3303
  findCurrentOrNextBreak(nowMs) {
3225
3304
  var _a;
@@ -3379,10 +3458,18 @@ var StormcloudVideoPlayer = class {
3379
3458
  this.clearAdRequestWatchdog();
3380
3459
  this.clearAdFailsafeTimer();
3381
3460
  this.activeAdRequestToken = null;
3461
+ this.stopContinuousFetching();
3462
+ if (this.isShowingPlaceholder) {
3463
+ this.ima.hidePlaceholder();
3464
+ this.isShowingPlaceholder = false;
3465
+ this.placeholderStartTimeMs = null;
3466
+ }
3382
3467
  this.preloadingAdUrls.clear();
3383
3468
  this.vastToMediaUrlMap.clear();
3384
3469
  this.preloadedMediaUrls.clear();
3385
3470
  this.preloadingMediaUrls.clear();
3471
+ this.adRequestQueue = [];
3472
+ this.successfulAdRequests = [];
3386
3473
  this.inAdBreak = false;
3387
3474
  this.expectedAdBreakDurationMs = void 0;
3388
3475
  this.currentAdBreakStartWallClockMs = void 0;
@@ -3409,61 +3496,14 @@ var StormcloudVideoPlayer = class {
3409
3496
  }
3410
3497
  }
3411
3498
  handleAdFailure() {
3412
- const remaining = this.getRemainingAdMs();
3413
- const availableAds = this.adPodQueue.filter((url) => !this.failedVastUrls.has(url)).length;
3414
- if (remaining > 500 && availableAds > 0) {
3415
- if (this.isAdaptiveMode && this.currentAdIndex <= 1) {
3416
- console.log("[ADAPTIVE-POD] \u23F3 First ad failed, waiting for sequential preload to catch up...");
3417
- setTimeout(() => {
3418
- this.tryNextAdWithRetry(0);
3419
- }, 1500);
3420
- return;
3421
- }
3422
- const nextPreloaded = this.findNextPreloadedAd();
3423
- if (nextPreloaded) {
3424
- this.currentAdIndex++;
3425
- this.playSingleAd(nextPreloaded).catch(() => {
3426
- this.handleAdPodComplete();
3427
- });
3428
- return;
3429
- }
3430
- }
3431
- console.error("[AD-ERROR] All ads failed or time expired. Failed URLs:", this.failedVastUrls.size);
3432
- this.handleAdPodComplete();
3433
- }
3434
- tryNextAdWithRetry(retryCount) {
3435
- const maxRetries = 3;
3436
3499
  const remaining = this.getRemainingAdMs();
3437
3500
  if (this.config.debugAdTiming) {
3438
- console.log(
3439
- `[ADAPTIVE-POD] \u{1F50D} Retry attempt ${retryCount}: remaining=${remaining}ms, queue=${this.adPodQueue.length}, totalAds=${this.totalAdsInBreak}`
3440
- );
3501
+ console.log(`[CONTINUOUS-FETCH] Ad failure: remaining=${remaining}ms, queued ads=${this.adRequestQueue.length}`);
3441
3502
  }
3442
- if (remaining <= 500 || this.adPodQueue.length === 0) {
3443
- console.log("[ADAPTIVE-POD] \u23F9\uFE0F No more time or ads available");
3444
- this.handleAdPodComplete();
3445
- return;
3446
- }
3447
- const nextPreloaded = this.findNextPreloadedAd();
3448
- if (nextPreloaded) {
3449
- this.currentAdIndex++;
3450
- console.log(
3451
- `[ADAPTIVE-POD] \u2705 Found preloaded ad after retry ${retryCount}, playing (${this.currentAdIndex}/${this.totalAdsInBreak})`
3452
- );
3453
- this.playSingleAd(nextPreloaded).catch(() => {
3454
- this.handleAdPodComplete();
3455
- });
3456
- } else if (retryCount < maxRetries) {
3457
- console.log(
3458
- `[ADAPTIVE-POD] \u23F3 No preloaded ads yet (queue has ${this.adPodQueue.length} URLs), retry ${retryCount + 1}/${maxRetries} in 1s...`
3459
- );
3460
- setTimeout(() => {
3461
- this.tryNextAdWithRetry(retryCount + 1);
3462
- }, 1e3);
3503
+ if (remaining > 500) {
3504
+ this.tryNextAvailableAd();
3463
3505
  } else {
3464
- console.log(
3465
- `[ADAPTIVE-POD] \u274C Max retries reached, no preloaded ads available (queue=${this.adPodQueue.length} URLs)`
3466
- );
3506
+ console.error("[AD-ERROR] Ad failed and no time remaining. Failed URLs:", this.failedVastUrls.size);
3467
3507
  this.handleAdPodComplete();
3468
3508
  }
3469
3509
  }
@@ -3860,6 +3900,12 @@ var StormcloudVideoPlayer = class {
3860
3900
  );
3861
3901
  }
3862
3902
  mediaUrls = await this.fetchAndParseVastXml(vastTagUrl);
3903
+ if (this.config.debugAdTiming) {
3904
+ console.log(
3905
+ `[StormcloudVideoPlayer] Extracted ${mediaUrls.length} media URLs:`,
3906
+ mediaUrls
3907
+ );
3908
+ }
3863
3909
  if (mediaUrls.length > 0) {
3864
3910
  this.vastToMediaUrlMap.set(vastTagUrl, mediaUrls);
3865
3911
  }
@@ -4055,6 +4101,7 @@ var StormcloudVideoPlayer = class {
4055
4101
  }
4056
4102
  destroy() {
4057
4103
  var _a, _b;
4104
+ this.stopContinuousFetching();
4058
4105
  this.clearAdStartTimer();
4059
4106
  this.clearAdStopTimer();
4060
4107
  this.clearAdFailsafeTimer();
@@ -4069,6 +4116,8 @@ var StormcloudVideoPlayer = class {
4069
4116
  this.preloadedMediaUrls.clear();
4070
4117
  this.preloadingMediaUrls.clear();
4071
4118
  this.adPodAllUrls = [];
4119
+ this.adRequestQueue = [];
4120
+ this.successfulAdRequests = [];
4072
4121
  }
4073
4122
  };
4074
4123