stormcloud-video-player 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -369,185 +369,8 @@ function _ts_values(o) {
369
369
  // src/ui/StormcloudVideoPlayer.tsx
370
370
  import React2, { useEffect as useEffect2, useRef as useRef2, useMemo, useCallback as useCallback2 } from "react";
371
371
  // src/player/StormcloudVideoPlayer.ts
372
- import Hls2 from "hls.js";
372
+ import Hls from "hls.js";
373
373
  // src/sdk/vastParser.ts
374
- function isHlsType(type) {
375
- return type === "application/x-mpegURL" || type.includes("m3u8");
376
- }
377
- function isMp4Type(type) {
378
- return type === "video/mp4" || type.includes("mp4");
379
- }
380
- function parseVastXml(xmlString) {
381
- var filter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all", logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
382
- try {
383
- var _xmlDoc_querySelector, _xmlDoc_querySelector1, _xmlDoc_querySelector_textContent, _xmlDoc_querySelector2;
384
- var parser = new DOMParser();
385
- var xmlDoc = parser.parseFromString(xmlString, "text/xml");
386
- var parserError = xmlDoc.querySelector("parsererror");
387
- if (parserError) {
388
- console.error("".concat(logPrefix, " XML parsing error (malformed VAST XML):"), parserError.textContent);
389
- return null;
390
- }
391
- var adElement = xmlDoc.querySelector("Ad");
392
- if (!adElement) {
393
- console.warn("".concat(logPrefix, " No Ad element found in VAST XML"));
394
- return null;
395
- }
396
- var adId = adElement.getAttribute("id") || "unknown";
397
- var title = ((_xmlDoc_querySelector = xmlDoc.querySelector("AdTitle")) === null || _xmlDoc_querySelector === void 0 ? void 0 : _xmlDoc_querySelector.textContent) || "Ad";
398
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
399
- var durationText = ((_xmlDoc_querySelector1 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector1 === void 0 ? void 0 : _xmlDoc_querySelector1.textContent) || "00:00:30";
400
- var durationParts = durationText.split(":");
401
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + Math.round(parseFloat(durationParts[2] || "0"));
402
- var mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
403
- var mediaFiles = [];
404
- console.log("".concat(logPrefix, " Found ").concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
405
- mediaFileElements.forEach(function(mf, index) {
406
- var _mf_textContent;
407
- var type = mf.getAttribute("type") || "";
408
- var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
409
- var width = mf.getAttribute("width") || "";
410
- var height = mf.getAttribute("height") || "";
411
- console.log("".concat(logPrefix, " MediaFile ").concat(index, ': type="').concat(type, '", url="').concat(url.substring(0, 80), '...", width="').concat(width, '", height="').concat(height, '"'));
412
- if (!url) {
413
- console.warn("".concat(logPrefix, " MediaFile ").concat(index, " has empty URL"));
414
- return;
415
- }
416
- var isHls = isHlsType(type);
417
- var isMp4 = isMp4Type(type);
418
- var accepted = false;
419
- if (filter === "hls-only") {
420
- accepted = isHls;
421
- } else if (filter === "mp4-first") {
422
- accepted = isMp4 || isHls;
423
- } else {
424
- accepted = true;
425
- }
426
- if (!accepted) {
427
- console.log("".concat(logPrefix, " MediaFile ").concat(index, ' ignored (type="').concat(type, '" not accepted by filter "').concat(filter, '")'));
428
- return;
429
- }
430
- var bitrateAttr = mf.getAttribute("bitrate");
431
- var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
432
- mediaFiles.push({
433
- url: url,
434
- type: type,
435
- width: parseInt(width || "1920", 10),
436
- height: parseInt(height || "1080", 10),
437
- bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
438
- });
439
- console.log("".concat(logPrefix, ' Added MediaFile: type="').concat(type, '" url="').concat(url.substring(0, 80), '..."'));
440
- });
441
- if (filter === "mp4-first" && mediaFiles.length > 1) {
442
- mediaFiles.sort(function(a, b) {
443
- var aIsMp4 = isMp4Type(a.type) ? 0 : 1;
444
- var bIsMp4 = isMp4Type(b.type) ? 0 : 1;
445
- return aIsMp4 - bIsMp4;
446
- });
447
- }
448
- if (mediaFiles.length === 0) {
449
- if (isNoAdAvailable) {
450
- console.warn("".concat(logPrefix, " No ads available (VAST response indicates no ads)"));
451
- } else {
452
- console.warn("".concat(logPrefix, " No compatible media files found in VAST XML"));
453
- }
454
- return null;
455
- }
456
- var trackingUrls = {
457
- impression: [],
458
- start: [],
459
- firstQuartile: [],
460
- midpoint: [],
461
- thirdQuartile: [],
462
- complete: [],
463
- mute: [],
464
- unmute: [],
465
- pause: [],
466
- resume: [],
467
- fullscreen: [],
468
- exitFullscreen: [],
469
- skip: [],
470
- error: []
471
- };
472
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
473
- var _el_textContent;
474
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
475
- if (url) trackingUrls.impression.push(url);
476
- });
477
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
478
- var _el_textContent;
479
- var event = el.getAttribute("event");
480
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
481
- if (event && url) {
482
- var eventKey = event;
483
- if (trackingUrls[eventKey]) {
484
- trackingUrls[eventKey].push(url);
485
- }
486
- }
487
- });
488
- 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();
489
- return {
490
- id: adId,
491
- title: title,
492
- duration: duration,
493
- mediaFiles: mediaFiles,
494
- trackingUrls: trackingUrls,
495
- clickThrough: clickThrough
496
- };
497
- } catch (error) {
498
- console.error("".concat(logPrefix, " Error parsing VAST XML:"), error);
499
- return null;
500
- }
501
- }
502
- function fetchAndParseVastAd(vastTagUrl) {
503
- var filter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all", logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
504
- return _async_to_generator(function() {
505
- var response, vastXml;
506
- return _ts_generator(this, function(_state) {
507
- switch(_state.label){
508
- case 0:
509
- return [
510
- 4,
511
- fetch(vastTagUrl, {
512
- mode: "cors",
513
- credentials: "include",
514
- headers: {
515
- Accept: "application/xml, text/xml, */*"
516
- },
517
- referrerPolicy: "no-referrer-when-downgrade"
518
- })
519
- ];
520
- case 1:
521
- response = _state.sent();
522
- if (!response.ok) {
523
- throw new Error("Failed to fetch VAST: ".concat(response.statusText));
524
- }
525
- return [
526
- 4,
527
- response.text()
528
- ];
529
- case 2:
530
- vastXml = _state.sent();
531
- console.log("".concat(logPrefix, " VAST XML received"));
532
- console.log("".concat(logPrefix, " VAST XML content (first 2000 chars):"), vastXml.substring(0, 2e3));
533
- return [
534
- 2,
535
- parseVastXml(vastXml, filter, logPrefix)
536
- ];
537
- }
538
- });
539
- })();
540
- }
541
- function createEmptyTrackingState() {
542
- return {
543
- impression: false,
544
- start: false,
545
- firstQuartile: false,
546
- midpoint: false,
547
- thirdQuartile: false,
548
- complete: false
549
- };
550
- }
551
374
  function firePixelWithRetry(url) {
552
375
  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]";
553
376
  return _async_to_generator(function() {
@@ -670,16 +493,164 @@ function fireTrackingPixels(urls, sessionId) {
670
493
  }
671
494
  });
672
495
  }
