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.
@@ -1,5 +1,5 @@
1
1
  import { Component } from 'react';
2
- import { S as StormcloudVideoPlayerConfig } from '../types-D1xfSdLP.cjs';
2
+ import { S as StormcloudVideoPlayerConfig } from '../types-9_2sbHCg.cjs';
3
3
 
4
4
  interface HlsPlayerProps extends StormcloudVideoPlayerConfig {
5
5
  onMount?: (player: any) => void;
@@ -242,6 +242,8 @@ function createImaController(video, options) {
242
242
  let adPlaying = false;
243
243
  let originalMutedState = false;
244
244
  const listeners = /* @__PURE__ */ new Map();
245
+ const preloadedVast = /* @__PURE__ */ new Map();
246
+ const preloadingVast = /* @__PURE__ */ new Map();
245
247
  function setAdPlayingFlag(isPlaying) {
246
248
  if (isPlaying) {
247
249
  video.dataset.stormcloudAdPlaying = "true";
@@ -332,7 +334,15 @@ function createImaController(video, options) {
332
334
  let adsLoadedReject;
333
335
  function makeAdsRequest(google, vastTagUrl) {
334
336
  const adsRequest = new google.ima.AdsRequest();
335
- adsRequest.adTagUrl = vastTagUrl;
337
+ const preloadedResponse = preloadedVast.get(vastTagUrl);
338
+ if (preloadedResponse) {
339
+ adsRequest.adsResponse = preloadedResponse;
340
+ console.log(
341
+ "[IMA] Using preloaded VAST response for immediate ad request"
342
+ );
343
+ } else {
344
+ adsRequest.adTagUrl = vastTagUrl;
345
+ }
336
346
  const videoWidth = video.offsetWidth || video.clientWidth || 640;
337
347
  const videoHeight = video.offsetHeight || video.clientHeight || 360;
338
348
  adsRequest.linearAdSlotWidth = videoWidth;
@@ -342,6 +352,36 @@ function createImaController(video, options) {
342
352
  adsRequest.vastLoadTimeout = 5e3;
343
353
  console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
344
354
  adsLoader.requestAds(adsRequest);
355
+ if (preloadedResponse) {
356
+ preloadedVast.delete(vastTagUrl);
357
+ }
358
+ }
359
+ function ensurePlaceholderContainer() {
360
+ var _a;
361
+ if (adContainerEl) {
362
+ return;
363
+ }
364
+ const container = document.createElement("div");
365
+ container.style.position = "absolute";
366
+ container.style.left = "0";
367
+ container.style.top = "0";
368
+ container.style.right = "0";
369
+ container.style.bottom = "0";
370
+ container.style.display = "none";
371
+ container.style.alignItems = "center";
372
+ container.style.justifyContent = "center";
373
+ container.style.pointerEvents = "none";
374
+ container.style.zIndex = "10";
375
+ container.style.backgroundColor = "#000";
376
+ (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
377
+ adContainerEl = container;
378
+ }
379
+ async function fetchVastDocument(vastTagUrl) {
380
+ const response = await fetch(vastTagUrl, { mode: "cors" });
381
+ if (!response.ok) {
382
+ throw new Error(`Failed to preload VAST: ${response.status}`);
383
+ }
384
+ return response.text();
345
385
  }
346
386
  function destroyAdsManager() {
347
387
  if (adsManager) {
@@ -357,29 +397,16 @@ function createImaController(video, options) {
357
397
  return {
358
398
  initialize() {
359
399
  ensureImaLoaded().then(() => {
360
- var _a, _b;
400
+ var _a;
361
401
  const google = window.google;
362
- if (!adDisplayContainer) {
363
- const container = document.createElement("div");
364
- container.style.position = "absolute";
365
- container.style.left = "0";
366
- container.style.top = "0";
367
- container.style.right = "0";
368
- container.style.bottom = "0";
369
- container.style.display = "none";
370
- container.style.alignItems = "center";
371
- container.style.justifyContent = "center";
372
- container.style.pointerEvents = "none";
373
- container.style.zIndex = "10";
374
- container.style.backgroundColor = "#000";
375
- (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
376
- adContainerEl = container;
402
+ ensurePlaceholderContainer();
403
+ if (!adDisplayContainer && adContainerEl) {
377
404
  adDisplayContainer = new google.ima.AdDisplayContainer(
378
- container,
405
+ adContainerEl,
379
406
  video
380
407
  );
381
408
  try {
382
- (_b = adDisplayContainer.initialize) == null ? void 0 : _b.call(adDisplayContainer);
409
+ (_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
383
410
  } catch {
384
411
  }
385
412
  }
@@ -481,9 +508,13 @@ function createImaController(video, options) {
481
508
  adsLoader.addEventListener(
482
509
  google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
483
510
  (evt) => {
484
- console.log("[IMA] Ads manager loaded");
511
+ console.log(
512
+ "[IMA] Ads manager loaded - enabling preloading for continuous playback"
513
+ );
485
514
  try {
486
- adsManager = evt.getAdsManager(video);
515
+ const adsRenderingSettings = new google.ima.AdsRenderingSettings();
516
+ adsRenderingSettings.enablePreloading = true;
517
+ adsManager = evt.getAdsManager(video, adsRenderingSettings);
487
518
  const AdEvent = google.ima.AdEvent.Type;
488
519
  const AdErrorEvent = google.ima.AdErrorEvent.Type;
489
520
  adsManager.addEventListener(
@@ -679,6 +710,32 @@ function createImaController(video, options) {
679
710
  return Promise.reject(error);
680
711
  }
681
712
  },
713
+ async preloadAds(vastTagUrl) {
714
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
715
+ return Promise.resolve();
716
+ }
717
+ if (preloadedVast.has(vastTagUrl)) {
718
+ return Promise.resolve();
719
+ }
720
+ const inflight = preloadingVast.get(vastTagUrl);
721
+ if (inflight) {
722
+ return inflight;
723
+ }
724
+ const preloadPromise = fetchVastDocument(vastTagUrl).then((xml) => {
725
+ preloadedVast.set(vastTagUrl, xml);
726
+ console.log("[IMA] Cached VAST response for preloading:", vastTagUrl);
727
+ }).catch((error) => {
728
+ console.warn("[IMA] Failed to preload VAST response:", error);
729
+ preloadedVast.delete(vastTagUrl);
730
+ }).finally(() => {
731
+ preloadingVast.delete(vastTagUrl);
732
+ });
733
+ preloadingVast.set(vastTagUrl, preloadPromise);
734
+ return preloadPromise;
735
+ },
736
+ hasPreloadedAd(vastTagUrl) {
737
+ return preloadedVast.has(vastTagUrl);
738
+ },
682
739
  async play() {
683
740
  var _a, _b;
684
741
  if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
@@ -754,6 +811,8 @@ function createImaController(video, options) {
754
811
  adContainerEl = void 0;
755
812
  adDisplayContainer = void 0;
756
813
  adsLoader = void 0;
814
+ preloadedVast.clear();
815
+ preloadingVast.clear();
757
816
  },
758
817
  isAdPlaying() {
759
818
  return adPlaying;
@@ -809,6 +868,19 @@ function createImaController(video, options) {
809
868
  }
810
869
  }
811
870
  return 1;
871
+ },
872
+ showPlaceholder() {
873
+ ensurePlaceholderContainer();
874
+ if (adContainerEl) {
875
+ adContainerEl.style.display = "flex";
876
+ adContainerEl.style.pointerEvents = "auto";
877
+ }
878
+ },
879
+ hidePlaceholder() {
880
+ if (adContainerEl) {
881
+ adContainerEl.style.display = "none";
882
+ adContainerEl.style.pointerEvents = "none";
883
+ }
812
884
  }
813
885
  };
814
886
  }
@@ -826,6 +898,8 @@ function createHlsAdPlayer(contentVideo, options) {
826
898
  let adContainerEl;
827
899
  let currentAd;
828
900
  let sessionId;
901
+ const preloadedAds = /* @__PURE__ */ new Map();
902
+ const preloadingAds = /* @__PURE__ */ new Map();
829
903
  let trackingFired = {
830
904
  impression: false,
831
905
  start: false,
@@ -1055,6 +1129,19 @@ function createHlsAdPlayer(contentVideo, options) {
1055
1129
  return null;
1056
1130
  }
1057
1131
  }
1132
+ async function fetchAndParseVastAd(vastTagUrl) {
1133
+ const response = await fetch(vastTagUrl);
1134
+ if (!response.ok) {
1135
+ throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1136
+ }
1137
+ const vastXml = await response.text();
1138
+ console.log("[HlsAdPlayer] VAST XML received");
1139
+ console.log(
1140
+ "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1141
+ vastXml.substring(0, 2e3)
1142
+ );
1143
+ return parseVastXml(vastXml);
1144
+ }
1058
1145
  function createAdVideoElement() {
1059
1146
  const video = document.createElement("video");
1060
1147
  video.style.position = "absolute";
@@ -1206,17 +1293,17 @@ function createHlsAdPlayer(contentVideo, options) {
1206
1293
  }
1207
1294
  try {
1208
1295
  sessionId = generateSessionId();
1209
- const response = await fetch(vastTagUrl);
1210
- if (!response.ok) {
1211
- throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1296
+ let ad;
1297
+ if (preloadedAds.has(vastTagUrl)) {
1298
+ ad = preloadedAds.get(vastTagUrl);
1299
+ preloadedAds.delete(vastTagUrl);
1300
+ console.log(
1301
+ "[HlsAdPlayer] Using preloaded VAST response:",
1302
+ vastTagUrl
1303
+ );
1304
+ } else {
1305
+ ad = await fetchAndParseVastAd(vastTagUrl);
1212
1306
  }
1213
- const vastXml = await response.text();
1214
- console.log("[HlsAdPlayer] VAST XML received");
1215
- console.log(
1216
- "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1217
- vastXml.substring(0, 2e3)
1218
- );
1219
- const ad = parseVastXml(vastXml);
1220
1307
  if (!ad) {
1221
1308
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1222
1309
  emit("ad_error");
@@ -1235,6 +1322,37 @@ function createHlsAdPlayer(contentVideo, options) {
1235
1322
  return Promise.reject(error);
1236
1323
  }
1237
1324
  },
1325
+ async preloadAds(vastTagUrl) {
1326
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
1327
+ return Promise.resolve();
1328
+ }
1329
+ if (preloadedAds.has(vastTagUrl)) {
1330
+ return Promise.resolve();
1331
+ }
1332
+ const inflight = preloadingAds.get(vastTagUrl);
1333
+ if (inflight) {
1334
+ return inflight;
1335
+ }
1336
+ const preloadPromise = fetchAndParseVastAd(vastTagUrl).then((ad) => {
1337
+ if (ad) {
1338
+ preloadedAds.set(vastTagUrl, ad);
1339
+ console.log(
1340
+ "[HlsAdPlayer] Cached VAST response for preloading:",
1341
+ vastTagUrl
1342
+ );
1343
+ }
1344
+ }).catch((error) => {
1345
+ console.warn("[HlsAdPlayer] Failed to preload VAST response:", error);
1346
+ preloadedAds.delete(vastTagUrl);
1347
+ }).finally(() => {
1348
+ preloadingAds.delete(vastTagUrl);
1349
+ });
1350
+ preloadingAds.set(vastTagUrl, preloadPromise);
1351
+ return preloadPromise;
1352
+ },
1353
+ hasPreloadedAd(vastTagUrl) {
1354
+ return preloadedAds.has(vastTagUrl);
1355
+ },
1238
1356
  async play() {
1239
1357
  if (!currentAd) {
1240
1358
  console.warn(
@@ -1365,6 +1483,8 @@ function createHlsAdPlayer(contentVideo, options) {
1365
1483
  adContainerEl = void 0;
1366
1484
  currentAd = void 0;
1367
1485
  listeners.clear();
1486
+ preloadedAds.clear();
1487
+ preloadingAds.clear();
1368
1488
  },
1369
1489
  isAdPlaying() {
1370
1490
  return adPlaying;
@@ -1407,6 +1527,35 @@ function createHlsAdPlayer(contentVideo, options) {
1407
1527
  return adVideoElement.volume;
1408
1528
  }
1409
1529
  return 1;
1530
+ },
1531
+ showPlaceholder() {
1532
+ var _a;
1533
+ if (!adContainerEl) {
1534
+ const container = document.createElement("div");
1535
+ container.style.position = "absolute";
1536
+ container.style.left = "0";
1537
+ container.style.top = "0";
1538
+ container.style.right = "0";
1539
+ container.style.bottom = "0";
1540
+ container.style.display = "none";
1541
+ container.style.alignItems = "center";
1542
+ container.style.justifyContent = "center";
1543
+ container.style.pointerEvents = "none";
1544
+ container.style.zIndex = "10";
1545
+ container.style.backgroundColor = "#000";
1546
+ (_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
1547
+ adContainerEl = container;
1548
+ }
1549
+ if (adContainerEl) {
1550
+ adContainerEl.style.display = "flex";
1551
+ adContainerEl.style.pointerEvents = "auto";
1552
+ }
1553
+ },
1554
+ hidePlaceholder() {
1555
+ if (adContainerEl) {
1556
+ adContainerEl.style.display = "none";
1557
+ adContainerEl.style.pointerEvents = "none";
1558
+ }
1410
1559
  }
1411
1560
  };
1412
1561
  }
@@ -1887,6 +2036,8 @@ var StormcloudVideoPlayer = class {
1887
2036
  this.bufferedSegmentsCount = 0;
1888
2037
  this.shouldAutoplayAfterBuffering = false;
1889
2038
  this.hasInitialBufferCompleted = false;
2039
+ this.adPodAllUrls = [];
2040
+ this.preloadingAdUrls = /* @__PURE__ */ new Set();
1890
2041
  initializePolyfills();
1891
2042
  const browserOverrides = getBrowserConfigOverrides();
1892
2043
  this.config = { ...config, ...browserOverrides };
@@ -2187,6 +2338,7 @@ var StormcloudVideoPlayer = class {
2187
2338
  console.log("[StormcloudVideoPlayer] IMA content_pause event received");
2188
2339
  }
2189
2340
  this.clearAdFailsafeTimer();
2341
+ this.enforceAdHoldState();
2190
2342
  });
2191
2343
  this.ima.on("content_resume", () => {
2192
2344
  if (this.config.debugAdTiming) {
@@ -2211,12 +2363,10 @@ var StormcloudVideoPlayer = class {
2211
2363
  if (remaining > 500 && this.adPodQueue.length > 0) {
2212
2364
  const next = this.adPodQueue.shift();
2213
2365
  this.currentAdIndex++;
2214
- this.video.dataset.stormcloudAdPlaying = "true";
2215
- this.video.muted = true;
2216
- this.video.volume = 0;
2366
+ this.enforceAdHoldState();
2217
2367
  if (this.config.debugAdTiming) {
2218
2368
  console.log(
2219
- `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - main video stays muted, ad layer stays visible`
2369
+ `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
2220
2370
  );
2221
2371
  }
2222
2372
  this.playSingleAd(next).catch(() => {
@@ -2801,25 +2951,21 @@ var StormcloudVideoPlayer = class {
2801
2951
  this.video.currentTime * 1e3
2802
2952
  );
2803
2953
  const tags = this.selectVastTagsForBreak(scheduled);
2804
- let vastTagUrl;
2954
+ let vastTagUrls = [];
2805
2955
  if (this.apiVastTagUrl) {
2806
- vastTagUrl = this.apiVastTagUrl;
2807
- this.adPodQueue = [];
2808
- this.currentAdIndex = 0;
2809
- this.totalAdsInBreak = 1;
2956
+ vastTagUrls = [this.apiVastTagUrl];
2810
2957
  if (this.config.debugAdTiming) {
2811
- console.log("[StormcloudVideoPlayer] Using VAST endpoint:", vastTagUrl);
2958
+ console.log(
2959
+ "[StormcloudVideoPlayer] Using VAST endpoint:",
2960
+ this.apiVastTagUrl
2961
+ );
2812
2962
  }
2813
2963
  } else if (tags && tags.length > 0) {
2814
- vastTagUrl = tags[0];
2815
- const rest = tags.slice(1);
2816
- this.adPodQueue = rest;
2817
- this.currentAdIndex = 0;
2818
- this.totalAdsInBreak = tags.length;
2964
+ vastTagUrls = tags;
2819
2965
  if (this.config.debugAdTiming) {
2820
2966
  console.log(
2821
- "[StormcloudVideoPlayer] Using scheduled VAST tag:",
2822
- vastTagUrl
2967
+ "[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
2968
+ tags
2823
2969
  );
2824
2970
  }
2825
2971
  } else {
@@ -2828,16 +2974,28 @@ var StormcloudVideoPlayer = class {
2828
2974
  }
2829
2975
  return;
2830
2976
  }
2831
- if (vastTagUrl) {
2977
+ if (vastTagUrls.length > 0) {
2978
+ this.adPodAllUrls = [...vastTagUrls];
2979
+ this.preloadingAdUrls.clear();
2980
+ this.logQueuedAdUrls(this.adPodAllUrls);
2832
2981
  this.inAdBreak = true;
2833
2982
  this.showAds = true;
2834
- this.currentAdIndex++;
2983
+ this.currentAdIndex = 0;
2984
+ this.totalAdsInBreak = vastTagUrls.length;
2985
+ this.adPodQueue = [...vastTagUrls];
2986
+ this.enforceAdHoldState();
2987
+ this.preloadUpcomingAds();
2988
+ if (this.config.debugAdTiming) {
2989
+ console.log(
2990
+ `[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
2991
+ );
2992
+ }
2835
2993
  try {
2836
- await this.playSingleAd(vastTagUrl);
2994
+ await this.playAdPod();
2837
2995
  } catch (error) {
2838
2996
  if (this.config.debugAdTiming) {
2839
2997
  console.error(
2840
- "[StormcloudVideoPlayer] Ad playback failed in handleAdStart:",
2998
+ "[StormcloudVideoPlayer] Ad pod playback failed:",
2841
2999
  error
2842
3000
  );
2843
3001
  }
@@ -2850,6 +3008,22 @@ var StormcloudVideoPlayer = class {
2850
3008
  this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
2851
3009
  }
2852
3010
  }
3011
+ async playAdPod() {
3012
+ if (this.adPodQueue.length === 0) {
3013
+ if (this.config.debugAdTiming) {
3014
+ console.log("[StormcloudVideoPlayer] No ads in pod to play");
3015
+ }
3016
+ return;
3017
+ }
3018
+ const firstAd = this.adPodQueue.shift();
3019
+ this.currentAdIndex++;
3020
+ if (this.config.debugAdTiming) {
3021
+ console.log(
3022
+ `[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
3023
+ );
3024
+ }
3025
+ await this.playSingleAd(firstAd);
3026
+ }
2853
3027
  findCurrentOrNextBreak(nowMs) {
2854
3028
  var _a;
2855
3029
  const schedule = [];
@@ -2881,6 +3055,7 @@ var StormcloudVideoPlayer = class {
2881
3055
  const first = tags[0];
2882
3056
  const rest = tags.slice(1);
2883
3057
  this.adPodQueue = rest;
3058
+ this.enforceAdHoldState();
2884
3059
  await this.playSingleAd(first);
2885
3060
  this.inAdBreak = true;
2886
3061
  this.expectedAdBreakDurationMs = remainingMs;
@@ -2994,6 +3169,12 @@ var StormcloudVideoPlayer = class {
2994
3169
  }
2995
3170
  return;
2996
3171
  }
3172
+ const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
3173
+ if (wasPreloaded && this.config.debugAdTiming) {
3174
+ console.log(
3175
+ `[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
3176
+ );
3177
+ }
2997
3178
  if (!this.showAds) {
2998
3179
  if (this.config.debugAdTiming) {
2999
3180
  console.log(
@@ -3014,12 +3195,14 @@ var StormcloudVideoPlayer = class {
3014
3195
  this.startAdFailsafeTimer();
3015
3196
  try {
3016
3197
  await this.ima.requestAds(vastTagUrl);
3198
+ this.preloadUpcomingAds();
3017
3199
  try {
3018
3200
  if (this.config.debugAdTiming) {
3019
3201
  console.log(
3020
3202
  "[StormcloudVideoPlayer] Ad request completed, attempting playback"
3021
3203
  );
3022
3204
  }
3205
+ this.enforceAdHoldState();
3023
3206
  await this.ima.play();
3024
3207
  if (this.config.debugAdTiming) {
3025
3208
  console.log(
@@ -3049,6 +3232,8 @@ var StormcloudVideoPlayer = class {
3049
3232
  "[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
3050
3233
  );
3051
3234
  }
3235
+ this.releaseAdHoldState();
3236
+ this.preloadingAdUrls.clear();
3052
3237
  this.inAdBreak = false;
3053
3238
  this.expectedAdBreakDurationMs = void 0;
3054
3239
  this.currentAdBreakStartWallClockMs = void 0;
@@ -3056,6 +3241,7 @@ var StormcloudVideoPlayer = class {
3056
3241
  this.clearAdStopTimer();
3057
3242
  this.clearAdFailsafeTimer();
3058
3243
  this.adPodQueue = [];
3244
+ this.adPodAllUrls = [];
3059
3245
  this.showAds = false;
3060
3246
  this.currentAdIndex = 0;
3061
3247
  this.totalAdsInBreak = 0;
@@ -3136,6 +3322,64 @@ var StormcloudVideoPlayer = class {
3136
3322
  }
3137
3323
  return [b.vastTagUrl];
3138
3324
  }
3325
+ logQueuedAdUrls(urls) {
3326
+ if (!this.config.debugAdTiming) {
3327
+ return;
3328
+ }
3329
+ console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
3330
+ }
3331
+ enforceAdHoldState() {
3332
+ this.video.dataset.stormcloudAdPlaying = "true";
3333
+ this.video.muted = true;
3334
+ this.video.volume = 0;
3335
+ if (typeof this.ima.showPlaceholder === "function") {
3336
+ this.ima.showPlaceholder();
3337
+ }
3338
+ }
3339
+ releaseAdHoldState() {
3340
+ delete this.video.dataset.stormcloudAdPlaying;
3341
+ if (typeof this.ima.hidePlaceholder === "function") {
3342
+ this.ima.hidePlaceholder();
3343
+ }
3344
+ }
3345
+ preloadUpcomingAds() {
3346
+ if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
3347
+ return;
3348
+ }
3349
+ const upcoming = this.adPodQueue.slice(0, 2);
3350
+ for (const url of upcoming) {
3351
+ if (!url) continue;
3352
+ if (this.ima.hasPreloadedAd(url)) {
3353
+ this.preloadingAdUrls.delete(url);
3354
+ continue;
3355
+ }
3356
+ if (this.preloadingAdUrls.has(url)) {
3357
+ continue;
3358
+ }
3359
+ if (this.config.debugAdTiming) {
3360
+ console.log(
3361
+ `[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
3362
+ );
3363
+ }
3364
+ this.preloadingAdUrls.add(url);
3365
+ this.ima.preloadAds(url).then(() => {
3366
+ if (this.config.debugAdTiming) {
3367
+ console.log(
3368
+ `[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
3369
+ );
3370
+ }
3371
+ }).catch((error) => {
3372
+ if (this.config.debugAdTiming) {
3373
+ console.warn(
3374
+ `[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
3375
+ error
3376
+ );
3377
+ }
3378
+ }).finally(() => {
3379
+ this.preloadingAdUrls.delete(url);
3380
+ });
3381
+ }
3382
+ }
3139
3383
  getRemainingAdMs() {
3140
3384
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
3141
3385
  return 0;
@@ -3287,6 +3531,9 @@ var StormcloudVideoPlayer = class {
3287
3531
  }
3288
3532
  (_a = this.hls) == null ? void 0 : _a.destroy();
3289
3533
  (_b = this.ima) == null ? void 0 : _b.destroy();
3534
+ this.releaseAdHoldState();
3535
+ this.preloadingAdUrls.clear();
3536
+ this.adPodAllUrls = [];
3290
3537
  }
3291
3538
  };
3292
3539