stormcloud-video-player 0.8.22 → 0.8.23

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.d.cts CHANGED
@@ -229,6 +229,7 @@ interface BaseStormcloudPlayerProps {
229
229
  wrapperStyle?: CSSProperties;
230
230
  allowNativeHls?: boolean;
231
231
  lowLatencyMode?: boolean;
232
+ isLiveStream?: boolean;
232
233
  driftToleranceMs?: number;
233
234
  immediateManifestAds?: boolean;
234
235
  debugAdTiming?: boolean;
package/lib/index.d.ts CHANGED
@@ -229,6 +229,7 @@ interface BaseStormcloudPlayerProps {
229
229
  wrapperStyle?: CSSProperties;
230
230
  allowNativeHls?: boolean;
231
231
  lowLatencyMode?: boolean;
232
+ isLiveStream?: boolean;
232
233
  driftToleranceMs?: number;
233
234
  immediateManifestAds?: boolean;
234
235
  debugAdTiming?: boolean;
package/lib/index.js CHANGED
@@ -2364,12 +2364,14 @@ var ANDROID_ID_TYPES = /* @__PURE__ */ new Set([
2364
2364
  "adid"
2365
2365
  ]);
2366
2366
  function resolveVastEnvironmentSignals(isCtv) {
2367
- var _ref, _bridgeSignals_limitAdTracking;
2367
+ var _ref;
2368
2368
  var bridgeSignals = readNativeBridgeSignals();
2369
+ var platformDevice = readPlatformNativeDeviceId();
2369
2370
  var lg = isCtv && isLgWebOS();
2370
- var deviceId = bridgeSignals.deviceId || readStoredDeviceId() || (lg ? getLgTestDeviceId() : void 0);
2371
- var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || inferDeviceIdType() || (lg ? "lgudid" : void 0);
2372
- var limitAdTracking = deviceId != null ? (_ref = (_bridgeSignals_limitAdTracking = bridgeSignals.limitAdTracking) !== null && _bridgeSignals_limitAdTracking !== void 0 ? _bridgeSignals_limitAdTracking : readStoredLimitAdTracking()) !== null && _ref !== void 0 ? _ref : false : void 0;
2371
+ var deviceId = bridgeSignals.deviceId || readStoredDeviceId() || platformDevice.deviceId || (lg && platformDevice.limitAdTracking !== true ? getLgTestDeviceId() : void 0);
2372
+ var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || platformDevice.deviceIdType || inferDeviceIdType() || (lg ? "lgudid" : void 0);
2373
+ var platformLat = bridgeSignals.deviceId ? bridgeSignals.limitAdTracking : platformDevice.limitAdTracking;
2374
+ var limitAdTracking = deviceId != null ? (_ref = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref !== void 0 ? _ref : false : void 0;
2373
2375
  if (isCtv) {
2374
2376
  return _object_spread_props(_object_spread({
2375
2377
  isCtv: true,
@@ -2440,6 +2442,72 @@ function createUuid() {
2440
2442
  return nibble.toString(16);
2441
2443
  });
2442
2444
  }
2445
+ function readPlatformNativeDeviceId() {
2446
+ if (typeof window === "undefined") return {};
2447
+ try {
2448
+ var _window_webapis;
2449
+ var adinfo = (_window_webapis = window.webapis) === null || _window_webapis === void 0 ? void 0 : _window_webapis.adinfo;
2450
+ if (adinfo) {
2451
+ var tifa = typeof adinfo.getTIFA === "function" ? adinfo.getTIFA() : adinfo.tifa;
2452
+ if (typeof tifa === "string" && tifa && !isMacroPlaceholder(tifa)) {
2453
+ var lat = typeof adinfo.isLATEnabled === "function" ? adinfo.isLATEnabled() : void 0;
2454
+ return _object_spread({
2455
+ deviceId: tifa,
2456
+ deviceIdType: "tifa"
2457
+ }, typeof lat === "boolean" ? {
2458
+ limitAdTracking: lat
2459
+ } : {});
2460
+ }
2461
+ }
2462
+ } catch (unused) {}
2463
+ try {
2464
+ var webOSDev = window.webOSDev;
2465
+ if (webOSDev) {
2466
+ var _webOSDev_lgudid;
2467
+ var lgudid = typeof webOSDev.LGUDID === "function" ? webOSDev.LGUDID() : (_webOSDev_lgudid = webOSDev.lgudid) !== null && _webOSDev_lgudid !== void 0 ? _webOSDev_lgudid : webOSDev.LGUDID;
2468
+ if (typeof lgudid === "string" && lgudid) {
2469
+ if (isZeroedAdId(lgudid)) {
2470
+ return {
2471
+ deviceIdType: "lgudid",
2472
+ limitAdTracking: true
2473
+ };
2474
+ }
2475
+ if (!isMacroPlaceholder(lgudid)) {
2476
+ return {
2477
+ deviceId: lgudid,
2478
+ deviceIdType: "lgudid",
2479
+ limitAdTracking: false
2480
+ };
2481
+ }
2482
+ }
2483
+ }
2484
+ } catch (unused) {}
2485
+ try {
2486
+ var roku = window.Roku;
2487
+ if (roku) {
2488
+ var rida = typeof roku.getPublisherUniqueId === "function" ? roku.getPublisherUniqueId() : roku.rida;
2489
+ if (typeof rida === "string" && rida && !isMacroPlaceholder(rida)) {
2490
+ return {
2491
+ deviceId: rida,
2492
+ deviceIdType: "rida",
2493
+ limitAdTracking: false
2494
+ };
2495
+ }
2496
+ }
2497
+ } catch (unused) {}
2498
+ return {};
2499
+ }
2500
+ var ZEROED_AD_ID_PATTERNS = /* @__PURE__ */ new Set([
2501
+ "38400000-8cf0-11bd-b23e-10b96e40000d",
2502
+ "00000000-0000-0000-0000-000000000000"
2503
+ ]);
2504
+ function isMacroPlaceholder(value) {
2505
+ var t = value.trim();
2506
+ return !t || /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/.test(t) || /^(unknown|null|undefined|none|n\/a|\$\{[^}]+\})$/i.test(t) || ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());
2507
+ }
2508
+ function isZeroedAdId(value) {
2509
+ return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());
2510
+ }
2443
2511
  function readNativeBridgeSignals() {
2444
2512
  if (typeof window === "undefined") {
2445
2513
  return {};
@@ -2780,7 +2848,7 @@ var INLINE_DEVICE_MACRO_REPLACEMENTS = [
2780
2848
  }
2781
2849
  }
2782
2850
  ];
2783
- function isMacroPlaceholder(value) {
2851
+ function isMacroPlaceholder2(value) {
2784
2852
  if (value == null) return true;
2785
2853
  var trimmed = value.trim();
2786
2854
  if (!trimmed) return true;
@@ -2839,11 +2907,11 @@ function applyDeviceIdentityParams(params, ctx) {
2839
2907
  if (runtimeId) {
2840
2908
  params.set("rdid", runtimeId);
2841
2909
  params.set("idtype", runtimeType || tagType || "aaid");
2842
- params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : isMacroPlaceholder(tagLat) ? "0" : tagLat);
2910
+ params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : isMacroPlaceholder2(tagLat) ? "0" : tagLat);
2843
2911
  return;
2844
2912
  }
2845
- var tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder(tagRdid));
2846
- var tagTypeValid = Boolean(tagType && !isMacroPlaceholder(tagType));
2913
+ var tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder2(tagRdid));
2914
+ var tagTypeValid = Boolean(tagType && !isMacroPlaceholder2(tagType));
2847
2915
  if (tagRdidValid && tagTypeValid && runtimeType && !isEquivalentDeviceIdType(tagType, runtimeType)) {
2848
2916
  params.delete("rdid");
2849
2917
  params.delete("idtype");
@@ -2851,10 +2919,10 @@ function applyDeviceIdentityParams(params, ctx) {
2851
2919
  return;
2852
2920
  }
2853
2921
  if (tagRdidValid) {
2854
- if (isMacroPlaceholder(tagType) && runtimeType) {
2922
+ if (isMacroPlaceholder2(tagType) && runtimeType) {
2855
2923
  params.set("idtype", runtimeType);
2856
2924
  }
2857
- if (isMacroPlaceholder(tagLat)) {
2925
+ if (isMacroPlaceholder2(tagLat)) {
2858
2926
  params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : "0");
2859
2927
  }
2860
2928
  return;
@@ -3040,7 +3108,7 @@ function applyVastMacros(baseUrl, ctx) {
3040
3108
  }
3041
3109
  var staleKeys = [];
3042
3110
  params.forEach(function(value, key) {
3043
- if (isMacroPlaceholder(value)) {
3111
+ if (isMacroPlaceholder2(value)) {
3044
3112
  staleKeys.push(key);
3045
3113
  }
3046
3114
  });
@@ -6019,7 +6087,7 @@ var HlsEngine = /*#__PURE__*/ function() {
6019
6087
  key: "setupNativeHls",
6020
6088
  value: function setupNativeHls() {
6021
6089
  return _async_to_generator(function() {
6022
- var _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
6090
+ var _this_config_isLiveStream, _this_config_lowLatencyMode, adBehavior, _this_video_play;
6023
6091
  return _ts_generator(this, function(_state) {
6024
6092
  switch(_state.label){
6025
6093
  case 0:
@@ -6028,10 +6096,11 @@ var HlsEngine = /*#__PURE__*/ function() {
6028
6096
  this.video.src = this.config.src;
6029
6097
  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;
6030
6098
  if (this.debug) {
6031
- console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
6099
+ adBehavior = this.isLiveStream ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
6100
+ console.log("[StormcloudVideoPlayer] Using native HLS playback:", {
6032
6101
  isLive: this.isLiveStream,
6033
6102
  allowNativeHls: this.config.allowNativeHls,
6034
- adBehavior: "vod (main video pauses during ads)"
6103
+ adBehavior: adBehavior
6035
6104
  });
6036
6105
  }
6037
6106
  if (!this.config.autoplay) return [
@@ -6440,6 +6509,14 @@ var HlsEngine = /*#__PURE__*/ function() {
6440
6509
  });
6441
6510
  }
6442
6511
  },
6512
+ {
6513
+ key: "getLiveSyncPosition",
6514
+ value: function getLiveSyncPosition() {
6515
+ var _this_hls;
6516
+ var pos = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.liveSyncPosition;
6517
+ return typeof pos === "number" && Number.isFinite(pos) ? pos : void 0;
6518
+ }
6519
+ },
6443
6520
  {
6444
6521
  key: "destroy",
6445
6522
  value: function destroy() {
@@ -8015,6 +8092,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8015
8092
  this.host.video.volume = restoredVolume;
8016
8093
  }
8017
8094
  if (this.host.shouldContinueLiveStreamDuringAds()) {
8095
+ var liveSyncPos = this.host.getLiveSyncPosition();
8096
+ if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8097
+ if (this.debug) {
8098
+ console.log("[StormcloudVideoPlayer] Live break end — snapping to live edge: ".concat(this.host.video.currentTime.toFixed(2), "s → ").concat(liveSyncPos.toFixed(2), "s"));
8099
+ }
8100
+ this.host.video.currentTime = liveSyncPos;
8101
+ }
8018
8102
  if (this.host.video.paused) {
8019
8103
  var _this_host_video_play;
8020
8104
  if (this.debug) console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
@@ -8158,6 +8242,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8158
8242
  shouldContinueLiveStreamDuringAds: function shouldContinueLiveStreamDuringAds() {
8159
8243
  return _this.shouldContinueLiveStreamDuringAds();
8160
8244
  },
8245
+ getLiveSyncPosition: function getLiveSyncPosition() {
8246
+ return _this.hlsEngine.getLiveSyncPosition();
8247
+ },
8161
8248
  generateVastUrls: function generateVastUrls(base, count) {
8162
8249
  return _this.generateVastUrls(base, count);
8163
8250
  }
@@ -8199,7 +8286,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8199
8286
  // ───────────────────────────────────────────────────────────────
8200
8287
  function load() {
8201
8288
  return _async_to_generator(function() {
8202
- var _this, _this_config_lowLatencyMode, error;
8289
+ var _this, _this_config_lowLatencyMode, error, continueLiveStreamDuringAds;
8203
8290
  return _ts_generator(this, function(_state) {
8204
8291
  switch(_state.label){
8205
8292
  case 0:
@@ -8253,15 +8340,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8253
8340
  3,
8254
8341
  6
8255
8342
  ];
8256
- this.adPlayer.destroy();
8257
- this.adPlayer = this.createAdPlayer(false);
8258
- this.adPlayer.initialize();
8259
8343
  return [
8260
8344
  4,
8261
8345
  this.hlsEngine.setupNativeHls()
8262
8346
  ];
8263
8347
  case 5:
8264
8348
  _state.sent();
8349
+ continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
8350
+ if (this.debug) {
8351
+ console.log("[StormcloudVideoPlayer] Native HLS ad behavior:", {
8352
+ isLive: this.hlsEngine.isLiveStream,
8353
+ continueLiveStreamDuringAds: continueLiveStreamDuringAds
8354
+ });
8355
+ }
8356
+ this.adPlayer.destroy();
8357
+ this.adPlayer = this.createAdPlayer(continueLiveStreamDuringAds);
8358
+ this.adPlayer.initialize();
8265
8359
  return [
8266
8360
  2
8267
8361
  ];
@@ -8369,9 +8463,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8369
8463
  {
8370
8464
  key: "shouldContinueLiveStreamDuringAds",
8371
8465
  value: function shouldContinueLiveStreamDuringAds() {
8372
- if (this.config.allowNativeHls) return false;
8373
- if (!this.hlsEngine.isLiveStream) return false;
8374
- return true;
8466
+ if (this.hlsEngine.isLiveStream) {
8467
+ return true;
8468
+ }
8469
+ var duration = this.video.duration;
8470
+ if (!Number.isFinite(duration) || duration === Infinity) {
8471
+ return true;
8472
+ }
8473
+ return false;
8375
8474
  }
8376
8475
  },
8377
8476
  {
@@ -8669,9 +8768,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8669
8768
  this.adBreak.showAds = true;
8670
8769
  this.adBreak.inAdBreak = true;
8671
8770
  this.timing.currentAdBreakStartWallClockMs = Date.now();
8672
- if (!this.video.paused) {
8673
- this.video.pause();
8674
- }
8675
8771
  _state.label = 1;
8676
8772
  case 1:
8677
8773
  _state.trys.push([
@@ -9045,7 +9141,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
9045
9141
  setShowSpeedMenu(false);
9046
9142
  };
9047
9143
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
9048
- var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
9144
+ var isLiveUiMode = isLiveStream === true;
9145
+ var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? !isLiveUiMode : true);
9049
9146
  var criticalPropsKey = useMemo(function() {
9050
9147
  return CRITICAL_PROPS.map(function(prop) {
9051
9148
  return "".concat(prop, ":").concat(props[prop]);
@@ -10426,6 +10523,7 @@ var HlsPlayer = /*#__PURE__*/ function(Component) {
10426
10523
  if (_this1.props.muted !== void 0) config.muted = _this1.props.muted;
10427
10524
  if (_this1.props.lowLatencyMode !== void 0) config.lowLatencyMode = _this1.props.lowLatencyMode;
10428
10525
  if (_this1.props.allowNativeHls !== void 0) config.allowNativeHls = _this1.props.allowNativeHls;
10526
+ if (_this1.props.isLiveStream !== void 0) config.isLiveStream = _this1.props.isLiveStream;
10429
10527
  if (_this1.props.driftToleranceMs !== void 0) config.driftToleranceMs = _this1.props.driftToleranceMs;
10430
10528
  if (_this1.props.immediateManifestAds !== void 0) config.immediateManifestAds = _this1.props.immediateManifestAds;
10431
10529
  if (_this1.props.debugAdTiming !== void 0) config.debugAdTiming = _this1.props.debugAdTiming;
@@ -11194,6 +11292,7 @@ var SUPPORTED_PROPS = [
11194
11292
  "wrapperStyle",
11195
11293
  "allowNativeHls",
11196
11294
  "lowLatencyMode",
11295
+ "isLiveStream",
11197
11296
  "driftToleranceMs",
11198
11297
  "immediateManifestAds",
11199
11298
  "debugAdTiming",