stormcloud-video-player 0.3.61 → 0.3.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -3563,7 +3563,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3563
3563
  key: "load",
3564
3564
  value: function load() {
3565
3565
  return _async_to_generator(function() {
3566
- var _this, error, _this_config_lowLatencyMode, _this_video_play;
3566
+ var _this, error, _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
3567
3567
  return _ts_generator(this, function(_state) {
3568
3568
  switch(_state.label){
3569
3569
  case 0:
@@ -3607,7 +3607,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3607
3607
  this.nativeHlsMode = true;
3608
3608
  this.videoSrcProtection = this.config.src;
3609
3609
  this.video.src = this.config.src;
3610
- this.isLiveStream = (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false;
3610
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false;
3611
3611
  if (this.config.debugAdTiming) {
3612
3612
  console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
3613
3613
  isLive: this.isLiveStream,
@@ -3658,19 +3658,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3658
3658
  });
3659
3659
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
3660
3660
  return _async_to_generator(function() {
3661
- var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, minSegments, _this_video_play;
3661
+ var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
3662
3662
  return _ts_generator(this, function(_state) {
3663
3663
  switch(_state.label){
3664
3664
  case 0:
3665
- if (this.config.allowNativeHls === false) {
3666
- this.isLiveStream = true;
3667
- } else {
3668
- ;
3669
- ;
3670
- this.isLiveStream = (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
3671
- var _level_details, _level_details1;
3672
- return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
3673
- })) !== null && _ref !== void 0 ? _ref : false;
3665
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
3666
+ var _level_details, _level_details1;
3667
+ return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
3668
+ })) !== null && _ref !== void 0 ? _ref : false;
3669
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
3670
+ prerollKey = "synthetic-vod-preroll";
3671
+ if (!this.consumedVmapBreakIds.has(prerollKey)) {
3672
+ this.vmapBreaks = [
3673
+ {
3674
+ id: prerollKey,
3675
+ startTimeMs: 0,
3676
+ vastTagUrl: this.apiVastTagUrl
3677
+ }
3678
+ ];
3679
+ if (this.config.debugAdTiming) {
3680
+ console.log("[StormcloudVideoPlayer] Injected synthetic VOD preroll from apiVastTagUrl");
3681
+ }
3682
+ }
3674
3683
  }
3675
3684
  if (this.config.debugAdTiming) {
3676
3685
  adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
@@ -4240,6 +4249,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4240
4249
  _this.onTimeUpdate(_this.video.currentTime);
4241
4250
  };
4242
4251
  this.video.addEventListener("timeupdate", this.timeUpdateHandler);
4252
+ this.endedHandler = function() {
4253
+ _this.onVideoEnded();
4254
+ };
4255
+ this.video.addEventListener("ended", this.endedHandler);
4243
4256
  this.emptiedHandler = function() {
4244
4257
  if (_this.nativeHlsMode && _this.videoSrcProtection && !_this.ima.isAdPlaying()) {
4245
4258
  if (_this.config.debugAdTiming) {
@@ -5551,6 +5564,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5551
5564
  }
5552
5565
  }
5553
5566
  },
5567
+ {
5568
+ key: "isVmapEnabled",
5569
+ value: function isVmapEnabled() {
5570
+ var _this_config_vmapUrl;
5571
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
5572
+ }
5573
+ },
5554
5574
  {
5555
5575
  key: "fetchAdConfiguration",
5556
5576
  value: function fetchAdConfiguration() {
@@ -5559,7 +5579,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5559
5579
  return _ts_generator(this, function(_state) {
5560
5580
  switch(_state.label){
5561
5581
  case 0:
5562
- if (!this.config.vmapUrl) return [
5582
+ if (!this.isVmapEnabled()) return [
5563
5583
  3,
5564
5584
  2
5565
5585
  ];
@@ -5569,7 +5589,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5569
5589
  ];
5570
5590
  case 1:
5571
5591
  _state.sent();
5572
- _state.label = 2;
5592
+ if (this.config.debugAdTiming) {
5593
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
5594
+ }
5595
+ return [
5596
+ 2
5597
+ ];
5573
5598
  case 2:
5574
5599
  vastMode = this.config.vastMode || "default";
5575
5600
  if (this.config.debugAdTiming) {
@@ -5737,7 +5762,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5737
5762
  }
5738
5763
  return [];
5739
5764
  }
5740
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5765
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
5766
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
5767
+ if (adBreakNodes.length === 0) {
5768
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5769
+ }
5770
+ if (adBreakNodes.length === 0) {
5771
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
5772
+ return el.localName === "AdBreak";
5773
+ });
5774
+ }
5741
5775
  var parsed = [];
5742
5776
  adBreakNodes.forEach(function(node, index) {
5743
5777
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -5745,8 +5779,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5745
5779
  if (startTimeMs == null) {
5746
5780
  return;
5747
5781
  }
5748
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
5749
- var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
5782
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
5783
+ if (!adTagNode) {
5784
+ var _node_querySelector;
5785
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
5786
+ }
5787
+ if (!adTagNode) {
5788
+ adTagNode = Array.from(node.getElementsByTagName("*")).find(function(el) {
5789
+ return el.localName === "AdTagURI";
5790
+ });
5791
+ }
5792
+ var adTagUrl = _this.resolveVmapAdTagUrl(((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim());
5750
5793
  if (!adTagUrl) {
5751
5794
  return;
5752
5795
  }
@@ -5765,6 +5808,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5765
5808
  return parsed;
5766
5809
  }
5767
5810
  },
5811
+ {
5812
+ key: "resolveVmapAdTagUrl",
5813
+ value: function resolveVmapAdTagUrl(url) {
5814
+ if (!url) {
5815
+ return "";
5816
+ }
5817
+ return url.replace(/\[timestamp\]/gi, String(Date.now())).replace(/\$\{GDPR\}/gi, "0").trim();
5818
+ }
5819
+ },
5768
5820
  {
5769
5821
  key: "parseVmapTimeOffsetToMs",
5770
5822
  value: function parseVmapTimeOffsetToMs(timeOffset) {
@@ -5787,6 +5839,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5787
5839
  var millis = Number(ms.padEnd(3, "0").slice(0, 3));
5788
5840
  return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
5789
5841
  }
5842
+ var msOnly = timeOffset.match(/^(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
5843
+ if (msOnly) {
5844
+ var _msOnly = _sliced_to_array(msOnly, 4), mm1 = _msOnly[1], ss1 = _msOnly[2], tmp1 = _msOnly[3], ms1 = tmp1 === void 0 ? "0" : tmp1;
5845
+ var minutes1 = Number(mm1);
5846
+ var seconds1 = Number(ss1);
5847
+ var millis1 = Number(ms1.padEnd(3, "0").slice(0, 3));
5848
+ return (minutes1 * 60 + seconds1) * 1e3 + millis1;
5849
+ }
5790
5850
  var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
5791
5851
  if (percent) {
5792
5852
  var ratio = Number(percent[1]) / 100;
@@ -7302,23 +7362,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7302
7362
  key: "onTimeUpdate",
7303
7363
  value: function onTimeUpdate(currentTimeSec) {
7304
7364
  var _this = this;
7365
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7366
+ return;
7367
+ }
7305
7368
  if (this.ima.isAdPlaying() || this.inAdBreak) return;
7306
7369
  var nowMs = currentTimeSec * 1e3;
7307
7370
  var breakToPlay = this.findBreakForTime(nowMs);
7308
7371
  if (breakToPlay) {
7309
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
7372
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
7373
+ if (_this.config.debugAdTiming) {
7374
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
7375
+ }
7376
+ });
7377
+ }
7378
+ }
7379
+ },
7380
+ {
7381
+ key: "onVideoEnded",
7382
+ value: function onVideoEnded() {
7383
+ var _this = this;
7384
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7385
+ return;
7386
+ }
7387
+ if (this.ima.isAdPlaying() || this.inAdBreak) {
7388
+ return;
7389
+ }
7390
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
7391
+ var postroll = this.vmapBreaks.find(function(b) {
7392
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
7393
+ });
7394
+ if (postroll) {
7395
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
7310
7396
  if (_this.config.debugAdTiming) {
7311
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
7397
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
7312
7398
  }
7313
7399
  });
7314
7400
  }
7315
7401
  }
7316
7402
  },
7317
7403
  {
7318
- key: "handleMidAdJoin",
7319
- value: function handleMidAdJoin(adBreak, nowMs) {
7404
+ key: "handleVmapAdBreak",
7405
+ value: function handleVmapAdBreak(adBreak, nowMs) {
7320
7406
  return _async_to_generator(function() {
7321
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
7407
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
7322
7408
  return _ts_generator(this, function(_state) {
7323
7409
  switch(_state.label){
7324
7410
  case 0:
@@ -7336,25 +7422,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7336
7422
  }
7337
7423
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
7338
7424
  endMs = breakStartMs + durationMs;
7339
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7340
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
7425
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
7341
7426
  if (!inWindow) return [
7342
7427
  3,
7343
7428
  4
7344
7429
  ];
7345
7430
  this.consumedVmapBreakIds.add(key);
7346
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
7347
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
7348
- this.apiVastTagUrl
7349
- ] : void 0);
7350
- if (!(tags && tags.length > 0)) return [
7351
- 3,
7352
- 4
7353
- ];
7431
+ tags = this.selectVastTagsForBreak(adBreak);
7432
+ if (!tags || tags.length === 0) {
7433
+ return [
7434
+ 2
7435
+ ];
7436
+ }
7354
7437
  first = tags[0];
7355
7438
  rest = tags.slice(1);
7356
7439
  this.adPodQueue = rest;
7357
7440
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
7441
+ this.showAds = true;
7442
+ this.inAdBreak = true;
7443
+ this.currentAdBreakStartWallClockMs = Date.now();
7444
+ if (!this.video.paused) {
7445
+ this.video.pause();
7446
+ }
7358
7447
  _state.label = 1;
7359
7448
  case 1:
7360
7449
  _state.trys.push([
@@ -7369,10 +7458,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7369
7458
  ];
7370
7459
  case 2:
7371
7460
  _state.sent();
7372
- this.inAdBreak = true;
7373
- this.expectedAdBreakDurationMs = remainingMs;
7374
- this.currentAdBreakStartWallClockMs = Date.now();
7375
- this.scheduleAdStopCountdown(remainingMs);
7376
7461
  return [
7377
7462
  3,
7378
7463
  4
@@ -7380,8 +7465,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7380
7465
  case 3:
7381
7466
  error = _state.sent();
7382
7467
  this.adPodQueue = [];
7468
+ this.inAdBreak = false;
7469
+ this.showAds = false;
7383
7470
  if (this.config.debugAdTiming) {
7384
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
7471
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7385
7472
  }
7386
7473
  return [
7387
7474
  3,
@@ -8052,16 +8139,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8052
8139
  {
8053
8140
  key: "selectVastTagsForBreak",
8054
8141
  value: function selectVastTagsForBreak(b) {
8142
+ var _this = this;
8055
8143
  if (!b || !b.vastTagUrl) return void 0;
8056
- if (b.vastTagUrl.includes(",")) {
8057
- return b.vastTagUrl.split(",").map(function(s) {
8058
- return s.trim();
8144
+ var resolvedUrl = this.resolveVmapAdTagUrl(b.vastTagUrl);
8145
+ if (resolvedUrl.includes(",")) {
8146
+ return resolvedUrl.split(",").map(function(s) {
8147
+ return _this.resolveVmapAdTagUrl(s.trim());
8059
8148
  }).filter(function(s) {
8060
8149
  return s.length > 0;
8061
8150
  });
8062
8151
  }
8063
8152
  return [
8064
- b.vastTagUrl
8153
+ resolvedUrl
8065
8154
  ];
8066
8155
  }
8067
8156
  },
@@ -8093,9 +8182,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8093
8182
  {
8094
8183
  key: "findBreakForTime",
8095
8184
  value: function findBreakForTime(nowMs) {
8096
- var _this_config_driftToleranceMs;
8097
8185
  var schedule = this.vmapBreaks;
8098
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
8099
8186
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
8100
8187
  try {
8101
8188
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -8107,8 +8194,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8107
8194
  if (breakStartMs == null) {
8108
8195
  continue;
8109
8196
  }
8110
- var end = breakStartMs + (b.durationMs || 0);
8111
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
8197
+ if (b.durationMs) {
8198
+ var end = breakStartMs + b.durationMs;
8199
+ if (nowMs >= breakStartMs && nowMs < end) {
8200
+ return b;
8201
+ }
8202
+ continue;
8203
+ }
8204
+ if (nowMs >= breakStartMs) {
8112
8205
  return b;
8113
8206
  }
8114
8207
  }
@@ -8316,6 +8409,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8316
8409
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
8317
8410
  delete this.timeUpdateHandler;
8318
8411
  }
8412
+ if (this.endedHandler) {
8413
+ this.video.removeEventListener("ended", this.endedHandler);
8414
+ delete this.endedHandler;
8415
+ }
8319
8416
  if (this.emptiedHandler) {
8320
8417
  this.video.removeEventListener("emptied", this.emptiedHandler);
8321
8418
  delete this.emptiedHandler;
@@ -8339,7 +8436,9 @@ var import_jsx_runtime = require("react/jsx-runtime");
8339
8436
  var CRITICAL_PROPS = [
8340
8437
  "src",
8341
8438
  "allowNativeHls",
8439
+ "isLiveStream",
8342
8440
  "licenseKey",
8441
+ "isVmap",
8343
8442
  "vmapUrl",
8344
8443
  "lowLatencyMode",
8345
8444
  "driftToleranceMs",
@@ -8348,12 +8447,13 @@ var CRITICAL_PROPS = [
8348
8447
  var CONTROLS_HIDE_DELAY = 3e3;
8349
8448
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
8350
8449
  var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8351
- var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, vmapUrl = props.vmapUrl, adPlayerType = props.adPlayerType, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
8450
+ var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, isLiveStream = props.isLiveStream, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, isVmap = props.isVmap, vmapUrl = props.vmapUrl, adPlayerType = props.adPlayerType, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
8352
8451
  "src",
8353
8452
  "autoplay",
8354
8453
  "muted",
8355
8454
  "lowLatencyMode",
8356
8455
  "allowNativeHls",
8456
+ "isLiveStream",
8357
8457
  "driftToleranceMs",
8358
8458
  "immediateManifestAds",
8359
8459
  "debugAdTiming",
@@ -8375,6 +8475,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8375
8475
  "licenseKey",
8376
8476
  "vastMode",
8377
8477
  "vastTagUrl",
8478
+ "isVmap",
8378
8479
  "vmapUrl",
8379
8480
  "adPlayerType",
8380
8481
  "minSegmentsBeforePlay"
@@ -8508,7 +8609,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8508
8609
  setShowSpeedMenu(false);
8509
8610
  };
8510
8611
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
8511
- var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
8612
+ var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
8512
8613
  var criticalPropsKey = (0, import_react.useMemo)(function() {
8513
8614
  return CRITICAL_PROPS.map(function(prop) {
8514
8615
  return "".concat(prop, ":").concat(props[prop]);
@@ -8516,7 +8617,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8516
8617
  }, [
8517
8618
  src,
8518
8619
  allowNativeHls,
8620
+ isLiveStream,
8519
8621
  licenseKey,
8622
+ isVmap,
8520
8623
  vmapUrl,
8521
8624
  lowLatencyMode,
8522
8625
  driftToleranceMs,
@@ -8550,6 +8653,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8550
8653
  if (muted !== void 0) cfg.muted = muted;
8551
8654
  if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
8552
8655
  if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
8656
+ if (isLiveStream !== void 0) cfg.isLiveStream = isLiveStream;
8553
8657
  if (driftToleranceMs !== void 0) cfg.driftToleranceMs = driftToleranceMs;
8554
8658
  if (immediateManifestAds !== void 0) cfg.immediateManifestAds = immediateManifestAds;
8555
8659
  if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
@@ -8560,6 +8664,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8560
8664
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
8561
8665
  if (vastMode !== void 0) cfg.vastMode = vastMode;
8562
8666
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
8667
+ if (isVmap !== void 0) cfg.isVmap = isVmap;
8563
8668
  if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
8564
8669
  if (adPlayerType !== void 0) cfg.adPlayerType = adPlayerType;
8565
8670
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
@@ -9389,161 +9494,202 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
9389
9494
  ]
9390
9495
  })
9391
9496
  ]
9392
- }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9393
- className: "sc-controls-bar",
9394
- style: {
9395
- position: "absolute",
9396
- bottom: "".concat(10 * responsiveScale, "px"),
9397
- right: "".concat(10 * responsiveScale, "px"),
9398
- display: "flex",
9399
- flexDirection: isPortrait ? "column" : "row",
9400
- gap: "".concat(8 * responsiveScale, "px"),
9401
- zIndex: 10,
9402
- opacity: controlsVisible ? 1 : 0,
9403
- transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
9404
- pointerEvents: controlsVisible ? "auto" : "none"
9405
- },
9497
+ }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
9406
9498
  children: [
9407
9499
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9408
9500
  style: {
9501
+ position: "absolute",
9502
+ top: "".concat(10 * responsiveScale, "px"),
9503
+ left: "".concat(10 * responsiveScale, "px"),
9409
9504
  display: "flex",
9410
9505
  alignItems: "center",
9411
- background: "rgba(0, 0, 0, 0.6)",
9412
- borderRadius: "".concat(18 * responsiveScale, "px"),
9413
- padding: "2px",
9414
- paddingRight: "".concat(8 * responsiveScale, "px")
9415
- },
9416
- onMouseEnter: function onMouseEnter() {
9417
- return setShowVolumeSlider(true);
9506
+ gap: "6px",
9507
+ zIndex: 10,
9508
+ opacity: controlsVisible ? 1 : 0,
9509
+ transition: "opacity 0.35s ease"
9418
9510
  },
9419
- onMouseLeave: function onMouseLeave() {
9420
- return setShowVolumeSlider(false);
9511
+ children: [
9512
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9513
+ style: {
9514
+ width: "8px",
9515
+ height: "8px",
9516
+ borderRadius: "50%",
9517
+ background: "#ff3b30",
9518
+ animation: "sc-pulse 1.5s ease-in-out infinite",
9519
+ flexShrink: 0
9520
+ }
9521
+ }),
9522
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
9523
+ style: {
9524
+ fontSize: "".concat(12 * responsiveScale, "px"),
9525
+ fontFamily: "'SF Pro Display', 'Segoe UI', Arial, sans-serif",
9526
+ fontWeight: 700,
9527
+ letterSpacing: "0.08em",
9528
+ color: "#fff",
9529
+ textShadow: "0 1px 3px rgba(0,0,0,0.6)",
9530
+ userSelect: "none"
9531
+ },
9532
+ children: "LIVE"
9533
+ })
9534
+ ]
9535
+ }),
9536
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9537
+ className: "sc-controls-bar",
9538
+ style: {
9539
+ position: "absolute",
9540
+ bottom: "".concat(10 * responsiveScale, "px"),
9541
+ right: "".concat(10 * responsiveScale, "px"),
9542
+ display: "flex",
9543
+ flexDirection: isPortrait ? "column" : "row",
9544
+ gap: "".concat(8 * responsiveScale, "px"),
9545
+ zIndex: 10,
9546
+ opacity: controlsVisible ? 1 : 0,
9547
+ transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
9548
+ pointerEvents: controlsVisible ? "auto" : "none"
9421
9549
  },
9422
9550
  children: [
9551
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9552
+ style: {
9553
+ display: "flex",
9554
+ alignItems: "center",
9555
+ background: "rgba(0, 0, 0, 0.6)",
9556
+ borderRadius: "".concat(18 * responsiveScale, "px"),
9557
+ padding: "2px",
9558
+ paddingRight: "".concat(8 * responsiveScale, "px")
9559
+ },
9560
+ onMouseEnter: function onMouseEnter() {
9561
+ return setShowVolumeSlider(true);
9562
+ },
9563
+ onMouseLeave: function onMouseLeave() {
9564
+ return setShowVolumeSlider(false);
9565
+ },
9566
+ children: [
9567
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
9568
+ className: "sc-ctrl-btn",
9569
+ onClick: function onClick() {
9570
+ if (playerRef.current) playerRef.current.toggleMute();
9571
+ onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
9572
+ resetControlsTimer();
9573
+ },
9574
+ style: {
9575
+ padding: "".concat(8 * responsiveScale, "px"),
9576
+ borderRadius: "50%",
9577
+ minWidth: "".concat(36 * responsiveScale, "px"),
9578
+ minHeight: "".concat(36 * responsiveScale, "px")
9579
+ },
9580
+ title: isMuted ? "Unmute" : "Mute",
9581
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
9582
+ size: Math.max(14, 18 * responsiveScale)
9583
+ })
9584
+ }),
9585
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9586
+ style: {
9587
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
9588
+ overflow: "hidden",
9589
+ transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
9590
+ display: "flex",
9591
+ alignItems: "center",
9592
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
9593
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
9594
+ },
9595
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9596
+ style: {
9597
+ position: "relative",
9598
+ width: "".concat(56 * responsiveScale, "px"),
9599
+ height: "3px",
9600
+ cursor: "pointer",
9601
+ borderRadius: "1.5px"
9602
+ },
9603
+ onMouseDown: function onMouseDown(e) {
9604
+ e.preventDefault();
9605
+ var el = e.currentTarget;
9606
+ var move = function move(ev) {
9607
+ var r2 = el.getBoundingClientRect();
9608
+ handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
9609
+ };
9610
+ var up = function up1() {
9611
+ document.removeEventListener("mousemove", move);
9612
+ document.removeEventListener("mouseup", up);
9613
+ };
9614
+ document.addEventListener("mousemove", move);
9615
+ document.addEventListener("mouseup", up);
9616
+ var r = el.getBoundingClientRect();
9617
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9618
+ },
9619
+ onClick: function onClick(e) {
9620
+ e.stopPropagation();
9621
+ var r = e.currentTarget.getBoundingClientRect();
9622
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9623
+ },
9624
+ children: [
9625
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9626
+ style: {
9627
+ position: "absolute",
9628
+ inset: 0,
9629
+ background: "rgba(255, 255, 255, 0.2)",
9630
+ borderRadius: "1.5px"
9631
+ }
9632
+ }),
9633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9634
+ style: {
9635
+ position: "absolute",
9636
+ top: 0,
9637
+ left: 0,
9638
+ bottom: 0,
9639
+ width: "".concat((isMuted ? 0 : volume) * 100, "%"),
9640
+ background: "#fff",
9641
+ borderRadius: "1.5px",
9642
+ transition: "width 0.1s ease-out"
9643
+ }
9644
+ }),
9645
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9646
+ style: {
9647
+ position: "absolute",
9648
+ top: "50%",
9649
+ left: "".concat((isMuted ? 0 : volume) * 100, "%"),
9650
+ transform: "translate(-50%, -50%)",
9651
+ width: "12px",
9652
+ height: "12px",
9653
+ background: "#fff",
9654
+ borderRadius: "50%",
9655
+ boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
9656
+ transition: "left 0.1s ease-out"
9657
+ }
9658
+ })
9659
+ ]
9660
+ })
9661
+ })
9662
+ ]
9663
+ }),
9423
9664
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
9424
9665
  className: "sc-ctrl-btn",