673
- // src/sdk/vastManager.ts
674
- 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";
675
- var DEFAULT_TIMEOUT_MS = 5e3;
676
- var MAX_RETRIES = 3;
677
- var RETRY_BACKOFF_MS = 1500;
678
- function createVastManager() {
679
- var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
680
- var _options_debug;
681
- var initialized = false;
682
- var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
496
+ // src/sdk/adstormPlayer.ts
497
+ var SUPPORTED_VIDEO_EXTENSIONS = [
498
+ ".mp4",
499
+ ".webm",
500
+ ".ogg",
501
+ ".m3u8",
502
+ ".ts"
503
+ ];
504
+ var UNSUPPORTED_VIDEO_EXTENSIONS = [
505
+ ".flv",
506
+ ".f4v",
507
+ ".swf",
508
+ ".wmv",
509
+ ".avi",
510
+ ".mov",
511
+ ".mkv"
512
+ ];
513
+ var REQUEST_TIMEOUT_MS = 5e3;
514
+ var REQUEST_MAX_RETRIES = 3;
515
+ var REQUEST_RETRY_BACKOFF_MS = 1500;
516
+ var AD_LAYER_Z_INDEX = "2147483646";
517
+ var COUNTDOWN_Z_INDEX = "2147483647";
518
+ var STALL_TIMEOUT_MS = 8e3;
519
+ function getFileExtension(url) {
520
+ try {
521
+ var pathname = new URL(url, "http://dummy").pathname;
522
+ var lastDot = pathname.lastIndexOf(".");
523
+ if (lastDot === -1) return "";
524
+ return pathname.slice(lastDot).toLowerCase();
525
+ } catch (unused) {
526
+ var lastDot1 = url.lastIndexOf(".");
527
+ if (lastDot1 === -1) return "";
528
+ var ext = url.slice(lastDot1).split(/[?#]/)[0];
529
+ return (ext || "").toLowerCase();
530
+ }
531
+ }
532
+ function isUnsupportedFormat(url) {
533
+ var ext = getFileExtension(url);
534
+ return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;
535
+ }
536
+ function replaceFlvExtension(url) {
537
+ var ext = getFileExtension(url);
538
+ if (ext === ".flv") {
539
+ return url.replace(/\.flv(\?|$)/i, ".mp4$1");
540
+ }
541
+ return url;
542
+ }
543
+ function isSupportedFormat(url, mimeType) {
544
+ if (isUnsupportedFormat(url)) {
545
+ return false;
546
+ }
547
+ var ext = getFileExtension(url);
548
+ if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {
549
+ return true;
550
+ }
551
+ if (ext === "" || ext === ".") {
552
+ return mimeType.includes("video/mp4") || mimeType.includes("video/webm") || mimeType.includes("m3u8") || mimeType.includes("application/x-mpegurl");
553
+ }
554
+ return false;
555
+ }
556
+ function createAdStormPlayer(contentVideo, options) {
557
+ var licenseKey = options.licenseKey, _options_debug = options.debug, debug = _options_debug === void 0 ? false : _options_debug;
558
+ var adPlaying = false;
559
+ var originalMutedState = false;
560
+ var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
561
+ var listeners = /* @__PURE__ */ new Map();
562
+ var adVideoElement;
563
+ var adContainerEl;
564
+ var adCountdownEl;
565
+ var currentAd;
566
+ var destroyed = false;
567
+ var tornDown = false;
568
+ var continueLiveStreamDuringAds = false;
569
+ var sessionId;
570
+ var adStallTimerId;
571
+ var adCountdownTimerId;
572
+ var adHideTimerId;
573
+ var lastCountdownSecond = -1;
574
+ var adListenersBound = false;
575
+ var parentPositionOverridden = false;
576
+ var adHandlers = {
577
+ timeupdate: function timeupdate() {
578
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
579
+ var progress = adVideoElement.currentTime / currentAd.duration;
580
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
581
+ trackingFired.firstQuartile = true;
582
+ fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);
583
+ }
584
+ if (progress >= 0.5 && !trackingFired.midpoint) {
585
+ trackingFired.midpoint = true;
586
+ fireTrackingPixels2(currentAd.trackingUrls.midpoint);
587
+ }
588
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
589
+ trackingFired.thirdQuartile = true;
590
+ fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);
591
+ }
592
+ updateAdCountdown();
593
+ },
594
+ playing: function playing() {
595
+ clearAdStallTimer();
596
+ if (!currentAd || trackingFired.start || destroyed || tornDown) return;
597
+ trackingFired.start = true;
598
+ fireTrackingPixels2(currentAd.trackingUrls.start);
599
+ startAdCountdown();
600
+ log("Ad started playing");
601
+ },
602
+ ended: function ended() {
603
+ if (!currentAd || trackingFired.complete || destroyed || tornDown) return;
604
+ trackingFired.complete = true;
605
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
606
+ log("Ad completed");
607
+ handleAdComplete();
608
+ },
609
+ error: function error(e) {
610
+ if (destroyed || tornDown) return;
611
+ console.error("[AdStormPlayer] Ad video error:", e);
612
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
613
+ handleAdError();
614
+ },
615
+ waiting: function waiting() {
616
+ clearAdStallTimer();
617
+ adStallTimerId = setTimeout(function() {
618
+ adStallTimerId = void 0;
619
+ if (!adPlaying || destroyed || tornDown) return;
620
+ console.warn("[AdStormPlayer] Ad playback stalled too long");
621
+ handleAdError();
622
+ }, STALL_TIMEOUT_MS);
623
+ },
624
+ volumechange: function volumechange() {
625
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
626
+ if (adVideoElement.muted || adVideoElement.volume <= 0) {
627
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
628
+ } else {
629
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
630
+ }
631
+ },
632
+ pause: function pause() {
633
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
634
+ if (!adVideoElement.ended) {
635
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
636
+ }
637
+ },
638
+ play: function play() {
639
+ if (!currentAd || !adVideoElement || destroyed || tornDown) return;
640
+ if (adVideoElement.currentTime > 0) {
641
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
642
+ }
643
+ }
644
+ };
645
+ var trackingFired = {
646
+ impression: false,
647
+ start: false,
648
+ firstQuartile: false,
649
+ midpoint: false,
650
+ thirdQuartile: false,
651
+ complete: false
652
+ };
653
+ var preloadSlots = /* @__PURE__ */ new Map();
683
654
  function log() {
684
655
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
685
656
  args[_key] = arguments[_key];
@@ -687,58 +658,340 @@ function createVastManager() {
687
658
  if (debug) {
688
659
  var _console;
689
660
  (_console = console).log.apply(_console, [
690
- "[VastManager]"
661
+ "[AdStormPlayer]"
691
662
  ].concat(_to_consumable_array(args)));
692
663
  }
693
664
  }
694
- function warn() {
695
- for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
696
- args[_key] = arguments[_key];
665
+ function emit(event, payload) {
666
+ var set = listeners.get(event);
667
+ if (!set) return;
668
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
669
+ try {
670
+ for(var _iterator = Array.from(set)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
671
+ var fn = _step.value;
672
+ try {
673
+ fn(payload);
674
+ } catch (error) {
675
+ console.warn("[AdStormPlayer] Error in event listener for ".concat(event, ":"), error);
676
+ }
677
+ }
678
+ } catch (err) {
679
+ _didIteratorError = true;
680
+ _iteratorError = err;
681
+ } finally{
682
+ try {
683
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
684
+ _iterator.return();
685
+ }
686
+ } finally{
687
+ if (_didIteratorError) {
688
+ throw _iteratorError;
689
+ }
690
+ }
697
691
  }
698
- var _console;
699
- (_console = console).warn.apply(_console, [
700
- "[VastManager]"
701
- ].concat(_to_consumable_array(args)));
702
692
  }
703
- function initialize() {
704
- return _async_to_generator(function() {
705
- return _ts_generator(this, function(_state) {
706
- if (initialized) return [
707
- 2
708
- ];
709
- initialized = true;
710
- log("Initialized, VAST tag URL:", VAST_TAG_URL.split("?")[0]);
711
- return [
712
- 2
713
- ];
693
+ function fireTrackingPixels2(urls) {
694
+ fireTrackingPixels(urls, sessionId, "[AdStormPlayer]");
695
+ }
696
+ function clearAdStallTimer() {
697
+ if (adStallTimerId) {
698
+ clearTimeout(adStallTimerId);
699
+ adStallTimerId = void 0;
700
+ }
701
+ }
702
+ function clearAdCountdownTimer() {
703
+ if (adCountdownTimerId) {
704
+ clearInterval(adCountdownTimerId);
705
+ adCountdownTimerId = void 0;
706
+ }
707
+ lastCountdownSecond = -1;
708
+ }
709
+ function updateAdCountdown() {
710
+ if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;
711
+ var remainingSec = Math.max(0, Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime));
712
+ if (remainingSec === lastCountdownSecond) return;
713
+ lastCountdownSecond = remainingSec;
714
+ adCountdownEl.textContent = "Ad ".concat(remainingSec, "s");
715
+ emit("ad_countdown", {
716
+ remainingSec: remainingSec,
717
+ durationSec: currentAd.duration,
718
+ currentTimeSec: adVideoElement.currentTime
719
+ });
720
+ }
721
+ function startAdCountdown() {
722
+ clearAdCountdownTimer();
723
+ updateAdCountdown();
724
+ adCountdownTimerId = setInterval(updateAdCountdown, 250);
725
+ }
726
+ function generateSessionId() {
727
+ return "adstorm-".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2, 10));
728
+ }
729
+ function bindAdEventListeners() {
730
+ if (!adVideoElement || adListenersBound) return;
731
+ adVideoElement.addEventListener("timeupdate", adHandlers.timeupdate);
732
+ adVideoElement.addEventListener("playing", adHandlers.playing);
733
+ adVideoElement.addEventListener("ended", adHandlers.ended);
734
+ adVideoElement.addEventListener("error", adHandlers.error);
735
+ adVideoElement.addEventListener("waiting", adHandlers.waiting);
736
+ adVideoElement.addEventListener("volumechange", adHandlers.volumechange);
737
+ adVideoElement.addEventListener("pause", adHandlers.pause);
738
+ adVideoElement.addEventListener("play", adHandlers.play);
739
+ adListenersBound = true;
740
+ }
741
+ function unbindAdEventListeners() {
742
+ if (!adVideoElement || !adListenersBound) return;
743
+ adVideoElement.removeEventListener("timeupdate", adHandlers.timeupdate);
744
+ adVideoElement.removeEventListener("playing", adHandlers.playing);
745
+ adVideoElement.removeEventListener("ended", adHandlers.ended);
746
+ adVideoElement.removeEventListener("error", adHandlers.error);
747
+ adVideoElement.removeEventListener("waiting", adHandlers.waiting);
748
+ adVideoElement.removeEventListener("volumechange", adHandlers.volumechange);
749
+ adVideoElement.removeEventListener("pause", adHandlers.pause);
750
+ adVideoElement.removeEventListener("play", adHandlers.play);
751
+ adListenersBound = false;
752
+ }
753
+ function teardownCurrentPlayback() {
754
+ unbindAdEventListeners();
755
+ clearAdStallTimer();
756
+ clearAdCountdownTimer();
757
+ if (!adVideoElement) return;
758
+ adVideoElement.pause();
759
+ adVideoElement.removeAttribute("src");
760
+ adVideoElement.load();
761
+ }
762
+ function buildVastUrl(durationSeconds, metadata) {
763
+ var baseUrl = "https://adstorm.co/api-adstorm-dev/adstorm/vast/".concat(licenseKey, "/pod");
764
+ var defaultMetadata = {
765
+ video: {
766
+ codec: "h264",
767
+ width: contentVideo.videoWidth || 1280,
768
+ height: contentVideo.videoHeight || 720,
769
+ fps: 29.97,
770
+ bitrate: 5e3,
771
+ profile: "high",
772
+ pix_fmt: "yuv420p",
773
+ has_b_frames: 0
774
+ },
775
+ audio: {
776
+ codec: "aac",
777
+ sample_rate: 48e3,
778
+ bitrate: 128
779
+ }
780
+ };
781
+ var finalMetadata = metadata || defaultMetadata;
782
+ var metadataStr = encodeURIComponent(JSON.stringify(finalMetadata));
783
+ return "".concat(baseUrl, "?duration=").concat(Math.ceil(durationSeconds), "&metadata=").concat(metadataStr);
784
+ }
785
+ function parseVastXml(xmlString) {
786
+ var ads = [];
787
+ try {
788
+ var parser = new DOMParser();
789
+ var xmlDoc = parser.parseFromString(xmlString, "text/xml");
790
+ var parserError = xmlDoc.querySelector("parsererror");
791
+ if (parserError) {
792
+ console.error("[AdStormPlayer] XML parsing error:", parserError.textContent);
793
+ return [];
794
+ }
795
+ var adElements = xmlDoc.querySelectorAll("Ad");
796
+ adElements.forEach(function(adElement) {
797
+ var _adElement_querySelector, _adElement_querySelector1, _adElement_querySelector_textContent, _adElement_querySelector2;
798
+ var adId = adElement.getAttribute("id") || "unknown";
799
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
800
+ var durationText = ((_adElement_querySelector1 = adElement.querySelector("Duration")) === null || _adElement_querySelector1 === void 0 ? void 0 : _adElement_querySelector1.textContent) || "00:00:30";
801
+ var durationParts = durationText.split(":");
802
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseFloat(durationParts[2] || "0");
803
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
804
+ var mediaFiles = [];
805
+ mediaFileElements.forEach(function(mf) {
806
+ var _mf_textContent;
807
+ var type = mf.getAttribute("type") || "";
808
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
809
+ var width = parseInt(mf.getAttribute("width") || "1920", 10);
810
+ var height = parseInt(mf.getAttribute("height") || "1080", 10);
811
+ var bitrate = mf.getAttribute("bitrate") ? parseInt(mf.getAttribute("bitrate"), 10) : void 0;
812
+ if (!url) {
813
+ log("Skipping empty MediaFile URL");
814
+ return;
815
+ }
816
+ var originalUrl = url;
817
+ url = replaceFlvExtension(url);
818
+ if (url !== originalUrl) {
819
+ log("Converted FLV to MP4: ".concat(originalUrl, " -> ").concat(url));
820
+ }
821
+ if (isUnsupportedFormat(url)) {
822
+ var ext = getFileExtension(url);
823
+ log("Skipping unsupported format: ".concat(url, " (extension: ").concat(ext, ", declared type: ").concat(type, ")"));
824
+ return;
825
+ }
826
+ if (isSupportedFormat(url, type)) {
827
+ mediaFiles.push({
828
+ url: url,
829
+ type: type,
830
+ width: width,
831
+ height: height,
832
+ bitrate: bitrate
833
+ });
834
+ log("Found media file: ".concat(url, " (").concat(type, ", ").concat(width, "x").concat(height, ")"));
835
+ } else {
836
+ log("Skipping incompatible media file: ".concat(url, " (type: ").concat(type, ")"));
837
+ }
838
+ });
839
+ if (mediaFiles.length === 0) {
840
+ log("No valid media files found in ad:", adId);
841
+ return;
842
+ }
843
+ var trackingUrls = {
844
+ impression: [],
845
+ start: [],
846
+ firstQuartile: [],
847
+ midpoint: [],
848
+ thirdQuartile: [],
849
+ complete: [],
850
+ mute: [],
851
+ unmute: [],
852
+ pause: [],
853
+ resume: [],
854
+ error: []
855
+ };
856
+ adElement.querySelectorAll("Impression").forEach(function(el) {
857
+ var _el_textContent;
858
+ var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
859
+ if (url) trackingUrls.impression.push(url);
860
+ });
861
+ adElement.querySelectorAll("Tracking").forEach(function(el) {
862
+ var _el_textContent;
863
+ var event = el.getAttribute("event");
864
+ var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
865
+ if (event && url) {
866
+ var eventKey = event;
867
+ if (trackingUrls[eventKey]) {
868
+ trackingUrls[eventKey].push(url);
869
+ }
870
+ }
871
+ });
872
+ 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();
873
+ ads.push({
874
+ id: adId,
875
+ title: title,
876
+ duration: duration,
877
+ mediaFiles: mediaFiles,
878
+ trackingUrls: trackingUrls,
879
+ clickThrough: clickThrough
880
+ });
881
+ log("Parsed ad: ".concat(title, ", duration: ").concat(duration, "s, media files: ").concat(mediaFiles.length));
714
882
  });
715
- })();
883
+ } catch (error) {
884
+ console.error("[AdStormPlayer] Error parsing VAST XML:", error);
885
+ }
886
+ return ads;
887
+ }
888
+ function selectBestMediaFile(mediaFiles) {
889
+ if (mediaFiles.length === 0) return null;
890
+ if (mediaFiles.length === 1) return mediaFiles[0];
891
+ var mp4Files = mediaFiles.filter(function(mf) {
892
+ return mf.type.includes("video/mp4");
893
+ });
894
+ var candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;
895
+ var targetWidth = contentVideo.videoWidth || 1280;
896
+ var targetHeight = contentVideo.videoHeight || 720;
897
+ candidates.sort(function(a, b) {
898
+ var diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);
899
+ var diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);
900
+ return diffA - diffB;
901
+ });
902
+ return candidates[0] || null;
903
+ }
904
+ function createAdVideoElement() {
905
+ var video = document.createElement("video");
906
+ video.style.position = "absolute";
907
+ video.style.left = "0";
908
+ video.style.top = "0";
909
+ video.style.width = "100%";
910
+ video.style.height = "100%";
911
+ video.style.objectFit = "contain";
912
+ video.style.backgroundColor = "#000";
913
+ video.style.zIndex = "1";
914
+ video.playsInline = true;
915
+ video.preload = "auto";
916
+ video.muted = originalMutedState;
917
+ video.volume = originalMutedState ? 0 : originalVolume;
918
+ return video;
919
+ }
920
+ function setAdPlayingFlag(isPlaying) {
921
+ if (isPlaying) {
922
+ contentVideo.dataset.stormcloudAdPlaying = "true";
923
+ } else {
924
+ delete contentVideo.dataset.stormcloudAdPlaying;
925
+ }
926
+ }
927
+ function setupAdEventListeners() {
928
+ bindAdEventListeners();
929
+ }
930
+ function handleAdComplete() {
931
+ if (destroyed || tornDown) return;
932
+ log("Handling ad completion");
933
+ adPlaying = false;
934
+ setAdPlayingFlag(false);
935
+ clearAdStallTimer();
936
+ clearAdCountdownTimer();
937
+ if (adContainerEl) {
938
+ adContainerEl.style.opacity = "0";
939
+ adHideTimerId = setTimeout(function() {
940
+ if (adContainerEl) {
941
+ adContainerEl.style.display = "none";
942
+ adContainerEl.style.pointerEvents = "none";
943
+ }
944
+ }, 300);
945
+ }
946
+ contentVideo.style.visibility = "visible";
947
+ contentVideo.style.opacity = "1";
948
+ contentVideo.muted = originalMutedState;
949
+ contentVideo.volume = originalVolume;
950
+ currentAd = void 0;
951
+ emit("content_resume");
952
+ emit("all_ads_completed");
953
+ }
954
+ function handleAdError() {
955
+ if (destroyed || tornDown) return;
956
+ log("Handling ad error");
957
+ if (!adPlaying) return;
958
+ adPlaying = false;
959
+ setAdPlayingFlag(false);
960
+ clearAdStallTimer();
961
+ clearAdCountdownTimer();
962
+ contentVideo.muted = originalMutedState;
963
+ contentVideo.volume = originalVolume;
964
+ contentVideo.style.visibility = "visible";
965
+ contentVideo.style.opacity = "1";
966
+ if (adContainerEl) {
967
+ adContainerEl.style.display = "none";
968
+ adContainerEl.style.pointerEvents = "none";
969
+ }
970
+ currentAd = void 0;
971
+ emit("ad_error");
972
+ emit("content_resume");
716
973
  }
