stormcloud-video-player 0.5.26 → 0.6.1

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.
@@ -348,362 +348,6 @@ __export(StormcloudVideoPlayer_exports, {
348
348
  });
349
349
  module.exports = __toCommonJS(StormcloudVideoPlayer_exports);
350
350
  var import_hls2 = __toESM(require("hls.js"), 1);
351
- // src/sdk/prebid.ts
352
- var DEFAULT_TIMEOUT_MS = 3e3;
353
- var AUCTION_URL = "https://sspproxy.adstorm.co/openrtb2/auction/adstorm";
354
- function createPrebidManager() {
355
- var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
356
- var _options_debug;
357
- var initialized = false;
358
- var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
359
- function log() {
360
- for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
361
- args[_key] = arguments[_key];
362
- }
363
- if (debug) {
364
- var _console;
365
- (_console = console).log.apply(_console, [
366
- "[Prebid]"
367
- ].concat(_to_consumable_array(args)));
368
- }
369
- }
370
- function warn() {
371
- for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
372
- args[_key] = arguments[_key];
373
- }
374
- var _console;
375
- (_console = console).warn.apply(_console, [
376
- "[Prebid]"
377
- ].concat(_to_consumable_array(args)));
378
- }
379
- function parseResponse(data) {
380
- var bids = [];
381
- var seatbids = (data === null || data === void 0 ? void 0 : data.seatbid) || [];
382
- var currency = (data === null || data === void 0 ? void 0 : data.cur) || "USD";
383
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
384
- try {
385
- for(var _iterator = seatbids[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
386
- var seatbid = _step.value;
387
- var seat = seatbid.seat || "unknown";
388
- var bidArray = seatbid.bid || [];
389
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
390
- try {
391
- for(var _iterator1 = bidArray[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
392
- var bid = _step1.value;
393
- var _bid_ext_prebid_cache_vastXml, _bid_ext_prebid_cache, _bid_ext_prebid, _bid_ext;
394
- var cacheUrl = (_bid_ext = bid.ext) === null || _bid_ext === void 0 ? void 0 : (_bid_ext_prebid = _bid_ext.prebid) === null || _bid_ext_prebid === void 0 ? void 0 : (_bid_ext_prebid_cache = _bid_ext_prebid.cache) === null || _bid_ext_prebid_cache === void 0 ? void 0 : (_bid_ext_prebid_cache_vastXml = _bid_ext_prebid_cache.vastXml) === null || _bid_ext_prebid_cache_vastXml === void 0 ? void 0 : _bid_ext_prebid_cache_vastXml.url;
395
- var vastXml = bid.adm || void 0;
396
- var bidResponse = {
397
- bidder: seat,
398
- cpm: bid.price || 0,
399
- width: bid.w || 0,
400
- height: bid.h || 0,
401
- adId: bid.id || "",
402
- impId: bid.impid || "",
403
- creativeId: bid.crid || "",
404
- currency: currency
405
- };
406
- if (cacheUrl) bidResponse.vastUrl = cacheUrl;
407
- if (vastXml) bidResponse.vastXml = vastXml;
408
- if (bid.adomain) bidResponse.adomain = bid.adomain;
409
- bids.push(bidResponse);
410
- }
411
- } catch (err) {
412
- _didIteratorError1 = true;
413
- _iteratorError1 = err;
414
- } finally{
415
- try {
416
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
417
- _iterator1.return();
418
- }
419
- } finally{
420
- if (_didIteratorError1) {
421
- throw _iteratorError1;
422
- }
423
- }
424
- }
425
- }
426
- } catch (err) {
427
- _didIteratorError = true;
428
- _iteratorError = err;
429
- } finally{
430
- try {
431
- if (!_iteratorNormalCompletion && _iterator.return != null) {
432
- _iterator.return();
433
- }
434
- } finally{
435
- if (_didIteratorError) {
436
- throw _iteratorError;
437
- }
438
- }
439
- }
440
- bids.sort(function(a, b) {
441
- return b.cpm - a.cpm;
442
- });
443
- return bids;
444
- }
445
- function initialize() {
446
- return _async_to_generator(function() {
447
- return _ts_generator(this, function(_state) {
448
- if (initialized) return [
449
- 2
450
- ];
451
- initialized = true;
452
- log("Initialized, auction URL:", AUCTION_URL);
453
- return [
454
- 2
455
- ];
456
- });
457
- })();
458
- }
459
- function requestBids(context) {
460
- return _async_to_generator(function() {
461
- var timeout, controller, timeoutId, _data_ext, _data_ext1, fetchOptions, body, response, body1, data, bids, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, b, error;
462
- return _ts_generator(this, function(_state) {
463
- switch(_state.label){
464
- case 0:
465
- if (!initialized) {
466
- throw new Error("Prebid not initialized. Call initialize() first.");
467
- }
468
- timeout = DEFAULT_TIMEOUT_MS;
469
- log("Fetching auction response from:", AUCTION_URL);
470
- controller = typeof AbortController !== "undefined" ? new AbortController() : null;
471
- timeoutId = setTimeout(function() {
472
- controller === null || controller === void 0 ? void 0 : controller.abort();
473
- }, timeout + 2e3);
474
- _state.label = 1;
475
- case 1:
476
- _state.trys.push([
477
- 1,
478
- 6,
479
- ,
480
- 7
481
- ]);
482
- fetchOptions = {
483
- method: "POST"
484
- };
485
- if (controller) {
486
- fetchOptions.signal = controller.signal;
487
- }
488
- if ((context === null || context === void 0 ? void 0 : context.remainingBreakSec) != null) {
489
- body = {
490
- imp: [
491
- {
492
- video: {
493
- maxduration: Math.floor(context.remainingBreakSec)
494
- }
495
- }
496
- ]
497
- };
498
- fetchOptions.body = JSON.stringify(body);
499
- fetchOptions.headers = {
500
- "Content-Type": "application/json"
501
- };
502
- log("Sending context to auction: maxduration=", Math.floor(context.remainingBreakSec));
503
- }
504
- return [
505
- 4,
506
- fetch(AUCTION_URL, fetchOptions)
507
- ];
508
- case 2:
509
- response = _state.sent();
510
- clearTimeout(timeoutId);
511
- if (!!response.ok) return [
512
- 3,
513
- 4
514
- ];
515
- return [
516
- 4,
517
- response.text().catch(function() {
518
- return "";
519
- })
520
- ];
521
- case 3:
522
- body1 = _state.sent();
523
- throw new Error("Prebid Server returned HTTP ".concat(response.status, ": ").concat(body1.slice(0, 200)));
524
- case 4:
525
- return [
526
- 4,
527
- response.json()
528
- ];
529
- case 5:
530
- data = _state.sent();
531
- if (debug && (data === null || data === void 0 ? void 0 : (_data_ext = data.ext) === null || _data_ext === void 0 ? void 0 : _data_ext.responsetimemillis)) {
532
- log("Bidder response times:", data.ext.responsetimemillis);
533
- }
534
- if (debug && (data === null || data === void 0 ? void 0 : (_data_ext1 = data.ext) === null || _data_ext1 === void 0 ? void 0 : _data_ext1.errors)) {
535
- warn("Auction errors:", data.ext.errors);
536
- }
537
- bids = parseResponse(data);
538
- log("Received ".concat(bids.length, " bid(s)"));
539
- if (debug) {
540
- _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
541
- try {
542
- for(_iterator = bids[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
543
- b = _step.value;
544
- log(" ".concat(b.bidder, ": $").concat(b.cpm.toFixed(2), " ").concat(b.currency, " ").concat(b.width, "x").concat(b.height) + (b.vastUrl ? " [cached VAST]" : "") + (b.vastXml && !b.vastUrl ? " [VAST XML]" : ""));
545
- }
546
- } catch (err) {
547
- _didIteratorError = true;
548
- _iteratorError = err;
549
- } finally{
550
- try {
551
- if (!_iteratorNormalCompletion && _iterator.return != null) {
552
- _iterator.return();
553
- }
554
- } finally{
555
- if (_didIteratorError) {
556
- throw _iteratorError;
557
- }
558
- }
559
- }
560
- }
561
- return [
562
- 2,
563
- bids
564
- ];
565
- case 6:
566
- error = _state.sent();
567
- clearTimeout(timeoutId);
568
- if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
569
- warn("Auction request timed out after ".concat(timeout + 2e3, "ms"));
570
- return [
571
- 2,
572
- []
573
- ];
574
- }
575
- throw error;
576
- case 7:
577
- return [
578
- 2
579
- ];
580
- }
581
- });
582
- })();
583
- }
584
- var REQUEST_BIDS_MAX_RETRIES = 3;
585
- var REQUEST_BIDS_BACKOFF_MS = 1500;
586
- function requestBidsUntilResponse(context) {
587
- return _async_to_generator(function() {
588
- var _loop, lastError, attempt, _ret;
589
- return _ts_generator(this, function(_state) {
590
- switch(_state.label){
591
- case 0:
592
- _loop = function(attempt) {
593
- var bids, err, delay;
594
- return _ts_generator(this, function(_state) {
595
- switch(_state.label){
596
- case 0:
597
- _state.trys.push([
598
- 0,
599
- 2,
600
- ,
601
- 3
602
- ]);
603
- return [
604
- 4,
605
- requestBids(context)
606
- ];
607
- case 1:
608
- bids = _state.sent();
609
- if (bids.length > 0) {
610
- log("requestBidsUntilResponse: got ".concat(bids.length, " bid(s) on attempt ").concat(attempt));
611
- return [
612
- 2,
613
- {
614
- v: bids
615
- }
616
- ];
617
- }
618
- log("requestBidsUntilResponse: no bids on attempt ".concat(attempt, "/").concat(REQUEST_BIDS_MAX_RETRIES));
619
- return [
620
- 3,
621
- 3
622
- ];
623
- case 2:
624
- err = _state.sent();
625
- lastError = err;
626
- warn("requestBidsUntilResponse: attempt ".concat(attempt, "/").concat(REQUEST_BIDS_MAX_RETRIES, " failed:"), err);
627
- return [
628
- 3,
629
- 3
630
- ];
631
- case 3:
632
- if (!(attempt < REQUEST_BIDS_MAX_RETRIES)) return [
633
- 3,
634
- 5
635
- ];
636
- delay = REQUEST_BIDS_BACKOFF_MS * attempt;
637
- log("requestBidsUntilResponse: waiting ".concat(delay, "ms before retry"));
638
- return [
639
- 4,
640
- new Promise(function(resolve) {
641
- return setTimeout(resolve, delay);
642
- })
643
- ];
644
- case 4:
645
- _state.sent();
646
- _state.label = 5;
647
- case 5:
648
- return [
649
- 2
650
- ];
651
- }
652
- });
653
- };
654
- if (!initialized) {
655
- throw new Error("Prebid not initialized. Call initialize() first.");
656
- }
657
- attempt = 1;
658
- _state.label = 1;
659
- case 1:
660
- if (!(attempt <= REQUEST_BIDS_MAX_RETRIES)) return [
661
- 3,
662
- 4
663
- ];
664
- return [
665
- 5,
666
- _ts_values(_loop(attempt))
667
- ];
668
- case 2:
669
- _ret = _state.sent();
670
- if (_type_of(_ret) === "object") return [
671
- 2,
672
- _ret.v
673
- ];
674
- _state.label = 3;
675
- case 3:
676
- attempt++;
677
- return [
678
- 3,
679
- 1
680
- ];
681
- case 4:
682
- if (_instanceof(lastError, Error)) {
683
- throw lastError;
684
- }
685
- return [
686
- 2,
687
- []
688
- ];
689
- }
690
- });
691
- })();
692
- }
693
- function destroy() {
694
- initialized = false;
695
- log("Destroyed");
696
- }
697
- return {
698
- initialize: initialize,
699
- requestBids: requestBids,
700
- requestBidsUntilResponse: requestBidsUntilResponse,
701
- destroy: destroy,
702
- get isInitialized () {
703
- return initialized;
704
- }
705
- };
706
- }
707
351
  // src/sdk/vastParser.ts