9425
9666
  onClick: function onClick() {
9426
- if (playerRef.current) playerRef.current.toggleMute();
9427
- onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
9667
+ if (onFullscreenToggle) {
9668
+ onFullscreenToggle();
9669
+ } else if (wrapperRef.current) {
9670
+ if (!document.fullscreenElement) {
9671
+ wrapperRef.current.requestFullscreen().catch(function() {});
9672
+ } else {
9673
+ document.exitFullscreen().catch(function() {});
9674
+ }
9675
+ }
9428
9676
  resetControlsTimer();
9429
9677
  },
9430
9678
  style: {
9431
9679
  padding: "".concat(8 * responsiveScale, "px"),
9432
9680
  borderRadius: "50%",
9433
9681
  minWidth: "".concat(36 * responsiveScale, "px"),
9434
- minHeight: "".concat(36 * responsiveScale, "px")
9682
+ minHeight: "".concat(36 * responsiveScale, "px"),
9683
+ background: "rgba(0, 0, 0, 0.6)"
9435
9684
  },
9436
- title: isMuted ? "Unmute" : "Mute",
9437
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
9685
+ title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
9686
+ children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
9687
+ size: Math.max(14, 18 * responsiveScale)
9688
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
9438
9689
  size: Math.max(14, 18 * responsiveScale)
