stormcloud-video-player 0.5.4 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/stormcloud-vp.min.js +1 -1
  2. package/lib/index.cjs +438 -53
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +9 -1
  5. package/lib/index.d.ts +9 -1
  6. package/lib/index.js +438 -53
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/StormcloudVideoPlayer.cjs +438 -53
  9. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  10. package/lib/player/StormcloudVideoPlayer.d.cts +10 -2
  11. package/lib/players/FilePlayer.cjs.map +1 -1
  12. package/lib/players/HlsPlayer.cjs +438 -53
  13. package/lib/players/HlsPlayer.cjs.map +1 -1
  14. package/lib/players/HlsPlayer.d.cts +1 -1
  15. package/lib/players/index.cjs +438 -53
  16. package/lib/players/index.cjs.map +1 -1
  17. package/lib/sdk/hlsAdPlayer.cjs +5 -2
  18. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  19. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  20. package/lib/sdk/ima.cjs +1 -0
  21. package/lib/sdk/ima.cjs.map +1 -1
  22. package/lib/sdk/ima.d.cts +1 -1
  23. package/lib/sdk/prebid.cjs.map +1 -1
  24. package/lib/sdk/prebid.d.cts +1 -1
  25. package/lib/sdk/prebidController.cjs +5 -2
  26. package/lib/sdk/prebidController.cjs.map +1 -1
  27. package/lib/sdk/prebidController.d.cts +1 -1
  28. package/lib/sdk/vastParser.cjs.map +1 -1
  29. package/lib/{types-CRi_KrjM.d.cts → types-Bwp6-yys.d.cts} +20 -1
  30. package/lib/ui/StormcloudVideoPlayer.cjs +438 -53
  31. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  32. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  33. package/lib/utils/browserCompat.cjs.map +1 -1
  34. package/lib/utils/polyfills.cjs.map +1 -1
  35. package/lib/utils/tracking.cjs +226 -1
  36. package/lib/utils/tracking.cjs.map +1 -1
  37. package/lib/utils/tracking.d.cts +5 -2
  38. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -1256,6 +1256,7 @@ function createImaController(video, options) {
1256
1256
  adContainerEl.offsetHeight;
1257
1257
  adContainerEl.style.opacity = "1";
1258
1258
  }
1259
+ emit("ad_impression");
1259
1260
  });
