stormcloud-video-player 0.7.3 → 0.7.5

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.
@@ -399,185 +399,8 @@ __export(HlsPlayer_exports, {
399
399
  module.exports = __toCommonJS(HlsPlayer_exports);
400
400
  var import_react = require("react");
401
401
  // src/player/StormcloudVideoPlayer.ts
402
- var import_hls2 = __toESM(require("hls.js"), 1);
402
+ var import_hls = __toESM(require("hls.js"), 1);
403
403
  // src/sdk/vastParser.ts
404
- function isHlsType(type) {
405
- return type === "application/x-mpegURL" || type.includes("m3u8");
406
- }
407
- function isMp4Type(type) {
408
- return type === "video/mp4" || type.includes("mp4");
409
- }
410
- function parseVastXml(xmlString) {
411
- var filter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all", logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
412
- try {
413
- var _xmlDoc_querySelector, _xmlDoc_querySelector1, _xmlDoc_querySelector_textContent, _xmlDoc_querySelector2;
414
- var parser = new DOMParser();
415
- var xmlDoc = parser.parseFromString(xmlString, "text/xml");
416
- var parserError = xmlDoc.querySelector("parsererror");
417
- if (parserError) {
418
- console.error("".concat(logPrefix, " XML parsing error (malformed VAST XML):"), parserError.textContent);
419
- return null;
420
- }
421
- var adElement = xmlDoc.querySelector("Ad");
422
- if (!adElement) {
423
- console.warn("".concat(logPrefix, " No Ad element found in VAST XML"));
424
- return null;
425
- }
426
- var adId = adElement.getAttribute("id") || "unknown";
427
- var title = ((_xmlDoc_querySelector = xmlDoc.querySelector("AdTitle")) === null || _xmlDoc_querySelector === void 0 ? void 0 : _xmlDoc_querySelector.textContent) || "Ad";
428
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
429
- var durationText = ((_xmlDoc_querySelector1 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector1 === void 0 ? void 0 : _xmlDoc_querySelector1.textContent) || "00:00:30";
430
- var durationParts = durationText.split(":");
431
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + Math.round(parseFloat(durationParts[2] || "0"));
432
- var mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
433
- var mediaFiles = [];
434
- console.log("".concat(logPrefix, " Found ").concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
435
- mediaFileElements.forEach(function(mf, index) {
436
- var _mf_textContent;
437
- var type = mf.getAttribute("type") || "";
438
- var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
439
- var width = mf.getAttribute("width") || "";
440
- var height = mf.getAttribute("height") || "";
441
- console.log("".concat(logPrefix, " MediaFile ").concat(index, ': type="').concat(type, '", url="').concat(url.substring(0, 80), '...", width="').concat(width, '", height="').concat(height, '"'));
442
- if (!url) {
443
- console.warn("".concat(logPrefix, " MediaFile ").concat(index, " has empty URL"));
444
- return;
445
- }
446
- var isHls = isHlsType(type);
447
- var isMp4 = isMp4Type(type);
448
- var accepted = false;
449
- if (filter === "hls-only") {
450
- accepted = isHls;
451
- } else if (filter === "mp4-first") {
452
- accepted = isMp4 || isHls;
453
- } else {
454
- accepted = true;
455
- }
456
- if (!accepted) {
457
- console.log("".concat(logPrefix, " MediaFile ").concat(index, ' ignored (type="').concat(type, '" not accepted by filter "').concat(filter, '")'));
458
- return;
459
- }
460
- var bitrateAttr = mf.getAttribute("bitrate");
461
- var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
462
- mediaFiles.push({
463
- url: url,
464
- type: type,
465
- width: parseInt(width || "1920", 10),
466
- height: parseInt(height || "1080", 10),
467
- bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
468
- });
469
- console.log("".concat(logPrefix, ' Added MediaFile: type="').concat(type, '" url="').concat(url.substring(0, 80), '..."'));
470
- });
471
- if (filter === "mp4-first" && mediaFiles.length > 1) {
472
- mediaFiles.sort(function(a, b) {
473
- var aIsMp4 = isMp4Type(a.type) ? 0 : 1;
474
- var bIsMp4 = isMp4Type(b.type) ? 0 : 1;
475
- return aIsMp4 - bIsMp4;
476
- });
477
- }
478
- if (mediaFiles.length === 0) {
479
- if (isNoAdAvailable) {
480
- console.warn("".concat(logPrefix, " No ads available (VAST response indicates no ads)"));
481
- } else {
482
- console.warn("".concat(logPrefix, " No compatible media files found in VAST XML"));
483
- }
484
- return null;
485
- }
486
- var trackingUrls = {
487
- impression: [],
488
- start: [],
489
- firstQuartile: [],
490
- midpoint: [],
491
- thirdQuartile: [],
492
- complete: [],
493
- mute: [],
494
- unmute: [],
495
- pause: [],
496
- resume: [],
497
- fullscreen: [],
498
- exitFullscreen: [],
499
- skip: [],
500
- error: []
501
- };
502
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
503
- var _el_textContent;
504
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
505
- if (url) trackingUrls.impression.push(url);
506
- });
507
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
508
- var _el_textContent;
509
- var event = el.getAttribute("event");
510
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
511
- if (event && url) {
512
- var eventKey = event;
513
- if (trackingUrls[eventKey]) {
514
- trackingUrls[eventKey].push(url);
515
- }
516
- }
517
- });
518
- 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();
519
- return {
520
- id: adId,
521
- title: title,
522
- duration: duration,
523
- mediaFiles: mediaFiles,
524
- trackingUrls: trackingUrls,
525
- clickThrough: clickThrough
526
- };
527
- } catch (error) {
528
- console.error("".concat(logPrefix, " Error parsing VAST XML:"), error);
529
- return null;
530
- }
531
- }
532
- function fetchAndParseVastAd(vastTagUrl) {
533
- var filter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all", logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
534
- return _async_to_generator(function() {
535
- var response, vastXml;
536
- return _ts_generator(this, function(_state) {
537
- switch(_state.label){
538
- case 0:
539
- return [
540
- 4,
541
- fetch(vastTagUrl, {
542
- mode: "cors",
543
- credentials: "include",
544
- headers: {
545
- Accept: "application/xml, text/xml, */*"
546
- },
547
- referrerPolicy: "no-referrer-when-downgrade"
548
- })
549
- ];
550
- case 1:
551
- response = _state.sent();
552
- if (!response.ok) {
553
- throw new Error("Failed to fetch VAST: ".concat(response.statusText));
554
- }
555
- return [
556
- 4,
557
- response.text()
558
- ];
559
- case 2:
560
- vastXml = _state.sent();
561
- console.log("".concat(logPrefix, " VAST XML received"));
562
- console.log("".concat(logPrefix, " VAST XML content (first 2000 chars):"), vastXml.substring(0, 2e3));
563
- return [
564
- 2,
565
- parseVastXml(vastXml, filter, logPrefix)
566
- ];
567
- }
568
- });
569
- })();
570
- }
571
- function createEmptyTrackingState() {
572
- return {
573
- impression: false,
574
- start: false,
575
- firstQuartile: false,
576
- midpoint: false,
577
- thirdQuartile: false,
578
- complete: false
579
- };
580
- }
581
404
  function firePixelWithRetry(url) {
582
405
  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]";
583
406
  return _async_to_generator(function() {
@@ -700,16 +523,164 @@ function fireTrackingPixels(urls, sessionId) {
700
523
  }
701
524
  });
702
525
  }