9439
- })
9440
- }),
9441
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9442
- style: {
9443
- width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
9444
- overflow: "hidden",
9445
- transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
9446
- display: "flex",
9447
- alignItems: "center",
9448
- paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
9449
- paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
9450
- },
9451
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9452
- style: {
9453
- position: "relative",
9454
- width: "".concat(56 * responsiveScale, "px"),
9455
- height: "3px",
9456
- cursor: "pointer",
9457
- borderRadius: "1.5px"
9458
- },
9459
- onMouseDown: function onMouseDown(e) {
9460
- e.preventDefault();
9461
- var el = e.currentTarget;
9462
- var move = function move(ev) {
9463
- var r2 = el.getBoundingClientRect();
9464
- handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
9465
- };
9466
- var up = function up1() {
9467
- document.removeEventListener("mousemove", move);
9468
- document.removeEventListener("mouseup", up);
9469
- };
9470
- document.addEventListener("mousemove", move);
9471
- document.addEventListener("mouseup", up);
9472
- var r = el.getBoundingClientRect();
9473
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9474
- },
9475
- onClick: function onClick(e) {
9476
- e.stopPropagation();
9477
- var r = e.currentTarget.getBoundingClientRect();
9478
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9479
- },
9480
- children: [
9481
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9482
- style: {
9483
- position: "absolute",
9484
- inset: 0,
9485
- background: "rgba(255, 255, 255, 0.2)",
9486
- borderRadius: "1.5px"
9487
- }
9488
- }),
9489
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9490
- style: {
9491
- position: "absolute",
9492
- top: 0,
9493
- left: 0,
9494
- bottom: 0,
9495
- width: "".concat((isMuted ? 0 : volume) * 100, "%"),
9496
- background: "#fff",
9497
- borderRadius: "1.5px",
9498
- transition: "width 0.1s ease-out"
9499
- }
9500
- }),
9501
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9502
- style: {
9503
- position: "absolute",
9504
- top: "50%",
9505
- left: "".concat((isMuted ? 0 : volume) * 100, "%"),
9506
- transform: "translate(-50%, -50%)",
9507
- width: "12px",
9508
- height: "12px",
9509
- background: "#fff",
9510
- borderRadius: "50%",
9511
- boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
9512
- transition: "left 0.1s ease-out"
9513
- }
9514
- })
9515
- ]
9516
9690
  })
