stormcloud-video-player 0.8.34 → 0.8.36

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 (39) hide show
  1. package/dist/stormcloud-vp.min.js +1 -1
  2. package/lib/index.cjs +120 -16
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +21 -19
  5. package/lib/index.d.ts +21 -19
  6. package/lib/index.js +120 -16
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/AdBreakOrchestrator.cjs +36 -16
  9. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  10. package/lib/player/AdBreakOrchestrator.d.cts +3 -7
  11. package/lib/player/AdConfigManager.cjs +18 -0
  12. package/lib/player/AdConfigManager.cjs.map +1 -1
  13. package/lib/player/AdConfigManager.d.cts +2 -1
  14. package/lib/player/AdTimingService.d.cts +1 -1
  15. package/lib/player/HlsEngine.d.cts +1 -1
  16. package/lib/player/PlayerControls.d.cts +1 -1
  17. package/lib/player/Scte35CueManager.d.cts +1 -1
  18. package/lib/player/Scte35Parser.d.cts +1 -1
  19. package/lib/player/StormcloudVideoPlayer.cjs +123 -16
  20. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  21. package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
  22. package/lib/player/playerTypes.d.cts +1 -1
  23. package/lib/players/HlsPlayer.cjs +123 -16
  24. package/lib/players/HlsPlayer.cjs.map +1 -1
  25. package/lib/players/HlsPlayer.d.cts +1 -1
  26. package/lib/players/index.cjs +123 -16
  27. package/lib/players/index.cjs.map +1 -1
  28. package/lib/sdk/hlsAdPlayer.cjs +62 -0
  29. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  30. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  31. package/lib/{types-CSHvCbhZ.d.cts → types-cTqIKw_D.d.cts} +1 -0
  32. package/lib/ui/StormcloudVideoPlayer.cjs +123 -16
  33. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  34. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  35. package/lib/utils/browserCompat.cjs +1 -0
  36. package/lib/utils/browserCompat.cjs.map +1 -1
  37. package/lib/utils/browserCompat.d.cts +1 -0
  38. package/lib/utils/tracking.d.cts +1 -1
  39. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { b as AdBreak, a as StormcloudVideoPlayerConfig, A as AdController } from '../types-CSHvCbhZ.cjs';
1
+ import { b as AdBreak, a as StormcloudVideoPlayerConfig, A as AdController } from '../types-cTqIKw_D.cjs';
2
2
  import { PalNonceManager } from '../sdk/pal.cjs';
3
3
  import { VastConsentSignals } from '../utils/vastMacros.cjs';
4
4
 
