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.
package/lib/index.cjs CHANGED
@@ -267,6 +267,8 @@ function createImaController(video, options) {
267
267
  let adPlaying = false;
268
268
  let originalMutedState = false;
269
269
  const listeners = /* @__PURE__ */ new Map();
270
+ const preloadedVast = /* @__PURE__ */ new Map();
271
+ const preloadingVast = /* @__PURE__ */ new Map();
270
272
  function setAdPlayingFlag(isPlaying) {
271
273
  if (isPlaying) {
272
274
  video.dataset.stormcloudAdPlaying = "true";
@@ -357,7 +359,15 @@ function createImaController(video, options) {
357
359
  let adsLoadedReject;
358
360
  function makeAdsRequest(google, vastTagUrl) {
359
361
  const adsRequest = new google.ima.AdsRequest();
360
- adsRequest.adTagUrl = vastTagUrl;
362
+ const preloadedResponse = preloadedVast.get(vastTagUrl);
363
+ if (preloadedResponse) {
364
+ adsRequest.adsResponse = preloadedResponse;
365
+ console.log(
366
+ "[IMA] Using preloaded VAST response for immediate ad request"
367
+ );
368
+ } else {
369
+ adsRequest.adTagUrl = vastTagUrl;
370
+ }
361
371
  const videoWidth = video.offsetWidth || video.clientWidth || 640;
362
372
  const videoHeight = video.offsetHeight || video.clientHeight || 360;
363
373
  adsRequest.linearAdSlotWidth = videoWidth;
@@ -367,6 +377,36 @@ function createImaController(video, options) {
367
377
  adsRequest.vastLoadTimeout = 5e3;
368
378
  console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
369
379
  adsLoader.requestAds(adsRequest);
380
+ if (preloadedResponse) {
381
+ preloadedVast.delete(vastTagUrl);
382
+ }
383
+ }
384
+ function ensurePlaceholderContainer() {
385
+ var _a;
386
+ if (adContainerEl) {
387
+ return;
388
+ }
389
+ const container = document.createElement("div");
390
+ container.style.position = "absolute";
391
+ container.style.left = "0";
392
+ container.style.top = "0";
393
+ container.style.right = "0";
394
+ container.style.bottom = "0";
395
+ container.style.display = "none";
396
+ container.style.alignItems = "center";
397
+ container.style.justifyContent = "center";
398
+ container.style.pointerEvents = "none";
399
+ container.style.zIndex = "10";
400
+ container.style.backgroundColor = "#000";
401
+ (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
402
+ adContainerEl = container;
403
+ }
404
+ async function fetchVastDocument(vastTagUrl) {
405
+ const response = await fetch(vastTagUrl, { mode: "cors" });
406
+ if (!response.ok) {
407
+ throw new Error(`Failed to preload VAST: ${response.status}`);
408
+ }
409
+ return response.text();
370
410
  }
371
411
  function destroyAdsManager() {
372
412
  if (adsManager) {
@@ -382,29 +422,16 @@ function createImaController(video, options) {
382
422
  return {
383
423
  initialize() {
384
424
  ensureImaLoaded().then(() => {
385
- var _a, _b;
425
+ var _a;
386
426
  const google = window.google;
387
- if (!adDisplayContainer) {
388
- const container = document.createElement("div");
389
- container.style.position = "absolute";
390
- container.style.left = "0";
391
- container.style.top = "0";
392
- container.style.right = "0";
393
- container.style.bottom = "0";
394
- container.style.display = "none";
395
- container.style.alignItems = "center";
396
- container.style.justifyContent = "center";
397
- container.style.pointerEvents = "none";
398
- container.style.zIndex = "10";
399
- container.style.backgroundColor = "#000";
400
- (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
401
- adContainerEl = container;
427
+ ensurePlaceholderContainer();
428
+ if (!adDisplayContainer && adContainerEl) {
402
429
  adDisplayContainer = new google.ima.AdDisplayContainer(
403
- container,
430
+ adContainerEl,
404
431
  video
405
432
  );
406
433
  try {
407
- (_b = adDisplayContainer.initialize) == null ? void 0 : _b.call(adDisplayContainer);
434
+ (_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
408
435
  } catch {
409
436
  }
410
437
  }
@@ -506,9 +533,13 @@ function createImaController(video, options) {
506
533
  adsLoader.addEventListener(
507
534
  google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
508
535
  (evt) => {
509
- console.log("[IMA] Ads manager loaded");
536
+ console.log(
537
+ "[IMA] Ads manager loaded - enabling preloading for continuous playback"
538
+ );
510
539
  try {
511
- adsManager = evt.getAdsManager(video);
540
+ const adsRenderingSettings = new google.ima.AdsRenderingSettings();
541
+ adsRenderingSettings.enablePreloading = true;
542
+ adsManager = evt.getAdsManager(video, adsRenderingSettings);
512
543
  const AdEvent = google.ima.AdEvent.Type;
513
544
  const AdErrorEvent = google.ima.AdErrorEvent.Type;
514
545
  adsManager.addEventListener(
@@ -704,6 +735,32 @@ function createImaController(video, options) {
704
735
  return Promise.reject(error);
705
736
  }
706
737
  },
738
+ async preloadAds(vastTagUrl) {
739
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
740
+ return Promise.resolve();
741
+ }
742
+ if (preloadedVast.has(vastTagUrl)) {
743
+ return Promise.resolve();
744
+ }
745
+ const inflight = preloadingVast.get(vastTagUrl);
746
+ if (inflight) {
747
+ return inflight;
748
+ }
749
+ const preloadPromise = fetchVastDocument(vastTagUrl).then((xml) => {
750
+ preloadedVast.set(vastTagUrl, xml);
751
+ console.log("[IMA] Cached VAST response for preloading:", vastTagUrl);
752
+ }).catch((error) => {
753
+ console.warn("[IMA] Failed to preload VAST response:", error);
754
+ preloadedVast.delete(vastTagUrl);
755
+ }).finally(() => {
756
+ preloadingVast.delete(vastTagUrl);
757
+ });
758
+ preloadingVast.set(vastTagUrl, preloadPromise);
759
+ return preloadPromise;
760
+ },
761
+ hasPreloadedAd(vastTagUrl) {
762
+ return preloadedVast.has(vastTagUrl);
763
+ },
707
764
  async play() {
708
765
  var _a, _b;
709
766
  if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
@@ -779,6 +836,8 @@ function createImaController(video, options) {
779
836
  adContainerEl = void 0;
780
837
  adDisplayContainer = void 0;
781
838
  adsLoader = void 0;
839
+ preloadedVast.clear();
840
+ preloadingVast.clear();
782
841
  },
783
842
  isAdPlaying() {
784
843
  return adPlaying;
@@ -834,6 +893,19 @@ function createImaController(video, options) {
834
893
  }
835
894
  }
836
895
  return 1;
896
+ },
897
+ showPlaceholder() {
898
+ ensurePlaceholderContainer();
899
+ if (adContainerEl) {
900
+ adContainerEl.style.display = "flex";
901
+ adContainerEl.style.pointerEvents = "auto";
902
+ }
903
+ },
904
+ hidePlaceholder() {
905
+ if (adContainerEl) {
906
+ adContainerEl.style.display = "none";
907
+ adContainerEl.style.pointerEvents = "none";
908
+ }
837
909
  }
838
910
  };
839
911
  }
@@ -851,6 +923,8 @@ function createHlsAdPlayer(contentVideo, options) {
851
923
  let adContainerEl;
852
924
  let currentAd;
853
925
  let sessionId;
926
+ const preloadedAds = /* @__PURE__ */ new Map();
927
+ const preloadingAds = /* @__PURE__ */ new Map();
854
928
  let trackingFired = {
855
929
  impression: false,
856
930
  start: false,
@@ -1080,6 +1154,19 @@ function createHlsAdPlayer(contentVideo, options) {
1080
1154
  return null;
1081
1155
  }
1082
1156
  }
1157
+ async function fetchAndParseVastAd(vastTagUrl) {
1158
+ const response = await fetch(vastTagUrl);
1159
+ if (!response.ok) {
1160
+ throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1161
+ }
1162
+ const vastXml = await response.text();
1163
+ console.log("[HlsAdPlayer] VAST XML received");
1164
+ console.log(
1165
+ "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1166
+ vastXml.substring(0, 2e3)
1167
+ );
1168
+ return parseVastXml(vastXml);
1169
+ }
1083
1170
  function createAdVideoElement() {
1084
1171
  const video = document.createElement("video");
1085
1172
  video.style.position = "absolute";
@@ -1231,17 +1318,17 @@ function createHlsAdPlayer(contentVideo, options) {
1231
1318
  }
1232
1319
  try {
1233
1320
  sessionId = generateSessionId();
1234
- const response = await fetch(vastTagUrl);
1235
- if (!response.ok) {
1236
- throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1321
+ let ad;
1322
+ if (preloadedAds.has(vastTagUrl)) {
1323
+ ad = preloadedAds.get(vastTagUrl);
1324
+ preloadedAds.delete(vastTagUrl);
1325
+ console.log(
1326
+ "[HlsAdPlayer] Using preloaded VAST response:",
1327
+ vastTagUrl
1328
+ );
1329
+ } else {
1330
+ ad = await fetchAndParseVastAd(vastTagUrl);
1237
1331
  }
1238
- const vastXml = await response.text();
1239
- console.log("[HlsAdPlayer] VAST XML received");
1240
- console.log(
1241
- "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1242
- vastXml.substring(0, 2e3)
1243
- );
1244
- const ad = parseVastXml(vastXml);
1245
1332
  if (!ad) {
1246
1333
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1247
1334
  emit("ad_error");
@@ -1260,6 +1347,37 @@ function createHlsAdPlayer(contentVideo, options) {
1260
1347
  return Promise.reject(error);
1261
1348
  }
1262
1349
  },
1350
+ async preloadAds(vastTagUrl) {
1351
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
1352
+ return Promise.resolve();
1353
+ }
1354
+ if (preloadedAds.has(vastTagUrl)) {
1355
+ return Promise.resolve();
1356
+ }
1357
+ const inflight = preloadingAds.get(vastTagUrl);
1358
+ if (inflight) {
1359
+ return inflight;
1360
+ }
1361
+ const preloadPromise = fetchAndParseVastAd(vastTagUrl).then((ad) => {
1362
+ if (ad) {
1363
+ preloadedAds.set(vastTagUrl, ad);
1364
+ console.log(
1365
+ "[HlsAdPlayer] Cached VAST response for preloading:",
1366
+ vastTagUrl
1367
+ );
1368
+ }
1369
+ }).catch((error) => {
1370
+ console.warn("[HlsAdPlayer] Failed to preload VAST response:", error);
1371
+ preloadedAds.delete(vastTagUrl);
1372
+ }).finally(() => {
1373
+ preloadingAds.delete(vastTagUrl);
1374
+ });
1375
+ preloadingAds.set(vastTagUrl, preloadPromise);
1376
+ return preloadPromise;
1377
+ },
1378
+ hasPreloadedAd(vastTagUrl) {
1379
+ return preloadedAds.has(vastTagUrl);
1380
+ },
1263
1381
  async play() {
1264
1382
  if (!currentAd) {
1265
1383
  console.warn(
@@ -1390,6 +1508,8 @@ function createHlsAdPlayer(contentVideo, options) {
1390
1508
  adContainerEl = void 0;
1391
1509
  currentAd = void 0;
1392
1510
  listeners.clear();
1511
+ preloadedAds.clear();
1512
+ preloadingAds.clear();
1393
1513
  },
1394
1514
  isAdPlaying() {
1395
1515
  return adPlaying;
@@ -1432,6 +1552,35 @@ function createHlsAdPlayer(contentVideo, options) {
1432
1552
  return adVideoElement.volume;
1433
1553
  }
1434
1554
  return 1;
1555
+ },
1556
+ showPlaceholder() {
1557
+ var _a;
1558
+ if (!adContainerEl) {
1559
+ const container = document.createElement("div");
1560
+ container.style.position = "absolute";
1561
+ container.style.left = "0";
1562
+ container.style.top = "0";
1563
+ container.style.right = "0";
1564
+ container.style.bottom = "0";
1565
+ container.style.display = "none";
1566
+ container.style.alignItems = "center";
1567
+ container.style.justifyContent = "center";
1568
+ container.style.pointerEvents = "none";
1569
+ container.style.zIndex = "10";
1570
+ container.style.backgroundColor = "#000";
1571
+ (_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
1572
+ adContainerEl = container;
1573
+ }
1574
+ if (adContainerEl) {
1575
+ adContainerEl.style.display = "flex";
1576
+ adContainerEl.style.pointerEvents = "auto";
1577
+ }
1578
+ },
1579
+ hidePlaceholder() {
1580
+ if (adContainerEl) {
1581
+ adContainerEl.style.display = "none";
1582
+ adContainerEl.style.pointerEvents = "none";
1583
+ }
1435
1584
  }
1436
1585
  };
1437
1586
  }
@@ -1912,6 +2061,8 @@ var StormcloudVideoPlayer = class {
1912
2061
  this.bufferedSegmentsCount = 0;
1913
2062
  this.shouldAutoplayAfterBuffering = false;
1914
2063
  this.hasInitialBufferCompleted = false;
2064
+ this.adPodAllUrls = [];
2065
+ this.preloadingAdUrls = /* @__PURE__ */ new Set();
1915
2066
  initializePolyfills();
1916
2067
  const browserOverrides = getBrowserConfigOverrides();
1917
2068
  this.config = { ...config, ...browserOverrides };
@@ -2212,6 +2363,7 @@ var StormcloudVideoPlayer = class {
2212
2363
  console.log("[StormcloudVideoPlayer] IMA content_pause event received");
2213
2364
  }
2214
2365
  this.clearAdFailsafeTimer();
2366
+ this.enforceAdHoldState();
2215
2367
  });
2216
2368
  this.ima.on("content_resume", () => {
2217
2369
  if (this.config.debugAdTiming) {
@@ -2236,12 +2388,10 @@ var StormcloudVideoPlayer = class {
2236
2388
  if (remaining > 500 && this.adPodQueue.length > 0) {
2237
2389
  const next = this.adPodQueue.shift();
2238
2390
  this.currentAdIndex++;
2239
- this.video.dataset.stormcloudAdPlaying = "true";
2240
- this.video.muted = true;
2241
- this.video.volume = 0;
2391
+ this.enforceAdHoldState();
2242
2392
  if (this.config.debugAdTiming) {
2243
2393
  console.log(
2244
- `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - main video stays muted, ad layer stays visible`
2394
+ `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
2245
2395
  );
2246
2396
  }
2247
2397
  this.playSingleAd(next).catch(() => {
@@ -2826,25 +2976,21 @@ var StormcloudVideoPlayer = class {
2826
2976
  this.video.currentTime * 1e3
2827
2977
  );
2828
2978
  const tags = this.selectVastTagsForBreak(scheduled);
2829
- let vastTagUrl;
2979
+ let vastTagUrls = [];
2830
2980
  if (this.apiVastTagUrl) {
2831
- vastTagUrl = this.apiVastTagUrl;
2832
- this.adPodQueue = [];
2833
- this.currentAdIndex = 0;
2834
- this.totalAdsInBreak = 1;
2981
+ vastTagUrls = [this.apiVastTagUrl];
2835
2982
  if (this.config.debugAdTiming) {
2836
- console.log("[StormcloudVideoPlayer] Using VAST endpoint:", vastTagUrl);
2983
+ console.log(
2984
+ "[StormcloudVideoPlayer] Using VAST endpoint:",
2985
+ this.apiVastTagUrl
2986
+ );
2837
2987
  }
2838
2988
  } else if (tags && tags.length > 0) {
2839
- vastTagUrl = tags[0];
2840
- const rest = tags.slice(1);
2841
- this.adPodQueue = rest;
2842
- this.currentAdIndex = 0;
2843
- this.totalAdsInBreak = tags.length;
2989
+ vastTagUrls = tags;
2844
2990
  if (this.config.debugAdTiming) {
2845
2991
  console.log(
2846
- "[StormcloudVideoPlayer] Using scheduled VAST tag:",
2847
- vastTagUrl
2992
+ "[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
2993
+ tags
2848
2994
  );
2849
2995
  }
2850
2996
  } else {
@@ -2853,16 +2999,28 @@ var StormcloudVideoPlayer = class {
2853
2999
  }
2854
3000
  return;
2855
3001
  }
2856
- if (vastTagUrl) {
3002
+ if (vastTagUrls.length > 0) {
3003
+ this.adPodAllUrls = [...vastTagUrls];
3004
+ this.preloadingAdUrls.clear();
3005
+ this.logQueuedAdUrls(this.adPodAllUrls);
2857
3006
  this.inAdBreak = true;
2858
3007
  this.showAds = true;
2859
- this.currentAdIndex++;
3008
+ this.currentAdIndex = 0;
3009
+ this.totalAdsInBreak = vastTagUrls.length;
3010
+ this.adPodQueue = [...vastTagUrls];
3011
+ this.enforceAdHoldState();
3012
+ this.preloadUpcomingAds();
3013
+ if (this.config.debugAdTiming) {
3014
+ console.log(
3015
+ `[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
3016
+ );
3017
+ }
2860
3018
  try {
2861
- await this.playSingleAd(vastTagUrl);
3019
+ await this.playAdPod();
2862
3020
  } catch (error) {
2863
3021
  if (this.config.debugAdTiming) {
2864
3022
  console.error(
2865
- "[StormcloudVideoPlayer] Ad playback failed in handleAdStart:",
3023
+ "[StormcloudVideoPlayer] Ad pod playback failed:",
2866
3024
  error
2867
3025
  );
2868
3026
  }
@@ -2875,6 +3033,22 @@ var StormcloudVideoPlayer = class {
2875
3033
  this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
2876
3034
  }
2877
3035
  }
3036
+ async playAdPod() {
3037
+ if (this.adPodQueue.length === 0) {
3038
+ if (this.config.debugAdTiming) {
3039
+ console.log("[StormcloudVideoPlayer] No ads in pod to play");
3040
+ }
3041
+ return;
3042
+ }
3043
+ const firstAd = this.adPodQueue.shift();
3044
+ this.currentAdIndex++;
3045
+ if (this.config.debugAdTiming) {
3046
+ console.log(
3047
+ `[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
3048
+ );
3049
+ }
3050
+ await this.playSingleAd(firstAd);
3051
+ }
2878
3052
  findCurrentOrNextBreak(nowMs) {
2879
3053
  var _a;
2880
3054
  const schedule = [];
@@ -2906,6 +3080,7 @@ var StormcloudVideoPlayer = class {
2906
3080
  const first = tags[0];
2907
3081
  const rest = tags.slice(1);
2908
3082
  this.adPodQueue = rest;
3083
+ this.enforceAdHoldState();
2909
3084
  await this.playSingleAd(first);
2910
3085
  this.inAdBreak = true;
2911
3086
  this.expectedAdBreakDurationMs = remainingMs;
@@ -3019,6 +3194,12 @@ var StormcloudVideoPlayer = class {
3019
3194
  }
3020
3195
  return;
3021
3196
  }
3197
+ const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
3198
+ if (wasPreloaded && this.config.debugAdTiming) {
3199
+ console.log(
3200
+ `[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
3201
+ );
3202
+ }
3022
3203
  if (!this.showAds) {
3023
3204
  if (this.config.debugAdTiming) {
3024
3205
  console.log(
@@ -3039,12 +3220,14 @@ var StormcloudVideoPlayer = class {
3039
3220
  this.startAdFailsafeTimer();
3040
3221
  try {
3041
3222
  await this.ima.requestAds(vastTagUrl);
3223
+ this.preloadUpcomingAds();
3042
3224
  try {
3043
3225
  if (this.config.debugAdTiming) {
3044
3226
  console.log(
3045
3227
  "[StormcloudVideoPlayer] Ad request completed, attempting playback"
3046
3228
  );
3047
3229
  }
3230
+ this.enforceAdHoldState();
3048
3231
  await this.ima.play();
3049
3232
  if (this.config.debugAdTiming) {
3050
3233
  console.log(
@@ -3074,6 +3257,8 @@ var StormcloudVideoPlayer = class {
3074
3257
  "[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
3075
3258
  );
3076
3259
  }
3260
+ this.releaseAdHoldState();
3261
+ this.preloadingAdUrls.clear();
3077
3262
  this.inAdBreak = false;
3078
3263
  this.expectedAdBreakDurationMs = void 0;
3079
3264
  this.currentAdBreakStartWallClockMs = void 0;
@@ -3081,6 +3266,7 @@ var StormcloudVideoPlayer = class {
3081
3266
  this.clearAdStopTimer();
3082
3267
  this.clearAdFailsafeTimer();
3083
3268
  this.adPodQueue = [];
3269
+ this.adPodAllUrls = [];
3084
3270
  this.showAds = false;
3085
3271
  this.currentAdIndex = 0;
3086
3272
  this.totalAdsInBreak = 0;
@@ -3161,6 +3347,64 @@ var StormcloudVideoPlayer = class {
3161
3347
  }
3162
3348
  return [b.vastTagUrl];
3163
3349
  }
3350
+ logQueuedAdUrls(urls) {
3351
+ if (!this.config.debugAdTiming) {
3352
+ return;
3353
+ }
3354
+ console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
3355
+ }
3356
+ enforceAdHoldState() {
3357
+ this.video.dataset.stormcloudAdPlaying = "true";
3358
+ this.video.muted = true;
3359
+ this.video.volume = 0;
3360
+ if (typeof this.ima.showPlaceholder === "function") {
3361
+ this.ima.showPlaceholder();
3362
+ }
3363
+ }
3364
+ releaseAdHoldState() {
3365
+ delete this.video.dataset.stormcloudAdPlaying;
3366
+ if (typeof this.ima.hidePlaceholder === "function") {
3367
+ this.ima.hidePlaceholder();
3368
+ }
3369
+ }
3370
+ preloadUpcomingAds() {
3371
+ if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
3372
+ return;
3373
+ }
3374
+ const upcoming = this.adPodQueue.slice(0, 2);
3375
+ for (const url of upcoming) {
3376
+ if (!url) continue;
3377
+ if (this.ima.hasPreloadedAd(url)) {
3378
+ this.preloadingAdUrls.delete(url);
3379
+ continue;
3380
+ }
3381
+ if (this.preloadingAdUrls.has(url)) {
3382
+ continue;
3383
+ }
3384
+ if (this.config.debugAdTiming) {
3385
+ console.log(
3386
+ `[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
3387
+ );
3388
+ }
3389
+ this.preloadingAdUrls.add(url);
3390
+ this.ima.preloadAds(url).then(() => {
3391
+ if (this.config.debugAdTiming) {
3392
+ console.log(
3393
+ `[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
3394
+ );
3395
+ }
3396
+ }).catch((error) => {
3397
+ if (this.config.debugAdTiming) {
3398
+ console.warn(
3399
+ `[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
3400
+ error
3401
+ );
3402
+ }
3403
+ }).finally(() => {
3404
+ this.preloadingAdUrls.delete(url);
3405
+ });
3406
+ }
3407
+ }
3164
3408
  getRemainingAdMs() {
3165
3409
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
3166
3410
  return 0;
@@ -3312,6 +3556,9 @@ var StormcloudVideoPlayer = class {
3312
3556
  }
3313
3557
  (_a = this.hls) == null ? void 0 : _a.destroy();
3314
3558
  (_b = this.ima) == null ? void 0 : _b.destroy();
3559
+ this.releaseAdHoldState();
3560
+ this.preloadingAdUrls.clear();
3561
+ this.adPodAllUrls = [];
3315
3562
  }
3316
3563
  };
3317
3564