703
- // src/sdk/vastManager.ts
704
- 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";
705
- var DEFAULT_TIMEOUT_MS = 5e3;
706
- var MAX_RETRIES = 3;
707
- var RETRY_BACKOFF_MS = 1500;
708
- function createVastManager() {
709
- var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
710
- var _options_debug;
711
- var initialized = false;
712
- var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
526
+ // src/sdk/adstormPlayer.ts
527
+ var SUPPORTED_VIDEO_EXTENSIONS = [
528
+ ".mp4",
529
+ ".webm",
530
+ ".ogg",
531
+ ".m3u8",
532
+ ".ts"
533
+ ];
534
+ var UNSUPPORTED_VIDEO_EXTENSIONS = [
535
+ ".flv",
536
+ ".f4v",
537
+ ".swf",
538
+ ".wmv",
539
+ ".avi",
540
+ ".mov",
541
+ ".mkv"
542
+ ];
543
+ var REQUEST_TIMEOUT_MS = 5e3;
544
+ var REQUEST_MAX_RETRIES = 3;
545
+ var REQUEST_RETRY_BACKOFF_MS = 1500;
546
+ var AD_LAYER_Z_INDEX = "30";
547
+ var COUNTDOWN_Z_INDEX = "31";
548
+ var STALL_TIMEOUT_MS = 8e3;
549
+ function getFileExtension(url) {
550
+ try {
551
+ var pathname = new URL(url, "http://dummy").pathname;
552
+ var lastDot = pathname.lastIndexOf(".");
553
+ if (lastDot === -1) return "";
554
+ return pathname.slice(lastDot).toLowerCase();
555
+ } catch (unused) {
556
+ var lastDot1 = url.lastIndexOf(".");
557
+ if (lastDot1 === -1) return "";
558
+ var ext = url.slice(lastDot1).split(/[?#]/)[0];
559
+ return (ext || "").toLowerCase();
560
+ }
561
+ }
562
+ function isUnsupportedFormat(url) {
563
+ var ext = getFileExtension(url);
564
+ return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;
565
+ }
566
+ function replaceFlvExtension(url) {
567
+ var ext = getFileExtension(url);
568
+ if (ext === ".flv") {
569
+ return url.replace(/\.flv(\?|$)/i, ".mp4$1");
570
+ }
571
+ return url;
572
+ }
573
+ function isSupportedFormat(url, mimeType) {
574
+ if (isUnsupportedFormat(url)) {
575
+ return false;
576
+ }
577
+ var ext = getFileExtension(url);
578
+ if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {
579
+ return true;
580
+ }
581
+ if (ext === "" || ext === ".") {
582
+ return mimeType.includes("video/mp4") || mimeType.includes("video/webm") || mimeType.includes("m3u8") || mimeType.includes("application/x-mpegurl");
583
+ }
584
+ return false;
585
+ }
586
+ function createAdStormPlayer(contentVideo, options) {
587
+ var licenseKey = options.licenseKey, _options_debug = options.debug, debug = _options_debug === void 0 ? false : _options_debug;
588
+ var adPlaying = false;
589
+ var originalMutedState = false;
590
+ var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
591
+ var listeners = /* @__PURE__ */ new Map();
592
+ var adVideoElement;
593
+ var adContainerEl;
594
+ var adCountdownEl;
595
+ var currentAd;
596
+ var destroyed = false;
597
+ var tornDown = false;
598
+ var continueLiveStreamDuringAds = false;
599
+ var sessionId;
600
+ var adStallTimerId;
601
+ var adCountdownTimerId;
602
+ var adHideTimerId;
603
+ var lastCountdownSecond = -1;
604
+ var adListenersBound = false;
605
+ var parentPositionOverridden = false;
606
+ var adHandlers = {
607
+ timeupdate: function timeupdate() {
608
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
609
+ var progress = adVideoElement.currentTime / currentAd.duration;
610
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
611
+ trackingFired.firstQuartile = true;
612
+ fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);
613
+ }
614
+ if (progress >= 0.5 && !trackingFired.midpoint) {
615
+ trackingFired.midpoint = true;
616
+ fireTrackingPixels2(currentAd.trackingUrls.midpoint);
617
+ }
618
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
619
+ trackingFired.thirdQuartile = true;
620
+ fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);
621
+ }
622
+ updateAdCountdown();
623
+ },
624
+ playing: function playing() {
625
+ clearAdStallTimer();
626
+ if (!currentAd || trackingFired.start || destroyed || tornDown) return;
627
+ trackingFired.start = true;
628
+ fireTrackingPixels2(currentAd.trackingUrls.start);
629
+ startAdCountdown();
630
+ log("Ad started playing");
631
+ },
632
+ ended: function ended() {
633
+ if (!currentAd || trackingFired.complete || destroyed || tornDown) return;
634
+ trackingFired.complete = true;
635
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
636
+ log("Ad completed");
637
+ handleAdComplete();
638
+ },
639
+ error: function error(e) {
640
+ if (destroyed || tornDown) return;
641
+ console.error("[AdStormPlayer] Ad video error:", e);
642
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
643
+ handleAdError();
644
+ },
645
+ waiting: function waiting() {
646
+ clearAdStallTimer();
647
+ adStallTimerId = setTimeout(function() {
648
+ adStallTimerId = void 0;
649
+ if (!adPlaying || destroyed || tornDown) return;
650
+ console.warn("[AdStormPlayer] Ad playback stalled too long");
651
+ handleAdError();
652
+ }, STALL_TIMEOUT_MS);
653
+ },
654
+ volumechange: function volumechange() {
655
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
656
+ if (adVideoElement.muted || adVideoElement.volume <= 0) {
657
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
658
+ } else {
659
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
660
+ }
661
+ },
662
+ pause: function pause() {
663
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
664
+ if (!adVideoElement.ended) {
665
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
666
+ }
667
+ },
668
+ play: function play() {
669
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
670
+ if (adVideoElement.currentTime > 0) {
671
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
672
+ }
673
+ }
674
+ };
675
+ var trackingFired = {
676
+ impression: false,
677
+ start: false,
678
+ firstQuartile: false,
679
+ midpoint: false,
680
+ thirdQuartile: false,
681
+ complete: false
682
+ };
683
+ var preloadSlots = /* @__PURE__ */ new Map();
713
684
  function log() {
714
685
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
715
686
  args[_key] = arguments[_key];
@@ -717,58 +688,340 @@ function createVastManager() {
717
688
  if (debug) {
718
689
  var _console;
719
690
  (_console = console).log.apply(_console, [
720
- "[VastManager]"
691
+ "[AdStormPlayer]"
721
692
  ].concat(_to_consumable_array(args)));
722
693
  }
723
694
  }
724
- function warn() {
725
- for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
726
- args[_key] = arguments[_key];
695
+ function emit(event, payload) {
696
+ var set = listeners.get(event);
697
+ if (!set) return;
698
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
699
+ try {
700
+ for(var _iterator = Array.from(set)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
701
+ var fn = _step.value;
702
+ try {
703
+ fn(payload);
704
+ } catch (error) {
705
+ console.warn("[AdStormPlayer] Error in event listener for ".concat(event, ":"), error);
706
+ }
707
+ }
708
+ } catch (err) {
709
+ _didIteratorError = true;
710
+ _iteratorError = err;
711
+ } finally{
712
+ try {
713
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
714
+ _iterator.return();
715
+ }
716
+ } finally{
717
+ if (_didIteratorError) {
718
+ throw _iteratorError;
719
+ }
720
+ }
727
721
  }
728
- var _console;
729
- (_console = console).warn.apply(_console, [
730
- "[VastManager]"
731
- ].concat(_to_consumable_array(args)));
732
722
  }
733
- function initialize() {
734
- return _async_to_generator(function() {
735
- return _ts_generator(this, function(_state) {
736
- if (initialized) return [
737
- 2
738
- ];
739
- initialized = true;
740
- log("Initialized, VAST tag URL:", VAST_TAG_URL.split("?")[0]);
741
- return [
742
- 2
743
- ];
723
+ function fireTrackingPixels2(urls) {
724
+ fireTrackingPixels(urls, sessionId, "[AdStormPlayer]");
725
+ }
726
+ function clearAdStallTimer() {
727
+ if (adStallTimerId) {
728
+ clearTimeout(adStallTimerId);
729
+ adStallTimerId = void 0;
730
+ }
731
+ }
732
+ function clearAdCountdownTimer() {
733
+ if (adCountdownTimerId) {
734
+ clearInterval(adCountdownTimerId);
735
+ adCountdownTimerId = void 0;
736
+ }
737
+ lastCountdownSecond = -1;
738
+ }
739
+ function updateAdCountdown() {
740
+ if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;
741
+ var remainingSec = Math.max(0, Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime));
742
+ if (remainingSec === lastCountdownSecond) return;
743
+ lastCountdownSecond = remainingSec;
744
+ adCountdownEl.textContent = "Ad ".concat(remainingSec, "s");
745
+ emit("ad_countdown", {
746
+ remainingSec: remainingSec,
747
+ durationSec: currentAd.duration,
748
+ currentTimeSec: adVideoElement.currentTime
749
+ });
750
+ }
751
+ function startAdCountdown() {
752
+ clearAdCountdownTimer();
753
+ updateAdCountdown();
754
+ adCountdownTimerId = setInterval(updateAdCountdown, 250);
755
+ }
756
+ function generateSessionId() {
757
+ return "adstorm-".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2, 10));
758
+ }
759
+ function bindAdEventListeners() {
760
+ if (!adVideoElement || adListenersBound) return;
761
+ adVideoElement.addEventListener("timeupdate", adHandlers.timeupdate);
762
+ adVideoElement.addEventListener("playing", adHandlers.playing);
763
+ adVideoElement.addEventListener("ended", adHandlers.ended);
764
+ adVideoElement.addEventListener("error", adHandlers.error);
765
+ adVideoElement.addEventListener("waiting", adHandlers.waiting);
766
+ adVideoElement.addEventListener("volumechange", adHandlers.volumechange);
767
+ adVideoElement.addEventListener("pause", adHandlers.pause);
768
+ adVideoElement.addEventListener("play", adHandlers.play);
769
+ adListenersBound = true;
770
+ }
771
+ function unbindAdEventListeners() {
772
+ if (!adVideoElement || !adListenersBound) return;
773
+ adVideoElement.removeEventListener("timeupdate", adHandlers.timeupdate);
774
+ adVideoElement.removeEventListener("playing", adHandlers.playing);
775
+ adVideoElement.removeEventListener("ended", adHandlers.ended);
776
+ adVideoElement.removeEventListener("error", adHandlers.error);
777
+ adVideoElement.removeEventListener("waiting", adHandlers.waiting);
778
+ adVideoElement.removeEventListener("volumechange", adHandlers.volumechange);
779
+ adVideoElement.removeEventListener("pause", adHandlers.pause);
780
+ adVideoElement.removeEventListener("play", adHandlers.play);
781
+ adListenersBound = false;
782
+ }
783
+ function teardownCurrentPlayback() {
784
+ unbindAdEventListeners();
785
+ clearAdStallTimer();
786
+ clearAdCountdownTimer();
787
+ if (!adVideoElement) return;
788
+ adVideoElement.pause();
789
+ adVideoElement.removeAttribute("src");
790
+ adVideoElement.load();
791
+ }
792
+ function buildVastUrl(durationSeconds, metadata) {
793
+ var baseUrl = "https://adstorm.co/api-adstorm-dev/adstorm/vast/".concat(licenseKey, "/pod");
794
+ var defaultMetadata = {
795
+ video: {
796
+ codec: "h264",
797
+ width: contentVideo.videoWidth || 1280,
798
+ height: contentVideo.videoHeight || 720,
799
+ fps: 29.97,
800
+ bitrate: 5e3,
801
+ profile: "high",
802
+ pix_fmt: "yuv420p",
803
+ has_b_frames: 0
804
+ },
805
+ audio: {
806
+ codec: "aac",
807
+ sample_rate: 48e3,
808
+ bitrate: 128
809
+ }
810
+ };
811
+ var finalMetadata = metadata || defaultMetadata;
812
+ var metadataStr = encodeURIComponent(JSON.stringify(finalMetadata));
813
+ return "".concat(baseUrl, "?duration=").concat(Math.ceil(durationSeconds), "&metadata=").concat(metadataStr);
814
+ }
815
+ function parseVastXml(xmlString) {
816
+ var ads = [];
817
+ try {
818
+ var parser = new DOMParser();
819
+ var xmlDoc = parser.parseFromString(xmlString, "text/xml");
820
+ var parserError = xmlDoc.querySelector("parsererror");
821
+ if (parserError) {
822
+ console.error("[AdStormPlayer] XML parsing error:", parserError.textContent);
823
+ return [];
824
+ }
825
+ var adElements = xmlDoc.querySelectorAll("Ad");
826
+ adElements.forEach(function(adElement) {
827
+ var _adElement_querySelector, _adElement_querySelector1, _adElement_querySelector_textContent, _adElement_querySelector2;
828
+ var adId = adElement.getAttribute("id") || "unknown";
829
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
830
+ var durationText = ((_adElement_querySelector1 = adElement.querySelector("Duration")) === null || _adElement_querySelector1 === void 0 ? void 0 : _adElement_querySelector1.textContent) || "00:00:30";
831
+ var durationParts = durationText.split(":");
832
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseFloat(durationParts[2] || "0");
833
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
834
+ var mediaFiles = [];
835
+ mediaFileElements.forEach(function(mf) {
836
+ var _mf_textContent;
837
+ var type = mf.getAttribute("type") || "";
838
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
839
+ var width = parseInt(mf.getAttribute("width") || "1920", 10);
840
+ var height = parseInt(mf.getAttribute("height") || "1080", 10);
841
+ var bitrate = mf.getAttribute("bitrate") ? parseInt(mf.getAttribute("bitrate"), 10) : void 0;
842
+ if (!url) {
843
+ log("Skipping empty MediaFile URL");
844
+ return;
845
+ }
846
+ var originalUrl = url;
847
+ url = replaceFlvExtension(url);
848
+ if (url !== originalUrl) {
849
+ log("Converted FLV to MP4: ".concat(originalUrl, " -> ").concat(url));
850
+ }
851
+ if (isUnsupportedFormat(url)) {
852
+ var ext = getFileExtension(url);
853
+ log("Skipping unsupported format: ".concat(url, " (extension: ").concat(ext, ", declared type: ").concat(type, ")"));
854
+ return;
855
+ }
856
+ if (isSupportedFormat(url, type)) {
857
+ mediaFiles.push({
858
+ url: url,
859
+ type: type,
860
+ width: width,
861
+ height: height,
862
+ bitrate: bitrate
863
+ });
864
+ log("Found media file: ".concat(url, " (").concat(type, ", ").concat(width, "x").concat(height, ")"));
865
+ } else {
866
+ log("Skipping incompatible media file: ".concat(url, " (type: ").concat(type, ")"));
867
+ }
868
+ });
869
+ if (mediaFiles.length === 0) {
870
+ log("No valid media files found in ad:", adId);
871
+ return;
872
+ }
873
+ var trackingUrls = {
874
+ impression: [],
875
+ start: [],
876
+ firstQuartile: [],
877
+ midpoint: [],
878
+ thirdQuartile: [],
879
+ complete: [],
880
+ mute: [],
881
+ unmute: [],
882
+ pause: [],
883
+ resume: [],
884
+ error: []
885
+ };
886
+ adElement.querySelectorAll("Impression").forEach(function(el) {
887
+ var _el_textContent;
888
+ var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
889
+ if (url) trackingUrls.impression.push(url);
890
+ });
891
+ adElement.querySelectorAll("Tracking").forEach(function(el) {
892
+ var _el_textContent;
893
+ var event = el.getAttribute("event");
894
+ var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
895
+ if (event && url) {
896
+ var eventKey = event;
897
+ if (trackingUrls[eventKey]) {
898
+ trackingUrls[eventKey].push(url);
899
+ }
900
+ }
901
+ });
902
+ 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();
903
+ ads.push({
904
+ id: adId,
905
+ title: title,
906
+ duration: duration,
907
+ mediaFiles: mediaFiles,
908
+ trackingUrls: trackingUrls,
909
+ clickThrough: clickThrough
910
+ });
911
+ log("Parsed ad: ".concat(title, ", duration: ").concat(duration, "s, media files: ").concat(mediaFiles.length));
744
912
  });
745
- })();
913
+ } catch (error) {
914
+ console.error("[AdStormPlayer] Error parsing VAST XML:", error);
915
+ }
916
+ return ads;
917
+ }
918
+ function selectBestMediaFile(mediaFiles) {
919
+ if (mediaFiles.length === 0) return null;
920
+ if (mediaFiles.length === 1) return mediaFiles[0];
921
+ var mp4Files = mediaFiles.filter(function(mf) {
922
+ return mf.type.includes("video/mp4");
923
+ });
924
+ var candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;
925
+ var targetWidth = contentVideo.videoWidth || 1280;
926
+ var targetHeight = contentVideo.videoHeight || 720;
927
+ candidates.sort(function(a, b) {
928
+ var diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);
929
+ var diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);
930
+ return diffA - diffB;
931
+ });
932
+ return candidates[0] || null;
933
+ }
934
+ function createAdVideoElement() {
935
+ var video = document.createElement("video");
936
+ video.style.position = "absolute";
937
+ video.style.left = "0";
938
+ video.style.top = "0";
939
+ video.style.width = "100%";
940
+ video.style.height = "100%";
941
+ video.style.objectFit = "contain";
942
+ video.style.backgroundColor = "#000";
943
+ video.style.zIndex = "1";
944
+ video.playsInline = true;
945
+ video.preload = "auto";
946
+ video.muted = originalMutedState;
947
+ video.volume = originalMutedState ? 0 : originalVolume;
948
+ return video;
949
+ }
950
+ function setAdPlayingFlag(isPlaying) {
951
+ if (isPlaying) {
952
+ contentVideo.dataset.stormcloudAdPlaying = "true";
953
+ } else {
954
+ delete contentVideo.dataset.stormcloudAdPlaying;
955
+ }
956
+ }
957
+ function setupAdEventListeners() {
958
+ bindAdEventListeners();
959
+ }
960
+ function handleAdComplete() {
961
+ if (destroyed || tornDown) return;
962
+ log("Handling ad completion");
963
+ adPlaying = false;
964
+ setAdPlayingFlag(false);
965
+ clearAdStallTimer();
966
+ clearAdCountdownTimer();
967
+ if (adContainerEl) {
968
+ adContainerEl.style.opacity = "0";
969
+ adHideTimerId = setTimeout(function() {
970
+ if (adContainerEl) {
971
+ adContainerEl.style.display = "none";
972
+ adContainerEl.style.pointerEvents = "none";
973
+ }
974
+ }, 300);
975
+ }
976
+ contentVideo.style.visibility = "visible";
977
+ contentVideo.style.opacity = "1";
978
+ contentVideo.muted = originalMutedState;
979
+ contentVideo.volume = originalVolume;
980
+ currentAd = void 0;
981
+ emit("content_resume");
982
+ emit("all_ads_completed");
983
+ }
984
+ function handleAdError() {
985
+ if (destroyed || tornDown) return;
986
+ log("Handling ad error");
987
+ if (!adPlaying) return;
988
+ adPlaying = false;
989
+ setAdPlayingFlag(false);
990
+ clearAdStallTimer();
991
+ clearAdCountdownTimer();
992
+ contentVideo.muted = originalMutedState;
993
+ contentVideo.volume = originalVolume;
994
+ contentVideo.style.visibility = "visible";
995
+ contentVideo.style.opacity = "1";
996
+ if (adContainerEl) {
997
+ adContainerEl.style.display = "none";
998
+ adContainerEl.style.pointerEvents = "none";
999
+ }
1000
+ currentAd = void 0;
1001
+ emit("ad_error");
1002
+ emit("content_resume");
746
1003
  }