708
352
  function isHlsType(type) {
709
353
  return type === "application/x-mpegURL" || type.includes("m3u8");
@@ -1002,11 +646,271 @@ function fireTrackingPixels(urls, sessionId) {
1002
646
  } catch (error) {
1003
647
  console.warn("".concat(logPrefix, " Error firing tracking pixel:"), error);
1004
648
  }
1005
- });
649
+ });
650
+ }
651
+ // src/sdk/vastManager.ts
652
+ 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";
653
+ var DEFAULT_TIMEOUT_MS = 5e3;
654
+ var MAX_RETRIES = 3;
655
+ var RETRY_BACKOFF_MS = 1500;
656
+ function createVastManager() {
657
+ var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
658
+ var _options_debug;
659
+ var initialized = false;
660
+ var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
661
+ function log() {
662
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
663
+ args[_key] = arguments[_key];
664
+ }
665
+ if (debug) {
666
+ var _console;
667
+ (_console = console).log.apply(_console, [
668
+ "[VastManager]"
669
+ ].concat(_to_consumable_array(args)));
670
+ }
671
+ }
672
+ function warn() {
673
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
674
+ args[_key] = arguments[_key];
675
+ }
676
+ var _console;
677
+ (_console = console).warn.apply(_console, [
678
+ "[VastManager]"
679
+ ].concat(_to_consumable_array(args)));
680
+ }
681
+ function initialize() {
682
+ return _async_to_generator(function() {
683
+ return _ts_generator(this, function(_state) {
684
+ if (initialized) return [
685
+ 2
686
+ ];
687
+ initialized = true;
688
+ log("Initialized, VAST tag URL:", VAST_TAG_URL.split("?")[0]);
689
+ return [
690
+ 2
691
+ ];
692
+ });
693
+ })();
694
+ }
695
+ function requestBids(_context) {
696
+ return _async_to_generator(function() {
697
+ var correlator, url, controller, timeoutId, _ref, _ref1, _vastAd_mediaFiles_, _vastAd_mediaFiles_1, fetchOptions, response, vastXml, vastAd, bid, error;
698
+ return _ts_generator(this, function(_state) {
699
+ switch(_state.label){
700
+ case 0:
701
+ if (!initialized) {
702
+ throw new Error("VastManager not initialized. Call initialize() first.");
703
+ }
704
+ correlator = Math.floor(Math.random() * 1e12).toString();
705
+ url = VAST_TAG_URL.replace("[placeholder]", correlator);
706
+ log("Fetching VAST tag, correlator:", correlator);
707
+ controller = typeof AbortController !== "undefined" ? new AbortController() : null;
708
+ timeoutId = setTimeout(function() {
709
+ return controller === null || controller === void 0 ? void 0 : controller.abort();
710
+ }, DEFAULT_TIMEOUT_MS);
711
+ _state.label = 1;
712
+ case 1:
713
+ _state.trys.push([
714
+ 1,
715
+ 4,
716
+ ,
717
+ 5
718
+ ]);
719
+ fetchOptions = {
720
+ method: "GET",
721
+ mode: "cors",
722
+ credentials: "omit",
723
+ headers: {
724
+ Accept: "application/xml, text/xml, */*"
725
+ },
726
+ referrerPolicy: "no-referrer-when-downgrade"
727
+ };
728
+ if (controller) fetchOptions.signal = controller.signal;
729
+ return [
730
+ 4,
731
+ fetch(url, fetchOptions)
732
+ ];
733
+ case 2:
734
+ response = _state.sent();
735
+ clearTimeout(timeoutId);
736
+ if (!response.ok) {
737
+ throw new Error("VAST request returned HTTP ".concat(response.status));
738
+ }
739
+ return [
740
+ 4,
741
+ response.text()
742
+ ];
743
+ case 3:
744
+ vastXml = _state.sent();
745
+ log("VAST XML received, length:", vastXml.length);
746
+ vastAd = parseVastXml(vastXml, "mp4-first", "[VastManager]");
747
+ if (!vastAd) {
748
+ log("VAST parsed but no usable ad found");
749
+ return [
750
+ 2,
751
+ []
752
+ ];
753
+ }
754
+ log("Ad parsed: id=".concat(vastAd.id, ", duration=").concat(vastAd.duration, "s, mediaFiles=").concat(vastAd.mediaFiles.length));
755
+ bid = {
756
+ bidder: "vast-direct",
757
+ cpm: 0,
758
+ vastXml: vastXml,
759
+ width: (_ref = (_vastAd_mediaFiles_ = vastAd.mediaFiles[0]) === null || _vastAd_mediaFiles_ === void 0 ? void 0 : _vastAd_mediaFiles_.width) !== null && _ref !== void 0 ? _ref : 0,
760
+ 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,
761
+ adId: vastAd.id,
762
+ impId: correlator,
763
+ creativeId: vastAd.id,
764
+ currency: "USD",
765
+ durationSec: vastAd.duration
766
+ };
767
+ return [
768
+ 2,
769
+ [
770
+ bid
771
+ ]
772
+ ];
773
+ case 4:
774
+ error = _state.sent();
775
+ clearTimeout(timeoutId);
776
+ if ((error === null || error === void 0 ? void 0 : error.name) === "AbortError") {
777
+ warn("VAST request timed out after ".concat(DEFAULT_TIMEOUT_MS, "ms"));
778
+ return [
779
+ 2,
780
+ []
781
+ ];
782
+ }
783
+ throw error;
784
+ case 5:
785
+ return [
786
+ 2
787
+ ];
788
+ }
789
+ });
790
+ })();
791
+ }
792
+ function requestBidsUntilResponse(context) {
793
+ return _async_to_generator(function() {
794
+ var _loop, lastError, attempt, _ret;
795
+ return _ts_generator(this, function(_state) {
796
+ switch(_state.label){
797
+ case 0:
798
+ _loop = function(attempt) {
799
+ var bids, err, delay;
800
+ return _ts_generator(this, function(_state) {
801
+ switch(_state.label){
802
+ case 0:
803
+ _state.trys.push([
804
+ 0,
805
+ 2,
806
+ ,
807
+ 3
808
+ ]);
809
+ return [
810
+ 4,
811
+ requestBids(context)
812
+ ];
813
+ case 1:
814
+ bids = _state.sent();
815
+ if (bids.length > 0) {
816
+ log("requestBidsUntilResponse: got ".concat(bids.length, " ad(s) on attempt ").concat(attempt));
817
+ return [
818
+ 2,
819
+ {
820
+ v: bids
821
+ }
822
+ ];
823
+ }
824
+ log("requestBidsUntilResponse: no ads on attempt ".concat(attempt, "/").concat(MAX_RETRIES));
825
+ return [
826
+ 3,
827
+ 3
828
+ ];
829
+ case 2:
830
+ err = _state.sent();
831
+ lastError = err;
832
+ warn("requestBidsUntilResponse: attempt ".concat(attempt, "/").concat(MAX_RETRIES, " failed:"), err);
833
+ return [
834
+ 3,
835
+ 3
836
+ ];
837
+ case 3:
838
+ if (!(attempt < MAX_RETRIES)) return [
839
+ 3,
840
+ 5
841
+ ];
842
+ delay = RETRY_BACKOFF_MS * attempt;
843
+ log("requestBidsUntilResponse: waiting ".concat(delay, "ms before retry"));
844
+ return [
845
+ 4,
846
+ new Promise(function(resolve) {
847
+ return setTimeout(resolve, delay);
848
+ })
849
+ ];
850
+ case 4:
851
+ _state.sent();
852
+ _state.label = 5;
853
+ case 5:
854
+ return [
855
+ 2
856
+ ];
857
+ }
858
+ });
859
+ };
860
+ if (!initialized) {
861
+ throw new Error("VastManager not initialized. Call initialize() first.");
862
+ }
863
+ attempt = 1;
864
+ _state.label = 1;
865
+ case 1:
866
+ if (!(attempt <= MAX_RETRIES)) return [
867
+ 3,
868
+ 4
869
+ ];
870
+ return [
871
+ 5,
872
+ _ts_values(_loop(attempt))
873
+ ];
874
+ case 2:
875
+ _ret = _state.sent();
876
+ if (_type_of(_ret) === "object") return [
877
+ 2,
878
+ _ret.v
879
+ ];
880
+ _state.label = 3;
881
+ case 3:
882
+ attempt++;
883
+ return [
884
+ 3,
885
+ 1
886
+ ];
887
+ case 4:
888
+ if (_instanceof(lastError, Error)) throw lastError;
889
+ return [
890
+ 2,
891
+ []
892
+ ];
893
+ }
894
+ });
895
+ })();
896
+ }
897
+ function destroy() {
898
+ initialized = false;
899
+ log("Destroyed");
900
+ }
901
+ return {
902
+ initialize: initialize,
903
+ requestBids: requestBids,
904
+ requestBidsUntilResponse: requestBidsUntilResponse,
905
+ destroy: destroy,
906
+ get isInitialized () {
907
+ return initialized;
908
+ }
909
+ };
1006
910
  }