@@ -20,6 +20,7 @@ declare class AdConfigManager {
20
20
  get debug(): boolean;
21
21
  isVmapEnabled(): boolean;
22
22
  fetchAdConfiguration(): Promise<void>;
23
+ private applyMqttConfigFromResponse;
23
24
  private fetchAndParseVmap;
24
25
  private parseVmapToBreaks;
25
26
  private parseVmapTimeOffsetToMs;
@@ -1,4 +1,4 @@
1
- import { a as StormcloudVideoPlayerConfig, S as Scte35Marker, A as AdController } from '../types-CSHvCbhZ.cjs';
1
+ import { a as StormcloudVideoPlayerConfig, S as Scte35Marker, A as AdController } from '../types-cTqIKw_D.cjs';
2
2
 
3
3
  interface AdTimingCallbacks {
4
4
  onAdStopTimerFired(): void;
@@ -1,5 +1,5 @@
1
1
  import Hls from 'hls.js';
2
- import { a as StormcloudVideoPlayerConfig, S as Scte35Marker } from '../types-CSHvCbhZ.cjs';
2
+ import { a as StormcloudVideoPlayerConfig, S as Scte35Marker } from '../types-cTqIKw_D.cjs';
3
3
  import { Scte35CueContext } from './playerTypes.cjs';
4
4
  import { Scte35CueManager } from './Scte35CueManager.cjs';
5
5
  import { AdTimingService } from './AdTimingService.cjs';
@@ -1,4 +1,4 @@
1
- import { A as AdController } from '../types-CSHvCbhZ.cjs';
1
+ import { A as AdController } from '../types-cTqIKw_D.cjs';
2
2
 
3
3
  declare function getAdAudioVolume(adPlayer: AdController): number;
4
4
  declare function toggleMute(video: HTMLVideoElement, adPlayer: AdController, debug: boolean): void;
@@ -1,4 +1,4 @@
1
- import { S as Scte35Marker } from '../types-CSHvCbhZ.cjs';
1
+ import { S as Scte35Marker } from '../types-cTqIKw_D.cjs';
2
2
  import { Scte35CueSource, Scte35CueReadiness, Scte35CueContext } from './playerTypes.cjs';
3
3
 
4
4
  interface Scte35CueManagerCallbacks {
@@ -1,4 +1,4 @@
1
- import { S as Scte35Marker, I as Id3TagInfo } from '../types-CSHvCbhZ.cjs';
1
+ import { S as Scte35Marker, I as Id3TagInfo } from '../types-cTqIKw_D.cjs';
2
2
 
3
3
  declare function parseCueOutDuration(value: string): number | undefined;
4
4
  declare function parseCueOutCont(value: string): {
@@ -368,6 +368,11 @@ function createHlsAdPlayer(contentVideo, options) {
368
368
  var preloadingAds = /* @__PURE__ */ new Map();
369
369
  var destroyed = false;
370
370
  var pendingTimeouts = [];
371
+ var STALL_TIMEOUT_MS = 4e3;
372
+ var STALL_CHECK_INTERVAL_MS = 1e3;
373
+ var stallWatchdogId;
374
+ var lastAdProgressTime = 0;
375
+ var lastAdProgressPosition = 0;
371
376
  var trackingFired = {
372
377
  impression: false,
373
378
  start: false,
@@ -1000,6 +1005,7 @@ function createHlsAdPlayer(contentVideo, options) {
1000
1005
  if (!adVideoElement || !currentAd) return;
1001
1006
  adVideoElement.addEventListener("timeupdate", function() {
1002
1007
  if (!currentAd || !adVideoElement) return;
1008
+ noteAdProgress();
1003
1009
  var progress = adVideoElement.currentTime / currentAd.duration;
1004
1010
  if (progress >= 0.25 && !trackingFired.firstQuartile) {
1005
1011
  trackingFired.firstQuartile = true;
@@ -1015,6 +1021,7 @@ function createHlsAdPlayer(contentVideo, options) {
1015
1021
  }
1016
1022
  });
1017
1023
  adVideoElement.addEventListener("playing", function() {
1024
+ startStallWatchdog();
1018
1025
  if (!currentAd || trackingFired.start) return;
1019
1026
  trackingFired.start = true;
1020
1027
  fireTrackingPixels(currentAd.trackingUrls.start);
@@ -1155,8 +1162,52 @@ function createHlsAdPlayer(contentVideo, options) {
1155
1162
  return false;
1156
1163
  }
1157
1164
  }
1165
+ function clearStallWatchdog() {
1166
+ if (stallWatchdogId != null) {
1167
+ clearInterval(stallWatchdogId);
1168
+ stallWatchdogId = void 0;
1169
+ }
1170
+ }
1171
+ function noteAdProgress() {
1172
+ lastAdProgressTime = Date.now();
1173
+ if (adVideoElement) {
1174
+ lastAdProgressPosition = adVideoElement.currentTime;
1175
+ }
1176
+ }
1177
+ function handleAdStall() {
1178
+ console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1179
+ clearStallWatchdog();
1180
+ if (currentAd) {
1181
+ fireTrackingPixels(currentAd.trackingUrls.error);
1182
+ }
1183
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1184
+ return;
1185
+ }
1186
+ handleAdError();
1187
+ }
1188
+ function startStallWatchdog() {
1189
+ clearStallWatchdog();
1190
+ noteAdProgress();
1191
+ stallWatchdogId = window.setInterval(function() {
1192
+ if (!adPlaying || !adVideoElement) {
1193
+ return;
1194
+ }
1195
+ if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1196
+ noteAdProgress();
1197
+ return;
1198
+ }
1199
+ if (adVideoElement.paused) {
1200
+ noteAdProgress();
1201
+ return;
1202
+ }
1203
+ if (Date.now() - lastAdProgressTime >= STALL_TIMEOUT_MS) {
1204
+ handleAdStall();
1205
+ }
1206
+ }, STALL_CHECK_INTERVAL_MS);
1207
+ }
1158
1208
  function handleAdComplete() {
1159
1209
  console.log("[HlsAdPlayer] Handling ad completion");
1210
+ clearStallWatchdog();
1160
1211
  adPlaying = false;
1161
1212
  setAdPlayingFlag(false);
1162
1213
  contentVideo.muted = true;
@@ -1164,6 +1215,10 @@ function createHlsAdPlayer(contentVideo, options) {
1164
1215
  adContainerEl.style.display = "none";
1165
1216
  adContainerEl.style.pointerEvents = "none";
1166
1217
  }
1218
+ if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
1219
+ contentVideo.style.visibility = "visible";
1220
+ contentVideo.style.opacity = "1";
1221
+ }
1167
1222
  if (options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) {
1168
1223
  if (contentVideo.paused) {
1169
1224
  console.log("[HlsAdPlayer] Content video paused in live mode, resuming playback");
@@ -1176,6 +1231,7 @@ function createHlsAdPlayer(contentVideo, options) {
1176
1231
  }
1177
1232
  function handleAdError() {
1178
1233
  console.log("[HlsAdPlayer] Handling ad error");
1234
+ clearStallWatchdog();
1179
1235
  adPlaying = false;
1180
1236
  setAdPlayingFlag(false);
1181
1237
  contentVideo.muted = true;
@@ -1183,6 +1239,10 @@ function createHlsAdPlayer(contentVideo, options) {
1183
1239
  adContainerEl.style.display = "none";
1184
1240
  adContainerEl.style.pointerEvents = "none";
1185
1241
  }
1242
+ if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
1243
+ contentVideo.style.visibility = "visible";
1244
+ contentVideo.style.opacity = "1";
1245
+ }
1186
1246
  emit("ad_error");
1187
1247
  }
1188
1248
  return {
@@ -1380,6 +1440,7 @@ function createHlsAdPlayer(contentVideo, options) {
1380
1440
  var previousMutedState;
1381
1441
  return _ts_generator(this, function(_state) {
1382
1442
  console.log("[HlsAdPlayer] Stopping ad");
1443
+ clearStallWatchdog();
1383
1444
  adPlaying = false;
1384
1445
  setAdPlayingFlag(false);
1385
1446
  previousMutedState = contentVideo.muted;
@@ -1418,6 +1479,7 @@ function createHlsAdPlayer(contentVideo, options) {
1418
1479
  destroy: function destroy() {
1419
1480
  console.log("[HlsAdPlayer] Destroying");
1420
1481
  destroyed = true;
1482
+ clearStallWatchdog();
1421
1483
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1422
1484
  try {
1423
1485
  for(var _iterator = pendingTimeouts[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -1793,6 +1855,9 @@ var DEFAULT_MQTT_CONFIG = {
1793
1855
  qos: 1
1794
1856
  };
1795
1857
  var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
1858
+ function applyMQTTConfig(overrides) {
1859
+ Object.assign(mqttConfig, overrides);
1860
+ }
1796
1861
  function isMQTTEnabled() {
1797
1862
  return mqttConfig.enabled;
1798
1863
  }
@@ -3809,6 +3874,7 @@ function getBrowserConfigOverrides() {
3809
3874
  var overrides = {};
3810
3875
  if (browser.isSmartTV) {
3811
3876
  overrides.allowNativeHls = true;
3877
+ overrides.pauseContentDuringAds = true;
3812
3878
  }
3813
3879
  return overrides;
3814
3880
  }
@@ -4963,6 +5029,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4963
5029
  ];
4964
5030
  case 4:
4965
5031
  data = _state.sent();
5032
+ this.applyMqttConfigFromResponse(data);
4966
5033
  imaPayload = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
4967
5034
  if (imaPayload) {
4968
5035
  decodedPayload = imaPayload;
@@ -4996,6 +5063,20 @@ var AdConfigManager = /*#__PURE__*/ function() {
4996
5063
  }).call(this);
4997
5064
  }
4998
5065
  },
5066
+ {
5067
+ key: "applyMqttConfigFromResponse",
5068
+ value: function applyMqttConfigFromResponse(data) {
5069
+ var _data_response;
5070
+ var mqttConfig2 = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : _data_response.mqtt_config;
5071
+ if (!mqttConfig2 || (typeof mqttConfig2 === "undefined" ? "undefined" : _type_of(mqttConfig2)) !== "object") {
5072
+ return;
5073
+ }
5074
+ applyMQTTConfig(mqttConfig2);
5075
+ if (this.debug) {
5076
+ console.log("[StormcloudVideoPlayer] Applied MQTT config from /ads/web:", mqttConfig2);
5077
+ }
5078
+ }
5079
+ },
4999
5080
  {
5000
5081
  key: "fetchAndParseVmap",
5001
5082
  value: function fetchAndParseVmap(vmapUrl) {
@@ -6691,12 +6772,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6691
6772
  // ───────────────────────────────────────────────────────────────
6692
6773
  // IMA event listeners
6693
6774
  // ───────────────────────────────────────────────────────────────
6694
- /**
6695
- * Produces the next pod ad-request URL for the current break. Every request
6696
- * (initial and continuous-fetch top-up) carries pod macros (pmad/pmnd/pmxd,
6697
- * no ppos); pmxd tracks the remaining break time so top-up pods only ask for
6698
- * what still fits.
6699
- */ key: "nextAdRequestUrl",
6775
+ key: "nextAdRequestUrl",
6700
6776
  value: function nextAdRequestUrl(baseVastUrl) {
6701
6777
  var remaining = Math.min(this.timing.getWallClockRemainingAdMs(), this.timing.getDurationBudgetRemainingMs());
6702
6778
  var breakDurationMs = remaining > 0 ? remaining : void 0;
@@ -7825,7 +7901,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7825
7901
  if (Math.abs(this.host.video.volume - restoredVolume) > 0.01) {
7826
7902
  this.host.video.volume = restoredVolume;
7827
7903
  }
7828
- if (this.host.shouldContinueLiveStreamDuringAds()) {
7904
+ this.host.video.style.visibility = "visible";
7905
+ this.host.video.style.opacity = "1";
7906
+ if (this.host.isLiveStream()) {
7829
7907
  var liveSyncPos = this.host.getLiveSyncPosition();
7830
7908
  if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
7831
7909
  if (this.debug) {
@@ -7833,16 +7911,39 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7833
7911
  }
7834
7912
  this.host.video.currentTime = liveSyncPos;
7835
7913
  }
7836
- if (this.host.video.paused) {
7837
- var _this_host_video_play;
7838
- if (this.debug) console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
7839
- (_this_host_video_play = this.host.video.play()) === null || _this_host_video_play === void 0 ? void 0 : _this_host_video_play.catch(function() {});
7840
- } else {
7841
- if (this.debug) console.log("[StormcloudVideoPlayer] Content video already playing in live mode after ads");
7914
+ }
7915
+ this.resumeContentPlayback();
7916
+ }
7917
+ },
7918
+ {
7919
+ key: "resumeContentPlayback",
7920
+ value: function resumeContentPlayback() {
7921
+ var _this = this;
7922
+ var attempt = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 0;
7923
+ var maxAttempts = 3;
7924
+ if (!this.host.video.paused) {
7925
+ if (this.debug && attempt === 0) {
7926
+ console.log("[StormcloudVideoPlayer] Content video already playing after ads");
7842
7927
  }
7843
- } else if (this.host.video.paused) {
7844
- var _this_host_video_play1;
7845
- (_this_host_video_play1 = this.host.video.play()) === null || _this_host_video_play1 === void 0 ? void 0 : _this_host_video_play1.catch(function() {});
7928
+ return;
7929
+ }
7930
+ if (this.debug) {
7931
+ console.log("[StormcloudVideoPlayer] Resuming content playback after ads (attempt ".concat(attempt + 1, "/").concat(maxAttempts, ")"));
7932
+ }
7933
+ var playResult = this.host.video.play();
7934
+ if (playResult && typeof playResult.catch === "function") {
7935
+ playResult.catch(function(error) {
7936
+ if (attempt + 1 >= maxAttempts) {
7937
+ if (_this.debug) {
7938
+ console.warn("[StormcloudVideoPlayer] Failed to resume content playback after ads:", error);
7939
+ }
7940
+ return;
7941
+ }
7942
+ var backoffMs = 250 * (attempt + 1);
7943
+ window.setTimeout(function() {
7944
+ _this.resumeContentPlayback(attempt + 1);
7945
+ }, backoffMs);
7946
+ });
7846
7947
  }
7847
7948
  }
7848
7949
  },
@@ -7956,6 +8057,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7956
8057
  shouldContinueLiveStreamDuringAds: function shouldContinueLiveStreamDuringAds() {
7957
8058
  return _this.shouldContinueLiveStreamDuringAds();
7958
8059
  },
8060
+ isLiveStream: function isLiveStream() {
8061
+ return _this.hlsEngine.isLiveStream;
8062
+ },
7959
8063
  getLiveSyncPosition: function getLiveSyncPosition() {
7960
8064
  return _this.hlsEngine.getLiveSyncPosition();
7961
8065
  },
@@ -8178,6 +8282,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8178
8282
  {
8179
8283
  key: "shouldContinueLiveStreamDuringAds",
8180
8284
  value: function shouldContinueLiveStreamDuringAds() {
8285
+ if (this.config.pauseContentDuringAds) {
8286
+ return false;
8287
+ }
8181
8288
  if (this.hlsEngine.isLiveStream) {
8182
8289
  return true;
8183
8290
  }