stormcloud-video-player 0.3.13 → 0.3.14

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.
@@ -922,6 +922,8 @@ function createHlsAdPlayer(contentVideo, options) {
922
922
  let sessionId;
923
923
  const preloadedAds = /* @__PURE__ */ new Map();
924
924
  const preloadingAds = /* @__PURE__ */ new Map();
925
+ let destroyed = false;
926
+ let pendingTimeouts = [];
925
927
  let trackingFired = {
926
928
  impression: false,
927
929
  start: false,
@@ -1250,13 +1252,27 @@ function createHlsAdPlayer(contentVideo, options) {
1250
1252
  adPlaying = false;
1251
1253
  setAdPlayingFlag(false);
1252
1254
  emit("content_resume");
1253
- setTimeout(() => {
1254
- if (!adPlaying && adContainerEl) {
1255
- adContainerEl.style.display = "none";
1256
- adContainerEl.style.pointerEvents = "none";
1257
- console.log("[HlsAdPlayer] Ad container hidden after completion (waiting for next ad)");
1255
+ const timeoutId = window.setTimeout(() => {
1256
+ if (destroyed) {
1257
+ console.log("[HlsAdPlayer] Player destroyed, skipping post-completion check");
1258
+ return;
1259
+ }
1260
+ const stillInPod = contentVideo.dataset.stormcloudAdPlaying === "true";
1261
+ if (stillInPod) {
1262
+ console.log(
1263
+ "[HlsAdPlayer] Still in ad pod - keeping ad container visible (black screen)"
1264
+ );
1265
+ if (adContainerEl) {
1266
+ adContainerEl.style.display = "flex";
1267
+ adContainerEl.style.pointerEvents = "auto";
1268
+ }
1269
+ }
1270
+ const idx = pendingTimeouts.indexOf(timeoutId);
1271
+ if (idx !== -1) {
1272
+ pendingTimeouts.splice(idx, 1);
1258
1273
  }
1259
1274
  }, 50);
1275
+ pendingTimeouts.push(timeoutId);
1260
1276
  }
1261
1277
  function handleAdError() {
1262
1278
  console.log("[HlsAdPlayer] Handling ad error");
@@ -1486,6 +1502,11 @@ function createHlsAdPlayer(contentVideo, options) {
1486
1502
  },
1487
1503
  destroy() {
1488
1504
  console.log("[HlsAdPlayer] Destroying");
1505
+ destroyed = true;
1506
+ for (const timeoutId of pendingTimeouts) {
1507
+ clearTimeout(timeoutId);
1508
+ }
1509
+ pendingTimeouts = [];
1489
1510
  adPlaying = false;
1490
1511
  setAdPlayingFlag(false);
1491
1512
  contentVideo.muted = originalMutedState;
@@ -2398,10 +2419,11 @@ var StormcloudVideoPlayer = class {
2398
2419
  this.handleAdPodComplete();
2399
2420
  }
2400
2421
  });
2401
- this.video.addEventListener("timeupdate", () => {
2422
+ this.timeUpdateHandler = () => {
2402
2423
  this.onTimeUpdate(this.video.currentTime);
2403
- });
2404
- this.video.addEventListener("emptied", () => {
2424
+ };
2425
+ this.video.addEventListener("timeupdate", this.timeUpdateHandler);
2426
+ this.emptiedHandler = () => {
2405
2427
  if (this.nativeHlsMode && this.videoSrcProtection && !this.ima.isAdPlaying()) {
2406
2428
  if (this.config.debugAdTiming) {
2407
2429
  console.log(
@@ -2418,7 +2440,8 @@ var StormcloudVideoPlayer = class {
2418
2440
  });
2419
2441
  }
2420
2442
  }
2421
- });
2443
+ };
2444
+ this.video.addEventListener("emptied", this.emptiedHandler);
2422
2445
  }
2423
2446
  shouldUseNativeHls() {
2424
2447
  const streamType = this.getStreamType();
@@ -3110,7 +3133,7 @@ var StormcloudVideoPlayer = class {
3110
3133
  continue;
3111
3134
  }
3112
3135
  if (this.config.debugAdTiming) {
3113
- console.log(`[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch ad #${this.successfulAdRequests.length + this.adRequestQueue.length + 1} (queue: ${this.adRequestQueue.length}, remaining: ${Math.round(remaining / 1e3)}s)...`);
3136
+ console.log(`[CONTINUOUS-FETCH] \u{1F4E1} Attempting to fetch ad (${this.successfulAdRequests.length + this.adRequestQueue.length + 1} total)...`);
3114
3137
  }
3115
3138
  try {
3116
3139
  const response = await fetch(newAdUrl, { mode: "cors" });
@@ -3126,8 +3149,7 @@ var StormcloudVideoPlayer = class {
3126
3149
  console.log("[CONTINUOUS-FETCH] \u26A0\uFE0F VAST response has no media files, skipping");
3127
3150
  }
3128
3151
  this.failedVastUrls.add(newAdUrl);
3129
- const retryDelay = this.adRequestQueue.length > 0 ? 1e3 : 500;
3130
- await new Promise((resolve) => setTimeout(resolve, retryDelay));
3152
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3131
3153
  continue;
3132
3154
  }
3133
3155
  if (this.config.debugAdTiming) {
@@ -3135,19 +3157,17 @@ var StormcloudVideoPlayer = class {
3135
3157
  }
3136
3158
  this.adRequestQueue.push(newAdUrl);
3137
3159
  this.totalAdsInBreak++;
3138
- const successDelay = this.adRequestQueue.length <= 1 ? 300 : 500;
3139
- await new Promise((resolve) => setTimeout(resolve, successDelay));
3160
+ await new Promise((resolve) => setTimeout(resolve, 500));
3140
3161
  } catch (error) {
3141
3162
  if (this.config.debugAdTiming) {
3142
3163
  console.log("[CONTINUOUS-FETCH] \u274C Ad fetch failed:", error.message);
3143
3164
  }
3144
3165
  this.failedVastUrls.add(newAdUrl);
3145
- const retryDelay = this.adRequestQueue.length > 0 ? 2e3 : 1e3;
3146
- await new Promise((resolve) => setTimeout(resolve, retryDelay));
3166
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3147
3167
  }
3148
3168
  }
3149
3169
  if (this.config.debugAdTiming) {
3150
- console.log(`[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended (fetched ${this.successfulAdRequests.length} ads, ${this.adRequestQueue.length} in queue)`);
3170
+ console.log("[CONTINUOUS-FETCH] \u{1F6D1} Continuous fetch loop ended");
3151
3171
  }
3152
3172
  }
3153
3173
  stopContinuousFetching() {
@@ -3185,27 +3205,20 @@ var StormcloudVideoPlayer = class {
3185
3205
  return;
3186
3206
  }
3187
3207
  }
3188
- const hasPlayedAtLeastOneAd = this.successfulAdRequests.length > 0;
3189
- const maxRetries = hasPlayedAtLeastOneAd ? 10 : 5;
3190
- const retryDelayMs = hasPlayedAtLeastOneAd ? 500 : 1e3;
3191
- const minRemainingForRetry = 1e3;
3192
- if (this.continuousFetchingActive && retryCount < maxRetries && remaining > minRemainingForRetry) {
3208
+ const maxRetries = 5;
3209
+ if (this.continuousFetchingActive && retryCount < maxRetries && remaining > 2e3) {
3193
3210
  if (this.config.debugAdTiming) {
3194
- console.log(`[CONTINUOUS-FETCH] \u23F3 Queue empty but fetching active, waiting ${retryDelayMs}ms... (retry ${retryCount + 1}/${maxRetries}, remaining: ${remaining}ms)`);
3211
+ console.log(`[CONTINUOUS-FETCH] \u23F3 Queue empty but fetching active, waiting... (retry ${retryCount + 1}/${maxRetries})`);
3195
3212
  }
3196
- await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
3213
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3197
3214
  await this.tryNextAvailableAd(retryCount + 1);
3198
3215
  return;
3199
3216
  }
3200
- const minTimeForPlaceholder = 3e3;
3201
- if (!this.isShowingPlaceholder && remaining >= minTimeForPlaceholder && this.continuousFetchingActive) {
3202
- if (this.config.debugAdTiming) {
3203
- console.log(`[CONTINUOUS-FETCH] \u2B1B Last resort: showing placeholder (${remaining}ms remaining)`);
3204
- }
3217
+ if (!this.isShowingPlaceholder && remaining > 1e3) {
3205
3218
  this.showPlaceholderAndWaitForAds();
3206
3219
  } else {
3207
3220
  if (this.config.debugAdTiming) {
3208
- console.log(`[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available or insufficient time remaining (${remaining}ms), ending ad break`);
3221
+ console.log("[CONTINUOUS-FETCH] \u23F9\uFE0F No more ads available, ending ad break");
3209
3222
  }
3210
3223
  this.handleAdPodComplete();
3211
3224
  }
@@ -3213,36 +3226,26 @@ var StormcloudVideoPlayer = class {
3213
3226
  async showPlaceholderAndWaitForAds() {
3214
3227
  const remaining = this.getRemainingAdMs();
3215
3228
  const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
3216
- if (waitTime < 3e3) {
3217
- if (this.config.debugAdTiming) {
3218
- console.log(`[CONTINUOUS-FETCH] \u23F9\uFE0F Insufficient time for placeholder (${waitTime}ms), ending ad break`);
3219
- }
3229
+ if (waitTime < 1e3) {
3220
3230
  this.handleAdPodComplete();
3221
3231
  return;
3222
3232
  }
3223
3233
  if (this.config.debugAdTiming) {
3224
- console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for up to ${waitTime}ms while waiting for ads (last resort)`);
3234
+ console.log(`[CONTINUOUS-FETCH] \u2B1B Showing black placeholder for ${waitTime}ms while waiting for ads`);
3225
3235
  }
3226
3236
  this.isShowingPlaceholder = true;
3227
3237
  this.placeholderStartTimeMs = Date.now();
3228
3238
  this.ima.showPlaceholder();
3229
- const checkInterval = 300;
3239
+ const checkInterval = 500;
3230
3240
  const maxChecks = Math.floor(waitTime / checkInterval);
3231
3241
  for (let i = 0; i < maxChecks; i++) {
3232
3242
  await new Promise((resolve) => setTimeout(resolve, checkInterval));
3233
3243
  if (!this.inAdBreak) {
3234
- if (this.config.debugAdTiming) {
3235
- console.log("[CONTINUOUS-FETCH] \u2139\uFE0F Ad break ended during placeholder wait");
3236
- }
3237
- this.isShowingPlaceholder = false;
3238
- this.placeholderStartTimeMs = null;
3239
- this.ima.hidePlaceholder();
3240
3244
  return;
3241
3245
  }
3242
3246
  if (this.adRequestQueue.length > 0) {
3243
- const elapsedInPlaceholder = Date.now() - (this.placeholderStartTimeMs || Date.now());
3244
3247
  if (this.config.debugAdTiming) {
3245
- console.log(`[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder (after ${elapsedInPlaceholder}ms)`);
3248
+ console.log("[CONTINUOUS-FETCH] \u2705 New ad became available during placeholder");
3246
3249
  }
3247
3250
  this.isShowingPlaceholder = false;
3248
3251
  this.placeholderStartTimeMs = null;
@@ -3261,9 +3264,8 @@ var StormcloudVideoPlayer = class {
3261
3264
  return;
3262
3265
  }
3263
3266
  }
3264
- const totalPlaceholderTime = Date.now() - (this.placeholderStartTimeMs || Date.now());
3265
3267
  if (this.config.debugAdTiming) {
3266
- console.log(`[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached after ${totalPlaceholderTime}ms, no ads fetched`);
3268
+ console.log("[CONTINUOUS-FETCH] \u23F0 Placeholder timeout reached, no ads fetched");
3267
3269
  }
3268
3270
  this.isShowingPlaceholder = false;
3269
3271
  this.placeholderStartTimeMs = null;
@@ -4075,6 +4077,15 @@ var StormcloudVideoPlayer = class {
4075
4077
  this.clearAdStartTimer();
4076
4078
  this.clearAdStopTimer();
4077
4079
  this.clearAdFailsafeTimer();
4080
+ this.clearAdRequestWatchdog();
4081
+ if (this.timeUpdateHandler) {
4082
+ this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
4083
+ delete this.timeUpdateHandler;
4084
+ }
4085
+ if (this.emptiedHandler) {
4086
+ this.video.removeEventListener("emptied", this.emptiedHandler);
4087
+ delete this.emptiedHandler;
4088
+ }
4078
4089
  if (this.heartbeatInterval) {
4079
4090
  clearInterval(this.heartbeatInterval);
4080
4091
  this.heartbeatInterval = void 0;