1007
- // src/sdk/prebidAdLayer.ts
911
+ // src/sdk/vastAdLayer.ts
1008
912
  var import_hls = __toESM(require("hls.js"), 1);
1009
- var LOG = "[PrebidAdLayer]";
913
+ var LOG = "[VastAdLayer]";
1010
914
  function resolveBidToVastAd(winner, logPrefix) {
1011
915
  if (winner.vastXml) {
1012
916
  var ad = parseVastXml(winner.vastXml, "mp4-first", logPrefix);
@@ -1017,15 +921,17 @@ function resolveBidToVastAd(winner, logPrefix) {
1017
921
  }
1018
922
  return Promise.resolve(null);
1019
923
  }
1020
- function createPrebidAdLayer(contentVideo, options) {
1021
- var _ref, _ref1;
924
+ function createVastAdLayer(contentVideo, options) {
925
+ var _ref, _ref1, _ref2, _ref3;
1022
926
  var adPlaying = false;
1023
927
  var originalMutedState = false;
1024
928
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
1025
929
  var listeners = /* @__PURE__ */ new Map();
1026
930
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
1027
931
  var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
1028
- var debug = (_ref1 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref1 !== void 0 ? _ref1 : false;
932
+ var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
933
+ var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
934
+ var debug = (_ref3 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref3 !== void 0 ? _ref3 : false;
1029
935
  var adVideoElement;
1030
936
  var adHls;
1031
937
  var adContainerEl;
@@ -1034,6 +940,7 @@ function createPrebidAdLayer(contentVideo, options) {
1034
940
  var destroyed = false;
1035
941
  var tornDown = false;
1036
942
  var trackingFired = createEmptyTrackingState();
943
+ var currentAdEventHandlers;
1037
944
  var preloadSlots = /* @__PURE__ */ new Map();
1038
945
  function emit(event, payload) {
1039
946
  var set = listeners.get(event);
@@ -1136,63 +1043,86 @@ function createPrebidAdLayer(contentVideo, options) {
1136
1043
  video.volume = 1;
1137
1044
  return video;
1138
1045
  }
1046
+ function removeAdEventListeners() {
1047
+ if (!currentAdEventHandlers || !adVideoElement) return;
1048
+ var el = adVideoElement;
1049
+ el.removeEventListener("timeupdate", currentAdEventHandlers.timeupdate);
1050
+ el.removeEventListener("playing", currentAdEventHandlers.playing);
1051
+ el.removeEventListener("ended", currentAdEventHandlers.ended);
1052
+ el.removeEventListener("error", currentAdEventHandlers.error);
1053
+ el.removeEventListener("volumechange", currentAdEventHandlers.volumechange);
1054
+ el.removeEventListener("pause", currentAdEventHandlers.pause);
1055
+ el.removeEventListener("play", currentAdEventHandlers.play);
1056
+ currentAdEventHandlers = void 0;
1057
+ }
1139
1058
  function setupAdEventListeners() {
1140
1059
  if (!adVideoElement) return;
1141
- adVideoElement.addEventListener("timeupdate", function() {
1142
- var ad = currentAd;
1143
- if (!ad || !adVideoElement) return;
1144
- var progress = adVideoElement.currentTime / ad.duration;
1145
- if (progress >= 0.25 && !trackingFired.firstQuartile) {
1146
- trackingFired.firstQuartile = true;
1147
- fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1148
- }
1149
- if (progress >= 0.5 && !trackingFired.midpoint) {
1150
- trackingFired.midpoint = true;
1151
- fireTrackingPixels2(ad.trackingUrls.midpoint);
1152
- }
1153
- if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1154
- trackingFired.thirdQuartile = true;
1155
- fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1156
- }
1157
- });
1158
- adVideoElement.addEventListener("playing", function() {
1159
- var ad = currentAd;
1160
- if (!ad || trackingFired.start) return;
1161
- trackingFired.start = true;
1162
- fireTrackingPixels2(ad.trackingUrls.start);
1163
- if (debug) console.log("".concat(LOG, " Ad started playing"));
1164
- });
1165
- adVideoElement.addEventListener("ended", function() {
1166
- if (tornDown || !currentAd || trackingFired.complete) return;
1167
- trackingFired.complete = true;
1168
- fireTrackingPixels2(currentAd.trackingUrls.complete);
1169
- if (debug) console.log("".concat(LOG, " Ad completed"));
1170
- handleAdComplete();
1171
- });
1172
- adVideoElement.addEventListener("error", function(e) {
1173
- if (tornDown) return;
1174
- console.error("".concat(LOG, " Ad video error:"), e);
1175
- if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1176
- handleAdError();
1177
- });
1178
- adVideoElement.addEventListener("volumechange", function() {
1179
- if (!currentAd || !adVideoElement) return;
1180
- if (adVideoElement.muted) {
1181
- fireTrackingPixels2(currentAd.trackingUrls.mute);
1182
- } else {
1183
- fireTrackingPixels2(currentAd.trackingUrls.unmute);
1184
- }
1185
- });
1186
- adVideoElement.addEventListener("pause", function() {
1187
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1188
- fireTrackingPixels2(currentAd.trackingUrls.pause);
1189
- }
1190
- });
1191
- adVideoElement.addEventListener("play", function() {
1192
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1193
- fireTrackingPixels2(currentAd.trackingUrls.resume);
1060
+ removeAdEventListeners();
1061
+ var handlers = {
1062
+ timeupdate: function timeupdate() {
1063
+ var ad = currentAd;
1064
+ if (!ad || !adVideoElement) return;
1065
+ var progress = adVideoElement.currentTime / ad.duration;
1066
+ if (progress >= 0.25 && !trackingFired.firstQuartile) {
1067
+ trackingFired.firstQuartile = true;
1068
+ fireTrackingPixels2(ad.trackingUrls.firstQuartile);
1069
+ }
1070
+ if (progress >= 0.5 && !trackingFired.midpoint) {
1071
+ trackingFired.midpoint = true;
1072
+ fireTrackingPixels2(ad.trackingUrls.midpoint);
1073
+ }
1074
+ if (progress >= 0.75 && !trackingFired.thirdQuartile) {
1075
+ trackingFired.thirdQuartile = true;
1076
+ fireTrackingPixels2(ad.trackingUrls.thirdQuartile);
1077
+ }
1078
+ },
1079
+ playing: function playing() {
1080
+ var ad = currentAd;
1081
+ if (!ad || trackingFired.start) return;
1082
+ trackingFired.start = true;
1083
+ fireTrackingPixels2(ad.trackingUrls.start);
1084
+ if (debug) console.log("".concat(LOG, " Ad started playing"));
1085
+ },
1086
+ ended: function ended() {
1087
+ if (tornDown || !currentAd || trackingFired.complete) return;
1088
+ trackingFired.complete = true;
1089
+ fireTrackingPixels2(currentAd.trackingUrls.complete);
1090
+ if (debug) console.log("".concat(LOG, " Ad completed"));
1091
+ handleAdComplete();
1092
+ },
1093
+ error: function error(e) {
1094
+ if (tornDown) return;
1095
+ console.error("".concat(LOG, " Ad video error:"), e);
1096
+ if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);
1097
+ handleAdError();
1098
+ },
1099
+ volumechange: function volumechange() {
1100
+ if (!currentAd || !adVideoElement) return;
1101
+ if (adVideoElement.muted) {
1102
+ fireTrackingPixels2(currentAd.trackingUrls.mute);
1103
+ } else {
1104
+ fireTrackingPixels2(currentAd.trackingUrls.unmute);
1105
+ }
1106
+ },
1107
+ pause: function pause() {
1108
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1109
+ fireTrackingPixels2(currentAd.trackingUrls.pause);
1110
+ }
1111
+ },
1112
+ play: function play() {
1113
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1114
+ fireTrackingPixels2(currentAd.trackingUrls.resume);
1115
+ }
1194
1116
  }
1195
- });
1117
+ };
1118
+ adVideoElement.addEventListener("timeupdate", handlers.timeupdate);
1119
+ adVideoElement.addEventListener("playing", handlers.playing);
1120
+ adVideoElement.addEventListener("ended", handlers.ended);
1121
+ adVideoElement.addEventListener("error", handlers.error);
1122
+ adVideoElement.addEventListener("volumechange", handlers.volumechange);
1123
+ adVideoElement.addEventListener("pause", handlers.pause);
1124
+ adVideoElement.addEventListener("play", handlers.play);
1125
+ currentAdEventHandlers = handlers;
1196
1126
  }
1197
1127
  function setAdPlayingFlag(isPlaying) {
1198
1128
  if (isPlaying) {
@@ -1215,6 +1145,7 @@ function createPrebidAdLayer(contentVideo, options) {
1215
1145
  }
1216
1146
  function handleAdError() {
1217
1147
  if (tornDown) return;
1148
+ if (!adPlaying) return;
1218
1149
  if (debug) console.log("".concat(LOG, " Handling ad error"));
1219
1150
  adPlaying = false;
1220
1151
  setAdPlayingFlag(false);
@@ -1225,14 +1156,19 @@ function createPrebidAdLayer(contentVideo, options) {
1225
1156
  emit("ad_error");
1226
1157
  }
1227
1158
  function teardownCurrentPlayback() {
1159
+ removeAdEventListeners();
1228
1160
  if (adHls) {
1229
1161
  adHls.destroy();
1230
1162
  adHls = void 0;
1231
1163
  }
1232
1164
  if (adVideoElement) {
1233
- adVideoElement.pause();
1234
- adVideoElement.removeAttribute("src");
1235
- adVideoElement.load();
1165
+ if (singleElementMode && adVideoElement === contentVideo) {
1166
+ contentVideo.pause();
1167
+ } else {
1168
+ adVideoElement.pause();
1169
+ adVideoElement.removeAttribute("src");
1170
+ adVideoElement.load();
1171
+ }
1236
1172
  }
1237
1173
  }
1238
1174
  function startNativePlayback(mediaFile) {
@@ -1265,8 +1201,17 @@ function createPrebidAdLayer(contentVideo, options) {
1265
1201
  handleAdError();
1266
1202
  });
1267
1203
  });
1204
+ var nonFatalNetworkErrors = 0;
1268
1205
  adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1269
- if (data.fatal) handleAdError();
1206
+ if (data.fatal) {
1207
+ handleAdError();
1208
+ } else if (data.type === import_hls.default.ErrorTypes.NETWORK_ERROR) {
1209
+ nonFatalNetworkErrors++;
1210
+ if (nonFatalNetworkErrors >= 3) {
1211
+ if (debug) console.warn("".concat(LOG, " Too many non-fatal HLS network errors (").concat(nonFatalNetworkErrors, "), treating as fatal"));
1212
+ handleAdError();
1213
+ }
1214
+ }
1270
1215
  });
1271
1216
  } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1272