717
- function requestBids(_context) {
974
+ function fetchVastOnce(durationSeconds) {
718
975
  return _async_to_generator(function() {
719
- var correlator, url, controller, timeoutId, _ref, _ref1, _vastAd_mediaFiles_, _vastAd_mediaFiles_1, fetchOptions, response, vastXml, vastAd, bid, error;
976
+ var vastUrl, controller, timeoutId, requestInit, response, xmlText;
720
977
  return _ts_generator(this, function(_state) {
721
978
  switch(_state.label){
722
979
  case 0:
723
- if (!initialized) {
724
- throw new Error("VastManager not initialized. Call initialize() first.");
725
- }
726
- correlator = Math.floor(Math.random() * 1e12).toString();
727
- url = VAST_TAG_URL.replace("[placeholder]", correlator);
728
- log("Fetching VAST tag, correlator:", correlator);
980
+ vastUrl = buildVastUrl(durationSeconds);
981
+ log("Fetching VAST from:", vastUrl);
729
982
  controller = typeof AbortController !== "undefined" ? new AbortController() : null;
730
983
  timeoutId = setTimeout(function() {
731
984
  return controller === null || controller === void 0 ? void 0 : controller.abort();
732
- }, DEFAULT_TIMEOUT_MS);
985
+ }, REQUEST_TIMEOUT_MS);
733
986
  _state.label = 1;
734
987
  case 1:
735
988
  _state.trys.push([
736
989
  1,
737
- 4,
738
990
  ,
991
+ 4,
739
992
  5
740
993
  ]);
741
- fetchOptions = {
994
+ requestInit = {
742
995
  method: "GET",
743
996
  mode: "cors",
744
997
  credentials: "omit",
@@ -747,63 +1000,35 @@ function createVastManager() {
747
1000
  },
748
1001
  referrerPolicy: "no-referrer-when-downgrade"
749
1002
  };
750
- if (controller) fetchOptions.signal = controller.signal;
1003
+ if (controller) {
1004
+ requestInit.signal = controller.signal;
1005
+ }
751
1006
  return [
752
1007
  4,
753
- fetch(url, fetchOptions)
1008
+ fetch(vastUrl, requestInit)
754
1009
  ];
755
1010
  case 2:
756
1011
  response = _state.sent();
757
- clearTimeout(timeoutId);
758
1012
  if (!response.ok) {
759
- throw new Error("VAST request returned HTTP ".concat(response.status));
1013
+ throw new Error("Failed to fetch VAST: ".concat(response.status, " ").concat(response.statusText));
760
1014
  }
761
1015
  return [
762
1016
  4,
763
1017
  response.text()
764
1018
  ];
765
1019
  case 3:
766
- vastXml = _state.sent();
767
- log("VAST XML received, length:", vastXml.length);
768
- vastAd = parseVastXml(vastXml, "mp4-first", "[VastManager]");
769
- if (!vastAd) {
770
- log("VAST parsed but no usable ad found");
771
- return [
772
- 2,
773
- []
774
- ];
775
- }
776
- log("Ad parsed: id=".concat(vastAd.id, ", duration=").concat(vastAd.duration, "s, mediaFiles=").concat(vastAd.mediaFiles.length));
777
- bid = {
778
- bidder: "vast-direct",
779
- cpm: 0,
780
- vastXml: vastXml,
781
- width: (_ref = (_vastAd_mediaFiles_ = vastAd.mediaFiles[0]) === null || _vastAd_mediaFiles_ === void 0 ? void 0 : _vastAd_mediaFiles_.width) !== null && _ref !== void 0 ? _ref : 0,
782
- 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,
783
- adId: vastAd.id,
784
- impId: correlator,
785
- creativeId: vastAd.id,
786
- currency: "USD",
787
- durationSec: vastAd.duration
788
- };
1020
+ xmlText = _state.sent();
1021
+ log("VAST response received, length:", xmlText.length);
789
1022
  return [
790
1023
  2,
791
- [
792
- bid
793
- ]
1024
+ parseVastXml(xmlText)
794
1025
  ];
795
1026
  case 4:
796
- error = _state.sent();
797
1027
  clearTimeout(timeoutId);
798
- if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
799
- warn("VAST request timed out after ".concat(DEFAULT_TIMEOUT_MS, "ms"));
800
- return [
801
- 2,
802
- []
803
- ];
804
- }
805
- throw error;
806
- case 5:
1028
+ return [
1029
+ 7
1030
+ ];
1031
+ case 5:
807
1032
  return [
808
1033
  2
809
1034
  ];
@@ -811,14 +1036,14 @@ function createVastManager() {
811
1036
  });
812
1037
  })();
813
1038
  }
814
- function requestBidsUntilResponse(context) {
1039
+ function fetchVast(durationSeconds) {
815
1040
  return _async_to_generator(function() {
816
1041
  var _loop, lastError, attempt, _ret;
817
1042
  return _ts_generator(this, function(_state) {
818
1043
  switch(_state.label){
819
1044
  case 0:
820
1045
  _loop = function(attempt) {
821
- var bids, err, delay;
1046
+ var ads, error, delay;
822
1047
  return _ts_generator(this, function(_state) {
823
1048
  switch(_state.label){
824
1049
  case 0:
@@ -830,39 +1055,39 @@ function createVastManager() {
830
1055
  ]);
831
1056
  return [
832
1057
  4,
833
- requestBids(context)
1058
+ fetchVastOnce(durationSeconds)
834
1059
  ];
835
1060
  case 1:
836
- bids = _state.sent();
837
- if (bids.length > 0) {
838
- log("requestBidsUntilResponse: got ".concat(bids.length, " ad(s) on attempt ").concat(attempt));
839
- return [
840
- 2,
841
- {
842
- v: bids
843
- }
844
- ];
845
- }
846
- log("requestBidsUntilResponse: no ads on attempt ".concat(attempt, "/").concat(MAX_RETRIES));
1061
+ ads = _state.sent();
1062
+ if (ads.length > 0) return [
1063
+ 2,
1064
+ {
1065
+ v: ads
1066
+ }
1067
+ ];
1068
+ log("No ad returned from VAST on attempt ".concat(attempt, "/").concat(REQUEST_MAX_RETRIES));
847
1069
  return [
848
1070
  3,
849
1071
  3
850
1072
  ];
851
1073
  case 2:
852
- err = _state.sent();
853
- lastError = err;
854
- warn("requestBidsUntilResponse: attempt ".concat(attempt, "/").concat(MAX_RETRIES, " failed:"), err);
1074
+ error = _state.sent();
1075
+ lastError = error;
1076
+ if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
1077
+ console.warn("[AdStormPlayer] VAST request timed out (".concat(REQUEST_TIMEOUT_MS, "ms), attempt ").concat(attempt, "/").concat(REQUEST_MAX_RETRIES));
1078
+ } else {
1079
+ console.warn("[AdStormPlayer] VAST request failed on attempt ".concat(attempt, "/").concat(REQUEST_MAX_RETRIES, ":"), error);
1080
+ }
855
1081
  return [
856
1082
  3,
857
1083
  3
858
1084
  ];
859
1085
  case 3:
860
- if (!(attempt < MAX_RETRIES)) return [
1086
+ if (!(attempt < REQUEST_MAX_RETRIES)) return [
861
1087
  3,
862
1088
  5
863
1089
  ];
864
- delay = RETRY_BACKOFF_MS * attempt;
865
- log("requestBidsUntilResponse: waiting ".concat(delay, "ms before retry"));
1090
+ delay = REQUEST_RETRY_BACKOFF_MS * attempt;
866
1091
  return [
867
1092
  4,
868
1093
  new Promise(function(resolve) {
@@ -879,13 +1104,10 @@ function createVastManager() {
879
1104
  }
880
1105
  });
881
1106
  };
882
- if (!initialized) {
883
- throw new Error("VastManager not initialized. Call initialize() first.");
884
- }
885
1107
  attempt = 1;
886
1108
  _state.label = 1;
887
1109
  case 1:
888
- if (!(attempt <= MAX_RETRIES)) return [
1110
+ if (!(attempt <= REQUEST_MAX_RETRIES)) return [
889
1111
  3,
890
1112
  4
891
1113
  ];
@@ -907,7 +1129,9 @@ function createVastManager() {
907
1129
  1
908
1130
  ];
909
1131
  case 4:
910
- if (_instanceof(lastError, Error)) throw lastError;
1132
+ if (_instanceof(lastError, Error)) {
1133
+ throw lastError;
1134
+ }
911
1135
  return [
912
1136
  2,
913
1137
  []
@@ -916,971 +1140,468 @@ function createVastManager() {
916
1140
  });
917
1141
  })();
918
1142
  }
919
- function destroy() {
920
- initialized = false;
921
- log("Destroyed");
922
- }
923
- return {
924
- initialize: initialize,
925
- requestBids: requestBids,
926
- requestBidsUntilResponse: requestBidsUntilResponse,
927
- destroy: destroy,
928
- get isInitialized () {
929
- return initialized;
930
- }
931
- };
932
- }
933
- // src/sdk/vastAdLayer.ts
934
- import Hls from "hls.js";
935
- var LOG = "[VastAdLayer]";
936
- function resolveBidToVastAd(winner, logPrefix) {
937
- if (winner.vastXml) {
938
- var ad = parseVastXml(winner.vastXml, "mp4-first", logPrefix);
939
- return Promise.resolve(ad);
940
- }
941
- if (winner.vastUrl) {
942
- return fetchAndParseVastAd(winner.vastUrl, "mp4-first", logPrefix);
943
- }
944
- return Promise.resolve(null);
945
- }
946
- function createVastAdLayer(contentVideo, options) {
947
- var _ref, _ref1, _ref2, _ref3, _ref4;
948
- var adPlaying = false;
949
- var originalMutedState = false;
950
- var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
951
- var listeners = /* @__PURE__ */ new Map();
952
- var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
953
- var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
954
- var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
955
- var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
956
- var forceMP4Ads = (_ref3 = options === null || options === void 0 ? void 0 : options.forceMP4Ads) !== null && _ref3 !== void 0 ? _ref3 : smartTVMode || singleElementMode;
957
- var debug = (_ref4 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref4 !== void 0 ? _ref4 : false;
958
- var adVideoElement;
959
- var adHls;
960
- var adContainerEl;
961
- var currentAd;
962
- var sessionId;
963
- var destroyed = false;
964
- var tornDown = false;
965
- var trackingFired = createEmptyTrackingState();
966
- var adStallTimerId;
967
- var savedContentVideoStyles;
968
- var currentAdEventHandlers;
969
- var preloadSlots = /* @__PURE__ */ new Map();
970
- function emit(event, payload) {
971
- var set = listeners.get(event);
972
- if (!set) return;
973
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
974
- try {
975
- for(var _iterator = Array.from(set)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
976
- var fn = _step.value;
977
- try {
978
- fn(payload);
979
- } catch (error) {
980
- console.warn("".concat(LOG, " Error in event listener for ").concat(event, ":"), error);
981
- }
982
- }
983
- } catch (err) {
984
- _didIteratorError = true;
985
- _iteratorError = err;
986
- } finally{
987
- try {
988
- if (!_iteratorNormalCompletion && _iterator.return != null) {
989
- _iterator.return();
990
- }
991
- } finally{
992
- if (_didIteratorError) {
993
- throw _iteratorError;
994
- }
995
- }
996
- }
997
- }
998
- function generateSessionId() {
999
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
1000
- }
1001
- function fireTrackingPixels2(urls) {
1002
- fireTrackingPixels(urls, sessionId, LOG);
1003
- }
1004
- function getMainStreamQuality() {
1005
- if (!(mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.levels)) return null;
1006
- var currentLevel = mainHlsInstance.currentLevel;
1007
- if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {
1008
- var autoLevel = mainHlsInstance.loadLevel;
1009
- if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {
1010
- var level2 = mainHlsInstance.levels[autoLevel];
1011
- return {
1012
- width: level2.width || 1920,
1013
- height: level2.height || 1080,
1014
- bitrate: level2.bitrate || 5e6
1015
- };
1016
- }
1017
- return null;
1018
- }
1019
- var level = mainHlsInstance.levels[currentLevel];
1020
- return {
1021
- width: level.width || 1920,
1022
- height: level.height || 1080,
1023
- bitrate: level.bitrate || 5e6
1024
- };
1025
- }
1026
- function selectBestMediaFile(mediaFiles) {
1027
- var _ref;
1028
- var _scoredFiles_;
1029
- if (mediaFiles.length === 0) throw new Error("No media files available");
1030
- var candidates = mediaFiles;
1031
- if (forceMP4Ads) {
1032
- var mp4Only = candidates.filter(function(f) {
1033
- return !isHlsMediaFile(f);
1034
- });
1035
- if (mp4Only.length > 0) {
1036
- candidates = mp4Only;
1037
- if (debug) console.log("".concat(LOG, " forceMP4Ads: filtered to ").concat(mp4Only.length, " MP4-only file(s)"));
1038
- } else if (debug) {
1039
- console.warn("".concat(LOG, " forceMP4Ads: no MP4 files available, falling back to all media files"));
1040
- }
1041
- } else {
1042
- var mp4Only1 = candidates.filter(function(f) {
1043
- return !isHlsMediaFile(f);
1044
- });
1045
- if (mp4Only1.length > 0) {
1046
- candidates = mp4Only1;
1047
- if (debug) console.log("".concat(LOG, " Preferring ").concat(mp4Only1.length, " MP4 file(s) over HLS (mp4-first)"));
1048
- }
1049
- }
1050
- var firstFile = candidates[0];
1051
- if (candidates.length === 1) return firstFile;
1052
- var mainQuality = getMainStreamQuality();
1053
- if (!mainQuality) {
1054
- if (debug) console.log("".concat(LOG, " No main stream quality info, using first media file"));
1055
- return firstFile;
1056
- }
1057
- var scoredFiles = candidates.map(function(file) {
1058
- var widthDiff = Math.abs(file.width - mainQuality.width);
1059
- var heightDiff = Math.abs(file.height - mainQuality.height);
1060
- var resolutionDiff = widthDiff + heightDiff;
1061
- var fileBitrate = (file.bitrate || 5e3) * 1e3;
1062
- var bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);
1063
- var score = resolutionDiff * 2 + bitrateDiff / 1e3;
1064
- return {
1065
- file: file,
1066
- score: score
1067
- };
1068
- });
1069
- scoredFiles.sort(function(a, b) {
1070
- return a.score - b.score;
1071
- });
1072
- return (_ref = (_scoredFiles_ = scoredFiles[0]) === null || _scoredFiles_ === void 0 ? void 0 : _scoredFiles_.file) !== null && _ref !== void 0 ? _ref : firstFile;
1073
- }
1074
- function isHlsMediaFile(file) {
1075
- return file.type === "application/x-mpegURL" || file.type.includes("m3u8");
1076
- }
1077
- function createAdVideoElement() {
1078
- var video = document.createElement("video");
1079
- video.style.position = "absolute";
1080
- video.style.left = "0";
1081
- video.style.top = "0";
1082
- video.style.width = "100%";
1083
- video.style.height = "100%";
1084
- video.style.objectFit = "cover";
1085
- video.style.backgroundColor = "#000";
1086
- video.playsInline = true;
1087
- video.muted = false;
1088
- video.volume = 1;
1089
- return video;
1090
- }
1091
- function clearAdStallTimer() {
1092
- if (adStallTimerId != null) {
1093
- clearTimeout(adStallTimerId);
1094
- adStallTimerId = void 0;
1095
- }
1096
- }
1097
- function removeAdEventListeners() {
1098
- clearAdStallTimer();
1099
- if (!currentAdEventHandlers || !adVideoElement) return;
1100
- var el = adVideoElement;
1101
- el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1102
- el.removeEventListener("playing", currentAdEventHandlers.playing);
1103
- el.removeEventListener("ended", currentAdEventHandlers.ended);
1104
- el.removeEventListener("error", currentAdEventHandlers.error);
1105
- el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1106
- el.removeEventListener("pause", currentAdEventHandlers.pause);
1107
- el.removeEventListener("play", currentAdEventHandlers.play);
1108
- el.removeEventListener("waiting", currentAdEventHandlers.waiting);
1109
- currentAdEventHandlers = void 0;
1110
- }
1111
- function setupAdEventListeners() {
1112
- if (!adVideoElement) return;
1113
- removeAdEventListeners();
1114
- var handlers = {
1115
- timeupdate: function timeupdate() {
1116
- var ad = currentAd;
1117
- if (!ad || !adVideoElement) return;
1118
- var progress = adVideoElement.currentTime / ad.duration;
1119
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1120
- trackingFired.firstQuartile = true;
1121
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1122
- }
1123
- if (progress >= 0.5 && !trackingFired.midpoint) {
1124
- trackingFired.midpoint = true;
1125
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1126
- }
1127
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1128
- trackingFired.thirdQuartile = true;
1129
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1130
- }
1131
- },
1132
- playing: function playing() {
1133
- clearAdStallTimer();
1134
- var ad = currentAd;
1135
- if (!ad || trackingFired.start) return;
1136
- trackingFired.start = true;
1137
- fireTrackingPixels2(ad.trackingUrls.start);
1138
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1139
- },
1140
- ended: function ended() {
1141
- if (tornDown || !currentAd || trackingFired.complete) return;
1142
- trackingFired.complete = true;
1143
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1144
- if (debug) console.log("".concat(LOG, " Ad completed"));
1145
- handleAdComplete();
1146
- },
1147
- error: function error(e) {
1148
- if (tornDown) return;
1149
- console.error("".concat(LOG, " Ad video error:"), e);
1150
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1151
- handleAdError();
1152
- },
1153
- volumechange: function volumechange() {
1154
- if (!currentAd || !adVideoElement) return;
1155
- if (adVideoElement.muted) {
1156
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1157
- } else {
1158
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1159
- }
1160
- },
1161
- pause: function pause() {
1162
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1163
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1164
- }
1165
- },
1166
- play: function play() {
1167
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1168
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1169
- }
1170
- },
1171
- waiting: function waiting() {
1172
- clearAdStallTimer();
1173
- adStallTimerId = setTimeout(function() {
1174
- adStallTimerId = void 0;
1175
- if (adPlaying) {
1176
- if (debug) console.warn("".concat(LOG, " Ad video stalled for too long, treating as error"));
1177
- handleAdError();
1178
- }
1179
- }, 8e3);
1180
- }
1181
- };
1182
- adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1183
- adVideoElement.addEventListener("playing", handlers.playing);
1184
- adVideoElement.addEventListener("ended", handlers.ended);
1185
- adVideoElement.addEventListener("error", handlers.error);
1186
- adVideoElement.addEventListener("volumechange", handlers.volumechange);
1187
- adVideoElement.addEventListener("pause", handlers.pause);
1188
- adVideoElement.addEventListener("play", handlers.play);
1189
- adVideoElement.addEventListener("waiting", handlers.waiting);
1190
- currentAdEventHandlers = handlers;
1191
- }
1192
- function setAdPlayingFlag(isPlaying) {
1193
- if (isPlaying) {
1194
- contentVideo.dataset.stormcloudAdPlaying = "true";
1195
- } else {
1196
- delete contentVideo.dataset.stormcloudAdPlaying;
1197
- }
1198
- }
1199
- function applyContentVideoAdCoverStyles() {
1200
- if (!singleElementMode) return;
1201
- savedContentVideoStyles = {
1202
- objectFit: contentVideo.style.objectFit,
1203
- width: contentVideo.style.width,
1204
- height: contentVideo.style.height
1205
- };
1206
- contentVideo.style.objectFit = "cover";
1207
- contentVideo.style.width = "100%";
1208
- contentVideo.style.height = "100%";
1209
- }
1210
- function restoreContentVideoStyles() {
1211
- if (!singleElementMode || !savedContentVideoStyles) return;
1212
- contentVideo.style.objectFit = savedContentVideoStyles.objectFit;
1213
- contentVideo.style.width = savedContentVideoStyles.width;
1214
- contentVideo.style.height = savedContentVideoStyles.height;
1215
- savedContentVideoStyles = void 0;
1216
- }
1217
- function handleAdComplete() {
1218
- if (tornDown) return;
1219
- clearAdStallTimer();
1220
- if (debug) console.log("".concat(LOG, " Handling ad completion"));
1221
- adPlaying = false;
1222
- setAdPlayingFlag(false);
1223
- restoreContentVideoStyles();
1224
- if (adContainerEl) {
1225
- adContainerEl.style.display = "none";
1226
- adContainerEl.style.pointerEvents = "none";
1227
- }
1228
- emit("ad_impression");
1229
- emit("content_resume");
1230
- }
1231
- function handleAdError() {
1232
- if (tornDown) return;
1233
- if (!adPlaying) return;
1234
- clearAdStallTimer();
1235
- if (debug) console.log("".concat(LOG, " Handling ad error"));
1236
- adPlaying = false;
1237
- setAdPlayingFlag(false);
1238
- restoreContentVideoStyles();
1239
- if (adContainerEl) {
1240
- adContainerEl.style.display = "none";
1241
- adContainerEl.style.pointerEvents = "none";
1242
- }
1243
- emit("ad_error");
1244
- }
1245
- function teardownCurrentPlayback() {
1246
- removeAdEventListeners();
1247
- if (adHls) {
1248
- adHls.destroy();
1249
- adHls = void 0;
1250
- }
1251
- if (adVideoElement) {
1252
- if (singleElementMode && adVideoElement === contentVideo) {
1253
- contentVideo.pause();
1254
- } else {
1255
- adVideoElement.pause();
1256
- adVideoElement.removeAttribute("src");
1257
- adVideoElement.load();
1258
- }
1259
- }
1260
- }
1261
- function startNativePlayback(mediaFile) {
1262
- if (!adVideoElement) return;
1263
- if (debug) console.log("".concat(LOG, " Starting native MP4 playback: ").concat(mediaFile.url));
1264
- adVideoElement.src = mediaFile.url;
1265
- adVideoElement.load();
1266
- adVideoElement.play().catch(function(error) {
1267
- console.error("".concat(LOG, " Error starting native ad playback:"), error);
1268
- handleAdError();
1269
- });
1270
- }
1271
- function startHlsPlayback(mediaFile) {
1272
- if (!adVideoElement) return;
1273
- if (debug) console.log("".concat(LOG, " Starting HLS playback: ").concat(mediaFile.url));
1274
- if (Hls.isSupported()) {
1275
- if (adHls) {
1276
- adHls.destroy();
1277
- adHls = void 0;
1278
- }
1279
- adHls = new Hls({
1280
- enableWorker: true,
1281
- lowLatencyMode: false
1282
- });
1283
- adHls.loadSource(mediaFile.url);
1284
- adHls.attachMedia(adVideoElement);
1285
- adHls.on(Hls.Events.MANIFEST_PARSED, function() {
1286
- if (!adPlaying) return;
1287
- adVideoElement.play().catch(function(error) {
1288
- console.error("".concat(LOG, " Error starting HLS ad playback:"), error);
1289
- handleAdError();
1290
- });
1291
- });
1292
- var nonFatalNetworkErrors = 0;
1293
- adHls.on(Hls.Events.ERROR, function(_event, data) {
1294
- if (data.fatal) {
1295
- handleAdError();
1296
- } else if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
1297
- nonFatalNetworkErrors++;
1298
- if (nonFatalNetworkErrors >= 3) {
1299
- if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1300
- handleAdError();
1301
- }
1302
- }
1303
- });
1304
- } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1305
- adVideoElement.src = mediaFile.url;
1306
- adVideoElement.play().catch(function(error) {
1307
- console.error("".concat(LOG, " Error starting native HLS ad playback:"), error);
1308
- handleAdError();
1309
- });
1310
- } else {
1311
- console.error("".concat(LOG, " HLS not supported on this platform"));
1312
- handleAdError();
1143
+ function getDurationSecondsFromContext(requestContext) {
1144
+ var _ctx_remainingBreakSec;
1145
+ if (!requestContext || (typeof requestContext === "undefined" ? "undefined" : _type_of(requestContext)) !== "object") {
1146
+ return 30;
1313
1147
  }
1314
- }
1315
- function startPlayback(mediaFile) {
1316
- if (!adVideoElement) return;
1317
- if (singleElementMode && isHlsMediaFile(mediaFile)) {
1318
- var mp4Fallback = currentAd === null || currentAd === void 0 ? void 0 : currentAd.mediaFiles.find(function(f) {
1319
- return !isHlsMediaFile(f);
1320
- });
1321
- if (mp4Fallback) {
1322
- if (debug) console.log("".concat(LOG, " singleElementMode: HLS ad blocked, using MP4 fallback"));
1323
- startNativePlayback(mp4Fallback);
1324
- return;
1325
- }
1326
- }
1327
- if (isHlsMediaFile(mediaFile)) {
1328
- startHlsPlayback(mediaFile);
1329
- } else {
1330
- startNativePlayback(mediaFile);
1148
+ var ctx = requestContext;
1149
+ var value = (_ctx_remainingBreakSec = ctx.remainingBreakSec) !== null && _ctx_remainingBreakSec !== void 0 ? _ctx_remainingBreakSec : ctx.breakDurationSec;
1150
+ if (typeof value !== "number" || Number.isNaN(value)) {
1151
+ return 30;
1331
1152
  }
1153
+ return Math.max(1, Math.ceil(value));
1332
1154
  }
1333
- function playAd(bids) {
1155
+ function requestAdFromApi(requestContext) {
1334
1156
  return _async_to_generator(function() {
1335
- var winner, ad, contentVolume, adVolume2, mediaFile2, _contentVideo_parentElement, container, adVolume, mediaFile;
1157
+ var durationSeconds, ads;
1336
1158
  return _ts_generator(this, function(_state) {
1337
1159
  switch(_state.label){
1338
1160
  case 0:
1339
- if (destroyed) {
1340
- return [
1341
- 2,
1342
- Promise.reject(new Error("Layer has been destroyed"))
1343
- ];
1344
- }
1345
- if (bids.length === 0) {
1346
- return [
1347
- 2,
1348
- Promise.reject(new Error("No bids provided"))
1349
- ];
1350
- }
1351
- winner = bids[0];
1352
- if (debug) {
1353
- console.log("".concat(LOG, " Winning bid: ").concat(winner.bidder, " $").concat(winner.cpm.toFixed(2), " ").concat(winner.currency));
1354
- }
1161
+ durationSeconds = getDurationSecondsFromContext(requestContext);
1355
1162
  return [
1356
1163
  4,
1357
- resolveBidToVastAd(winner, LOG)
1164
+ fetchVast(durationSeconds)
1358
1165
  ];
1359
1166
  case 1:
1360
- ad = _state.sent();
1361
- if (!ad) {
1362
- if (debug) console.warn("".concat(LOG, " Winning bid has no VAST URL or XML"));
1363
- emit("ad_error");
1364
- return [
1365
- 2,
1366
- Promise.reject(new Error("No VAST from bid"))
1367
- ];
1368
- }
1369
- if (debug) {
1370
- console.log("".concat(LOG, " Ad parsed: ").concat(ad.title, ", duration: ").concat(ad.duration, "s, mediaFiles: ").concat(ad.mediaFiles.length));
1371
- }
1372
- sessionId = generateSessionId();
1373
- currentAd = ad;
1374
- trackingFired = _object_spread({}, createEmptyTrackingState());
1375
- fireTrackingPixels2(ad.trackingUrls.impression);
1376
- trackingFired.impression = true;
1377
- contentVolume = contentVideo.volume;
1378
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1379
- if (!singleElementMode) return [
1380
- 3,
1381
- 3
1382
- ];
1383
- mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1384
- teardownCurrentPlayback();
1385
- adVideoElement = contentVideo;
1386
- adHls = void 0;
1387
- adPlaying = true;
1388
- setAdPlayingFlag(true);
1389
- contentVideo.removeAttribute("src");
1390
- contentVideo.load();
1391
- if (!continueLiveStreamDuringAds) {
1392
- contentVideo.pause();
1393
- }
1394
- contentVideo.muted = true;
1395
- contentVideo.volume = 0;
1396
- return [
1397
- 4,
1398
- new Promise(function(resolve) {
1399
- return setTimeout(resolve, 200);
1400
- })
1401
- ];
1402
- case 2:
1403
- _state.sent();
1404
- if (destroyed || tornDown) return [
1405
- 2
1406
- ];
1407
- contentVideo.style.visibility = "visible";
1408
- contentVideo.style.opacity = "1";
1409
- applyContentVideoAdCoverStyles();
1410
- emit("content_pause");
1411
- setupAdEventListeners();
1412
- adVolume2 = originalMutedState ? 1 : originalVolume;
1413
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume2));
1414
- adVideoElement.muted = false;
1415
- mediaFile2 = selectBestMediaFile(ad.mediaFiles);
1416
- if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile2.url));
1417
- startPlayback(mediaFile2);
1418
- return [
1419
- 2
1420
- ];
1421
- case 3:
1422
- if (!adContainerEl) {
1423
- ;
1424
- container = document.createElement("div");
1425
- container.style.position = "absolute";
1426
- container.style.left = "0";
1427
- container.style.top = "0";
1428
- container.style.right = "0";
1429
- container.style.bottom = "0";
1430
- container.style.display = "none";
1431
- container.style.alignItems = "center";
1432
- container.style.justifyContent = "center";
1433
- container.style.pointerEvents = "none";
1434
- container.style.zIndex = "10";
1435
- container.style.backgroundColor = "#000";
1436
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1437
- adContainerEl = container;
1438
- }
1439
- if (!adVideoElement) {
1440
- adVideoElement = createAdVideoElement();
1441
- adContainerEl.appendChild(adVideoElement);
1442
- setupAdEventListeners();
1443
- } else {
1444
- teardownCurrentPlayback();
1445
- }
1446
- if (!continueLiveStreamDuringAds) {
1447
- contentVideo.pause();
1448
- }
1449
- contentVideo.muted = true;
1450
- contentVideo.volume = 0;
1451
- adPlaying = true;
1452
- setAdPlayingFlag(true);
1453
- adVolume = originalMutedState ? 1 : originalVolume;
1454
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1455
- adVideoElement.muted = false;
1456
- if (adContainerEl) {
1457
- adContainerEl.style.display = "flex";
1458
- adContainerEl.style.pointerEvents = "auto";
1459
- }
1460
- emit("content_pause");
1461
- mediaFile = selectBestMediaFile(ad.mediaFiles);
1462
- if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile.url));
1463
- startPlayback(mediaFile);
1167
+ ads = _state.sent();
1464
1168
  return [
1465
- 2
1169
+ 2,
1170
+ ads[0] || null
1466
1171
  ];
1467
1172
  }
1468
1173
  });
1469
1174
  })();
1470
1175
  }
1471
- function ensureAdContainer() {
1472
- if (!adContainerEl) {
1473
- var _contentVideo_parentElement;
1474
- var container = document.createElement("div");
1475
- container.style.position = "absolute";
1476
- container.style.left = "0";
1477
- container.style.top = "0";
1478
- container.style.right = "0";
1479
- container.style.bottom = "0";
1480
- container.style.display = "none";
1481
- container.style.alignItems = "center";
1482
- container.style.justifyContent = "center";
1483
- container.style.pointerEvents = "none";
1484
- container.style.zIndex = "10";
1485
- container.style.backgroundColor = "#000";
1486
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1487
- adContainerEl = container;
1488
- }
1489
- return adContainerEl;
1176
+ function assignCurrentAd(ad) {
1177
+ currentAd = ad;
1178
+ sessionId = generateSessionId();
1179
+ trackingFired = {
1180
+ impression: false,
1181
+ start: false,
1182
+ firstQuartile: false,
1183
+ midpoint: false,
1184
+ thirdQuartile: false,
1185
+ complete: false
1186
+ };
1187
+ fireTrackingPixels2(currentAd.trackingUrls.impression);
1188
+ trackingFired.impression = true;
1189
+ emit("ad_impression");
1490
1190
  }
1491
- function preloadAd(bids, token) {
1492
- return _async_to_generator(function() {
1493
- var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1494
- return _ts_generator(this, function(_state) {
1495
- switch(_state.label){
1496
- case 0:
1497
- if (destroyed) return [
1498
- 2
1499
- ];
1500
- winner = bids[0];
1501
- if (!winner) return [
1502
- 2
1503
- ];
1504
- if (debug) console.log("".concat(LOG, " [preload] Resolving VAST for token=").concat(token));
1505
- return [
1506
- 4,
1507
- resolveBidToVastAd(winner, LOG)
1508
- ];
1509
- case 1:
1510
- ad = _state.sent();
1511
- if (!ad || destroyed) return [
1512
- 2
1513
- ];
1514
- mediaFile = selectBestMediaFile(ad.mediaFiles);
1515
- if (!mediaFile) return [
1516
- 2
1517
- ];
1518
- if (smartTVMode || singleElementMode) {
1519
- slot = {
1520
- bids: bids,
1521
- ad: ad,
1522
- mediaFile: mediaFile,
1523
- videoEl: null,
1524
- ready: true
1525
- };
1526
- preloadSlots.set(token, slot);
1527
- if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1191
+ return {
1192
+ initialize: function initialize() {
1193
+ log("Initializing");
1194
+ if (!adContainerEl) {
1195
+ var _contentVideo_parentElement;
1196
+ var parent = contentVideo.parentElement;
1197
+ if (parent) {
1198
+ var computed = window.getComputedStyle(parent).position;
1199
+ if (computed === "static") {
1200
+ parent.style.position = "relative";
1201
+ parentPositionOverridden = true;
1202
+ }
1203
+ }
1204
+ var container = document.createElement("div");
1205
+ container.style.position = "absolute";
1206
+ container.style.left = "0";
1207
+ container.style.top = "0";
1208
+ container.style.right = "0";
1209
+ container.style.bottom = "0";
1210
+ container.style.display = "none";
1211
+ container.style.alignItems = "center";
1212
+ container.style.justifyContent = "center";
1213
+ container.style.pointerEvents = "none";
1214
+ container.style.zIndex = AD_LAYER_Z_INDEX;
1215
+ container.style.backgroundColor = "#000";
1216
+ container.style.transition = "opacity 0.3s ease-in-out";
1217
+ container.style.opacity = "0";
1218
+ container.style.isolation = "isolate";
1219
+ var countdown = document.createElement("div");
1220
+ countdown.style.position = "absolute";
1221
+ countdown.style.right = "12px";
1222
+ countdown.style.top = "12px";
1223
+ countdown.style.padding = "4px 8px";
1224
+ countdown.style.borderRadius = "4px";
1225
+ countdown.style.background = "rgba(0,0,0,0.75)";
1226
+ countdown.style.color = "#fff";
1227
+ countdown.style.fontFamily = "sans-serif";
1228
+ countdown.style.fontSize = "12px";
1229
+ countdown.style.lineHeight = "1.2";
1230
+ countdown.style.pointerEvents = "none";
1231
+ countdown.style.zIndex = COUNTDOWN_Z_INDEX;
1232
+ countdown.textContent = "Ad";
1233
+ container.appendChild(countdown);
1234
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1235
+ adContainerEl = container;
1236
+ adCountdownEl = countdown;
1237
+ }
1238
+ },
1239
+ requestAds: function requestAds(duration) {
1240
+ return _async_to_generator(function() {
1241
+ var durationSeconds, parsed, ads, error;
1242
+ return _ts_generator(this, function(_state) {
1243
+ switch(_state.label){
1244
+ case 0:
1245
+ log("Requesting ads for duration:", duration);
1246
+ if (adPlaying) {
1247
+ return [
1248
+ 2,
1249
+ Promise.reject(new Error("Ad already playing"))
1250
+ ];
1251
+ }
1252
+ if (destroyed) {
1253
+ return [
1254
+ 2,
1255
+ Promise.reject(new Error("Player has been destroyed"))
1256
+ ];
1257
+ }
1258
+ _state.label = 1;
1259
+ case 1:
1260
+ _state.trys.push([
1261
+ 1,
1262
+ 3,
1263
+ ,
1264
+ 4
1265
+ ]);
1266
+ tornDown = false;
1267
+ durationSeconds = 30;
1268
+ parsed = parseInt(duration || "", 10);
1269
+ if (!isNaN(parsed) && parsed > 0) {
1270
+ durationSeconds = parsed;
1271
+ }
1528
1272
  return [
1529
- 2
1273
+ 4,
1274
+ fetchVast(durationSeconds)
1530
1275
  ];
1531
- }
1532
- videoEl = createAdVideoElement();
1533
- videoEl.style.visibility = "hidden";
1534
- videoEl.style.pointerEvents = "none";
1535
- videoEl.preload = "auto";
1536
- container = ensureAdContainer();
1537
- container.appendChild(videoEl);
1538
- if (isHlsMediaFile(mediaFile) && Hls.isSupported()) {
1539
- hls = new Hls({
1540
- enableWorker: true,
1541
- lowLatencyMode: false
1542
- });
1543
- hls.loadSource(mediaFile.url);
1544
- hls.attachMedia(videoEl);
1545
- slot1 = {
1546
- bids: bids,
1547
- ad: ad,
1548
- mediaFile: mediaFile,
1549
- videoEl: videoEl,
1550
- hlsInstance: hls,
1551
- ready: false
1552
- };
1553
- preloadSlots.set(token, slot1);
1554
- hls.on(Hls.Events.MANIFEST_PARSED, function() {
1555
- var s = preloadSlots.get(token);
1556
- if (s) s.ready = true;
1557
- if (debug) console.log("".concat(LOG, " [preload] HLS manifest parsed, token=").concat(token));
1558
- });
1559
- hls.on(Hls.Events.ERROR, function(_evt, data) {
1560
- if (!preloadSlots.has(token)) return;
1561
- if (data.fatal) {
1562
- if (debug) console.warn("".concat(LOG, " [preload] HLS error for token=").concat(token));
1563
- preloadSlots.delete(token);
1564
- hls.destroy();
1565
- videoEl.remove();
1566
- }
1567
- });
1568
- } else {
1569
- videoEl.src = mediaFile.url;
1570
- videoEl.load();
1571
- slot2 = {
1572
- bids: bids,
1573
- ad: ad,
1574
- mediaFile: mediaFile,
1575
- videoEl: videoEl,
1576
- ready: false
1577
- };
1578
- preloadSlots.set(token, slot2);
1579
- videoEl.addEventListener("canplay", function() {
1580
- var s = preloadSlots.get(token);
1581
- if (s) s.ready = true;
1582
- if (debug) console.log("".concat(LOG, " [preload] canplay fired, token=").concat(token));
1583
- }, {
1584
- once: true
1585
- });
1586
- }
1587
- if (debug) console.log("".concat(LOG, " [preload] Started buffering token=").concat(token, ", url=").concat(mediaFile.url));
1588
- return [
1589
- 2
1590
- ];
1591
- }
1592
- });
1593
- })();
1594
- }
1595
- function playPreloaded(token) {
1596
- return _async_to_generator(function() {
1597
- var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, nonFatalNetworkErrors, adVolume, container;
1598
- return _ts_generator(this, function(_state) {
1599
- switch(_state.label){
1600
- case 0:
1601
- if (destroyed) return [
1602
- 2,
1603
- Promise.reject(new Error("Layer has been destroyed"))
1604
- ];
1605
- slot = preloadSlots.get(token);
1606
- if (!slot) {
1607
- if (debug) console.warn("".concat(LOG, " [preload] No slot found for token=").concat(token, ", nothing to play"));
1276
+ case 2:
1277
+ ads = _state.sent();
1278
+ if (ads.length === 0) {
1279
+ log("No ads available from VAST response");
1280
+ emit("ad_error");
1281
+ return [
1282
+ 2,
1283
+ Promise.resolve()
1284
+ ];
1285
+ }
1286
+ assignCurrentAd(ads[0]);
1287
+ log("Ad loaded: ".concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1288
+ return [
1289
+ 2,
1290
+ Promise.resolve()
1291
+ ];
1292
+ case 3:
1293
+ error = _state.sent();
1294
+ console.error("[AdStormPlayer] Error requesting ads:", error);
1295
+ emit("ad_error");
1296
+ return [
1297
+ 2,
1298
+ Promise.reject(error)
1299
+ ];
1300
+ case 4:
1608
1301
  return [
1609
1302
  2
1610
1303
  ];
1611
- }
1612
- preloadSlots.delete(token);
1613
- if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1614
- contentVolume = contentVideo.volume;
1615
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1616
- sessionId = generateSessionId();
1617
- currentAd = slot.ad;
1618
- trackingFired = _object_spread({}, createEmptyTrackingState());
1619
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1620
- trackingFired.impression = true;
1621
- if (!singleElementMode) return [
1622
- 3,
1623
- 2
1624
- ];
1625
- mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1626
- teardownCurrentPlayback();
1627
- adVideoElement = contentVideo;
1628
- adHls = void 0;
1629
- adPlaying = true;
1630
- setAdPlayingFlag(true);
1631
- contentVideo.removeAttribute("src");
1632
- contentVideo.load();
1633
- contentVideo.muted = true;
1634
- contentVideo.volume = 0;
1635
- return [
1636
- 4,
1637
- new Promise(function(resolve) {
1638
- return setTimeout(resolve, 200);
1639
- })
1640
- ];
1641
- case 1:
1642
- _state.sent();
1643
- if (destroyed || tornDown) return [
1644
- 2
1645
- ];
1646
- contentVideo.style.visibility = "visible";
1647
- contentVideo.style.opacity = "1";
1648
- applyContentVideoAdCoverStyles();
1649
- emit("content_pause");
1650
- setupAdEventListeners();
1651
- adVolume2 = originalMutedState ? 1 : originalVolume;
1652
- contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1653
- contentVideo.muted = false;
1654
- if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1655
- startPlayback(slot.mediaFile);
1656
- return [
1657
- 2
1658
- ];
1659
- case 2:
1660
- if (smartTVMode && !slot.videoEl) {
1661
- teardownCurrentPlayback();
1662
- if (adVideoElement) {
1663
- adVideoElement.remove();
1664
- adVideoElement = void 0;
1304
+ }
1305
+ });
1306
+ })();
1307
+ },
1308
+ play: function play() {
1309
+ return _async_to_generator(function() {
1310
+ var mediaFile, error;
1311
+ return _ts_generator(this, function(_state) {
1312
+ switch(_state.label){
1313
+ case 0:
1314
+ if (!currentAd) {
1315
+ return [
1316
+ 2,
1317
+ Promise.reject(new Error("No ad loaded"))
1318
+ ];
1319
+ }
1320
+ if (destroyed) {
1321
+ return [
1322
+ 2,
1323
+ Promise.reject(new Error("Player has been destroyed"))
1324
+ ];
1325
+ }
1326
+ log("Starting ad playback");
1327
+ _state.label = 1;
1328
+ case 1:
1329
+ _state.trys.push([
1330
+ 1,
1331
+ 3,
1332
+ ,
1333
+ 4
1334
+ ]);
1335
+ tornDown = false;
1336
+ if (adHideTimerId) {
1337
+ clearTimeout(adHideTimerId);
1338
+ adHideTimerId = void 0;
1339
+ }
1340
+ if (!adVideoElement) {
1341
+ adVideoElement = createAdVideoElement();
1342
+ adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1343
+ } else {
1344
+ teardownCurrentPlayback();
1665
1345
  }
1666
- videoEl = createAdVideoElement();
1667
- videoEl.style.visibility = "visible";
1668
- videoEl.style.pointerEvents = "none";
1669
- container2 = ensureAdContainer();
1670
- container2.appendChild(videoEl);
1671
- adVideoElement = videoEl;
1672
1346
  setupAdEventListeners();
1347
+ trackingFired = {
1348
+ impression: trackingFired.impression,
1349
+ start: false,
1350
+ firstQuartile: false,
1351
+ midpoint: false,
1352
+ thirdQuartile: false,
1353
+ complete: false
1354
+ };
1355
+ contentVideo.style.transition = "opacity 0.3s ease-in-out";
1356
+ contentVideo.style.opacity = "0";
1357
+ setTimeout(function() {
1358
+ contentVideo.style.visibility = "hidden";
1359
+ }, 300);
1360
+ contentVideo.muted = true;
1361
+ contentVideo.volume = 0;
1673
1362
  if (!continueLiveStreamDuringAds) {
1674
1363
  contentVideo.pause();
1675
1364
  }
1676
- contentVideo.muted = true;
1677
- contentVideo.volume = 0;
1678
1365
  adPlaying = true;
1679
1366
  setAdPlayingFlag(true);
1680
- adVolume21 = originalMutedState ? 1 : originalVolume;
1681
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1682
- adVideoElement.muted = false;
1683
- container2.style.display = "flex";
1684
- container2.style.pointerEvents = "auto";
1367
+ if (adVideoElement) {
1368
+ adVideoElement.volume = originalMutedState ? 0 : originalVolume;
1369
+ adVideoElement.muted = originalMutedState;
1370
+ }
1371
+ if (adContainerEl) {
1372
+ adContainerEl.style.display = "flex";
1373
+ adContainerEl.style.pointerEvents = "auto";
1374
+ adContainerEl.offsetHeight;
1375
+ adContainerEl.style.opacity = "1";
1376
+ }
1685
1377
  emit("content_pause");
1686
- if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1687
- startPlayback(slot.mediaFile);
1378
+ mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1379
+ if (!mediaFile) {
1380
+ throw new Error("No media file available");
1381
+ }
1382
+ log("Playing media file:", mediaFile.url);
1383
+ adVideoElement.src = mediaFile.url;
1384
+ adVideoElement.load();
1688
1385
  return [
1689
- 2
1386
+ 4,
1387
+ adVideoElement.play()
1690
1388
  ];
1691
- }
1692
- teardownCurrentPlayback();
1693
- if (adVideoElement && adVideoElement !== slot.videoEl) {
1694
- adVideoElement.remove();
1695
- }
1696
- slot.videoEl.style.visibility = "visible";
1697
- slot.videoEl.style.pointerEvents = "none";
1698
- adVideoElement = slot.videoEl;
1699
- adHls = slot.hlsInstance;
1700
- if (adHls) {
1701
- nonFatalNetworkErrors = 0;
1702
- adHls.on(Hls.Events.ERROR, function(_event, data) {
1703
- if (!adPlaying) return;
1704
- if (data.fatal) {
1705
- handleAdError();
1706
- } else if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
1707
- nonFatalNetworkErrors++;
1708
- if (nonFatalNetworkErrors >= 3) {
1709
- if (debug) console.warn("".concat(LOG, " [preload] Too many non-fatal HLS network errors during playback, treating as fatal"));
1710
- handleAdError();
1711
- }
1712
- }
1713
- });
1714
- }
1715
- setupAdEventListeners();
1716
- if (!continueLiveStreamDuringAds) {
1717
- contentVideo.pause();
1718
- }
1719
- contentVideo.muted = true;
1720
- contentVideo.volume = 0;
1721
- adPlaying = true;
1722
- setAdPlayingFlag(true);
1723
- adVolume = originalMutedState ? 1 : originalVolume;
1724
- adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1725
- adVideoElement.muted = false;
1726
- container = ensureAdContainer();
1727
- container.style.display = "flex";
1728
- container.style.pointerEvents = "auto";
1729
- emit("content_pause");
1730
- adVideoElement.play().catch(function(error) {
1731
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1389
+ case 2:
1390
+ _state.sent();
1391
+ return [
1392
+ 2,
1393
+ Promise.resolve()
1394
+ ];
1395
+ case 3:
1396
+ error = _state.sent();
1397
+ console.error("[AdStormPlayer] Error playing ad:", error);
1732
1398
  handleAdError();
1733
- });
1734
- return [
1735
- 2
1736
- ];
1737
- }
1738
- });
1739
- })();
1740
- }
1741
- function cancelPreload(token) {
1742
- var slot = preloadSlots.get(token);
1743
- if (!slot) return;
1744
- preloadSlots.delete(token);
1745
- if (slot.hlsInstance) {
1746
- slot.hlsInstance.destroy();
1747
- }
1748
- if (slot.videoEl) {
1749
- slot.videoEl.pause();
1750
- slot.videoEl.removeAttribute("src");
1751
- slot.videoEl.load();
1752
- slot.videoEl.remove();
1753
- }
1754
- if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1755
- }
1756
- return {
1757
- initialize: function initialize() {
1758
- if (debug) console.log("".concat(LOG, " Initializing"));
1759
- },
1760
- updateOptions: function updateOptions(opts) {
1761
- if (opts.continueLiveStreamDuringAds !== void 0) {
1762
- continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;
1763
- }
1764
- if (opts.mainHlsInstance !== void 0) {
1765
- var _opts_mainHlsInstance;
1766
- mainHlsInstance = (_opts_mainHlsInstance = opts.mainHlsInstance) !== null && _opts_mainHlsInstance !== void 0 ? _opts_mainHlsInstance : void 0;
1767
- }
1768
- },
1769
- playAd: playAd,
1770
- preloadAd: preloadAd,
1771
- playPreloaded: playPreloaded,
1772
- hasPreloaded: function hasPreloaded(token) {
1773
- return preloadSlots.has(token);
1774
- },
1775
- cancelPreload: cancelPreload,
1776
- pause: function pause() {
1777
- if (!adPlaying || !adVideoElement) return;
1778
- try {
1779
- if (!adVideoElement.paused) adVideoElement.pause();
1780
- } catch (error) {
1781
- if (debug) console.warn("".concat(LOG, " Error pausing ad:"), error);
1782
- }
1783
- },
1784
- resume: function resume() {
1785
- if (!adPlaying || !adVideoElement) return;
1786
- try {
1787
- if (adVideoElement.paused) adVideoElement.play().catch(function() {});
1788
- } catch (error) {
1789
- if (debug) console.warn("".concat(LOG, " Error resuming ad:"), error);
1790
- }
1399
+ return [
1400
+ 2,
1401
+ Promise.reject(error)
1402
+ ];
1403
+ case 4:
1404
+ return [
1405
+ 2
1406
+ ];
1407
+ }
1408
+ });
1409
+ })();
1791
1410
  },
1792
1411
  stop: function stop() {
1793
1412
  return _async_to_generator(function() {
1794
1413
  return _ts_generator(this, function(_state) {
1414
+ log("Stopping ad");
1795
1415
  tornDown = true;
1796
- if (debug) console.log("".concat(LOG, " Stopping ad"));
1797
1416
  adPlaying = false;
1798
1417
  setAdPlayingFlag(false);
1799
- restoreContentVideoStyles();
1800
- contentVideo.muted = originalMutedState;
1801
- contentVideo.volume = originalMutedState ? 0 : originalVolume;
1418
+ clearAdStallTimer();
1419
+ clearAdCountdownTimer();
1420
+ if (adContainerEl) {
1421
+ adContainerEl.style.opacity = "0";
1422
+ adHideTimerId = setTimeout(function() {
1423
+ if (adContainerEl) {
1424
+ adContainerEl.style.display = "none";
1425
+ adContainerEl.style.pointerEvents = "none";
1426
+ }
1427
+ }, 300);
1428
+ }
1429
+ teardownCurrentPlayback();
1802
1430
  contentVideo.style.visibility = "visible";
1803
1431
  contentVideo.style.opacity = "1";
1804
- if (singleElementMode) {
1805
- teardownCurrentPlayback();
1806
- contentVideo.removeAttribute("src");
1807
- contentVideo.load();
1808
- adVideoElement = void 0;
1809
- } else {
1810
- if (adContainerEl) {
1811
- adContainerEl.style.display = "none";
1812
- adContainerEl.style.pointerEvents = "none";
1813
- }
1814
- if (continueLiveStreamDuringAds) {
1815
- contentVideo.play().catch(function() {});
1816
- }
1817
- teardownCurrentPlayback();
1818
- if (adVideoElement) {
1819
- adVideoElement.pause();
1820
- adVideoElement.removeAttribute("src");
1821
- adVideoElement.load();
1822
- }
1823
- }
1432
+ contentVideo.muted = originalMutedState;
1433
+ contentVideo.volume = originalVolume;
1824
1434
  currentAd = void 0;
1825
1435
  tornDown = false;
1826
1436
  return [
1827
- 2
1437
+ 2,
1438
+ Promise.resolve()
1828
1439
  ];
1829
1440
  });
1830
1441
  })();
1831
1442
  },
1443
+ pause: function pause() {
1444
+ if (!adPlaying || !adVideoElement) return;
1445
+ try {
1446
+ if (!adVideoElement.paused) adVideoElement.pause();
1447
+ } catch (error) {
1448
+ console.warn("[AdStormPlayer] Error pausing ad:", error);
1449
+ }
1450
+ },
1451
+ resume: function resume() {
1452
+ if (!adPlaying || !adVideoElement) return;
1453
+ try {
1454
+ if (adVideoElement.paused) adVideoElement.play().catch(function() {});
1455
+ } catch (error) {
1456
+ console.warn("[AdStormPlayer] Error resuming ad:", error);
1457
+ }
1458
+ },
1832
1459
  destroy: function destroy() {
1833
- tornDown = true;
1834
- if (debug) console.log("".concat(LOG, " Destroying"));
1460
+ log("Destroying");
1835
1461
  destroyed = true;
1462
+ tornDown = true;
1836
1463
  adPlaying = false;
1837
1464
  setAdPlayingFlag(false);
1838
- restoreContentVideoStyles();
1465
+ clearAdStallTimer();
1466
+ clearAdCountdownTimer();
1467
+ if (adHideTimerId) {
1468
+ clearTimeout(adHideTimerId);
1469
+ adHideTimerId = void 0;
1470
+ }
1839
1471
  contentVideo.muted = originalMutedState;
1840
1472
  contentVideo.volume = originalVolume;
1841
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1842
- try {
1843
- for(var _iterator = Array.from(preloadSlots.entries())[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1844
- var _step_value = _sliced_to_array(_step.value, 1), token = _step_value[0];
1845
- cancelPreload(token);
1846
- }
1847
- } catch (err) {
1848
- _didIteratorError = true;
1849
- _iteratorError = err;
1850
- } finally{
1851
- try {
1852
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1853
- _iterator.return();
1854
- }
1855
- } finally{
1856
- if (_didIteratorError) {
1857
- throw _iteratorError;
1858
- }
1859
- }
1860
- }
1473
+ contentVideo.style.visibility = "visible";
1474
+ contentVideo.style.opacity = "1";
1861
1475
  teardownCurrentPlayback();
1862
- if (adVideoElement) {
1863
- if (singleElementMode && adVideoElement === contentVideo) {
1864
- contentVideo.removeAttribute("src");
1865
- contentVideo.load();
1866
- } else {
1867
- adVideoElement.pause();
1868
- adVideoElement.removeAttribute("src");
1869
- adVideoElement.remove();
1870
- }
1871
- adVideoElement = void 0;
1872
- }
1476
+ adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.remove();
1477
+ adVideoElement = void 0;
1873
1478
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
1874
1479
  adContainerEl.parentElement.removeChild(adContainerEl);
1875
1480
  }
1876
1481
  adContainerEl = void 0;
1482
+ adCountdownEl = void 0;
1877
1483
  currentAd = void 0;
1484
+ sessionId = void 0;
1485
+ preloadSlots.clear();
1878
1486
  listeners.clear();
1487
+ if (parentPositionOverridden && contentVideo.parentElement) {
1488
+ contentVideo.parentElement.style.position = "";
1489
+ parentPositionOverridden = false;
1490
+ }
1491
+ },
1492
+ updateOptions: function updateOptions(opts) {
1493
+ if (opts.continueLiveStreamDuringAds !== void 0) {
1494
+ continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;
1495
+ }
1496
+ },
1497
+ playAd: function playAd(requestContext) {
1498
+ return _async_to_generator(function() {
1499
+ var ad;
1500
+ return _ts_generator(this, function(_state) {
1501
+ switch(_state.label){
1502
+ case 0:
1503
+ if (destroyed) return [
1504
+ 2,
1505
+ Promise.reject(new Error("Player has been destroyed"))
1506
+ ];
1507
+ if (!!currentAd) return [
1508
+ 3,
1509
+ 2
1510
+ ];
1511
+ return [
1512
+ 4,
1513
+ requestAdFromApi(requestContext)
1514
+ ];
1515
+ case 1:
1516
+ ad = _state.sent();
1517
+ if (!ad) {
1518
+ emit("ad_error", {
1519
+ message: "No valid ad from AdStorm API"
1520
+ });
1521
+ return [
1522
+ 2,
1523
+ Promise.reject(new Error("No valid ad from AdStorm API"))
1524
+ ];
1525
+ }
1526
+ assignCurrentAd(ad);
1527
+ _state.label = 2;
1528
+ case 2:
1529
+ return [
1530
+ 2,
1531
+ this.play()
1532
+ ];
1533
+ }
1534
+ });
1535
+ }).call(this);
1536
+ },
1537
+ preloadAd: function preloadAd(arg1, arg2) {
1538
+ return _async_to_generator(function() {
1539
+ var token, requestContext, ad;
1540
+ return _ts_generator(this, function(_state) {
1541
+ switch(_state.label){
1542
+ case 0:
1543
+ if (destroyed) return [
1544
+ 2
1545
+ ];
1546
+ token = typeof arg1 === "string" ? arg1 : typeof arg2 === "string" ? arg2 : void 0;
1547
+ if (!token) return [
1548
+ 2
1549
+ ];
1550
+ requestContext = typeof arg1 === "string" ? arg2 : arg1;
1551
+ return [
1552
+ 4,
1553
+ requestAdFromApi(requestContext)
1554
+ ];
1555
+ case 1:
1556
+ ad = _state.sent();
1557
+ if (!ad) return [
1558
+ 2
1559
+ ];
1560
+ preloadSlots.set(token, {
1561
+ ad: ad
1562
+ });
1563
+ return [
1564
+ 2
1565
+ ];
1566
+ }
1567
+ });
1568
+ })();
1569
+ },
1570
+ playPreloaded: function playPreloaded(token) {
1571
+ return _async_to_generator(function() {
1572
+ var slot;
1573
+ return _ts_generator(this, function(_state) {
1574
+ if (destroyed) return [
1575
+ 2,
1576
+ Promise.reject(new Error("Player has been destroyed"))
1577
+ ];
1578
+ slot = preloadSlots.get(token);
1579
+ if (!slot) {
1580
+ return [
1581
+ 2,
1582
+ Promise.reject(new Error("No preloaded ad for token ".concat(token)))
1583
+ ];
1584
+ }
1585
+ preloadSlots.delete(token);
1586
+ assignCurrentAd(slot.ad);
1587
+ return [
1588
+ 2,
1589
+ this.play()
1590
+ ];
1591
+ });
1592
+ }).call(this);
1593
+ },
1594
+ hasPreloaded: function hasPreloaded(token) {
1595
+ return preloadSlots.has(token);
1596
+ },
1597
+ cancelPreload: function cancelPreload(token) {
1598
+ preloadSlots.delete(token);
1879
1599
  },
1880
1600
  isAdPlaying: function isAdPlaying() {
1881
1601
  return adPlaying;
1882
1602
  },
1883
1603
  resize: function resize(width, height) {
1604
+ log("Resizing to ".concat(width, "x").concat(height));
1884
1605
  if (adContainerEl) {
1885
1606
  adContainerEl.style.width = "".concat(width, "px");
1886
1607
  adContainerEl.style.height = "".concat(height, "px");
@@ -1900,6 +1621,7 @@ function createVastAdLayer(contentVideo, options) {
1900
1621
  },
1901
1622
  updateOriginalMutedState: function updateOriginalMutedState(muted, volume) {
1902
1623
  var nextVolume = typeof volume === "number" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;
1624
+ log("updateOriginalMutedState: muted=".concat(muted, ", volume=").concat(nextVolume));
1903
1625
  originalMutedState = muted;
1904
1626
  originalVolume = nextVolume;
1905
1627
  },
@@ -1912,6 +1634,7 @@ function createVastAdLayer(contentVideo, options) {
1912
1634
  setAdVolume: function setAdVolume(volume) {
1913
1635
  if (adVideoElement && adPlaying) {
1914
1636
  adVideoElement.volume = Math.max(0, Math.min(1, volume));
1637
+ adVideoElement.muted = volume === 0;
1915
1638
  }
1916
1639
  },
1917
1640
  getAdVolume: function getAdVolume() {
@@ -1921,11 +1644,16 @@ function createVastAdLayer(contentVideo, options) {
1921
1644
  return 1;
1922
1645
  },
1923
1646
  showPlaceholder: function showPlaceholder() {
1924
- if (singleElementMode) return;
1925
- contentVideo.style.opacity = "0";
1926
- contentVideo.style.visibility = "hidden";
1927
1647
  if (!adContainerEl) {
1928
1648
  var _contentVideo_parentElement;
1649
+ var parent = contentVideo.parentElement;
1650
+ if (parent) {
1651
+ var computed = window.getComputedStyle(parent).position;
1652
+ if (computed === "static") {
1653
+ parent.style.position = "relative";
1654
+ parentPositionOverridden = true;
1655
+ }
1656
+ }
1929
1657
  var container = document.createElement("div");
1930
1658
  container.style.position = "absolute";
1931
1659
  container.style.left = "0";
@@ -1936,24 +1664,43 @@ function createVastAdLayer(contentVideo, options) {
1936
1664
  container.style.alignItems = "center";
1937
1665
  container.style.justifyContent = "center";
1938
1666
  container.style.pointerEvents = "none";
1939
- container.style.zIndex = "10";
1667
+ container.style.zIndex = AD_LAYER_Z_INDEX;
1940
1668
  container.style.backgroundColor = "#000";
1669
+ container.style.isolation = "isolate";
1670
+ var countdown = document.createElement("div");
1671
+ countdown.style.position = "absolute";
1672
+ countdown.style.right = "12px";
1673
+ countdown.style.top = "12px";
1674
+ countdown.style.padding = "4px 8px";
1675
+ countdown.style.borderRadius = "4px";
1676
+ countdown.style.background = "rgba(0,0,0,0.75)";
1677
+ countdown.style.color = "#fff";
1678
+ countdown.style.fontFamily = "sans-serif";
1679
+ countdown.style.fontSize = "12px";
1680
+ countdown.style.lineHeight = "1.2";
1681
+ countdown.style.pointerEvents = "none";
1682
+ countdown.style.zIndex = COUNTDOWN_Z_INDEX;
1683
+ countdown.textContent = "Ad";
1684
+ container.appendChild(countdown);
1941
1685
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1942
1686
  adContainerEl = container;
1687
+ adCountdownEl = countdown;
1943
1688
  }
1944
1689
  if (adContainerEl) {
1945
1690
  adContainerEl.style.display = "flex";
1691
+ adContainerEl.style.opacity = "1";
1946
1692
  adContainerEl.style.pointerEvents = "auto";
1947
1693
  }
1948
1694
  },
1949
1695
  hidePlaceholder: function hidePlaceholder() {
1950
1696
  if (adContainerEl) {
1951
- adContainerEl.style.display = "none";
1952
- adContainerEl.style.pointerEvents = "none";
1953
- }
1954
- if (!adPlaying) {
1955
- contentVideo.style.visibility = "visible";
1956
- contentVideo.style.opacity = "1";
1697
+ adContainerEl.style.opacity = "0";
1698
+ setTimeout(function() {
1699
+ if (adContainerEl) {
1700
+ adContainerEl.style.display = "none";
1701
+ adContainerEl.style.pointerEvents = "none";
1702
+ }
1703
+ }, 300);
1957
1704
  }
1958
1705
  }
1959
1706
  };
@@ -3084,6 +2831,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3084
2831
  this.backoffBaseMs = 1e3;
3085
2832
  this.maxBackoffMs = 15e3;
3086
2833
  this.MIN_AD_REMAINING_MS = 15e3;
2834
+ this.adRequestTimeoutMs = 5e3;
2835
+ this.adRequestMaxRetries = 3;
2836
+ this.adRequestRetryBackoffMs = 1500;
3087
2837
  this.preloadedTokens = [];
3088
2838
  initializePolyfills();
3089
2839
  var browserOverrides = getBrowserConfigOverrides();
@@ -3091,24 +2841,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3091
2841
  this.video = config.videoElement;
3092
2842
  this.adTransitionGapMs = (_this_config_adTransitionGapMs = this.config.adTransitionGapMs) !== null && _this_config_adTransitionGapMs !== void 0 ? _this_config_adTransitionGapMs : 100;
3093
2843
  logBrowserInfo(config.debugAdTiming);
3094
- this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
3095
- debug: !!config.debugAdTiming
3096
- } : {});
3097
2844
  var browserForAdLayer = detectBrowser();
3098
2845
  var isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;
3099
- this.adLayer = createVastAdLayer(this.video, {
3100
- continueLiveStreamDuringAds: false,
3101
- smartTVMode: isSinglePipeline,
3102
- singleElementMode: isSinglePipeline,
3103
- forceMP4Ads: isSinglePipeline,
2846
+ this.adLayer = createAdStormPlayer(this.video, {
2847
+ licenseKey: this.config.licenseKey || "",
3104
2848
  debug: !!config.debugAdTiming
3105
2849
  });
2850
+ this.adLayer.updateOptions({
2851
+ continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds()
2852
+ });
3106
2853
  }
3107
2854
  _create_class(StormcloudVideoPlayer, [
3108
2855
  {
3109
2856
  key: "adRequest",
3110
2857
  value: function adRequest(context) {
3111
2858
  return _async_to_generator(function() {
2859
+ var _ref, _ref1, durationSeconds;
3112
2860
  return _ts_generator(this, function(_state) {
3113
2861
  switch(_state.label){
3114
2862
  case 0:
@@ -3116,15 +2864,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3116
2864
  2,
3117
2865
  []
3118
2866
  ];
2867
+ 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));
3119
2868
  return [
3120
2869
  4,
3121
- this.vastManager.initialize()
2870
+ this.adLayer.requestAds(String(durationSeconds))
3122
2871
  ];
3123
2872
  case 1:
3124
2873
  _state.sent();
3125
2874
  return [
3126
2875
  2,
3127
- this.vastManager.requestBidsUntilResponse(context)
2876
+ [
2877
+ {
2878
+ bidder: "adstorm-direct",
2879
+ cpm: 0,
2880
+ width: 0,
2881
+ height: 0,
2882
+ adId: "adstorm",
2883
+ impId: "",
2884
+ creativeId: "adstorm",
2885
+ currency: "USD",
2886
+ durationSec: durationSeconds
2887
+ }
2888
+ ]
3128
2889
  ];
3129
2890
  }
3130
2891
  });
@@ -3181,7 +2942,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3181
2942
  2
3182
2943
  ];
3183
2944
  case 3:
3184
- this.hls = new Hls2(_object_spread_props(_object_spread({
2945
+ this.hls = new Hls(_object_spread_props(_object_spread({
3185
2946
  enableWorker: true,
3186
2947
  backBufferLength: 30,
3187
2948
  liveDurationInfinity: true,
@@ -3199,11 +2960,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3199
2960
  nudgeMaxRetry: 3,
3200
2961
  startPosition: -1
3201
2962
  }));
3202
- this.hls.on(Hls2.Events.MEDIA_ATTACHED, function() {
2963
+ this.hls.on(Hls.Events.MEDIA_ATTACHED, function() {
3203
2964
  var _this_hls;
3204
2965
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.loadSource(_this.config.src);
3205
2966
  });
3206
- this.hls.on(Hls2.Events.MANIFEST_PARSED, function(_, data) {
2967
+ this.hls.on(Hls.Events.MANIFEST_PARSED, function(_, data) {
3207
2968
  return _async_to_generator(function() {
3208
2969
  var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, _this_hls1, minSegments, _this_video_play;
3209
2970
  return _ts_generator(this, function(_state) {
@@ -3265,7 +3026,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3265
3026
  });
3266
3027
  }).call(_this);
3267
3028
  });
3268
- this.hls.on(Hls2.Events.LEVEL_LOADED, function(_evt, data) {
3029
+ this.hls.on(Hls.Events.LEVEL_LOADED, function(_evt, data) {
3269
3030
  if (_this.inAdBreak || _this.pendingAdBreak) {
3270
3031
  return;
3271
3032
  }
@@ -3338,7 +3099,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3338
3099
  }
3339
3100
  }
3340
3101
  });
3341
- this.hls.on(Hls2.Events.FRAG_BUFFERED, function(_evt, data) {
3102
+ this.hls.on(Hls.Events.FRAG_BUFFERED, function(_evt, data) {
3342
3103
  return _async_to_generator(function() {
3343
3104
  var _this, _this_config_minSegmentsBeforePlay, minSegments, _this_video_play;
3344
3105
  return _ts_generator(this, function(_state) {
@@ -3398,7 +3159,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3398
3159
  });
3399
3160
  }).call(_this);
3400
3161
  });
3401
- this.hls.on(Hls2.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3162
+ this.hls.on(Hls.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3402
3163
  var id3Tags = ((data === null || data === void 0 ? void 0 : data.samples) || []).map(function(s) {
3403
3164
  return {
3404
3165
  key: "ID3",
@@ -3410,7 +3171,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3410
3171
  return _this.onId3Tag(tag);
3411
3172
  });
3412
3173
  });
3413
- this.hls.on(Hls2.Events.FRAG_CHANGED, function(_evt, data) {
3174
+ this.hls.on(Hls.Events.FRAG_CHANGED, function(_evt, data) {
3414
3175
  var frag = data === null || data === void 0 ? void 0 : data.frag;
3415
3176
  var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3416
3177
  if (!Array.isArray(tagList)) return;
@@ -3519,14 +3280,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3519
3280
  }
3520
3281
  }
3521
3282
  });
3522
- this.hls.on(Hls2.Events.ERROR, function(_evt, data) {
3283
+ this.hls.on(Hls.Events.ERROR, function(_evt, data) {
3523
3284
  if (data === null || data === void 0 ? void 0 : data.fatal) {
3524
3285
  switch(data.type){
3525
- case Hls2.ErrorTypes.NETWORK_ERROR:
3286
+ case Hls.ErrorTypes.NETWORK_ERROR:
3526
3287
  var _this_hls;
3527
3288
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.startLoad();
3528
3289
  break;
3529
- case Hls2.ErrorTypes.MEDIA_ERROR:
3290
+ case Hls.ErrorTypes.MEDIA_ERROR:
3530
3291
  var _this_hls1;
3531
3292
  (_this_hls1 = _this.hls) === null || _this_hls1 === void 0 ? void 0 : _this_hls1.recoverMediaError();
3532
3293
  break;
@@ -3618,7 +3379,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3618
3379
  }
3619
3380
  });
3620
3381
  this.adLayer.on("content_resume", function() {
3382
+ var _ref, _ref1;
3383
+ var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
3621
3384
  var remaining = _this.getRemainingAdMs();
3385
+ 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();
3386
+ 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();
3622
3387
  if (_this.config.debugAdTiming) {
3623
3388
  console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s", _this.inAdBreak, remaining, _this.preloadedTokens.length, !!_this.pendingNextAdBids);
3624
3389
  }
@@ -3633,7 +3398,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3633
3398
  return;
3634
3399
  }
3635
3400
  _this.consecutiveFailures = 0;
3636
- if (!_this.video.muted) {
3401
+ if (!_this.config.disableFiller && !_this.video.muted) {
3637
3402
  _this.video.muted = true;
3638
3403
  _this.video.volume = 0;
3639
3404
  }
@@ -3700,6 +3465,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3700
3465
  if (!_this.config.disableFiller) {
3701
3466
  _this.showPlaceholderLayer();
3702
3467
  _this.adLayer.showPlaceholder();
3468
+ } else {
3469
+ _this.adLayer.hidePlaceholder();
3470
+ if (_this.video.muted !== breakMuted) {
3471
+ _this.video.muted = breakMuted;
3472
+ }
3473
+ if (Math.abs(_this.video.volume - breakVolume) > 0.01) {
3474
+ _this.video.volume = breakVolume;
3475
+ }
3476
+ if (_this.video.paused) {
3477
+ var _this_video_play;
3478
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3479
+ }
3703
3480
  }
3704
3481
  _this.stopContinuousFetching();
3705
3482
  return;
@@ -4427,6 +4204,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4427
4204
  return this.totalAdsInBreak;
4428
4205
  }
4429
4206
  },
4207
+ {
4208
+ key: "getRemainingAdSeconds",
4209
+ value: function getRemainingAdSeconds() {
4210
+ var remainingMs = this.getRemainingAdMs();
4211
+ if (!Number.isFinite(remainingMs) || remainingMs <= 0 || remainingMs === Number.MAX_SAFE_INTEGER) {
4212
+ return 0;
4213
+ }
4214
+ return Math.ceil(remainingMs / 1e3);
4215
+ }
4216
+ },
4430
4217
  {
4431
4218
  key: "isAdPlaying",
4432
4219
  value: function isAdPlaying() {
@@ -5656,7 +5443,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5656
5443
  });
5657
5444
  };
5658
5445
  var onManifestParsedRestore = function onManifestParsedRestore1() {
5659
- hlsRef.off(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5446
+ hlsRef.off(Hls.Events.MANIFEST_PARSED, onManifestParsedRestore);
5660
5447
  if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5661
5448
  if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;
5662
5449
  if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;
@@ -5669,7 +5456,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5669
5456
  }
5670
5457
  }
5671
5458
  };
5672
- hlsRef.on(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5459
+ hlsRef.on(Hls.Events.MANIFEST_PARSED, onManifestParsedRestore);
5673
5460
  var pipelineDelayMs = 300;
5674
5461
  if (debugEnabled) {
5675
5462
  console.log("[StormcloudVideoPlayer] Smart TV: waiting ".concat(pipelineDelayMs, "ms for hardware pipeline release before re-attach"));
@@ -7283,7 +7070,8 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
7283
7070
  var _React2_useState = _sliced_to_array(React2.useState({
7284
7071
  showAds: false,
7285
7072
  currentIndex: 0,
7286
- totalAds: 0
7073
+ totalAds: 0,
7074
+ remainingSeconds: 0
7287
7075
  }), 2), adStatus = _React2_useState[0], setAdStatus = _React2_useState[1];
7288
7076
  var _React2_useState1 = _sliced_to_array(React2.useState(true), 2), shouldShowNativeControls = _React2_useState1[0], setShouldShowNativeControls = _React2_useState1[1];
7289
7077
  var _React2_useState2 = _sliced_to_array(React2.useState(false), 2), isMuted = _React2_useState2[0], setIsMuted = _React2_useState2[1];
@@ -7535,15 +7323,17 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
7535
7323
  var showAds = showAdsFromMethod || showAdsFromAttribute;
7536
7324
  var currentIndex = playerRef.current.getCurrentAdIndex();
7537
7325
  var totalAds = playerRef.current.getTotalAdsInBreak();
7326
+ var remainingSeconds = playerRef.current.getRemainingAdSeconds();
7538
7327
  setAdStatus(function(prev) {
7539
- if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds) {
7328
+ if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds || prev.remainingSeconds !== remainingSeconds) {
7540
7329
  if (showAds && !prev.showAds) {
7541
7330
  setShowCenterPlay(false);
7542
7331
  }
7543
7332
  return {
7544
7333
  showAds: showAds,
7545
7334
  currentIndex: currentIndex,
7546
- totalAds: totalAds
7335
+ totalAds: totalAds,
7336
+ remainingSeconds: remainingSeconds
7547
7337
  };
7548
7338
  }
7549
7339
  return prev;
@@ -7933,6 +7723,22 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
7933
7723
  " of ",
7934
7724
  Math.max(adStatus.totalAds, adStatus.currentIndex)
7935
7725
  ]
7726
+ }),
7727
+ adStatus.remainingSeconds > 0 && /* @__PURE__ */ jsxs2("div", {
7728
+ style: {
7729
+ background: "rgba(0, 0, 0, 0.5)",
7730
+ backdropFilter: "blur(12px)",
7731
+ color: "rgba(255, 255, 255, 0.9)",
7732
+ padding: "".concat(4 * responsiveScale, "px ").concat(10 * responsiveScale, "px"),
7733
+ borderRadius: "6px",
7734
+ fontSize: "".concat(11 * responsiveScale, "px"),
7735
+ fontWeight: "600",
7736
+ border: "1px solid rgba(255, 255, 255, 0.08)"
7737
+ },
7738
+ children: [
7739
+ adStatus.remainingSeconds,
7740
+ "s"
7741
+ ]
7936
7742
  })
7937
7743
  ]
7938
7744
  }),
@@ -9732,5 +9538,5 @@ var createStormcloudPlayer = function createStormcloudPlayer(playerList, fallbac
9732
9538
  };
9733
9539
  var StormcloudPlayer = createStormcloudPlayer(players_default, players_default[players_default.length - 1]);
9734
9540
  var StormcloudPlayer_default = StormcloudPlayer;
9735
- export { IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer_default as StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, canPlay, createStormcloudPlayer, createVastAdLayer, createVastManager, StormcloudVideoPlayerComponent as default, detectBrowser, fetchProjectOverlays, getBrowserConfigOverrides, getBrowserID, getClientInfo, initializePolyfills, isMediaStream, isOverlayActive, lazy, logBrowserInfo, merge, omit, parseQuery, players_default as players, randomString, resolveImageUrl, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode, timeStringToSeconds };
9541
+ export { IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer_default as StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, canPlay, createAdStormPlayer, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, fetchProjectOverlays, getBrowserConfigOverrides, getBrowserID, getClientInfo, initializePolyfills, isMediaStream, isOverlayActive, lazy, logBrowserInfo, merge, omit, parseQuery, players_default as players, randomString, resolveImageUrl, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode, timeStringToSeconds };
9736
9542
  //# sourceMappingURL=index.js.map