stormcloud-video-player 0.7.3 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -458,15 +458,12 @@ __export(index_exports, {
458
458
  canPlay: function canPlay1() {
459
459
  return canPlay;
460
460
  },
461
+ createAdStormPlayer: function createAdStormPlayer1() {
462
+ return createAdStormPlayer;
463
+ },
461
464
  createStormcloudPlayer: function createStormcloudPlayer1() {
462
465
  return createStormcloudPlayer;
463
466
  },
464
- createVastAdLayer: function createVastAdLayer1() {
465
- return createVastAdLayer;
466
- },
467
- createVastManager: function createVastManager1() {
468
- return createVastManager;
469
- },
470
467
  default: function _default() {
471
468
  return StormcloudVideoPlayerComponent;
472
469
  },
@@ -541,185 +538,8 @@ module.exports = __toCommonJS(index_exports);
541
538
  // src/ui/StormcloudVideoPlayer.tsx
542
539
  var import_react2 = __toESM(require("react"), 1);
543
540
  // src/player/StormcloudVideoPlayer.ts
544
- var import_hls2 = __toESM(require("hls.js"), 1);
541
+ var import_hls = __toESM(require("hls.js"), 1);
545
542
  // src/sdk/vastParser.ts
546
- function isHlsType(type) {
547
- return type === "application/x-mpegURL" || type.includes("m3u8");
548
- }
549
- function isMp4Type(type) {
550
- return type === "video/mp4" || type.includes("mp4");
551
- }
552
- function parseVastXml(xmlString) {
553
- var filter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all", logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
554
- try {
555
- var _xmlDoc_querySelector, _xmlDoc_querySelector1, _xmlDoc_querySelector_textContent, _xmlDoc_querySelector2;
556
- var parser = new DOMParser();
557
- var xmlDoc = parser.parseFromString(xmlString, "text/xml");
558
- var parserError = xmlDoc.querySelector("parsererror");
559
- if (parserError) {
560
- console.error("".concat(logPrefix, " XML parsing error (malformed VAST XML):"), parserError.textContent);
561
- return null;
562
- }
563
- var adElement = xmlDoc.querySelector("Ad");
564
- if (!adElement) {
565
- console.warn("".concat(logPrefix, " No Ad element found in VAST XML"));
566
- return null;
567
- }
568
- var adId = adElement.getAttribute("id") || "unknown";
569
- var title = ((_xmlDoc_querySelector = xmlDoc.querySelector("AdTitle")) === null || _xmlDoc_querySelector === void 0 ? void 0 : _xmlDoc_querySelector.textContent) || "Ad";
570
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
571
- var durationText = ((_xmlDoc_querySelector1 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector1 === void 0 ? void 0 : _xmlDoc_querySelector1.textContent) || "00:00:30";
572
- var durationParts = durationText.split(":");
573
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + Math.round(parseFloat(durationParts[2] || "0"));
574
- var mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
575
- var mediaFiles = [];
576
- console.log("".concat(logPrefix, " Found ").concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
577
- mediaFileElements.forEach(function(mf, index) {
578
- var _mf_textContent;
579
- var type = mf.getAttribute("type") || "";
580
- var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
581
- var width = mf.getAttribute("width") || "";
582
- var height = mf.getAttribute("height") || "";
583
- console.log("".concat(logPrefix, " MediaFile ").concat(index, ': type="').concat(type, '", url="').concat(url.substring(0, 80), '...", width="').concat(width, '", height="').concat(height, '"'));
584
- if (!url) {
585
- console.warn("".concat(logPrefix, " MediaFile ").concat(index, " has empty URL"));
586
- return;
587
- }
588
- var isHls = isHlsType(type);
589
- var isMp4 = isMp4Type(type);
590
- var accepted = false;
591
- if (filter === "hls-only") {
592
- accepted = isHls;
593
- } else if (filter === "mp4-first") {
594
- accepted = isMp4 || isHls;
595
- } else {
596
- accepted = true;
597
- }
598
- if (!accepted) {
599
- console.log("".concat(logPrefix, " MediaFile ").concat(index, ' ignored (type="').concat(type, '" not accepted by filter "').concat(filter, '")'));
600
- return;
601
- }
602
- var bitrateAttr = mf.getAttribute("bitrate");
603
- var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
604
- mediaFiles.push({
605
- url: url,
606
- type: type,
607
- width: parseInt(width || "1920", 10),
608
- height: parseInt(height || "1080", 10),
609
- bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
610
- });
611
- console.log("".concat(logPrefix, ' Added MediaFile: type="').concat(type, '" url="').concat(url.substring(0, 80), '..."'));
612
- });
613
- if (filter === "mp4-first" && mediaFiles.length > 1) {
614
- mediaFiles.sort(function(a, b) {
615
- var aIsMp4 = isMp4Type(a.type) ? 0 : 1;
616
- var bIsMp4 = isMp4Type(b.type) ? 0 : 1;
617
- return aIsMp4 - bIsMp4;
618
- });
619
- }
620
- if (mediaFiles.length === 0) {
621
- if (isNoAdAvailable) {
622
- console.warn("".concat(logPrefix, " No ads available (VAST response indicates no ads)"));
623
- } else {
624
- console.warn("".concat(logPrefix, " No compatible media files found in VAST XML"));
625
- }
626
- return null;
627
- }
628
- var trackingUrls = {
629
- impression: [],
630
- start: [],
631
- firstQuartile: [],
632
- midpoint: [],
633
- thirdQuartile: [],
634
- complete: [],
635
- mute: [],
636
- unmute: [],
637
- pause: [],
638
- resume: [],
639
- fullscreen: [],
640
- exitFullscreen: [],
641
- skip: [],
642
- error: []
643
- };
644
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
645
- var _el_textContent;
646
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
647
- if (url) trackingUrls.impression.push(url);
648
- });
649
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
650
- var _el_textContent;
651
- var event = el.getAttribute("event");
652
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
653
- if (event && url) {
654
- var eventKey = event;
655
- if (trackingUrls[eventKey]) {
656
- trackingUrls[eventKey].push(url);
657
- }
658
- }
659
- });
660
- var clickThrough = (_xmlDoc_querySelector2 = xmlDoc.querySelector("ClickThrough")) === null || _xmlDoc_querySelector2 === void 0 ? void 0 : (_xmlDoc_querySelector_textContent = _xmlDoc_querySelector2.textContent) === null || _xmlDoc_querySelector_textContent === void 0 ? void 0 : _xmlDoc_querySelector_textContent.trim();
661
- return {
662
- id: adId,
663
- title: title,
664
- duration: duration,
665
- mediaFiles: mediaFiles,
666
- trackingUrls: trackingUrls,
667
- clickThrough: clickThrough
668
- };
669
- } catch (error) {
670
- console.error("".concat(logPrefix, " Error parsing VAST XML:"), error);
671
- return null;
672
- }
673
- }
674
- function fetchAndParseVastAd(vastTagUrl) {
675
- var filter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all", logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
676
- return _async_to_generator(function() {
677
- var response, vastXml;
678
- return _ts_generator(this, function(_state) {
679
- switch(_state.label){
680
- case 0:
681
- return [
682
- 4,
683
- fetch(vastTagUrl, {
684
- mode: "cors",
685
- credentials: "include",
686
- headers: {
687
- Accept: "application/xml, text/xml, */*"
688
- },
689
- referrerPolicy: "no-referrer-when-downgrade"
690
- })
691
- ];
692
- case 1:
693
- response = _state.sent();
694
- if (!response.ok) {
695
- throw new Error("Failed to fetch VAST: ".concat(response.statusText));
696
- }
697
- return [
698
- 4,
699
- response.text()
700
- ];
701
- case 2:
702
- vastXml = _state.sent();
703
- console.log("".concat(logPrefix, " VAST XML received"));
704
- console.log("".concat(logPrefix, " VAST XML content (first 2000 chars):"), vastXml.substring(0, 2e3));
705
- return [
706
- 2,
707
- parseVastXml(vastXml, filter, logPrefix)
708
- ];
709
- }
710
- });
711
- })();
712
- }
713
- function createEmptyTrackingState() {
714
- return {
715
- impression: false,
716
- start: false,
717
- firstQuartile: false,
718
- midpoint: false,
719
- thirdQuartile: false,
720
- complete: false
721
- };
722
- }
723
543
  function firePixelWithRetry(url) {
724
544
  var retries = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 2, delayMs = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 500, logPrefix = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "[VastParser]";
725
545
  return _async_to_generator(function() {
@@ -842,16 +662,164 @@ function fireTrackingPixels(urls, sessionId) {
842
662
  }
843
663
  });
844
664
  }