1217
  adVideoElement.src = mediaFile.url;
@@ -1289,7 +1234,7 @@ function createPrebidAdLayer(contentVideo, options) {
1289
1234
  }
1290
1235
  function playAd(bids) {
1291
1236
  return _async_to_generator(function() {
1292
- var winner, ad, _contentVideo_parentElement, container, contentVolume, adVolume, mediaFile;
1237
+ var winner, ad, contentVolume, _contentVideo_parentElement, container, adVolume, mediaFile;
1293
1238
  return _ts_generator(this, function(_state) {
1294
1239
  switch(_state.label){
1295
1240
  case 0:
@@ -1331,32 +1276,40 @@ function createPrebidAdLayer(contentVideo, options) {
1331
1276
  trackingFired = _object_spread({}, createEmptyTrackingState());
1332
1277
  fireTrackingPixels2(ad.trackingUrls.impression);
1333
1278
  trackingFired.impression = true;
1334
- if (!adContainerEl) {
1335
- ;
1336
- container = document.createElement("div");
1337
- container.style.position = "absolute";
1338
- container.style.left = "0";
1339
- container.style.top = "0";
1340
- container.style.right = "0";
1341
- container.style.bottom = "0";
1342
- container.style.display = "none";
1343
- container.style.alignItems = "center";
1344
- container.style.justifyContent = "center";
1345
- container.style.pointerEvents = "none";
1346
- container.style.zIndex = "10";
1347
- container.style.backgroundColor = "#000";
1348
- (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1349
- adContainerEl = container;
1350
- }
1351
- if (!adVideoElement) {
1352
- adVideoElement = createAdVideoElement();
1353
- adContainerEl.appendChild(adVideoElement);
1279
+ contentVolume = contentVideo.volume;
1280
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1281
+ if (singleElementMode) {
1282
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1283
+ teardownCurrentPlayback();
1284
+ adVideoElement = contentVideo;
1285
+ adHls = void 0;
1354
1286
  setupAdEventListeners();
1355
1287
  } else {
1356
- teardownCurrentPlayback();
1288
+ if (!adContainerEl) {
1289
+ ;
1290
+ container = document.createElement("div");
1291
+ container.style.position = "absolute";
1292
+ container.style.left = "0";
1293
+ container.style.top = "0";
1294
+ container.style.right = "0";
1295
+ container.style.bottom = "0";
1296
+ container.style.display = "none";
1297
+ container.style.alignItems = "center";
1298
+ container.style.justifyContent = "center";
1299
+ container.style.pointerEvents = "none";
1300
+ container.style.zIndex = "10";
1301
+ container.style.backgroundColor = "#000";
1302
+ (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1303
+ adContainerEl = container;
1304
+ }
1305
+ if (!adVideoElement) {
1306
+ adVideoElement = createAdVideoElement();
1307
+ adContainerEl.appendChild(adVideoElement);
1308
+ setupAdEventListeners();
1309
+ } else {
1310
+ teardownCurrentPlayback();
1311
+ }
1357
1312
  }
1358
- contentVolume = contentVideo.volume;
1359
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1360
1313
  if (!continueLiveStreamDuringAds) {
1361
1314
  contentVideo.pause();
1362
1315
  }
@@ -1367,7 +1320,7 @@ function createPrebidAdLayer(contentVideo, options) {
1367
1320
  adVolume = originalMutedState ? 1 : originalVolume;
1368
1321
  adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1369
1322
  adVideoElement.muted = false;
1370
- if (adContainerEl) {
1323
+ if (!singleElementMode && adContainerEl) {
1371
1324
  adContainerEl.style.display = "flex";
1372
1325
  adContainerEl.style.pointerEvents = "auto";
1373
1326
  }
@@ -1404,7 +1357,7 @@ function createPrebidAdLayer(contentVideo, options) {
1404
1357
  }
1405
1358
  function preloadAd(bids, token) {
1406
1359
  return _async_to_generator(function() {
1407
- var winner, ad, mediaFile, videoEl, container, hls, slot, slot1;
1360
+ var winner, ad, mediaFile, slot, videoEl, container, hls, slot1, slot2;
1408
1361
  return _ts_generator(this, function(_state) {
1409
1362
  switch(_state.label){
1410
1363
  case 0:
@@ -1429,6 +1382,20 @@ function createPrebidAdLayer(contentVideo, options) {
1429
1382
  if (!mediaFile) return [
1430
1383
  2
1431
1384
  ];
1385
+ if (smartTVMode || singleElementMode) {
1386
+ slot = {
1387
+ bids: bids,
1388
+ ad: ad,
1389
+ mediaFile: mediaFile,
1390
+ videoEl: null,
1391
+ ready: true
1392
+ };
1393
+ preloadSlots.set(token, slot);
1394
+ if (debug) console.log("".concat(LOG, " [preload] Metadata-only preload (smartTV/singleElement), token=").concat(token, ", url=").concat(mediaFile.url));
1395
+ return [
1396
+ 2
1397
+ ];
1398
+ }
1432
1399
  videoEl = createAdVideoElement();
1433
1400
  videoEl.style.visibility = "hidden";
1434
1401
  videoEl.style.pointerEvents = "none";
@@ -1442,7 +1409,7 @@ function createPrebidAdLayer(contentVideo, options) {
1442
1409
  });
1443
1410
  hls.loadSource(mediaFile.url);
1444
1411
  hls.attachMedia(videoEl);
1445
- slot = {
1412
+ slot1 = {
1446
1413
  bids: bids,
1447
1414
  ad: ad,
1448
1415
  mediaFile: mediaFile,
@@ -1450,7 +1417,7 @@ function createPrebidAdLayer(contentVideo, options) {
1450
1417
  hlsInstance: hls,
1451
1418
  ready: false
1452
1419
  };
1453
- preloadSlots.set(token, slot);
1420
+ preloadSlots.set(token, slot1);
1454
1421
  hls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1455
1422
  var s = preloadSlots.get(token);
1456
1423
  if (s) s.ready = true;
@@ -1467,14 +1434,14 @@ function createPrebidAdLayer(contentVideo, options) {
1467
1434
  } else {
1468
1435
  videoEl.src = mediaFile.url;
1469
1436
  videoEl.load();
1470
- slot1 = {
1437
+ slot2 = {
1471
1438
  bids: bids,
1472
1439
  ad: ad,
1473
1440
  mediaFile: mediaFile,
1474
1441
  videoEl: videoEl,
1475
1442
  ready: false
1476
1443
  };
1477
- preloadSlots.set(token, slot1);
1444
+ preloadSlots.set(token, slot2);
1478
1445
  videoEl.addEventListener("canplay", function() {
1479
1446
  var s = preloadSlots.get(token);
1480
1447
  if (s) s.ready = true;
@@ -1493,7 +1460,7 @@ function createPrebidAdLayer(contentVideo, options) {
1493
1460
  }
1494
1461
  function playPreloaded(token) {
1495
1462
  return _async_to_generator(function() {
1496
- var slot, contentVolume, adVolume, container;
1463
+ var slot, contentVolume, adVolume2, videoEl, container2, adVolume21, adVolume, container;
1497
1464
  return _ts_generator(this, function(_state) {
1498
1465
  if (destroyed) return [
1499
1466
  2,
@@ -1508,6 +1475,68 @@ function createPrebidAdLayer(contentVideo, options) {
1508
1475
  }
1509
1476
  preloadSlots.delete(token);
1510
1477
  if (debug) console.log("".concat(LOG, " [preload] Playing preloaded ad, token=").concat(token, ", ready=").concat(slot.ready));
1478
+ contentVolume = contentVideo.volume;
1479
+ originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1480
+ sessionId = generateSessionId();
1481
+ currentAd = slot.ad;
1482
+ trackingFired = _object_spread({}, createEmptyTrackingState());
1483
+ fireTrackingPixels2(slot.ad.trackingUrls.impression);
1484
+ trackingFired.impression = true;
1485
+ if (singleElementMode) {
1486
+ mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1487
+ teardownCurrentPlayback();
1488
+ adVideoElement = contentVideo;
1489
+ adHls = void 0;
1490
+ setupAdEventListeners();
1491
+ if (!continueLiveStreamDuringAds) {
1492
+ contentVideo.pause();
1493
+ }
1494
+ contentVideo.muted = true;
1495
+ contentVideo.volume = 0;
1496
+ adPlaying = true;
1497
+ setAdPlayingFlag(true);
1498
+ adVolume2 = originalMutedState ? 1 : originalVolume;
1499
+ contentVideo.volume = Math.max(0, Math.min(1, adVolume2));
1500
+ contentVideo.muted = false;
1501
+ emit("content_pause");
1502
+ if (debug) console.log("".concat(LOG, " [preload] singleElementMode: attaching ad to contentVideo, url=").concat(slot.mediaFile.url));
1503
+ startPlayback(slot.mediaFile);
1504
+ return [
1505
+ 2
1506
+ ];
1507
+ }
1508
+ if (smartTVMode && !slot.videoEl) {
1509
+ teardownCurrentPlayback();
1510
+ if (adVideoElement) {
1511
+ adVideoElement.remove();
1512
+ adVideoElement = void 0;
1513
+ }
1514
+ videoEl = createAdVideoElement();
1515
+ videoEl.style.visibility = "visible";
1516
+ videoEl.style.pointerEvents = "none";
1517
+ container2 = ensureAdContainer();
1518
+ container2.appendChild(videoEl);
1519
+ adVideoElement = videoEl;
1520
+ setupAdEventListeners();
1521
+ if (!continueLiveStreamDuringAds) {
1522
+ contentVideo.pause();
1523
+ }
1524
+ contentVideo.muted = true;
1525
+ contentVideo.volume = 0;
1526
+ adPlaying = true;
1527
+ setAdPlayingFlag(true);
1528
+ adVolume21 = originalMutedState ? 1 : originalVolume;
1529
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume21));
1530
+ adVideoElement.muted = false;
1531
+ container2.style.display = "flex";
1532
+ container2.style.pointerEvents = "auto";
1533
+ emit("content_pause");
1534
+ if (debug) console.log("".concat(LOG, " [preload] smartTVMode deferred: creating video element and loading, url=").concat(slot.mediaFile.url));
1535
+ startPlayback(slot.mediaFile);
1536
+ return [
1537
+ 2
1538
+ ];
1539
+ }
1511
1540
  teardownCurrentPlayback();
1512
1541
  if (adVideoElement && adVideoElement !== slot.videoEl) {
1513
1542
  adVideoElement.remove();
@@ -1517,13 +1546,6 @@ function createPrebidAdLayer(contentVideo, options) {
1517
1546
  adVideoElement = slot.videoEl;
1518
1547
  adHls = slot.hlsInstance;
1519
1548
  setupAdEventListeners();
1520
- sessionId = generateSessionId();
1521
- currentAd = slot.ad;
1522
- trackingFired = _object_spread({}, createEmptyTrackingState());
1523
- fireTrackingPixels2(slot.ad.trackingUrls.impression);
1524
- trackingFired.impression = true;
1525
- contentVolume = contentVideo.volume;
1526
- originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1527
1549
  if (!continueLiveStreamDuringAds) {
1528
1550
  contentVideo.pause();
1529
1551
  }
@@ -1538,17 +1560,10 @@ function createPrebidAdLayer(contentVideo, options) {
1538
1560
  container.style.display = "flex";
1539
1561
  container.style.pointerEvents = "auto";
1540
1562
  emit("content_pause");
1541
- if (slot.hlsInstance) {
1542
- adVideoElement.play().catch(function(error) {
1543
- console.error("".concat(LOG, " [preload] Error playing preloaded HLS ad:"), error);
1544
- handleAdError();
1545
- });
1546
- } else {
1547
- adVideoElement.play().catch(function(error) {
1548
- console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1549
- handleAdError();
1550
- });
1551
- }
1563
+ adVideoElement.play().catch(function(error) {
1564
+ console.error("".concat(LOG, " [preload] Error playing preloaded ad:"), error);
1565
+ handleAdError();
1566
+ });
1552
1567
  return [
1553
1568
  2
1554
1569
  ];
@@ -1562,10 +1577,12 @@ function createPrebidAdLayer(contentVideo, options) {
1562
1577
  if (slot.hlsInstance) {
1563
1578
  slot.hlsInstance.destroy();
1564
1579
  }
1565
- slot.videoEl.pause();
1566
- slot.videoEl.removeAttribute("src");
1567
- slot.videoEl.load();
1568
- slot.videoEl.remove();
1580
+ if (slot.videoEl) {
1581
+ slot.videoEl.pause();
1582
+ slot.videoEl.removeAttribute("src");
1583
+ slot.videoEl.load();
1584
+ slot.videoEl.remove();
1585
+ }
1569
1586
  if (debug) console.log("".concat(LOG, " [preload] Cancelled and cleaned up token=").concat(token));
1570
1587
  }
1571
1588
  return {
@@ -1613,20 +1630,27 @@ function createPrebidAdLayer(contentVideo, options) {
1613
1630
  setAdPlayingFlag(false);
1614
1631
  contentVideo.muted = originalMutedState;
1615
1632
  contentVideo.volume = originalMutedState ? 0 : originalVolume;
1616
- if (adContainerEl) {
1617
- adContainerEl.style.display = "none";
1618
- adContainerEl.style.pointerEvents = "none";
1619
- }
1620
1633
  contentVideo.style.visibility = "visible";
1621
1634
  contentVideo.style.opacity = "1";
1622
- if (continueLiveStreamDuringAds) {
1623
- contentVideo.play().catch(function() {});
1624
- }
1625
- teardownCurrentPlayback();
1626
- if (adVideoElement) {
1627
- adVideoElement.pause();
1628
- adVideoElement.removeAttribute("src");
1629
- adVideoElement.load();
1635
+ if (singleElementMode) {
1636
+ teardownCurrentPlayback();
1637
+ contentVideo.removeAttribute("src");
1638
+ contentVideo.load();
1639
+ adVideoElement = void 0;
1640
+ } else {
1641
+ if (adContainerEl) {
1642
+ adContainerEl.style.display = "none";
1643
+ adContainerEl.style.pointerEvents = "none";
1644
+ }
1645
+ if (continueLiveStreamDuringAds) {
1646
+ contentVideo.play().catch(function() {});
1647
+ }
1648
+ teardownCurrentPlayback();
1649
+ if (adVideoElement) {
1650
+ adVideoElement.pause();
1651
+ adVideoElement.removeAttribute("src");
1652
+ adVideoElement.load();
1653
+ }
1630
1654
  }
1631
1655
  currentAd = void 0;
1632
1656
  tornDown = false;
@@ -1666,9 +1690,14 @@ function createPrebidAdLayer(contentVideo, options) {
1666
1690
  }
1667
1691
  teardownCurrentPlayback();
1668
1692
  if (adVideoElement) {
1669
- adVideoElement.pause();
1670
- adVideoElement.removeAttribute("src");
1671
- adVideoElement.remove();
1693
+ if (singleElementMode && adVideoElement === contentVideo) {
1694
+ contentVideo.removeAttribute("src");
1695
+ contentVideo.load();
1696
+ } else {
1697
+ adVideoElement.pause();
1698
+ adVideoElement.removeAttribute("src");
1699
+ adVideoElement.remove();
1700
+ }
1672
1701
  adVideoElement = void 0;
1673
1702
  }
1674
1703
  if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
@@ -2863,11 +2892,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2863
2892
  this.video = config.videoElement;
2864
2893
  this.adTransitionGapMs = (_this_config_adTransitionGapMs = this.config.adTransitionGapMs) !== null && _this_config_adTransitionGapMs !== void 0 ? _this_config_adTransitionGapMs : 100;
2865
2894
  logBrowserInfo(config.debugAdTiming);
2866
- this.prebidManager = createPrebidManager(config.debugAdTiming !== void 0 ? {
2895
+ this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
2867
2896
  debug: !!config.debugAdTiming
2868
2897
  } : {});
2869
- this.adLayer = createPrebidAdLayer(this.video, {
2898
+ var browserForAdLayer = detectBrowser();
2899
+ this.adLayer = createVastAdLayer(this.video, {
2870
2900
  continueLiveStreamDuringAds: false,
2901
+ smartTVMode: browserForAdLayer.isSmartTV,
2902
+ singleElementMode: browserForAdLayer.isSmartTV,
2871
2903
  debug: !!config.debugAdTiming
2872
2904
  });
2873
2905
  }
@@ -2879,19 +2911,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2879
2911
  return _ts_generator(this, function(_state) {
2880
2912
  switch(_state.label){
2881
2913
  case 0:
2882
- if (this.config.disablePrebid) return [
2914
+ if (this.config.disableAds) return [
2883
2915
  2,
2884
2916
  []
2885
2917
  ];
2886
2918
  return [
2887
2919
  4,
2888
- this.prebidManager.initialize()
2920
+ this.vastManager.initialize()
2889
2921
  ];
2890
2922
  case 1:
2891
2923
  _state.sent();
2892
2924
  return [
2893
2925
  2,
2894
- this.prebidManager.requestBidsUntilResponse(context)
2926
+ this.vastManager.requestBidsUntilResponse(context)
2895
2927
  ];
2896
2928
  }
2897
2929
  });
@@ -2926,7 +2958,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2926
2958
  adBehavior: "vod (main video pauses during ads)"
2927
2959
  });
2928
2960
  }
2929
- if (!this.config.disablePrebid) {
2961
+ if (!this.config.disableAds) {
2930
2962
  this.adLayer.updateOptions({
2931
2963
  continueLiveStreamDuringAds: false,
2932
2964
  mainHlsInstance: null
@@ -2994,7 +3026,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2994
3026
  adBehavior: adBehavior
2995
3027
  });
2996
3028
  }
2997
- if (!this.config.disablePrebid) {
3029
+ if (!this.config.disableAds) {
2998
3030
  ;
2999
3031
  this.adLayer.updateOptions({
3000
3032
  continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds(),
@@ -3315,7 +3347,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3315
3347
  {
3316
3348
  key: "getAdSource",
3317
3349
  value: function getAdSource() {
3318
- return "prebid";
3350
+ return "vast";
3319
3351
  }
3320
3352
  },
3321
3353
  {
@@ -3561,7 +3593,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3561
3593
  this.attached = true;
3562
3594
  this.video.autoplay = !!this.config.autoplay;
3563
3595
  this.video.muted = !!this.config.muted;
3564
- if (!this.config.disablePrebid) {
3596
+ if (!this.config.disableAds) {
3565
3597
  this.adLayer.initialize();
3566
3598
  if (!this.config.disableFiller) {
3567
3599
  this.ensureFillerVideo();
@@ -3757,7 +3789,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3757
3789
  key: "onScte35Marker",
3758
3790
  value: function onScte35Marker(marker) {
3759
3791
  var _this = this;
3760
- if (this.config.disablePrebid) return;
3792
+ if (this.config.disableAds) return;
3761
3793
  if (this.config.debugAdTiming) {
3762
3794
  console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
3763
3795
  type: marker.type,
@@ -4229,13 +4261,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4229
4261
  if (!this.isLiveStream) {
4230
4262
  return false;
4231
4263
  }
4264
+ var browser = detectBrowser();
4265
+ if (browser.isSmartTV) {
4266
+ return false;
4267
+ }
4232
4268
  return true;
4233
4269
  }
4234
4270
  },
4235
4271
  {
4236
4272
  key: "startAdPrefetch",
4237
4273
  value: function startAdPrefetch(marker, fragmentSn) {
4238
- if (this.config.disablePrebid) return;
4274
+ if (this.config.disableAds) return;
4239
4275
  if (this.pendingAdBreak || this.inAdBreak) {
4240
4276
  return;
4241
4277
  }
@@ -4257,25 +4293,75 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4257
4293
  key: "runAdPrefetch",
4258
4294
  value: function runAdPrefetch(marker) {
4259
4295
  return _async_to_generator(function() {
4260
- var _this, _marker_durationSeconds, durSec, estimatedCount, context, fetches, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token;
4296
+ var _this, _marker_durationSeconds, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token;
4261
4297
  return _ts_generator(this, function(_state) {
4262
4298
  switch(_state.label){
4263
4299
  case 0:
4264
4300
  _this = this;
4265
4301
  durSec = (_marker_durationSeconds = marker.durationSeconds) !== null && _marker_durationSeconds !== void 0 ? _marker_durationSeconds : 60;
4266
- estimatedCount = Math.min(4, Math.max(1, Math.ceil(durSec / 30)));
4267
- if (this.config.debugAdTiming) {
4268
- console.log("[PREFETCH] Firing ".concat(estimatedCount, " parallel bid request(s) for ").concat(durSec, "s break"));
4269
- }
4270
4302
  context = {
4271
4303
  breakDurationSec: durSec,
4272
4304
  remainingBreakSec: durSec
4273
4305
  };
4274
- fetches = Array.from({
4275
- length: estimatedCount
4306
+ _state.label = 1;
4307
+ case 1:
4308
+ _state.trys.push([
4309
+ 1,
4310
+ 3,
4311
+ ,
4312
+ 4
4313
+ ]);
4314
+ return [
4315
+ 4,
4316
+ this.adRequest(_object_spread_props(_object_spread({}, context), {
4317
+ adIndex: 1
4318
+ }))
4319
+ ];
4320
+ case 2:
4321
+ firstBids = _state.sent();
4322
+ return [
4323
+ 3,
4324
+ 4
4325
+ ];
4326
+ case 3:
4327
+ unused = _state.sent();
4328
+ firstBids = [];
4329
+ return [
4330
+ 3,
4331
+ 4
4332
+ ];
4333
+ case 4:
4334
+ if (this.inAdBreak) return [
4335
+ 2
4336
+ ];
4337
+ if (firstBids.length === 0) {
4338
+ if (this.config.debugAdTiming) {
4339
+ console.log("[PREFETCH] First VAST request returned no ad, aborting prefetch");
4340
+ }
4341
+ return [
4342
+ 2
4343
+ ];
4344
+ }
4345
+ adDurationSec = (_ref = (_firstBids_ = firstBids[0]) === null || _firstBids_ === void 0 ? void 0 : _firstBids_.durationSec) !== null && _ref !== void 0 ? _ref : 30;
4346
+ estimatedCount = Math.max(1, Math.ceil(durSec / adDurationSec));
4347
+ if (this.config.debugAdTiming) {
4348
+ console.log("[PREFETCH] Ad duration=".concat(adDurationSec, "s, break=").concat(durSec, "s → ").concat(estimatedCount, " ad(s) needed"));
4349
+ }
4350
+ firstToken = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4351
+ this.preloadedTokens.push(firstToken);
4352
+ void this.adLayer.preloadAd(firstBids, firstToken);
4353
+ if (this.config.debugAdTiming) {
4354
+ console.log("[PREFETCH] First ad preloading, token=".concat(firstToken));
4355
+ }
4356
+ if (!(estimatedCount > 1)) return [
4357
+ 3,
4358
+ 6
4359
+ ];
4360
+ remaining = Array.from({
4361
+ length: estimatedCount - 1
4276
4362
  }, function(_, i) {
4277
4363
  return _this.adRequest(_object_spread_props(_object_spread({}, context), {
4278
- adIndex: i + 1
4364
+ adIndex: i + 2
4279
4365
  })).then(function(bids) {
4280
4366
  return {
4281
4367
  ok: true,
@@ -4289,9 +4375,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4289
4375
  });
4290
4376
  return [
4291
4377
  4,
4292
- Promise.all(fetches)
4378
+ Promise.all(remaining)
4293
4379
  ];
4294
- case 1:
4380
+ case 5:
4295
4381
  results = _state.sent();
4296
4382
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
4297
4383
  try {
@@ -4303,7 +4389,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4303
4389
  this.preloadedTokens.push(token);
4304
4390
  void this.adLayer.preloadAd(result.value, token);
4305
4391
  if (this.config.debugAdTiming) {
4306
- console.log("[PREFETCH] Bid received, preloading video token=".concat(token));
4392
+ console.log("[PREFETCH] Additional ad preloading, token=".concat(token));
4307
4393
  }
4308
4394
  }
4309
4395
  }
@@ -4321,6 +4407,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4321
4407
  }
4322
4408
  }
4323
4409
  }
4410
+ _state.label = 6;
4411
+ case 6:
4324
4412
  if (this.config.debugAdTiming) {
4325
4413
  console.log("[PREFETCH] Pre-fetch complete: ".concat(this.preloadedTokens.length, " ad(s) queued"));
4326
4414
  }
@@ -4384,7 +4472,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4384
4472
  switch(_state.label){
4385
4473
  case 0:
4386
4474
  _loop = function() {
4387
- var remaining, prefetchContext, bids, err, bids1, remainingNow, delay, elapsed, remaining1, context, bids2, remainingNow1, err1;
4475
+ var remaining, prefetchContext, bids, err, bids1, remainingNow, urgentNeedAd, delay, elapsed, remaining1, context, bids2, remainingNow1, err1, sleepMs;
4388
4476
  return _ts_generator(this, function(_state) {
4389
4477
  switch(_state.label){
4390
4478
  case 0:
@@ -4435,6 +4523,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4435
4523
  if (bids.length > 0) {
4436
4524
  _this.consecutiveFailures = 0;
4437
4525
  _this.pendingNextAdBids = bids;
4526
+ _this.totalAdsInBreak = Math.max(_this.totalAdsInBreak, _this.currentAdIndex + _this.preloadedTokens.length + 1);
4438
4527
  if (_this.config.debugAdTiming) {
4439
4528
  console.log("[CONTINUOUS-FETCH] Pre-fetched next ad stored as pending");
4440
4529
  }
@@ -4519,7 +4608,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4519
4608
  "continue"
4520
4609
  ];
4521
4610
  case 12:
4522
- delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (_this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4611
+ urgentNeedAd = _this.inAdBreak && !_this.adLayer.isAdPlaying();
4612
+ delay = _this.lastAdRequestTime ? _this.minAdRequestIntervalMs + (!urgentNeedAd && _this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;
4523
4613
  elapsed = Date.now() - _this.lastAdRequestTime;
4524
4614
  if (!(elapsed < delay && _this.lastAdRequestTime > 0)) return [
4525
4615
  3,
@@ -4574,6 +4664,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4574
4664
  17
4575
4665
  ];
4576
4666
  _this.pendingNextAdBids = bids2;
4667
+ _this.totalAdsInBreak = Math.max(_this.totalAdsInBreak, _this.currentAdIndex + _this.preloadedTokens.length + 1);
4577
4668
  if (_this.config.debugAdTiming) {
4578
4669
  console.log("[CONTINUOUS-FETCH] Next ad response stored (ad currently playing or in transition)");
4579
4670
  }
@@ -4637,10 +4728,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4637
4728
  24
4638
4729
  ];
4639
4730
  case 24:
4731
+ sleepMs = _this.inAdBreak && !_this.adLayer.isAdPlaying() ? 0 : backoffMs();
4640
4732
  return [
4641
4733
  4,
4642
4734
  new Promise(function(r) {
4643
- return setTimeout(r, backoffMs());
4735
+ return setTimeout(r, sleepMs);
4644
4736
  })
4645
4737
  ];
4646
4738
  case 25:
@@ -4727,7 +4819,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4727
4819
  this.inAdBreak = true;
4728
4820
  this.currentAdBreakStartWallClockMs = Date.now();
4729
4821
  this.currentAdIndex = 0;
4730
- this.totalAdsInBreak = 1;
4822
+ this.totalAdsInBreak = Math.max(1, this.preloadedTokens.length);
4731
4823
  this.adPodQueue = [];
4732
4824
  if (!this.config.disableFiller) this.showAds = true;
4733
4825
  if (adBreakDurationMs != null) {
@@ -4952,6 +5044,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4952
5044
  3
4953
5045
  ];
4954
5046
  this.pendingNextAdBids = bids;
5047
+ this.totalAdsInBreak = Math.max(this.totalAdsInBreak, this.currentAdIndex + this.preloadedTokens.length);
4955
5048
  return [
4956
5049
  3,
4957
5050
  5
@@ -5320,40 +5413,45 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5320
5413
  var browser = detectBrowser();
5321
5414
  var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0;
5322
5415
  if (isSmartTV && this.hls) {
5323
- if (!restoredMuted) {
5324
- var hlsRef = this.hls;
5325
- var savedMuted = restoredMuted;
5326
- var savedVolume = restoredVolume;
5327
- var onManifestParsedRestore = function onManifestParsedRestore1() {
5328
- hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5329
- if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5330
- if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5331
- if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5332
- if (_this.config.debugAdTiming) {
5333
- console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5334
- }
5416
+ var hlsRef = this.hls;
5417
+ var savedMuted = restoredMuted;
5418
+ var savedVolume = restoredVolume;
5419
+ var onManifestParsedRestore = function onManifestParsedRestore1() {
5420
+ hlsRef.off(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5421
+ if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5422
+ var _this_video_play;
5423
+ if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5424
+ if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5425
+ if (_this.config.debugAdTiming) {
5426
+ console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5335
5427
  }
5336
- };
5337
- hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5338
- }
5428
+ hlsRef.startLoad(-1);
5429
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5430
+ if (_this.config.debugAdTiming) {
5431
+ console.log("[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach");
5432
+ }
5433
+ }
5434
+ };
5435
+ hlsRef.on(import_hls2.default.Events.MANIFEST_PARSED, onManifestParsedRestore);
5339
5436
  this.hls.attachMedia(this.video);
5340
5437
  if (this.config.debugAdTiming) {
5341
5438
  console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5342
5439
  }
5343
- }
5344
- if (this.shouldContinueLiveStreamDuringAds()) {
5345
- var _this_video_play;
5346
- if (this.config.debugAdTiming) {
5347
- if (this.video.paused) {
5348
- console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5349
- } else {
5350
- console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5440
+ } else {
5441
+ if (this.shouldContinueLiveStreamDuringAds()) {
5442
+ var _this_video_play;
5443
+ if (this.config.debugAdTiming) {
5444
+ if (this.video.paused) {
5445
+ console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
5446
+ } else {
5447
+ console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
5448
+ }
5351
5449
  }
5450
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5451
+ } else if (this.video.paused) {
5452
+ var _this_video_play1;
5453
+ (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5352
5454
  }
5353
- (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5354
- } else if (this.video.paused) {
5355
- var _this_video_play1;
5356
- (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});
5357
5455
  }
5358
5456
  this.syncMainContentAudioWhenVisible();
5359
5457
  if (!restoredMuted) {
@@ -5404,6 +5502,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5404
5502
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Max consecutive failures reached (".concat(this.consecutiveFailures, "), ending ad break gracefully"));
5405
5503
  }
5406
5504
  this.handleAdPodComplete();
5505
+ return;
5506
+ }
5507
+ if (this.inAdBreak && !this.config.disableFiller) {
5508
+ if (this.config.debugAdTiming) {
5509
+ console.log("[CONTINUOUS-FETCH] Ad failure in active break \u2014 showing filler while awaiting next ad");
5510
+ }
5511
+ this.showPlaceholderLayer();
5512
+ this.adLayer.showPlaceholder();
5407
5513
  }
5408
5514
  }
5409
5515
  },