747
- function requestBids(_context) {
1004
+ function fetchVastOnce(durationSeconds) {
748
1005
  return _async_to_generator(function() {
749
- var correlator, url, controller, timeoutId, _ref, _ref1, _vastAd_mediaFiles_, _vastAd_mediaFiles_1, fetchOptions, response, vastXml, vastAd, bid, error;
1006
+ var vastUrl, controller, timeoutId, requestInit, response, xmlText;
750
1007
  return _ts_generator(this, function(_state) {
751
1008
  switch(_state.label){
752
1009
  case 0:
753
- if (!initialized) {
754
- throw new Error("VastManager not initialized. Call initialize() first.");
755
- }
756
- correlator = Math.floor(Math.random() * 1e12).toString();
757
- url = VAST_TAG_URL.replace("[placeholder]", correlator);
758
- log("Fetching VAST tag, correlator:", correlator);
1010
+ vastUrl = buildVastUrl(durationSeconds);
1011
+ log("Fetching VAST from:", vastUrl);
759
1012
  controller = typeof AbortController !== "undefined" ? new AbortController() : null;
760
1013
  timeoutId = setTimeout(function() {
761
1014
  return controller === null || controller === void 0 ? void 0 : controller.abort();
762
- }, DEFAULT_TIMEOUT_MS);
1015
+ }, REQUEST_TIMEOUT_MS);
763
1016
  _state.label = 1;
764
1017
  case 1:
765
1018
  _state.trys.push([
766
1019
  1,
767
- 4,
768
1020
  ,
1021
+ 4,
769
1022
  5
770
1023
  ]);
771
- fetchOptions = {
1024
+ requestInit = {
772
1025
  method: "GET",
773
1026
  mode: "cors",
774
1027
  credentials: "omit",
@@ -777,62 +1030,34 @@ function createVastManager() {
777
1030
  },
778
1031
  referrerPolicy: "no-referrer-when-downgrade"
779
1032
  };
780
- if (controller) fetchOptions.signal = controller.signal;
1033
+ if (controller) {
1034
+ requestInit.signal = controller.signal;
1035
+ }
781
1036
  return [
782
1037
  4,
783
- fetch(url, fetchOptions)
1038
+ fetch(vastUrl, requestInit)
784
1039
  ];
785
1040
  case 2:
786
1041
  response = _state.sent();
787
- clearTimeout(timeoutId);
788
1042
  if (!response.ok) {
789
- throw new Error("VAST request returned HTTP ".concat(response.status));
1043
+ throw new Error("Failed to fetch VAST: ".concat(response.status, " ").concat(response.statusText));
790
1044
  }
791
1045
  return [
792
1046
  4,
793
1047
  response.text()
794
1048
  ];
795
1049
  case 3:
796
- vastXml = _state.sent();
797
- log("VAST XML received, length:", vastXml.length);
798
- vastAd = parseVastXml(vastXml, "mp4-first", "[VastManager]");
799
- if (!vastAd) {
800
- log("VAST parsed but no usable ad found");
801
- return [
802
- 2,
803
- []
804
- ];
805
- }
806
- log("Ad parsed: id=".concat(vastAd.id, ", duration=").concat(vastAd.duration, "s, mediaFiles=").concat(vastAd.mediaFiles.length));
807
- bid = {
808
- bidder: "vast-direct",
809
- cpm: 0,
810
- vastXml: vastXml,
811
- width: (_ref = (_vastAd_mediaFiles_ = vastAd.mediaFiles[0]) === null || _vastAd_mediaFiles_ === void 0 ? void 0 : _vastAd_mediaFiles_.width) !== null && _ref !== void 0 ? _ref : 0,
812
- 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,
813
- adId: vastAd.id,
814
- impId: correlator,
815
- creativeId: vastAd.id,
816
- currency: "USD",
817
- durationSec: vastAd.duration
818
- };
1050
+ xmlText = _state.sent();
1051
+ log("VAST response received, length:", xmlText.length);
819
1052
  return [
820
1053
  2,
821
- [
822
- bid
823
- ]
1054
+ parseVastXml(xmlText)
824
1055
  ];
825
1056
  case 4:
826
- error = _state.sent();
827
1057
  clearTimeout(timeoutId);
828
- if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
829
- warn("VAST request timed out after ".concat(DEFAULT_TIMEOUT_MS, "ms"));
830
- return [
831
- 2,
832
- []
833
- ];
834
- }
835
- throw error;
1058
+ return [
1059
+ 7
1060
+ ];
836
1061
  case 5:
837
1062
  return [
838
1063
  2
@@ -841,14 +1066,14 @@ function createVastManager() {
841
1066
  });
842
1067
  })();
843
1068
  }
844
- function requestBidsUntilResponse(context) {
1069
+ function fetchVast(durationSeconds) {
845
1070
  return _async_to_generator(function() {
846
1071
  var _loop, lastError, attempt, _ret;
847
1072
  return _ts_generator(this, function(_state) {
848
1073
  switch(_state.label){
849
1074
  case 0:
850
1075
  _loop = function(attempt) {
851
- var bids, err, delay;
1076
+ var ads, error, delay;
852
1077
  return _ts_generator(this, function(_state) {
853
1078
  switch(_state.label){
854
1079
  case 0:
@@ -860,39 +1085,39 @@ function createVastManager() {
860
1085
  ]);
861
1086
  return [
862
1087
  4,
863
- requestBids(context)
1088
+ fetchVastOnce(durationSeconds)
864
1089
  ];
865
1090
  case 1:
866
- bids = _state.sent();
867
- if (bids.length > 0) {
868
- log("requestBidsUntilResponse: got ".concat(bids.length, " ad(s) on attempt ").concat(attempt));
869
- return [
870
- 2,
871
- {
872
- v: bids
873
- }
874
- ];
875
- }
876
- log("requestBidsUntilResponse: no ads on attempt ".concat(attempt, "/").concat(MAX_RETRIES));
1091
+ ads = _state.sent();
1092
+ if (ads.length > 0) return [
1093
+ 2,
1094
+ {
1095
+ v: ads
1096
+ }
1097
+ ];
1098
+ log("No ad returned from VAST on attempt ".concat(attempt, "/").concat(REQUEST_MAX_RETRIES));
877
1099
  return [
878
1100
  3,
879
1101
  3
880
1102
  ];
881
1103
  case 2:
882
- err = _state.sent();
883
- lastError = err;
884
- warn("requestBidsUntilResponse: attempt ".concat(attempt, "/").concat(MAX_RETRIES, " failed:"), err);
1104
+ error = _state.sent();
1105
+ lastError = error;
1106
+ if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
1107
+ console.warn("[AdStormPlayer] VAST request timed out (".concat(REQUEST_TIMEOUT_MS, "ms), attempt ").concat(attempt, "/").concat(REQUEST_MAX_RETRIES));
1108
+ } else {
1109
+ console.warn("[AdStormPlayer] VAST request failed on attempt ".concat(attempt, "/").concat(REQUEST_MAX_RETRIES, ":"), error);
1110
+ }
885
1111
  return [
886
1112
  3,
887
1113
  3
888
1114
  ];
889
1115
  case 3:
890
- if (!(attempt < MAX_RETRIES)) return [
1116
+ if (!(attempt < REQUEST_MAX_RETRIES)) return [
891
1117
  3,
892
1118
  5
893
1119
  ];
894
- delay = RETRY_BACKOFF_MS * attempt;
895
- log("requestBidsUntilResponse: waiting ".concat(delay, "ms before retry"));
1120
+ delay = REQUEST_RETRY_BACKOFF_MS * attempt;
896
1121
  return [
897
1122
  4,
898
1123
  new Promise(function(resolve) {
@@ -909,13 +1134,10 @@ function createVastManager() {
909
1134
  }
910
1135
  });
911
1136
  };
912
- if (!initialized) {
913
- throw new Error("VastManager not initialized. Call initialize() first.");
914
- }
915
1137
  attempt = 1;
916
1138
  _state.label = 1;
917
1139
  case 1:
918
- if (!(attempt <= MAX_RETRIES)) return [
1140
+ if (!(attempt <= REQUEST_MAX_RETRIES)) return [
919
1141
  3,
920
1142
  4
921
1143
  ];
@@ -937,7 +1159,9 @@ function createVastManager() {
937
1159
  1
938
1160
  ];
939
1161
  case 4:
940
- if (_instanceof(lastError, Error)) throw lastError;
1162
+ if (_instanceof(lastError, Error)) {
1163
+ throw lastError;
1164
+ }
941
1165
  return [
942
1166
  2,
943
1167
  []
@@ -946,946 +1170,468 @@ function createVastManager() {
946
1170
  });
947
1171
  })();
948
1172
  }
949
- function destroy() {
950
- initialized = false;
951
- log("Destroyed");
952
- }
953
- return {
954
- initialize: initialize,
955
- requestBids: requestBids,
956
- requestBidsUntilResponse: requestBidsUntilResponse,
957
- destroy: destroy,
958
- get isInitialized () {
959
- return initialized;
960
- }
961
- };
962
- }
963
- // src/sdk/vastAdLayer.ts
964
- var import_hls = __toESM(require("hls.js"), 1);
965
- var LOG = "[VastAdLayer]";
966
- function resolveBidToVastAd(winner, logPrefix) {
967
- if (winner.vastXml) {
968
- var ad = parseVastXml(winner.vastXml, "mp4-first", logPrefix);
969
- return Promise.resolve(ad);
970
- }
971
- if (winner.vastUrl) {
972
- return fetchAndParseVastAd(winner.vastUrl, "mp4-first", logPrefix);
973
- }
974
- return Promise.resolve(null);
975
- }
976
- function createVastAdLayer(contentVideo, options) {
977
- var _ref, _ref1, _ref2, _ref3, _ref4;
978
- var adPlaying = false;
979
- var originalMutedState = false;
980
- var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
981
- var listeners = /* @__PURE__ */ new Map();
982
- var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
983
- var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
984
- var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
985
- var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
986
- var forceMP4Ads = (_ref3 = options === null || options === void 0 ? void 0 : options.forceMP4Ads) !== null && _ref3 !== void 0 ? _ref3 : smartTVMode || singleElementMode;
987
- var debug = (_ref4 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref4 !== void 0 ? _ref4 : false;
988
- var adVideoElement;
989
- var adHls;
990
- var adContainerEl;
991
- var currentAd;
992
- var sessionId;
993
- var destroyed = false;
994
- var tornDown = false;
995
- var trackingFired = createEmptyTrackingState();
996
- var adStallTimerId;
997
- var currentAdEventHandlers;
998
- var preloadSlots = /* @__PURE__ */ new Map();
999
- function emit(event, payload) {
1000
- var set = listeners.get(event);
1001
- if (!set) return;
1002
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1003
- try {
1004
- for(var _iterator = Array.from(set)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1005
- var fn = _step.value;
1006
- try {
1007
- fn(payload);
1008
- } catch (error) {
1009
- console.warn("".concat(LOG, " Error in event listener for ").concat(event, ":"), error);
1010
- }
1011
- }
1012
- } catch (err) {
1013
- _didIteratorError = true;
1014
- _iteratorError = err;
1015
- } finally{
1016
- try {
1017
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1018
- _iterator.return();
1019
- }
1020
- } finally{
1021
- if (_didIteratorError) {
1022
- throw _iteratorError;
1023
- }
1024
- }
1025
- }
1026
- }
1027
- function generateSessionId() {
1028
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
1029
- }
1030
- function fireTrackingPixels2(urls) {
1031
- fireTrackingPixels(urls, sessionId, LOG);
1032
- }
1033
- function getMainStreamQuality() {
1034
- if (!(mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.levels)) return null;
1035
- var currentLevel = mainHlsInstance.currentLevel;
1036
- if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {
1037
- var autoLevel = mainHlsInstance.loadLevel;
1038
- if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {
1039
- var level2 = mainHlsInstance.levels[autoLevel];
1040
- return {
1041
- width: level2.width || 1920,
1042
- height: level2.height || 1080,
1043
- bitrate: level2.bitrate || 5e6
1044
- };
1045
- }
1046
- return null;
1047
- }
1048
- var level = mainHlsInstance.levels[currentLevel];
1049
- return {
1050
- width: level.width || 1920,
1051
- height: level.height || 1080,
1052
- bitrate: level.bitrate || 5e6
1053
- };
1054
- }
1055
- function selectBestMediaFile(mediaFiles) {
1056
- var _ref;
1057
- var _scoredFiles_;
1058
- if (mediaFiles.length === 0) throw new Error("No media files available");
1059
- var candidates = mediaFiles;
1060
- if (forceMP4Ads) {
1061
- var mp4Only = candidates.filter(function(f) {
1062
- return !isHlsMediaFile(f);
1063
- });
1064
- if (mp4Only.length > 0) {
1065
- candidates = mp4Only;
1066
- if (debug) console.log("".concat(LOG, " forceMP4Ads: filtered to ").concat(mp4Only.length, " MP4-only file(s)"));
1067
- } else if (debug) {
1068
- console.warn("".concat(LOG, " forceMP4Ads: no MP4 files available, falling back to all media files"));
1069
- }
1070
- } else {
1071
- var mp4Only1 = candidates.filter(function(f) {
1072
- return !isHlsMediaFile(f);
1073
- });
1074
- if (mp4Only1.length > 0) {
1075
- candidates = mp4Only1;
1076
- if (debug) console.log("".concat(LOG, " Preferring ").concat(mp4Only1.length, " MP4 file(s) over HLS (mp4-first)"));
1077
- }
1173
+ function getDurationSecondsFromContext(requestContext) {
1174
+ var _ctx_remainingBreakSec;
1175
+ if (!requestContext || (typeof requestContext === "undefined" ? "undefined" : _type_of(requestContext)) !== "object") {
1176
+ return 30;
1078
1177
  }
1079
- var firstFile = candidates[0];
1080
- if (candidates.length === 1) return firstFile;
1081
- var mainQuality = getMainStreamQuality();
1082
- if (!mainQuality) {
1083
- if (debug) console.log("".concat(LOG, " No main stream quality info, using first media file"));
1084
- return firstFile;
1178
+ var ctx = requestContext;
1179
+ var value = (_ctx_remainingBreakSec = ctx.remainingBreakSec) !== null && _ctx_remainingBreakSec !== void 0 ? _ctx_remainingBreakSec : ctx.breakDurationSec;
1180
+ if (typeof value !== "number" || Number.isNaN(value)) {
1181
+ return 30;
1085
1182
  }
1086
- var scoredFiles = candidates.map(function(file) {
1087
- var widthDiff = Math.abs(file.width - mainQuality.width);
1088
- var heightDiff = Math.abs(file.height - mainQuality.height);
1089
- var resolutionDiff = widthDiff + heightDiff;
1090
- var fileBitrate = (file.bitrate || 5e3) * 1e3;
1091
- var bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);
1092
- var score = resolutionDiff * 2 + bitrateDiff / 1e3;
1093
- return {
1094
- file: file,
1095
- score: score
1096
- };
1097
- });
1098
- scoredFiles.sort(function(a, b) {
1099
- return a.score - b.score;
1100
- });
1101
- return (_ref = (_scoredFiles_ = scoredFiles[0]) === null || _scoredFiles_ === void 0 ? void 0 : _scoredFiles_.file) !== null && _ref !== void 0 ? _ref : firstFile;
1183
+ return Math.max(1, Math.ceil(value));
1102
1184
  }
1103
- function isHlsMediaFile(file) {
1104
- return file.type === "application/x-mpegURL" || file.type.includes("m3u8");
1105
- }
1106
- function createAdVideoElement() {
1107
- var video = document.createElement("video");
1108
- video.style.position = "absolute";
1109
- video.style.left = "0";
1110
- video.style.top = "0";
1111
- video.style.width = "100%";
1112
- video.style.height = "100%";
1113
- video.style.objectFit = "contain";
1114
- video.style.backgroundColor = "#000";
1115
- video.playsInline = true;
1116
- video.muted = false;
1117
- video.volume = 1;
1118
- return video;
1119
- }
1120
- function clearAdStallTimer() {
1121
- if (adStallTimerId != null) {
1122
- clearTimeout(adStallTimerId);
1123
- adStallTimerId = void 0;
1124
- }
1125
- }
1126
- function removeAdEventListeners() {
1127
- clearAdStallTimer();
1128
- if (!currentAdEventHandlers || !adVideoElement) return;
1129
- var el = adVideoElement;
1130
- el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1131
- el.removeEventListener("playing", currentAdEventHandlers.playing);
1132
- el.removeEventListener("ended", currentAdEventHandlers.ended);
1133
- el.removeEventListener("error", currentAdEventHandlers.error);
1134
- el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1135
- el.removeEventListener("pause", currentAdEventHandlers.pause);
1136
- el.removeEventListener("play", currentAdEventHandlers.play);
1137
- el.removeEventListener("waiting", currentAdEventHandlers.waiting);
1138
- currentAdEventHandlers = void 0;
1139
- }
1140
- function setupAdEventListeners() {
1141
- if (!adVideoElement) return;
1142
- removeAdEventListeners();
1143
- var handlers = {
1144
- timeupdate: function timeupdate() {
1145
- var ad = currentAd;
1146
- if (!ad || !adVideoElement) return;
1147
- var progress = adVideoElement.currentTime / ad.duration;
1148
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1149
- trackingFired.firstQuartile = true;
1150
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1151
- }
1152
- if (progress >= 0.5 && !trackingFired.midpoint) {
1153
- trackingFired.midpoint = true;
1154
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1155
- }
1156
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1157
- trackingFired.thirdQuartile = true;
1158
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1159
- }
1160
- },
1161
- playing: function playing() {
1162
- clearAdStallTimer();
1163
- var ad = currentAd;
1164
- if (!ad || trackingFired.start) return;
1165
- trackingFired.start = true;
1166
- fireTrackingPixels2(ad.trackingUrls.start);
1167
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1168
- },
1169
- ended: function ended() {
1170
- if (tornDown || !currentAd || trackingFired.complete) return;
1171
- trackingFired.complete = true;
1172
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1173
- if (debug) console.log("".concat(LOG, " Ad completed"));
1174
- handleAdComplete();
1175
- },
1176
- error: function error(e) {
1177
- if (tornDown) return;
1178
- console.error("".concat(LOG, " Ad video error:"), e);
1179
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1180
- handleAdError();
1181
- },
1182
- volumechange: function volumechange() {
1183
- if (!currentAd || !adVideoElement) return;
1184
- if (adVideoElement.muted) {
1185
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1186
- } else {
1187
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1188
- }
1189
- },
1190
- pause: function pause() {
1191
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1192
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1193
- }
1194
- },
1195
- play: function play() {
1196
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1197
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1198
- }
1199
- },
1200
- waiting: function waiting() {
1201
- clearAdStallTimer();
1202
- adStallTimerId = setTimeout(function() {
1203
- adStallTimerId = void 0;
1204
- if (adPlaying) {
1205
- if (debug) console.warn("".concat(LOG, " Ad video stalled for too long, treating as error"));
1206
- handleAdError();
1207
- }
1208
- }, 8e3);
1209
- }
1210
- };
1211
- adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1212
- adVideoElement.addEventListener("playing", handlers.playing);
1213
- adVideoElement.addEventListener("ended", handlers.ended);
1214
- adVideoElement.addEventListener("error", handlers.error);
1215
- adVideoElement.addEventListener("volumechange", handlers.volumechange);
1216
- adVideoElement.addEventListener("pause", handlers.pause);
1217
- adVideoElement.addEventListener("play", handlers.play);
1218
- adVideoElement.addEventListener("waiting", handlers.waiting);
1219
- currentAdEventHandlers = handlers;
1220
- }
1221
- function setAdPlayingFlag(isPlaying) {
1222
- if (isPlaying) {
1223
- contentVideo.dataset.stormcloudAdPlaying = "true";
1224
- } else {
1225
- delete contentVideo.dataset.stormcloudAdPlaying;
1226
- }
1227
- }
1228
- function handleAdComplete() {
1229
- if (tornDown) return;
1230
- clearAdStallTimer();
1231
- if (debug) console.log("".concat(LOG, " Handling ad completion"));
1232
- adPlaying = false;
1233
- setAdPlayingFlag(false);
1234
- if (adContainerEl) {
1235
- adContainerEl.style.display = "none";
1236
- adContainerEl.style.pointerEvents = "none";
1237
- }
1238
- emit("ad_impression");
1239
- emit("content_resume");
1240
- }
1241
- function handleAdError() {
1242
- if (tornDown) return;
1243
- if (!adPlaying) return;
1244
- clearAdStallTimer();
1245
- if (debug) console.log("".concat(LOG, " Handling ad error"));
1246
- adPlaying = false;
1247
- setAdPlayingFlag(false);
1248
- if (adContainerEl) {
1249
- adContainerEl.style.display = "none";
1250
- adContainerEl.style.pointerEvents = "none";
1251
- }
1252
- emit("ad_error");
1253
- }
1254
- function teardownCurrentPlayback() {
1255
- removeAdEventListeners();
1256
- if (adHls) {
1257
- adHls.destroy();
1258
- adHls = void 0;
1259
- }
1260
- if (adVideoElement) {
1261
- if (singleElementMode && adVideoElement === contentVideo) {
1262
- contentVideo.pause();
1263
- } else {
1264
- adVideoElement.pause();
1265
- adVideoElement.removeAttribute("src");
1266
- adVideoElement.load();
1267
- }
1268
- }
1269
- }
1270
- function startNativePlayback(mediaFile) {
1271
- if (!adVideoElement) return;
1272
- if (debug) console.log("".concat(LOG, " Starting native MP4 playback: ").concat(mediaFile.url));
1273
- adVideoElement.src = mediaFile.url;
1274
- adVideoElement.load();
1275
- adVideoElement.play().catch(function(error) {
1276
- console.error("".concat(LOG, " Error starting native ad playback:"), error);
1277
- handleAdError();
1278
- });
1279
- }
1280
- function startHlsPlayback(mediaFile) {
1281
- if (!adVideoElement) return;
1282
- if (debug) console.log("".concat(LOG, " Starting HLS playback: ").concat(mediaFile.url));
1283
- if (import_hls.default.isSupported()) {
1284
- if (adHls) {
1285
- adHls.destroy();
1286
- adHls = void 0;
1287
- }
1288
- adHls = new import_hls.default({
1289
- enableWorker: true,
1290
- lowLatencyMode: false
1291
- });
1292
- adHls.loadSource(mediaFile.url);
1293
- adHls.attachMedia(adVideoElement);
1294
- adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1295
- if (!adPlaying) return;
1296
- adVideoElement.play().catch(function(error) {
1297
- console.error("".concat(LOG, " Error starting HLS ad playback:"), error);
1298
- handleAdError();
1299
- });
1300
- });
1301
- var nonFatalNetworkErrors = 0;
1302
- adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1303
- if (data.fatal) {
1304
- handleAdError();
1305
- } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1306
- nonFatalNetworkErrors++;
1307
- if (nonFatalNetworkErrors >= 3) {
1308
- if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1309
- handleAdError();
1310
- }
1311
- }
1312
- });
1313
- } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1314
- adVideoElement.src = mediaFile.url;
1315
- adVideoElement.play().catch(function(error) {
1316
- console.error("".concat(LOG, " Error starting native HLS ad playback:"), error);
1317
- handleAdError();
1318
- });
1319
- } else {
1320
- console.error("".concat(LOG, " HLS not supported on this platform"));
1321
- handleAdError();
1322
- }
1323
- }
1324
- function startPlayback(mediaFile) {
1325
- if (!adVideoElement) return;
1326
- if (singleElementMode && isHlsMediaFile(mediaFile)) {
1327
- var mp4Fallback = currentAd === null || currentAd === void 0 ? void 0 : currentAd.mediaFiles.find(function(f) {
1328
- return !isHlsMediaFile(f);
1329
- });
1330
- if (mp4Fallback) {
1331
- if (debug) console.log("".concat(LOG, " singleElementMode: HLS ad blocked, using MP4 fallback"));
1332
- startNativePlayback(mp4Fallback);
1333
- return;
1334
- }
1335
- }
1336
- if (isHlsMediaFile(mediaFile)) {
1337
- startHlsPlayback(mediaFile);
1338
- } else {
1339
- startNativePlayback(mediaFile);
1340
- }
1341
- }
1342
- function playAd(bids) {
1185
+ function requestAdFromApi(requestContext) {
1343
1186
  return _async_to_generator(function() {
1344
- var winner, ad, contentVolume, adVolume2, mediaFile2, _contentVideo_parentElement, container, adVolume, mediaFile;
1187
+ var durationSeconds, ads;
1345
1188
  return _ts_generator(this, function(_state) {
1346
1189
  switch(_state.label){
1347
1190
  case 0:
1348
- if (destroyed) {
1349
- return [
1350
- 2,
1351
- Promise.reject(new Error("Layer has been destroyed"))
1352
- ];
1353
- }
1354
- if (bids.length === 0) {
1355
- return [
1356
- 2,
1357
- Promise.reject(new Error("No bids provided"))
1358
- ];
1359
- }
1360
- winner = bids[0];
1361
- if (debug) {
1362
- console.log("".concat(LOG, " Winning bid: ").concat(winner.bidder, " $").concat(winner.cpm.toFixed(2), " ").concat(winner.currency));
1363
- }
1191
+ durationSeconds = getDurationSecondsFromContext(requestContext);
1364
1192
  return [
1365
1193
  4,
1366
- resolveBidToVastAd(winner, LOG)
1194
+ fetchVast(durationSeconds)
1367
1195
  ];
1368
1196
  case 1:
1369
- ad = _state.sent();
1370
- if (!ad) {
1371
- if (debug) console.warn("".concat(LOG, " Winning bid has no VAST URL or XML"));
1372
- emit("ad_error");
1373
- return [
1374
- 2,
1375
- Promise.reject(new Error("No VAST from bid"))
1376
- ];
1377
- }
1378
- if (debug) {
1379
- console.log("".concat(LOG, " Ad parsed: ").concat(ad.title, ", duration: ").concat(ad.duration, "s, mediaFiles: ").concat(ad.mediaFiles.length));
1380
- }
1381
- sessionId = generateSessionId();
1382
- currentAd = ad;
1383
- trackingFired = _object_spread({}, createEmptyTrackingState());
1384
- fireTrackingPixels2(ad.trackingUrls.impression);
1385
- trackingFired.impression = true;
1386
- contentVolume = contentVideo.volume;
1387
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1388
- if (!singleElementMode) return [
1389
- 3,
1390
- 3
1391
- ];
1392
- mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1393
- teardownCurrentPlayback();
1394
- adVideoElement = contentVideo;
1395
- adHls = void 0;
1396
- adPlaying = true;
1397
- setAdPlayingFlag(true);
1398
- contentVideo.removeAttribute("src");
1399
- contentVideo.load();
1400
- if (!continueLiveStreamDuringAds) {
1401
- contentVideo.pause();
1402
- }
1403
- contentVideo.muted = true;
1404
- contentVideo.volume = 0;
1197
+ ads = _state.sent();
1405
1198
  return [
1406
- 4,
1407
- new Promise(function(resolve) {
1408
- return setTimeout(resolve, 200);
1409
- })
1410
- ];
1411
- case 2:
1412
- _state.sent();
1413
- if (destroyed || tornDown) return [
1414
- 2
1415
- ];
1416
- contentVideo.style.visibility = "visible";
1417
- contentVideo.style.opacity = "1";
1418
- emit("content_pause");
1419
- setupAdEventListeners();
1420
- adVolume2 = originalMutedState ? 1 : originalVolume;
1421
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume2));
1422
- adVideoElement.muted = false;
1423
- mediaFile2 = selectBestMediaFile(ad.mediaFiles);
1424
- if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile2.url));
1425
- startPlayback(mediaFile2);
1426
- return [
1427
- 2
1428
- ];
1429
- case 3:
1430
- if (!adContainerEl) {
1431
- ;
1432
- container = document.createElement("div");
1433
- container.style.position = "absolute";
1434
- container.style.left = "0";
1435
- container.style.top = "0";
1436
- container.style.right = "0";
1437
- container.style.bottom = "0";
1438
- container.style.display = "none";
1439
- container.style.alignItems = "center";
1440
- container.style.justifyContent = "center";
1441
- container.style.pointerEvents = "none";
1442
- container.style.zIndex = "10";
1443
- container.style.backgroundColor = "#000";
1444
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1445
- adContainerEl = container;
1446
- }
1447
- if (!adVideoElement) {
1448
- adVideoElement = createAdVideoElement();
1449
- adContainerEl.appendChild(adVideoElement);
1450
- setupAdEventListeners();
1451
- } else {
1452
- teardownCurrentPlayback();
1453
- }
1454
- if (!continueLiveStreamDuringAds) {
1455
- contentVideo.pause();
1456
- }
1457
- contentVideo.muted = true;
1458
- contentVideo.volume = 0;
1459
- adPlaying = true;
1460
- setAdPlayingFlag(true);
1461
- adVolume = originalMutedState ? 1 : originalVolume;
1462
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1463
- adVideoElement.muted = false;
1464
- if (adContainerEl) {
1465
- adContainerEl.style.display = "flex";
1466
- adContainerEl.style.pointerEvents = "auto";
1467
- }
1468
- emit("content_pause");
1469
- mediaFile = selectBestMediaFile(ad.mediaFiles);
1470
- if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile.url));
1471
- startPlayback(mediaFile);
1472
- return [
1473
- 2
1199
+ 2,
1200
+ ads[0] || null
1474
1201
  ];
1475
1202
  }
1476
1203
  });
