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.js CHANGED
@@ -3391,7 +3391,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3391
3391
  key: "load",
3392
3392
  value: function load() {
3393
3393
  return _async_to_generator(function() {
3394
- var _this, error, _this_config_lowLatencyMode, _this_video_play;
3394
+ var _this, error, _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
3395
3395
  return _ts_generator(this, function(_state) {
3396
3396
  switch(_state.label){
3397
3397
  case 0:
@@ -3435,7 +3435,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3435
3435
  this.nativeHlsMode = true;
3436
3436
  this.videoSrcProtection = this.config.src;
3437
3437
  this.video.src = this.config.src;
3438
- this.isLiveStream = (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false;
3438
+ 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;
3439
3439
  if (this.config.debugAdTiming) {
3440
3440
  console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
3441
3441
  isLive: this.isLiveStream,
@@ -3486,19 +3486,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3486
3486
  });
3487
3487
  this.hls.on(Hls2.Events.MANIFEST_PARSED, function(_, data) {
3488
3488
  return _async_to_generator(function() {
3489
- var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, minSegments, _this_video_play;
3489
+ var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
3490
3490
  return _ts_generator(this, function(_state) {
3491
3491
  switch(_state.label){
3492
3492
  case 0:
3493
- if (this.config.allowNativeHls === false) {
3494
- this.isLiveStream = true;
3495
- } else {
3496
- ;
3497
- ;
3498
- 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) {
3499
- var _level_details, _level_details1;
3500
- 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";
3501
- })) !== null && _ref !== void 0 ? _ref : false;
3493
+ 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) {
3494
+ var _level_details, _level_details1;
3495
+ 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";
3496
+ })) !== null && _ref !== void 0 ? _ref : false;
3497
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
3498
+ prerollKey = "synthetic-vod-preroll";
3499
+ if (!this.consumedVmapBreakIds.has(prerollKey)) {
3500
+ this.vmapBreaks = [
3501
+ {
3502
+ id: prerollKey,
3503
+ startTimeMs: 0,
3504
+ vastTagUrl: this.apiVastTagUrl
3505
+ }
3506
+ ];
3507
+ if (this.config.debugAdTiming) {
3508
+ console.log("[StormcloudVideoPlayer] Injected synthetic VOD preroll from apiVastTagUrl");
3509
+ }
3510
+ }
3502
3511
  }
3503
3512
  if (this.config.debugAdTiming) {
3504
3513
  adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
@@ -4068,6 +4077,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4068
4077
  _this.onTimeUpdate(_this.video.currentTime);
4069
4078
  };
4070
4079
  this.video.addEventListener("timeupdate", this.timeUpdateHandler);
4080
+ this.endedHandler = function() {
4081
+ _this.onVideoEnded();
4082
+ };
4083
+ this.video.addEventListener("ended", this.endedHandler);
4071
4084
  this.emptiedHandler = function() {
4072
4085
  if (_this.nativeHlsMode && _this.videoSrcProtection && !_this.ima.isAdPlaying()) {
4073
4086
  if (_this.config.debugAdTiming) {
@@ -5379,6 +5392,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5379
5392
  }
5380
5393
  }
5381
5394
  },
5395
+ {
5396
+ key: "isVmapEnabled",
5397
+ value: function isVmapEnabled() {
5398
+ var _this_config_vmapUrl;
5399
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
5400
+ }
5401
+ },
5382
5402
  {
5383
5403
  key: "fetchAdConfiguration",
5384
5404
  value: function fetchAdConfiguration() {
@@ -5387,7 +5407,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5387
5407
  return _ts_generator(this, function(_state) {
5388
5408
  switch(_state.label){
5389
5409
  case 0:
5390
- if (!this.config.vmapUrl) return [
5410
+ if (!this.isVmapEnabled()) return [
5391
5411
  3,
5392
5412
  2
5393
5413
  ];
@@ -5397,7 +5417,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5397
5417
  ];
5398
5418
  case 1:
5399
5419
  _state.sent();
5400
- _state.label = 2;
5420
+ if (this.config.debugAdTiming) {
5421
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
5422
+ }
5423
+ return [
5424
+ 2
5425
+ ];
5401
5426
  case 2:
5402
5427
  vastMode = this.config.vastMode || "default";
5403
5428
  if (this.config.debugAdTiming) {
@@ -5565,7 +5590,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5565
5590
  }
5566
5591
  return [];
5567
5592
  }
5568
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5593
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
5594
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
5595
+ if (adBreakNodes.length === 0) {
5596
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5597
+ }
5598
+ if (adBreakNodes.length === 0) {
5599
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
5600
+ return el.localName === "AdBreak";
5601
+ });
5602
+ }
5569
5603
  var parsed = [];
5570
5604
  adBreakNodes.forEach(function(node, index) {
5571
5605
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -5573,8 +5607,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5573
5607
  if (startTimeMs == null) {
5574
5608
  return;
5575
5609
  }
5576
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
5577
- var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
5610
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
5611
+ if (!adTagNode) {
5612
+ var _node_querySelector;
5613
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
5614
+ }
5615
+ if (!adTagNode) {
5616
+ adTagNode = Array.from(node.getElementsByTagName("*")).find(function(el) {
5617
+ return el.localName === "AdTagURI";
5618
+ });
5619
+ }
5620
+ var adTagUrl = _this.resolveVmapAdTagUrl(((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim());
5578
5621
  if (!adTagUrl) {
5579
5622
  return;
5580
5623
  }
@@ -5593,6 +5636,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5593
5636
  return parsed;
5594
5637
  }
5595
5638
  },
5639
+ {
5640
+ key: "resolveVmapAdTagUrl",
5641
+ value: function resolveVmapAdTagUrl(url) {
5642
+ if (!url) {
5643
+ return "";
5644
+ }
5645
+ return url.replace(/\[timestamp\]/gi, String(Date.now())).replace(/\$\{GDPR\}/gi, "0").trim();
5646
+ }
5647
+ },
5596
5648
  {
5597
5649
  key: "parseVmapTimeOffsetToMs",
5598
5650
  value: function parseVmapTimeOffsetToMs(timeOffset) {
@@ -5615,6 +5667,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5615
5667
  var millis = Number(ms.padEnd(3, "0").slice(0, 3));
5616
5668
  return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
5617
5669
  }
5670
+ var msOnly = timeOffset.match(/^(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
5671
+ if (msOnly) {
5672
+ var _msOnly = _sliced_to_array(msOnly, 4), mm1 = _msOnly[1], ss1 = _msOnly[2], tmp1 = _msOnly[3], ms1 = tmp1 === void 0 ? "0" : tmp1;
5673
+ var minutes1 = Number(mm1);
5674
+ var seconds1 = Number(ss1);
5675
+ var millis1 = Number(ms1.padEnd(3, "0").slice(0, 3));
5676
+ return (minutes1 * 60 + seconds1) * 1e3 + millis1;
5677
+ }
5618
5678
  var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
5619
5679
  if (percent) {
5620
5680
  var ratio = Number(percent[1]) / 100;
@@ -7130,23 +7190,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7130
7190
  key: "onTimeUpdate",
7131
7191
  value: function onTimeUpdate(currentTimeSec) {
7132
7192
  var _this = this;
7193
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7194
+ return;
7195
+ }
7133
7196
  if (this.ima.isAdPlaying() || this.inAdBreak) return;
7134
7197
  var nowMs = currentTimeSec * 1e3;
7135
7198
  var breakToPlay = this.findBreakForTime(nowMs);
7136
7199
  if (breakToPlay) {
7137
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
7200
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
7201
+ if (_this.config.debugAdTiming) {
7202
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
7203
+ }
7204
+ });
7205
+ }
7206
+ }
7207
+ },
7208
+ {
7209
+ key: "onVideoEnded",
7210
+ value: function onVideoEnded() {
7211
+ var _this = this;
7212
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7213
+ return;
7214
+ }
7215
+ if (this.ima.isAdPlaying() || this.inAdBreak) {
7216
+ return;
7217
+ }
7218
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
7219
+ var postroll = this.vmapBreaks.find(function(b) {
7220
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
7221
+ });
7222
+ if (postroll) {
7223
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
7138
7224
  if (_this.config.debugAdTiming) {
7139
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
7225
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
7140
7226
  }
7141
7227
  });
7142
7228
  }
7143
7229
  }
7144
7230
  },
7145
7231
  {
7146
- key: "handleMidAdJoin",
7147
- value: function handleMidAdJoin(adBreak, nowMs) {
7232
+ key: "handleVmapAdBreak",
7233
+ value: function handleVmapAdBreak(adBreak, nowMs) {
7148
7234
  return _async_to_generator(function() {
7149
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
7235
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
7150
7236
  return _ts_generator(this, function(_state) {
7151
7237
  switch(_state.label){
7152
7238
  case 0:
@@ -7164,25 +7250,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7164
7250
  }
7165
7251
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
7166
7252
  endMs = breakStartMs + durationMs;
7167
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7168
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
7253
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
7169
7254
  if (!inWindow) return [
7170
7255
  3,
7171
7256
  4
7172
7257
  ];
7173
7258
  this.consumedVmapBreakIds.add(key);
7174
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
7175
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
7176
- this.apiVastTagUrl
7177
- ] : void 0);
7178
- if (!(tags && tags.length > 0)) return [
7179
- 3,
7180
- 4
7181
- ];
7259
+ tags = this.selectVastTagsForBreak(adBreak);
7260
+ if (!tags || tags.length === 0) {
7261
+ return [
7262
+ 2
7263
+ ];
7264
+ }
7182
7265
  first = tags[0];
7183
7266
  rest = tags.slice(1);
7184
7267
  this.adPodQueue = rest;
7185
7268
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
7269
+ this.showAds = true;
7270
+ this.inAdBreak = true;
7271
+ this.currentAdBreakStartWallClockMs = Date.now();
7272
+ if (!this.video.paused) {
7273
+ this.video.pause();
7274
+ }
7186
7275
  _state.label = 1;
7187
7276
  case 1:
7188
7277
  _state.trys.push([
@@ -7197,10 +7286,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7197
7286
  ];
7198
7287
  case 2:
7199
7288
  _state.sent();
7200
- this.inAdBreak = true;
7201
- this.expectedAdBreakDurationMs = remainingMs;
7202
- this.currentAdBreakStartWallClockMs = Date.now();
7203
- this.scheduleAdStopCountdown(remainingMs);
7204
7289
  return [
7205
7290
  3,
7206
7291
  4
@@ -7208,8 +7293,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7208
7293
  case 3:
7209
7294
  error = _state.sent();
7210
7295
  this.adPodQueue = [];
7296
+ this.inAdBreak = false;
7297
+ this.showAds = false;
7211
7298
  if (this.config.debugAdTiming) {
7212
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
7299
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7213
7300
  }
7214
7301
  return [
7215
7302
  3,
@@ -7880,16 +7967,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7880
7967
  {
7881
7968
  key: "selectVastTagsForBreak",
7882
7969
  value: function selectVastTagsForBreak(b) {
7970
+ var _this = this;
7883
7971
  if (!b || !b.vastTagUrl) return void 0;
7884
- if (b.vastTagUrl.includes(",")) {
7885
- return b.vastTagUrl.split(",").map(function(s) {
7886
- return s.trim();
7972
+ var resolvedUrl = this.resolveVmapAdTagUrl(b.vastTagUrl);
7973
+ if (resolvedUrl.includes(",")) {
7974
+ return resolvedUrl.split(",").map(function(s) {
7975
+ return _this.resolveVmapAdTagUrl(s.trim());
7887
7976
  }).filter(function(s) {
7888
7977
  return s.length > 0;
7889
7978
  });
7890
7979
  }
7891
7980
  return [
7892
- b.vastTagUrl
7981
+ resolvedUrl
7893
7982
  ];
7894
7983
  }
7895
7984
  },
@@ -7921,9 +8010,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7921
8010
  {
7922
8011
  key: "findBreakForTime",
7923
8012
  value: function findBreakForTime(nowMs) {
7924
- var _this_config_driftToleranceMs;
7925
8013
  var schedule = this.vmapBreaks;
7926
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7927
8014
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7928
8015
  try {
7929
8016
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7935,8 +8022,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7935
8022
  if (breakStartMs == null) {
7936
8023
  continue;
7937
8024
  }
7938
- var end = breakStartMs + (b.durationMs || 0);
7939
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
8025
+ if (b.durationMs) {
8026
+ var end = breakStartMs + b.durationMs;
8027
+ if (nowMs >= breakStartMs && nowMs < end) {
8028
+ return b;
8029
+ }
8030
+ continue;
8031
+ }
8032
+ if (nowMs >= breakStartMs) {
7940
8033
  return b;
7941
8034
  }
7942
8035
  }
@@ -8144,6 +8237,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8144
8237
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
8145
8238
  delete this.timeUpdateHandler;
8146
8239
  }
8240
+ if (this.endedHandler) {
8241
+ this.video.removeEventListener("ended", this.endedHandler);
8242
+ delete this.endedHandler;
8243
+ }
8147
8244
  if (this.emptiedHandler) {
8148
8245
  this.video.removeEventListener("emptied", this.emptiedHandler);
8149
8246
  delete this.emptiedHandler;
@@ -8167,7 +8264,9 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8167
8264
  var CRITICAL_PROPS = [
8168
8265
  "src",
8169
8266
  "allowNativeHls",
8267
+ "isLiveStream",
8170
8268
  "licenseKey",
8269
+ "isVmap",
8171
8270
  "vmapUrl",
8172
8271
  "lowLatencyMode",
8173
8272
  "driftToleranceMs",
@@ -8176,12 +8275,13 @@ var CRITICAL_PROPS = [
8176
8275
  var CONTROLS_HIDE_DELAY = 3e3;
8177
8276
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
8178
8277
  var StormcloudVideoPlayerComponent = React.memo(function(props) {
8179
- 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, [
8278
+ 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, [
8180
8279
  "src",
8181
8280
  "autoplay",
8182
8281
  "muted",
8183
8282
  "lowLatencyMode",
8184
8283
  "allowNativeHls",
8284
+ "isLiveStream",
8185
8285
  "driftToleranceMs",
8186
8286
  "immediateManifestAds",
8187
8287
  "debugAdTiming",
@@ -8203,6 +8303,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8203
8303
  "licenseKey",
8204
8304
  "vastMode",
8205
8305
  "vastTagUrl",
8306
+ "isVmap",
8206
8307
  "vmapUrl",
8207
8308
  "adPlayerType",
8208
8309
  "minSegmentsBeforePlay"
@@ -8336,7 +8437,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8336
8437
  setShowSpeedMenu(false);
8337
8438
  };
8338
8439
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
8339
- var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
8440
+ var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
8340
8441
  var criticalPropsKey = useMemo(function() {
8341
8442
  return CRITICAL_PROPS.map(function(prop) {
8342
8443
  return "".concat(prop, ":").concat(props[prop]);
@@ -8344,7 +8445,9 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8344
8445
  }, [
8345
8446
  src,
8346
8447
  allowNativeHls,
8448
+ isLiveStream,
8347
8449
  licenseKey,
8450
+ isVmap,
8348
8451
  vmapUrl,
8349
8452
  lowLatencyMode,
8350
8453
  driftToleranceMs,
@@ -8378,6 +8481,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8378
8481
  if (muted !== void 0) cfg.muted = muted;
8379
8482
  if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
8380
8483
  if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
8484
+ if (isLiveStream !== void 0) cfg.isLiveStream = isLiveStream;
8381
8485
  if (driftToleranceMs !== void 0) cfg.driftToleranceMs = driftToleranceMs;
8382
8486
  if (immediateManifestAds !== void 0) cfg.immediateManifestAds = immediateManifestAds;
8383
8487
  if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
@@ -8388,6 +8492,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8388
8492
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
8389
8493
  if (vastMode !== void 0) cfg.vastMode = vastMode;
8390
8494
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
8495
+ if (isVmap !== void 0) cfg.isVmap = isVmap;
8391
8496
  if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
8392
8497
  if (adPlayerType !== void 0) cfg.adPlayerType = adPlayerType;
8393
8498
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
@@ -9217,161 +9322,202 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
9217
9322
  ]
9218
9323
  })
9219
9324
  ]
9220
- }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ jsxs("div", {
9221
- className: "sc-controls-bar",
9222
- style: {
9223
- position: "absolute",
9224
- bottom: "".concat(10 * responsiveScale, "px"),
9225
- right: "".concat(10 * responsiveScale, "px"),
9226
- display: "flex",
9227
- flexDirection: isPortrait ? "column" : "row",
9228
- gap: "".concat(8 * responsiveScale, "px"),
9229
- zIndex: 10,
9230
- opacity: controlsVisible ? 1 : 0,
9231
- transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
9232
- pointerEvents: controlsVisible ? "auto" : "none"
9233
- },
9325
+ }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ jsxs(Fragment, {
9234
9326
  children: [
9235
9327
  /* @__PURE__ */ jsxs("div", {
9236
9328
  style: {
9329
+ position: "absolute",
9330
+ top: "".concat(10 * responsiveScale, "px"),
9331
+ left: "".concat(10 * responsiveScale, "px"),
9237
9332
  display: "flex",
9238
9333
  alignItems: "center",
9239
- background: "rgba(0, 0, 0, 0.6)",
9240
- borderRadius: "".concat(18 * responsiveScale, "px"),
9241
- padding: "2px",
9242
- paddingRight: "".concat(8 * responsiveScale, "px")
9243
- },
9244
- onMouseEnter: function onMouseEnter() {
9245
- return setShowVolumeSlider(true);
9334
+ gap: "6px",
9335
+ zIndex: 10,
9336
+ opacity: controlsVisible ? 1 : 0,
9337
+ transition: "opacity 0.35s ease"
9246
9338
  },
9247
- onMouseLeave: function onMouseLeave() {
9248
- return setShowVolumeSlider(false);
9339
+ children: [
9340
+ /* @__PURE__ */ jsx("div", {
9341
+ style: {
9342
+ width: "8px",
9343
+ height: "8px",
9344
+ borderRadius: "50%",
9345
+ background: "#ff3b30",
9346
+ animation: "sc-pulse 1.5s ease-in-out infinite",
9347
+ flexShrink: 0
9348
+ }
9349
+ }),
9350
+ /* @__PURE__ */ jsx("span", {
9351
+ style: {
9352
+ fontSize: "".concat(12 * responsiveScale, "px"),
9353
+ fontFamily: "'SF Pro Display', 'Segoe UI', Arial, sans-serif",
9354
+ fontWeight: 700,
9355
+ letterSpacing: "0.08em",
9356
+ color: "#fff",
9357
+ textShadow: "0 1px 3px rgba(0,0,0,0.6)",
9358
+ userSelect: "none"
9359
+ },
9360
+ children: "LIVE"
9361
+ })
9362
+ ]
9363
+ }),
9364
+ /* @__PURE__ */ jsxs("div", {
9365
+ className: "sc-controls-bar",
9366
+ style: {
9367
+ position: "absolute",
9368
+ bottom: "".concat(10 * responsiveScale, "px"),
9369
+ right: "".concat(10 * responsiveScale, "px"),
9370
+ display: "flex",
9371
+ flexDirection: isPortrait ? "column" : "row",
9372
+ gap: "".concat(8 * responsiveScale, "px"),
9373
+ zIndex: 10,
9374
+ opacity: controlsVisible ? 1 : 0,
9375
+ transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
9376
+ pointerEvents: controlsVisible ? "auto" : "none"
9249
9377
  },
9250
9378
  children: [
9379
+ /* @__PURE__ */ jsxs("div", {
9380
+ style: {
9381
+ display: "flex",
9382
+ alignItems: "center",
9383
+ background: "rgba(0, 0, 0, 0.6)",
9384
+ borderRadius: "".concat(18 * responsiveScale, "px"),
9385
+ padding: "2px",
9386
+ paddingRight: "".concat(8 * responsiveScale, "px")
9387
+ },
9388
+ onMouseEnter: function onMouseEnter() {
9389
+ return setShowVolumeSlider(true);
9390
+ },
9391
+ onMouseLeave: function onMouseLeave() {
9392
+ return setShowVolumeSlider(false);
9393
+ },
9394
+ children: [
9395
+ /* @__PURE__ */ jsx("button", {
9396
+ className: "sc-ctrl-btn",
9397
+ onClick: function onClick() {
9398
+ if (playerRef.current) playerRef.current.toggleMute();
9399
+ onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
9400
+ resetControlsTimer();
9401
+ },
9402
+ style: {
9403
+ padding: "".concat(8 * responsiveScale, "px"),
9404
+ borderRadius: "50%",
9405
+ minWidth: "".concat(36 * responsiveScale, "px"),
9406
+ minHeight: "".concat(36 * responsiveScale, "px")
9407
+ },
9408
+ title: isMuted ? "Unmute" : "Mute",
9409
+ children: /* @__PURE__ */ jsx(VolumeIcon, {
9410
+ size: Math.max(14, 18 * responsiveScale)
9411
+ })
9412
+ }),
9413
+ /* @__PURE__ */ jsx("div", {
9414
+ style: {
9415
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
9416
+ overflow: "hidden",
9417
+ transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
9418
+ display: "flex",
9419
+ alignItems: "center",
9420
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
9421
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
9422
+ },
9423
+ children: /* @__PURE__ */ jsxs("div", {
9424
+ style: {
9425
+ position: "relative",
9426
+ width: "".concat(56 * responsiveScale, "px"),
9427
+ height: "3px",
9428
+ cursor: "pointer",
9429
+ borderRadius: "1.5px"
9430
+ },
9431
+ onMouseDown: function onMouseDown(e) {
9432
+ e.preventDefault();
9433
+ var el = e.currentTarget;
9434
+ var move = function move(ev) {
9435
+ var r2 = el.getBoundingClientRect();
9436
+ handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
9437
+ };
9438
+ var up = function up1() {
9439
+ document.removeEventListener("mousemove", move);
9440
+ document.removeEventListener("mouseup", up);
9441
+ };
9442
+ document.addEventListener("mousemove", move);
9443
+ document.addEventListener("mouseup", up);
9444
+ var r = el.getBoundingClientRect();
9445
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9446
+ },
9447
+ onClick: function onClick(e) {
9448
+ e.stopPropagation();
9449
+ var r = e.currentTarget.getBoundingClientRect();
9450
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9451
+ },
9452
+ children: [
9453
+ /* @__PURE__ */ jsx("div", {
9454
+ style: {
9455
+ position: "absolute",
9456
+ inset: 0,
9457
+ background: "rgba(255, 255, 255, 0.2)",
9458
+ borderRadius: "1.5px"
9459
+ }
9460
+ }),
9461
+ /* @__PURE__ */ jsx("div", {
9462
+ style: {
9463
+ position: "absolute",
9464
+ top: 0,
9465
+ left: 0,
9466
+ bottom: 0,
9467
+ width: "".concat((isMuted ? 0 : volume) * 100, "%"),
9468
+ background: "#fff",
9469
+ borderRadius: "1.5px",
9470
+ transition: "width 0.1s ease-out"
9471
+ }
9472
+ }),
9473
+ /* @__PURE__ */ jsx("div", {
9474
+ style: {
9475
+ position: "absolute",
9476
+ top: "50%",
9477
+ left: "".concat((isMuted ? 0 : volume) * 100, "%"),
9478
+ transform: "translate(-50%, -50%)",
9479
+ width: "12px",
9480
+ height: "12px",
9481
+ background: "#fff",
9482
+ borderRadius: "50%",
9483
+ boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
9484
+ transition: "left 0.1s ease-out"
9485
+ }
9486
+ })
9487
+ ]
9488
+ })
9489
+ })
9490
+ ]
9491
+ }),
9251
9492
  /* @__PURE__ */ jsx("button", {
9252
9493
  className: "sc-ctrl-btn",
9253
9494
  onClick: function onClick() {
9254
- if (playerRef.current) playerRef.current.toggleMute();
9255
- onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
9495
+ if (onFullscreenToggle) {
9496
+ onFullscreenToggle();
9497
+ } else if (wrapperRef.current) {
9498
+ if (!document.fullscreenElement) {
9499
+ wrapperRef.current.requestFullscreen().catch(function() {});
9500
+ } else {
9501
+ document.exitFullscreen().catch(function() {});
9502
+ }
9503
+ }
9256
9504
  resetControlsTimer();
9257
9505
  },
9258
9506
  style: {
9259
9507
  padding: "".concat(8 * responsiveScale, "px"),
9260
9508
  borderRadius: "50%",
9261
9509
  minWidth: "".concat(36 * responsiveScale, "px"),
9262
- minHeight: "".concat(36 * responsiveScale, "px")
9510
+ minHeight: "".concat(36 * responsiveScale, "px"),
9511
+ background: "rgba(0, 0, 0, 0.6)"
9263
9512
  },
9264
- title: isMuted ? "Unmute" : "Mute",
9265
- children: /* @__PURE__ */ jsx(VolumeIcon, {
9513
+ title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
9514
+ children: isFullscreen ? /* @__PURE__ */ jsx(FaCompress, {
9515
+ size: Math.max(14, 18 * responsiveScale)
9516
+ }) : /* @__PURE__ */ jsx(FaExpand, {
9266
9517
  size: Math.max(14, 18 * responsiveScale)
9267
- })
9268
- }),
9269
- /* @__PURE__ */ jsx("div", {
9270
- style: {
9271
- width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
9272
- overflow: "hidden",
9273
- transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
9274
- display: "flex",
9275
- alignItems: "center",
9276
- paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
9277
- paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
9278
- },
9279
- children: /* @__PURE__ */ jsxs("div", {
9280
- style: {
9281
- position: "relative",
9282
- width: "".concat(56 * responsiveScale, "px"),
9283
- height: "3px",
9284
- cursor: "pointer",
9285
- borderRadius: "1.5px"
9286
- },
9287
- onMouseDown: function onMouseDown(e) {
9288
- e.preventDefault();
9289
- var el = e.currentTarget;
9290
- var move = function move(ev) {
9291
- var r2 = el.getBoundingClientRect();
9292
- handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
9293
- };
9294
- var up = function up1() {
9295
- document.removeEventListener("mousemove", move);
9296
- document.removeEventListener("mouseup", up);
9297
- };
9298
- document.addEventListener("mousemove", move);
9299
- document.addEventListener("mouseup", up);
9300
- var r = el.getBoundingClientRect();
9301
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9302
- },
9303
- onClick: function onClick(e) {
9304
- e.stopPropagation();
9305
- var r = e.currentTarget.getBoundingClientRect();
9306
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9307
- },
9308
- children: [
9309
- /* @__PURE__ */ jsx("div", {
9310
- style: {
9311
- position: "absolute",
9312
- inset: 0,
9313
- background: "rgba(255, 255, 255, 0.2)",
9314
- borderRadius: "1.5px"
9315
- }
9316
- }),
9317
- /* @__PURE__ */ jsx("div", {
9318
- style: {
9319
- position: "absolute",
9320
- top: 0,
9321
- left: 0,
9322
- bottom: 0,
9323
- width: "".concat((isMuted ? 0 : volume) * 100, "%"),
9324
- background: "#fff",
9325
- borderRadius: "1.5px",
9326
- transition: "width 0.1s ease-out"
9327
- }
9328
- }),
9329
- /* @__PURE__ */ jsx("div", {
9330
- style: {
9331
- position: "absolute",
9332
- top: "50%",
9333
- left: "".concat((isMuted ? 0 : volume) * 100, "%"),
9334
- transform: "translate(-50%, -50%)",
9335
- width: "12px",
9336
- height: "12px",
9337
- background: "#fff",
9338
- borderRadius: "50%",
9339
- boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
9340
- transition: "left 0.1s ease-out"
9341
- }
9342
- })
9343
- ]
9344
9518
  })
9345
9519
  })
9346
9520
  ]
9347
- }),
9348
- /* @__PURE__ */ jsx("button", {
9349
- className: "sc-ctrl-btn",
9350
- onClick: function onClick() {
9351
- if (onFullscreenToggle) {
9352
- onFullscreenToggle();
9353
- } else if (wrapperRef.current) {
9354
- if (!document.fullscreenElement) {
9355
- wrapperRef.current.requestFullscreen().catch(function() {});
9356
- } else {
9357
- document.exitFullscreen().catch(function() {});
9358
- }
9359
- }
9360
- resetControlsTimer();
9361
- },
9362
- style: {
9363
- padding: "".concat(8 * responsiveScale, "px"),
9364
- borderRadius: "50%",
9365
- minWidth: "".concat(36 * responsiveScale, "px"),
9366
- minHeight: "".concat(36 * responsiveScale, "px"),
9367
- background: "rgba(0, 0, 0, 0.6)"
9368
- },
9369
- title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
9370
- children: isFullscreen ? /* @__PURE__ */ jsx(FaCompress, {
9371
- size: Math.max(14, 18 * responsiveScale)
9372
- }) : /* @__PURE__ */ jsx(FaExpand, {
9373
- size: Math.max(14, 18 * responsiveScale)
9374
- })
9375
9521
  })
9376
9522
  ]
9377
9523
  }),
@@ -9510,6 +9656,7 @@ var defaultProps = {
9510
9656
  showCustomControls: false,
9511
9657
  hideLoadingIndicator: false,
9512
9658
  licenseKey: "",
9659
+ isVmap: false,
9513
9660
  vmapUrl: "",
9514
9661
  adFailsafeTimeoutMs: 1e4,
9515
9662
  minSegmentsBeforePlay: 2,
@@ -10457,6 +10604,7 @@ var SUPPORTED_PROPS = [
10457
10604
  "debugAdTiming",
10458
10605
  "showCustomControls",
10459
10606
  "licenseKey",
10607
+ "isVmap",
10460
10608
  "vmapUrl",
10461
10609
  "adFailsafeTimeoutMs",
10462
10610
  "minSegmentsBeforePlay",