9517
9691
  })
9518
9692
  ]
9519
- }),
9520
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
9521
- className: "sc-ctrl-btn",
9522
- onClick: function onClick() {
9523
- if (onFullscreenToggle) {
9524
- onFullscreenToggle();
9525
- } else if (wrapperRef.current) {
9526
- if (!document.fullscreenElement) {
9527
- wrapperRef.current.requestFullscreen().catch(function() {});
9528
- } else {
9529
- document.exitFullscreen().catch(function() {});
9530
- }
9531
- }
9532
- resetControlsTimer();
9533
- },
9534
- style: {
9535
- padding: "".concat(8 * responsiveScale, "px"),
9536
- borderRadius: "50%",
9537
- minWidth: "".concat(36 * responsiveScale, "px"),
9538
- minHeight: "".concat(36 * responsiveScale, "px"),
9539
- background: "rgba(0, 0, 0, 0.6)"
9540
- },
9541
- title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
9542
- children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
9543
- size: Math.max(14, 18 * responsiveScale)
9544
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
9545
- size: Math.max(14, 18 * responsiveScale)
9546
- })
9547
9693
  })
9548
9694
  ]
9549
9695
  }),
@@ -9682,6 +9828,7 @@ var defaultProps = {
9682
9828
  showCustomControls: false,
9683
9829
  hideLoadingIndicator: false,
9684
9830
  licenseKey: "",
9831
+ isVmap: false,
9685
9832
  vmapUrl: "",
9686
9833
  adFailsafeTimeoutMs: 1e4,
9687
9834
  minSegmentsBeforePlay: 2,
@@ -10626,6 +10773,7 @@ var SUPPORTED_PROPS = [
10626
10773
  "debugAdTiming",
10627
10774
  "showCustomControls",
10628
10775
  "licenseKey",
10776
+ "isVmap",
10629
10777
  "vmapUrl",
10630
10778
  "adFailsafeTimeoutMs",
10631
10779
  "minSegmentsBeforePlay",