stormcloud-video-player 0.2.5 → 0.2.6

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.d.cts CHANGED
@@ -28,15 +28,6 @@ interface StormcloudVideoPlayerConfig {
28
28
  onFullscreenToggle?: () => void;
29
29
  onControlClick?: () => void;
30
30
  licenseKey?: string;
31
- adBreakGapToleranceMs?: number;
32
- maxAdsPerBreak?: number;
33
- minAdDurationMs?: number;
34
- enableAdPreloading?: boolean;
35
- }
36
- interface AdInfo {
37
- duration: number;
38
- vastTagUrl: string;
39
- isPreloaded: boolean;
40
31
  }
41
32
  interface ClientInfo {
42
33
  brand: string;
@@ -101,9 +92,6 @@ declare class StormcloudVideoPlayer {
101
92
  private totalAdsInBreak;
102
93
  private showAds;
103
94
  private isLiveStream;
104
- private preloadedAdInfo;
105
- private currentAdBreakTargetDurationMs;
106
- private cumulativeAdDurationMs;
107
95
  constructor(config: StormcloudVideoPlayerConfig);
108
96
  load(): Promise<void>;
109
97
  private attach;
@@ -125,20 +113,9 @@ declare class StormcloudVideoPlayer {
125
113
  getTotalAdsInBreak(): number;
126
114
  isAdPlaying(): boolean;
127
115
  isShowingAds(): boolean;
128
- getAdBreakStats(): {
129
- isInAdBreak: boolean;
130
- currentAdIndex: number;
131
- totalAdsInBreak: number;
132
- targetDurationMs: number | undefined;
133
- cumulativeDurationMs: number;
134
- estimatedFillRate: number | undefined;
135
- remainingDurationMs: number | undefined;
136
- };
137
- getPreloadedAdInfo(): AdInfo[];
138
116
  getStreamType(): "hls" | "other";
139
117
  shouldShowNativeControls(): boolean;
140
118
  private shouldContinueLiveStreamDuringAds;
141
- loadDefaultVastFromAdstorm(adstormApiUrl: string, params?: Record<string, string>): Promise<void>;
142
119
  private handleAdStart;
143
120
  private findCurrentOrNextBreak;
144
121
  private onTimeUpdate;
@@ -151,16 +128,9 @@ declare class StormcloudVideoPlayer {
151
128
  private updatePtsDrift;
152
129
  private playSingleAd;
153
130
  private handleAdFailure;
154
- private endAdBreak;
155
- private shouldContinueAdBreak;
156
- private canRequestMoreAds;
157
- private requestAdditionalAds;
158
131
  private startAdFailsafeTimer;
159
132
  private clearAdFailsafeTimer;
160
133
  private selectVastTagsForBreak;
161
- private buildAdQueueForDuration;
162
- private getEstimatedAdDuration;
163
- private getAdInfoForQueue;
164
134
  private getRemainingAdMs;
165
135
  private findBreakForTime;
166
136
  toggleMute(): void;
package/lib/index.d.ts CHANGED
@@ -28,15 +28,6 @@ interface StormcloudVideoPlayerConfig {
28
28
  onFullscreenToggle?: () => void;
29
29
  onControlClick?: () => void;
30
30
  licenseKey?: string;
31
- adBreakGapToleranceMs?: number;
32
- maxAdsPerBreak?: number;
33
- minAdDurationMs?: number;
34
- enableAdPreloading?: boolean;
35
- }
36
- interface AdInfo {
37
- duration: number;
38
- vastTagUrl: string;
39
- isPreloaded: boolean;
40
31
  }
41
32
  interface ClientInfo {
42
33
  brand: string;
@@ -101,9 +92,6 @@ declare class StormcloudVideoPlayer {
101
92
  private totalAdsInBreak;
102
93
  private showAds;
103
94
  private isLiveStream;
104
- private preloadedAdInfo;
105
- private currentAdBreakTargetDurationMs;
106
- private cumulativeAdDurationMs;
107
95
  constructor(config: StormcloudVideoPlayerConfig);
108
96
  load(): Promise<void>;
109
97
  private attach;
@@ -125,20 +113,9 @@ declare class StormcloudVideoPlayer {
125
113
  getTotalAdsInBreak(): number;
126
114
  isAdPlaying(): boolean;
127
115
  isShowingAds(): boolean;
128
- getAdBreakStats(): {
129
- isInAdBreak: boolean;
130
- currentAdIndex: number;
131
- totalAdsInBreak: number;
132
- targetDurationMs: number | undefined;
133
- cumulativeDurationMs: number;
134
- estimatedFillRate: number | undefined;
135
- remainingDurationMs: number | undefined;
136
- };
137
- getPreloadedAdInfo(): AdInfo[];
138
116
  getStreamType(): "hls" | "other";
139
117
  shouldShowNativeControls(): boolean;
140
118
  private shouldContinueLiveStreamDuringAds;
141
- loadDefaultVastFromAdstorm(adstormApiUrl: string, params?: Record<string, string>): Promise<void>;
142
119
  private handleAdStart;
143
120
  private findCurrentOrNextBreak;
144
121
  private onTimeUpdate;
@@ -151,16 +128,9 @@ declare class StormcloudVideoPlayer {
151
128
  private updatePtsDrift;
152
129
  private playSingleAd;
153
130
  private handleAdFailure;
154
- private endAdBreak;
155
- private shouldContinueAdBreak;
156
- private canRequestMoreAds;
157
- private requestAdditionalAds;
158
131
  private startAdFailsafeTimer;
159
132
  private clearAdFailsafeTimer;
160
133
  private selectVastTagsForBreak;
161
- private buildAdQueueForDuration;
162
- private getEstimatedAdDuration;
163
- private getAdInfoForQueue;
164
134
  private getRemainingAdMs;
165
135
  private findBreakForTime;
166
136
  toggleMute(): void;
package/lib/index.js CHANGED
@@ -68,8 +68,6 @@ function createImaController(video, options) {
68
68
  let adsLoadedPromise;
69
69
  let adsLoadedResolve;
70
70
  let adsLoadedReject;
71
- let currentAdDuration = 0;
72
- let preloadedAds = [];
73
71
  function makeAdsRequest(google, vastTagUrl) {
74
72
  const adsRequest = new google.ima.AdsRequest();
75
73
  adsRequest.adTagUrl = vastTagUrl;
@@ -176,7 +174,6 @@ function createImaController(video, options) {
176
174
  } catch {
177
175
  }
178
176
  adPlaying = false;
179
- currentAdDuration = 0;
180
177
  video.muted = originalMutedState;
181
178
  if (adContainerEl)
182
179
  adContainerEl.style.pointerEvents = "none";
@@ -248,22 +245,9 @@ function createImaController(video, options) {
248
245
  emit("content_resume");
249
246
  }
250
247
  );
251
- adsManager.addEventListener(AdEvent.STARTED, (adEvent) => {
252
- console.log("[IMA] Ad started");
253
- try {
254
- const ad = adEvent.getAd();
255
- if (ad && ad.getDuration) {
256
- currentAdDuration = ad.getDuration();
257
- console.log(`[IMA] Ad duration: ${currentAdDuration}s`);
258
- }
259
- } catch (error) {
260
- console.warn("[IMA] Could not get ad duration:", error);
261
- }
262
- });
263
248
  adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, () => {
264
249
  console.log("[IMA] All ads completed");
265
250
  adPlaying = false;
266
- currentAdDuration = 0;
267
251
  video.muted = originalMutedState;
268
252
  if (adContainerEl) adContainerEl.style.pointerEvents = "none";
269
253
  if (!options?.continueLiveStreamDuringAds) {
@@ -448,84 +432,6 @@ function createImaController(video, options) {
448
432
  }
449
433
  }
450
434
  return 1;
451
- },
452
- getAdDuration() {
453
- return currentAdDuration;
454
- },
455
- async preloadAds(vastTagUrls) {
456
- console.log(`[IMA] Preloading ${vastTagUrls.length} ads`);
457
- const adInfos = [];
458
- for (const vastTagUrl of vastTagUrls) {
459
- try {
460
- await ensureImaLoaded();
461
- const google = window.google;
462
- const tempAdsLoader = new google.ima.AdsLoader(adDisplayContainer);
463
- const adInfo = await new Promise((resolve, reject) => {
464
- const timeout = setTimeout(() => {
465
- reject(new Error("Preload timeout"));
466
- }, 5e3);
467
- tempAdsLoader.addEventListener(
468
- google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
469
- (evt) => {
470
- clearTimeout(timeout);
471
- try {
472
- const tempAdsManager = evt.getAdsManager(video);
473
- let duration = 30;
474
- try {
475
- const ads = tempAdsManager.getCuePoints?.() || [];
476
- if (ads.length > 0) {
477
- duration = 15;
478
- }
479
- } catch {
480
- }
481
- tempAdsManager.destroy();
482
- resolve({
483
- duration,
484
- vastTagUrl,
485
- isPreloaded: true
486
- });
487
- } catch (error) {
488
- clearTimeout(timeout);
489
- reject(error);
490
- }
491
- }
492
- );
493
- tempAdsLoader.addEventListener(
494
- google.ima.AdErrorEvent.Type.AD_ERROR,
495
- (errorEvent) => {
496
- clearTimeout(timeout);
497
- console.warn(
498
- `[IMA] Preload error for ${vastTagUrl}:`,
499
- errorEvent.getError()
500
- );
501
- resolve({
502
- duration: 30,
503
- vastTagUrl,
504
- isPreloaded: false
505
- });
506
- }
507
- );
508
- const adsRequest = new google.ima.AdsRequest();
509
- adsRequest.adTagUrl = vastTagUrl;
510
- tempAdsLoader.requestAds(adsRequest);
511
- });
512
- adInfos.push(adInfo);
513
- tempAdsLoader.destroy();
514
- } catch (error) {
515
- console.warn(`[IMA] Failed to preload ad ${vastTagUrl}:`, error);
516
- adInfos.push({
517
- duration: 30,
518
- vastTagUrl,
519
- isPreloaded: false
520
- });
521
- }
522
- }
523
- preloadedAds = adInfos;
524
- console.log(
525
- `[IMA] Preloaded ${adInfos.length} ads with total duration:`,
526
- adInfos.reduce((sum, ad) => sum + ad.duration, 0)
527
- );
528
- return adInfos;
529
435
  }
530
436
  };
531
437
  }
@@ -758,8 +664,6 @@ var StormcloudVideoPlayer = class {
758
664
  this.totalAdsInBreak = 0;
759
665
  this.showAds = false;
760
666
  this.isLiveStream = false;
761
- this.preloadedAdInfo = [];
762
- this.cumulativeAdDurationMs = 0;
763
667
  this.config = config;
764
668
  this.video = config.videoElement;
765
669
  this.ima = createImaController(this.video, {
@@ -931,28 +835,16 @@ var StormcloudVideoPlayer = class {
931
835
  this.ima.initialize();
932
836
  this.ima.on("all_ads_completed", () => {
933
837
  if (!this.inAdBreak) return;
934
- const actualAdDuration = this.ima.getAdDuration();
935
- if (actualAdDuration > 0) {
936
- this.cumulativeAdDurationMs += actualAdDuration * 1e3;
937
- if (this.config.debugAdTiming) {
938
- console.log(
939
- `[StormcloudVideoPlayer] Ad completed. Duration: ${actualAdDuration}s, Cumulative: ${this.cumulativeAdDurationMs}ms`
940
- );
941
- }
942
- }
943
838
  const remaining = this.getRemainingAdMs();
944
- const shouldContinue = this.shouldContinueAdBreak(remaining);
945
- if (shouldContinue && this.adPodQueue.length > 0) {
839
+ if (remaining > 500 && this.adPodQueue.length > 0) {
946
840
  const next = this.adPodQueue.shift();
947
841
  this.currentAdIndex++;
948
842
  this.playSingleAd(next).catch(() => {
949
843
  });
950
- } else if (shouldContinue && this.canRequestMoreAds()) {
951
- this.requestAdditionalAds().catch(() => {
952
- this.endAdBreak();
953
- });
954
844
  } else {
955
- this.endAdBreak();
845
+ this.currentAdIndex = 0;
846
+ this.totalAdsInBreak = 0;
847
+ this.showAds = false;
956
848
  }
957
849
  });
958
850
  this.ima.on("ad_error", () => {
@@ -961,16 +853,11 @@ var StormcloudVideoPlayer = class {
961
853
  }
962
854
  if (!this.inAdBreak) return;
963
855
  const remaining = this.getRemainingAdMs();
964
- const shouldContinue = this.shouldContinueAdBreak(remaining);
965
- if (shouldContinue && this.adPodQueue.length > 0) {
856
+ if (remaining > 500 && this.adPodQueue.length > 0) {
966
857
  const next = this.adPodQueue.shift();
967
858
  this.currentAdIndex++;
968
859
  this.playSingleAd(next).catch(() => {
969
860
  });
970
- } else if (shouldContinue && this.canRequestMoreAds()) {
971
- this.requestAdditionalAds().catch(() => {
972
- this.handleAdFailure();
973
- });
974
861
  } else {
975
862
  this.handleAdFailure();
976
863
  }
@@ -1461,25 +1348,6 @@ var StormcloudVideoPlayer = class {
1461
1348
  isShowingAds() {
1462
1349
  return this.showAds;
1463
1350
  }
1464
- getAdBreakStats() {
1465
- const remainingDurationMs = this.currentAdBreakTargetDurationMs != null ? Math.max(
1466
- 0,
1467
- this.currentAdBreakTargetDurationMs - this.cumulativeAdDurationMs
1468
- ) : void 0;
1469
- const estimatedFillRate = this.currentAdBreakTargetDurationMs != null && this.currentAdBreakTargetDurationMs > 0 ? this.cumulativeAdDurationMs / this.currentAdBreakTargetDurationMs * 100 : void 0;
1470
- return {
1471
- isInAdBreak: this.inAdBreak,
1472
- currentAdIndex: this.currentAdIndex,
1473
- totalAdsInBreak: this.totalAdsInBreak,
1474
- targetDurationMs: this.currentAdBreakTargetDurationMs,
1475
- cumulativeDurationMs: this.cumulativeAdDurationMs,
1476
- estimatedFillRate,
1477
- remainingDurationMs
1478
- };
1479
- }
1480
- getPreloadedAdInfo() {
1481
- return [...this.preloadedAdInfo];
1482
- }
1483
1351
  getStreamType() {
1484
1352
  const url = this.config.src.toLowerCase();
1485
1353
  if (url.includes(".m3u8") || url.includes("/hls/") || url.includes("application/vnd.apple.mpegurl")) {
@@ -1503,70 +1371,59 @@ var StormcloudVideoPlayer = class {
1503
1371
  }
1504
1372
  return true;
1505
1373
  }
1506
- async loadDefaultVastFromAdstorm(adstormApiUrl, params) {
1507
- const usp = new URLSearchParams(params || {});
1508
- const url = `${adstormApiUrl}?${usp.toString()}`;
1509
- const res = await fetch(url);
1510
- if (!res.ok) throw new Error(`Failed to fetch adstorm ads: ${res.status}`);
1511
- const data = await res.json();
1512
- const tag = data?.adTagUrl || data?.vastTagUrl || data?.tagUrl;
1513
- if (typeof tag === "string" && tag.length > 0) {
1514
- this.apiVastTagUrl = tag;
1515
- }
1516
- }
1517
- async handleAdStart(marker) {
1374
+ async handleAdStart(_marker) {
1518
1375
  const scheduled = this.findCurrentOrNextBreak(
1519
1376
  this.video.currentTime * 1e3
1520
1377
  );
1521
- let targetDurationMs = this.expectedAdBreakDurationMs;
1522
- if (!targetDurationMs && scheduled?.durationMs != null) {
1523
- targetDurationMs = scheduled.durationMs;
1524
- }
1525
- if (!targetDurationMs && marker.durationSeconds != null) {
1526
- targetDurationMs = marker.durationSeconds * 1e3;
1527
- }
1528
- this.currentAdBreakTargetDurationMs = targetDurationMs;
1529
- this.cumulativeAdDurationMs = 0;
1530
- if (this.config.debugAdTiming) {
1531
- console.log(
1532
- "[StormcloudVideoPlayer] Starting ad break with target duration:",
1533
- {
1534
- targetDurationMs,
1535
- scte35Duration: marker.durationSeconds,
1536
- scheduledDuration: scheduled?.durationMs
1378
+ const tags = this.selectVastTagsForBreak(scheduled);
1379
+ let vastTagUrl;
1380
+ let adsNumber = 1;
1381
+ if (this.apiVastTagUrl) {
1382
+ vastTagUrl = this.apiVastTagUrl;
1383
+ if (this.vastConfig) {
1384
+ const isHls = this.config.src.includes(".m3u8") || this.config.src.includes("hls");
1385
+ if (isHls && this.vastConfig.cue_tones?.number_ads) {
1386
+ adsNumber = this.vastConfig.cue_tones.number_ads;
1387
+ } else if (!isHls && this.vastConfig.timer_vod?.number_ads) {
1388
+ adsNumber = this.vastConfig.timer_vod.number_ads;
1537
1389
  }
1538
- );
1539
- }
1540
- const adQueue = await this.buildAdQueueForDuration(targetDurationMs);
1541
- if (adQueue.length === 0) {
1390
+ }
1391
+ this.adPodQueue = new Array(adsNumber - 1).fill(vastTagUrl);
1392
+ this.currentAdIndex = 0;
1393
+ this.totalAdsInBreak = adsNumber;
1542
1394
  if (this.config.debugAdTiming) {
1543
- console.log("[StormcloudVideoPlayer] No ads available for ad break");
1395
+ console.log(
1396
+ `[StormcloudVideoPlayer] Using API VAST tag with ${adsNumber} ads:`,
1397
+ vastTagUrl
1398
+ );
1399
+ }
1400
+ } else if (tags && tags.length > 0) {
1401
+ vastTagUrl = tags[0];
1402
+ const rest = tags.slice(1);
1403
+ this.adPodQueue = rest;
1404
+ this.currentAdIndex = 0;
1405
+ this.totalAdsInBreak = tags.length;
1406
+ if (this.config.debugAdTiming) {
1407
+ console.log(
1408
+ "[StormcloudVideoPlayer] Using scheduled VAST tag:",
1409
+ vastTagUrl
1410
+ );
1411
+ }
1412
+ } else {
1413
+ if (this.config.debugAdTiming) {
1414
+ console.log("[StormcloudVideoPlayer] No VAST tag available for ad");
1544
1415
  }
1545
1416
  return;
1546
1417
  }
1547
- this.adPodQueue = adQueue.slice(1);
1548
- this.preloadedAdInfo = await this.getAdInfoForQueue(adQueue);
1549
- this.currentAdIndex = 0;
1550
- this.totalAdsInBreak = adQueue.length;
1551
- this.showAds = true;
1552
- if (this.config.debugAdTiming) {
1553
- const totalEstimatedDuration = this.preloadedAdInfo.reduce(
1554
- (sum, ad) => sum + ad.duration,
1555
- 0
1556
- );
1557
- console.log("[StormcloudVideoPlayer] Ad queue built:", {
1558
- totalAds: adQueue.length,
1559
- estimatedTotalDuration: totalEstimatedDuration,
1560
- targetDuration: targetDurationMs ? targetDurationMs / 1e3 : "unknown",
1561
- fillRate: targetDurationMs ? totalEstimatedDuration * 1e3 / targetDurationMs : "unknown"
1562
- });
1418
+ if (vastTagUrl) {
1419
+ this.showAds = true;
1420
+ this.currentAdIndex++;
1421
+ await this.playSingleAd(vastTagUrl);
1563
1422
  }
1564
- this.currentAdIndex++;
1565
- await this.playSingleAd(adQueue[0]);
1566
- if (targetDurationMs != null) {
1567
- this.expectedAdBreakDurationMs = targetDurationMs;
1423
+ if (this.expectedAdBreakDurationMs == null && scheduled?.durationMs != null) {
1424
+ this.expectedAdBreakDurationMs = scheduled.durationMs;
1568
1425
  this.currentAdBreakStartWallClockMs = this.currentAdBreakStartWallClockMs ?? Date.now();
1569
- this.scheduleAdStopCountdown(targetDurationMs);
1426
+ this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
1570
1427
  }
1571
1428
  }
1572
1429
  findCurrentOrNextBreak(nowMs) {
@@ -1683,89 +1540,25 @@ var StormcloudVideoPlayer = class {
1683
1540
  "[StormcloudVideoPlayer] Handling ad failure - resuming content"
1684
1541
  );
1685
1542
  }
1686
- this.endAdBreak();
1687
- if (this.video.paused) {
1688
- this.video.play().catch(() => {
1689
- if (this.config.debugAdTiming) {
1690
- console.error(
1691
- "[StormcloudVideoPlayer] Failed to resume video after ad failure"
1692
- );
1693
- }
1694
- });
1695
- }
1696
- }
1697
- endAdBreak() {
1698
- if (this.config.debugAdTiming) {
1699
- const targetDuration = this.currentAdBreakTargetDurationMs ? this.currentAdBreakTargetDurationMs / 1e3 : "unknown";
1700
- const actualDuration = this.cumulativeAdDurationMs / 1e3;
1701
- const fillRate = this.currentAdBreakTargetDurationMs ? (this.cumulativeAdDurationMs / this.currentAdBreakTargetDurationMs * 100).toFixed(1) : "unknown";
1702
- console.log("[StormcloudVideoPlayer] Ad break ended:", {
1703
- targetDurationSeconds: targetDuration,
1704
- actualDurationSeconds: actualDuration,
1705
- fillRate: `${fillRate}%`,
1706
- totalAdsPlayed: this.currentAdIndex
1707
- });
1708
- }
1709
1543
  this.inAdBreak = false;
1710
1544
  this.expectedAdBreakDurationMs = void 0;
1711
1545
  this.currentAdBreakStartWallClockMs = void 0;
1712
- this.currentAdBreakTargetDurationMs = void 0;
1713
- this.cumulativeAdDurationMs = 0;
1714
1546
  this.clearAdStartTimer();
1715
1547
  this.clearAdStopTimer();
1716
1548
  this.clearAdFailsafeTimer();
1717
1549
  this.adPodQueue = [];
1718
- this.preloadedAdInfo = [];
1719
1550
  this.showAds = false;
1720
1551
  this.currentAdIndex = 0;
1721
1552
  this.totalAdsInBreak = 0;
1722
- }
1723
- shouldContinueAdBreak(remainingMs) {
1724
- if (remainingMs > 500) {
1725
- return true;
1726
- }
1727
- if (this.currentAdBreakTargetDurationMs) {
1728
- const targetRemainingMs = this.currentAdBreakTargetDurationMs - this.cumulativeAdDurationMs;
1729
- const minAdDuration = this.config.minAdDurationMs ?? 5e3;
1730
- if (targetRemainingMs > minAdDuration) {
1553
+ if (this.video.paused) {
1554
+ this.video.play().catch(() => {
1731
1555
  if (this.config.debugAdTiming) {
1732
- console.log(
1733
- `[StormcloudVideoPlayer] Target duration not filled, continuing. Remaining: ${targetRemainingMs}ms`
1556
+ console.error(
1557
+ "[StormcloudVideoPlayer] Failed to resume video after ad failure"
1734
1558
  );
1735
1559
  }
1736
- return true;
1737
- }
1738
- }
1739
- return false;
1740
- }
1741
- canRequestMoreAds() {
1742
- const maxAdsPerBreak = this.config.maxAdsPerBreak ?? 10;
1743
- if (this.currentAdIndex >= maxAdsPerBreak) {
1744
- return false;
1745
- }
1746
- return !!this.apiVastTagUrl;
1747
- }
1748
- async requestAdditionalAds() {
1749
- if (!this.currentAdBreakTargetDurationMs || !this.apiVastTagUrl) {
1750
- throw new Error(
1751
- "Cannot request additional ads without target duration and VAST URL"
1752
- );
1753
- }
1754
- const remainingDurationMs = this.currentAdBreakTargetDurationMs - this.cumulativeAdDurationMs;
1755
- const estimatedAdDurationMs = this.getEstimatedAdDuration() * 1e3;
1756
- if (remainingDurationMs < estimatedAdDurationMs * 0.5) {
1757
- throw new Error("Not enough time remaining for additional ads");
1758
- }
1759
- if (this.config.debugAdTiming) {
1760
- console.log(
1761
- `[StormcloudVideoPlayer] Requesting additional ads for remaining ${remainingDurationMs}ms`
1762
- );
1560
+ });
1763
1561
  }
1764
- this.adPodQueue.push(this.apiVastTagUrl);
1765
- this.totalAdsInBreak++;
1766
- const next = this.adPodQueue.shift();
1767
- this.currentAdIndex++;
1768
- await this.playSingleAd(next);
1769
1562
  }
1770
1563
  startAdFailsafeTimer() {
1771
1564
  this.clearAdFailsafeTimer();
@@ -1799,109 +1592,6 @@ var StormcloudVideoPlayer = class {
1799
1592
  }
1800
1593
  return [b.vastTagUrl];
1801
1594
  }
1802
- async buildAdQueueForDuration(targetDurationMs) {
1803
- const adQueue = [];
1804
- let baseVastTagUrl = this.apiVastTagUrl;
1805
- if (!baseVastTagUrl) {
1806
- const scheduled = this.findCurrentOrNextBreak(
1807
- this.video.currentTime * 1e3
1808
- );
1809
- const scheduledTags = this.selectVastTagsForBreak(scheduled);
1810
- if (scheduledTags && scheduledTags.length > 0) {
1811
- baseVastTagUrl = scheduledTags[0];
1812
- }
1813
- }
1814
- if (!baseVastTagUrl) {
1815
- return adQueue;
1816
- }
1817
- if (!targetDurationMs) {
1818
- let adsNumber = 1;
1819
- if (this.vastConfig) {
1820
- const isHls = this.config.src.includes(".m3u8") || this.config.src.includes("hls");
1821
- if (isHls && this.vastConfig.cue_tones?.number_ads) {
1822
- adsNumber = this.vastConfig.cue_tones.number_ads;
1823
- } else if (!isHls && this.vastConfig.timer_vod?.number_ads) {
1824
- adsNumber = this.vastConfig.timer_vod.number_ads;
1825
- }
1826
- }
1827
- return new Array(adsNumber).fill(baseVastTagUrl);
1828
- }
1829
- const targetDurationSeconds = targetDurationMs / 1e3;
1830
- let cumulativeDurationSeconds = 0;
1831
- const maxAdsToTry = 10;
1832
- let adsAdded = 0;
1833
- if (this.config.debugAdTiming) {
1834
- console.log(
1835
- `[StormcloudVideoPlayer] Attempting to fill ${targetDurationSeconds}s with ads`
1836
- );
1837
- }
1838
- while (cumulativeDurationSeconds < targetDurationSeconds && adsAdded < maxAdsToTry) {
1839
- adQueue.push(baseVastTagUrl);
1840
- adsAdded++;
1841
- const estimatedAdDuration = this.getEstimatedAdDuration();
1842
- cumulativeDurationSeconds += estimatedAdDuration;
1843
- if (this.config.debugAdTiming) {
1844
- console.log(
1845
- `[StormcloudVideoPlayer] Added ad ${adsAdded}, cumulative duration: ${cumulativeDurationSeconds}s`
1846
- );
1847
- }
1848
- const remainingDuration = targetDurationSeconds - cumulativeDurationSeconds;
1849
- const toleranceSeconds = (this.config.adBreakGapToleranceMs ?? 2e3) / 1e3;
1850
- if (remainingDuration < estimatedAdDuration && remainingDuration >= -toleranceSeconds) {
1851
- if (this.config.debugAdTiming) {
1852
- console.log(
1853
- `[StormcloudVideoPlayer] Within tolerance, adding final ad. Overage: ${-remainingDuration}s`
1854
- );
1855
- }
1856
- break;
1857
- }
1858
- if (remainingDuration < estimatedAdDuration && remainingDuration < -toleranceSeconds) {
1859
- if (this.config.debugAdTiming) {
1860
- console.log(
1861
- `[StormcloudVideoPlayer] Would exceed duration by too much, stopping at ${adsAdded} ads`
1862
- );
1863
- }
1864
- break;
1865
- }
1866
- }
1867
- return adQueue;
1868
- }
1869
- getEstimatedAdDuration() {
1870
- if (this.vastConfig) {
1871
- return 15;
1872
- }
1873
- return 30;
1874
- }
1875
- async getAdInfoForQueue(adQueue) {
1876
- if (this.config.enableAdPreloading === false) {
1877
- if (this.config.debugAdTiming) {
1878
- console.log(
1879
- "[StormcloudVideoPlayer] Ad preloading disabled, using estimates"
1880
- );
1881
- }
1882
- return adQueue.map((vastTagUrl) => ({
1883
- duration: this.getEstimatedAdDuration(),
1884
- vastTagUrl,
1885
- isPreloaded: false
1886
- }));
1887
- }
1888
- try {
1889
- const adInfos = await this.ima.preloadAds(adQueue);
1890
- return adInfos;
1891
- } catch (error) {
1892
- if (this.config.debugAdTiming) {
1893
- console.warn(
1894
- "[StormcloudVideoPlayer] Failed to preload ads, using estimates:",
1895
- error
1896
- );
1897
- }
1898
- return adQueue.map((vastTagUrl) => ({
1899
- duration: this.getEstimatedAdDuration(),
1900
- vastTagUrl,
1901
- isPreloaded: false
1902
- }));
1903
- }
1904
- }
1905
1595
  getRemainingAdMs() {
1906
1596
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
1907
1597
  return 0;