1260
1261
  adsManager.addEventListener(AdEvent.CONTENT_RESUME_REQUESTED, function() {
1261
1262
  adPlaying = false;
@@ -2057,11 +2058,12 @@ function createHlsAdPlayer(contentVideo, options) {
2057
2058
  if (options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) {
2058
2059
  if (contentVideo.paused) {
2059
2060
  console.log("[HlsAdPlayer] Content video paused in live mode, resuming playback");
2060
- contentVideo.play().catch(function() {});
2061
2061
  } else {
2062
2062
  console.log("[HlsAdPlayer] Content video already playing in live mode");
2063
2063
  }
2064
+ contentVideo.play().catch(function() {});
2064
2065
  }
2066
+ emit("ad_impression");
2065
2067
  emit("content_resume");
2066
2068
  }
2067
2069
  function handleAdError() {
@@ -2333,8 +2335,8 @@ function createHlsAdPlayer(contentVideo, options) {
2333
2335
  if (options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) {
2334
2336
  if (contentVideo.paused) {
2335
2337
  console.log("[HlsAdPlayer] Content video paused in live mode, resuming playback on stop");
2336
- contentVideo.play().catch(function() {});
2337
2338
  }
2339
+ contentVideo.play().catch(function() {});
2338
2340
  }
2339
2341
  if (adHls) {
2340
2342
  adHls.destroy();
@@ -2343,6 +2345,8 @@ function createHlsAdPlayer(contentVideo, options) {
2343
2345
  if (adVideoElement) {
2344
2346
  adVideoElement.pause();
2345
2347
  adVideoElement.src = "";
2348
+ adVideoElement.remove();
2349
+ adVideoElement = void 0;
2346
2350
  }
2347
2351
  currentAd = void 0;
2348
2352
  return [
@@ -2993,11 +2997,12 @@ function createPrebidController(contentVideo, options) {
2993
2997
  if (options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) {
2994
2998
  if (contentVideo.paused) {
2995
2999
  console.log("".concat(LOG, " Content video paused in live mode, resuming playback"));
2996
- contentVideo.play().catch(function() {});
2997
3000
  } else {
2998
3001
  console.log("".concat(LOG, " Content video already playing in live mode"));
2999
3002
  }
3003
+ contentVideo.play().catch(function() {});
3000
3004
  }
3005
+ emit("ad_impression");
3001
3006
  emit("content_resume");
3002
3007
  }
3003
3008
  function handleAdError() {
@@ -3362,8 +3367,8 @@ function createPrebidController(contentVideo, options) {
3362
3367
  if (options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) {
3363
3368
  if (contentVideo.paused) {
3364
3369
  console.log("".concat(LOG, " Content video paused in live mode, resuming playback on stop"));
3365
- contentVideo.play().catch(function() {});
3366
3370
  }
3371
+ contentVideo.play().catch(function() {});
3367
3372
  }
3368
3373
  if (adHls) {
3369
3374
  adHls.destroy();
@@ -3372,6 +3377,8 @@ function createPrebidController(contentVideo, options) {
3372
3377
  if (adVideoElement) {
3373
3378
  adVideoElement.pause();
3374
3379
  adVideoElement.src = "";
3380
+ adVideoElement.remove();
3381
+ adVideoElement = void 0;
3375
3382
  }
3376
3383
  currentAd = void 0;
3377
3384
  return [
@@ -3718,6 +3725,45 @@ function getBrowserID(clientInfo) {
3718
3725
  });
3719
3726
  })();
3720
3727
  }
3728
+ var TRACK_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track";
3729
+ function sendTrackRequest(licenseKey, body) {
3730
+ return _async_to_generator(function() {
3731
+ var headers, response;
3732
+ return _ts_generator(this, function(_state) {
3733
+ switch(_state.label){
3734
+ case 0:
3735
+ headers = {
3736
+ "Content-Type": "application/json"
3737
+ };
3738
+ if (licenseKey) {
3739
+ headers["Authorization"] = "Bearer ".concat(licenseKey);
3740
+ }
3741
+ return [
3742
+ 4,
3743
+ fetch(TRACK_URL, {
3744
+ method: "POST",
3745
+ headers: headers,
3746
+ body: JSON.stringify(body)
3747
+ })
3748
+ ];
3749
+ case 1:
3750
+ response = _state.sent();
3751
+ if (!response.ok) {
3752
+ throw new Error("HTTP error! status: ".concat(response.status));
3753
+ }
3754
+ return [
3755
+ 4,
3756
+ response.json()
3757
+ ];
3758
+ case 2:
3759
+ _state.sent();
3760
+ return [
3761
+ 2
3762
+ ];
3763
+ }
3764
+ });
3765
+ })();
3766
+ }
3721
3767
  function sendInitialTracking(licenseKey) {
3722
3768
  return _async_to_generator(function() {
3723
3769
  var clientInfo, browserId, trackingData, headers, response, error;
@@ -3748,7 +3794,7 @@ function sendInitialTracking(licenseKey) {
3748
3794
  }
3749
3795
  return [
3750
3796
  4,
3751
- fetch("https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track", {
3797
+ fetch(TRACK_URL, {
3752
3798
  method: "POST",
3753
3799
  headers: headers,
3754
3800
  body: JSON.stringify(trackingData)
@@ -3784,6 +3830,156 @@ function sendInitialTracking(licenseKey) {
3784
3830
  });
3785
3831
  })();
3786
3832
  }
3833
+ function sendAdDetectTracking(licenseKey, adDetectInfo) {
3834
+ return _async_to_generator(function() {
3835
+ var clientInfo, browserId, trackingData, error;
3836
+ return _ts_generator(this, function(_state) {
3837
+ switch(_state.label){
3838
+ case 0:
3839
+ _state.trys.push([
3840
+ 0,
3841
+ 3,
3842
+ ,
3843
+ 4
3844
+ ]);
3845
+ clientInfo = getClientInfo();
3846
+ return [
3847
+ 4,
3848
+ getBrowserID(clientInfo)
3849
+ ];
3850
+ case 1:
3851
+ browserId = _state.sent();
3852
+ trackingData = _object_spread({
3853
+ browserId: browserId
3854
+ }, clientInfo);
3855
+ return [
3856
+ 4,
3857
+ sendTrackRequest(licenseKey, _object_spread_props(_object_spread({}, trackingData), {
3858
+ licenseKey: licenseKey,
3859
+ adDetectInfo: adDetectInfo
3860
+ }))
3861
+ ];
3862
+ case 2:
3863
+ _state.sent();
3864
+ return [
3865
+ 3,
3866
+ 4
3867
+ ];
3868
+ case 3:
3869
+ error = _state.sent();
3870
+ console.error("[StormcloudVideoPlayer] Error sending ad detect tracking:", error);
3871
+ return [
3872
+ 3,
3873
+ 4
3874
+ ];
3875
+ case 4:
3876
+ return [
3877
+ 2
3878
+ ];
3879
+ }
3880
+ });
3881
+ })();
3882
+ }
3883
+ function sendAdLoadedTracking(licenseKey, adLoadedInfo) {
3884
+ return _async_to_generator(function() {
3885
+ var clientInfo, browserId, trackingData, error;
3886
+ return _ts_generator(this, function(_state) {
3887
+ switch(_state.label){
3888
+ case 0:
3889
+ _state.trys.push([
3890
+ 0,
3891
+ 3,
3892
+ ,
3893
+ 4
3894
+ ]);
3895
+ clientInfo = getClientInfo();
3896
+ return [
3897
+ 4,
3898
+ getBrowserID(clientInfo)
3899
+ ];
3900
+ case 1:
3901
+ browserId = _state.sent();
3902
+ trackingData = _object_spread({
3903
+ browserId: browserId
3904
+ }, clientInfo);
3905
+ return [
3906
+ 4,
3907
+ sendTrackRequest(licenseKey, _object_spread_props(_object_spread({}, trackingData), {
3908
+ licenseKey: licenseKey,
3909
+ adLoadedInfo: adLoadedInfo
3910
+ }))
3911
+ ];
3912
+ case 2:
3913
+ _state.sent();
3914
+ return [
3915
+ 3,
3916
+ 4
3917
+ ];
3918
+ case 3:
3919
+ error = _state.sent();
3920
+ console.error("[StormcloudVideoPlayer] Error sending ad loaded tracking:", error);
3921
+ return [
3922
+ 3,
3923
+ 4
3924
+ ];
3925
+ case 4:
3926
+ return [
3927
+ 2
3928
+ ];
3929
+ }
3930
+ });
3931
+ })();
3932
+ }
3933
+ function sendAdImpressionTracking(licenseKey, adImpressionInfo) {
3934
+ return _async_to_generator(function() {
3935
+ var clientInfo, browserId, trackingData, error;
3936
+ return _ts_generator(this, function(_state) {
3937
+ switch(_state.label){
3938
+ case 0:
3939
+ _state.trys.push([
3940
+ 0,
3941
+ 3,
3942
+ ,
3943
+ 4
3944
+ ]);
3945
+ clientInfo = getClientInfo();
3946
+ return [
3947
+ 4,
3948
+ getBrowserID(clientInfo)
3949
+ ];
3950
+ case 1:
3951
+ browserId = _state.sent();
3952
+ trackingData = _object_spread({
3953
+ browserId: browserId
3954
+ }, clientInfo);
3955
+ return [
3956
+ 4,
3957
+ sendTrackRequest(licenseKey, _object_spread_props(_object_spread({}, trackingData), {
3958
+ licenseKey: licenseKey,
3959
+ adImpressionInfo: adImpressionInfo
3960
+ }))
3961
+ ];
3962
+ case 2:
3963
+ _state.sent();
3964
+ return [
3965
+ 3,
3966
+ 4
3967
+ ];
3968
+ case 3:
3969
+ error = _state.sent();
3970
+ console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
3971
+ return [
3972
+ 3,
3973
+ 4
3974
+ ];
3975
+ case 4:
3976
+ return [
3977
+ 2
3978
+ ];
3979
+ }
3980
+ });
3981
+ })();
3982
+ }
3787
3983
  function sendHeartbeat(licenseKey) {
3788
3984
  return _async_to_generator(function() {
3789
3985
  var clientInfo, browserId, heartbeatData, headers, response, error;
@@ -4143,6 +4339,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4143
4339
  this.minAdRequestIntervalMs = 2500;
4144
4340
  this.backoffBaseMs = 1e3;
4145
4341
  this.maxBackoffMs = 15e3;
4342
+ this.continuousFetchWallClockBufferMs = 3e4;
4343
+ this.continuousFetchMaxIterations = 500;
4344
+ this.continuousFetchQueueFullConsecutiveWaits = 0;
4146
4345
  this.preloadPool = [];
4147
4346
  this.maxPreloadPoolSize = 3;
4148
4347
  this.preloadPoolActive = false;
@@ -4202,6 +4401,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4202
4401
  }
4203
4402
  }
4204
4403
  },
4404
+ {
4405
+ key: "getAdPlayerTypeLabel",
4406
+ value: function getAdPlayerTypeLabel() {
4407
+ var t = this.config.adPlayerType;
4408
+ if (t === "prebid") return "Prebid";
4409
+ if (t === "hls") return "HLS";
4410
+ return "IMA";
4411
+ }
4412
+ },
4205
4413
  {
4206
4414
  key: "load",
4207
4415
  value: function load() {
@@ -4625,10 +4833,26 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4625
4833
  }).call(this);
4626
4834
  }
4627
4835
  },
4836
+ {
4837
+ key: "getAdSource",
4838
+ value: function getAdSource() {
4839
+ var _this_config_adPlayerType;
4840
+ return (_this_config_adPlayerType = this.config.adPlayerType) !== null && _this_config_adPlayerType !== void 0 ? _this_config_adPlayerType : "ima";
4841
+ }
4842
+ },
4628
4843
  {
4629
4844
  key: "attachImaEventListeners",
4630
4845
  value: function attachImaEventListeners() {
4631
4846
  var _this = this;
4847
+ this.ima.on("ad_impression", function() {
4848
+ if (_this.config.licenseKey) {
4849
+ sendAdImpressionTracking(_this.config.licenseKey, {
4850
+ source: _this.getAdSource(),
4851
+ adIndex: _this.currentAdIndex,
4852
+ timestamp: /* @__PURE__ */ new Date().toISOString()
4853
+ });
4854
+ }
4855
+ });
4632
4856
  this.ima.on("all_ads_completed", function() {
4633
4857
  var remaining = _this.getRemainingAdMs();
4634
4858
  _this.consecutiveFailures = 0;
@@ -4691,6 +4915,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4691
4915
  }
4692
4916
  });
4693
4917
  this.ima.on("content_resume", function() {
4918
+ console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s", _this.inAdBreak, _this.getRemainingAdMs());
4694
4919
  if (!_this.video.muted) {
4695
4920
  _this.video.muted = true;
4696
4921
  _this.video.volume = 0;
@@ -4721,15 +4946,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4721
4946
  }
4722
4947
  },
4723
4948
  {
4724
- key: "recreateImaController",
4725
- value: function recreateImaController() {
4949
+ key: "recreateAdController",
4950
+ value: function recreateAdController() {
4951
+ var label = this.getAdPlayerTypeLabel();
4726
4952
  if (this.config.debugAdTiming) {
4727
- console.log("[StormcloudVideoPlayer] Recreating ImaController for new ad");
4953
+ console.log("[StormcloudVideoPlayer] Recreating ad controller (".concat(label, ") for new ad"));
4728
4954
  }
4729
4955
  var shouldShowPlaceholder = this.inAdBreak && this.showAds;
4730
4956
  if (shouldShowPlaceholder && this.ima) {
4731
4957
  if (this.config.debugAdTiming) {
4732
- console.log("[StormcloudVideoPlayer] Showing placeholder before destroying old ImaController");
4958
+ console.log("[StormcloudVideoPlayer] Showing placeholder before destroying old ".concat(label, " controller"));
4733
4959
  }
4734
4960
  this.showPlaceholderLayer();
4735
4961
  this.ima.showPlaceholder();
@@ -4742,7 +4968,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4742
4968
  this.video.volume = 0;
4743
4969
  } catch (error) {
4744
4970
  if (this.config.debugAdTiming) {
4745
- console.warn("[StormcloudVideoPlayer] Error destroying old ImaController:", error);
4971
+ console.warn("[StormcloudVideoPlayer] Error destroying old ".concat(label, " controller:"), error);
4746
4972
  }
4747
4973
  }
4748
4974
  }
@@ -4822,7 +5048,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4822
5048
  });
4823
5049
  }
4824
5050
  if (this.config.debugAdTiming) {
4825
- console.log("[StormcloudVideoPlayer] Showing placeholder layer (between content and IMA)");
5051
+ console.log("[StormcloudVideoPlayer] Showing placeholder layer (between content and ".concat(this.getAdPlayerTypeLabel(), ")"));
4826
5052
  }
4827
5053
  }
4828
5054
  },
@@ -5079,6 +5305,20 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5079
5305
  var durationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : ((_this_pendingAdBreak = this.pendingAdBreak) === null || _this_pendingAdBreak === void 0 ? void 0 : _this_pendingAdBreak.marker.durationSeconds) != null ? this.pendingAdBreak.marker.durationSeconds * 1e3 : void 0;
5080
5306
  this.expectedAdBreakDurationMs = durationMs;
5081
5307
  this.currentAdBreakStartWallClockMs = Date.now();
5308
+ if (this.config.licenseKey) {
5309
+ var _this_pendingAdBreak1;
5310
+ var adDetectInfo = _object_spread({
5311
+ source: "scte35",
5312
+ timestamp: /* @__PURE__ */ new Date().toISOString()
5313
+ }, marker.durationSeconds != null && {
5314
+ durationSeconds: marker.durationSeconds
5315
+ }, marker.ptsSeconds != null && {
5316
+ ptsSeconds: marker.ptsSeconds
5317
+ }, ((_this_pendingAdBreak1 = this.pendingAdBreak) === null || _this_pendingAdBreak1 === void 0 ? void 0 : _this_pendingAdBreak1.detectedAtFragmentSn) != null && {
5318
+ detectedAtFragmentSn: this.pendingAdBreak.detectedAtFragmentSn
5319
+ });
5320
+ sendAdDetectTracking(this.config.licenseKey, adDetectInfo);
5321
+ }
5082
5322
  var isManifestMarker = this.isManifestBasedMarker(marker);
5083
5323
  var forceImmediate = (_this_config_immediateManifestAds = this.config.immediateManifestAds) !== null && _this_config_immediateManifestAds !== void 0 ? _this_config_immediateManifestAds : true;
5084
5324
  if (this.config.debugAdTiming) {
@@ -5534,6 +5774,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5534
5774
  return this.config.adPlayerType === "prebid";
5535
5775
  }
5536
5776
  },
5777
+ {
5778
+ key: "isLgStbDevice",
5779
+ value: function isLgStbDevice() {
5780
+ if (typeof navigator === "undefined" || !navigator.userAgent) return false;
5781
+ var ua = navigator.userAgent;
5782
+ return /Web0S|webOS|LG Browser|LGSTB/i.test(ua);
5783
+ }
5784
+ },
5537
5785
  {
5538
5786
  key: "getCurrentAdIndex",
5539
5787
  value: function getCurrentAdIndex() {
@@ -6056,7 +6304,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6056
6304
  key: "handleAdStart",
6057
6305
  value: function handleAdStart(_marker) {
6058
6306
  return _async_to_generator(function() {
6059
- var scheduled, tags, isPrebid, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adVolume, adVolume1, error, fallbackPreloaded, adVolume2, fallbackError;
6307
+ var scheduled, tags, isPrebid, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adLoadedInfo, adVolume, adLoadedInfo1, adVolume1, error, fallbackPreloaded, adVolume2, fallbackError;
6060
6308
  return _ts_generator(this, function(_state) {
6061
6309
  switch(_state.label){
6062
6310
  case 0:
@@ -6168,6 +6416,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6168
6416
  this.video.volume = 0;
6169
6417
  this.ima = preloadedController;
6170
6418
  this.attachImaEventListeners();
6419
+ if (this.config.licenseKey) {
6420
+ adLoadedInfo = _object_spread({
6421
+ source: this.getAdSource(),
6422
+ timestamp: /* @__PURE__ */ new Date().toISOString()
6423
+ }, firstAdUrl && {
6424
+ vastUrl: firstAdUrl
6425
+ });
6426
+ sendAdLoadedTracking(this.config.licenseKey, adLoadedInfo);
6427
+ }
6171
6428
  if (this.config.debugAdTiming) {
6172
6429
  console.log("[CONTINUOUS-FETCH] \u2705 Using preloaded ad, resuming and starting playback immediately (no request delay!)");
6173
6430
  }
@@ -6203,6 +6460,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6203
6460
  ];
6204
6461
  case 4:
6205
6462
  _state.sent();
6463
+ if (this.config.licenseKey) {
6464
+ adLoadedInfo1 = _object_spread({
6465
+ source: this.getAdSource(),
6466
+ timestamp: /* @__PURE__ */ new Date().toISOString()
6467
+ }, firstAdUrl && {
6468
+ vastUrl: firstAdUrl
6469
+ });
6470
+ sendAdLoadedTracking(this.config.licenseKey, adLoadedInfo1);
6471
+ }
6206
6472
  if (this.config.debugAdTiming) {
6207
6473
  console.log("[CONTINUOUS-FETCH] \u2705 First ad request successful, starting playback");
6208
6474
  }
@@ -6348,15 +6614,34 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6348
6614
  key: "continuousFetchLoop",
6349
6615
  value: function continuousFetchLoop(baseVastUrl) {
6350
6616
  return _async_to_generator(function() {
6351
- var _this, _loop, _ret;
6617
+ var loopIterations, _this, _loop, _ret;
6352
6618
  return _ts_generator(this, function(_state) {
6353
6619
  switch(_state.label){
6354
6620
  case 0:
6621
+ loopIterations = 0;
6622
+ _state.label = 1;
6623
+ case 1:
6624
+ _state.trys.push([
6625
+ 1,
6626
+ ,
6627
+ 5,
6628
+ 6
6629
+ ]);
6355
6630
  _loop = function() {
6356
- var remaining, maxQueueSize, newAdUrl, queuedUrlsPreview, generationDelay;
6631
+ var remaining, elapsedMs, maxLoopMs, maxQueueSize, newAdUrl, queuedUrlsPreview, generationDelay;
6357
6632
  return _ts_generator(this, function(_state) {
6358
6633
  switch(_state.label){
6359
6634
  case 0:
6635
+ loopIterations++;
6636
+ if (loopIterations > _this.continuousFetchMaxIterations) {
6637
+ if (_this.config.debugAdTiming) {
6638
+ console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Max iterations reached (".concat(_this.continuousFetchMaxIterations, "), stopping URL generation"));
6639
+ }
6640
+ return [
6641
+ 2,
6642
+ "break"
6643
+ ];
6644
+ }
6360
6645
  remaining = _this.getRemainingAdMs();
6361
6646
  if (remaining <= 0) {
6362
6647
  if (_this.config.debugAdTiming) {
@@ -6367,6 +6652,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6367
6652
  "break"
6368
6653
  ];
6369
6654
  }
6655
+ if (_this.currentAdBreakStartWallClockMs != null && _this.expectedAdBreakDurationMs != null) {
6656
+ elapsedMs = Date.now() - _this.currentAdBreakStartWallClockMs;
6657
+ maxLoopMs = _this.expectedAdBreakDurationMs + _this.continuousFetchWallClockBufferMs;
6658
+ if (elapsedMs >= maxLoopMs) {
6659
+ if (_this.config.debugAdTiming) {
6660
+ console.log("[CONTINUOUS-FETCH] ⏹️ Wall-clock limit reached (".concat(elapsedMs, "ms >= ").concat(maxLoopMs, "ms), stopping URL generation"));
6661
+ }
6662
+ return [
6663
+ 2,
6664
+ "break"
6665
+ ];
6666
+ }
6667
+ }
6370
6668
  if (_this.consecutiveFailures >= _this.maxConsecutiveFailures) {
6371
6669
  if (_this.config.debugAdTiming) {
6372
6670
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Too many consecutive failures (".concat(_this.consecutiveFailures, "), stopping URL generation"));
@@ -6388,46 +6686,63 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6388
6686
  maxQueueSize = 5;
6389
6687
  if (!(_this.adRequestQueue.length >= maxQueueSize)) return [
6390
6688
  3,
6391
- 2
6689
+ 4
6392
6690
  ];
6691
+ if (!(_this.isPrebidMode() && _this.isLgStbDevice())) return [
6692
+ 3,
6693
+ 1
6694
+ ];
6695
+ _this.adRequestQueue.shift();
6696
+ _this.adRequestQueue.push("");
6697
+ _this.totalAdsInBreak++;
6698
+ _this.continuousFetchQueueFullConsecutiveWaits = 0;
6393
6699
  if (_this.config.debugAdTiming) {
6394
- console.log("[CONTINUOUS-FETCH] ⏸️ URL queue full (".concat(_this.adRequestQueue.length, "), waiting..."));
6700
+ console.log("[CONTINUOUS-FETCH] Prebid slot rotated (queue full, dropped oldest); queue: ".concat(_this.adRequestQueue.length));
6395
6701
  }
6396
6702
  return [
6397
- 4,
6398
- new Promise(function(resolve) {
6399
- return setTimeout(resolve, 1e3);
6400
- })
6703
+ 3,
6704
+ 3
6401
6705
  ];
6402
6706
  case 1:
6707
+ return [
6708
+ 4,
6709
+ _this.waitForQueueWithBackoff()
6710
+ ];
6711
+ case 2:
6403
6712
  _state.sent();
6404
6713
  return [
6405
6714
  2,
6406
6715
  "continue"
6407
6716
  ];
6408
- case 2:
6717
+ case 3:
6718
+ return [
6719
+ 3,
6720
+ 8
6721
+ ];
6722
+ case 4:
6409
6723
  if (!_this.isPrebidMode()) return [
6410
6724
  3,
6411
- 3
6725
+ 5
6412
6726
  ];
6413
6727
  _this.adRequestQueue.push("");
6414
6728
  _this.totalAdsInBreak++;
6729
+ _this.continuousFetchQueueFullConsecutiveWaits = 0;
6415
6730
  if (_this.config.debugAdTiming) {
6416
6731
  console.log("[CONTINUOUS-FETCH] Prebid auction slot queued (queue: ".concat(_this.adRequestQueue.length, ")"));
6417
6732
  }
6418
6733
  return [
6419
6734
  3,
6420
- 6
6735
+ 8
6421
6736
  ];
6422
- case 3:
6737
+ case 5:
6423
6738
  if (!baseVastUrl) return [
6424
6739
  3,
6425
- 6
6740
+ 8
6426
6741
  ];
6427
6742
  newAdUrl = _this.generateVastUrlsWithCorrelators(baseVastUrl, 1)[0];
6428
6743
  if (!(!newAdUrl || _this.failedVastUrls.has(newAdUrl) || _this.isUrlInCooldown(newAdUrl))) return [
6429
6744
  3,
6430
- 5
6745
+ 7
6431
6746
  ];
6432
6747
  return [
6433
6748
  4,
@@ -6435,13 +6750,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6435
6750
  return setTimeout(resolve, 500);
6436
6751
  })
6437
6752
  ];
6438
- case 4:
6753
+ case 6:
6439
6754
  _state.sent();
6440
6755
  return [
6441
6756
  2,
6442
6757
  "continue"
6443
6758
  ];
6444
- case 5:
6759
+ case 7:
6445
6760
  if (_this.config.debugAdTiming) {
6446
6761
  queuedUrlsPreview = _to_consumable_array(_this.adRequestQueue).concat([
6447
6762
  newAdUrl
@@ -6452,8 +6767,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6452
6767
  }
6453
6768
  _this.adRequestQueue.push(newAdUrl);
6454
6769
  _this.totalAdsInBreak++;
6455
- _state.label = 6;
6456
- case 6:
6770
+ _this.continuousFetchQueueFullConsecutiveWaits = 0;
6771
+ _state.label = 8;
6772
+ case 8:
6457
6773
  generationDelay = _this.consecutiveFailures > 0 ? Math.min(1e3 * Math.pow(2, _this.consecutiveFailures), 5e3) : 500;
6458
6774
  return [
6459
6775
  4,
@@ -6461,7 +6777,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6461
6777
  return setTimeout(resolve, generationDelay);
6462
6778
  })
6463
6779
  ];
6464
- case 7:
6780
+ case 9:
6465
6781
  _state.sent();
6466
6782
  return [
6467
6783
  2
@@ -6469,33 +6785,41 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6469
6785
  }
6470
6786
  });
6471
6787
  };
6472
- _state.label = 1;
6473
- case 1:
6788
+ _state.label = 2;
6789
+ case 2:
6474
6790
  if (!(this.continuousFetchingActive && this.inAdBreak)) return [
6475
6791
  3,
6476
- 3
6792
+ 4
6477
6793
  ];
6478
6794
  _this = this;
6479
6795
  return [
6480
6796
  5,
6481
6797
  _ts_values(_loop())
6482
6798
  ];
6483
- case 2:
6799
+ case 3:
6484
6800
  _ret = _state.sent();
6485
6801
  if (_ret === "break") return [
6486
6802
  3,
6487
- 3
6803
+ 4
6488
6804
  ];
6489
6805
  return [
6490
6806
  3,
6491
- 1
6807
+ 2
6492
6808
  ];
6493
- case 3:
6809
+ case 4:
6810
+ return [
6811
+ 3,
6812
+ 6
6813
+ ];
6814
+ case 5:
6494
6815
  this.continuousFetchLoopRunning = false;
6816
+ this.continuousFetchQueueFullConsecutiveWaits = 0;
6817
+ return [
6818
+ 7
6819
+ ];
6820
+ case 6:
6495
6821
  if (this.config.debugAdTiming) {
6496
- console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 URL generation loop ended (queued: ".concat(this.adRequestQueue.length, ")"), this.adRequestQueue.length > 0 ? {
6497
- queuedUrls: _to_consumable_array(this.adRequestQueue)
6498
- } : {});
6822
+ this.logQueueState("URL generation loop ended");
6499
6823
  }
6500
6824
  return [
6501
6825
  2
@@ -6505,6 +6829,51 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6505
6829
  }).call(this);
6506
6830
  }
6507
6831
  },
6832
+ {
6833
+ key: "waitForQueueWithBackoff",
6834
+ value: function waitForQueueWithBackoff() {
6835
+ return _async_to_generator(function() {
6836
+ var delayMs, shouldLog;
6837
+ return _ts_generator(this, function(_state) {
6838
+ switch(_state.label){
6839
+ case 0:
6840
+ this.continuousFetchQueueFullConsecutiveWaits++;
6841
+ delayMs = Math.min(1e3 * Math.pow(2, this.continuousFetchQueueFullConsecutiveWaits - 1), 5e3);
6842
+ shouldLog = this.config.debugAdTiming && (this.continuousFetchQueueFullConsecutiveWaits <= 2 || this.continuousFetchQueueFullConsecutiveWaits % 4 === 0);
6843
+ if (shouldLog) {
6844
+ console.log("[CONTINUOUS-FETCH] ⏸️ URL queue full (".concat(this.adRequestQueue.length, "), waiting ").concat(delayMs, "ms (wait #").concat(this.continuousFetchQueueFullConsecutiveWaits, ")"));
6845
+ }
6846
+ return [
6847
+ 4,
6848
+ new Promise(function(resolve) {
6849
+ return setTimeout(resolve, delayMs);
6850
+ })
6851
+ ];
6852
+ case 1:
6853
+ _state.sent();
6854
+ return [
6855
+ 2
6856
+ ];
6857
+ }
6858
+ });
6859
+ }).call(this);
6860
+ }
6861
+ },
6862
+ {
6863
+ key: "logQueueState",
6864
+ value: function logQueueState(reason) {
6865
+ if (!this.config.debugAdTiming) return;
6866
+ console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 ".concat(reason), {
6867
+ queueLength: this.adRequestQueue.length,
6868
+ totalAdsInBreak: this.totalAdsInBreak,
6869
+ totalAdRequestsInBreak: this.totalAdRequestsInBreak,
6870
+ consecutiveFailures: this.consecutiveFailures,
6871
+ continuousFetchingActive: this.continuousFetchingActive,
6872
+ continuousFetchLoopRunning: this.continuousFetchLoopRunning,
6873
+ inAdBreak: this.inAdBreak
6874
+ });
6875
+ }
6876
+ },
6508
6877
  {
6509
6878
  key: "stopContinuousFetching",
6510
6879
  value: function stopContinuousFetching() {
@@ -6569,7 +6938,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6569
6938
  value: function tryNextAvailableAd() {
6570
6939
  var retryCount = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 0;
6571
6940
  return _async_to_generator(function() {
6572
- var remaining, preloaded, currentMuted, currentVolume, adVolume, error, nextAdUrl, currentMuted1, currentVolume1, error1, errorMessage, maxRetries;
6941
+ var remaining, preloaded, adLoadedInfo, currentMuted, currentVolume, adVolume, error, nextAdUrl, currentMuted1, currentVolume1, error1, errorMessage, maxRetries;
6573
6942
  return _ts_generator(this, function(_state) {
6574
6943
  switch(_state.label){
6575
6944
  case 0:
@@ -6614,6 +6983,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6614
6983
  this.video.volume = 0;
6615
6984
  this.ima = preloaded.imaController;
6616
6985
  this.attachImaEventListeners();
6986
+ if (this.config.licenseKey) {
6987
+ adLoadedInfo = {
6988
+ source: this.getAdSource(),
6989
+ timestamp: /* @__PURE__ */ new Date().toISOString()
6990
+ };
6991
+ sendAdLoadedTracking(this.config.licenseKey, adLoadedInfo);
6992
+ }
6617
6993
  this.ima.resume();
6618
6994
  this.currentAdIndex++;
6619
6995
  this.totalAdRequestsInBreak++;
@@ -6675,8 +7051,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6675
7051
  4
6676
7052
  ];
6677
7053
  }
7054
+ console.log("[StormcloudVideoPlayer] Requesting next ad (%s), queue remaining=%s", nextAdUrl === "" ? "Prebid" : "VAST", this.adRequestQueue.length);
6678
7055
  if (this.config.debugAdTiming) {
6679
- console.log("[CONTINUOUS-FETCH] \uD83C\uDFAC Requesting next ad via IMA SDK (".concat(this.currentAdIndex + 1, "/").concat(this.totalAdsInBreak, ", ").concat(this.adRequestQueue.length, " remaining in queue)"));
7056
+ console.log("[CONTINUOUS-FETCH] \uD83C\uDFAC Requesting next ad via ".concat(this.getAdPlayerTypeLabel(), " (").concat(this.currentAdIndex + 1, "/").concat(this.totalAdsInBreak, ", ").concat(this.adRequestQueue.length, " remaining in queue)"));
6680
7057
  }
6681
7058
  currentMuted1 = this.video.muted;
6682
7059
  currentVolume1 = this.video.volume;
@@ -6856,7 +7233,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6856
7233
  ];
6857
7234
  }
6858
7235
  if (this.config.debugAdTiming) {
6859
- console.log("[CONTINUOUS-FETCH] \u2705 Ad URL available, requesting via IMA SDK");
7236
+ console.log("[CONTINUOUS-FETCH] Ad URL available, requesting via ".concat(this.getAdPlayerTypeLabel()));
6860
7237
  }
6861
7238
  this.isShowingPlaceholder = false;
6862
7239
  this.ima.hidePlaceholder();
@@ -7171,7 +7548,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7171
7548
  key: "playSingleAd",
7172
7549
  value: function playSingleAd(vastTagUrl) {
7173
7550
  return _async_to_generator(function() {
7174
- var requestToken, currentMuted, currentVolume, adVolume, playError, preloadedFallback, currentMuted1, currentVolume1, adVolume1, fallbackError, error, errorMessage, preloadedFallback1, currentMuted2, currentVolume2, adVolume2, fallbackError1;
7551
+ var requestToken, adLoadedInfo, currentMuted, currentVolume, adVolume, playError, preloadedFallback, currentMuted1, currentVolume1, adVolume1, fallbackError, error, errorMessage, preloadedFallback1, currentMuted2, currentVolume2, adVolume2, fallbackError1;
7175
7552
  return _ts_generator(this, function(_state) {
7176
7553
  switch(_state.label){
7177
7554
  case 0:
@@ -7198,7 +7575,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7198
7575
  }
7199
7576
  throw new Error("Too many consecutive failures");
7200
7577
  }
7201
- this.recreateImaController();
7578
+ this.recreateAdController();
7202
7579
  requestToken = ++this.adRequestTokenCounter;
7203
7580
  this.activeAdRequestToken = requestToken;
7204
7581
  this.startAdRequestWatchdog(requestToken);
@@ -7223,6 +7600,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7223
7600
  2
7224
7601
  ];
7225
7602
  }
7603
+ if (this.config.licenseKey) {
7604
+ adLoadedInfo = _object_spread({
7605
+ source: this.getAdSource(),
7606
+ timestamp: /* @__PURE__ */ new Date().toISOString()
7607
+ }, vastTagUrl && {
7608
+ vastUrl: vastTagUrl
7609
+ });
7610
+ sendAdLoadedTracking(this.config.licenseKey, adLoadedInfo);
7611
+ }
7226
7612
  _state.label = 3;
7227
7613
  case 3:
7228
7614
  _state.trys.push([
@@ -7443,6 +7829,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7443
7829
  this.showAds = false;
7444
7830
  this.currentAdIndex = 0;
7445
7831
  this.totalAdsInBreak = 0;
7832
+ this.totalAdRequestsInBreak = 0;
7446
7833
  this.consecutiveFailures = 0;
7447
7834
  this.ima.stop().catch(function() {});
7448
7835
  var restoredMuted = this.ima.getOriginalMutedState();
@@ -7454,17 +7841,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7454
7841
  this.video.volume = restoredVolume;
7455
7842
  }
7456
7843
  if (this.shouldContinueLiveStreamDuringAds()) {
7457
- if (this.video.paused) {
7458
- var _this_video_play;
7459
- if (this.config.debugAdTiming) {
7844
+ var _this_video_play;
7845
+ if (this.config.debugAdTiming) {
7846
+ if (this.video.paused) {
7460
7847
  console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
7461
- }
7462
- (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
7463
- } else {
7464
- if (this.config.debugAdTiming) {
7848
+ } else {
7465
7849
  console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
7466
7850
  }
7467
7851
  }
7852
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
7468
7853
  } else if (this.video.paused) {
7469
7854
  var _this_video_play1;
7470
7855
  (_this_video_play1 = this.video.play()) === null || _this_video_play1 === void 0 ? void 0 : _this_video_play1.catch(function() {});