845
- // src/sdk/vastManager.ts
846
- var VAST_TAG_URL = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
847
- var DEFAULT_TIMEOUT_MS = 5e3;
848
- var MAX_RETRIES = 3;
849
- var RETRY_BACKOFF_MS = 1500;
850
- function createVastManager() {
851
- var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
852
- var _options_debug;
853
- var initialized = false;
854
- var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
665
+ // src/sdk/adstormPlayer.ts
666
+ var SUPPORTED_VIDEO_EXTENSIONS = [
667
+ ".mp4",
668
+ ".webm",
669
+ ".ogg",
670
+ ".m3u8",
671
+ ".ts"
672
+ ];
673
+ var UNSUPPORTED_VIDEO_EXTENSIONS = [
674
+ ".flv",
675
+ ".f4v",
676
+ ".swf",
677
+ ".wmv",
678
+ ".avi",
679
+ ".mov",
680
+ ".mkv"
681
+ ];
682
+ var REQUEST_TIMEOUT_MS = 5e3;
683
+ var REQUEST_MAX_RETRIES = 3;
684
+ var REQUEST_RETRY_BACKOFF_MS = 1500;
685
+ var AD_LAYER_Z_INDEX = "2147483646";
686
+ var COUNTDOWN_Z_INDEX = "2147483647";
687
+ var STALL_TIMEOUT_MS = 8e3;
688
+ function getFileExtension(url) {
689
+ try {
690
+ var pathname = new URL(url, "http://dummy").pathname;
691
+ var lastDot = pathname.lastIndexOf(".");
692
+ if (lastDot === -1) return "";
693
+ return pathname.slice(lastDot).toLowerCase();
694
+ } catch (unused) {
695
+ var lastDot1 = url.lastIndexOf(".");
696
+ if (lastDot1 === -1) return "";
697
+ var ext = url.slice(lastDot1).split(/[?#]/)[0];
698
+ return (ext || "").toLowerCase();
699
+ }
700
+ }
701
+ function isUnsupportedFormat(url) {
702
+ var ext = getFileExtension(url);
703
+ return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;
704
+ }
705
+ function replaceFlvExtension(url) {
706
+ var ext = getFileExtension(url);
707
+ if (ext === ".flv") {
708
+ return url.replace(/\.flv(\?|$)/i, ".mp4$1");
709
+ }
710
+ return url;
711
+ }
712
+ function isSupportedFormat(url, mimeType) {
713
+ if (isUnsupportedFormat(url)) {
714
+ return false;
715
+ }
716
+ var ext = getFileExtension(url);
717
+ if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {
718
+ return true;
719
+ }
720
+ if (ext === "" || ext === ".") {
721
+ return mimeType.includes("video/mp4") || mimeType.includes("video/webm") || mimeType.includes("m3u8") || mimeType.includes("application/x-mpegurl");
722
+ }
723
+ return false;
724
+ }
725
+ function createAdStormPlayer(contentVideo, options) {
726
+ var licenseKey = options.licenseKey, _options_debug = options.debug, debug = _options_debug === void 0 ? false : _options_debug;
727
+ var adPlaying = false;
728
+ var originalMutedState = false;
729
+ var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
730
+ var listeners = /* @__PURE__ */ new Map();
731
+ var adVideoElement;
732
+ var adContainerEl;
733
+ var adCountdownEl;
734
+ var currentAd;
735
+ var destroyed = false;
736
+ var tornDown = false;
737
+ var continueLiveStreamDuringAds = false;
738
+ var sessionId;
739
+ var adStallTimerId;
740
+ var adCountdownTimerId;
741
+ var adHideTimerId;
742
+ var lastCountdownSecond = -1;
743
+ var adListenersBound = false;
744
+ var parentPositionOverridden = false;
745
+ var adHandlers = {
746
+ timeupdate: function timeupdate() {
747
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
748
+ var progress = adVideoElement.currentTime / currentAd.duration;
749
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
750
+ trackingFired.firstQuartile = true;
751
+ fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);
752
+ }
753
+ if (progress >= 0.5 && !trackingFired.midpoint) {
754
+ trackingFired.midpoint = true;
755
+ fireTrackingPixels2(currentAd.trackingUrls.midpoint);
756
+ }
757
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
758
+ trackingFired.thirdQuartile = true;
759
+ fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);
760
+ }
761
+ updateAdCountdown();
762
+ },
763
+ playing: function playing() {
764
+ clearAdStallTimer();
765
+ if (!currentAd || trackingFired.start || destroyed || tornDown) return;
766
+ trackingFired.start = true;
767
+ fireTrackingPixels2(currentAd.trackingUrls.start);
768
+ startAdCountdown();
769
+ log("Ad started playing");
770
+ },
771
+ ended: function ended() {
772
+ if (!currentAd || trackingFired.complete || destroyed || tornDown) return;
773
+ trackingFired.complete = true;
774
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
775
+ log("Ad completed");
776
+ handleAdComplete();
777
+ },
778
+ error: function error(e) {
779
+ if (destroyed || tornDown) return;
780
+ console.error("[AdStormPlayer] Ad video error:", e);
781
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
782
+ handleAdError();
783
+ },
784
+ waiting: function waiting() {
785
+ clearAdStallTimer();
786
+ adStallTimerId = setTimeout(function() {
787
+ adStallTimerId = void 0;
788
+ if (!adPlaying || destroyed || tornDown) return;
789
+ console.warn("[AdStormPlayer] Ad playback stalled too long");
790
+ handleAdError();
791
+ }, STALL_TIMEOUT_MS);
792
+ },
793
+ volumechange: function volumechange() {
794
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
795
+ if (adVideoElement.muted || adVideoElement.volume <= 0) {
796
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
797
+ } else {
798
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
799
+ }
800
+ },
801
+ pause: function pause() {
802
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
803
+ if (!adVideoElement.ended) {
804
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
805
+ }
806
+ },
807
+ play: function play() {
808
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
809
+ if (adVideoElement.currentTime > 0) {
810
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
811
+ }
812
+ }
813
+ };
814
+ var trackingFired = {
815
+ impression: false,
816
+ start: false,
817
+ firstQuartile: false,
818
+ midpoint: false,
819
+ thirdQuartile: false,
820
+ complete: false
821
+ };
822
+ var preloadSlots = /* @__PURE__ */ new Map();
855
823
  function log() {
856
824
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
857
825
  args[_key] = arguments[_key];
@@ -859,58 +827,340 @@ function createVastManager() {
859
827
  if (debug) {
860
828
  var _console;
861
829
  (_console = console).log.apply(_console, [
862
- "[VastManager]"
830
+ "[AdStormPlayer]"
863
831
  ].concat(_to_consumable_array(args)));
864
832
  }
865
833
  }
866
- function warn() {
867
- for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
868
- args[_key] = arguments[_key];
834
+ function emit(event, payload) {
835
+ var set = listeners.get(event);
836
+ if (!set) return;
837
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
838
+ try {
839
+ for(var _iterator = Array.from(set)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
840
+ var fn = _step.value;
841
+ try {
842
+ fn(payload);
843
+ } catch (error) {
844
+ console.warn("[AdStormPlayer] Error in event listener for ".concat(event, ":"), error);
845
+ }
846
+ }
847
+ } catch (err) {
848
+ _didIteratorError = true;
849
+ _iteratorError = err;
850
+ } finally{
851
+ try {
852
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
853
+ _iterator.return();
854
+ }
855
+ } finally{
856
+ if (_didIteratorError) {
857
+ throw _iteratorError;
858
+ }
859
+ }
869
860
  }
870
- var _console;
871
- (_console = console).warn.apply(_console, [
872
- "[VastManager]"
873
- ].concat(_to_consumable_array(args)));
874
861
  }
875
- function initialize() {
876
- return _async_to_generator(function() {
877
- return _ts_generator(this, function(_state) {
878
- if (initialized) return [
879
- 2
880
- ];
881
- initialized = true;
882
- log("Initialized, VAST tag URL:", VAST_TAG_URL.split("?")[0]);
883
- return [
884
- 2
885
- ];
862
+ function fireTrackingPixels2(urls) {
863
+ fireTrackingPixels(urls, sessionId, "[AdStormPlayer]");
864
+ }
865
+ function clearAdStallTimer() {
866
+ if (adStallTimerId) {
867
+ clearTimeout(adStallTimerId);
868
+ adStallTimerId = void 0;
869
+ }
870
+ }
871
+ function clearAdCountdownTimer() {
872
+ if (adCountdownTimerId) {
873
+ clearInterval(adCountdownTimerId);
874
+ adCountdownTimerId = void 0;
875
+ }
876
+ lastCountdownSecond = -1;
877
+ }
878
+ function updateAdCountdown() {
879
+ if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;
880
+ var remainingSec = Math.max(0, Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime));
881
+ if (remainingSec === lastCountdownSecond) return;
882
+ lastCountdownSecond = remainingSec;
883
+ adCountdownEl.textContent = "Ad ".concat(remainingSec, "s");
884
+ emit("ad_countdown", {
885
+ remainingSec: remainingSec,
886
+ durationSec: currentAd.duration,
887
+ currentTimeSec: adVideoElement.currentTime
888
+ });
889
+ }
890
+ function startAdCountdown() {
891
+ clearAdCountdownTimer();
892
+ updateAdCountdown();
893
+ adCountdownTimerId = setInterval(updateAdCountdown, 250);
894
+ }
895
+ function generateSessionId() {
896
+ return "adstorm-".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2, 10));
897
+ }
898
+ function bindAdEventListeners() {
899
+ if (!adVideoElement || adListenersBound) return;
900
+ adVideoElement.addEventListener("timeupdate", adHandlers.timeupdate);
901
+ adVideoElement.addEventListener("playing", adHandlers.playing);
902
+ adVideoElement.addEventListener("ended", adHandlers.ended);
903
+ adVideoElement.addEventListener("error", adHandlers.error);
904
+ adVideoElement.addEventListener("waiting", adHandlers.waiting);
905
+ adVideoElement.addEventListener("volumechange", adHandlers.volumechange);
906
+ adVideoElement.addEventListener("pause", adHandlers.pause);
907
+ adVideoElement.addEventListener("play", adHandlers.play);
908
+ adListenersBound = true;
909
+ }
910
+ function unbindAdEventListeners() {
911
+ if (!adVideoElement || !adListenersBound) return;
912
+ adVideoElement.removeEventListener("timeupdate", adHandlers.timeupdate);
913
+ adVideoElement.removeEventListener("playing", adHandlers.playing);
914
+ adVideoElement.removeEventListener("ended", adHandlers.ended);
915
+ adVideoElement.removeEventListener("error", adHandlers.error);
916
+ adVideoElement.removeEventListener("waiting", adHandlers.waiting);
917
+ adVideoElement.removeEventListener("volumechange", adHandlers.volumechange);
918
+ adVideoElement.removeEventListener("pause", adHandlers.pause);
919
+ adVideoElement.removeEventListener("play", adHandlers.play);
920
+ adListenersBound = false;
921
+ }
922
+ function teardownCurrentPlayback() {
923
+ unbindAdEventListeners();
924
+ clearAdStallTimer();
925
+ clearAdCountdownTimer();
926
+ if (!adVideoElement) return;
927
+ adVideoElement.pause();
928
+ adVideoElement.removeAttribute("src");
929
+ adVideoElement.load();
930
+ }
931
+ function buildVastUrl(durationSeconds, metadata) {
932
+ var baseUrl = "https://adstorm.co/api-adstorm-dev/adstorm/vast/".concat(licenseKey, "/pod");
933
+ var defaultMetadata = {
934
+ video: {
935
+ codec: "h264",
936
+ width: contentVideo.videoWidth || 1280,
937
+ height: contentVideo.videoHeight || 720,
938
+ fps: 29.97,
939
+ bitrate: 5e3,
940
+ profile: "high",
941
+ pix_fmt: "yuv420p",
942
+ has_b_frames: 0
943
+ },
944
+ audio: {
945
+ codec: "aac",
946
+ sample_rate: 48e3,
947
+ bitrate: 128
948
+ }
949
+ };
950
+ var finalMetadata = metadata || defaultMetadata;
951
+ var metadataStr = encodeURIComponent(JSON.stringify(finalMetadata));
952
+ return "".concat(baseUrl, "?duration=").concat(Math.ceil(durationSeconds), "&metadata=").concat(metadataStr);
953
+ }
954
+ function parseVastXml(xmlString) {
955
+ var ads = [];
956
+ try {
957
+ var parser = new DOMParser();
958
+ var xmlDoc = parser.parseFromString(xmlString, "text/xml");
959
+ var parserError = xmlDoc.querySelector("parsererror");
960
+ if (parserError) {
961
+ console.error("[AdStormPlayer] XML parsing error:", parserError.textContent);
962
+ return [];
963
+ }
964
+ var adElements = xmlDoc.querySelectorAll("Ad");
965
+ adElements.forEach(function(adElement) {
966
+ var _adElement_querySelector, _adElement_querySelector1, _adElement_querySelector_textContent, _adElement_querySelector2;
967
+ var adId = adElement.getAttribute("id") || "unknown";
968
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
969
+ var durationText = ((_adElement_querySelector1 = adElement.querySelector("Duration")) === null || _adElement_querySelector1 === void 0 ? void 0 : _adElement_querySelector1.textContent) || "00:00:30";
970
+ var durationParts = durationText.split(":");
971
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseFloat(durationParts[2] || "0");
972
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
973
+ var mediaFiles = [];
974
+ mediaFileElements.forEach(function(mf) {
975
+ var _mf_textContent;
976
+ var type = mf.getAttribute("type") || "";
977
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
978
+ var width = parseInt(mf.getAttribute("width") || "1920", 10);
979
+ var height = parseInt(mf.getAttribute("height") || "1080", 10);
980
+ var bitrate = mf.getAttribute("bitrate") ? parseInt(mf.getAttribute("bitrate"), 10) : void 0;
981
+ if (!url) {
982
+ log("Skipping empty MediaFile URL");
983
+ return;
984
+ }
985
+ var originalUrl = url;
986
+ url = replaceFlvExtension(url);
987
+ if (url !== originalUrl) {
988
+ log("Converted FLV to MP4: ".concat(originalUrl, " -> ").concat(url));
989
+ }
990
+ if (isUnsupportedFormat(url)) {
991
+ var ext = getFileExtension(url);
992
+ log("Skipping unsupported format: ".concat(url, " (extension: ").concat(ext, ", declared type: ").concat(type, ")"));
993
+ return;
994
+ }
995
+ if (isSupportedFormat(url, type)) {
996
+ mediaFiles.push({
997
+ url: url,
998
+ type: type,
999
+ width: width,
1000
+ height: height,
1001
+ bitrate: bitrate
1002
+ });
1003
+ log("Found media file: ".concat(url, " (").concat(type, ", ").concat(width, "x").concat(height, ")"));
1004
+ } else {
1005
+ log("Skipping incompatible media file: ".concat(url, " (type: ").concat(type, ")"));
1006
+ }
1007
+ });
1008
+ if (mediaFiles.length === 0) {
1009
+ log("No valid media files found in ad:", adId);
1010
+ return;
1011
+ }
1012
+ var trackingUrls = {
1013
+ impression: [],
1014
+ start: [],
1015
+ firstQuartile: [],
1016
+ midpoint: [],
1017
+ thirdQuartile: [],
1018
+ complete: [],
1019
+ mute: [],
1020
+ unmute: [],
1021
+ pause: [],
1022
+ resume: [],
1023
+ error: []
1024
+ };
1025
+ adElement.querySelectorAll("Impression").forEach(function(el) {
1026
+ var _el_textContent;
1027
+ var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
1028
+ if (url) trackingUrls.impression.push(url);
1029
+ });
1030
+ adElement.querySelectorAll("Tracking").forEach(function(el) {
1031
+ var _el_textContent;
1032
+ var event = el.getAttribute("event");
1033
+ var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
1034
+ if (event && url) {
1035
+ var eventKey = event;
1036
+ if (trackingUrls[eventKey]) {
1037
+ trackingUrls[eventKey].push(url);
1038
+ }
1039
+ }
1040
+ });
1041
+ var clickThrough = (_adElement_querySelector2 = adElement.querySelector("ClickThrough")) === null || _adElement_querySelector2 === void 0 ? void 0 : (_adElement_querySelector_textContent = _adElement_querySelector2.textContent) === null || _adElement_querySelector_textContent === void 0 ? void 0 : _adElement_querySelector_textContent.trim();
1042
+ ads.push({
1043
+ id: adId,
1044
+ title: title,
1045
+ duration: duration,
1046
+ mediaFiles: mediaFiles,
1047
+ trackingUrls: trackingUrls,
1048
+ clickThrough: clickThrough
1049
+ });
1050
+ log("Parsed ad: ".concat(title, ", duration: ").concat(duration, "s, media files: ").concat(mediaFiles.length));
886
1051
  });
887
- })();
1052
+ } catch (error) {
1053
+ console.error("[AdStormPlayer] Error parsing VAST XML:", error);
1054
+ }
1055
+ return ads;
1056
+ }
1057
+ function selectBestMediaFile(mediaFiles) {
1058
+ if (mediaFiles.length === 0) return null;
1059
+ if (mediaFiles.length === 1) return mediaFiles[0];
1060
+ var mp4Files = mediaFiles.filter(function(mf) {
1061
+ return mf.type.includes("video/mp4");
1062
+ });
1063
+ var candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;
1064
+ var targetWidth = contentVideo.videoWidth || 1280;
1065
+ var targetHeight = contentVideo.videoHeight || 720;
1066
+ candidates.sort(function(a, b) {
1067
+ var diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);
1068
+ var diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);
1069
+ return diffA - diffB;
1070
+ });
1071
+ return candidates[0] || null;
1072
+ }
1073
+ function createAdVideoElement() {
1074
+ var video = document.createElement("video");
1075
+ video.style.position = "absolute";
1076
+ video.style.left = "0";
1077
+ video.style.top = "0";
1078
+ video.style.width = "100%";
1079
+ video.style.height = "100%";
1080
+ video.style.objectFit = "contain";
1081
+ video.style.backgroundColor = "#000";
1082
+ video.style.zIndex = "1";
1083
+ video.playsInline = true;
1084
+ video.preload = "auto";
1085
+ video.muted = originalMutedState;
1086
+ video.volume = originalMutedState ? 0 : originalVolume;
1087
+ return video;
1088
+ }
1089
+ function setAdPlayingFlag(isPlaying) {
1090
+ if (isPlaying) {
1091
+ contentVideo.dataset.stormcloudAdPlaying = "true";
1092
+ } else {
1093
+ delete contentVideo.dataset.stormcloudAdPlaying;
1094
+ }
1095
+ }
1096
+ function setupAdEventListeners() {
1097
+ bindAdEventListeners();
1098
+ }
1099
+ function handleAdComplete() {
1100
+ if (destroyed || tornDown) return;
1101
+ log("Handling ad completion");
1102
+ adPlaying = false;
1103
+ setAdPlayingFlag(false);
1104
+ clearAdStallTimer();
1105
+ clearAdCountdownTimer();
1106
+ if (adContainerEl) {
1107
+ adContainerEl.style.opacity = "0";
1108
+ adHideTimerId = setTimeout(function() {
1109
+ if (adContainerEl) {
1110
+ adContainerEl.style.display = "none";
1111
+ adContainerEl.style.pointerEvents = "none";
1112
+ }
1113
+ }, 300);
1114
+ }
1115
+ contentVideo.style.visibility = "visible";
1116
+ contentVideo.style.opacity = "1";
1117
+ contentVideo.muted = originalMutedState;
1118
+ contentVideo.volume = originalVolume;
1119
+ currentAd = void 0;
1120
+ emit("content_resume");
1121
+ emit("all_ads_completed");
1122
+ }
1123
+ function handleAdError() {
1124
+ if (destroyed || tornDown) return;
1125
+ log("Handling ad error");
1126
+ if (!adPlaying) return;
1127
+ adPlaying = false;
1128
+ setAdPlayingFlag(false);
1129
+ clearAdStallTimer();
1130
+ clearAdCountdownTimer();
1131
+ contentVideo.muted = originalMutedState;
1132
+ contentVideo.volume = originalVolume;
1133
+ contentVideo.style.visibility = "visible";
1134
+ contentVideo.style.opacity = "1";
1135
+ if (adContainerEl) {
1136
+ adContainerEl.style.display = "none";
1137
+ adContainerEl.style.pointerEvents = "none";
1138
+ }
1139
+ currentAd = void 0;
1140
+ emit("ad_error");
1141
+ emit("content_resume");
888
1142
  }
