stormcloud-video-player 0.8.21 → 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.
@@ -2367,6 +2367,18 @@ var AIRY_ROKU_APP_ID = "com.freeairytv.roku";
2367
2367
  var AIRY_APP_NAME = "AiryTV Movies & TV";
2368
2368
  var AIRY_DEFAULT_CONTENT_URL = "https://live.airy.tv";
2369
2369
  var CTV_SESSION_STORAGE_KEY = "stormcloud.ctv.sid";
2370
+ var LG_TEST_APP_ID = "com.hulu.plus";
2371
+ var LG_TEST_APP_NAME = "Hulu";
2372
+ var LG_TEST_CONTENT_URL = "https://www.hulu.com/live-tv";
2373
+ var _lgTestDeviceId;
2374
+ function getLgTestDeviceId() {
2375
+ if (!_lgTestDeviceId) _lgTestDeviceId = createUuid();
2376
+ return _lgTestDeviceId;
2377
+ }
2378
+ function isLgWebOS() {
2379
+ if (typeof navigator === "undefined") return false;
2380
+ return /Web0S|webOS|LG Browser|LGSTB|LGE/i.test(navigator.userAgent);
2381
+ }
2370
2382
  function getDefaultAppId() {
2371
2383
  if (typeof navigator === "undefined") return AIRY_ANDROID_APP_ID;
2372
2384
  var ua = navigator.userAgent;
@@ -2392,17 +2404,20 @@ var ANDROID_ID_TYPES = /* @__PURE__ */ new Set([
2392
2404
  "adid"
2393
2405
  ]);
2394
2406
  function resolveVastEnvironmentSignals(isCtv) {
2395
- var _ref, _bridgeSignals_limitAdTracking;
2407
+ var _ref;
2396
2408
  var bridgeSignals = readNativeBridgeSignals();
2397
- var deviceId = bridgeSignals.deviceId || readStoredDeviceId();
2398
- var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || inferDeviceIdType();
2399
- 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;
2409
+ var platformDevice = readPlatformNativeDeviceId();
2410
+ var lg = isCtv && isLgWebOS();
2411
+ var deviceId = bridgeSignals.deviceId || readStoredDeviceId() || platformDevice.deviceId || (lg && platformDevice.limitAdTracking !== true ? getLgTestDeviceId() : void 0);
2412
+ var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || platformDevice.deviceIdType || inferDeviceIdType() || (lg ? "lgudid" : void 0);
2413
+ var platformLat = bridgeSignals.deviceId ? bridgeSignals.limitAdTracking : platformDevice.limitAdTracking;
2414
+ var limitAdTracking = deviceId != null ? (_ref = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref !== void 0 ? _ref : false : void 0;
2400
2415
  if (isCtv) {
2401
2416
  return _object_spread_props(_object_spread({
2402
2417
  isCtv: true,
2403
- contentUrl: bridgeSignals.contentUrl || readStoredString("contentUrl") || AIRY_DEFAULT_CONTENT_URL,
2404
- appId: bridgeSignals.appId || readStoredString("appId") || readStoredString("msid") || getDefaultAppId(),
2405
- appName: bridgeSignals.appName || readStoredString("appName") || readStoredString("an") || AIRY_APP_NAME,
2418
+ contentUrl: bridgeSignals.contentUrl || readStoredString("contentUrl") || (lg ? LG_TEST_CONTENT_URL : AIRY_DEFAULT_CONTENT_URL),
2419
+ appId: bridgeSignals.appId || readStoredString("appId") || readStoredString("msid") || (lg ? LG_TEST_APP_ID : getDefaultAppId()),
2420
+ appName: bridgeSignals.appName || readStoredString("appName") || readStoredString("an") || (lg ? LG_TEST_APP_NAME : AIRY_APP_NAME),
2406
2421
  sessionId: getOrCreateCtvSessionId()
2407
2422
  }, deviceId ? {
2408
2423
  deviceId: deviceId
@@ -2467,6 +2482,72 @@ function createUuid() {
2467
2482
  return nibble.toString(16);
2468
2483
  });
2469
2484
  }
2485
+ function readPlatformNativeDeviceId() {
2486
+ if (typeof window === "undefined") return {};
2487
+ try {
2488
+ var _window_webapis;
2489
+ var adinfo = (_window_webapis = window.webapis) === null || _window_webapis === void 0 ? void 0 : _window_webapis.adinfo;
2490
+ if (adinfo) {
2491
+ var tifa = typeof adinfo.getTIFA === "function" ? adinfo.getTIFA() : adinfo.tifa;
2492
+ if (typeof tifa === "string" && tifa && !isMacroPlaceholder(tifa)) {
2493
+ var lat = typeof adinfo.isLATEnabled === "function" ? adinfo.isLATEnabled() : void 0;
2494
+ return _object_spread({
2495
+ deviceId: tifa,
2496
+ deviceIdType: "tifa"
2497
+ }, typeof lat === "boolean" ? {
2498
+ limitAdTracking: lat
2499
+ } : {});
2500
+ }
2501
+ }
2502
+ } catch (unused) {}
2503
+ try {
2504
+ var webOSDev = window.webOSDev;
2505
+ if (webOSDev) {
2506
+ var _webOSDev_lgudid;
2507
+ var lgudid = typeof webOSDev.LGUDID === "function" ? webOSDev.LGUDID() : (_webOSDev_lgudid = webOSDev.lgudid) !== null && _webOSDev_lgudid !== void 0 ? _webOSDev_lgudid : webOSDev.LGUDID;
2508
+ if (typeof lgudid === "string" && lgudid) {
2509
+ if (isZeroedAdId(lgudid)) {
2510
+ return {
2511
+ deviceIdType: "lgudid",
2512
+ limitAdTracking: true
2513
+ };
2514
+ }
2515
+ if (!isMacroPlaceholder(lgudid)) {
2516
+ return {
2517
+ deviceId: lgudid,
2518
+ deviceIdType: "lgudid",
2519
+ limitAdTracking: false
2520
+ };
2521
+ }
2522
+ }
2523
+ }
2524
+ } catch (unused) {}
2525
+ try {
2526
+ var roku = window.Roku;
2527
+ if (roku) {
2528
+ var rida = typeof roku.getPublisherUniqueId === "function" ? roku.getPublisherUniqueId() : roku.rida;
2529
+ if (typeof rida === "string" && rida && !isMacroPlaceholder(rida)) {
2530
+ return {
2531
+ deviceId: rida,
2532
+ deviceIdType: "rida",
2533
+ limitAdTracking: false
2534
+ };
2535
+ }
2536
+ }
2537
+ } catch (unused) {}
2538
+ return {};
2539
+ }
2540
+ var ZEROED_AD_ID_PATTERNS = /* @__PURE__ */ new Set([
2541
+ "38400000-8cf0-11bd-b23e-10b96e40000d",
2542
+ "00000000-0000-0000-0000-000000000000"
2543
+ ]);
2544
+ function isMacroPlaceholder(value) {
2545
+ var t = value.trim();
2546
+ return !t || /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/.test(t) || /^(unknown|null|undefined|none|n\/a|\$\{[^}]+\})$/i.test(t) || ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());
2547
+ }
2548
+ function isZeroedAdId(value) {
2549
+ return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());
2550
+ }
2470
2551
  function readNativeBridgeSignals() {
2471
2552
  if (typeof window === "undefined") {
2472
2553
  return {};
@@ -2807,7 +2888,7 @@ var INLINE_DEVICE_MACRO_REPLACEMENTS = [
2807
2888
  }
2808
2889
  }
2809
2890
  ];
2810
- function isMacroPlaceholder(value) {
2891
+ function isMacroPlaceholder2(value) {
2811
2892
  if (value == null) return true;
2812
2893
  var trimmed = value.trim();
2813
2894
  if (!trimmed) return true;
@@ -2866,11 +2947,11 @@ function applyDeviceIdentityParams(params, ctx) {
2866
2947
  if (runtimeId) {
2867
2948
  params.set("rdid", runtimeId);
2868
2949
  params.set("idtype", runtimeType || tagType || "aaid");
2869
- params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : isMacroPlaceholder(tagLat) ? "0" : tagLat);
2950
+ params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : isMacroPlaceholder2(tagLat) ? "0" : tagLat);
2870
2951
  return;
2871
2952
  }
2872
- var tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder(tagRdid));
2873
- var tagTypeValid = Boolean(tagType && !isMacroPlaceholder(tagType));
2953
+ var tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder2(tagRdid));
2954
+ var tagTypeValid = Boolean(tagType && !isMacroPlaceholder2(tagType));
2874
2955
  if (tagRdidValid && tagTypeValid && runtimeType && !isEquivalentDeviceIdType(tagType, runtimeType)) {
2875
2956
  params.delete("rdid");
2876
2957
  params.delete("idtype");
@@ -2878,10 +2959,10 @@ function applyDeviceIdentityParams(params, ctx) {
2878
2959
  return;
2879
2960
  }
2880
2961
  if (tagRdidValid) {
2881
- if (isMacroPlaceholder(tagType) && runtimeType) {
2962
+ if (isMacroPlaceholder2(tagType) && runtimeType) {
2882
2963
  params.set("idtype", runtimeType);
2883
2964
  }
2884
- if (isMacroPlaceholder(tagLat)) {
2965
+ if (isMacroPlaceholder2(tagLat)) {
2885
2966
  params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : "0");
2886
2967
  }
2887
2968
  return;
@@ -3067,7 +3148,7 @@ function applyVastMacros(baseUrl, ctx) {
3067
3148
  }
3068
3149
  var staleKeys = [];
3069
3150
  params.forEach(function(value, key) {
3070
- if (isMacroPlaceholder(value)) {
3151
+ if (isMacroPlaceholder2(value)) {
3071
3152
  staleKeys.push(key);
3072
3153
  }
3073
3154
  });
@@ -6016,7 +6097,7 @@ var HlsEngine = /*#__PURE__*/ function() {
6016
6097
  key: "setupNativeHls",
6017
6098
  value: function setupNativeHls() {
6018
6099
  return _async_to_generator(function() {
6019
- var _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
6100
+ var _this_config_isLiveStream, _this_config_lowLatencyMode, adBehavior, _this_video_play;
6020
6101
  return _ts_generator(this, function(_state) {
6021
6102
  switch(_state.label){
6022
6103
  case 0:
@@ -6025,10 +6106,11 @@ var HlsEngine = /*#__PURE__*/ function() {
6025
6106
  this.video.src = this.config.src;
6026
6107
  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;
6027
6108
  if (this.debug) {
6028
- console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
6109
+ adBehavior = this.isLiveStream ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
6110
+ console.log("[StormcloudVideoPlayer] Using native HLS playback:", {
6029
6111
  isLive: this.isLiveStream,
6030
6112
  allowNativeHls: this.config.allowNativeHls,
6031
- adBehavior: "vod (main video pauses during ads)"
6113
+ adBehavior: adBehavior
6032
6114
  });
6033
6115
  }
6034
6116
  if (!this.config.autoplay) return [
@@ -6437,6 +6519,14 @@ var HlsEngine = /*#__PURE__*/ function() {
6437
6519
  });
6438
6520
  }
6439
6521
  },
6522
+ {
6523
+ key: "getLiveSyncPosition",
6524
+ value: function getLiveSyncPosition() {
6525
+ var _this_hls;
6526
+ var pos = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.liveSyncPosition;
6527
+ return typeof pos === "number" && Number.isFinite(pos) ? pos : void 0;
6528
+ }
6529
+ },
6440
6530
  {
6441
6531
  key: "destroy",
6442
6532
  value: function destroy() {
@@ -8011,6 +8101,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8011
8101
  this.host.video.volume = restoredVolume;
8012
8102
  }
8013
8103
  if (this.host.shouldContinueLiveStreamDuringAds()) {
8104
+ var liveSyncPos = this.host.getLiveSyncPosition();
8105
+ if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8106
+ if (this.debug) {
8107
+ console.log("[StormcloudVideoPlayer] Live break end — snapping to live edge: ".concat(this.host.video.currentTime.toFixed(2), "s → ").concat(liveSyncPos.toFixed(2), "s"));
8108
+ }
8109
+ this.host.video.currentTime = liveSyncPos;
8110
+ }
8014
8111
  if (this.host.video.paused) {
8015
8112
  var _this_host_video_play;
8016
8113
  if (this.debug) console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
@@ -8153,6 +8250,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8153
8250
  shouldContinueLiveStreamDuringAds: function shouldContinueLiveStreamDuringAds() {
8154
8251
  return _this.shouldContinueLiveStreamDuringAds();
8155
8252
  },
8253
+ getLiveSyncPosition: function getLiveSyncPosition() {
8254
+ return _this.hlsEngine.getLiveSyncPosition();
8255
+ },
8156
8256
  generateVastUrls: function generateVastUrls(base, count) {
8157
8257
  return _this.generateVastUrls(base, count);
8158
8258
  }
@@ -8194,7 +8294,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8194
8294
  // ───────────────────────────────────────────────────────────────
8195
8295
  function load() {
8196
8296
  return _async_to_generator(function() {
8197
- var _this, _this_config_lowLatencyMode, error;
8297
+ var _this, _this_config_lowLatencyMode, error, continueLiveStreamDuringAds;
8198
8298
  return _ts_generator(this, function(_state) {
8199
8299
  switch(_state.label){
8200
8300
  case 0:
@@ -8248,15 +8348,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8248
8348
  3,
8249
8349
  6
8250
8350
  ];
8251
- this.adPlayer.destroy();
8252
- this.adPlayer = this.createAdPlayer(false);
8253
- this.adPlayer.initialize();
8254
8351
  return [
8255
8352
  4,
8256
8353
  this.hlsEngine.setupNativeHls()
8257
8354
  ];
8258
8355
  case 5:
8259
8356
  _state.sent();
8357
+ continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
8358
+ if (this.debug) {
8359
+ console.log("[StormcloudVideoPlayer] Native HLS ad behavior:", {
8360
+ isLive: this.hlsEngine.isLiveStream,
8361
+ continueLiveStreamDuringAds: continueLiveStreamDuringAds
8362
+ });
8363
+ }
8364
+ this.adPlayer.destroy();
8365
+ this.adPlayer = this.createAdPlayer(continueLiveStreamDuringAds);
8366
+ this.adPlayer.initialize();
8260
8367
  return [
8261
8368
  2
8262
8369
  ];
@@ -8364,9 +8471,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8364
8471
  {
8365
8472
  key: "shouldContinueLiveStreamDuringAds",
8366
8473
  value: function shouldContinueLiveStreamDuringAds() {
8367
- if (this.config.allowNativeHls) return false;
8368
- if (!this.hlsEngine.isLiveStream) return false;
8369
- return true;
8474
+ if (this.hlsEngine.isLiveStream) {
8475
+ return true;
8476
+ }
8477
+ var duration = this.video.duration;
8478
+ if (!Number.isFinite(duration) || duration === Infinity) {
8479
+ return true;
8480
+ }
8481
+ return false;
8370
8482
  }
8371
8483
  },
8372
8484
  {
@@ -8664,9 +8776,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8664
8776
  this.adBreak.showAds = true;
8665
8777
  this.adBreak.inAdBreak = true;
8666
8778
  this.timing.currentAdBreakStartWallClockMs = Date.now();
8667
- if (!this.video.paused) {
8668
- this.video.pause();
8669
- }
8670
8779
  _state.label = 1;
8671
8780
  case 1:
8672
8781
  _state.trys.push([
@@ -8899,6 +9008,7 @@ var HlsPlayer = /*#__PURE__*/ function(_import_react2_Component) {
8899
9008
  if (_this1.props.muted !== void 0) config.muted = _this1.props.muted;
8900
9009
  if (_this1.props.lowLatencyMode !== void 0) config.lowLatencyMode = _this1.props.lowLatencyMode;
8901
9010
  if (_this1.props.allowNativeHls !== void 0) config.allowNativeHls = _this1.props.allowNativeHls;
9011
+ if (_this1.props.isLiveStream !== void 0) config.isLiveStream = _this1.props.isLiveStream;
8902
9012
  if (_this1.props.driftToleranceMs !== void 0) config.driftToleranceMs = _this1.props.driftToleranceMs;
8903
9013
  if (_this1.props.immediateManifestAds !== void 0) config.immediateManifestAds = _this1.props.immediateManifestAds;
8904
9014
  if (_this1.props.debugAdTiming !== void 0) config.debugAdTiming = _this1.props.debugAdTiming;