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.
@@ -3375,7 +3375,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3375
3375
  key: "load",
3376
3376
  value: function load() {
3377
3377
  return _async_to_generator(function() {
3378
- var _this, error, _this_config_lowLatencyMode, _this_video_play;
3378
+ var _this, error, _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
3379
3379
  return _ts_generator(this, function(_state) {
3380
3380
  switch(_state.label){
3381
3381
  case 0:
@@ -3419,7 +3419,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3419
3419
  this.nativeHlsMode = true;
3420
3420
  this.videoSrcProtection = this.config.src;
3421
3421
  this.video.src = this.config.src;
3422
- this.isLiveStream = (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false;
3422
+ 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;
3423
3423
  if (this.config.debugAdTiming) {
3424
3424
  console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
3425
3425
  isLive: this.isLiveStream,
@@ -3470,19 +3470,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3470
3470
  });
3471
3471
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
3472
3472
  return _async_to_generator(function() {
3473
- var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, minSegments, _this_video_play;
3473
+ var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
3474
3474
  return _ts_generator(this, function(_state) {
3475
3475
  switch(_state.label){
3476
3476
  case 0:
3477
- if (this.config.allowNativeHls === false) {
3478
- this.isLiveStream = true;
3479
- } else {
3480
- ;
3481
- ;
3482
- 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) {
3483
- var _level_details, _level_details1;
3484
- 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";
3485
- })) !== null && _ref !== void 0 ? _ref : false;
3477
+ 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) {
3478
+ var _level_details, _level_details1;
3479
+ 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";
3480
+ })) !== null && _ref !== void 0 ? _ref : false;
3481
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
3482
+ prerollKey = "synthetic-vod-preroll";
3483
+ if (!this.consumedVmapBreakIds.has(prerollKey)) {
3484
+ this.vmapBreaks = [
3485
+ {
3486
+ id: prerollKey,
3487
+ startTimeMs: 0,
3488
+ vastTagUrl: this.apiVastTagUrl
3489
+ }
3490
+ ];
3491
+ if (this.config.debugAdTiming) {
3492
+ console.log("[StormcloudVideoPlayer] Injected synthetic VOD preroll from apiVastTagUrl");
3493
+ }
3494
+ }
3486
3495
  }
3487
3496
  if (this.config.debugAdTiming) {
3488
3497
  adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
@@ -4052,6 +4061,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4052
4061
  _this.onTimeUpdate(_this.video.currentTime);
4053
4062
  };
4054
4063
  this.video.addEventListener("timeupdate", this.timeUpdateHandler);
4064
+ this.endedHandler = function() {
4065
+ _this.onVideoEnded();
4066
+ };
4067
+ this.video.addEventListener("ended", this.endedHandler);
4055
4068
  this.emptiedHandler = function() {
4056
4069
  if (_this.nativeHlsMode && _this.videoSrcProtection && !_this.ima.isAdPlaying()) {
4057
4070
  if (_this.config.debugAdTiming) {
@@ -5363,6 +5376,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5363
5376
  }
5364
5377
  }
5365
5378
  },
5379
+ {
5380
+ key: "isVmapEnabled",
5381
+ value: function isVmapEnabled() {
5382
+ var _this_config_vmapUrl;
5383
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
5384
+ }
5385
+ },
5366
5386
  {
5367
5387
  key: "fetchAdConfiguration",
5368
5388
  value: function fetchAdConfiguration() {
@@ -5371,7 +5391,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5371
5391
  return _ts_generator(this, function(_state) {
5372
5392
  switch(_state.label){
5373
5393
  case 0:
5374
- if (!this.config.vmapUrl) return [
5394
+ if (!this.isVmapEnabled()) return [
5375
5395
  3,
5376
5396
  2
5377
5397
  ];
@@ -5381,7 +5401,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5381
5401
  ];
5382
5402
  case 1:
5383
5403
  _state.sent();
5384
- _state.label = 2;
5404
+ if (this.config.debugAdTiming) {
5405
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
5406
+ }
5407
+ return [
5408
+ 2
5409
+ ];
5385
5410
  case 2:
5386
5411
  vastMode = this.config.vastMode || "default";
5387
5412
  if (this.config.debugAdTiming) {
@@ -5549,7 +5574,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5549
5574
  }
5550
5575
  return [];
5551
5576
  }
5552
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5577
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
5578
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
5579
+ if (adBreakNodes.length === 0) {
5580
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5581
+ }
5582
+ if (adBreakNodes.length === 0) {
5583
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
5584
+ return el.localName === "AdBreak";
5585
+ });
5586
+ }
5553
5587
  var parsed = [];
5554
5588
  adBreakNodes.forEach(function(node, index) {
5555
5589
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -5557,8 +5591,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5557
5591
  if (startTimeMs == null) {
5558
5592
  return;
5559
5593
  }
5560
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
5561
- var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
5594
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
5595
+ if (!adTagNode) {
5596
+ var _node_querySelector;
5597
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
5598
+ }
5599
+ if (!adTagNode) {
5600
+ adTagNode = Array.from(node.getElementsByTagName("*")).find(function(el) {
5601
+ return el.localName === "AdTagURI";
5602
+ });
5603
+ }
5604
+ var adTagUrl = _this.resolveVmapAdTagUrl(((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim());
5562
5605
  if (!adTagUrl) {
5563
5606
  return;
5564
5607
  }
@@ -5577,6 +5620,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5577
5620
  return parsed;
5578
5621
  }
5579
5622
  },
5623
+ {
5624
+ key: "resolveVmapAdTagUrl",
5625
+ value: function resolveVmapAdTagUrl(url) {
5626
+ if (!url) {
5627
+ return "";
5628
+ }
5629
+ return url.replace(/\[timestamp\]/gi, String(Date.now())).replace(/\$\{GDPR\}/gi, "0").trim();
5630
+ }
5631
+ },
5580
5632
  {
5581
5633
  key: "parseVmapTimeOffsetToMs",
5582
5634
  value: function parseVmapTimeOffsetToMs(timeOffset) {
@@ -5599,6 +5651,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5599
5651
  var millis = Number(ms.padEnd(3, "0").slice(0, 3));
5600
5652
  return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
5601
5653
  }
5654
+ var msOnly = timeOffset.match(/^(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
5655
+ if (msOnly) {
5656
+ var _msOnly = _sliced_to_array(msOnly, 4), mm1 = _msOnly[1], ss1 = _msOnly[2], tmp1 = _msOnly[3], ms1 = tmp1 === void 0 ? "0" : tmp1;
5657
+ var minutes1 = Number(mm1);
5658
+ var seconds1 = Number(ss1);
5659
+ var millis1 = Number(ms1.padEnd(3, "0").slice(0, 3));
5660
+ return (minutes1 * 60 + seconds1) * 1e3 + millis1;
5661
+ }
5602
5662
  var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
5603
5663
  if (percent) {
5604
5664
  var ratio = Number(percent[1]) / 100;
@@ -7114,23 +7174,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7114
7174
  key: "onTimeUpdate",
7115
7175
  value: function onTimeUpdate(currentTimeSec) {
7116
7176
  var _this = this;
7177
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7178
+ return;
7179
+ }
7117
7180
  if (this.ima.isAdPlaying() || this.inAdBreak) return;
7118
7181
  var nowMs = currentTimeSec * 1e3;
7119
7182
  var breakToPlay = this.findBreakForTime(nowMs);
7120
7183
  if (breakToPlay) {
7121
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
7184
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
7185
+ if (_this.config.debugAdTiming) {
7186
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
7187
+ }
7188
+ });
7189
+ }
7190
+ }
7191
+ },
7192
+ {
7193
+ key: "onVideoEnded",
7194
+ value: function onVideoEnded() {
7195
+ var _this = this;
7196
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7197
+ return;
7198
+ }
7199
+ if (this.ima.isAdPlaying() || this.inAdBreak) {
7200
+ return;
7201
+ }
7202
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
7203
+ var postroll = this.vmapBreaks.find(function(b) {
7204
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
7205
+ });
7206
+ if (postroll) {
7207
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
7122
7208
  if (_this.config.debugAdTiming) {
7123
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
7209
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
7124
7210
  }
7125
7211
  });
7126
7212
  }
7127
7213
  }
7128
7214
  },
7129
7215
  {
7130
- key: "handleMidAdJoin",
7131
- value: function handleMidAdJoin(adBreak, nowMs) {
7216
+ key: "handleVmapAdBreak",
7217
+ value: function handleVmapAdBreak(adBreak, nowMs) {
7132
7218
  return _async_to_generator(function() {
7133
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
7219
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
7134
7220
  return _ts_generator(this, function(_state) {
7135
7221
  switch(_state.label){
7136
7222
  case 0:
@@ -7148,25 +7234,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7148
7234
  }
7149
7235
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
7150
7236
  endMs = breakStartMs + durationMs;
7151
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7152
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
7237
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
7153
7238
  if (!inWindow) return [
7154
7239
  3,
7155
7240
  4
7156
7241
  ];
7157
7242
  this.consumedVmapBreakIds.add(key);
7158
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
7159
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
7160
- this.apiVastTagUrl
7161
- ] : void 0);
7162
- if (!(tags && tags.length > 0)) return [
7163
- 3,
7164
- 4
7165
- ];
7243
+ tags = this.selectVastTagsForBreak(adBreak);
7244
+ if (!tags || tags.length === 0) {
7245
+ return [
7246
+ 2
7247
+ ];
7248
+ }
7166
7249
  first = tags[0];
7167
7250
  rest = tags.slice(1);
7168
7251
  this.adPodQueue = rest;
7169
7252
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
7253
+ this.showAds = true;
7254
+ this.inAdBreak = true;
7255
+ this.currentAdBreakStartWallClockMs = Date.now();
7256
+ if (!this.video.paused) {
7257
+ this.video.pause();
7258
+ }
7170
7259
  _state.label = 1;
7171
7260
  case 1:
7172
7261
  _state.trys.push([
@@ -7181,10 +7270,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7181
7270
  ];
7182
7271
  case 2:
7183
7272
  _state.sent();
7184
- this.inAdBreak = true;
7185
- this.expectedAdBreakDurationMs = remainingMs;
7186
- this.currentAdBreakStartWallClockMs = Date.now();
7187
- this.scheduleAdStopCountdown(remainingMs);
7188
7273
  return [
7189
7274
  3,
7190
7275
  4
@@ -7192,8 +7277,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7192
7277
  case 3:
7193
7278
  error = _state.sent();
7194
7279
  this.adPodQueue = [];
7280
+ this.inAdBreak = false;
7281
+ this.showAds = false;
7195
7282
  if (this.config.debugAdTiming) {
7196
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
7283
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7197
7284
  }
7198
7285
  return [
7199
7286
  3,
@@ -7864,16 +7951,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7864
7951
  {
7865
7952
  key: "selectVastTagsForBreak",
7866
7953
  value: function selectVastTagsForBreak(b) {
7954
+ var _this = this;
7867
7955
  if (!b || !b.vastTagUrl) return void 0;
7868
- if (b.vastTagUrl.includes(",")) {
7869
- return b.vastTagUrl.split(",").map(function(s) {
7870
- return s.trim();
7956
+ var resolvedUrl = this.resolveVmapAdTagUrl(b.vastTagUrl);
7957
+ if (resolvedUrl.includes(",")) {
7958
+ return resolvedUrl.split(",").map(function(s) {
7959
+ return _this.resolveVmapAdTagUrl(s.trim());
7871
7960
  }).filter(function(s) {
7872
7961
  return s.length > 0;
7873
7962
  });
7874
7963
  }
7875
7964
  return [
7876
- b.vastTagUrl
7965
+ resolvedUrl
7877
7966
  ];
7878
7967
  }
7879
7968
  },
@@ -7905,9 +7994,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7905
7994
  {
7906
7995
  key: "findBreakForTime",
7907
7996
  value: function findBreakForTime(nowMs) {
7908
- var _this_config_driftToleranceMs;
7909
7997
  var schedule = this.vmapBreaks;
7910
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7911
7998
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7912
7999
  try {
7913
8000
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7919,8 +8006,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7919
8006
  if (breakStartMs == null) {
7920
8007
  continue;
7921
8008
  }
7922
- var end = breakStartMs + (b.durationMs || 0);
7923
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
8009
+ if (b.durationMs) {
8010
+ var end = breakStartMs + b.durationMs;
8011
+ if (nowMs >= breakStartMs && nowMs < end) {
8012
+ return b;
8013
+ }
8014
+ continue;
8015
+ }
8016
+ if (nowMs >= breakStartMs) {
7924
8017
  return b;
7925
8018
  }
7926
8019
  }
@@ -8128,6 +8221,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8128
8221
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
8129
8222
  delete this.timeUpdateHandler;
8130
8223
  }
8224
+ if (this.endedHandler) {
8225
+ this.video.removeEventListener("ended", this.endedHandler);
8226
+ delete this.endedHandler;
8227
+ }
8131
8228
  if (this.emptiedHandler) {
8132
8229
  this.video.removeEventListener("emptied", this.emptiedHandler);
8133
8230
  delete this.emptiedHandler;
@@ -8151,7 +8248,9 @@ var import_jsx_runtime = require("react/jsx-runtime");
8151
8248
  var CRITICAL_PROPS = [
8152
8249
  "src",
8153
8250
  "allowNativeHls",
8251
+ "isLiveStream",
8154
8252
  "licenseKey",
8253
+ "isVmap",
8155
8254
  "vmapUrl",
8156
8255
  "lowLatencyMode",
8157
8256
  "driftToleranceMs",
@@ -8160,12 +8259,13 @@ var CRITICAL_PROPS = [
8160
8259
  var CONTROLS_HIDE_DELAY = 3e3;
8161
8260
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
8162
8261
  var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8163
- 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, [
8262
+ 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, [
8164
8263
  "src",
8165
8264
  "autoplay",
8166
8265
  "muted",
8167
8266
  "lowLatencyMode",
8168
8267
  "allowNativeHls",
8268
+ "isLiveStream",
8169
8269
  "driftToleranceMs",
8170
8270
  "immediateManifestAds",
8171
8271
  "debugAdTiming",
@@ -8187,6 +8287,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8187
8287
  "licenseKey",
8188
8288
  "vastMode",
8189
8289
  "vastTagUrl",
8290
+ "isVmap",
8190
8291
  "vmapUrl",
8191
8292
  "adPlayerType",
8192
8293
  "minSegmentsBeforePlay"
@@ -8320,7 +8421,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8320
8421
  setShowSpeedMenu(false);
8321
8422
  };
8322
8423
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
8323
- var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
8424
+ var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
8324
8425
  var criticalPropsKey = (0, import_react.useMemo)(function() {
8325
8426
  return CRITICAL_PROPS.map(function(prop) {
8326
8427
  return "".concat(prop, ":").concat(props[prop]);
@@ -8328,7 +8429,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8328
8429
  }, [
8329
8430
  src,
8330
8431
  allowNativeHls,
8432
+ isLiveStream,
8331
8433
  licenseKey,
8434
+ isVmap,
8332
8435
  vmapUrl,
8333
8436
  lowLatencyMode,
8334
8437
  driftToleranceMs,
@@ -8362,6 +8465,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8362
8465
  if (muted !== void 0) cfg.muted = muted;
8363
8466
  if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
8364
8467
  if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
8468
+ if (isLiveStream !== void 0) cfg.isLiveStream = isLiveStream;
8365
8469
  if (driftToleranceMs !== void 0) cfg.driftToleranceMs = driftToleranceMs;
8366
8470
  if (immediateManifestAds !== void 0) cfg.immediateManifestAds = immediateManifestAds;
8367
8471
  if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
@@ -8372,6 +8476,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8372
8476
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
8373
8477
  if (vastMode !== void 0) cfg.vastMode = vastMode;
8374
8478
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
8479
+ if (isVmap !== void 0) cfg.isVmap = isVmap;
8375
8480
  if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
8376
8481
  if (adPlayerType !== void 0) cfg.adPlayerType = adPlayerType;
8377
8482
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
@@ -9201,161 +9306,202 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
9201
9306
  ]
9202
9307
  })
9203
9308
  ]
9204
- }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9205
- className: "sc-controls-bar",
9206
- style: {
9207
- position: "absolute",
9208
- bottom: "".concat(10 * responsiveScale, "px"),
9209
- right: "".concat(10 * responsiveScale, "px"),
9210
- display: "flex",
9211
- flexDirection: isPortrait ? "column" : "row",
9212
- gap: "".concat(8 * responsiveScale, "px"),
9213
- zIndex: 10,
9214
- opacity: controlsVisible ? 1 : 0,
9215
- transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
9216
- pointerEvents: controlsVisible ? "auto" : "none"
9217
- },
9309
+ }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
9218
9310
  children: [
9219
9311
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9220
9312
  style: {
9313
+ position: "absolute",
9314
+ top: "".concat(10 * responsiveScale, "px"),
9315
+ left: "".concat(10 * responsiveScale, "px"),
9221
9316
  display: "flex",
9222
9317
  alignItems: "center",
9223
- background: "rgba(0, 0, 0, 0.6)",
9224
- borderRadius: "".concat(18 * responsiveScale, "px"),
9225
- padding: "2px",
9226
- paddingRight: "".concat(8 * responsiveScale, "px")
9227
- },
9228
- onMouseEnter: function onMouseEnter() {
9229
- return setShowVolumeSlider(true);
9318
+ gap: "6px",
9319
+ zIndex: 10,
9320
+ opacity: controlsVisible ? 1 : 0,
9321
+ transition: "opacity 0.35s ease"
9230
9322
  },
9231
- onMouseLeave: function onMouseLeave() {
9232
- return setShowVolumeSlider(false);
9323
+ children: [
9324
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9325
+ style: {
9326
+ width: "8px",
9327
+ height: "8px",
9328
+ borderRadius: "50%",
9329
+ background: "#ff3b30",
9330
+ animation: "sc-pulse 1.5s ease-in-out infinite",
9331
+ flexShrink: 0
9332
+ }
9333
+ }),
9334
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
9335
+ style: {
9336
+ fontSize: "".concat(12 * responsiveScale, "px"),
9337
+ fontFamily: "'SF Pro Display', 'Segoe UI', Arial, sans-serif",
9338
+ fontWeight: 700,
9339
+ letterSpacing: "0.08em",
9340
+ color: "#fff",
9341
+ textShadow: "0 1px 3px rgba(0,0,0,0.6)",
9342
+ userSelect: "none"
9343
+ },
9344
+ children: "LIVE"
9345
+ })
9346
+ ]
9347
+ }),
9348
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9349
+ className: "sc-controls-bar",
9350
+ style: {
9351
+ position: "absolute",
9352
+ bottom: "".concat(10 * responsiveScale, "px"),
9353
+ right: "".concat(10 * responsiveScale, "px"),
9354
+ display: "flex",
9355
+ flexDirection: isPortrait ? "column" : "row",
9356
+ gap: "".concat(8 * responsiveScale, "px"),
9357
+ zIndex: 10,
9358
+ opacity: controlsVisible ? 1 : 0,
9359
+ transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
9360
+ pointerEvents: controlsVisible ? "auto" : "none"
9233
9361
  },
9234
9362
  children: [
9363
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9364
+ style: {
9365
+ display: "flex",
9366
+ alignItems: "center",
9367
+ background: "rgba(0, 0, 0, 0.6)",
9368
+ borderRadius: "".concat(18 * responsiveScale, "px"),
9369
+ padding: "2px",
9370
+ paddingRight: "".concat(8 * responsiveScale, "px")
9371
+ },
9372
+ onMouseEnter: function onMouseEnter() {
9373
+ return setShowVolumeSlider(true);
9374
+ },
9375
+ onMouseLeave: function onMouseLeave() {
9376
+ return setShowVolumeSlider(false);
9377
+ },
9378
+ children: [
9379
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
9380
+ className: "sc-ctrl-btn",
9381
+ onClick: function onClick() {
9382
+ if (playerRef.current) playerRef.current.toggleMute();
9383
+ onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
9384
+ resetControlsTimer();
9385
+ },
9386
+ style: {
9387
+ padding: "".concat(8 * responsiveScale, "px"),
9388
+ borderRadius: "50%",
9389
+ minWidth: "".concat(36 * responsiveScale, "px"),
9390
+ minHeight: "".concat(36 * responsiveScale, "px")
9391
+ },
9392
+ title: isMuted ? "Unmute" : "Mute",
9393
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
9394
+ size: Math.max(14, 18 * responsiveScale)
9395
+ })
9396
+ }),
9397
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9398
+ style: {
9399
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
9400
+ overflow: "hidden",
9401
+ transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
9402
+ display: "flex",
9403
+ alignItems: "center",
9404
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
9405
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
9406
+ },
9407
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9408
+ style: {
9409
+ position: "relative",
9410
+ width: "".concat(56 * responsiveScale, "px"),
9411
+ height: "3px",
9412
+ cursor: "pointer",
9413
+ borderRadius: "1.5px"
9414
+ },
9415
+ onMouseDown: function onMouseDown(e) {
9416
+ e.preventDefault();
9417
+ var el = e.currentTarget;
9418
+ var move = function move(ev) {
9419
+ var r2 = el.getBoundingClientRect();
9420
+ handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
9421
+ };
9422
+ var up = function up1() {
9423
+ document.removeEventListener("mousemove", move);
9424
+ document.removeEventListener("mouseup", up);
9425
+ };
9426
+ document.addEventListener("mousemove", move);
9427
+ document.addEventListener("mouseup", up);
9428
+ var r = el.getBoundingClientRect();
9429
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9430
+ },
9431
+ onClick: function onClick(e) {
9432
+ e.stopPropagation();
9433
+ var r = e.currentTarget.getBoundingClientRect();
9434
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9435
+ },
9436
+ children: [
9437
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9438
+ style: {
9439
+ position: "absolute",
9440
+ inset: 0,
9441
+ background: "rgba(255, 255, 255, 0.2)",
9442
+ borderRadius: "1.5px"
9443
+ }
9444
+ }),
9445
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9446
+ style: {
9447
+ position: "absolute",
9448
+ top: 0,
9449
+ left: 0,
9450
+ bottom: 0,
9451
+ width: "".concat((isMuted ? 0 : volume) * 100, "%"),
9452
+ background: "#fff",
9453
+ borderRadius: "1.5px",
9454
+ transition: "width 0.1s ease-out"
9455
+ }
9456
+ }),
9457
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9458
+ style: {
9459
+ position: "absolute",
9460
+ top: "50%",
9461
+ left: "".concat((isMuted ? 0 : volume) * 100, "%"),
9462
+ transform: "translate(-50%, -50%)",
9463
+ width: "12px",
9464
+ height: "12px",
9465
+ background: "#fff",
9466
+ borderRadius: "50%",
9467
+ boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
9468
+ transition: "left 0.1s ease-out"
9469
+ }
9470
+ })
9471
+ ]
9472
+ })
9473
+ })
9474
+ ]
9475
+ }),
9235
9476
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
9236
9477
  className: "sc-ctrl-btn",
9237
9478
  onClick: function onClick() {
9238
- if (playerRef.current) playerRef.current.toggleMute();
9239
- onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
9479
+ if (onFullscreenToggle) {
9480
+ onFullscreenToggle();
9481
+ } else if (wrapperRef.current) {
9482
+ if (!document.fullscreenElement) {
9483
+ wrapperRef.current.requestFullscreen().catch(function() {});
9484
+ } else {
9485
+ document.exitFullscreen().catch(function() {});
9486
+ }
9487
+ }
9240
9488
  resetControlsTimer();
9241
9489
  },
9242
9490
  style: {
9243
9491
  padding: "".concat(8 * responsiveScale, "px"),
9244
9492
  borderRadius: "50%",
9245
9493
  minWidth: "".concat(36 * responsiveScale, "px"),
9246
- minHeight: "".concat(36 * responsiveScale, "px")
9494
+ minHeight: "".concat(36 * responsiveScale, "px"),
9495
+ background: "rgba(0, 0, 0, 0.6)"
9247
9496
  },
9248
- title: isMuted ? "Unmute" : "Mute",
9249
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
9497
+ title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
9498
+ children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
9499
+ size: Math.max(14, 18 * responsiveScale)
9500
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
9250
9501
  size: Math.max(14, 18 * responsiveScale)
9251
- })
9252
- }),
9253
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9254
- style: {
9255
- width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
9256
- overflow: "hidden",
9257
- transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
9258
- display: "flex",
9259
- alignItems: "center",
9260
- paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
9261
- paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
9262
- },
9263
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
9264
- style: {
9265
- position: "relative",
9266
- width: "".concat(56 * responsiveScale, "px"),
9267
- height: "3px",
9268
- cursor: "pointer",
9269
- borderRadius: "1.5px"
9270
- },
9271
- onMouseDown: function onMouseDown(e) {
9272
- e.preventDefault();
9273
- var el = e.currentTarget;
9274
- var move = function move(ev) {
9275
- var r2 = el.getBoundingClientRect();
9276
- handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
9277
- };
9278
- var up = function up1() {
9279
- document.removeEventListener("mousemove", move);
9280
- document.removeEventListener("mouseup", up);
9281
- };
9282
- document.addEventListener("mousemove", move);
9283
- document.addEventListener("mouseup", up);
9284
- var r = el.getBoundingClientRect();
9285
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9286
- },
9287
- onClick: function onClick(e) {
9288
- e.stopPropagation();
9289
- var r = e.currentTarget.getBoundingClientRect();
9290
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
9291
- },
9292
- children: [
9293
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9294
- style: {
9295
- position: "absolute",
9296
- inset: 0,
9297
- background: "rgba(255, 255, 255, 0.2)",
9298
- borderRadius: "1.5px"
9299
- }
9300
- }),
9301
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9302
- style: {
9303
- position: "absolute",
9304
- top: 0,
9305
- left: 0,
9306
- bottom: 0,
9307
- width: "".concat((isMuted ? 0 : volume) * 100, "%"),
9308
- background: "#fff",
9309
- borderRadius: "1.5px",
9310
- transition: "width 0.1s ease-out"
9311
- }
9312
- }),
9313
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
9314
- style: {
9315
- position: "absolute",
9316
- top: "50%",
9317
- left: "".concat((isMuted ? 0 : volume) * 100, "%"),
9318
- transform: "translate(-50%, -50%)",
9319
- width: "12px",
9320
- height: "12px",
9321
- background: "#fff",
9322
- borderRadius: "50%",
9323
- boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
9324
- transition: "left 0.1s ease-out"
9325
- }
9326
- })
9327
- ]
9328
9502
  })
9329
9503
  })
9330
9504
  ]
9331
- }),
9332
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
9333
- className: "sc-ctrl-btn",
9334
- onClick: function onClick() {
9335
- if (onFullscreenToggle) {
9336
- onFullscreenToggle();
9337
- } else if (wrapperRef.current) {
9338
- if (!document.fullscreenElement) {
9339
- wrapperRef.current.requestFullscreen().catch(function() {});
9340
- } else {
9341
- document.exitFullscreen().catch(function() {});
9342
- }
9343
- }
9344
- resetControlsTimer();
9345
- },
9346
- style: {
9347
- padding: "".concat(8 * responsiveScale, "px"),
9348
- borderRadius: "50%",
9349
- minWidth: "".concat(36 * responsiveScale, "px"),
9350
- minHeight: "".concat(36 * responsiveScale, "px"),
9351
- background: "rgba(0, 0, 0, 0.6)"
9352
- },
9353
- title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
9354
- children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
9355
- size: Math.max(14, 18 * responsiveScale)
9356
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
9357
- size: Math.max(14, 18 * responsiveScale)
9358
- })
9359
9505
  })
9360
9506
  ]
9361
9507
  }),