889
- function requestBids(_context) {
1143
+ function fetchVastOnce(durationSeconds) {
890
1144
  return _async_to_generator(function() {
891
- var correlator, url, controller, timeoutId, _ref, _ref1, _vastAd_mediaFiles_, _vastAd_mediaFiles_1, fetchOptions, response, vastXml, vastAd, bid, error;
1145
+ var vastUrl, controller, timeoutId, requestInit, response, xmlText;
892
1146
  return _ts_generator(this, function(_state) {
893
1147
  switch(_state.label){
894
1148
  case 0:
895
- if (!initialized) {
896
- throw new Error("VastManager not initialized. Call initialize() first.");
897
- }
898
- correlator = Math.floor(Math.random() * 1e12).toString();
899
- url = VAST_TAG_URL.replace("[placeholder]", correlator);
900
- log("Fetching VAST tag, correlator:", correlator);
1149
+ vastUrl = buildVastUrl(durationSeconds);
1150
+ log("Fetching VAST from:", vastUrl);
901
1151
  controller = typeof AbortController !== "undefined" ? new AbortController() : null;
902
1152
  timeoutId = setTimeout(function() {
903
1153
  return controller === null || controller === void 0 ? void 0 : controller.abort();
904
- }, DEFAULT_TIMEOUT_MS);
1154
+ }, REQUEST_TIMEOUT_MS);
905
1155
  _state.label = 1;
906
1156
  case 1:
907
1157
  _state.trys.push([
908
1158
  1,
909
- 4,
910
1159
  ,
1160
+ 4,
911
1161
  5
912
1162
  ]);
913
- fetchOptions = {
1163
+ requestInit = {
914
1164
  method: "GET",
915
1165
  mode: "cors",
916
1166
  credentials: "omit",
@@ -919,62 +1169,34 @@ function createVastManager() {
919
1169
  },
920
1170
  referrerPolicy: "no-referrer-when-downgrade"
921
1171
  };
922
- if (controller) fetchOptions.signal = controller.signal;
1172
+ if (controller) {
1173
+ requestInit.signal = controller.signal;
1174
+ }
923
1175
  return [
924
1176
  4,
925
- fetch(url, fetchOptions)
1177
+ fetch(vastUrl, requestInit)
926
1178
  ];
927
1179
  case 2:
928
1180
  response = _state.sent();
929
- clearTimeout(timeoutId);
930
1181
  if (!response.ok) {
931
- throw new Error("VAST request returned HTTP ".concat(response.status));
1182
+ throw new Error("Failed to fetch VAST: ".concat(response.status, " ").concat(response.statusText));
932
1183
  }
933
1184
  return [
934
1185
  4,
935
1186
  response.text()
936
1187
  ];
937
1188
  case 3:
938
- vastXml = _state.sent();
939
- log("VAST XML received, length:", vastXml.length);
940
- vastAd = parseVastXml(vastXml, "mp4-first", "[VastManager]");
941
- if (!vastAd) {
942
- log("VAST parsed but no usable ad found");
943
- return [
944
- 2,
945
- []
946
- ];
947
- }
948
- log("Ad parsed: id=".concat(vastAd.id, ", duration=").concat(vastAd.duration, "s, mediaFiles=").concat(vastAd.mediaFiles.length));
949
- bid = {
950
- bidder: "vast-direct",
951
- cpm: 0,
952
- vastXml: vastXml,
953
- width: (_ref = (_vastAd_mediaFiles_ = vastAd.mediaFiles[0]) === null || _vastAd_mediaFiles_ === void 0 ? void 0 : _vastAd_mediaFiles_.width) !== null && _ref !== void 0 ? _ref : 0,
954
- height: (_ref1 = (_vastAd_mediaFiles_1 = vastAd.mediaFiles[0]) === null || _vastAd_mediaFiles_1 === void 0 ? void 0 : _vastAd_mediaFiles_1.height) !== null && _ref1 !== void 0 ? _ref1 : 0,
955
- adId: vastAd.id,
956
- impId: correlator,
957
- creativeId: vastAd.id,
958
- currency: "USD",
959
- durationSec: vastAd.duration
960
- };
1189
+ xmlText = _state.sent();
1190
+ log("VAST response received, length:", xmlText.length);
961
1191
  return [
962
1192
  2,
963
- [
964
- bid
965
- ]
1193
+ parseVastXml(xmlText)
966
1194
  ];
967
1195
  case 4:
968
- error = _state.sent();
969
1196
  clearTimeout(timeoutId);
970
- if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
971
- warn("VAST request timed out after ".concat(DEFAULT_TIMEOUT_MS, "ms"));
972
- return [
973
- 2,
974
- []
975
- ];
976
- }
977
- throw error;
1197
+ return [
1198
+ 7
1199
+ ];
978
1200
  case 5:
979
1201
  return [
980
1202
  2
@@ -983,14 +1205,14 @@ function createVastManager() {
983
1205
  });
984
1206
  })();
985
1207
  }
986
- function requestBidsUntilResponse(context) {
1208
+ function fetchVast(durationSeconds) {
987
1209
  return _async_to_generator(function() {
988
1210
  var _loop, lastError, attempt, _ret;
989
1211
  return _ts_generator(this, function(_state) {
990
1212
  switch(_state.label){
991
1213
  case 0:
992
1214
  _loop = function(attempt) {
993
- var bids, err, delay;
1215
+ var ads, error, delay;
994
1216
  return _ts_generator(this, function(_state) {
995
1217
  switch(_state.label){
996
1218
  case 0:
@@ -1002,39 +1224,39 @@ function createVastManager() {
1002
1224
  ]);
1003
1225
  return [
1004
1226
  4,
1005
- requestBids(context)
1227
+ fetchVastOnce(durationSeconds)
1006
1228
  ];
1007
1229
  case 1:
1008
- bids = _state.sent();
1009
- if (bids.length > 0) {
1010
- log("requestBidsUntilResponse: got ".concat(bids.length, " ad(s) on attempt ").concat(attempt));
1011
- return [
1012
- 2,
1013
- {
1014
- v: bids
1015
- }
1016
- ];
1017
- }
1018
- log("requestBidsUntilResponse: no ads on attempt ".concat(attempt, "/").concat(MAX_RETRIES));
1230
+ ads = _state.sent();
1231
+ if (ads.length > 0) return [
1232
+ 2,
1233
+ {
1234
+ v: ads
1235
+ }
1236
+ ];
1237
+ log("No ad returned from VAST on attempt ".concat(attempt, "/").concat(REQUEST_MAX_RETRIES));
1019
1238
  return [
1020
1239
  3,
1021
1240
  3
1022
1241
  ];
1023
1242
  case 2:
1024
- err = _state.sent();
1025
- lastError = err;
1026
- warn("requestBidsUntilResponse: attempt ".concat(attempt, "/").concat(MAX_RETRIES, " failed:"), err);
1243
+ error = _state.sent();
1244
+ lastError = error;
1245
+ if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
1246
+ console.warn("[AdStormPlayer] VAST request timed out (".concat(REQUEST_TIMEOUT_MS, "ms), attempt ").concat(attempt, "/").concat(REQUEST_MAX_RETRIES));
1247
+ } else {
1248
+ console.warn("[AdStormPlayer] VAST request failed on attempt ".concat(attempt, "/").concat(REQUEST_MAX_RETRIES, ":"), error);
1249
+ }
1027
1250
  return [
1028
1251
  3,
1029
1252
  3
1030
1253
  ];
1031
1254
  case 3:
1032
- if (!(attempt < MAX_RETRIES)) return [
1255
+ if (!(attempt < REQUEST_MAX_RETRIES)) return [
1033
1256
  3,
1034
1257
  5
1035
1258
  ];
1036
- delay = RETRY_BACKOFF_MS * attempt;
1037
- log("requestBidsUntilResponse: waiting ".concat(delay, "ms before retry"));
1259
+ delay = REQUEST_RETRY_BACKOFF_MS * attempt;
1038
1260
  return [
1039
1261
  4,
1040
1262
  new Promise(function(resolve) {
@@ -1051,13 +1273,10 @@ function createVastManager() {
1051
1273
  }
1052
1274
  });
1053
1275
  };
1054
- if (!initialized) {
1055
- throw new Error("VastManager not initialized. Call initialize() first.");
1056
- }
1057
1276
  attempt = 1;
1058
1277
  _state.label = 1;
1059
1278
  case 1:
1060
- if (!(attempt <= MAX_RETRIES)) return [
1279
+ if (!(attempt <= REQUEST_MAX_RETRIES)) return [
1061
1280
  3,
1062
1281
  4
1063
1282
  ];
@@ -1079,7 +1298,9 @@ function createVastManager() {
1079
1298
  1
1080
1299
  ];
1081
1300
  case 4:
1082
- if (_instanceof(lastError, Error)) throw lastError;
1301
+ if (_instanceof(lastError, Error)) {
1302
+ throw lastError;
1303
+ }
1083
1304
  return [
1084
1305
  2,
1085
1306
  []
@@ -1088,946 +1309,468 @@ function createVastManager() {
1088
1309
  });
1089
1310
  })();
1090
1311
  }
1091
- function destroy() {
1092
- initialized = false;
1093
- log("Destroyed");
1094
- }
1095
- return {
1096
- initialize: initialize,
1097
- requestBids: requestBids,
1098
- requestBidsUntilResponse: requestBidsUntilResponse,
1099
- destroy: destroy,
1100
- get isInitialized () {
1101
- return initialized;
1102
- }
1103
- };
1104
- }
1105
- // src/sdk/vastAdLayer.ts
1106
- var import_hls = __toESM(require("hls.js"), 1);
1107
- var LOG = "[VastAdLayer]";
1108
- function resolveBidToVastAd(winner, logPrefix) {
1109
- if (winner.vastXml) {
1110
- var ad = parseVastXml(winner.vastXml, "mp4-first", logPrefix);
1111
- return Promise.resolve(ad);
1112
- }
1113
- if (winner.vastUrl) {
1114
- return fetchAndParseVastAd(winner.vastUrl, "mp4-first", logPrefix);
1115
- }
1116
- return Promise.resolve(null);
1117
- }
1118
- function createVastAdLayer(contentVideo, options) {
1119
- var _ref, _ref1, _ref2, _ref3, _ref4;
1120
- var adPlaying = false;
1121
- var originalMutedState = false;
1122
- var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
1123
- var listeners = /* @__PURE__ */ new Map();
1124
- var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
1125
- var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
1126
- var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
1127
- var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
1128
- var forceMP4Ads = (_ref3 = options === null || options === void 0 ? void 0 : options.forceMP4Ads) !== null && _ref3 !== void 0 ? _ref3 : smartTVMode || singleElementMode;
1129
- var debug = (_ref4 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref4 !== void 0 ? _ref4 : false;
1130
- var adVideoElement;
1131
- var adHls;
1132
- var adContainerEl;
1133
- var currentAd;
1134
- var sessionId;
1135
- var destroyed = false;
1136
- var tornDown = false;
1137
- var trackingFired = createEmptyTrackingState();
1138
- var adStallTimerId;
1139
- var currentAdEventHandlers;
1140
- var preloadSlots = /* @__PURE__ */ new Map();
1141
- function emit(event, payload) {
1142
- var set = listeners.get(event);
1143
- if (!set) return;
1144
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1145
- try {
1146
- for(var _iterator = Array.from(set)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1147
- var fn = _step.value;
1148
- try {
1149
- fn(payload);
1150
- } catch (error) {
1151
- console.warn("".concat(LOG, " Error in event listener for ").concat(event, ":"), error);
1152
- }
1153
- }
1154
- } catch (err) {
1155
- _didIteratorError = true;
1156
- _iteratorError = err;
1157
- } finally{
1158
- try {
1159
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1160
- _iterator.return();
1161
- }
1162
- } finally{
1163
- if (_didIteratorError) {
1164
- throw _iteratorError;
1165
- }
1166
- }
1167
- }
1168
- }
1169
- function generateSessionId() {
1170
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
1171
- }
1172
- function fireTrackingPixels2(urls) {
1173
- fireTrackingPixels(urls, sessionId, LOG);
1174
- }
1175
- function getMainStreamQuality() {
1176
- if (!(mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.levels)) return null;
1177
- var currentLevel = mainHlsInstance.currentLevel;
1178
- if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {
1179
- var autoLevel = mainHlsInstance.loadLevel;
1180
- if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {
1181
- var level2 = mainHlsInstance.levels[autoLevel];
1182
- return {
1183
- width: level2.width || 1920,
1184
- height: level2.height || 1080,
1185
- bitrate: level2.bitrate || 5e6
1186
- };
1187
- }
1188
- return null;
1189
- }
1190
- var level = mainHlsInstance.levels[currentLevel];
1191
- return {
1192
- width: level.width || 1920,
1193
- height: level.height || 1080,
1194
- bitrate: level.bitrate || 5e6
1195
- };
1196
- }
1197
- function selectBestMediaFile(mediaFiles) {
1198
- var _ref;
1199
- var _scoredFiles_;
1200
- if (mediaFiles.length === 0) throw new Error("No media files available");
1201
- var candidates = mediaFiles;
1202
- if (forceMP4Ads) {
1203
- var mp4Only = candidates.filter(function(f) {
1204
- return !isHlsMediaFile(f);
1205
- });
1206
- if (mp4Only.length > 0) {
1207
- candidates = mp4Only;
1208
- if (debug) console.log("".concat(LOG, " forceMP4Ads: filtered to ").concat(mp4Only.length, " MP4-only file(s)"));
1209
- } else if (debug) {
1210
- console.warn("".concat(LOG, " forceMP4Ads: no MP4 files available, falling back to all media files"));
1211
- }
1212
- } else {
1213
- var mp4Only1 = candidates.filter(function(f) {
1214
- return !isHlsMediaFile(f);
1215
- });
1216
- if (mp4Only1.length > 0) {
1217
- candidates = mp4Only1;
1218
- if (debug) console.log("".concat(LOG, " Preferring ").concat(mp4Only1.length, " MP4 file(s) over HLS (mp4-first)"));
1219
- }
1220
- }
1221
- var firstFile = candidates[0];
1222
- if (candidates.length === 1) return firstFile;
1223
- var mainQuality = getMainStreamQuality();
1224
- if (!mainQuality) {
1225
- if (debug) console.log("".concat(LOG, " No main stream quality info, using first media file"));
1226
- return firstFile;
1227
- }
1228
- var scoredFiles = candidates.map(function(file) {
1229
- var widthDiff = Math.abs(file.width - mainQuality.width);
1230
- var heightDiff = Math.abs(file.height - mainQuality.height);
1231
- var resolutionDiff = widthDiff + heightDiff;
1232
- var fileBitrate = (file.bitrate || 5e3) * 1e3;
1233
- var bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);
1234
- var score = resolutionDiff * 2 + bitrateDiff / 1e3;
1235
- return {
1236
- file: file,
1237
- score: score
1238
- };
1239
- });
1240
- scoredFiles.sort(function(a, b) {
1241
- return a.score - b.score;
1242
- });
1243
- return (_ref = (_scoredFiles_ = scoredFiles[0]) === null || _scoredFiles_ === void 0 ? void 0 : _scoredFiles_.file) !== null && _ref !== void 0 ? _ref : firstFile;
1244
- }
1245
- function isHlsMediaFile(file) {
1246
- return file.type === "application/x-mpegURL" || file.type.includes("m3u8");
1247
- }
1248
- function createAdVideoElement() {
1249
- var video = document.createElement("video");
1250
- video.style.position = "absolute";
1251
- video.style.left = "0";
1252
- video.style.top = "0";
1253
- video.style.width = "100%";
1254
- video.style.height = "100%";
1255
- video.style.objectFit = "contain";
1256
- video.style.backgroundColor = "#000";
1257
- video.playsInline = true;
1258
- video.muted = false;
1259
- video.volume = 1;
1260
- return video;
1261
- }
1262
- function clearAdStallTimer() {
1263
- if (adStallTimerId != null) {
1264
- clearTimeout(adStallTimerId);
1265
- adStallTimerId = void 0;
1266
- }
1267
- }
1268
- function removeAdEventListeners() {
1269
- clearAdStallTimer();
1270
- if (!currentAdEventHandlers || !adVideoElement) return;
1271
- var el = adVideoElement;
1272
- el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1273
- el.removeEventListener("playing", currentAdEventHandlers.playing);
1274
- el.removeEventListener("ended", currentAdEventHandlers.ended);
1275
- el.removeEventListener("error", currentAdEventHandlers.error);
1276
- el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1277
- el.removeEventListener("pause", currentAdEventHandlers.pause);
1278
- el.removeEventListener("play", currentAdEventHandlers.play);
1279
- el.removeEventListener("waiting", currentAdEventHandlers.waiting);
1280
- currentAdEventHandlers = void 0;
1281
- }
1282
- function setupAdEventListeners() {
1283
- if (!adVideoElement) return;
1284
- removeAdEventListeners();
1285
- var handlers = {
1286
- timeupdate: function timeupdate() {
1287
- var ad = currentAd;
1288
- if (!ad || !adVideoElement) return;
1289
- var progress = adVideoElement.currentTime / ad.duration;
1290
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1291
- trackingFired.firstQuartile = true;
1292
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1293
- }
1294
- if (progress >= 0.5 && !trackingFired.midpoint) {
1295
- trackingFired.midpoint = true;
1296
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1297
- }
1298
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1299
- trackingFired.thirdQuartile = true;
1300
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1301
- }
1302
- },
1303
- playing: function playing() {
1304
- clearAdStallTimer();
1305
- var ad = currentAd;
1306
- if (!ad || trackingFired.start) return;
1307
- trackingFired.start = true;
1308
- fireTrackingPixels2(ad.trackingUrls.start);
1309
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1310
- },
1311
- ended: function ended() {
1312
- if (tornDown || !currentAd || trackingFired.complete) return;
1313
- trackingFired.complete = true;
1314
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1315
- if (debug) console.log("".concat(LOG, " Ad completed"));
1316
- handleAdComplete();
1317
- },
1318
- error: function error(e) {
1319
- if (tornDown) return;
1320
- console.error("".concat(LOG, " Ad video error:"), e);
1321
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1322
- handleAdError();
1323
- },
1324
- volumechange: function volumechange() {
1325
- if (!currentAd || !adVideoElement) return;
1326
- if (adVideoElement.muted) {
1327
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1328
- } else {
1329
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1330
- }
1331
- },
1332
- pause: function pause() {
1333
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1334
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1335
- }
1336
- },
1337
- play: function play() {
1338
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1339
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1340
- }
1341
- },
1342
- waiting: function waiting() {
1343
- clearAdStallTimer();
1344
- adStallTimerId = setTimeout(function() {
1345
- adStallTimerId = void 0;
1346
- if (adPlaying) {
1347
- if (debug) console.warn("".concat(LOG, " Ad video stalled for too long, treating as error"));
1348
- handleAdError();
1349
- }
1350
- }, 8e3);
1351
- }
1352
- };
1353
- adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1354
- adVideoElement.addEventListener("playing", handlers.playing);
1355
- adVideoElement.addEventListener("ended", handlers.ended);
1356
- adVideoElement.addEventListener("error", handlers.error);
1357
- adVideoElement.addEventListener("volumechange", handlers.volumechange);
1358
- adVideoElement.addEventListener("pause", handlers.pause);
1359
- adVideoElement.addEventListener("play", handlers.play);
1360
- adVideoElement.addEventListener("waiting", handlers.waiting);
1361
- currentAdEventHandlers = handlers;
1362
- }
1363
- function setAdPlayingFlag(isPlaying) {
1364
- if (isPlaying) {
1365
- contentVideo.dataset.stormcloudAdPlaying = "true";
1366
- } else {
1367
- delete contentVideo.dataset.stormcloudAdPlaying;
1368
- }
1369
- }
1370
- function handleAdComplete() {
1371
- if (tornDown) return;
1372
- clearAdStallTimer();
1373
- if (debug) console.log("".concat(LOG, " Handling ad completion"));
1374
- adPlaying = false;
1375
- setAdPlayingFlag(false);
1376
- if (adContainerEl) {
1377
- adContainerEl.style.display = "none";
1378
- adContainerEl.style.pointerEvents = "none";
1379
- }
1380
- emit("ad_impression");
1381
- emit("content_resume");
1382
- }
1383
- function handleAdError() {
1384
- if (tornDown) return;
1385
- if (!adPlaying) return;
1386
- clearAdStallTimer();
1387
- if (debug) console.log("".concat(LOG, " Handling ad error"));
1388
- adPlaying = false;
1389
- setAdPlayingFlag(false);
1390
- if (adContainerEl) {
1391
- adContainerEl.style.display = "none";
1392
- adContainerEl.style.pointerEvents = "none";
1393
- }
1394
- emit("ad_error");
1395
- }
1396
- function teardownCurrentPlayback() {
1397
- removeAdEventListeners();
1398
- if (adHls) {
1399
- adHls.destroy();
1400
- adHls = void 0;
1401
- }
1402
- if (adVideoElement) {
1403
- if (singleElementMode && adVideoElement === contentVideo) {
1404
- contentVideo.pause();
1405
- } else {
1406
- adVideoElement.pause();
1407
- adVideoElement.removeAttribute("src");
1408
- adVideoElement.load();
1409
- }
1410
- }
1411
- }
1412
- function startNativePlayback(mediaFile) {
1413
- if (!adVideoElement) return;
1414
- if (debug) console.log("".concat(LOG, " Starting native MP4 playback: ").concat(mediaFile.url));
1415
- adVideoElement.src = mediaFile.url;
1416
- adVideoElement.load();
1417
- adVideoElement.play().catch(function(error) {
1418
- console.error("".concat(LOG, " Error starting native ad playback:"), error);
1419
- handleAdError();
1420
- });
1421
- }
1422
- function startHlsPlayback(mediaFile) {
1423
- if (!adVideoElement) return;
1424
- if (debug) console.log("".concat(LOG, " Starting HLS playback: ").concat(mediaFile.url));
1425
- if (import_hls.default.isSupported()) {
1426
- if (adHls) {
1427
- adHls.destroy();
1428
- adHls = void 0;
1429
- }
1430
- adHls = new import_hls.default({
1431
- enableWorker: true,
1432
- lowLatencyMode: false
1433
- });
1434
- adHls.loadSource(mediaFile.url);
1435
- adHls.attachMedia(adVideoElement);
1436
- adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1437
- if (!adPlaying) return;
1438
- adVideoElement.play().catch(function(error) {
1439
- console.error("".concat(LOG, " Error starting HLS ad playback:"), error);
1440
- handleAdError();
1441
- });
1442
- });
1443
- var nonFatalNetworkErrors = 0;
1444
- adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1445
- if (data.fatal) {
1446
- handleAdError();
1447
- } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1448
- nonFatalNetworkErrors++;
1449
- if (nonFatalNetworkErrors >= 3) {
1450
- if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1451
- handleAdError();
1452
- }
1453
- }
1454
- });
1455
- } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1456
- adVideoElement.src = mediaFile.url;
1457
- adVideoElement.play().catch(function(error) {
1458
- console.error("".concat(LOG, " Error starting native HLS ad playback:"), error);
1459
- handleAdError();
1460
- });
1461
- } else {
1462
- console.error("".concat(LOG, " HLS not supported on this platform"));
1463
- handleAdError();
1312
+ function getDurationSecondsFromContext(requestContext) {
1313
+ var _ctx_remainingBreakSec;
1314
+ if (!requestContext || (typeof requestContext === "undefined" ? "undefined" : _type_of(requestContext)) !== "object") {
1315
+ return 30;
1464
1316
  }
1465
- }
1466
- function startPlayback(mediaFile) {
1467
- if (!adVideoElement) return;
1468
- if (singleElementMode && isHlsMediaFile(mediaFile)) {
1469
- var mp4Fallback = currentAd === null || currentAd === void 0 ? void 0 : currentAd.mediaFiles.find(function(f) {
1470
- return !isHlsMediaFile(f);
1471
- });
1472
- if (mp4Fallback) {
1473
- if (debug) console.log("".concat(LOG, " singleElementMode: HLS ad blocked, using MP4 fallback"));
1474
- startNativePlayback(mp4Fallback);
1475
- return;
1476
- }
1477
- }
1478
- if (isHlsMediaFile(mediaFile)) {
1479
- startHlsPlayback(mediaFile);
1480
- } else {
1481
- startNativePlayback(mediaFile);
1317
+ var ctx = requestContext;
1318
+ var value = (_ctx_remainingBreakSec = ctx.remainingBreakSec) !== null && _ctx_remainingBreakSec !== void 0 ? _ctx_remainingBreakSec : ctx.breakDurationSec;
1319
+ if (typeof value !== "number" || Number.isNaN(value)) {
1320
+ return 30;
1482
1321
  }
1322
+ return Math.max(1, Math.ceil(value));
1483
1323
  }
1484
- function playAd(bids) {
1324
+ function requestAdFromApi(requestContext) {
1485
1325
  return _async_to_generator(function() {
1486
- var winner, ad, contentVolume, adVolume2, mediaFile2, _contentVideo_parentElement, container, adVolume, mediaFile;
1326
+ var durationSeconds, ads;
1487
1327
  return _ts_generator(this, function(_state) {
1488
1328
  switch(_state.label){
1489
1329
  case 0:
1490
- if (destroyed) {
1491
- return [
1492
- 2,
1493
- Promise.reject(new Error("Layer has been destroyed"))
1494
- ];
1495
- }
1496
- if (bids.length === 0) {
1497
- return [
1498
- 2,
1499
- Promise.reject(new Error("No bids provided"))
1500
- ];
1501
- }
1502
- winner = bids[0];
1503
- if (debug) {
1504
- console.log("".concat(LOG, " Winning bid: ").concat(winner.bidder, " $").concat(winner.cpm.toFixed(2), " ").concat(winner.currency));
1505
- }
1330
+ durationSeconds = getDurationSecondsFromContext(requestContext);
1506
1331
  return [
1507
1332
  4,
1508
- resolveBidToVastAd(winner, LOG)
1333
+ fetchVast(durationSeconds)
1509
1334
  ];
1510
1335
  case 1:
1511
- ad = _state.sent();
1512
- if (!ad) {
1513
- if (debug) console.warn("".concat(LOG, " Winning bid has no VAST URL or XML"));
1514
- emit("ad_error");
1515
- return [
1516
- 2,
1517
- Promise.reject(new Error("No VAST from bid"))
1518
- ];
1519
- }
1520
- if (debug) {
1521
- console.log("".concat(LOG, " Ad parsed: ").concat(ad.title, ", duration: ").concat(ad.duration, "s, mediaFiles: ").concat(ad.mediaFiles.length));
1522
- }
1523
- sessionId = generateSessionId();
1524
- currentAd = ad;
1525
- trackingFired = _object_spread({}, createEmptyTrackingState());
1526
- fireTrackingPixels2(ad.trackingUrls.impression);
1527
- trackingFired.impression = true;
1528
- contentVolume = contentVideo.volume;
1529
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1530
- if (!singleElementMode) return [
1531
- 3,
1532
- 3
1533
- ];
1534
- mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1535
- teardownCurrentPlayback();
1536
- adVideoElement = contentVideo;
1537
- adHls = void 0;
1538
- adPlaying = true;
1539
- setAdPlayingFlag(true);
1540
- contentVideo.removeAttribute("src");
1541
- contentVideo.load();
1542
- if (!continueLiveStreamDuringAds) {
1543
- contentVideo.pause();
1544
- }
1545
- contentVideo.muted = true;
1546
- contentVideo.volume = 0;
1547
- return [
1548
- 4,
1549
- new Promise(function(resolve) {
1550
- return setTimeout(resolve, 200);
1551
- })
1552
- ];
1553
- case 2:
1554
- _state.sent();
1555
- if (destroyed || tornDown) return [
1556
- 2
1557
- ];
1558
- contentVideo.style.visibility = "visible";
1559
- contentVideo.style.opacity = "1";
1560
- emit("content_pause");
1561
- setupAdEventListeners();
1562
- adVolume2 = originalMutedState ? 1 : originalVolume;
1563
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume2));
1564
- adVideoElement.muted = false;
1565
- mediaFile2 = selectBestMediaFile(ad.mediaFiles);
1566
- if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile2.url));
1567
- startPlayback(mediaFile2);
1568
- return [
1569
- 2
1570
- ];
1571
- case 3:
1572
- if (!adContainerEl) {
1573
- ;
1574
- container = document.createElement("div");
1575
- container.style.position = "absolute";
1576
- container.style.left = "0";
1577
- container.style.top = "0";
1578
- container.style.right = "0";
1579
- container.style.bottom = "0";
1580
- container.style.display = "none";
1581
- container.style.alignItems = "center";
1582
- container.style.justifyContent = "center";
1583
- container.style.pointerEvents = "none";
1584
- container.style.zIndex = "10";
1585
- container.style.backgroundColor = "#000";
1586
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1587
- adContainerEl = container;
1588
- }
1589
- if (!adVideoElement) {
1590
- adVideoElement = createAdVideoElement();
1591
- adContainerEl.appendChild(adVideoElement);
1592
- setupAdEventListeners();
1593
- } else {
1594
- teardownCurrentPlayback();
1595
- }
1596
- if (!continueLiveStreamDuringAds) {
1597
- contentVideo.pause();
1598
- }
1599
- contentVideo.muted = true;
1600
- contentVideo.volume = 0;
1601
- adPlaying = true;
1602
- setAdPlayingFlag(true);
1603
- adVolume = originalMutedState ? 1 : originalVolume;
1604
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1605
- adVideoElement.muted = false;
1606
- if (adContainerEl) {
1607
- adContainerEl.style.display = "flex";
1608
- adContainerEl.style.pointerEvents = "auto";
1609
- }
1610
- emit("content_pause");
1611
- mediaFile = selectBestMediaFile(ad.mediaFiles);
1612
- if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile.url));
1613
- startPlayback(mediaFile);
1336
+ ads = _state.sent();
1614
1337
  return [
1615
- 2
1338
+ 2,
1339
+ ads[0] || null
1616
1340
  ];
1617
1341
  }
1618
1342
  });
