stormcloud-video-player 0.2.12 → 0.2.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.
Files changed (38) hide show
  1. package/README.md +100 -1
  2. package/dist/stormcloud-vp.min.js +2 -2
  3. package/lib/index.cjs +1206 -151
  4. package/lib/index.cjs.map +1 -1
  5. package/lib/index.d.cts +77 -2
  6. package/lib/index.d.ts +77 -2
  7. package/lib/index.js +1196 -151
  8. package/lib/index.js.map +1 -1
  9. package/lib/player/StormcloudVideoPlayer.cjs +1100 -114
  10. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  11. package/lib/player/StormcloudVideoPlayer.d.cts +2 -2
  12. package/lib/players/FilePlayer.cjs +14 -7
  13. package/lib/players/FilePlayer.cjs.map +1 -1
  14. package/lib/players/HlsPlayer.cjs +1108 -119
  15. package/lib/players/HlsPlayer.cjs.map +1 -1
  16. package/lib/players/HlsPlayer.d.cts +1 -1
  17. package/lib/players/index.cjs +1122 -126
  18. package/lib/players/index.cjs.map +1 -1
  19. package/lib/sdk/hlsAdPlayer.cjs +561 -0
  20. package/lib/sdk/hlsAdPlayer.cjs.map +1 -0
  21. package/lib/sdk/hlsAdPlayer.d.cts +10 -0
  22. package/lib/sdk/ima.cjs +176 -23
  23. package/lib/sdk/ima.cjs.map +1 -1
  24. package/lib/sdk/ima.d.cts +1 -1
  25. package/lib/{types-GpA_hKek.d.cts → types-mVgmKmzM.d.cts} +3 -0
  26. package/lib/ui/StormcloudVideoPlayer.cjs +1107 -119
  27. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  28. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  29. package/lib/utils/browserCompat.cjs +229 -0
  30. package/lib/utils/browserCompat.cjs.map +1 -0
  31. package/lib/utils/browserCompat.d.cts +36 -0
  32. package/lib/utils/polyfills.cjs +253 -0
  33. package/lib/utils/polyfills.cjs.map +1 -0
  34. package/lib/utils/polyfills.d.cts +11 -0
  35. package/lib/utils/tracking.cjs +10 -9
  36. package/lib/utils/tracking.cjs.map +1 -1
  37. package/lib/utils/tracking.d.cts +1 -1
  38. package/package.json +1 -1
@@ -33,7 +33,167 @@ __export(StormcloudVideoPlayer_exports, {
33
33
  StormcloudVideoPlayer: () => StormcloudVideoPlayer
34
34
  });
35
35
  module.exports = __toCommonJS(StormcloudVideoPlayer_exports);
36
- var import_hls = __toESM(require("hls.js"), 1);
36
+ var import_hls2 = __toESM(require("hls.js"), 1);
37
+
38
+ // src/utils/browserCompat.ts
39
+ function getChromeVersion(ua) {
40
+ const match = ua.match(/Chrome\/(\d+)/);
41
+ return match && match[1] ? parseInt(match[1], 10) : 0;
42
+ }
43
+ function getWebKitVersion(ua) {
44
+ const match = ua.match(/AppleWebKit\/(\d+)/);
45
+ return match && match[1] ? parseInt(match[1], 10) : 0;
46
+ }
47
+ function getPlatform() {
48
+ var _a;
49
+ if ("userAgentData" in navigator && ((_a = navigator.userAgentData) == null ? void 0 : _a.platform)) {
50
+ return navigator.userAgentData.platform;
51
+ }
52
+ const ua = navigator.userAgent;
53
+ if (/Mac|iPhone|iPad|iPod/i.test(ua)) {
54
+ return /iPhone|iPad|iPod/i.test(ua) ? "iPhone" : "MacIntel";
55
+ }
56
+ if (/Win/i.test(ua)) {
57
+ return "Win32";
58
+ }
59
+ if (/Linux/i.test(ua)) {
60
+ return /Android/i.test(ua) ? "Linux armv8l" : "Linux x86_64";
61
+ }
62
+ if (/CrOS/i.test(ua)) {
63
+ return "CrOS";
64
+ }
65
+ return navigator.platform || "Unknown";
66
+ }
67
+ function detectBrowser() {
68
+ const ua = navigator.userAgent;
69
+ const platform = getPlatform();
70
+ let name = "Unknown";
71
+ let version = "0";
72
+ let majorVersion = 0;
73
+ let isSmartTV = false;
74
+ let isLegacyTV = false;
75
+ let supportsIMA = true;
76
+ let supportsModernJS = true;
77
+ let recommendedAdPlayer = "ima";
78
+ if (/Web0S|webOS/i.test(ua)) {
79
+ name = "LG WebOS";
80
+ isSmartTV = true;
81
+ const match = ua.match(/Web0S[/\s]*([\d.]+)/i);
82
+ version = match && match[1] ? match[1] : "Unknown";
83
+ if (version !== "Unknown") {
84
+ const parts = version.split(".");
85
+ majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;
86
+ }
87
+ } else if (/Tizen/i.test(ua)) {
88
+ name = "Samsung Tizen";
89
+ isSmartTV = true;
90
+ const match = ua.match(/Tizen[/\s]*([\d.]+)/i);
91
+ version = match && match[1] ? match[1] : "Unknown";
92
+ if (version !== "Unknown") {
93
+ const parts = version.split(".");
94
+ majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;
95
+ }
96
+ } else if (/SMART-TV|SmartTV/i.test(ua)) {
97
+ name = "Smart TV";
98
+ isSmartTV = true;
99
+ } else if (/NetCast/i.test(ua)) {
100
+ name = "LG NetCast";
101
+ isSmartTV = true;
102
+ isLegacyTV = true;
103
+ } else if (/BRAVIA/i.test(ua)) {
104
+ name = "Sony BRAVIA";
105
+ isSmartTV = true;
106
+ }
107
+ const chromeVersion = getChromeVersion(ua);
108
+ const webkitVersion = getWebKitVersion(ua);
109
+ if (chromeVersion > 0) {
110
+ if (!isSmartTV) {
111
+ name = "Chrome";
112
+ version = chromeVersion.toString();
113
+ majorVersion = chromeVersion;
114
+ }
115
+ if (chromeVersion < 50) {
116
+ supportsIMA = false;
117
+ supportsModernJS = false;
118
+ isLegacyTV = true;
119
+ recommendedAdPlayer = "hls";
120
+ }
121
+ }
122
+ if (webkitVersion > 0 && webkitVersion < 600) {
123
+ supportsModernJS = false;
124
+ if (isSmartTV) {
125
+ isLegacyTV = true;
126
+ supportsIMA = false;
127
+ recommendedAdPlayer = "hls";
128
+ }
129
+ }
130
+ if (typeof Promise === "undefined" || typeof Map === "undefined" || typeof Set === "undefined") {
131
+ supportsModernJS = false;
132
+ supportsIMA = false;
133
+ recommendedAdPlayer = "hls";
134
+ }
135
+ if (typeof URLSearchParams === "undefined") {
136
+ supportsModernJS = false;
137
+ }
138
+ return {
139
+ name,
140
+ version,
141
+ majorVersion,
142
+ isSmartTV,
143
+ isLegacyTV,
144
+ platform,
145
+ supportsIMA,
146
+ supportsModernJS,
147
+ recommendedAdPlayer
148
+ };
149
+ }
150
+ function supportsGoogleIMA() {
151
+ const browser = detectBrowser();
152
+ if (browser.isLegacyTV) {
153
+ return false;
154
+ }
155
+ if (typeof document === "undefined" || typeof document.createElement !== "function") {
156
+ return false;
157
+ }
158
+ try {
159
+ const video = document.createElement("video");
160
+ if (!video) {
161
+ return false;
162
+ }
163
+ } catch (e) {
164
+ return false;
165
+ }
166
+ if (typeof Promise === "undefined") {
167
+ return false;
168
+ }
169
+ return browser.supportsIMA;
170
+ }
171
+ function logBrowserInfo(debug = false) {
172
+ if (!debug) return;
173
+ const browser = detectBrowser();
174
+ const imaSupport = supportsGoogleIMA();
175
+ console.log("[StormcloudVideoPlayer] Browser Compatibility Info:", {
176
+ browser: `${browser.name} ${browser.version}`,
177
+ platform: browser.platform,
178
+ isSmartTV: browser.isSmartTV,
179
+ isLegacyTV: browser.isLegacyTV,
180
+ supportsIMA: imaSupport,
181
+ supportsModernJS: browser.supportsModernJS,
182
+ recommendedAdPlayer: browser.recommendedAdPlayer,
183
+ userAgent: navigator.userAgent
184
+ });
185
+ }
186
+ function getBrowserConfigOverrides() {
187
+ const browser = detectBrowser();
188
+ const overrides = {};
189
+ if (browser.isLegacyTV || !browser.supportsIMA) {
190
+ overrides.adPlayerType = "hls";
191
+ }
192
+ if (browser.isSmartTV) {
193
+ overrides.allowNativeHls = true;
194
+ }
195
+ return overrides;
196
+ }
37
197
 
38
198
  // src/sdk/ima.ts
39
199
  function createImaController(video, options) {
@@ -51,9 +211,18 @@ function createImaController(video, options) {
51
211
  }
52
212
  }