1477
1204
  })();
1478
1205
  }
1479
- function ensureAdContainer() {
1480
- if (!adContainerEl) {
1481
- var _contentVideo_parentElement;
1482
- var container = document.createElement("div");
1483
- container.style.position = "absolute";
1484
- container.style.left = "0";
1485
- container.style.top = "0";
1486
- container.style.right = "0";
1487
- container.style.bottom = "0";
1488
- container.style.display = "none";
1489
- container.style.alignItems = "center";
1490
- container.style.justifyContent = "center";
1491
- container.style.pointerEvents = "none";
1492
- container.style.zIndex = "10";
1493
- container.style.backgroundColor = "#000";
1494
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1495
- adContainerEl = container;
1496
- }
1497
- return adContainerEl;
1206
+ function assignCurrentAd(ad) {
1207
+ currentAd = ad;
1208
+ sessionId = generateSessionId();
1209
+ trackingFired = {
1210
+ impression: false,
1211
+ start: false,
1212
+ firstQuartile: false,
1213
+ midpoint: false,
1214
+ thirdQuartile: false,
1215
+ complete: false
1216
+ };
1217
+ fireTrackingPixels2(currentAd.trackingUrls.impression);
1218
+ trackingFired.impression = true;
1219
+ emit("ad_impression");
1498
1220
  }
1499
- function preloadAd(bids, token) {
1500
- return _async_to_generator(function() {
1501
- var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1502
- return _ts_generator(this, function(_state) {
1503
- switch(_state.label){
1504
- case 0:
1505
- if (destroyed) return [
1506
- 2
1507
- ];
1508
- winner = bids[0];
1509
- if (!winner) return [
1510
- 2
1511
- ];
1512
- if (debug) console.log("".concat(LOG, " [preload] Resolving VAST for token=").concat(token));
1513
- return [
1514
- 4,
1515
- resolveBidToVastAd(winner, LOG)
1516
- ];
1517
- case 1:
1518
- ad = _state.sent();
1519
- if (!ad || destroyed) return [
1520
- 2
1521
- ];
1522
- mediaFile = selectBestMediaFile(ad.mediaFiles);
1523
- if (!mediaFile) return [
1524
- 2
1525
- ];
1526
- if (smartTVMode || singleElementMode) {
1527
- slot = {
1528
- bids: bids,
1529
- ad: ad,
1530
- mediaFile: mediaFile,
1531
- videoEl: null,
1532
- ready: true
1533
- };
1534
- preloadSlots.set(token, slot);
1535
- if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1536
- return [
1537
- 2
1538
- ];
1539
- }
1540
- videoEl = createAdVideoElement();
1541
- videoEl.style.visibility = "hidden";
1542
- videoEl.style.pointerEvents = "none";
1543
- videoEl.preload = "auto";
1544
- container = ensureAdContainer();
1545
- container.appendChild(videoEl);
1546
- if (isHlsMediaFile(mediaFile) && import_hls.default.isSupported()) {
1547
- hls = new import_hls.default({
1548
- enableWorker: true,
1549
- lowLatencyMode: false
1550
- });
1551
- hls.loadSource(mediaFile.url);
1552
- hls.attachMedia(videoEl);
1553
- slot1 = {
1554
- bids: bids,
1555
- ad: ad,
1556
- mediaFile: mediaFile,
1557
- videoEl: videoEl,
1558
- hlsInstance: hls,
1559
- ready: false
1560
- };
1561
- preloadSlots.set(token, slot1);
1562
- hls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1563
- var s = preloadSlots.get(token);
1564
- if (s) s.ready = true;
1565
- if (debug) console.log("".concat(LOG, " [preload] HLS manifest parsed, token=").concat(token));
1566
- });
1567
- hls.on(import_hls.default.Events.ERROR, function(_evt, data) {
1568
- if (!preloadSlots.has(token)) return;
1569
- if (data.fatal) {
1570
- if (debug) console.warn("".concat(LOG, " [preload] HLS error for token=").concat(token));
1571
- preloadSlots.delete(token);
1572
- hls.destroy();
1573
- videoEl.remove();
1574
- }
1575
- });
1576
- } else {
1577
- videoEl.src = mediaFile.url;
1578
- videoEl.load();
1579
- slot2 = {
1580
- bids: bids,
1581
- ad: ad,
1582
- mediaFile: mediaFile,
1583
- videoEl: videoEl,
1584
- ready: false
1585
- };
1586
- preloadSlots.set(token, slot2);
1587
- videoEl.addEventListener("canplay", function() {
1588
- var s = preloadSlots.get(token);
1589
- if (s) s.ready = true;
1590
- if (debug) console.log("".concat(LOG, " [preload] canplay fired, token=").concat(token));
1591
- }, {
1592
- once: true
1593
- });
1594
- }
1595
- if (debug) console.log("".concat(LOG, " [preload] Started buffering token=").concat(token, ", url=").concat(mediaFile.url));
1596
- return [
1597
- 2
1598
- ];
1221
+ return {
1222
+ initialize: function initialize() {
1223
+ log("Initializing");
1224
+ if (!adContainerEl) {
1225
+ var _contentVideo_parentElement;
1226
+ var parent = contentVideo.parentElement;
1227
+ if (parent) {
1228
+ var computed = window.getComputedStyle(parent).position;
1229
+ if (computed === "static") {
1230
+ parent.style.position = "relative";
1231
+ parentPositionOverridden = true;
1232
+ }
1599
1233
  }
1600
- });
1601
- })();
1602
- }
1603
- function playPreloaded(token) {
1604
- return _async_to_generator(function() {
1605
- var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, nonFatalNetworkErrors, adVolume, container;
1606
- return _ts_generator(this, function(_state) {
1607
- switch(_state.label){
1608
- case 0:
1609
- if (destroyed) return [
1610
- 2,
1611
- Promise.reject(new Error("Layer has been destroyed"))
1612
- ];
1613
- slot = preloadSlots.get(token);
1614
- if (!slot) {
1615
- if (debug) console.warn("".concat(LOG, " [preload] No slot found for token=").concat(token, ", nothing to play"));
1234
+ var container = document.createElement("div");
1235
+ container.style.position = "absolute";
1236
+ container.style.left = "0";
1237
+ container.style.top = "0";
1238
+ container.style.right = "0";
1239
+ container.style.bottom = "0";
1240
+ container.style.display = "none";
1241
+ container.style.alignItems = "center";
1242
+ container.style.justifyContent = "center";
1243
+ container.style.pointerEvents = "none";
1244
+ container.style.zIndex = AD_LAYER_Z_INDEX;
1245
+ container.style.backgroundColor = "#000";
1246
+ container.style.transition = "opacity 0.3s ease-in-out";
1247
+ container.style.opacity = "0";
1248
+ container.style.isolation = "isolate";
1249
+ var countdown = document.createElement("div");
1250
+ countdown.style.position = "absolute";
1251
+ countdown.style.left = "12px";
1252
+ countdown.style.top = "12px";
1253
+ countdown.style.padding = "4px 8px";
1254
+ countdown.style.borderRadius = "4px";
1255
+ countdown.style.background = "rgba(0,0,0,0.75)";
1256
+ countdown.style.color = "#fff";
1257
+ countdown.style.fontFamily = "sans-serif";
1258
+ countdown.style.fontSize = "12px";
1259
+ countdown.style.lineHeight = "1.2";
1260
+ countdown.style.pointerEvents = "none";
1261
+ countdown.style.zIndex = COUNTDOWN_Z_INDEX;
1262
+ countdown.textContent = "Ad";
1263
+ container.appendChild(countdown);
1264
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1265
+ adContainerEl = container;
1266
+ adCountdownEl = countdown;
1267
+ }
1268
+ },
1269
+ requestAds: function requestAds(duration) {
1270
+ return _async_to_generator(function() {
1271
+ var durationSeconds, parsed, ads, error;
1272
+ return _ts_generator(this, function(_state) {
1273
+ switch(_state.label){
1274
+ case 0:
1275
+ log("Requesting ads for duration:", duration);
1276
+ if (adPlaying) {
1277
+ return [
1278
+ 2,
1279
+ Promise.reject(new Error("Ad already playing"))
1280
+ ];
1281
+ }
1282
+ if (destroyed) {
1283
+ return [
1284
+ 2,
1285
+ Promise.reject(new Error("Player has been destroyed"))
1286
+ ];
1287
+ }
1288
+ _state.label = 1;
1289
+ case 1:
1290
+ _state.trys.push([
1291
+ 1,
1292
+ 3,
1293
+ ,
1294
+ 4
1295
+ ]);
1296
+ tornDown = false;
1297
+ durationSeconds = 30;
1298
+ parsed = parseInt(duration || "", 10);
1299
+ if (!isNaN(parsed) && parsed > 0) {
1300
+ durationSeconds = parsed;
1301
+ }
1616
1302
  return [
1617
- 2
1303
+ 4,
1304
+ fetchVast(durationSeconds)
1618
1305
  ];
1619
- }
1620
- preloadSlots.delete(token);
1621
- if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1622
- contentVolume = contentVideo.volume;
1623
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1624
- sessionId = generateSessionId();
1625
- currentAd = slot.ad;
1626
- trackingFired = _object_spread({}, createEmptyTrackingState());
1627
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1628
- trackingFired.impression = true;
1629
- if (!singleElementMode) return [
1630
- 3,
1631
- 2
1632
- ];
1633
- mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1634
- teardownCurrentPlayback();
1635
- adVideoElement = contentVideo;
1636
- adHls = void 0;
1637
- adPlaying = true;
1638
- setAdPlayingFlag(true);
1639
- contentVideo.removeAttribute("src");
1640
- contentVideo.load();
1641
- contentVideo.muted = true;
1642
- contentVideo.volume = 0;
1643
- return [
1644
- 4,
1645
- new Promise(function(resolve) {
1646
- return setTimeout(resolve, 200);
1647
- })
1648
- ];
1649
- case 1:
1650
- _state.sent();
1651
- if (destroyed || tornDown) return [
1652
- 2
1653
- ];
1654
- contentVideo.style.visibility = "visible";
1655
- contentVideo.style.opacity = "1";
1656
- emit("content_pause");
1657
- setupAdEventListeners();
1658
- adVolume2 = originalMutedState ? 1 : originalVolume;
1659
- contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1660
- contentVideo.muted = false;
1661
- if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1662
- startPlayback(slot.mediaFile);
1663
- return [
1664
- 2
1665
- ];
1666
- case 2:
1667
- if (smartTVMode && !slot.videoEl) {
1668
- teardownCurrentPlayback();
1669
- if (adVideoElement) {
1670
- adVideoElement.remove();
1671
- adVideoElement = void 0;
1306
+ case 2:
1307
+ ads = _state.sent();
1308
+ if (ads.length === 0) {
1309
+ log("No ads available from VAST response");
1310
+ emit("ad_error");
1311
+ return [
1312
+ 2,
1313
+ Promise.resolve()
1314
+ ];
1315
+ }
1316
+ assignCurrentAd(ads[0]);
1317
+ log("Ad loaded: ".concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1318
+ return [
1319
+ 2,
1320
+ Promise.resolve()
1321
+ ];
1322
+ case 3:
1323
+ error = _state.sent();
1324
+ console.error("[AdStormPlayer] Error requesting ads:", error);
1325
+ emit("ad_error");
1326
+ return [
1327
+ 2,
1328
+ Promise.reject(error)
1329
+ ];
1330
+ case 4:
1331
+ return [
1332
+ 2
1333
+ ];
1334
+ }
1335
+ });
1336
+ })();
1337
+ },
1338
+ play: function play() {
1339
+ return _async_to_generator(function() {
1340
+ var mediaFile, error;
1341
+ return _ts_generator(this, function(_state) {
1342
+ switch(_state.label){
1343
+ case 0:
1344
+ if (!currentAd) {
1345
+ return [
1346
+ 2,
1347
+ Promise.reject(new Error("No ad loaded"))
1348
+ ];
1349
+ }
1350
+ if (destroyed) {
1351
+ return [
1352
+ 2,
1353
+ Promise.reject(new Error("Player has been destroyed"))
1354
+ ];
1355
+ }
1356
+ log("Starting ad playback");
1357
+ _state.label = 1;
1358
+ case 1:
1359
+ _state.trys.push([
1360
+ 1,
1361
+ 3,
1362
+ ,
1363
+ 4
1364
+ ]);
1365
+ tornDown = false;
1366
+ if (adHideTimerId) {
1367
+ clearTimeout(adHideTimerId);
1368
+ adHideTimerId = void 0;
1369
+ }
1370
+ if (!adVideoElement) {
1371
+ adVideoElement = createAdVideoElement();
1372
+ adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1373
+ } else {
1374
+ teardownCurrentPlayback();
1672
1375
  }
1673
- videoEl = createAdVideoElement();
1674
- videoEl.style.visibility = "visible";
1675
- videoEl.style.pointerEvents = "none";
1676
- container2 = ensureAdContainer();
1677
- container2.appendChild(videoEl);
1678
- adVideoElement = videoEl;
1679
1376
  setupAdEventListeners();
1377
+ trackingFired = {
1378
+ impression: trackingFired.impression,
1379
+ start: false,
1380
+ firstQuartile: false,
1381
+ midpoint: false,
1382
+ thirdQuartile: false,
1383
+ complete: false
1384
+ };
1385
+ contentVideo.style.transition = "opacity 0.3s ease-in-out";
1386
+ contentVideo.style.opacity = "0";
1387
+ setTimeout(function() {
1388
+ contentVideo.style.visibility = "hidden";
1389
+ }, 300);
1390
+ contentVideo.muted = true;
1391
+ contentVideo.volume = 0;
1680
1392
  if (!continueLiveStreamDuringAds) {
1681
1393
  contentVideo.pause();
1682
1394
  }
1683
- contentVideo.muted = true;
1684
- contentVideo.volume = 0;
1685
1395
  adPlaying = true;
1686
1396
  setAdPlayingFlag(true);
1687
- adVolume21 = originalMutedState ? 1 : originalVolume;
1688
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1689
- adVideoElement.muted = false;
1690
- container2.style.display = "flex";
1691
- container2.style.pointerEvents = "auto";
1397
+ if (adVideoElement) {
1398
+ adVideoElement.volume = originalMutedState ? 0 : originalVolume;
1399
+ adVideoElement.muted = originalMutedState;
1400
+ }
1401
+ if (adContainerEl) {
1402
+ adContainerEl.style.display = "flex";
1403
+ adContainerEl.style.pointerEvents = "auto";
1404
+ adContainerEl.offsetHeight;
1405
+ adContainerEl.style.opacity = "1";
1406
+ }
1692
1407
  emit("content_pause");
1693
- if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1694
- startPlayback(slot.mediaFile);
1408
+ mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1409
+ if (!mediaFile) {
1410
+ throw new Error("No media file available");
1411
+ }
1412
+ log("Playing media file:", mediaFile.url);
1413
+ adVideoElement.src = mediaFile.url;
1414
+ adVideoElement.load();
1695
1415
  return [
1696
- 2
1416
+ 4,
1417
+ adVideoElement.play()
1697
1418
  ];
1698
- }
1699
- teardownCurrentPlayback();
1700
- if (adVideoElement && adVideoElement !== slot.videoEl) {
1701
- adVideoElement.remove();
1702
- }
1703
- slot.videoEl.style.visibility = "visible";
1704
- slot.videoEl.style.pointerEvents = "none";
1705
- adVideoElement = slot.videoEl;
1706
- adHls = slot.hlsInstance;
1707
- if (adHls) {
1708
- nonFatalNetworkErrors = 0;
1709
- adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1710
- if (!adPlaying) return;
1711
- if (data.fatal) {
1712
- handleAdError();
1713
- } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1714
- nonFatalNetworkErrors++;
1715
- if (nonFatalNetworkErrors >= 3) {
1716
- if (debug) console.warn("".concat(LOG, " [preload] Too many non-fatal HLS network errors during playback, treating as fatal"));
1717
- handleAdError();
1718
- }
1719
- }
1720
- });
1721
- }
1722
- setupAdEventListeners();
1723
- if (!continueLiveStreamDuringAds) {
1724
- contentVideo.pause();
1725
- }
1726
- contentVideo.muted = true;
1727
- contentVideo.volume = 0;
1728
- adPlaying = true;
1729
- setAdPlayingFlag(true);
1730
- adVolume = originalMutedState ? 1 : originalVolume;
1731
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1732
- adVideoElement.muted = false;
1733
- container = ensureAdContainer();
1734
- container.style.display = "flex";
1735
- container.style.pointerEvents = "auto";
1736
- emit("content_pause");
1737
- adVideoElement.play().catch(function(error) {
1738
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1419
+ case 2:
1420
+ _state.sent();
1421
+ return [
1422
+ 2,
1423
+ Promise.resolve()
1424
+ ];
1425
+ case 3:
1426
+ error = _state.sent();
1427
+ console.error("[AdStormPlayer] Error playing ad:", error);
1739
1428
  handleAdError();
1740
- });
1741
- return [
1742
- 2
1743
- ];
1744
- }
1745
- });
1746
- })();
1747
- }
1748
- function cancelPreload(token) {
1749
- var slot = preloadSlots.get(token);
1750
- if (!slot) return;
1751
- preloadSlots.delete(token);
1752
- if (slot.hlsInstance) {
1753
- slot.hlsInstance.destroy();
1754
- }
1755
- if (slot.videoEl) {
1756
- slot.videoEl.pause();
1757
- slot.videoEl.removeAttribute("src");
1758
- slot.videoEl.load();
1759
- slot.videoEl.remove();
1760
- }
1761
- if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1762
- }
1763
- return {
1764
- initialize: function initialize() {
1765
- if (debug) console.log("".concat(LOG, " Initializing"));
1766
- },
1767
- updateOptions: function updateOptions(opts) {
1768
- if (opts.continueLiveStreamDuringAds !== void 0) {
1769
- continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;
1770
- }
1771
- if (opts.mainHlsInstance !== void 0) {
1772
- var _opts_mainHlsInstance;
1773
- mainHlsInstance = (_opts_mainHlsInstance = opts.mainHlsInstance) !== null && _opts_mainHlsInstance !== void 0 ? _opts_mainHlsInstance : void 0;
1774
- }
1775
- },
1776
- playAd: playAd,
1777
- preloadAd: preloadAd,
1778
- playPreloaded: playPreloaded,
1779
- hasPreloaded: function hasPreloaded(token) {
1780
- return preloadSlots.has(token);
1781
- },
1782
- cancelPreload: cancelPreload,
1783
- pause: function pause() {
1784
- if (!adPlaying || !adVideoElement) return;
1785
- try {
1786
- if (!adVideoElement.paused) adVideoElement.pause();
1787
- } catch (error) {
1788
- if (debug) console.warn("".concat(LOG, " Error pausing ad:"), error);
1789
- }
1790
- },
1791
- resume: function resume() {
1792
- if (!adPlaying || !adVideoElement) return;
1793
- try {
1794
- if (adVideoElement.paused) adVideoElement.play().catch(function() {});
1795
- } catch (error) {
1796
- if (debug) console.warn("".concat(LOG, " Error resuming ad:"), error);
1797
- }
1429
+ return [
1430
+ 2,
1431
+ Promise.reject(error)
1432
+ ];
1433
+ case 4:
1434
+ return [
1435
+ 2
1436
+ ];
1437
+ }
1438
+ });
1439
+ })();
1798
1440
  },
1799
1441
  stop: function stop() {
1800
1442
  return _async_to_generator(function() {
1801
1443
  return _ts_generator(this, function(_state) {
1444
+ log("Stopping ad");
1802
1445
  tornDown = true;
1803
- if (debug) console.log("".concat(LOG, " Stopping ad"));
1804
1446
  adPlaying = false;
1805
1447
  setAdPlayingFlag(false);
1806
- contentVideo.muted = originalMutedState;
1807
- contentVideo.volume = originalMutedState ? 0 : originalVolume;
1448
+ clearAdStallTimer();
1449
+ clearAdCountdownTimer();
1450
+ if (adContainerEl) {
1451
+ adContainerEl.style.opacity = "0";
1452
+ adHideTimerId = setTimeout(function() {
1453
+ if (adContainerEl) {
1454
+ adContainerEl.style.display = "none";
1455
+ adContainerEl.style.pointerEvents = "none";
1456
+ }
1457
+ }, 300);
1458
+ }
1459
+ teardownCurrentPlayback();
1808
1460
  contentVideo.style.visibility = "visible";
1809
1461
  contentVideo.style.opacity = "1";
1810
- if (singleElementMode) {
1811
- teardownCurrentPlayback();
1812
- contentVideo.removeAttribute("src");
1813
- contentVideo.load();
1814
- adVideoElement = void 0;
1815
- } else {
1816
- if (adContainerEl) {
1817
- adContainerEl.style.display = "none";
1818
- adContainerEl.style.pointerEvents = "none";
1819
- }
1820
- if (continueLiveStreamDuringAds) {
1821
- contentVideo.play().catch(function() {});
1822
- }
1823
- teardownCurrentPlayback();
1824
- if (adVideoElement) {
1825
- adVideoElement.pause();
1826
- adVideoElement.removeAttribute("src");
1827
- adVideoElement.load();
1828
- }
1829
- }
1462
+ contentVideo.muted = originalMutedState;
1463
+ contentVideo.volume = originalVolume;
1830
1464
  currentAd = void 0;
1831
1465
  tornDown = false;
1832
1466
  return [
1833
- 2
1467
+ 2,
1468
+ Promise.resolve()
1834
1469
  ];
1835
1470
  });
1836
1471
  })();
1837
1472
  },
1473
+ pause: function pause() {
1474
+ if (!adPlaying || !adVideoElement) return;
1475
+ try {
1476
+ if (!adVideoElement.paused) adVideoElement.pause();
1477
+ } catch (error) {
1478
+ console.warn("[AdStormPlayer] Error pausing ad:", error);
1479
+ }
1480
+ },
1481
+ resume: function resume() {
1482
+ if (!adPlaying || !adVideoElement) return;
1483
+ try {
1484
+ if (adVideoElement.paused) adVideoElement.play().catch(function() {});
1485
+ } catch (error) {
1486
+ console.warn("[AdStormPlayer] Error resuming ad:", error);
1487
+ }
1488
+ },
1838
1489
  destroy: function destroy() {
1839
- tornDown = true;
1840
- if (debug) console.log("".concat(LOG, " Destroying"));
1490
+ log("Destroying");
1841
1491
  destroyed = true;
1492
+ tornDown = true;
1842
1493
  adPlaying = false;
1843
1494
  setAdPlayingFlag(false);
1495
+ clearAdStallTimer();
1496
+ clearAdCountdownTimer();
1497
+ if (adHideTimerId) {
1498
+ clearTimeout(adHideTimerId);
1499
+ adHideTimerId = void 0;
1500
+ }
1844
1501
  contentVideo.muted = originalMutedState;
1845
1502
  contentVideo.volume = originalVolume;
1846
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1847
- try {
1848
- for(var _iterator = Array.from(preloadSlots.entries())[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1849
- var _step_value = _sliced_to_array(_step.value, 1), token = _step_value[0];
1850
- cancelPreload(token);
1851
- }
1852
- } catch (err) {
1853
- _didIteratorError = true;
1854
- _iteratorError = err;
1855
- } finally{
1856
- try {
1857
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1858
- _iterator.return();
1859
- }
1860
- } finally{
1861
- if (_didIteratorError) {
1862
- throw _iteratorError;
1863
- }
1864
- }
1865
- }
1503
+ contentVideo.style.visibility = "visible";
1504
+ contentVideo.style.opacity = "1";
1866
1505
  teardownCurrentPlayback();
1867
- if (adVideoElement) {
1868
- if (singleElementMode && adVideoElement === contentVideo) {
1869
- contentVideo.removeAttribute("src");
1870
- contentVideo.load();
1871
- } else {
1872
- adVideoElement.pause();
1873
- adVideoElement.removeAttribute("src");
1874
- adVideoElement.remove();
1875
- }
1876
- adVideoElement = void 0;
1877
- }
1506
+ adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.remove();
1507
+ adVideoElement = void 0;
1878
1508
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
1879
1509
  adContainerEl.parentElement.removeChild(adContainerEl);
1880
1510
  }
1881
1511
  adContainerEl = void 0;
1512
+ adCountdownEl = void 0;
1882
1513
  currentAd = void 0;
1514
+ sessionId = void 0;
1515
+ preloadSlots.clear();
1883
1516
  listeners.clear();
1517
+ if (parentPositionOverridden && contentVideo.parentElement) {
1518
+ contentVideo.parentElement.style.position = "";
1519
+ parentPositionOverridden = false;
1520
+ }
1521
+ },
1522
+ updateOptions: function updateOptions(opts) {
1523
+ if (opts.continueLiveStreamDuringAds !== void 0) {
1524
+ continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;
1525
+ }
1526
+ },
1527
+ playAd: function playAd(requestContext) {
1528
+ return _async_to_generator(function() {
1529
+ var ad;
1530
+ return _ts_generator(this, function(_state) {
1531
+ switch(_state.label){
1532
+ case 0:
1533
+ if (destroyed) return [
1534
+ 2,
1535
+ Promise.reject(new Error("Player has been destroyed"))
1536
+ ];
1537
+ if (!!currentAd) return [
1538
+ 3,
1539
+ 2
1540
+ ];
1541
+ return [
1542
+ 4,
1543
+ requestAdFromApi(requestContext)
1544
+ ];
1545
+ case 1:
1546
+ ad = _state.sent();
1547
+ if (!ad) {
1548
+ emit("ad_error", {
1549
+ message: "No valid ad from AdStorm API"
1550
+ });
1551
+ return [
1552
+ 2,
1553
+ Promise.reject(new Error("No valid ad from AdStorm API"))
1554
+ ];
1555
+ }
1556
+ assignCurrentAd(ad);
1557
+ _state.label = 2;
1558
+ case 2:
1559
+ return [
1560
+ 2,
1561
+ this.play()
1562
+ ];
1563
+ }
1564
+ });
1565
+ }).call(this);
1566
+ },
1567
+ preloadAd: function preloadAd(arg1, arg2) {
1568
+ return _async_to_generator(function() {
1569
+ var token, requestContext, ad;
1570
+ return _ts_generator(this, function(_state) {
1571
+ switch(_state.label){
1572
+ case 0:
1573
+ if (destroyed) return [
1574
+ 2
1575
+ ];
1576
+ token = typeof arg1 === "string" ? arg1 : typeof arg2 === "string" ? arg2 : void 0;
1577
+ if (!token) return [
1578
+ 2
1579
+ ];
1580
+ requestContext = typeof arg1 === "string" ? arg2 : arg1;
1581
+ return [
1582
+ 4,
1583
+ requestAdFromApi(requestContext)
1584
+ ];
1585
+ case 1:
1586
+ ad = _state.sent();
1587
+ if (!ad) return [
1588
+ 2
1589
+ ];
1590
+ preloadSlots.set(token, {
1591
+ ad: ad
1592
+ });
1593
+ return [
1594
+ 2
1595
+ ];
1596
+ }
1597
+ });
1598
+ })();
1599
+ },
1600
+ playPreloaded: function playPreloaded(token) {
1601
+ return _async_to_generator(function() {
1602
+ var slot;
1603
+ return _ts_generator(this, function(_state) {
1604
+ if (destroyed) return [
1605
+ 2,
1606
+ Promise.reject(new Error("Player has been destroyed"))
1607
+ ];
1608
+ slot = preloadSlots.get(token);
1609
+ if (!slot) {
1610
+ return [
1611
+ 2,
1612
+ Promise.reject(new Error("No preloaded ad for token ".concat(token)))
1613
+ ];
1614
+ }
1615
+ preloadSlots.delete(token);
1616
+ assignCurrentAd(slot.ad);
1617
+ return [
1618
+ 2,
1619
+ this.play()
1620
+ ];
1621
+ });
1622
+ }).call(this);
1623
+ },
1624
+ hasPreloaded: function hasPreloaded(token) {
1625
+ return preloadSlots.has(token);
1626
+ },
1627
+ cancelPreload: function cancelPreload(token) {
1628
+ preloadSlots.delete(token);
1884
1629
  },
1885
1630
  isAdPlaying: function isAdPlaying() {
1886
1631
  return adPlaying;
1887
1632
  },
1888
1633
  resize: function resize(width, height) {
1634
+ log("Resizing to ".concat(width, "x").concat(height));
1889
1635
  if (adContainerEl) {
1890
1636
  adContainerEl.style.width = "".concat(width, "px");
1891
1637
  adContainerEl.style.height = "".concat(height, "px");
@@ -1905,6 +1651,7 @@ function createVastAdLayer(contentVideo, options) {
1905
1651
  },
1906
1652
  updateOriginalMutedState: function updateOriginalMutedState(muted, volume) {
1907
1653
  var nextVolume = typeof volume === "number" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;
1654
+ log("updateOriginalMutedState: muted=".concat(muted, ", volume=").concat(nextVolume));
1908
1655
  originalMutedState = muted;
1909
1656
  originalVolume = nextVolume;
1910
1657
  },
@@ -1917,6 +1664,7 @@ function createVastAdLayer(contentVideo, options) {
1917
1664
  setAdVolume: function setAdVolume(volume) {
1918
1665
  if (adVideoElement && adPlaying) {
1919
1666
  adVideoElement.volume = Math.max(0, Math.min(1, volume));
1667
+ adVideoElement.muted = volume === 0;
1920
1668
  }
1921
1669
  },
1922
1670
  getAdVolume: function getAdVolume() {
@@ -1926,11 +1674,16 @@ function createVastAdLayer(contentVideo, options) {
1926
1674
  return 1;
1927
1675
  },
1928
1676
  showPlaceholder: function showPlaceholder() {
1929
- if (singleElementMode) return;
1930
- contentVideo.style.opacity = "0";
1931
- contentVideo.style.visibility = "hidden";
1932
1677
  if (!adContainerEl) {
1933
1678
  var _contentVideo_parentElement;
1679
+ var parent = contentVideo.parentElement;
1680
+ if (parent) {
1681
+ var computed = window.getComputedStyle(parent).position;
1682
+ if (computed === "static") {
1683
+ parent.style.position = "relative";
1684
+ parentPositionOverridden = true;
1685
+ }
1686
+ }
1934
1687
  var container = document.createElement("div");
1935
1688
  container.style.position = "absolute";
1936
1689
  container.style.left = "0";
@@ -1941,24 +1694,43 @@ function createVastAdLayer(contentVideo, options) {
1941
1694
  container.style.alignItems = "center";
1942
1695
  container.style.justifyContent = "center";
1943
1696
  container.style.pointerEvents = "none";
1944
- container.style.zIndex = "10";
1697
+ container.style.zIndex = AD_LAYER_Z_INDEX;
1945
1698
  container.style.backgroundColor = "#000";
1699
+ container.style.isolation = "isolate";
1700
+ var countdown = document.createElement("div");
1701
+ countdown.style.position = "absolute";
1702
+ countdown.style.left = "12px";
1703
+ countdown.style.top = "12px";
1704
+ countdown.style.padding = "4px 8px";
1705
+ countdown.style.borderRadius = "4px";
1706
+ countdown.style.background = "rgba(0,0,0,0.75)";
1707
+ countdown.style.color = "#fff";
1708
+ countdown.style.fontFamily = "sans-serif";
1709
+ countdown.style.fontSize = "12px";
1710
+ countdown.style.lineHeight = "1.2";
1711
+ countdown.style.pointerEvents = "none";
1712
+ countdown.style.zIndex = COUNTDOWN_Z_INDEX;
1713
+ countdown.textContent = "Ad";
1714
+ container.appendChild(countdown);
1946
1715
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1947
1716
  adContainerEl = container;
1717
+ adCountdownEl = countdown;
1948
1718
  }
1949
1719
  if (adContainerEl) {
1950
1720
  adContainerEl.style.display = "flex";
1721
+ adContainerEl.style.opacity = "1";
1951
1722
  adContainerEl.style.pointerEvents = "auto";
1952
1723
  }
1953
1724
  },
1954
1725
  hidePlaceholder: function hidePlaceholder() {
1955
1726
  if (adContainerEl) {
1956
- adContainerEl.style.display = "none";
1957
- adContainerEl.style.pointerEvents = "none";
1958
- }
1959
- if (!adPlaying) {
1960
- contentVideo.style.visibility = "visible";
1961
- contentVideo.style.opacity = "1";
1727
+ adContainerEl.style.opacity = "0";
1728
+ setTimeout(function() {
1729
+ if (adContainerEl) {
1730
+ adContainerEl.style.display = "none";
1731
+ adContainerEl.style.pointerEvents = "none";
1732
+ }
1733
+ }, 300);
1962
1734
  }
1963
1735
  }
1964
1736
  };
@@ -3023,6 +2795,7 @@ function getBrowserConfigOverrides() {
3023
2795
  return overrides;
3024
2796
  }
3025
2797
  // src/player/StormcloudVideoPlayer.ts
2798
+ var DEBUG_HISTORY_LIMIT = 120;
3026
2799
  var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3027
2800
  function StormcloudVideoPlayer(config) {
3028
2801
  _class_call_check(this, StormcloudVideoPlayer);
@@ -3061,31 +2834,34 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3061
2834
  this.backoffBaseMs = 1e3;
3062
2835
  this.maxBackoffMs = 15e3;
3063
2836
  this.MIN_AD_REMAINING_MS = 15e3;
2837
+ this.adRequestTimeoutMs = 5e3;
2838
+ this.adRequestMaxRetries = 3;
2839
+ this.adRequestRetryBackoffMs = 1500;
3064
2840
  this.preloadedTokens = [];
2841
+ this.debugLogEntries = [];
2842
+ this.scteMarkerHistory = [];
3065
2843
  initializePolyfills();
3066
2844
  var browserOverrides = getBrowserConfigOverrides();
3067
2845
  this.config = _object_spread({}, browserOverrides, config);
3068
2846
  this.video = config.videoElement;
3069
2847
  this.adTransitionGapMs = (_this_config_adTransitionGapMs = this.config.adTransitionGapMs) !== null && _this_config_adTransitionGapMs !== void 0 ? _this_config_adTransitionGapMs : 100;
3070
2848
  logBrowserInfo(config.debugAdTiming);
3071
- this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
3072
- debug: !!config.debugAdTiming
3073
- } : {});
3074
2849
  var browserForAdLayer = detectBrowser();
3075
2850
  var isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;
3076
- this.adLayer = createVastAdLayer(this.video, {
3077
- continueLiveStreamDuringAds: false,
3078
- smartTVMode: isSinglePipeline,
3079
- singleElementMode: isSinglePipeline,
3080
- forceMP4Ads: isSinglePipeline,
2851
+ this.adLayer = createAdStormPlayer(this.video, {
2852
+ licenseKey: this.config.licenseKey || "",
3081
2853
  debug: !!config.debugAdTiming
3082
2854
  });
2855
+ this.adLayer.updateOptions({
2856
+ continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds()
2857
+ });
3083
2858
  }
3084
2859
  _create_class(StormcloudVideoPlayer, [
3085
2860
  {
3086
2861
  key: "adRequest",
3087
2862
  value: function adRequest(context) {
3088
2863
  return _async_to_generator(function() {
2864
+ var _ref, _ref1, durationSeconds;
3089
2865
  return _ts_generator(this, function(_state) {
3090
2866
  switch(_state.label){
3091
2867
  case 0:
@@ -3093,15 +2869,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3093
2869
  2,
3094
2870
  []
3095
2871
  ];
2872
+ 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));
3096
2873
  return [
3097
2874
  4,
3098
- this.vastManager.initialize()
2875
+ this.adLayer.requestAds(String(durationSeconds))
3099
2876
  ];
3100
2877
  case 1:
3101
2878
  _state.sent();
3102
2879
  return [
3103
2880
  2,
3104
- this.vastManager.requestBidsUntilResponse(context)
2881
+ [
2882
+ {
2883
+ bidder: "adstorm-direct",
2884
+ cpm: 0,
2885
+ width: 0,
2886
+ height: 0,
2887
+ adId: "adstorm",
2888
+ impId: "",
2889
+ creativeId: "adstorm",
2890
+ currency: "USD",
2891
+ durationSec: durationSeconds
2892
+ }
2893
+ ]
3105
2894
  ];
3106
2895
  }
3107
2896
  });
@@ -3158,7 +2947,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3158
2947
  2
3159
2948
  ];
3160
2949
  case 3:
3161
- this.hls = new import_hls2.default(_object_spread_props(_object_spread({
2950
+ this.hls = new import_hls.default(_object_spread_props(_object_spread({
3162
2951
  enableWorker: true,
3163
2952
  backBufferLength: 30,
3164
2953
  liveDurationInfinity: true,
@@ -3176,11 +2965,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3176
2965
  nudgeMaxRetry: 3,
3177
2966
  startPosition: -1
3178
2967
  }));
3179
- this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, function() {
2968
+ this.hls.on(import_hls.default.Events.MEDIA_ATTACHED, function() {
3180
2969
  var _this_hls;
3181
2970
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.loadSource(_this.config.src);
3182
2971
  });
3183
- this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
2972
+ this.hls.on(import_hls.default.Events.MANIFEST_PARSED, function(_, data) {
3184
2973
  return _async_to_generator(function() {
3185
2974
  var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, _this_hls1, minSegments, _this_video_play;
3186
2975
  return _ts_generator(this, function(_state) {
@@ -3242,7 +3031,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3242
3031
  });
3243
3032
  }).call(_this);
3244
3033
  });
3245
- this.hls.on(import_hls2.default.Events.LEVEL_LOADED, function(_evt, data) {
3034
+ this.hls.on(import_hls.default.Events.LEVEL_LOADED, function(_evt, data) {
3246
3035
  if (_this.inAdBreak || _this.pendingAdBreak) {
3247
3036
  return;
3248
3037
  }
@@ -3315,7 +3104,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3315
3104
  }
3316
3105
  }
3317
3106
  });
3318
- this.hls.on(import_hls2.default.Events.FRAG_BUFFERED, function(_evt, data) {
3107
+ this.hls.on(import_hls.default.Events.FRAG_BUFFERED, function(_evt, data) {
3319
3108
  return _async_to_generator(function() {
3320
3109
  var _this, _this_config_minSegmentsBeforePlay, minSegments, _this_video_play;
3321
3110
  return _ts_generator(this, function(_state) {
@@ -3375,7 +3164,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3375
3164
  });
3376
3165
  }).call(_this);
3377
3166
  });
3378
- this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3167
+ this.hls.on(import_hls.default.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3379
3168
  var id3Tags = ((data === null || data === void 0 ? void 0 : data.samples) || []).map(function(s) {
3380
3169
  return {
3381
3170
  key: "ID3",
@@ -3387,7 +3176,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3387
3176
  return _this.onId3Tag(tag);
3388
3177
  });
3389
3178
  });
3390
- this.hls.on(import_hls2.default.Events.FRAG_CHANGED, function(_evt, data) {
3179
+ this.hls.on(import_hls.default.Events.FRAG_CHANGED, function(_evt, data) {
3391
3180
  var frag = data === null || data === void 0 ? void 0 : data.frag;
3392
3181
  var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3393
3182
  if (!Array.isArray(tagList)) return;
@@ -3496,14 +3285,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3496
3285
  }
3497
3286
  }
3498
3287
  });
3499
- this.hls.on(import_hls2.default.Events.ERROR, function(_evt, data) {
3288
+ this.hls.on(import_hls.default.Events.ERROR, function(_evt, data) {
3500
3289
  if (data === null || data === void 0 ? void 0 : data.fatal) {
3501
3290
  switch(data.type){
3502
- case import_hls2.default.ErrorTypes.NETWORK_ERROR:
3291
+ case import_hls.default.ErrorTypes.NETWORK_ERROR:
3503
3292
  var _this_hls;
3504
3293
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.startLoad();
3505
3294
  break;
3506
- case import_hls2.default.ErrorTypes.MEDIA_ERROR:
3295
+ case import_hls.default.ErrorTypes.MEDIA_ERROR:
3507
3296
  var _this_hls1;
3508
3297
  (_this_hls1 = _this.hls) === null || _this_hls1 === void 0 ? void 0 : _this_hls1.recoverMediaError();
3509
3298
  break;
@@ -3557,6 +3346,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3557
3346
  errorMessage += ". Caused by: ".concat(causeMessage);
3558
3347
  }
3559
3348
  }
3349
+ _this.pushDebugLog("error", "ad", errorMessage, _object_spread({}, errorPayload ? {
3350
+ payload: errorPayload
3351
+ } : {}));
3560
3352
  console.error("[AD-ERROR]", errorMessage, errorPayload || "");
3561
3353
  _this.adLayer.stop().catch(function() {});
3562
3354
  _this.handleAdFailure();
@@ -3595,7 +3387,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3595
3387
  }
3596
3388
  });
3597
3389
  this.adLayer.on("content_resume", function() {
3390
+ var _ref, _ref1;
3391
+ var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
3598
3392
  var remaining = _this.getRemainingAdMs();
3393
+ 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();
3394
+ 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();
3599
3395
  if (_this.config.debugAdTiming) {
3600
3396
  console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s", _this.inAdBreak, remaining, _this.preloadedTokens.length, !!_this.pendingNextAdBids);
3601
3397
  }
@@ -3610,7 +3406,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3610
3406
  return;
3611
3407
  }
3612
3408
  _this.consecutiveFailures = 0;
3613
- if (!_this.video.muted) {
3409
+ if (!_this.config.disableFiller && !_this.video.muted) {
3614
3410
  _this.video.muted = true;
3615
3411
  _this.video.volume = 0;
3616
3412
  }
@@ -3677,6 +3473,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3677
3473
  if (!_this.config.disableFiller) {
3678
3474
  _this.showPlaceholderLayer();
3679
3475
  _this.adLayer.showPlaceholder();
3476
+ } else {
3477
+ _this.adLayer.hidePlaceholder();
3478
+ if (_this.video.muted !== breakMuted) {
3479
+ _this.video.muted = breakMuted;
3480
+ }
3481
+ if (Math.abs(_this.video.volume - breakVolume) > 0.01) {
3482
+ _this.video.volume = breakVolume;
3483
+ }
3484
+ if (_this.video.paused) {
3485
+ var _this_video_play;
3486
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3487
+ }
3680
3488
  }
3681
3489
  _this.stopContinuousFetching();
3682
3490
  return;
@@ -3982,6 +3790,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3982
3790
  value: function onScte35Marker(marker) {
3983
3791
  var _this = this;
3984
3792
  if (this.config.disableAds) return;
3793
+ this.pushScteMarker(marker);
3794
+ this.pushDebugLog("info", "scte35", "SCTE-35 marker detected", {
3795
+ type: marker.type,
3796
+ ptsSeconds: marker.ptsSeconds,
3797
+ durationSeconds: marker.durationSeconds,
3798
+ currentTime: this.video.currentTime
3799
+ });
3985
3800
  if (this.config.debugAdTiming) {
3986
3801
  console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
3987
3802
  type: marker.type,
@@ -4404,6 +4219,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4404
4219
  return this.totalAdsInBreak;
4405
4220
  }
4406
4221
  },
4222
+ {
4223
+ key: "getRemainingAdSeconds",
4224
+ value: function getRemainingAdSeconds() {
4225
+ var remainingMs = this.getRemainingAdMs();
4226
+ if (!Number.isFinite(remainingMs) || remainingMs <= 0 || remainingMs === Number.MAX_SAFE_INTEGER) {
4227
+ return 0;
4228
+ }
4229
+ return Math.ceil(remainingMs / 1e3);
4230
+ }
4231
+ },
4407
4232
  {
4408
4233
  key: "isAdPlaying",
4409
4234
  value: function isAdPlaying() {
@@ -5633,7 +5458,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5633
5458
  });
5634
5459
  };
5635
5460
  var onManifestParsedRestore = function onManifestParsedRestore1() {
5636
- hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5461
+ hlsRef.off(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5637
5462
  if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5638
5463
  if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;
5639
5464
  if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;
@@ -5646,7 +5471,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5646
5471
  }
5647
5472
  }
5648
5473
  };
5649
- hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5474
+ hlsRef.on(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5650
5475
  var pipelineDelayMs = 300;
5651
5476
  if (debugEnabled) {
5652
5477
  console.log("[StormcloudVideoPlayer] Smart TV: waiting ".concat(pipelineDelayMs, "ms for hardware pipeline release before re-attach"));
@@ -5840,6 +5665,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5840
5665
  if (!this.config.debugAdTiming) {
5841
5666
  return;
5842
5667
  }
5668
+ this.pushDebugLog("info", "ad-state", event, extra);
5843
5669
  console.log("[StormcloudVideoPlayer][AdState]", _object_spread({
5844
5670
  event: event,
5845
5671
  timestamp: /* @__PURE__ */ new Date().toISOString(),
@@ -5859,6 +5685,59 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5859
5685
  return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
5860
5686
  }
5861
5687
  },
5688
+ {
5689
+ key: "pushScteMarker",
5690
+ value: function pushScteMarker(marker) {
5691
+ if (!this.config.debugAdTiming) return;
5692
+ this.scteMarkerHistory.push({
5693
+ timestampMs: Date.now(),
5694
+ marker: marker
5695
+ });
5696
+ if (this.scteMarkerHistory.length > DEBUG_HISTORY_LIMIT) {
5697
+ this.scteMarkerHistory = this.scteMarkerHistory.slice(-DEBUG_HISTORY_LIMIT);
5698
+ }
5699
+ }
5700
+ },
5701
+ {
5702
+ key: "pushDebugLog",
5703
+ value: function pushDebugLog(level, category, message, details) {
5704
+ if (!this.config.debugAdTiming) return;
5705
+ this.debugLogEntries.push(_object_spread({
5706
+ timestampMs: Date.now(),
5707
+ level: level,
5708
+ category: category,
5709
+ message: message
5710
+ }, details ? {
5711
+ details: details
5712
+ } : {}));
5713
+ if (this.debugLogEntries.length > DEBUG_HISTORY_LIMIT) {
5714
+ this.debugLogEntries = this.debugLogEntries.slice(-DEBUG_HISTORY_LIMIT);
5715
+ }
5716
+ }
5717
+ },
5718
+ {
5719
+ key: "getRecentScteMarkers",
5720
+ value: function getRecentScteMarkers() {
5721
+ return this.scteMarkerHistory.map(function(entry) {
5722
+ return _object_spread({
5723
+ timestampMs: entry.timestampMs,
5724
+ type: entry.marker.type
5725
+ }, entry.marker.ptsSeconds !== void 0 ? {
5726
+ ptsSeconds: entry.marker.ptsSeconds
5727
+ } : {}, entry.marker.durationSeconds !== void 0 ? {
5728
+ durationSeconds: entry.marker.durationSeconds
5729
+ } : {}, entry.marker.raw !== void 0 ? {
5730
+ raw: entry.marker.raw
5731
+ } : {});
5732
+ });
5733
+ }
5734
+ },
5735
+ {
5736
+ key: "getDebugLogs",
5737
+ value: function getDebugLogs() {
5738
+ return this.debugLogEntries.slice();
5739
+ }
5740
+ },
5862
5741
  {
5863
5742
  key: "toggleMute",
5864
5743
  value: function toggleMute() {
@@ -6104,6 +5983,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6104
5983
  (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.destroy();
6105
5984
  (_this_adLayer = this.adLayer) === null || _this_adLayer === void 0 ? void 0 : _this_adLayer.destroy();
6106
5985
  this.consecutiveFailures = 0;
5986
+ this.debugLogEntries = [];
5987
+ this.scteMarkerHistory = [];
6107
5988
  }
6108
5989
  }
6109
5990
  ]);