1619
1343
  })();
1620
1344
  }
1621
- function ensureAdContainer() {
1622
- if (!adContainerEl) {
1623
- var _contentVideo_parentElement;
1624
- var container = document.createElement("div");
1625
- container.style.position = "absolute";
1626
- container.style.left = "0";
1627
- container.style.top = "0";
1628
- container.style.right = "0";
1629
- container.style.bottom = "0";
1630
- container.style.display = "none";
1631
- container.style.alignItems = "center";
1632
- container.style.justifyContent = "center";
1633
- container.style.pointerEvents = "none";
1634
- container.style.zIndex = "10";
1635
- container.style.backgroundColor = "#000";
1636
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1637
- adContainerEl = container;
1638
- }
1639
- return adContainerEl;
1345
+ function assignCurrentAd(ad) {
1346
+ currentAd = ad;
1347
+ sessionId = generateSessionId();
1348
+ trackingFired = {
1349
+ impression: false,
1350
+ start: false,
1351
+ firstQuartile: false,
1352
+ midpoint: false,
1353
+ thirdQuartile: false,
1354
+ complete: false
1355
+ };
1356
+ fireTrackingPixels2(currentAd.trackingUrls.impression);
1357
+ trackingFired.impression = true;
1358
+ emit("ad_impression");
1640
1359
  }
1641
- function preloadAd(bids, token) {
1642
- return _async_to_generator(function() {
1643
- var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1644
- return _ts_generator(this, function(_state) {
1645
- switch(_state.label){
1646
- case 0:
1647
- if (destroyed) return [
1648
- 2
1649
- ];
1650
- winner = bids[0];
1651
- if (!winner) return [
1652
- 2
1653
- ];
1654
- if (debug) console.log("".concat(LOG, " [preload] Resolving VAST for token=").concat(token));
1655
- return [
1656
- 4,
1657
- resolveBidToVastAd(winner, LOG)
1658
- ];
1659
- case 1:
1660
- ad = _state.sent();
1661
- if (!ad || destroyed) return [
1662
- 2
1663
- ];
1664
- mediaFile = selectBestMediaFile(ad.mediaFiles);
1665
- if (!mediaFile) return [
1666
- 2
1667
- ];
1668
- if (smartTVMode || singleElementMode) {
1669
- slot = {
1670
- bids: bids,
1671
- ad: ad,
1672
- mediaFile: mediaFile,
1673
- videoEl: null,
1674
- ready: true
1675
- };
1676
- preloadSlots.set(token, slot);
1677
- if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1360
+ return {
1361
+ initialize: function initialize() {
1362
+ log("Initializing");
1363
+ if (!adContainerEl) {
1364
+ var _contentVideo_parentElement;
1365
+ var parent = contentVideo.parentElement;
1366
+ if (parent) {
1367
+ var computed = window.getComputedStyle(parent).position;
1368
+ if (computed === "static") {
1369
+ parent.style.position = "relative";
1370
+ parentPositionOverridden = true;
1371
+ }
1372
+ }
1373
+ var container = document.createElement("div");
1374
+ container.style.position = "absolute";
1375
+ container.style.left = "0";
1376
+ container.style.top = "0";
1377
+ container.style.right = "0";
1378
+ container.style.bottom = "0";
1379
+ container.style.display = "none";
1380
+ container.style.alignItems = "center";
1381
+ container.style.justifyContent = "center";
1382
+ container.style.pointerEvents = "none";
1383
+ container.style.zIndex = AD_LAYER_Z_INDEX;
1384
+ container.style.backgroundColor = "#000";
1385
+ container.style.transition = "opacity 0.3s ease-in-out";
1386
+ container.style.opacity = "0";
1387
+ container.style.isolation = "isolate";
1388
+ var countdown = document.createElement("div");
1389
+ countdown.style.position = "absolute";
1390
+ countdown.style.right = "12px";
1391
+ countdown.style.top = "12px";
1392
+ countdown.style.padding = "4px 8px";
1393
+ countdown.style.borderRadius = "4px";
1394
+ countdown.style.background = "rgba(0,0,0,0.75)";
1395
+ countdown.style.color = "#fff";
1396
+ countdown.style.fontFamily = "sans-serif";
1397
+ countdown.style.fontSize = "12px";
1398
+ countdown.style.lineHeight = "1.2";
1399
+ countdown.style.pointerEvents = "none";
1400
+ countdown.style.zIndex = COUNTDOWN_Z_INDEX;
1401
+ countdown.textContent = "Ad";
1402
+ container.appendChild(countdown);
1403
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1404
+ adContainerEl = container;
1405
+ adCountdownEl = countdown;
1406
+ }
1407
+ },
1408
+ requestAds: function requestAds(duration) {
1409
+ return _async_to_generator(function() {
1410
+ var durationSeconds, parsed, ads, error;
1411
+ return _ts_generator(this, function(_state) {
1412
+ switch(_state.label){
1413
+ case 0:
1414
+ log("Requesting ads for duration:", duration);
1415
+ if (adPlaying) {
1416
+ return [
1417
+ 2,
1418
+ Promise.reject(new Error("Ad already playing"))
1419
+ ];
1420
+ }
1421
+ if (destroyed) {
1422
+ return [
1423
+ 2,
1424
+ Promise.reject(new Error("Player has been destroyed"))
1425
+ ];
1426
+ }
1427
+ _state.label = 1;
1428
+ case 1:
1429
+ _state.trys.push([
1430
+ 1,
1431
+ 3,
1432
+ ,
1433
+ 4
1434
+ ]);
1435
+ tornDown = false;
1436
+ durationSeconds = 30;
1437
+ parsed = parseInt(duration || "", 10);
1438
+ if (!isNaN(parsed) && parsed > 0) {
1439
+ durationSeconds = parsed;
1440
+ }
1678
1441
  return [
1679
- 2
1442
+ 4,
1443
+ fetchVast(durationSeconds)
1680
1444
  ];
1681
- }
1682
- videoEl = createAdVideoElement();
1683
- videoEl.style.visibility = "hidden";
1684
- videoEl.style.pointerEvents = "none";
1685
- videoEl.preload = "auto";
1686
- container = ensureAdContainer();
1687
- container.appendChild(videoEl);
1688
- if (isHlsMediaFile(mediaFile) && import_hls.default.isSupported()) {
1689
- hls = new import_hls.default({
1690
- enableWorker: true,
1691
- lowLatencyMode: false
1692
- });
1693
- hls.loadSource(mediaFile.url);
1694
- hls.attachMedia(videoEl);
1695
- slot1 = {
1696
- bids: bids,
1697
- ad: ad,
1698
- mediaFile: mediaFile,
1699
- videoEl: videoEl,
1700
- hlsInstance: hls,
1701
- ready: false
1702
- };
1703
- preloadSlots.set(token, slot1);
1704
- hls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1705
- var s = preloadSlots.get(token);
1706
- if (s) s.ready = true;
1707
- if (debug) console.log("".concat(LOG, " [preload] HLS manifest parsed, token=").concat(token));
1708
- });
1709
- hls.on(import_hls.default.Events.ERROR, function(_evt, data) {
1710
- if (!preloadSlots.has(token)) return;
1711
- if (data.fatal) {
1712
- if (debug) console.warn("".concat(LOG, " [preload] HLS error for token=").concat(token));
1713
- preloadSlots.delete(token);
1714
- hls.destroy();
1715
- videoEl.remove();
1716
- }
1717
- });
1718
- } else {
1719
- videoEl.src = mediaFile.url;
1720
- videoEl.load();
1721
- slot2 = {
1722
- bids: bids,
1723
- ad: ad,
1724
- mediaFile: mediaFile,
1725
- videoEl: videoEl,
1726
- ready: false
1727
- };
1728
- preloadSlots.set(token, slot2);
1729
- videoEl.addEventListener("canplay", function() {
1730
- var s = preloadSlots.get(token);
1731
- if (s) s.ready = true;
1732
- if (debug) console.log("".concat(LOG, " [preload] canplay fired, token=").concat(token));
1733
- }, {
1734
- once: true
1735
- });
1736
- }
1737
- if (debug) console.log("".concat(LOG, " [preload] Started buffering token=").concat(token, ", url=").concat(mediaFile.url));
1738
- return [
1739
- 2
1740
- ];
1741
- }
1742
- });
1743
- })();
1744
- }
1745
- function playPreloaded(token) {
1746
- return _async_to_generator(function() {
1747
- var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, nonFatalNetworkErrors, adVolume, container;
1748
- return _ts_generator(this, function(_state) {
1749
- switch(_state.label){
1750
- case 0:
1751
- if (destroyed) return [
1752
- 2,
1753
- Promise.reject(new Error("Layer has been destroyed"))
1754
- ];
1755
- slot = preloadSlots.get(token);
1756
- if (!slot) {
1757
- if (debug) console.warn("".concat(LOG, " [preload] No slot found for token=").concat(token, ", nothing to play"));
1445
+ case 2:
1446
+ ads = _state.sent();
1447
+ if (ads.length === 0) {
1448
+ log("No ads available from VAST response");
1449
+ emit("ad_error");
1450
+ return [
1451
+ 2,
1452
+ Promise.resolve()
1453
+ ];
1454
+ }
1455
+ assignCurrentAd(ads[0]);
1456
+ log("Ad loaded: ".concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1457
+ return [
1458
+ 2,
1459
+ Promise.resolve()
1460
+ ];
1461
+ case 3:
1462
+ error = _state.sent();
1463
+ console.error("[AdStormPlayer] Error requesting ads:", error);
1464
+ emit("ad_error");
1465
+ return [
1466
+ 2,
1467
+ Promise.reject(error)
1468
+ ];
1469
+ case 4:
1758
1470
  return [
1759
1471
  2
1760
1472
  ];
1761
- }
1762
- preloadSlots.delete(token);
1763
- if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1764
- contentVolume = contentVideo.volume;
1765
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1766
- sessionId = generateSessionId();
1767
- currentAd = slot.ad;
1768
- trackingFired = _object_spread({}, createEmptyTrackingState());
1769
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1770
- trackingFired.impression = true;
1771
- if (!singleElementMode) return [
1772
- 3,
1773
- 2
1774
- ];
1775
- mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1776
- teardownCurrentPlayback();
1777
- adVideoElement = contentVideo;
1778
- adHls = void 0;
1779
- adPlaying = true;
1780
- setAdPlayingFlag(true);
1781
- contentVideo.removeAttribute("src");
1782
- contentVideo.load();
1783
- contentVideo.muted = true;
1784
- contentVideo.volume = 0;
1785
- return [
1786
- 4,
1787
- new Promise(function(resolve) {
1788
- return setTimeout(resolve, 200);
1789
- })
1790
- ];
1791
- case 1:
1792
- _state.sent();
1793
- if (destroyed || tornDown) return [
1794
- 2
1795
- ];
1796
- contentVideo.style.visibility = "visible";
1797
- contentVideo.style.opacity = "1";
1798
- emit("content_pause");
1799
- setupAdEventListeners();
1800
- adVolume2 = originalMutedState ? 1 : originalVolume;
1801
- contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1802
- contentVideo.muted = false;
1803
- if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1804
- startPlayback(slot.mediaFile);
1805
- return [
1806
- 2
1807
- ];
1808
- case 2:
1809
- if (smartTVMode && !slot.videoEl) {
1810
- teardownCurrentPlayback();
1811
- if (adVideoElement) {
1812
- adVideoElement.remove();
1813
- adVideoElement = void 0;
1473
+ }
1474
+ });
1475
+ })();
1476
+ },
1477
+ play: function play() {
1478
+ return _async_to_generator(function() {
1479
+ var mediaFile, error;
1480
+ return _ts_generator(this, function(_state) {
1481
+ switch(_state.label){
1482
+ case 0:
1483
+ if (!currentAd) {
1484
+ return [
1485
+ 2,
1486
+ Promise.reject(new Error("No ad loaded"))
1487
+ ];
1488
+ }
1489
+ if (destroyed) {
1490
+ return [
1491
+ 2,
1492
+ Promise.reject(new Error("Player has been destroyed"))
1493
+ ];
1494
+ }
1495
+ log("Starting ad playback");
1496
+ _state.label = 1;
1497
+ case 1:
1498
+ _state.trys.push([
1499
+ 1,
1500
+ 3,
1501
+ ,
1502
+ 4
1503
+ ]);
1504
+ tornDown = false;
1505
+ if (adHideTimerId) {
1506
+ clearTimeout(adHideTimerId);
1507
+ adHideTimerId = void 0;
1508
+ }
1509
+ if (!adVideoElement) {
1510
+ adVideoElement = createAdVideoElement();
1511
+ adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1512
+ } else {
1513
+ teardownCurrentPlayback();
1814
1514
  }
1815
- videoEl = createAdVideoElement();
1816
- videoEl.style.visibility = "visible";
1817
- videoEl.style.pointerEvents = "none";
1818
- container2 = ensureAdContainer();
1819
- container2.appendChild(videoEl);
1820
- adVideoElement = videoEl;
1821
1515
  setupAdEventListeners();
1516
+ trackingFired = {
1517
+ impression: trackingFired.impression,
1518
+ start: false,
1519
+ firstQuartile: false,
1520
+ midpoint: false,
1521
+ thirdQuartile: false,
1522
+ complete: false
1523
+ };
1524
+ contentVideo.style.transition = "opacity 0.3s ease-in-out";
1525
+ contentVideo.style.opacity = "0";
1526
+ setTimeout(function() {
1527
+ contentVideo.style.visibility = "hidden";
1528
+ }, 300);
1529
+ contentVideo.muted = true;
1530
+ contentVideo.volume = 0;
1822
1531
  if (!continueLiveStreamDuringAds) {
1823
1532
  contentVideo.pause();
1824
1533
  }
1825
- contentVideo.muted = true;
1826
- contentVideo.volume = 0;
1827
1534
  adPlaying = true;
1828
1535
  setAdPlayingFlag(true);
1829
- adVolume21 = originalMutedState ? 1 : originalVolume;
1830
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1831
- adVideoElement.muted = false;
1832
- container2.style.display = "flex";
1833
- container2.style.pointerEvents = "auto";
1536
+ if (adVideoElement) {
1537
+ adVideoElement.volume = originalMutedState ? 0 : originalVolume;
1538
+ adVideoElement.muted = originalMutedState;
1539
+ }
1540
+ if (adContainerEl) {
1541
+ adContainerEl.style.display = "flex";
1542
+ adContainerEl.style.pointerEvents = "auto";
1543
+ adContainerEl.offsetHeight;
1544
+ adContainerEl.style.opacity = "1";
1545
+ }
1834
1546
  emit("content_pause");
1835
- if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1836
- startPlayback(slot.mediaFile);
1547
+ mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1548
+ if (!mediaFile) {
1549
+ throw new Error("No media file available");
1550
+ }
1551
+ log("Playing media file:", mediaFile.url);
1552
+ adVideoElement.src = mediaFile.url;
1553
+ adVideoElement.load();
1837
1554
  return [
1838
- 2
1555
+ 4,
1556
+ adVideoElement.play()
1839
1557
  ];
1840
- }
1841
- teardownCurrentPlayback();
1842
- if (adVideoElement && adVideoElement !== slot.videoEl) {
1843
- adVideoElement.remove();
1844
- }
1845
- slot.videoEl.style.visibility = "visible";
1846
- slot.videoEl.style.pointerEvents = "none";
1847
- adVideoElement = slot.videoEl;
1848
- adHls = slot.hlsInstance;
1849
- if (adHls) {
1850
- nonFatalNetworkErrors = 0;
1851
- adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1852
- if (!adPlaying) return;
1853
- if (data.fatal) {
1854
- handleAdError();
1855
- } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1856
- nonFatalNetworkErrors++;
1857
- if (nonFatalNetworkErrors >= 3) {
1858
- if (debug) console.warn("".concat(LOG, " [preload] Too many non-fatal HLS network errors during playback, treating as fatal"));
1859
- handleAdError();
1860
- }
1861
- }
1862
- });
1863
- }
1864
- setupAdEventListeners();
1865
- if (!continueLiveStreamDuringAds) {
1866
- contentVideo.pause();
1867
- }
1868
- contentVideo.muted = true;
1869
- contentVideo.volume = 0;
1870
- adPlaying = true;
1871
- setAdPlayingFlag(true);
1872
- adVolume = originalMutedState ? 1 : originalVolume;
1873
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1874
- adVideoElement.muted = false;
1875
- container = ensureAdContainer();
1876
- container.style.display = "flex";
1877
- container.style.pointerEvents = "auto";
1878
- emit("content_pause");
1879
- adVideoElement.play().catch(function(error) {
1880
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1558
+ case 2:
1559
+ _state.sent();
1560
+ return [
1561
+ 2,
1562
+ Promise.resolve()
1563
+ ];
1564
+ case 3:
1565
+ error = _state.sent();
1566
+ console.error("[AdStormPlayer] Error playing ad:", error);
1881
1567
  handleAdError();
1882
- });
1883
- return [
1884
- 2
1885
- ];
1886
- }
1887
- });
1888
- })();
1889
- }
1890
- function cancelPreload(token) {
1891
- var slot = preloadSlots.get(token);
1892
- if (!slot) return;
1893
- preloadSlots.delete(token);
1894
- if (slot.hlsInstance) {
1895
- slot.hlsInstance.destroy();
1896
- }
1897
- if (slot.videoEl) {
1898
- slot.videoEl.pause();
1899
- slot.videoEl.removeAttribute("src");
1900
- slot.videoEl.load();
1901
- slot.videoEl.remove();
1902
- }
1903
- if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1904
- }
1905
- return {
1906
- initialize: function initialize() {
1907
- if (debug) console.log("".concat(LOG, " Initializing"));
1908
- },
1909
- updateOptions: function updateOptions(opts) {
1910
- if (opts.continueLiveStreamDuringAds !== void 0) {
1911
- continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;
1912
- }
1913
- if (opts.mainHlsInstance !== void 0) {
1914
- var _opts_mainHlsInstance;
1915
- mainHlsInstance = (_opts_mainHlsInstance = opts.mainHlsInstance) !== null && _opts_mainHlsInstance !== void 0 ? _opts_mainHlsInstance : void 0;
1916
- }
1917
- },
1918
- playAd: playAd,
1919
- preloadAd: preloadAd,
1920
- playPreloaded: playPreloaded,
1921
- hasPreloaded: function hasPreloaded(token) {
1922
- return preloadSlots.has(token);
1923
- },
1924
- cancelPreload: cancelPreload,
1925
- pause: function pause() {
1926
- if (!adPlaying || !adVideoElement) return;
1927
- try {
1928
- if (!adVideoElement.paused) adVideoElement.pause();
1929
- } catch (error) {
1930
- if (debug) console.warn("".concat(LOG, " Error pausing ad:"), error);
1931
- }
1932
- },
1933
- resume: function resume() {
1934
- if (!adPlaying || !adVideoElement) return;
1935
- try {
1936
- if (adVideoElement.paused) adVideoElement.play().catch(function() {});
1937
- } catch (error) {
1938
- if (debug) console.warn("".concat(LOG, " Error resuming ad:"), error);
1939
- }
1568
+ return [
1569
+ 2,
1570
+ Promise.reject(error)
1571
+ ];
1572
+ case 4:
1573
+ return [
1574
+ 2
1575
+ ];
1576
+ }
1577
+ });
1578
+ })();
1940
1579
  },
1941
1580
  stop: function stop() {
1942
1581
  return _async_to_generator(function() {
1943
1582
  return _ts_generator(this, function(_state) {
1583
+ log("Stopping ad");
1944
1584
  tornDown = true;
1945
- if (debug) console.log("".concat(LOG, " Stopping ad"));
1946
1585
  adPlaying = false;
1947
1586
  setAdPlayingFlag(false);
1948
- contentVideo.muted = originalMutedState;
1949
- contentVideo.volume = originalMutedState ? 0 : originalVolume;
1587
+ clearAdStallTimer();
1588
+ clearAdCountdownTimer();
1589
+ if (adContainerEl) {
1590
+ adContainerEl.style.opacity = "0";
1591
+ adHideTimerId = setTimeout(function() {
1592
+ if (adContainerEl) {
1593
+ adContainerEl.style.display = "none";
1594
+ adContainerEl.style.pointerEvents = "none";
1595
+ }
1596
+ }, 300);
1597
+ }
1598
+ teardownCurrentPlayback();
1950
1599
  contentVideo.style.visibility = "visible";
1951
1600
  contentVideo.style.opacity = "1";
1952
- if (singleElementMode) {
1953
- teardownCurrentPlayback();
1954
- contentVideo.removeAttribute("src");
1955
- contentVideo.load();
1956
- adVideoElement = void 0;
1957
- } else {
1958
- if (adContainerEl) {
1959
- adContainerEl.style.display = "none";
1960
- adContainerEl.style.pointerEvents = "none";
1961
- }
1962
- if (continueLiveStreamDuringAds) {
1963
- contentVideo.play().catch(function() {});
1964
- }
1965
- teardownCurrentPlayback();
1966
- if (adVideoElement) {
1967
- adVideoElement.pause();
1968
- adVideoElement.removeAttribute("src");
1969
- adVideoElement.load();
1970
- }
1971
- }
1601
+ contentVideo.muted = originalMutedState;
1602
+ contentVideo.volume = originalVolume;
1972
1603
  currentAd = void 0;
1973
1604
  tornDown = false;
1974
1605
  return [
1975
- 2
1606
+ 2,
1607
+ Promise.resolve()
1976
1608
  ];
1977
1609
  });
1978
1610
  })();
1979
1611
  },
1612
+ pause: function pause() {
1613
+ if (!adPlaying || !adVideoElement) return;
1614
+ try {
1615
+ if (!adVideoElement.paused) adVideoElement.pause();
1616
+ } catch (error) {
1617
+ console.warn("[AdStormPlayer] Error pausing ad:", error);
1618
+ }
1619
+ },
1620
+ resume: function resume() {
1621
+ if (!adPlaying || !adVideoElement) return;
1622
+ try {
1623
+ if (adVideoElement.paused) adVideoElement.play().catch(function() {});
1624
+ } catch (error) {
1625
+ console.warn("[AdStormPlayer] Error resuming ad:", error);
1626
+ }
1627
+ },
1980
1628
  destroy: function destroy() {
1981
- tornDown = true;
1982
- if (debug) console.log("".concat(LOG, " Destroying"));
1629
+ log("Destroying");
1983
1630
  destroyed = true;
1631
+ tornDown = true;
1984
1632
  adPlaying = false;
1985
1633
  setAdPlayingFlag(false);
1634
+ clearAdStallTimer();
1635
+ clearAdCountdownTimer();
1636
+ if (adHideTimerId) {
1637
+ clearTimeout(adHideTimerId);
1638
+ adHideTimerId = void 0;
1639
+ }
1986
1640
  contentVideo.muted = originalMutedState;
1987
1641
  contentVideo.volume = originalVolume;
1988
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1989
- try {
1990
- for(var _iterator = Array.from(preloadSlots.entries())[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1991
- var _step_value = _sliced_to_array(_step.value, 1), token = _step_value[0];
1992
- cancelPreload(token);
1993
- }
1994
- } catch (err) {
1995
- _didIteratorError = true;
1996
- _iteratorError = err;
1997
- } finally{
1998
- try {
1999
- if (!_iteratorNormalCompletion && _iterator.return != null) {
2000
- _iterator.return();
2001
- }
2002
- } finally{
2003
- if (_didIteratorError) {
2004
- throw _iteratorError;
2005
- }
2006
- }
2007
- }
1642
+ contentVideo.style.visibility = "visible";
1643
+ contentVideo.style.opacity = "1";
2008
1644
  teardownCurrentPlayback();
2009
- if (adVideoElement) {
2010
- if (singleElementMode && adVideoElement === contentVideo) {
2011
- contentVideo.removeAttribute("src");
2012
- contentVideo.load();
2013
- } else {
2014
- adVideoElement.pause();
2015
- adVideoElement.removeAttribute("src");
2016
- adVideoElement.remove();
2017
- }
2018
- adVideoElement = void 0;
2019
- }
1645
+ adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.remove();
1646
+ adVideoElement = void 0;
2020
1647
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
2021
1648
  adContainerEl.parentElement.removeChild(adContainerEl);
2022
1649
  }
2023
1650
  adContainerEl = void 0;
1651
+ adCountdownEl = void 0;
2024
1652
  currentAd = void 0;
1653
+ sessionId = void 0;
1654
+ preloadSlots.clear();
2025
1655
  listeners.clear();
1656
+ if (parentPositionOverridden && contentVideo.parentElement) {
1657
+ contentVideo.parentElement.style.position = "";
1658
+ parentPositionOverridden = false;
1659
+ }
1660
+ },
1661
+ updateOptions: function updateOptions(opts) {
1662
+ if (opts.continueLiveStreamDuringAds !== void 0) {
1663
+ continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;
1664
+ }
1665
+ },
1666
+ playAd: function playAd(requestContext) {
1667
+ return _async_to_generator(function() {
1668
+ var ad;
1669
+ return _ts_generator(this, function(_state) {
1670
+ switch(_state.label){
1671
+ case 0:
1672
+ if (destroyed) return [
1673
+ 2,
1674
+ Promise.reject(new Error("Player has been destroyed"))
1675
+ ];
1676
+ if (!!currentAd) return [
1677
+ 3,
1678
+ 2
1679
+ ];
1680
+ return [
1681
+ 4,
1682
+ requestAdFromApi(requestContext)
1683
+ ];
1684
+ case 1:
1685
+ ad = _state.sent();
1686
+ if (!ad) {
1687
+ emit("ad_error", {
1688
+ message: "No valid ad from AdStorm API"
1689
+ });
1690
+ return [
1691
+ 2,
1692
+ Promise.reject(new Error("No valid ad from AdStorm API"))
1693
+ ];
1694
+ }
1695
+ assignCurrentAd(ad);
1696
+ _state.label = 2;
1697
+ case 2:
1698
+ return [
1699
+ 2,
1700
+ this.play()
1701
+ ];
1702
+ }
1703
+ });
1704
+ }).call(this);
1705
+ },
1706
+ preloadAd: function preloadAd(arg1, arg2) {
1707
+ return _async_to_generator(function() {
1708
+ var token, requestContext, ad;
1709
+ return _ts_generator(this, function(_state) {
1710
+ switch(_state.label){
1711
+ case 0:
1712
+ if (destroyed) return [
1713
+ 2
1714
+ ];
1715
+ token = typeof arg1 === "string" ? arg1 : typeof arg2 === "string" ? arg2 : void 0;
1716
+ if (!token) return [
1717
+ 2
1718
+ ];
1719
+ requestContext = typeof arg1 === "string" ? arg2 : arg1;
1720
+ return [
1721
+ 4,
1722
+ requestAdFromApi(requestContext)
1723
+ ];
1724
+ case 1:
1725
+ ad = _state.sent();
1726
+ if (!ad) return [
1727
+ 2
1728
+ ];
1729
+ preloadSlots.set(token, {
1730
+ ad: ad
1731
+ });
1732
+ return [
1733
+ 2
1734
+ ];
1735
+ }
1736
+ });
1737
+ })();
1738
+ },
1739
+ playPreloaded: function playPreloaded(token) {
1740
+ return _async_to_generator(function() {
1741
+ var slot;
1742
+ return _ts_generator(this, function(_state) {
1743
+ if (destroyed) return [
1744
+ 2,
1745
+ Promise.reject(new Error("Player has been destroyed"))
1746
+ ];
1747
+ slot = preloadSlots.get(token);
1748
+ if (!slot) {
1749
+ return [
1750
+ 2,
1751
+ Promise.reject(new Error("No preloaded ad for token ".concat(token)))
1752
+ ];
1753
+ }
1754
+ preloadSlots.delete(token);
1755
+ assignCurrentAd(slot.ad);
1756
+ return [
1757
+ 2,
1758
+ this.play()
1759
+ ];
1760
+ });
1761
+ }).call(this);
1762
+ },
1763
+ hasPreloaded: function hasPreloaded(token) {
1764
+ return preloadSlots.has(token);
1765
+ },
1766
+ cancelPreload: function cancelPreload(token) {
1767
+ preloadSlots.delete(token);
2026
1768
  },
2027
1769
  isAdPlaying: function isAdPlaying() {
2028
1770
  return adPlaying;
2029
1771
  },
2030
1772
  resize: function resize(width, height) {
1773
+ log("Resizing to ".concat(width, "x").concat(height));
2031
1774
  if (adContainerEl) {
2032
1775
  adContainerEl.style.width = "".concat(width, "px");
2033
1776
  adContainerEl.style.height = "".concat(height, "px");
@@ -2047,6 +1790,7 @@ function createVastAdLayer(contentVideo, options) {
2047
1790
  },
2048
1791
  updateOriginalMutedState: function updateOriginalMutedState(muted, volume) {
2049
1792
  var nextVolume = typeof volume === "number" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;
1793
+ log("updateOriginalMutedState: muted=".concat(muted, ", volume=").concat(nextVolume));
2050
1794
  originalMutedState = muted;
2051
1795
  originalVolume = nextVolume;
2052
1796
  },
@@ -2059,6 +1803,7 @@ function createVastAdLayer(contentVideo, options) {
2059
1803
  setAdVolume: function setAdVolume(volume) {
2060
1804
  if (adVideoElement && adPlaying) {
2061
1805
  adVideoElement.volume = Math.max(0, Math.min(1, volume));
1806
+ adVideoElement.muted = volume === 0;
2062
1807
  }
2063
1808
  },
2064
1809
  getAdVolume: function getAdVolume() {
@@ -2068,11 +1813,16 @@ function createVastAdLayer(contentVideo, options) {
2068
1813
  return 1;
2069
1814
  },
2070
1815
  showPlaceholder: function showPlaceholder() {
2071
- if (singleElementMode) return;
2072
- contentVideo.style.opacity = "0";
2073
- contentVideo.style.visibility = "hidden";
2074
1816
  if (!adContainerEl) {
2075
1817
  var _contentVideo_parentElement;
1818
+ var parent = contentVideo.parentElement;
1819
+ if (parent) {
1820
+ var computed = window.getComputedStyle(parent).position;
1821
+ if (computed === "static") {
1822
+ parent.style.position = "relative";
1823
+ parentPositionOverridden = true;
1824
+ }
1825
+ }
2076
1826
  var container = document.createElement("div");
2077
1827
  container.style.position = "absolute";
2078
1828
  container.style.left = "0";
@@ -2083,24 +1833,43 @@ function createVastAdLayer(contentVideo, options) {
2083
1833
  container.style.alignItems = "center";
2084
1834
  container.style.justifyContent = "center";
2085
1835
  container.style.pointerEvents = "none";
2086
- container.style.zIndex = "10";
1836
+ container.style.zIndex = AD_LAYER_Z_INDEX;
2087
1837
  container.style.backgroundColor = "#000";
1838
+ container.style.isolation = "isolate";
1839
+ var countdown = document.createElement("div");
1840
+ countdown.style.position = "absolute";
1841
+ countdown.style.right = "12px";
1842
+ countdown.style.top = "12px";
1843
+ countdown.style.padding = "4px 8px";
1844
+ countdown.style.borderRadius = "4px";
1845
+ countdown.style.background = "rgba(0,0,0,0.75)";
1846
+ countdown.style.color = "#fff";
1847
+ countdown.style.fontFamily = "sans-serif";
1848
+ countdown.style.fontSize = "12px";
1849
+ countdown.style.lineHeight = "1.2";
1850
+ countdown.style.pointerEvents = "none";
1851
+ countdown.style.zIndex = COUNTDOWN_Z_INDEX;
1852
+ countdown.textContent = "Ad";
1853
+ container.appendChild(countdown);
2088
1854
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
2089
1855
  adContainerEl = container;
1856
+ adCountdownEl = countdown;
2090
1857
  }
2091
1858
  if (adContainerEl) {
2092
1859
  adContainerEl.style.display = "flex";
1860
+ adContainerEl.style.opacity = "1";
2093
1861
  adContainerEl.style.pointerEvents = "auto";
2094
1862
  }
2095
1863
  },
2096
1864
  hidePlaceholder: function hidePlaceholder() {
2097
1865
  if (adContainerEl) {
2098
- adContainerEl.style.display = "none";
2099
- adContainerEl.style.pointerEvents = "none";
2100
- }
2101
- if (!adPlaying) {
2102
- contentVideo.style.visibility = "visible";
2103
- contentVideo.style.opacity = "1";
1866
+ adContainerEl.style.opacity = "0";
1867
+ setTimeout(function() {
1868
+ if (adContainerEl) {
1869
+ adContainerEl.style.display = "none";
1870
+ adContainerEl.style.pointerEvents = "none";
1871
+ }
1872
+ }, 300);
2104
1873
  }
2105
1874
  }
2106
1875
  };
@@ -3228,6 +2997,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3228
2997
  this.backoffBaseMs = 1e3;
3229
2998
  this.maxBackoffMs = 15e3;
3230
2999
  this.MIN_AD_REMAINING_MS = 15e3;
3000
+ this.adRequestTimeoutMs = 5e3;
3001
+ this.adRequestMaxRetries = 3;
3002
+ this.adRequestRetryBackoffMs = 1500;
3231
3003
  this.preloadedTokens = [];
3232
3004
  initializePolyfills();
3233
3005
  var browserOverrides = getBrowserConfigOverrides();
@@ -3235,24 +3007,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3235
3007
  this.video = config.videoElement;
3236
3008
  this.adTransitionGapMs = (_this_config_adTransitionGapMs = this.config.adTransitionGapMs) !== null && _this_config_adTransitionGapMs !== void 0 ? _this_config_adTransitionGapMs : 100;
3237
3009
  logBrowserInfo(config.debugAdTiming);
3238
- this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
3239
- debug: !!config.debugAdTiming
3240
- } : {});
3241
3010
  var browserForAdLayer = detectBrowser();
3242
3011
  var isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;
3243
- this.adLayer = createVastAdLayer(this.video, {
3244
- continueLiveStreamDuringAds: false,
3245
- smartTVMode: isSinglePipeline,
3246
- singleElementMode: isSinglePipeline,
3247
- forceMP4Ads: isSinglePipeline,
3012
+ this.adLayer = createAdStormPlayer(this.video, {
3013
+ licenseKey: this.config.licenseKey || "",
3248
3014
  debug: !!config.debugAdTiming
3249
3015
  });
3016
+ this.adLayer.updateOptions({
3017
+ continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds()
3018
+ });
3250
3019
  }
3251
3020
  _create_class(StormcloudVideoPlayer, [
3252
3021
  {
3253
3022
  key: "adRequest",
3254
3023
  value: function adRequest(context) {
3255
3024
  return _async_to_generator(function() {
3025
+ var _ref, _ref1, durationSeconds;
3256
3026
  return _ts_generator(this, function(_state) {
3257
3027
  switch(_state.label){
3258
3028
  case 0:
@@ -3260,15 +3030,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3260
3030
  2,
3261
3031
  []
3262
3032
  ];
3033
+ durationSeconds = Math.max(1, Math.ceil((_ref = (_ref1 = context === null || context === void 0 ? void 0 : context.remainingBreakSec) !== null && _ref1 !== void 0 ? _ref1 : context === null || context === void 0 ? void 0 : context.breakDurationSec) !== null && _ref !== void 0 ? _ref : 30));
3263
3034
  return [
3264
3035
  4,
3265
- this.vastManager.initialize()
3036
+ this.adLayer.requestAds(String(durationSeconds))
3266
3037
  ];
3267
3038
  case 1:
3268
3039
  _state.sent();
3269
3040
  return [
3270
3041
  2,
3271
- this.vastManager.requestBidsUntilResponse(context)
3042
+ [
3043
+ {
3044
+ bidder: "adstorm-direct",
3045
+ cpm: 0,
3046
+ width: 0,
3047
+ height: 0,
3048
+ adId: "adstorm",
3049
+ impId: "",
3050
+ creativeId: "adstorm",
3051
+ currency: "USD",
3052
+ durationSec: durationSeconds
3053
+ }
3054
+ ]
3272
3055
  ];
3273
3056
  }
3274
3057
  });
@@ -3325,7 +3108,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3325
3108
  2
3326
3109
  ];
3327
3110
  case 3:
3328
- this.hls = new import_hls2.default(_object_spread_props(_object_spread({
3111
+ this.hls = new import_hls.default(_object_spread_props(_object_spread({
3329
3112
  enableWorker: true,
3330
3113
  backBufferLength: 30,
3331
3114
  liveDurationInfinity: true,
@@ -3343,11 +3126,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3343
3126
  nudgeMaxRetry: 3,
3344
3127
  startPosition: -1
3345
3128
  }));
3346
- this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, function() {
3129
+ this.hls.on(import_hls.default.Events.MEDIA_ATTACHED, function() {
3347
3130
  var _this_hls;
3348
3131
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.loadSource(_this.config.src);
3349
3132
  });
3350
- this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
3133
+ this.hls.on(import_hls.default.Events.MANIFEST_PARSED, function(_, data) {
3351
3134
  return _async_to_generator(function() {
3352
3135
  var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, _this_hls1, minSegments, _this_video_play;
3353
3136
  return _ts_generator(this, function(_state) {
@@ -3409,7 +3192,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3409
3192
  });
3410
3193
  }).call(_this);
3411
3194
  });
3412
- this.hls.on(import_hls2.default.Events.LEVEL_LOADED, function(_evt, data) {
3195
+ this.hls.on(import_hls.default.Events.LEVEL_LOADED, function(_evt, data) {
3413
3196
  if (_this.inAdBreak || _this.pendingAdBreak) {
3414
3197
  return;
3415
3198
  }
@@ -3482,7 +3265,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3482
3265
  }
3483
3266
  }
3484
3267
  });
3485
- this.hls.on(import_hls2.default.Events.FRAG_BUFFERED, function(_evt, data) {
3268
+ this.hls.on(import_hls.default.Events.FRAG_BUFFERED, function(_evt, data) {
3486
3269
  return _async_to_generator(function() {
3487
3270
  var _this, _this_config_minSegmentsBeforePlay, minSegments, _this_video_play;
3488
3271
  return _ts_generator(this, function(_state) {
@@ -3542,7 +3325,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3542
3325
  });
3543
3326
  }).call(_this);
3544
3327
  });
3545
- this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3328
+ this.hls.on(import_hls.default.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3546
3329
  var id3Tags = ((data === null || data === void 0 ? void 0 : data.samples) || []).map(function(s) {
3547
3330
  return {
3548
3331
  key: "ID3",
@@ -3554,7 +3337,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3554
3337
  return _this.onId3Tag(tag);
3555
3338
  });
3556
3339
  });
3557
- this.hls.on(import_hls2.default.Events.FRAG_CHANGED, function(_evt, data) {
3340
+ this.hls.on(import_hls.default.Events.FRAG_CHANGED, function(_evt, data) {
3558
3341
  var frag = data === null || data === void 0 ? void 0 : data.frag;
3559
3342
  var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3560
3343
  if (!Array.isArray(tagList)) return;
@@ -3663,14 +3446,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3663
3446
  }
3664
3447
  }
3665
3448
  });
3666
- this.hls.on(import_hls2.default.Events.ERROR, function(_evt, data) {
3449
+ this.hls.on(import_hls.default.Events.ERROR, function(_evt, data) {
3667
3450
  if (data === null || data === void 0 ? void 0 : data.fatal) {
3668
3451
  switch(data.type){
3669
- case import_hls2.default.ErrorTypes.NETWORK_ERROR:
3452
+ case import_hls.default.ErrorTypes.NETWORK_ERROR:
3670
3453
  var _this_hls;
3671
3454
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.startLoad();
3672
3455
  break;
3673
- case import_hls2.default.ErrorTypes.MEDIA_ERROR:
3456
+ case import_hls.default.ErrorTypes.MEDIA_ERROR:
3674
3457
  var _this_hls1;
3675
3458
  (_this_hls1 = _this.hls) === null || _this_hls1 === void 0 ? void 0 : _this_hls1.recoverMediaError();
3676
3459
  break;
@@ -3762,7 +3545,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3762
3545
  }
3763
3546
  });
3764
3547
  this.adLayer.on("content_resume", function() {
3548
+ var _ref, _ref1;
3549
+ var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
3765
3550
  var remaining = _this.getRemainingAdMs();
3551
+ var breakMuted = (_ref = (_this_savedMutedStateBeforeScte = _this.savedMutedStateBeforeScte) === null || _this_savedMutedStateBeforeScte === void 0 ? void 0 : _this_savedMutedStateBeforeScte.muted) !== null && _ref !== void 0 ? _ref : _this.adLayer.getOriginalMutedState();
3552
+ var breakVolume = (_ref1 = (_this_savedMutedStateBeforeScte1 = _this.savedMutedStateBeforeScte) === null || _this_savedMutedStateBeforeScte1 === void 0 ? void 0 : _this_savedMutedStateBeforeScte1.volume) !== null && _ref1 !== void 0 ? _ref1 : _this.adLayer.getOriginalVolume();
3766
3553
  if (_this.config.debugAdTiming) {
3767
3554
  console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s", _this.inAdBreak, remaining, _this.preloadedTokens.length, !!_this.pendingNextAdBids);
3768
3555
  }
@@ -3777,7 +3564,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3777
3564
  return;
3778
3565
  }
3779
3566
  _this.consecutiveFailures = 0;
3780
- if (!_this.video.muted) {
3567
+ if (!_this.config.disableFiller && !_this.video.muted) {
3781
3568
  _this.video.muted = true;
3782
3569
  _this.video.volume = 0;
3783
3570
  }
@@ -3844,6 +3631,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3844
3631
  if (!_this.config.disableFiller) {
3845
3632
  _this.showPlaceholderLayer();
3846
3633
  _this.adLayer.showPlaceholder();
3634
+ } else {
3635
+ _this.adLayer.hidePlaceholder();
3636
+ if (_this.video.muted !== breakMuted) {
3637
+ _this.video.muted = breakMuted;
3638
+ }
3639
+ if (Math.abs(_this.video.volume - breakVolume) > 0.01) {
3640
+ _this.video.volume = breakVolume;
3641
+ }
3642
+ if (_this.video.paused) {
3643
+ var _this_video_play;
3644
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3645
+ }
3847
3646
  }
3848
3647
  _this.stopContinuousFetching();
3849
3648
  return;
@@ -4571,6 +4370,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4571
4370
  return this.totalAdsInBreak;
4572
4371
  }
4573
4372
  },
4373
+ {
4374
+ key: "getRemainingAdSeconds",
4375
+ value: function getRemainingAdSeconds() {
4376
+ var remainingMs = this.getRemainingAdMs();
4377
+ if (!Number.isFinite(remainingMs) || remainingMs <= 0 || remainingMs === Number.MAX_SAFE_INTEGER) {
4378
+ return 0;
4379
+ }
4380
+ return Math.ceil(remainingMs / 1e3);
4381
+ }
4382
+ },
4574
4383
  {
4575
4384
  key: "isAdPlaying",
4576
4385
  value: function isAdPlaying() {
@@ -5800,7 +5609,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5800
5609
  });
5801
5610
  };
5802
5611
  var onManifestParsedRestore = function onManifestParsedRestore1() {
5803
- hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5612
+ hlsRef.off(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5804
5613
  if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5805
5614
  if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;
5806
5615
  if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;
@@ -5813,7 +5622,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5813
5622
  }
5814
5623
  }
5815
5624
  };
5816
- hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5625
+ hlsRef.on(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5817
5626
  var pipelineDelayMs = 300;
5818
5627
  if (debugEnabled) {
5819
5628
  console.log("[StormcloudVideoPlayer] Smart TV: waiting ".concat(pipelineDelayMs, "ms for hardware pipeline release before re-attach"));
@@ -7427,7 +7236,8 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7427
7236
  var _import_react2_default_useState = _sliced_to_array(import_react2.default.useState({
7428
7237
  showAds: false,
7429
7238
  currentIndex: 0,
7430
- totalAds: 0
7239
+ totalAds: 0,
7240
+ remainingSeconds: 0
7431
7241
  }), 2), adStatus = _import_react2_default_useState[0], setAdStatus = _import_react2_default_useState[1];
7432
7242
  var _import_react2_default_useState1 = _sliced_to_array(import_react2.default.useState(true), 2), shouldShowNativeControls = _import_react2_default_useState1[0], setShouldShowNativeControls = _import_react2_default_useState1[1];
7433
7243
  var _import_react2_default_useState2 = _sliced_to_array(import_react2.default.useState(false), 2), isMuted = _import_react2_default_useState2[0], setIsMuted = _import_react2_default_useState2[1];
@@ -7679,15 +7489,17 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7679
7489
  var showAds = showAdsFromMethod || showAdsFromAttribute;
7680
7490
  var currentIndex = playerRef.current.getCurrentAdIndex();
7681
7491
  var totalAds = playerRef.current.getTotalAdsInBreak();
7492
+ var remainingSeconds = playerRef.current.getRemainingAdSeconds();
7682
7493
  setAdStatus(function(prev) {
7683
- if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds) {
7494
+ if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds || prev.remainingSeconds !== remainingSeconds) {
7684
7495
  if (showAds && !prev.showAds) {
7685
7496
  setShowCenterPlay(false);
7686
7497
  }
7687
7498
  return {
7688
7499
  showAds: showAds,
7689
7500
  currentIndex: currentIndex,
7690
- totalAds: totalAds
7501
+ totalAds: totalAds,
7502
+ remainingSeconds: remainingSeconds
7691
7503
  };
7692
7504
  }
7693
7505
  return prev;
@@ -8077,6 +7889,22 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8077
7889
  " of ",
8078
7890
  Math.max(adStatus.totalAds, adStatus.currentIndex)
8079
7891
  ]
7892
+ }),
7893
+ adStatus.remainingSeconds > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
7894
+ style: {
7895
+ background: "rgba(0, 0, 0, 0.5)",
7896
+ backdropFilter: "blur(12px)",
7897
+ color: "rgba(255, 255, 255, 0.9)",
7898
+ padding: "".concat(4 * responsiveScale, "px ").concat(10 * responsiveScale, "px"),
7899
+ borderRadius: "6px",
7900
+ fontSize: "".concat(11 * responsiveScale, "px"),
7901
+ fontWeight: "600",
7902
+ border: "1px solid rgba(255, 255, 255, 0.08)"
7903
+ },
7904
+ children: [
7905
+ adStatus.remainingSeconds,
7906
+ "s"
7907
+ ]
8080
7908
  })
8081
7909
  ]
8082
7910
  }),
@@ -9884,9 +9712,8 @@ var StormcloudPlayer_default = StormcloudPlayer;
9884
9712
  StormcloudVideoPlayer: StormcloudVideoPlayer,
9885
9713
  StormcloudVideoPlayerComponent: StormcloudVideoPlayerComponent,
9886
9714
  canPlay: canPlay,
9715
+ createAdStormPlayer: createAdStormPlayer,
9887
9716
  createStormcloudPlayer: createStormcloudPlayer,
9888
- createVastAdLayer: createVastAdLayer,
9889
- createVastManager: createVastManager,
9890
9717
  detectBrowser: detectBrowser,
9891
9718
  fetchProjectOverlays: fetchProjectOverlays,
9892
9719
  getBrowserConfigOverrides: getBrowserConfigOverrides,