53
213
  function ensureImaLoaded() {
214
+ var _a, _b, _c;
215
+ if (!supportsGoogleIMA()) {
216
+ console.warn(
217
+ "[IMA] Google IMA SDK is not supported on this browser. Please use HLS ad player instead."
218
+ );
219
+ return Promise.reject(
220
+ new Error("Google IMA SDK not supported on this browser")
221
+ );
222
+ }
54
223
  try {
55
224
  const frameEl = window.frameElement;
56
- const sandboxAttr = frameEl?.getAttribute?.("sandbox") || "";
225
+ const sandboxAttr = ((_a = frameEl == null ? void 0 : frameEl.getAttribute) == null ? void 0 : _a.call(frameEl, "sandbox")) || "";
57
226
  if (sandboxAttr) {
58
227
  const tokens = new Set(
59
228
  sandboxAttr.split(/\s+/).map((t) => t.trim()).filter((t) => t.length > 0)
@@ -67,13 +236,13 @@ function createImaController(video, options) {
67
236
  }
68
237
  } catch {
69
238
  }
70
- if (typeof window !== "undefined" && window.google?.ima)
239
+ if (typeof window !== "undefined" && ((_b = window.google) == null ? void 0 : _b.ima))
71
240
  return Promise.resolve();
72
241
  const existing = document.querySelector(
73
242
  'script[data-ima="true"]'
74
243
  );
75
244
  if (existing) {
76
- if (window.google?.ima) {
245
+ if ((_c = window.google) == null ? void 0 : _c.ima) {
77
246
  return Promise.resolve();
78
247
  }
79
248
  return new Promise((resolve, reject) => {
@@ -131,6 +300,7 @@ function createImaController(video, options) {
131
300
  return {
132
301
  initialize() {
133
302
  ensureImaLoaded().then(() => {
303
+ var _a, _b;
134
304
  const google = window.google;
135
305
  if (!adDisplayContainer) {
136
306
  const container = document.createElement("div");
@@ -144,14 +314,14 @@ function createImaController(video, options) {
144
314
  container.style.justifyContent = "center";
145
315
  container.style.pointerEvents = "none";
146
316
  container.style.zIndex = "2";
147
- video.parentElement?.appendChild(container);
317
+ (_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
148
318
  adContainerEl = container;
149
319
  adDisplayContainer = new google.ima.AdDisplayContainer(
150
320
  container,
151
321
  video
152
322
  );
153
323
  try {
154
- adDisplayContainer.initialize?.();
324
+ (_b = adDisplayContainer.initialize) == null ? void 0 : _b.call(adDisplayContainer);
155
325
  } catch {
156
326
  }
157
327
  }
@@ -236,6 +406,7 @@ function createImaController(video, options) {
236
406
  adsManager.addEventListener(
237
407
  AdErrorEvent.AD_ERROR,
238
408
  (errorEvent) => {
409
+ var _a;
239
410
  console.error("[IMA] Ad error:", errorEvent.getError());
240
411
  destroyAdsManager();
241
412
  adPlaying = false;
@@ -266,10 +437,10 @@ function createImaController(video, options) {
266
437
  "[IMA] Max retries reached, emitting ad_error"
267
438
  );
268
439
  emit("ad_error");
269
- if (!options?.continueLiveStreamDuringAds) {
440
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
270
441
  if (video.paused) {
271
442
  console.log("[IMA] Resuming paused video after ad error");
272
- video.play()?.catch(() => {
443
+ (_a = video.play()) == null ? void 0 : _a.catch(() => {
273
444
  });
274
445
  }
275
446
  }
@@ -280,7 +451,7 @@ function createImaController(video, options) {
280
451
  AdEvent.CONTENT_PAUSE_REQUESTED,
281
452
  () => {
282
453
  console.log("[IMA] Content pause requested");
283
- if (!options?.continueLiveStreamDuringAds) {
454
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
284
455
  video.pause();
285
456
  console.log("[IMA] Video paused (VOD mode)");
286
457
  } else {
@@ -306,6 +477,7 @@ function createImaController(video, options) {
306
477
  adsManager.addEventListener(
307
478
  AdEvent.CONTENT_RESUME_REQUESTED,
308
479
  () => {
480
+ var _a;
309
481
  console.log("[IMA] Content resume requested");
310
482
  adPlaying = false;
311
483
  video.muted = originalMutedState;
@@ -316,8 +488,8 @@ function createImaController(video, options) {
316
488
  "[IMA] Ad container hidden - pointer events disabled"
317
489
  );
318
490
  }
319
- if (!options?.continueLiveStreamDuringAds) {
320
- video.play()?.catch(() => {
491
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
492
+ (_a = video.play()) == null ? void 0 : _a.catch(() => {
321
493
  });
322
494
  console.log("[IMA] Video resumed (VOD mode)");
323
495
  } else {
@@ -339,7 +511,7 @@ function createImaController(video, options) {
339
511
  "[IMA] Ad container hidden after all ads completed"
340
512
  );
341
513
  }
342
- if (!options?.continueLiveStreamDuringAds) {
514
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
343
515
  video.play().catch(() => {
344
516
  });
345
517
  console.log(
@@ -367,7 +539,7 @@ function createImaController(video, options) {
367
539
  adContainerEl.style.display = "none";
368
540
  console.log("[IMA] Ad container hidden after setup error");
369
541
  }
370
- if (!options?.continueLiveStreamDuringAds) {
542
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
371
543
  if (video.paused) {
372
544
  console.log("[IMA] Resuming paused video after setup error");
373
545
  video.play().catch(() => {
@@ -395,7 +567,7 @@ function createImaController(video, options) {
395
567
  adContainerEl.style.display = "none";
396
568
  console.log("[IMA] Ad container hidden after loader error");
397
569
  }
398
- if (!options?.continueLiveStreamDuringAds) {
570
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
399
571
  if (video.paused) {
400
572
  console.log("[IMA] Resuming paused video after loader error");
401
573
  video.play().catch(() => {
@@ -417,14 +589,15 @@ function createImaController(video, options) {
417
589
  return adsLoadedPromise;
418
590
  } catch (error) {
419
591
  console.error("[IMA] Failed to request ads:", error);
420
- currentReject?.(error);
592
+ currentReject == null ? void 0 : currentReject(error);
421
593
  adsLoadedReject = void 0;
422
594
  adsLoadedResolve = void 0;
423
595
  return Promise.reject(error);
424
596
  }
425
597
  },
426
598
  async play() {
427
- if (!window.google?.ima || !adDisplayContainer) {
599
+ var _a, _b;
600
+ if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
428
601
  console.warn(
429
602
  "[IMA] Cannot play ad: IMA SDK or ad container not available"
430
603
  );
@@ -446,14 +619,15 @@ function createImaController(video, options) {
446
619
  } catch (error) {
447
620
  console.error("[IMA] Error starting ad playback:", error);
448
621
  adPlaying = false;
449
- if (!options?.continueLiveStreamDuringAds) {
450
- video.play()?.catch(() => {
622
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
623
+ (_b = video.play()) == null ? void 0 : _b.catch(() => {
451
624
  });
452
625
  }
453
626
  return Promise.reject(error);
454
627
  }
455
628
  },
456
629
  async stop() {
630
+ var _a;
457
631
  adPlaying = false;
458
632
  video.muted = originalMutedState;
459
633
  if (adContainerEl) {
@@ -462,11 +636,11 @@ function createImaController(video, options) {
462
636
  console.log("[IMA] Ad container hidden after stop");
463
637
  }
464
638
  try {
465
- adsManager?.stop?.();
639
+ (_a = adsManager == null ? void 0 : adsManager.stop) == null ? void 0 : _a.call(adsManager);
466
640
  } catch {
467
641
  }
468
642
  destroyAdsManager();
469
- if (!options?.continueLiveStreamDuringAds) {
643
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
470
644
  video.play().catch(() => {
471
645
  });
472
646
  console.log("[IMA] Video resumed after stop (VOD mode)");
@@ -475,6 +649,7 @@ function createImaController(video, options) {
475
649
  }
476
650
  },
477
651
  destroy() {
652
+ var _a;
478
653
  destroyAdsManager();
479
654
  adPlaying = false;
480
655
  video.muted = originalMutedState;
@@ -483,10 +658,10 @@ function createImaController(video, options) {
483
658
  adContainerEl.style.display = "none";
484
659
  }
485
660
  try {
486
- adsLoader?.destroy?.();
661
+ (_a = adsLoader == null ? void 0 : adsLoader.destroy) == null ? void 0 : _a.call(adsLoader);
487
662
  } catch {
488
663
  }
489
- if (adContainerEl?.parentElement) {
664
+ if (adContainerEl == null ? void 0 : adContainerEl.parentElement) {
490
665
  adContainerEl.parentElement.removeChild(adContainerEl);
491
666
  }
492
667
  adContainerEl = void 0;
@@ -497,7 +672,8 @@ function createImaController(video, options) {
497
672
  return adPlaying;
498
673
  },
499
674
  resize(width, height) {
500
- if (!adsManager || !window.google?.ima) {
675
+ var _a;
676
+ if (!adsManager || !((_a = window.google) == null ? void 0 : _a.ima)) {
501
677
  console.warn(
502
678
  "[IMA] Cannot resize: No ads manager or IMA SDK available"
503
679
  );
@@ -515,7 +691,8 @@ function createImaController(video, options) {
515
691
  listeners.get(event).add(listener);
516
692
  },
517
693
  off(event, listener) {
518
- listeners.get(event)?.delete(listener);
694
+ var _a;
695
+ (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
519
696
  },
520
697
  updateOriginalMutedState(muted) {
521
698
  originalMutedState = muted;
@@ -546,9 +723,533 @@ function createImaController(video, options) {
546
723
  };
547
724
  }
548
725
 
726
+ // src/sdk/hlsAdPlayer.ts
727
+ var import_hls = __toESM(require("hls.js"), 1);
728
+ function createHlsAdPlayer(contentVideo, options) {
729
+ let adPlaying = false;
730
+ let originalMutedState = false;
731
+ const listeners = /* @__PURE__ */ new Map();
732
+ const licenseKey = options == null ? void 0 : options.licenseKey;
733
+ const mainHlsInstance = options == null ? void 0 : options.mainHlsInstance;
734
+ let adVideoElement;
735
+ let adHls;
736
+ let adContainerEl;
737
+ let currentAd;
738
+ let sessionId;
739
+ let trackingFired = {
740
+ impression: false,
741
+ start: false,
742
+ firstQuartile: false,
743
+ midpoint: false,
744
+ thirdQuartile: false,
745
+ complete: false
746
+ };
747
+ function emit(event, payload) {
748
+ const set = listeners.get(event);
749
+ if (!set) return;
750
+ for (const fn of Array.from(set)) {
751
+ try {
752
+ fn(payload);
753
+ } catch (error) {
754
+ console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
755
+ }
756
+ }
757
+ }
758
+ function generateSessionId() {
759
+ return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
760
+ }
761
+ function fireTrackingPixels(urls) {
762
+ if (!urls || urls.length === 0) return;
763
+ urls.forEach((url) => {
764
+ try {
765
+ let trackingUrl = url;
766
+ if (sessionId) {
767
+ trackingUrl = `${trackingUrl}${trackingUrl.includes("?") ? "&" : "?"}session_id=${sessionId}`;
768
+ }
769
+ if (licenseKey) {
770
+ trackingUrl = `${trackingUrl}${trackingUrl.includes("?") ? "&" : "?"}license_key=${licenseKey}`;
771
+ }
772
+ const img = new Image(1, 1);
773
+ img.src = trackingUrl;
774
+ console.log(`[HlsAdPlayer] Fired tracking pixel: ${trackingUrl}`);
775
+ } catch (error) {
776
+ console.warn(`[HlsAdPlayer] Error firing tracking pixel:`, error);
777
+ }
778
+ });
779
+ }
780
+ function getMainStreamQuality() {
781
+ if (!mainHlsInstance || !mainHlsInstance.levels) {
782
+ return null;
783
+ }
784
+ const currentLevel = mainHlsInstance.currentLevel;
785
+ if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {
786
+ const autoLevel = mainHlsInstance.loadLevel;
787
+ if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {
788
+ const level2 = mainHlsInstance.levels[autoLevel];
789
+ return {
790
+ width: level2.width || 1920,
791
+ height: level2.height || 1080,
792
+ bitrate: level2.bitrate || 5e6
793
+ };
794
+ }
795
+ return null;
796
+ }
797
+ const level = mainHlsInstance.levels[currentLevel];
798
+ return {
799
+ width: level.width || 1920,
800
+ height: level.height || 1080,
801
+ bitrate: level.bitrate || 5e6
802
+ };
803
+ }
804
+ function selectBestMediaFile(mediaFiles) {
805
+ if (mediaFiles.length === 0) {
806
+ throw new Error("No media files available");
807
+ }
808
+ const firstFile = mediaFiles[0];
809
+ if (!firstFile) {
810
+ throw new Error("No media files available");
811
+ }
812
+ if (mediaFiles.length === 1) {
813
+ return firstFile;
814
+ }
815
+ const mainQuality = getMainStreamQuality();
816
+ if (!mainQuality) {
817
+ console.log("[HlsAdPlayer] No main stream quality info, using first media file");
818
+ return firstFile;
819
+ }
820
+ console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
821
+ const scoredFiles = mediaFiles.map((file) => {
822
+ const widthDiff = Math.abs(file.width - mainQuality.width);
823
+ const heightDiff = Math.abs(file.height - mainQuality.height);
824
+ const resolutionDiff = widthDiff + heightDiff;
825
+ const fileBitrate = (file.bitrate || 5e3) * 1e3;
826
+ const bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);
827
+ const score = resolutionDiff * 2 + bitrateDiff / 1e3;
828
+ return { file, score, resolutionDiff, bitrateDiff };
829
+ });
830
+ scoredFiles.sort((a, b) => a.score - b.score);
831
+ const bestMatch = scoredFiles[0];
832
+ if (!bestMatch) {
833
+ console.log("[HlsAdPlayer] No best match found, using first media file");
834
+ return firstFile;
835
+ }
836
+ console.log("[HlsAdPlayer] Selected media file:", {
837
+ url: bestMatch.file.url,
838
+ resolution: `${bestMatch.file.width}x${bestMatch.file.height}`,
839
+ bitrate: bestMatch.file.bitrate,
840
+ score: bestMatch.score,
841
+ resolutionDiff: bestMatch.resolutionDiff,
842
+ bitrateDiff: bestMatch.bitrateDiff
843
+ });
844
+ return bestMatch.file;
845
+ }
846
+ function parseVastXml(xmlString) {
847
+ var _a, _b, _c, _d;
848
+ try {
849
+ const parser = new DOMParser();
850
+ const xmlDoc = parser.parseFromString(xmlString, "text/xml");
851
+ const parserError = xmlDoc.querySelector("parsererror");
852
+ if (parserError) {
853
+ console.error("[HlsAdPlayer] XML parsing error:", parserError.textContent);
854
+ return null;
855
+ }
856
+ const adElement = xmlDoc.querySelector("Ad");
857
+ if (!adElement) {
858
+ console.warn("[HlsAdPlayer] No Ad element found in VAST XML");
859
+ return null;
860
+ }
861
+ const adId = adElement.getAttribute("id") || "unknown";
862
+ const title = ((_a = xmlDoc.querySelector("AdTitle")) == null ? void 0 : _a.textContent) || "Ad";
863
+ const durationText = ((_b = xmlDoc.querySelector("Duration")) == null ? void 0 : _b.textContent) || "00:00:30";
864
+ const durationParts = durationText.split(":");
865
+ const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
866
+ const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
867
+ const mediaFiles = [];
868
+ mediaFileElements.forEach((mf) => {
869
+ var _a2;
870
+ const type = mf.getAttribute("type") || "";
871
+ if (type === "application/x-mpegURL" || type.includes("m3u8")) {
872
+ const bitrateAttr = mf.getAttribute("bitrate");
873
+ const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
874
+ mediaFiles.push({
875
+ url: ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "",
876
+ type,
877
+ width: parseInt(mf.getAttribute("width") || "1920", 10),
878
+ height: parseInt(mf.getAttribute("height") || "1080", 10),
879
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
880
+ });
881
+ }
882
+ });
883
+ if (mediaFiles.length === 0) {
884
+ console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
885
+ return null;
886
+ }
887
+ const trackingUrls = {
888
+ impression: [],
889
+ start: [],
890
+ firstQuartile: [],
891
+ midpoint: [],
892
+ thirdQuartile: [],
893
+ complete: [],
894
+ mute: [],
895
+ unmute: [],
896
+ pause: [],
897
+ resume: [],
898
+ fullscreen: [],
899
+ exitFullscreen: [],
900
+ skip: [],
901
+ error: []
902
+ };
903
+ xmlDoc.querySelectorAll("Impression").forEach((el) => {
904
+ var _a2;
905
+ const url = (_a2 = el.textContent) == null ? void 0 : _a2.trim();
906
+ if (url) trackingUrls.impression.push(url);
907
+ });
908
+ xmlDoc.querySelectorAll("Tracking").forEach((el) => {
909
+ var _a2;
910
+ const event = el.getAttribute("event");
911
+ const url = (_a2 = el.textContent) == null ? void 0 : _a2.trim();
912
+ if (event && url) {
913
+ const eventKey = event;
914
+ if (trackingUrls[eventKey]) {
915
+ trackingUrls[eventKey].push(url);
916
+ }
917
+ }
918
+ });
919
+ const clickThrough = (_d = (_c = xmlDoc.querySelector("ClickThrough")) == null ? void 0 : _c.textContent) == null ? void 0 : _d.trim();
920
+ return {
921
+ id: adId,
922
+ title,
923
+ duration,
924
+ mediaFiles,
925
+ trackingUrls,
926
+ clickThrough
927
+ };
928
+ } catch (error) {
929
+ console.error("[HlsAdPlayer] Error parsing VAST XML:", error);
930
+ return null;
931
+ }
932
+ }
933
+ function createAdVideoElement() {
934
+ const video = document.createElement("video");
935
+ video.style.position = "absolute";
936
+ video.style.left = "0";
937
+ video.style.top = "0";
938
+ video.style.width = "100%";
939
+ video.style.height = "100%";
940
+ video.style.objectFit = "contain";
941
+ video.style.backgroundColor = "#000";
942
+ video.playsInline = true;
943
+ video.muted = false;
944
+ return video;
945
+ }
946
+ function setupAdEventListeners() {
947
+ if (!adVideoElement || !currentAd) return;
948
+ adVideoElement.addEventListener("timeupdate", () => {
949
+ if (!currentAd || !adVideoElement) return;
950
+ const progress = adVideoElement.currentTime / currentAd.duration;
951
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
952
+ trackingFired.firstQuartile = true;
953
+ fireTrackingPixels(currentAd.trackingUrls.firstQuartile);
954
+ }
955
+ if (progress >= 0.5 && !trackingFired.midpoint) {
956
+ trackingFired.midpoint = true;
957
+ fireTrackingPixels(currentAd.trackingUrls.midpoint);
958
+ }
959
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
960
+ trackingFired.thirdQuartile = true;
961
+ fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
962
+ }
963
+ });
964
+ adVideoElement.addEventListener("playing", () => {
965
+ if (!currentAd || trackingFired.start) return;
966
+ trackingFired.start = true;
967
+ fireTrackingPixels(currentAd.trackingUrls.start);
968
+ console.log("[HlsAdPlayer] Ad started playing");
969
+ });
970
+ adVideoElement.addEventListener("ended", () => {
971
+ if (!currentAd || trackingFired.complete) return;
972
+ trackingFired.complete = true;
973
+ fireTrackingPixels(currentAd.trackingUrls.complete);
974
+ console.log("[HlsAdPlayer] Ad completed");
975
+ handleAdComplete();
976
+ });
977
+ adVideoElement.addEventListener("error", (e) => {
978
+ console.error("[HlsAdPlayer] Ad video error:", e);
979
+ if (currentAd) {
980
+ fireTrackingPixels(currentAd.trackingUrls.error);
981
+ }
982
+ handleAdError();
983
+ });
984
+ adVideoElement.addEventListener("volumechange", () => {
985
+ if (!currentAd) return;
986
+ if (adVideoElement.muted) {
987
+ fireTrackingPixels(currentAd.trackingUrls.mute);
988
+ } else {
989
+ fireTrackingPixels(currentAd.trackingUrls.unmute);
990
+ }
991
+ });
992
+ adVideoElement.addEventListener("pause", () => {
993
+ if (currentAd && !adVideoElement.ended) {
994
+ fireTrackingPixels(currentAd.trackingUrls.pause);
995
+ }
996
+ });
997
+ adVideoElement.addEventListener("play", () => {
998
+ if (currentAd && adVideoElement.currentTime > 0) {
999
+ fireTrackingPixels(currentAd.trackingUrls.resume);
1000
+ }
1001
+ });
1002
+ }
1003
+ function handleAdComplete() {
1004
+ console.log("[HlsAdPlayer] Handling ad completion");
1005
+ adPlaying = false;
1006
+ contentVideo.muted = originalMutedState;
1007
+ if (adContainerEl) {
1008
+ adContainerEl.style.display = "none";
1009
+ adContainerEl.style.pointerEvents = "none";
1010
+ }
1011
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1012
+ contentVideo.play().catch(() => {
1013
+ });
1014
+ console.log("[HlsAdPlayer] Content resumed (VOD mode)");
1015
+ } else {
1016
+ console.log("[HlsAdPlayer] Content unmuted (Live mode)");
1017
+ }
1018
+ emit("content_resume");
1019
+ emit("all_ads_completed");
1020
+ }
1021
+ function handleAdError() {
1022
+ console.log("[HlsAdPlayer] Handling ad error");
1023
+ adPlaying = false;
1024
+ contentVideo.muted = originalMutedState;
1025
+ if (adContainerEl) {
1026
+ adContainerEl.style.display = "none";
1027
+ adContainerEl.style.pointerEvents = "none";
1028
+ }
1029
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1030
+ if (contentVideo.paused) {
1031
+ contentVideo.play().catch(() => {
1032
+ });
1033
+ }
1034
+ }
1035
+ emit("ad_error");
1036
+ }
1037
+ return {
1038
+ initialize() {
1039
+ var _a;
1040
+ console.log("[HlsAdPlayer] Initializing");
1041
+ if (!adContainerEl) {
1042
+ const container = document.createElement("div");
1043
+ container.style.position = "absolute";
1044
+ container.style.left = "0";
1045
+ container.style.top = "0";
1046
+ container.style.right = "0";
1047
+ container.style.bottom = "0";
1048
+ container.style.display = "none";
1049
+ container.style.alignItems = "center";
1050
+ container.style.justifyContent = "center";
1051
+ container.style.pointerEvents = "none";
1052
+ container.style.zIndex = "2";
1053
+ container.style.backgroundColor = "#000";
1054
+ (_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
1055
+ adContainerEl = container;
1056
+ }
1057
+ },
1058
+ async requestAds(vastTagUrl) {
1059
+ console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
1060
+ if (adPlaying) {
1061
+ console.warn("[HlsAdPlayer] Cannot request new ads while an ad is playing");
1062
+ return Promise.reject(new Error("Ad already playing"));
1063
+ }
1064
+ try {
1065
+ sessionId = generateSessionId();
1066
+ const response = await fetch(vastTagUrl);
1067
+ if (!response.ok) {
1068
+ throw new Error(`Failed to fetch VAST: ${response.statusText}`);
1069
+ }
1070
+ const vastXml = await response.text();
1071
+ console.log("[HlsAdPlayer] VAST XML received");
1072
+ const ad = parseVastXml(vastXml);
1073
+ if (!ad) {
1074
+ throw new Error("Failed to parse VAST XML or no ads available");
1075
+ }
1076
+ currentAd = ad;
1077
+ console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
1078
+ fireTrackingPixels(ad.trackingUrls.impression);
1079
+ trackingFired.impression = true;
1080
+ return Promise.resolve();
1081
+ } catch (error) {
1082
+ console.error("[HlsAdPlayer] Error requesting ads:", error);
1083
+ emit("ad_error");
1084
+ return Promise.reject(error);
1085
+ }
1086
+ },
1087
+ async play() {
1088
+ if (!currentAd) {
1089
+ console.warn("[HlsAdPlayer] Cannot play: No ad loaded");
1090
+ return Promise.reject(new Error("No ad loaded"));
1091
+ }
1092
+ console.log("[HlsAdPlayer] Starting ad playback");
1093
+ try {
1094
+ if (!adVideoElement) {
1095
+ adVideoElement = createAdVideoElement();
1096
+ adContainerEl == null ? void 0 : adContainerEl.appendChild(adVideoElement);
1097
+ setupAdEventListeners();
1098
+ }
1099
+ trackingFired = {
1100
+ impression: trackingFired.impression,
1101
+ start: false,
1102
+ firstQuartile: false,
1103
+ midpoint: false,
1104
+ thirdQuartile: false,
1105
+ complete: false
1106
+ };
1107
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1108
+ contentVideo.pause();
1109
+ console.log("[HlsAdPlayer] Content paused (VOD mode)");
1110
+ } else {
1111
+ console.log("[HlsAdPlayer] Content continues (Live mode)");
1112
+ }
1113
+ contentVideo.muted = true;
1114
+ adPlaying = true;
1115
+ if (adContainerEl) {
1116
+ adContainerEl.style.display = "flex";
1117
+ adContainerEl.style.pointerEvents = "auto";
1118
+ }
1119
+ emit("content_pause");
1120
+ const mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1121
+ if (!mediaFile) {
1122
+ throw new Error("No media file available for ad");
1123
+ }
1124
+ console.log(`[HlsAdPlayer] Loading ad from: ${mediaFile.url}`);
1125
+ if (import_hls.default.isSupported()) {
1126
+ if (adHls) {
1127
+ adHls.destroy();
1128
+ }
1129
+ adHls = new import_hls.default({
1130
+ enableWorker: true,
1131
+ lowLatencyMode: false
1132
+ });
1133
+ adHls.loadSource(mediaFile.url);
1134
+ adHls.attachMedia(adVideoElement);
1135
+ adHls.on(import_hls.default.Events.MANIFEST_PARSED, () => {
1136
+ console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1137
+ adVideoElement.play().catch((error) => {
1138
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1139
+ handleAdError();
1140
+ });
1141
+ });
1142
+ adHls.on(import_hls.default.Events.ERROR, (event, data) => {
1143
+ console.error("[HlsAdPlayer] HLS error:", data);
1144
+ if (data.fatal) {
1145
+ handleAdError();
1146
+ }
1147
+ });
1148
+ } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1149
+ adVideoElement.src = mediaFile.url;
1150
+ adVideoElement.play().catch((error) => {
1151
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1152
+ handleAdError();
1153
+ });
1154
+ } else {
1155
+ throw new Error("HLS not supported");
1156
+ }
1157
+ return Promise.resolve();
1158
+ } catch (error) {
1159
+ console.error("[HlsAdPlayer] Error playing ad:", error);
1160
+ handleAdError();
1161
+ return Promise.reject(error);
1162
+ }
1163
+ },
1164
+ async stop() {
1165
+ console.log("[HlsAdPlayer] Stopping ad");
1166
+ adPlaying = false;
1167
+ contentVideo.muted = originalMutedState;
1168
+ if (adContainerEl) {
1169
+ adContainerEl.style.display = "none";
1170
+ adContainerEl.style.pointerEvents = "none";
1171
+ }
1172
+ if (adHls) {
1173
+ adHls.destroy();
1174
+ adHls = void 0;
1175
+ }
1176
+ if (adVideoElement) {
1177
+ adVideoElement.pause();
1178
+ adVideoElement.src = "";
1179
+ }
1180
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1181
+ contentVideo.play().catch(() => {
1182
+ });
1183
+ }
1184
+ currentAd = void 0;
1185
+ },
1186
+ destroy() {
1187
+ console.log("[HlsAdPlayer] Destroying");
1188
+ adPlaying = false;
1189
+ contentVideo.muted = originalMutedState;
1190
+ if (adHls) {
1191
+ adHls.destroy();
1192
+ adHls = void 0;
1193
+ }
1194
+ if (adVideoElement) {
1195
+ adVideoElement.pause();
1196
+ adVideoElement.src = "";
1197
+ adVideoElement.remove();
1198
+ adVideoElement = void 0;
1199
+ }
1200
+ if (adContainerEl == null ? void 0 : adContainerEl.parentElement) {
1201
+ adContainerEl.parentElement.removeChild(adContainerEl);
1202
+ }
1203
+ adContainerEl = void 0;
1204
+ currentAd = void 0;
1205
+ listeners.clear();
1206
+ },
1207
+ isAdPlaying() {
1208
+ return adPlaying;
1209
+ },
1210
+ resize(width, height) {
1211
+ console.log(`[HlsAdPlayer] Resizing to ${width}x${height}`);
1212
+ if (adContainerEl) {
1213
+ adContainerEl.style.width = `${width}px`;
1214
+ adContainerEl.style.height = `${height}px`;
1215
+ }
1216
+ if (adVideoElement) {
1217
+ adVideoElement.style.width = `${width}px`;
1218
+ adVideoElement.style.height = `${height}px`;
1219
+ }
1220
+ },
1221
+ on(event, listener) {
1222
+ if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
1223
+ listeners.get(event).add(listener);
1224
+ },
1225
+ off(event, listener) {
1226
+ var _a;
1227
+ (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
1228
+ },
1229
+ updateOriginalMutedState(muted) {
1230
+ originalMutedState = muted;
1231
+ },
1232
+ getOriginalMutedState() {
1233
+ return originalMutedState;
1234
+ },
1235
+ setAdVolume(volume) {
1236
+ if (adVideoElement && adPlaying) {
1237
+ adVideoElement.volume = Math.max(0, Math.min(1, volume));
1238
+ }
1239
+ },
1240
+ getAdVolume() {
1241
+ if (adVideoElement && adPlaying) {
1242
+ return adVideoElement.volume;
1243
+ }
1244
+ return 1;
1245
+ }
1246
+ };
1247
+ }
1248
+
549
1249
  // src/utils/tracking.ts
550
1250
  var cachedBrowserId = null;
551
1251
  function getClientInfo() {
1252
+ var _a, _b, _c, _d;
552
1253
  const ua = navigator.userAgent;
553
1254
  const platform = navigator.platform;
554
1255
  const vendor = navigator.vendor || "";
@@ -556,12 +1257,12 @@ function getClientInfo() {
556
1257
  const memory = navigator.deviceMemory || null;
557
1258
  const hardwareConcurrency = navigator.hardwareConcurrency || 1;
558
1259
  const screenInfo = {
559
- width: screen?.width,
560
- height: screen?.height,
561
- availWidth: screen?.availWidth,
562
- availHeight: screen?.availHeight,
563
- orientation: screen?.orientation?.type || "",
564
- pixelDepth: screen?.pixelDepth
1260
+ width: screen == null ? void 0 : screen.width,
1261
+ height: screen == null ? void 0 : screen.height,
1262
+ availWidth: screen == null ? void 0 : screen.availWidth,
1263
+ availHeight: screen == null ? void 0 : screen.availHeight,
1264
+ orientation: ((_a = screen == null ? void 0 : screen.orientation) == null ? void 0 : _a.type) || "",
1265
+ pixelDepth: screen == null ? void 0 : screen.pixelDepth
565
1266
  };
566
1267
  let deviceType = "desktop";
567
1268
  let brand = "Unknown";
@@ -658,10 +1359,10 @@ function getClientInfo() {
658
1359
  if (vendor.includes("Samsung") || ua.includes("SM-")) brand = "Samsung";
659
1360
  }
660
1361
  isWebView = /wv|WebView|Linux; U;/.test(ua);
661
- if (window?.outerHeight === 0 && window?.outerWidth === 0) {
1362
+ if ((window == null ? void 0 : window.outerHeight) === 0 && (window == null ? void 0 : window.outerWidth) === 0) {
662
1363
  isWebView = true;
663
1364
  }
664
- isWebApp = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true || window.screen?.orientation?.angle !== void 0;
1365
+ isWebApp = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true || ((_c = (_b = window.screen) == null ? void 0 : _b.orientation) == null ? void 0 : _c.angle) !== void 0;
665
1366
  return {
666
1367
  brand,
667
1368
  os,
@@ -682,7 +1383,7 @@ function getClientInfo() {
682
1383
  deviceMemory: memory,
683
1384
  maxTouchPoints,
684
1385
  language: navigator.language,
685
- languages: navigator.languages?.join(",") || "",
1386
+ languages: ((_d = navigator.languages) == null ? void 0 : _d.join(",")) || "",
686
1387
  cookieEnabled: navigator.cookieEnabled,
687
1388
  doNotTrack: navigator.doNotTrack || "",
688
1389
  referrer: document.referrer,
@@ -795,6 +1496,215 @@ async function sendHeartbeat(licenseKey) {
795
1496
  }
796
1497
  }
797
1498
 
1499
+ // src/utils/polyfills.ts
1500
+ function polyfillURLSearchParams() {
1501
+ if (typeof URLSearchParams !== "undefined") {
1502
+ return;
1503
+ }
1504
+ class URLSearchParamsPolyfill {
1505
+ constructor(init) {
1506
+ this.params = /* @__PURE__ */ new Map();
1507
+ if (typeof init === "string") {
1508
+ this.parseQueryString(init);
1509
+ } else if (init instanceof URLSearchParamsPolyfill) {
1510
+ init.forEach((value, key) => {
1511
+ this.append(key, value);
1512
+ });
1513
+ }
1514
+ }
1515
+ parseQueryString(query) {
1516
+ const cleanQuery = query.startsWith("?") ? query.slice(1) : query;
1517
+ if (!cleanQuery) return;
1518
+ cleanQuery.split("&").forEach((param) => {
1519
+ const [key, value] = param.split("=");
1520
+ if (key) {
1521
+ const decodedKey = this.safeDecodeURIComponent(key);
1522
+ const decodedValue = value ? this.safeDecodeURIComponent(value) : "";
1523
+ this.append(decodedKey, decodedValue);
1524
+ }
1525
+ });
1526
+ }
1527
+ safeDecodeURIComponent(str) {
1528
+ try {
1529
+ return decodeURIComponent(str.replace(/\+/g, " "));
1530
+ } catch (e) {
1531
+ return str;
1532
+ }
1533
+ }
1534
+ append(name, value) {
1535
+ const values = this.params.get(name) || [];
1536
+ values.push(String(value));
1537
+ this.params.set(name, values);
1538
+ }
1539
+ delete(name) {
1540
+ this.params.delete(name);
1541
+ }
1542
+ get(name) {
1543
+ const values = this.params.get(name);
1544
+ return values && values.length > 0 && values[0] !== void 0 ? values[0] : null;
1545
+ }
1546
+ getAll(name) {
1547
+ return this.params.get(name) || [];
1548
+ }
1549
+ has(name) {
1550
+ return this.params.has(name);
1551
+ }
1552
+ set(name, value) {
1553
+ this.params.set(name, [String(value)]);
1554
+ }
1555
+ forEach(callback) {
1556
+ this.params.forEach((values, key) => {
1557
+ values.forEach((value) => {
1558
+ callback(value, key, this);
1559
+ });
1560
+ });
1561
+ }
1562
+ toString() {
1563
+ const parts = [];
1564
+ this.params.forEach((values, key) => {
1565
+ values.forEach((value) => {
1566
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
1567
+ });
1568
+ });
1569
+ return parts.join("&");
1570
+ }
1571
+ }
1572
+ window.URLSearchParams = URLSearchParamsPolyfill;
1573
+ }
1574
+ function polyfillTextEncoder() {
1575
+ if (typeof TextEncoder !== "undefined") {
1576
+ return;
1577
+ }
1578
+ class TextEncoderPolyfill {
1579
+ constructor() {
1580
+ this.encoding = "utf-8";
1581
+ }
1582
+ encode(str) {
1583
+ const utf8 = [];
1584
+ for (let i = 0; i < str.length; i++) {
1585
+ let charcode = str.charCodeAt(i);
1586
+ if (charcode < 128) {
1587
+ utf8.push(charcode);
1588
+ } else if (charcode < 2048) {
1589
+ utf8.push(192 | charcode >> 6, 128 | charcode & 63);
1590
+ } else if (charcode < 55296 || charcode >= 57344) {
1591
+ utf8.push(
1592
+ 224 | charcode >> 12,
1593
+ 128 | charcode >> 6 & 63,
1594
+ 128 | charcode & 63
1595
+ );
1596
+ } else {
1597
+ i++;
1598
+ charcode = 65536 + ((charcode & 1023) << 10 | str.charCodeAt(i) & 1023);
1599
+ utf8.push(
1600
+ 240 | charcode >> 18,
1601
+ 128 | charcode >> 12 & 63,
1602
+ 128 | charcode >> 6 & 63,
1603
+ 128 | charcode & 63
1604
+ );
1605
+ }
1606
+ }
1607
+ return new Uint8Array(utf8);
1608
+ }
1609
+ }
1610
+ window.TextEncoder = TextEncoderPolyfill;
1611
+ }
1612
+ function polyfillPromiseFinally() {
1613
+ if (typeof Promise !== "undefined" && !Promise.prototype.finally) {
1614
+ Promise.prototype.finally = function(callback) {
1615
+ const constructor = this.constructor;
1616
+ return this.then(
1617
+ (value) => constructor.resolve(callback()).then(() => value),
1618
+ (reason) => constructor.resolve(callback()).then(() => {
1619
+ throw reason;
1620
+ })
1621
+ );
1622
+ };
1623
+ }
1624
+ }
1625
+ function polyfillObjectAssign() {
1626
+ if (typeof Object.assign !== "function") {
1627
+ Object.assign = function(target, ...sources) {
1628
+ if (target == null) {
1629
+ throw new TypeError("Cannot convert undefined or null to object");
1630
+ }
1631
+ const to = Object(target);
1632
+ for (let i = 0; i < sources.length; i++) {
1633
+ const nextSource = sources[i];
1634
+ if (nextSource != null) {
1635
+ for (const nextKey in nextSource) {
1636
+ if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
1637
+ to[nextKey] = nextSource[nextKey];
1638
+ }
1639
+ }
1640
+ }
1641
+ }
1642
+ return to;
1643
+ };
1644
+ }
1645
+ }
1646
+ function polyfillArrayFrom() {
1647
+ if (!Array.from) {
1648
+ Array.from = function(arrayLike, mapFn, thisArg) {
1649
+ const items = Object(arrayLike);
1650
+ if (arrayLike == null) {
1651
+ throw new TypeError("Array.from requires an array-like object");
1652
+ }
1653
+ const len = items.length >>> 0;
1654
+ const result = new Array(len);
1655
+ for (let i = 0; i < len; i++) {
1656
+ if (mapFn) {
1657
+ result[i] = mapFn.call(thisArg, items[i], i);
1658
+ } else {
1659
+ result[i] = items[i];
1660
+ }
1661
+ }
1662
+ return result;
1663
+ };
1664
+ }
1665
+ }
1666
+ function polyfillStringStartsWith() {
1667
+ if (!String.prototype.startsWith) {
1668
+ String.prototype.startsWith = function(search, pos) {
1669
+ pos = !pos || pos < 0 ? 0 : +pos;
1670
+ return this.substring(pos, pos + search.length) === search;
1671
+ };
1672
+ }
1673
+ }
1674
+ function polyfillStringEndsWith() {
1675
+ if (!String.prototype.endsWith) {
1676
+ String.prototype.endsWith = function(search, length) {
1677
+ if (length === void 0 || length > this.length) {
1678
+ length = this.length;
1679
+ }
1680
+ return this.substring(length - search.length, length) === search;
1681
+ };
1682
+ }
1683
+ }
1684
+ function polyfillStringIncludes() {
1685
+ if (!String.prototype.includes) {
1686
+ String.prototype.includes = function(search, start) {
1687
+ if (typeof start !== "number") {
1688
+ start = 0;
1689
+ }
1690
+ if (start + search.length > this.length) {
1691
+ return false;
1692
+ }
1693
+ return this.indexOf(search, start) !== -1;
1694
+ };
1695
+ }
1696
+ }
1697
+ function initializePolyfills() {
1698
+ polyfillObjectAssign();
1699
+ polyfillArrayFrom();
1700
+ polyfillStringStartsWith();
1701
+ polyfillStringEndsWith();
1702
+ polyfillStringIncludes();
1703
+ polyfillURLSearchParams();
1704
+ polyfillTextEncoder();
1705
+ polyfillPromiseFinally();
1706
+ }
1707
+
798
1708
  // src/player/StormcloudVideoPlayer.ts
799
1709
  var StormcloudVideoPlayer = class {
800
1710
  constructor(config) {
@@ -807,13 +1717,44 @@ var StormcloudVideoPlayer = class {
807
1717
  this.totalAdsInBreak = 0;
808
1718
  this.showAds = false;
809
1719
  this.isLiveStream = false;
810
- this.config = config;
1720
+ initializePolyfills();
1721
+ const browserOverrides = getBrowserConfigOverrides();
1722
+ this.config = { ...config, ...browserOverrides };
811
1723
  this.video = config.videoElement;
812
- this.ima = createImaController(this.video, {
813
- continueLiveStreamDuringAds: false
814
- });
1724
+ logBrowserInfo(config.debugAdTiming);
1725
+ this.ima = this.createAdPlayer(false);
1726
+ }
1727
+ createAdPlayer(continueLiveStreamDuringAds) {
1728
+ const vastMode = this.config.vastMode || "default";
1729
+ let adPlayerType = this.config.adPlayerType || (vastMode === "adstorm" ? "hls" : "ima");
1730
+ if (adPlayerType === "ima" && !supportsGoogleIMA()) {
1731
+ if (this.config.debugAdTiming) {
1732
+ console.warn(
1733
+ "[StormcloudVideoPlayer] Google IMA SDK not supported on this browser, falling back to HLS ad player"
1734
+ );
1735
+ }
1736
+ adPlayerType = "hls";
1737
+ }
1738
+ if (adPlayerType === "hls") {
1739
+ if (this.config.debugAdTiming) {
1740
+ console.log("[StormcloudVideoPlayer] Creating HLS ad player (AdStorm mode)");
1741
+ }
1742
+ return createHlsAdPlayer(this.video, {
1743
+ continueLiveStreamDuringAds,
1744
+ ...this.config.licenseKey ? { licenseKey: this.config.licenseKey } : {},
1745
+ ...this.hls ? { mainHlsInstance: this.hls } : {}
1746
+ });
1747
+ } else {
1748
+ if (this.config.debugAdTiming) {
1749
+ console.log("[StormcloudVideoPlayer] Creating Google IMA ad player (Default mode)");
1750
+ }
1751
+ return createImaController(this.video, {
1752
+ continueLiveStreamDuringAds
1753
+ });
1754
+ }
815
1755
  }
816
1756
  async load() {
1757
+ var _a, _b;
817
1758
  if (!this.attached) {
818
1759
  this.attach();
819
1760
  }
@@ -830,7 +1771,7 @@ var StormcloudVideoPlayer = class {
830
1771
  this.initializeTracking();
831
1772
  if (this.shouldUseNativeHls()) {
832
1773
  this.video.src = this.config.src;
833
- this.isLiveStream = this.config.lowLatencyMode ?? false;
1774
+ this.isLiveStream = (_a = this.config.lowLatencyMode) != null ? _a : false;
834
1775
  if (this.config.debugAdTiming) {
835
1776
  console.log(
836
1777
  "[StormcloudVideoPlayer] allowNativeHls: true - VOD mode detected:",
@@ -842,17 +1783,15 @@ var StormcloudVideoPlayer = class {
842
1783
  );
843
1784
  }
844
1785
  this.ima.destroy();
845
- this.ima = createImaController(this.video, {
846
- continueLiveStreamDuringAds: false
847
- });
1786
+ this.ima = this.createAdPlayer(false);
848
1787
  this.ima.initialize();
849
1788
  if (this.config.autoplay) {
850
- await this.video.play()?.catch(() => {
851
- });
1789
+ await ((_b = this.video.play()) == null ? void 0 : _b.catch(() => {
1790
+ }));
852
1791
  }
853
1792
  return;
854
1793
  }
855
- this.hls = new import_hls.default({
1794
+ this.hls = new import_hls2.default({
856
1795
  enableWorker: true,
857
1796
  backBufferLength: 30,
858
1797
  liveDurationInfinity: true,
@@ -860,13 +1799,18 @@ var StormcloudVideoPlayer = class {
860
1799
  maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
861
1800
  ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}
862
1801
  });
863
- this.hls.on(import_hls.default.Events.MEDIA_ATTACHED, () => {
864
- this.hls?.loadSource(this.config.src);
1802
+ this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
1803
+ var _a2;
1804
+ (_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
865
1805
  });
866
- this.hls.on(import_hls.default.Events.MANIFEST_PARSED, async (_, data) => {
867
- this.isLiveStream = this.hls?.levels?.some(
868
- (level) => level?.details?.live === true || level?.details?.type === "LIVE"
869
- ) ?? false;
1806
+ this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
1807
+ var _a2, _b2, _c, _d;
1808
+ this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
1809
+ (level) => {
1810
+ var _a3, _b3;
1811
+ return ((_a3 = level == null ? void 0 : level.details) == null ? void 0 : _a3.live) === true || ((_b3 = level == null ? void 0 : level.details) == null ? void 0 : _b3.type) === "LIVE";
1812
+ }
1813
+ )) != null ? _c : false;
870
1814
  if (this.config.debugAdTiming) {
871
1815
  const adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
872
1816
  console.log("[StormcloudVideoPlayer] Stream type detected:", {
@@ -876,33 +1820,32 @@ var StormcloudVideoPlayer = class {
876
1820
  });
877
1821
  }
878
1822
  this.ima.destroy();
879
- this.ima = createImaController(this.video, {
880
- continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds()
881
- });
1823
+ this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
882
1824
  this.ima.initialize();
883
1825
  if (this.config.autoplay) {
884
- await this.video.play()?.catch(() => {
885
- });
1826
+ await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
1827
+ }));
886
1828
  }
887
1829
  });
888
- this.hls.on(import_hls.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
889
- const id3Tags = (data?.samples || []).map((s) => ({
1830
+ this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
1831
+ const id3Tags = ((data == null ? void 0 : data.samples) || []).map((s) => ({
890
1832
  key: "ID3",
891
- value: s?.data,
892
- ptsSeconds: s?.pts
1833
+ value: s == null ? void 0 : s.data,
1834
+ ptsSeconds: s == null ? void 0 : s.pts
893
1835
  }));
894
1836
  id3Tags.forEach((tag) => this.onId3Tag(tag));
895
1837
  });
896
- this.hls.on(import_hls.default.Events.FRAG_CHANGED, (_evt, data) => {
897
- const frag = data?.frag;
898
- const tagList = frag?.tagList;
1838
+ this.hls.on(import_hls2.default.Events.FRAG_CHANGED, (_evt, data) => {
1839
+ var _a2, _b2, _c;
1840
+ const frag = data == null ? void 0 : data.frag;
1841
+ const tagList = frag == null ? void 0 : frag.tagList;
899
1842
  if (!Array.isArray(tagList)) return;
900
1843
  for (const entry of tagList) {
901
1844
  let tag = "";
902
1845
  let value = "";
903
1846
  if (Array.isArray(entry)) {
904
- tag = String(entry[0] ?? "");
905
- value = String(entry[1] ?? "");
1847
+ tag = String((_a2 = entry[0]) != null ? _a2 : "");
1848
+ value = String((_b2 = entry[1]) != null ? _b2 : "");
906
1849
  } else if (typeof entry === "string") {
907
1850
  const idx = entry.indexOf(":");
908
1851
  if (idx >= 0) {
@@ -926,8 +1869,8 @@ var StormcloudVideoPlayer = class {
926
1869
  const prog = this.parseCueOutCont(value);
927
1870
  const marker = {
928
1871
  type: "progress",
929
- ...prog?.duration !== void 0 ? { durationSeconds: prog.duration } : {},
930
- ...prog?.elapsed !== void 0 ? { ptsSeconds: prog.elapsed } : {},
1872
+ ...(prog == null ? void 0 : prog.duration) !== void 0 ? { durationSeconds: prog.duration } : {},
1873
+ ...(prog == null ? void 0 : prog.elapsed) !== void 0 ? { ptsSeconds: prog.elapsed } : {},
931
1874
  raw: { tag, value }
932
1875
  };
933
1876
  this.onScte35Marker(marker);
@@ -937,7 +1880,7 @@ var StormcloudVideoPlayer = class {
937
1880
  const attrs = this.parseAttributeList(value);
938
1881
  const hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
939
1882
  const hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
940
- const klass = String(attrs["CLASS"] ?? "");
1883
+ const klass = String((_c = attrs["CLASS"]) != null ? _c : "");
941
1884
  const duration = this.toNumber(attrs["DURATION"]);
942
1885
  if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
943
1886
  const marker = {
@@ -953,14 +1896,15 @@ var StormcloudVideoPlayer = class {
953
1896
  }
954
1897
  }
955
1898
  });
956
- this.hls.on(import_hls.default.Events.ERROR, (_evt, data) => {
957
- if (data?.fatal) {
1899
+ this.hls.on(import_hls2.default.Events.ERROR, (_evt, data) => {
1900
+ var _a2, _b2;
1901
+ if (data == null ? void 0 : data.fatal) {
958
1902
  switch (data.type) {
959
- case import_hls.default.ErrorTypes.NETWORK_ERROR:
960
- this.hls?.startLoad();
1903
+ case import_hls2.default.ErrorTypes.NETWORK_ERROR:
1904
+ (_a2 = this.hls) == null ? void 0 : _a2.startLoad();
961
1905
  break;
962
- case import_hls.default.ErrorTypes.MEDIA_ERROR:
963
- this.hls?.recoverMediaError();
1906
+ case import_hls2.default.ErrorTypes.MEDIA_ERROR:
1907
+ (_b2 = this.hls) == null ? void 0 : _b2.recoverMediaError();
964
1908
  break;
965
1909
  default:
966
1910
  this.destroy();
@@ -1062,11 +2006,12 @@ var StormcloudVideoPlayer = class {
1062
2006
  }
1063
2007
  }
1064
2008
  parseScte35FromId3(tag) {
2009
+ var _a, _b, _c, _d;
1065
2010
  const text = this.decodeId3ValueToText(tag.value);
1066
2011
  if (!text) return void 0;
1067
2012
  const cueOutMatch = text.match(/EXT-X-CUE-OUT(?::([^\r\n]*))?/i) || text.match(/CUE-OUT(?::([^\r\n]*))?/i);
1068
2013
  if (cueOutMatch) {
1069
- const arg = (cueOutMatch[1] ?? "").trim();
2014
+ const arg = ((_a = cueOutMatch[1]) != null ? _a : "").trim();
1070
2015
  const dur = this.parseCueOutDuration(arg);
1071
2016
  const marker = {
1072
2017
  type: "start",
@@ -1078,12 +2023,12 @@ var StormcloudVideoPlayer = class {
1078
2023
  }
1079
2024
  const cueOutContMatch = text.match(/EXT-X-CUE-OUT-CONT:([^\r\n]*)/i);
1080
2025
  if (cueOutContMatch) {
1081
- const arg = (cueOutContMatch[1] ?? "").trim();
2026
+ const arg = ((_b = cueOutContMatch[1]) != null ? _b : "").trim();
1082
2027
  const cont = this.parseCueOutCont(arg);
1083
2028
  const marker = {
1084
2029
  type: "progress",
1085
2030
  ...tag.ptsSeconds !== void 0 ? { ptsSeconds: tag.ptsSeconds } : {},
1086
- ...cont?.duration !== void 0 ? { durationSeconds: cont.duration } : {},
2031
+ ...(cont == null ? void 0 : cont.duration) !== void 0 ? { durationSeconds: cont.duration } : {},
1087
2032
  raw: { id3: text }
1088
2033
  };
1089
2034
  return marker;
@@ -1099,10 +2044,10 @@ var StormcloudVideoPlayer = class {
1099
2044
  }
1100
2045
  const daterangeMatch = text.match(/EXT-X-DATERANGE:([^\r\n]*)/i);
1101
2046
  if (daterangeMatch) {
1102
- const attrs = this.parseAttributeList(daterangeMatch[1] ?? "");
2047
+ const attrs = this.parseAttributeList((_c = daterangeMatch[1]) != null ? _c : "");
1103
2048
  const hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
1104
2049
  const hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
1105
- const klass = String(attrs["CLASS"] ?? "");
2050
+ const klass = String((_d = attrs["CLASS"]) != null ? _d : "");
1106
2051
  const duration = this.toNumber(attrs["DURATION"]);
1107
2052
  if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
1108
2053
  const marker = {
@@ -1159,6 +2104,7 @@ var StormcloudVideoPlayer = class {
1159
2104
  }
1160
2105
  }
1161
2106
  onScte35Marker(marker) {
2107
+ var _a, _b;
1162
2108
  if (this.config.debugAdTiming) {
1163
2109
  console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
1164
2110
  type: marker.type,
@@ -1174,7 +2120,7 @@ var StormcloudVideoPlayer = class {
1174
2120
  this.expectedAdBreakDurationMs = durationMs;
1175
2121
  this.currentAdBreakStartWallClockMs = Date.now();
1176
2122
  const isManifestMarker = this.isManifestBasedMarker(marker);
1177
- const forceImmediate = this.config.immediateManifestAds ?? true;
2123
+ const forceImmediate = (_a = this.config.immediateManifestAds) != null ? _a : true;
1178
2124
  if (this.config.debugAdTiming) {
1179
2125
  console.log("[StormcloudVideoPlayer] Ad start decision:", {
1180
2126
  isManifestMarker,
@@ -1191,7 +2137,7 @@ var StormcloudVideoPlayer = class {
1191
2137
  this.clearAdStartTimer();
1192
2138
  this.handleAdStart(marker);
1193
2139
  } else if (typeof marker.ptsSeconds === "number") {
1194
- const tol = this.config.driftToleranceMs ?? 1e3;
2140
+ const tol = (_b = this.config.driftToleranceMs) != null ? _b : 1e3;
1195
2141
  const nowMs = this.video.currentTime * 1e3;
1196
2142
  const estCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
1197
2143
  const deltaMs = Math.floor(marker.ptsSeconds * 1e3 - estCurrentPtsMs);
@@ -1301,12 +2247,13 @@ var StormcloudVideoPlayer = class {
1301
2247
  return void 0;
1302
2248
  }
1303
2249
  parseAttributeList(value) {
2250
+ var _a, _b, _c;
1304
2251
  const attrs = {};
1305
2252
  const regex = /([A-Z0-9-]+)=(("[^"]*")|([^",]*))(?:,|$)/gi;
1306
2253
  let match;
1307
2254
  while ((match = regex.exec(value)) !== null) {
1308
- const key = match[1] ?? "";
1309
- let rawVal = match[3] ?? match[4] ?? "";
2255
+ const key = (_a = match[1]) != null ? _a : "";
2256
+ let rawVal = (_c = (_b = match[3]) != null ? _b : match[4]) != null ? _c : "";
1310
2257
  if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
1311
2258
  rawVal = rawVal.slice(1, -1);
1312
2259
  }
@@ -1470,6 +2417,43 @@ var StormcloudVideoPlayer = class {
1470
2417
  }
1471
2418
  }
1472
2419
  async fetchAdConfiguration() {
2420
+ var _a, _b, _c;
2421
+ const vastMode = this.config.vastMode || "default";
2422
+ if (this.config.debugAdTiming) {
2423
+ console.log(
2424
+ "[StormcloudVideoPlayer] VAST mode:",
2425
+ vastMode
2426
+ );
2427
+ }
2428
+ if (vastMode === "adstorm") {
2429
+ if (!this.config.licenseKey) {
2430
+ if (this.config.debugAdTiming) {
2431
+ console.warn(
2432
+ "[StormcloudVideoPlayer] AdStorm mode requires a license key"
2433
+ );
2434
+ }
2435
+ return;
2436
+ }
2437
+ const vastEndpoint = `https://adstorm.co/api-adstorm-dev/adstorm/vast/${this.config.licenseKey}`;
2438
+ this.apiVastTagUrl = vastEndpoint;
2439
+ if (this.config.debugAdTiming) {
2440
+ console.log(
2441
+ "[StormcloudVideoPlayer] Using AdStorm VAST endpoint:",
2442
+ vastEndpoint
2443
+ );
2444
+ }
2445
+ return;
2446
+ }
2447
+ if (this.config.vastTagUrl) {
2448
+ this.apiVastTagUrl = this.config.vastTagUrl;
2449
+ if (this.config.debugAdTiming) {
2450
+ console.log(
2451
+ "[StormcloudVideoPlayer] Using custom VAST tag URL:",
2452
+ this.apiVastTagUrl
2453
+ );
2454
+ }
2455
+ return;
2456
+ }
1473
2457
  const apiUrl = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
1474
2458
  if (this.config.debugAdTiming) {
1475
2459
  console.log(
@@ -1483,25 +2467,29 @@ var StormcloudVideoPlayer = class {
1483
2467
  }
1484
2468
  const response = await fetch(apiUrl, { headers });
1485
2469
  if (!response.ok) {
1486
- throw new Error(`Failed to fetch ad configuration: ${response.status}`);
2470
+ if (this.config.debugAdTiming) {
2471
+ console.warn(
2472
+ `[StormcloudVideoPlayer] Failed to fetch ad configuration: ${response.status}`
2473
+ );
2474
+ }
2475
+ return;
1487
2476
  }
1488
2477
  const data = await response.json();
1489
- const imaPayload = data.response?.ima?.["publisherdesk.ima"]?.payload;
2478
+ const imaPayload = (_c = (_b = (_a = data.response) == null ? void 0 : _a.ima) == null ? void 0 : _b["publisherdesk.ima"]) == null ? void 0 : _c.payload;
1490
2479
  if (imaPayload) {
1491
2480
  this.apiVastTagUrl = decodeURIComponent(imaPayload);
1492
2481
  if (this.config.debugAdTiming) {
1493
2482
  console.log(
1494
- "[StormcloudVideoPlayer] Extracted VAST tag URL:",
2483
+ "[StormcloudVideoPlayer] Extracted VAST tag URL from /ads/web:",
1495
2484
  this.apiVastTagUrl
1496
2485
  );
1497
2486
  }
1498
- }
1499
- this.vastConfig = data.response?.options?.vast;
1500
- if (this.config.debugAdTiming) {
1501
- console.log("[StormcloudVideoPlayer] Ad configuration loaded:", {
1502
- vastTagUrl: this.apiVastTagUrl,
1503
- vastConfig: this.vastConfig
1504
- });
2487
+ } else {
2488
+ if (this.config.debugAdTiming) {
2489
+ console.warn(
2490
+ "[StormcloudVideoPlayer] No VAST tag URL found in /ads/web response"
2491
+ );
2492
+ }
1505
2493
  }
1506
2494
  }
1507
2495
  getCurrentAdIndex() {
@@ -1524,11 +2512,12 @@ var StormcloudVideoPlayer = class {
1524
2512
  return "other";
1525
2513
  }
1526
2514
  shouldShowNativeControls() {
2515
+ var _a, _b;
1527
2516
  const streamType = this.getStreamType();
1528
2517
  if (streamType === "other") {
1529
- return !(this.config.showCustomControls ?? false);
2518
+ return !((_a = this.config.showCustomControls) != null ? _a : false);
1530
2519
  }
1531
- return !!(this.config.allowNativeHls && !(this.config.showCustomControls ?? false));
2520
+ return !!(this.config.allowNativeHls && !((_b = this.config.showCustomControls) != null ? _b : false));
1532
2521
  }
1533
2522
  shouldContinueLiveStreamDuringAds() {
1534
2523
  if (this.config.allowNativeHls) {
@@ -1540,28 +2529,20 @@ var StormcloudVideoPlayer = class {
1540
2529
  return true;
1541
2530
  }
1542
2531
  async handleAdStart(_marker) {
2532
+ var _a;
1543
2533
  const scheduled = this.findCurrentOrNextBreak(
1544
2534
  this.video.currentTime * 1e3
1545
2535
  );
1546
2536
  const tags = this.selectVastTagsForBreak(scheduled);
1547
2537
  let vastTagUrl;
1548
- let adsNumber = 1;
1549
2538
  if (this.apiVastTagUrl) {
1550
2539
  vastTagUrl = this.apiVastTagUrl;
1551
- if (this.vastConfig) {
1552
- const isHls = this.config.src.includes(".m3u8") || this.config.src.includes("hls");
1553
- if (isHls && this.vastConfig.cue_tones?.number_ads) {
1554
- adsNumber = this.vastConfig.cue_tones.number_ads;
1555
- } else if (!isHls && this.vastConfig.timer_vod?.number_ads) {
1556
- adsNumber = this.vastConfig.timer_vod.number_ads;
1557
- }
1558
- }
1559
- this.adPodQueue = new Array(adsNumber - 1).fill(vastTagUrl);
2540
+ this.adPodQueue = [];
1560
2541
  this.currentAdIndex = 0;
1561
- this.totalAdsInBreak = adsNumber;
2542
+ this.totalAdsInBreak = 1;
1562
2543
  if (this.config.debugAdTiming) {
1563
2544
  console.log(
1564
- `[StormcloudVideoPlayer] Using API VAST tag with ${adsNumber} ads:`,
2545
+ "[StormcloudVideoPlayer] Using VAST endpoint:",
1565
2546
  vastTagUrl
1566
2547
  );
1567
2548
  }
@@ -1599,17 +2580,18 @@ var StormcloudVideoPlayer = class {
1599
2580
  this.handleAdFailure();
1600
2581
  }
1601
2582
  }
1602
- if (this.expectedAdBreakDurationMs == null && scheduled?.durationMs != null) {
2583
+ if (this.expectedAdBreakDurationMs == null && (scheduled == null ? void 0 : scheduled.durationMs) != null) {
1603
2584
  this.expectedAdBreakDurationMs = scheduled.durationMs;
1604
- this.currentAdBreakStartWallClockMs = this.currentAdBreakStartWallClockMs ?? Date.now();
2585
+ this.currentAdBreakStartWallClockMs = (_a = this.currentAdBreakStartWallClockMs) != null ? _a : Date.now();
1605
2586
  this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
1606
2587
  }
1607
2588
  }
1608
2589
  findCurrentOrNextBreak(nowMs) {
2590
+ var _a;
1609
2591
  const schedule = [];
1610
2592
  let candidate;
1611
2593
  for (const b of schedule) {
1612
- const tol = this.config.driftToleranceMs ?? 1e3;
2594
+ const tol = (_a = this.config.driftToleranceMs) != null ? _a : 1e3;
1613
2595
  if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
1614
2596
  candidate = b;
1615
2597
  }
@@ -1625,7 +2607,8 @@ var StormcloudVideoPlayer = class {
1625
2607
  }
1626
2608
  }
1627
2609
  async handleMidAdJoin(adBreak, nowMs) {
1628
- const durationMs = adBreak.durationMs ?? 0;
2610
+ var _a;
2611
+ const durationMs = (_a = adBreak.durationMs) != null ? _a : 0;
1629
2612
  const endMs = adBreak.startTimeMs + durationMs;
1630
2613
  if (durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs) {
1631
2614
  const remainingMs = endMs - nowMs;
@@ -1726,6 +2709,7 @@ var StormcloudVideoPlayer = class {
1726
2709
  }
1727
2710
  }
1728
2711
  handleAdFailure() {
2712
+ var _a;
1729
2713
  if (this.config.debugAdTiming) {
1730
2714
  console.log(
1731
2715
  "[StormcloudVideoPlayer] Handling ad failure - resuming content",
@@ -1758,7 +2742,7 @@ var StormcloudVideoPlayer = class {
1758
2742
  if (this.config.debugAdTiming) {
1759
2743
  console.log("[StormcloudVideoPlayer] Resuming paused video");
1760
2744
  }
1761
- this.video.play()?.catch((error) => {
2745
+ (_a = this.video.play()) == null ? void 0 : _a.catch((error) => {
1762
2746
  if (this.config.debugAdTiming) {
1763
2747
  console.error(
1764
2748
  "[StormcloudVideoPlayer] Failed to resume video after ad failure:",
@@ -1773,8 +2757,9 @@ var StormcloudVideoPlayer = class {
1773
2757
  }
1774
2758
  }
1775
2759
  startAdFailsafeTimer() {
2760
+ var _a;
1776
2761
  this.clearAdFailsafeTimer();
1777
- const failsafeMs = this.config.adFailsafeTimeoutMs ?? 1e4;
2762
+ const failsafeMs = (_a = this.config.adFailsafeTimeoutMs) != null ? _a : 1e4;
1778
2763
  if (this.config.debugAdTiming) {
1779
2764
  console.log(
1780
2765
  `[StormcloudVideoPlayer] Starting failsafe timer (${failsafeMs}ms)`
@@ -1910,6 +2895,7 @@ var StormcloudVideoPlayer = class {
1910
2895
  }
1911
2896
  }
1912
2897
  destroy() {
2898
+ var _a, _b;
1913
2899
  this.clearAdStartTimer();
1914
2900
  this.clearAdStopTimer();
1915
2901
  this.clearAdFailsafeTimer();
@@ -1917,8 +2903,8 @@ var StormcloudVideoPlayer = class {
1917
2903
  clearInterval(this.heartbeatInterval);
1918
2904
  this.heartbeatInterval = void 0;
1919
2905
  }
1920
- this.hls?.destroy();
1921
- this.ima?.destroy();
2906
+ (_a = this.hls) == null ? void 0 : _a.destroy();
2907
+ (_b = this.ima) == null ? void 0 : _b.destroy();
1922
2908
  }
1923
2909
  };
1924
2910
  // Annotate the CommonJS export names for ESM import in node: