stormcloud-video-player 0.2.23 → 0.2.25

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.
@@ -200,6 +200,8 @@ function createImaController(video, options) {
200
200
  let adPlaying = false;
201
201
  let originalMutedState = false;
202
202
  const listeners = /* @__PURE__ */ new Map();
203
+ const preloadedVast = /* @__PURE__ */ new Map();
204
+ const preloadingVast = /* @__PURE__ */ new Map();
203
205
  function setAdPlayingFlag(isPlaying) {
204
206
  if (isPlaying) {
205
207
  video.dataset.stormcloudAdPlaying = "true";
@@ -290,7 +292,15 @@ function createImaController(video, options) {
290
292
  let adsLoadedReject;
291
293
  function makeAdsRequest(google, vastTagUrl) {
292
294
  const adsRequest = new google.ima.AdsRequest();
293
- adsRequest.adTagUrl = vastTagUrl;
295
+ const preloadedResponse = preloadedVast.get(vastTagUrl);
296
+ if (preloadedResponse) {
297
+ adsRequest.adsResponse = preloadedResponse;
298
+ console.log(
299
+ "[IMA] Using preloaded VAST response for immediate ad request"
300
+ );
301
+ } else {
302
+ adsRequest.adTagUrl = vastTagUrl;
303
+ }
294
304
  const videoWidth = video.offsetWidth || video.clientWidth || 640;
295
305
  const videoHeight = video.offsetHeight || video.clientHeight || 360;
296
306
  adsRequest.linearAdSlotWidth = videoWidth;
@@ -300,6 +310,36 @@ function createImaController(video, options) {
300
310
  adsRequest.vastLoadTimeout = 5e3;
301
311
  console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
302
312
  adsLoader.requestAds(adsRequest);
313
+ if (preloadedResponse) {
314
+ preloadedVast.delete(vastTagUrl);
315
+ }
316
+ }
317
+ function ensurePlaceholderContainer() {
318
+ var _a;
319
+ if (adContainerEl) {
320
+ return;
321
+ }
322
+ const container = document.createElement("div");
323
+ container.style.position = "absolute";
324
+ container.style.left = "0";
325
+ container.style.top = "0";
326
+ container.style.right = "0";
327
+ container.style.bottom = "0";
328
+ container.style.display = "none";
329
+ container.style.alignItems = "center";
330
+ container.style.justifyContent = "center";
331
+ container.style.pointerEvents = "none";
332
+ container.style.zIndex = "10";
333
+ container.style.backgroundColor = "#000";
334
+ (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
335
+ adContainerEl = container;
336
+ }
337
+ async function fetchVastDocument(vastTagUrl) {
338
+ const response = await fetch(vastTagUrl, { mode: "cors" });
339
+ if (!response.ok) {
340
+ throw new Error(`Failed to preload VAST: ${response.status}`);
341
+ }
342
+ return response.text();
303
343
  }
304
344
  function destroyAdsManager() {
305
345
  if (adsManager) {
@@ -315,29 +355,16 @@ function createImaController(video, options) {
315
355
  return {
316
356
  initialize() {
317
357
  ensureImaLoaded().then(() => {
318
- var _a, _b;
358
+ var _a;
319
359
  const google = window.google;
320
- if (!adDisplayContainer) {
321
- const container = document.createElement("div");
322
- container.style.position = "absolute";
323
- container.style.left = "0";
324
- container.style.top = "0";
325
- container.style.right = "0";
326
- container.style.bottom = "0";
327
- container.style.display = "none";
328
- container.style.alignItems = "center";
329
- container.style.justifyContent = "center";
330
- container.style.pointerEvents = "none";
331
- container.style.zIndex = "10";
332
- container.style.backgroundColor = "#000";
333
- (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
334
- adContainerEl = container;
360
+ ensurePlaceholderContainer();
361
+ if (!adDisplayContainer && adContainerEl) {
335
362
  adDisplayContainer = new google.ima.AdDisplayContainer(
336
- container,
363
+ adContainerEl,
337
364
  video
338
365
  );
339
366
  try {
340
- (_b = adDisplayContainer.initialize) == null ? void 0 : _b.call(adDisplayContainer);
367
+ (_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
341
368
  } catch {
342
369
  }
343
370
  }
@@ -439,9 +466,13 @@ function createImaController(video, options) {
439
466
  adsLoader.addEventListener(
440
467
  google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
441
468
  (evt) => {
442
- console.log("[IMA] Ads manager loaded");
469
+ console.log(
470
+ "[IMA] Ads manager loaded - enabling preloading for continuous playback"
471
+ );
443
472
  try {
444
- adsManager = evt.getAdsManager(video);
473
+ const adsRenderingSettings = new google.ima.AdsRenderingSettings();
474
+ adsRenderingSettings.enablePreloading = true;
475
+ adsManager = evt.getAdsManager(video, adsRenderingSettings);
445
476
  const AdEvent = google.ima.AdEvent.Type;
446
477
  const AdErrorEvent = google.ima.AdErrorEvent.Type;
447
478
  adsManager.addEventListener(
@@ -637,6 +668,32 @@ function createImaController(video, options) {
637
668
  return Promise.reject(error);
638
669
  }
639
670
  },
671
+ async preloadAds(vastTagUrl) {
672
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
673
+ return Promise.resolve();
674
+ }
675
+ if (preloadedVast.has(vastTagUrl)) {
676
+ return Promise.resolve();
677
+ }
678
+ const inflight = preloadingVast.get(vastTagUrl);
679
+ if (inflight) {
680
+ return inflight;
681
+ }
682
+ const preloadPromise = fetchVastDocument(vastTagUrl).then((xml) => {
683
+ preloadedVast.set(vastTagUrl, xml);
684
+ console.log("[IMA] Cached VAST response for preloading:", vastTagUrl);
685
+ }).catch((error) => {
686
+ console.warn("[IMA] Failed to preload VAST response:", error);
687
+ preloadedVast.delete(vastTagUrl);
688
+ }).finally(() => {
689
+ preloadingVast.delete(vastTagUrl);
690
+ });
691
+ preloadingVast.set(vastTagUrl, preloadPromise);
692
+ return preloadPromise;
693
+ },
694
+ hasPreloadedAd(vastTagUrl) {
695
+ return preloadedVast.has(vastTagUrl);
696
+ },
640
697
  async play() {
641
698
  var _a, _b;
642
699
  if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
@@ -712,6 +769,8 @@ function createImaController(video, options) {
712
769
  adContainerEl = void 0;
713
770
  adDisplayContainer = void 0;
714
771
  adsLoader = void 0;
772
+ preloadedVast.clear();
773
+ preloadingVast.clear();
715
774
  },
716
775
  isAdPlaying() {
717
776
  return adPlaying;
@@ -767,6 +826,19 @@ function createImaController(video, options) {
767
826
  }
768
827
  }
769
828
  return 1;
829
+ },
830
+ showPlaceholder() {
831
+ ensurePlaceholderContainer();
832
+ if (adContainerEl) {
833
+ adContainerEl.style.display = "flex";
834
+ adContainerEl.style.pointerEvents = "auto";
835
+ }
836
+ },
837
+ hidePlaceholder() {
838
+ if (adContainerEl) {
839
+ adContainerEl.style.display = "none";
840
+ adContainerEl.style.pointerEvents = "none";
841
+ }
770
842
  }
771
843
  };
772
844
  }
@@ -784,6 +856,8 @@ function createHlsAdPlayer(contentVideo, options) {
784
856
  let adContainerEl;
785
857
  let currentAd;
786
858
  let sessionId;
859
+ const preloadedAds = /* @__PURE__ */ new Map();
860
+ const preloadingAds = /* @__PURE__ */ new Map();
787
861
  let trackingFired = {
788
862
  impression: false,
789
863
  start: false,
@@ -1013,6 +1087,19 @@ function createHlsAdPlayer(contentVideo, options) {
1013
1087
  return null;
1014
1088
  }
1015
1089
  }
1090
+ async function fetchAndParseVastAd(vastTagUrl) {
1091
+ const response = await fetch(vastTagUrl);
1092
+ if (!response.ok) {
1093
+ throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1094
+ }
1095
+ const vastXml = await response.text();
1096
+ console.log("[HlsAdPlayer] VAST XML received");
1097
+ console.log(
1098
+ "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1099
+ vastXml.substring(0, 2e3)
1100
+ );
1101
+ return parseVastXml(vastXml);
1102
+ }
1016
1103
  function createAdVideoElement() {
1017
1104
  const video = document.createElement("video");
1018
1105
  video.style.position = "absolute";
@@ -1164,17 +1251,17 @@ function createHlsAdPlayer(contentVideo, options) {
1164
1251
  }
1165
1252
  try {
1166
1253
  sessionId = generateSessionId();
1167
- const response = await fetch(vastTagUrl);
1168
- if (!response.ok) {
1169
- throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1254
+ let ad;
1255
+ if (preloadedAds.has(vastTagUrl)) {
1256
+ ad = preloadedAds.get(vastTagUrl);
1257
+ preloadedAds.delete(vastTagUrl);
1258
+ console.log(
1259
+ "[HlsAdPlayer] Using preloaded VAST response:",
1260
+ vastTagUrl
1261
+ );
1262
+ } else {
1263
+ ad = await fetchAndParseVastAd(vastTagUrl);
1170
1264
  }
1171
- const vastXml = await response.text();
1172
- console.log("[HlsAdPlayer] VAST XML received");
1173
- console.log(
1174
- "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1175
- vastXml.substring(0, 2e3)
1176
- );
1177
- const ad = parseVastXml(vastXml);
1178
1265
  if (!ad) {
1179
1266
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1180
1267
  emit("ad_error");
@@ -1193,6 +1280,37 @@ function createHlsAdPlayer(contentVideo, options) {
1193
1280
  return Promise.reject(error);
1194
1281
  }
1195
1282
  },
1283
+ async preloadAds(vastTagUrl) {
1284
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
1285
+ return Promise.resolve();
1286
+ }
1287
+ if (preloadedAds.has(vastTagUrl)) {
1288
+ return Promise.resolve();
1289
+ }
1290
+ const inflight = preloadingAds.get(vastTagUrl);
1291
+ if (inflight) {
1292
+ return inflight;
1293
+ }
1294
+ const preloadPromise = fetchAndParseVastAd(vastTagUrl).then((ad) => {
1295
+ if (ad) {
1296
+ preloadedAds.set(vastTagUrl, ad);
1297
+ console.log(
1298
+ "[HlsAdPlayer] Cached VAST response for preloading:",
1299
+ vastTagUrl
1300
+ );
1301
+ }
1302
+ }).catch((error) => {
1303
+ console.warn("[HlsAdPlayer] Failed to preload VAST response:", error);
1304
+ preloadedAds.delete(vastTagUrl);
1305
+ }).finally(() => {
1306
+ preloadingAds.delete(vastTagUrl);
1307
+ });
1308
+ preloadingAds.set(vastTagUrl, preloadPromise);
1309
+ return preloadPromise;
1310
+ },
1311
+ hasPreloadedAd(vastTagUrl) {
1312
+ return preloadedAds.has(vastTagUrl);
1313
+ },
1196
1314
  async play() {
1197
1315
  if (!currentAd) {
1198
1316
  console.warn(
@@ -1323,6 +1441,8 @@ function createHlsAdPlayer(contentVideo, options) {
1323
1441
  adContainerEl = void 0;
1324
1442
  currentAd = void 0;
1325
1443
  listeners.clear();
1444
+ preloadedAds.clear();
1445
+ preloadingAds.clear();
1326
1446
  },
1327
1447
  isAdPlaying() {
1328
1448
  return adPlaying;
@@ -1365,6 +1485,35 @@ function createHlsAdPlayer(contentVideo, options) {
1365
1485
  return adVideoElement.volume;
1366
1486
  }
1367
1487
  return 1;
1488
+ },
1489
+ showPlaceholder() {
1490
+ var _a;
1491
+ if (!adContainerEl) {
1492
+ const container = document.createElement("div");
1493
+ container.style.position = "absolute";
1494
+ container.style.left = "0";
1495
+ container.style.top = "0";
1496
+ container.style.right = "0";
1497
+ container.style.bottom = "0";
1498
+ container.style.display = "none";
1499
+ container.style.alignItems = "center";
1500
+ container.style.justifyContent = "center";
1501
+ container.style.pointerEvents = "none";
1502
+ container.style.zIndex = "10";
1503
+ container.style.backgroundColor = "#000";
1504
+ (_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
1505
+ adContainerEl = container;
1506
+ }
1507
+ if (adContainerEl) {
1508
+ adContainerEl.style.display = "flex";
1509
+ adContainerEl.style.pointerEvents = "auto";
1510
+ }
1511
+ },
1512
+ hidePlaceholder() {
1513
+ if (adContainerEl) {
1514
+ adContainerEl.style.display = "none";
1515
+ adContainerEl.style.pointerEvents = "none";
1516
+ }
1368
1517
  }
1369
1518
  };
1370
1519
  }
@@ -1845,6 +1994,8 @@ var StormcloudVideoPlayer = class {
1845
1994
  this.bufferedSegmentsCount = 0;
1846
1995
  this.shouldAutoplayAfterBuffering = false;
1847
1996
  this.hasInitialBufferCompleted = false;
1997
+ this.adPodAllUrls = [];
1998
+ this.preloadingAdUrls = /* @__PURE__ */ new Set();
1848
1999
  initializePolyfills();
1849
2000
  const browserOverrides = getBrowserConfigOverrides();
1850
2001
  this.config = { ...config, ...browserOverrides };
@@ -2145,6 +2296,7 @@ var StormcloudVideoPlayer = class {
2145
2296
  console.log("[StormcloudVideoPlayer] IMA content_pause event received");
2146
2297
  }
2147
2298
  this.clearAdFailsafeTimer();
2299
+ this.enforceAdHoldState();
2148
2300
  });
2149
2301
  this.ima.on("content_resume", () => {
2150
2302
  if (this.config.debugAdTiming) {
@@ -2169,12 +2321,10 @@ var StormcloudVideoPlayer = class {
2169
2321
  if (remaining > 500 && this.adPodQueue.length > 0) {
2170
2322
  const next = this.adPodQueue.shift();
2171
2323
  this.currentAdIndex++;
2172
- this.video.dataset.stormcloudAdPlaying = "true";
2173
- this.video.muted = true;
2174
- this.video.volume = 0;
2324
+ this.enforceAdHoldState();
2175
2325
  if (this.config.debugAdTiming) {
2176
2326
  console.log(
2177
- `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - main video stays muted, ad layer stays visible`
2327
+ `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
2178
2328
  );
2179
2329
  }
2180
2330
  this.playSingleAd(next).catch(() => {
@@ -2759,25 +2909,21 @@ var StormcloudVideoPlayer = class {
2759
2909
  this.video.currentTime * 1e3
2760
2910
  );
2761
2911
  const tags = this.selectVastTagsForBreak(scheduled);
2762
- let vastTagUrl;
2912
+ let vastTagUrls = [];
2763
2913
  if (this.apiVastTagUrl) {
2764
- vastTagUrl = this.apiVastTagUrl;
2765
- this.adPodQueue = [];
2766
- this.currentAdIndex = 0;
2767
- this.totalAdsInBreak = 1;
2914
+ vastTagUrls = [this.apiVastTagUrl];
2768
2915
  if (this.config.debugAdTiming) {
2769
- console.log("[StormcloudVideoPlayer] Using VAST endpoint:", vastTagUrl);
2916
+ console.log(
2917
+ "[StormcloudVideoPlayer] Using VAST endpoint:",
2918
+ this.apiVastTagUrl
2919
+ );
2770
2920
  }
2771
2921
  } else if (tags && tags.length > 0) {
2772
- vastTagUrl = tags[0];
2773
- const rest = tags.slice(1);
2774
- this.adPodQueue = rest;
2775
- this.currentAdIndex = 0;
2776
- this.totalAdsInBreak = tags.length;
2922
+ vastTagUrls = tags;
2777
2923
  if (this.config.debugAdTiming) {
2778
2924
  console.log(
2779
- "[StormcloudVideoPlayer] Using scheduled VAST tag:",
2780
- vastTagUrl
2925
+ "[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
2926
+ tags
2781
2927
  );
2782
2928
  }
2783
2929
  } else {
@@ -2786,16 +2932,28 @@ var StormcloudVideoPlayer = class {
2786
2932
  }
2787
2933
  return;
2788
2934
  }
2789
- if (vastTagUrl) {
2935
+ if (vastTagUrls.length > 0) {
2936
+ this.adPodAllUrls = [...vastTagUrls];
2937
+ this.preloadingAdUrls.clear();
2938
+ this.logQueuedAdUrls(this.adPodAllUrls);
2790
2939
  this.inAdBreak = true;
2791
2940
  this.showAds = true;
2792
- this.currentAdIndex++;
2941
+ this.currentAdIndex = 0;
2942
+ this.totalAdsInBreak = vastTagUrls.length;
2943
+ this.adPodQueue = [...vastTagUrls];
2944
+ this.enforceAdHoldState();
2945
+ this.preloadUpcomingAds();
2946
+ if (this.config.debugAdTiming) {
2947
+ console.log(
2948
+ `[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
2949
+ );
2950
+ }
2793
2951
  try {
2794
- await this.playSingleAd(vastTagUrl);
2952
+ await this.playAdPod();
2795
2953
  } catch (error) {
2796
2954
  if (this.config.debugAdTiming) {
2797
2955
  console.error(
2798
- "[StormcloudVideoPlayer] Ad playback failed in handleAdStart:",
2956
+ "[StormcloudVideoPlayer] Ad pod playback failed:",
2799
2957
  error
2800
2958
  );
2801
2959
  }
@@ -2808,6 +2966,22 @@ var StormcloudVideoPlayer = class {
2808
2966
  this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
2809
2967
  }
2810
2968
  }
2969
+ async playAdPod() {
2970
+ if (this.adPodQueue.length === 0) {
2971
+ if (this.config.debugAdTiming) {
2972
+ console.log("[StormcloudVideoPlayer] No ads in pod to play");
2973
+ }
2974
+ return;
2975
+ }
2976
+ const firstAd = this.adPodQueue.shift();
2977
+ this.currentAdIndex++;
2978
+ if (this.config.debugAdTiming) {
2979
+ console.log(
2980
+ `[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
2981
+ );
2982
+ }
2983
+ await this.playSingleAd(firstAd);
2984
+ }
2811
2985
  findCurrentOrNextBreak(nowMs) {
2812
2986
  var _a;
2813
2987
  const schedule = [];
@@ -2839,6 +3013,7 @@ var StormcloudVideoPlayer = class {
2839
3013
  const first = tags[0];
2840
3014
  const rest = tags.slice(1);
2841
3015
  this.adPodQueue = rest;
3016
+ this.enforceAdHoldState();
2842
3017
  await this.playSingleAd(first);
2843
3018
  this.inAdBreak = true;
2844
3019
  this.expectedAdBreakDurationMs = remainingMs;
@@ -2952,6 +3127,12 @@ var StormcloudVideoPlayer = class {
2952
3127
  }
2953
3128
  return;
2954
3129
  }
3130
+ const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
3131
+ if (wasPreloaded && this.config.debugAdTiming) {
3132
+ console.log(
3133
+ `[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
3134
+ );
3135
+ }
2955
3136
  if (!this.showAds) {
2956
3137
  if (this.config.debugAdTiming) {
2957
3138
  console.log(
@@ -2972,12 +3153,14 @@ var StormcloudVideoPlayer = class {
2972
3153
  this.startAdFailsafeTimer();
2973
3154
  try {
2974
3155
  await this.ima.requestAds(vastTagUrl);
3156
+ this.preloadUpcomingAds();
2975
3157
  try {
2976
3158
  if (this.config.debugAdTiming) {
2977
3159
  console.log(
2978
3160
  "[StormcloudVideoPlayer] Ad request completed, attempting playback"
2979
3161
  );
2980
3162
  }
3163
+ this.enforceAdHoldState();
2981
3164
  await this.ima.play();
2982
3165
  if (this.config.debugAdTiming) {
2983
3166
  console.log(
@@ -3007,6 +3190,8 @@ var StormcloudVideoPlayer = class {
3007
3190
  "[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
3008
3191
  );
3009
3192
  }
3193
+ this.releaseAdHoldState();
3194
+ this.preloadingAdUrls.clear();
3010
3195
  this.inAdBreak = false;
3011
3196
  this.expectedAdBreakDurationMs = void 0;
3012
3197
  this.currentAdBreakStartWallClockMs = void 0;
@@ -3014,6 +3199,7 @@ var StormcloudVideoPlayer = class {
3014
3199
  this.clearAdStopTimer();
3015
3200
  this.clearAdFailsafeTimer();
3016
3201
  this.adPodQueue = [];
3202
+ this.adPodAllUrls = [];
3017
3203
  this.showAds = false;
3018
3204
  this.currentAdIndex = 0;
3019
3205
  this.totalAdsInBreak = 0;
@@ -3094,6 +3280,64 @@ var StormcloudVideoPlayer = class {
3094
3280
  }
3095
3281
  return [b.vastTagUrl];
3096
3282
  }
3283
+ logQueuedAdUrls(urls) {
3284
+ if (!this.config.debugAdTiming) {
3285
+ return;
3286
+ }
3287
+ console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
3288
+ }
3289
+ enforceAdHoldState() {
3290
+ this.video.dataset.stormcloudAdPlaying = "true";
3291
+ this.video.muted = true;
3292
+ this.video.volume = 0;
3293
+ if (typeof this.ima.showPlaceholder === "function") {
3294
+ this.ima.showPlaceholder();
3295
+ }
3296
+ }
3297
+ releaseAdHoldState() {
3298
+ delete this.video.dataset.stormcloudAdPlaying;
3299
+ if (typeof this.ima.hidePlaceholder === "function") {
3300
+ this.ima.hidePlaceholder();
3301
+ }
3302
+ }
3303
+ preloadUpcomingAds() {
3304
+ if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
3305
+ return;
3306
+ }
3307
+ const upcoming = this.adPodQueue.slice(0, 2);
3308
+ for (const url of upcoming) {
3309
+ if (!url) continue;
3310
+ if (this.ima.hasPreloadedAd(url)) {
3311
+ this.preloadingAdUrls.delete(url);
3312
+ continue;
3313
+ }
3314
+ if (this.preloadingAdUrls.has(url)) {
3315
+ continue;
3316
+ }
3317
+ if (this.config.debugAdTiming) {
3318
+ console.log(
3319
+ `[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
3320
+ );
3321
+ }
3322
+ this.preloadingAdUrls.add(url);
3323
+ this.ima.preloadAds(url).then(() => {
3324
+ if (this.config.debugAdTiming) {
3325
+ console.log(
3326
+ `[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
3327
+ );
3328
+ }
3329
+ }).catch((error) => {
3330
+ if (this.config.debugAdTiming) {
3331
+ console.warn(
3332
+ `[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
3333
+ error
3334
+ );
3335
+ }
3336
+ }).finally(() => {
3337
+ this.preloadingAdUrls.delete(url);
3338
+ });
3339
+ }
3340
+ }
3097
3341
  getRemainingAdMs() {
3098
3342
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
3099
3343
  return 0;
@@ -3245,6 +3489,9 @@ var StormcloudVideoPlayer = class {
3245
3489
  }
3246
3490
  (_a = this.hls) == null ? void 0 : _a.destroy();
3247
3491
  (_b = this.ima) == null ? void 0 : _b.destroy();
3492
+ this.releaseAdHoldState();
3493
+ this.preloadingAdUrls.clear();
3494
+ this.adPodAllUrls = [];
3248
3495
  }
3249
3496
  };
3250
3497
  // Annotate the CommonJS export names for ESM import in node: