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.
@@ -2331,6 +2331,18 @@ var AIRY_ROKU_APP_ID = "com.freeairytv.roku";
2331
2331
  var AIRY_APP_NAME = "AiryTV Movies & TV";
2332
2332
  var AIRY_DEFAULT_CONTENT_URL = "https://live.airy.tv";
2333
2333
  var CTV_SESSION_STORAGE_KEY = "stormcloud.ctv.sid";
2334
+ var LG_TEST_APP_ID = "com.hulu.plus";
2335
+ var LG_TEST_APP_NAME = "Hulu";
2336
+ var LG_TEST_CONTENT_URL = "https://www.hulu.com/live-tv";
2337
+ var _lgTestDeviceId;
2338
+ function getLgTestDeviceId() {
2339
+ if (!_lgTestDeviceId) _lgTestDeviceId = createUuid();
2340
+ return _lgTestDeviceId;
2341
+ }
2342
+ function isLgWebOS() {
2343
+ if (typeof navigator === "undefined") return false;
2344
+ return /Web0S|webOS|LG Browser|LGSTB|LGE/i.test(navigator.userAgent);
2345
+ }
2334
2346
  function getDefaultAppId() {
2335
2347
  if (typeof navigator === "undefined") return AIRY_ANDROID_APP_ID;
2336
2348
  var ua = navigator.userAgent;
@@ -2356,17 +2368,20 @@ var ANDROID_ID_TYPES = /* @__PURE__ */ new Set([
2356
2368
  "adid"
2357
2369
  ]);
2358
2370
  function resolveVastEnvironmentSignals(isCtv) {
2359
- var _ref, _bridgeSignals_limitAdTracking;
2371
+ var _ref;
2360
2372
  var bridgeSignals = readNativeBridgeSignals();
2361
- var deviceId = bridgeSignals.deviceId || readStoredDeviceId();
2362
- var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || inferDeviceIdType();
2363
- 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;
2373
+ var platformDevice = readPlatformNativeDeviceId();
2374
+ var lg = isCtv && isLgWebOS();
2375
+ var deviceId = bridgeSignals.deviceId || readStoredDeviceId() || platformDevice.deviceId || (lg && platformDevice.limitAdTracking !== true ? getLgTestDeviceId() : void 0);
2376
+ var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || platformDevice.deviceIdType || inferDeviceIdType() || (lg ? "lgudid" : void 0);
2377
+ var platformLat = bridgeSignals.deviceId ? bridgeSignals.limitAdTracking : platformDevice.limitAdTracking;
2378
+ var limitAdTracking = deviceId != null ? (_ref = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref !== void 0 ? _ref : false : void 0;
2364
2379
  if (isCtv) {
2365
2380
  return _object_spread_props(_object_spread({
2366
2381
  isCtv: true,
2367
- contentUrl: bridgeSignals.contentUrl || readStoredString("contentUrl") || AIRY_DEFAULT_CONTENT_URL,
2368
- appId: bridgeSignals.appId || readStoredString("appId") || readStoredString("msid") || getDefaultAppId(),
2369
- appName: bridgeSignals.appName || readStoredString("appName") || readStoredString("an") || AIRY_APP_NAME,
2382
+ contentUrl: bridgeSignals.contentUrl || readStoredString("contentUrl") || (lg ? LG_TEST_CONTENT_URL : AIRY_DEFAULT_CONTENT_URL),
2383
+ appId: bridgeSignals.appId || readStoredString("appId") || readStoredString("msid") || (lg ? LG_TEST_APP_ID : getDefaultAppId()),
2384
+ appName: bridgeSignals.appName || readStoredString("appName") || readStoredString("an") || (lg ? LG_TEST_APP_NAME : AIRY_APP_NAME),
2370
2385
  sessionId: getOrCreateCtvSessionId()
2371
2386
  }, deviceId ? {
2372
2387
  deviceId: deviceId
@@ -2431,6 +2446,72 @@ function createUuid() {
2431
2446
  return nibble.toString(16);
2432
2447
  });
2433
2448
  }
2449
+ function readPlatformNativeDeviceId() {
2450
+ if (typeof window === "undefined") return {};
2451
+ try {
2452
+ var _window_webapis;
2453
+ var adinfo = (_window_webapis = window.webapis) === null || _window_webapis === void 0 ? void 0 : _window_webapis.adinfo;
2454
+ if (adinfo) {
2455
+ var tifa = typeof adinfo.getTIFA === "function" ? adinfo.getTIFA() : adinfo.tifa;
2456
+ if (typeof tifa === "string" && tifa && !isMacroPlaceholder(tifa)) {
2457
+ var lat = typeof adinfo.isLATEnabled === "function" ? adinfo.isLATEnabled() : void 0;
2458
+ return _object_spread({
2459
+ deviceId: tifa,
2460
+ deviceIdType: "tifa"
2461
+ }, typeof lat === "boolean" ? {
2462
+ limitAdTracking: lat
2463
+ } : {});
2464
+ }
2465
+ }
2466
+ } catch (unused) {}
2467
+ try {
2468
+ var webOSDev = window.webOSDev;
2469
+ if (webOSDev) {
2470
+ var _webOSDev_lgudid;
2471
+ var lgudid = typeof webOSDev.LGUDID === "function" ? webOSDev.LGUDID() : (_webOSDev_lgudid = webOSDev.lgudid) !== null && _webOSDev_lgudid !== void 0 ? _webOSDev_lgudid : webOSDev.LGUDID;
2472
+ if (typeof lgudid === "string" && lgudid) {
2473
+ if (isZeroedAdId(lgudid)) {
2474
+ return {
2475
+ deviceIdType: "lgudid",
2476
+ limitAdTracking: true
2477
+ };
2478
+ }
2479
+ if (!isMacroPlaceholder(lgudid)) {
2480
+ return {
2481
+ deviceId: lgudid,
2482
+ deviceIdType: "lgudid",
2483
+ limitAdTracking: false
2484
+ };
2485
+ }
2486
+ }
2487
+ }
2488
+ } catch (unused) {}
2489
+ try {
2490
+ var roku = window.Roku;
2491
+ if (roku) {
2492
+ var rida = typeof roku.getPublisherUniqueId === "function" ? roku.getPublisherUniqueId() : roku.rida;
2493
+ if (typeof rida === "string" && rida && !isMacroPlaceholder(rida)) {
2494
+ return {
2495
+ deviceId: rida,
2496
+ deviceIdType: "rida",
2497
+ limitAdTracking: false
2498
+ };
2499
+ }
2500
+ }
2501
+ } catch (unused) {}
2502
+ return {};
2503
+ }
2504
+ var ZEROED_AD_ID_PATTERNS = /* @__PURE__ */ new Set([
2505
+ "38400000-8cf0-11bd-b23e-10b96e40000d",
2506
+ "00000000-0000-0000-0000-000000000000"
2507
+ ]);
2508
+ function isMacroPlaceholder(value) {
2509
+ var t = value.trim();
2510
+ return !t || /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/.test(t) || /^(unknown|null|undefined|none|n\/a|\$\{[^}]+\})$/i.test(t) || ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());
2511
+ }
2512
+ function isZeroedAdId(value) {
2513
+ return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());
2514
+ }
2434
2515
  function readNativeBridgeSignals() {
2435
2516
  if (typeof window === "undefined") {
2436
2517
  return {};
@@ -2771,7 +2852,7 @@ var INLINE_DEVICE_MACRO_REPLACEMENTS = [
2771
2852
  }
2772
2853
  }
2773
2854
  ];
2774
- function isMacroPlaceholder(value) {
2855
+ function isMacroPlaceholder2(value) {
2775
2856
  if (value == null) return true;
2776
2857
  var trimmed = value.trim();
2777
2858
  if (!trimmed) return true;
@@ -2830,11 +2911,11 @@ function applyDeviceIdentityParams(params, ctx) {
2830
2911
  if (runtimeId) {
2831
2912
  params.set("rdid", runtimeId);
2832
2913
  params.set("idtype", runtimeType || tagType || "aaid");
2833
- params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : isMacroPlaceholder(tagLat) ? "0" : tagLat);
2914
+ params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : isMacroPlaceholder2(tagLat) ? "0" : tagLat);
2834
2915
  return;
2835
2916
  }
2836
- var tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder(tagRdid));
2837
- var tagTypeValid = Boolean(tagType && !isMacroPlaceholder(tagType));
2917
+ var tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder2(tagRdid));
2918
+ var tagTypeValid = Boolean(tagType && !isMacroPlaceholder2(tagType));
2838
2919
  if (tagRdidValid && tagTypeValid && runtimeType && !isEquivalentDeviceIdType(tagType, runtimeType)) {
2839
2920
  params.delete("rdid");
2840
2921
  params.delete("idtype");
@@ -2842,10 +2923,10 @@ function applyDeviceIdentityParams(params, ctx) {
2842
2923
  return;
2843
2924
  }
2844
2925
  if (tagRdidValid) {
2845
- if (isMacroPlaceholder(tagType) && runtimeType) {
2926
+ if (isMacroPlaceholder2(tagType) && runtimeType) {
2846
2927
  params.set("idtype", runtimeType);
2847
2928
  }
2848
- if (isMacroPlaceholder(tagLat)) {
2929
+ if (isMacroPlaceholder2(tagLat)) {
2849
2930
  params.set("is_lat", latValue !== null && latValue !== void 0 ? latValue : "0");
2850
2931
  }
2851
2932
  return;
@@ -3031,7 +3112,7 @@ function applyVastMacros(baseUrl, ctx) {
3031
3112
  }
3032
3113
  var staleKeys = [];
3033
3114
  params.forEach(function(value, key) {
3034
- if (isMacroPlaceholder(value)) {
3115
+ if (isMacroPlaceholder2(value)) {
3035
3116
  staleKeys.push(key);
3036
3117
  }
3037
3118
  });
@@ -5980,7 +6061,7 @@ var HlsEngine = /*#__PURE__*/ function() {
5980
6061
  key: "setupNativeHls",
5981
6062
  value: function setupNativeHls() {
5982
6063
  return _async_to_generator(function() {
5983
- var _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
6064
+ var _this_config_isLiveStream, _this_config_lowLatencyMode, adBehavior, _this_video_play;
5984
6065
  return _ts_generator(this, function(_state) {
5985
6066
  switch(_state.label){
5986
6067
  case 0:
@@ -5989,10 +6070,11 @@ var HlsEngine = /*#__PURE__*/ function() {
5989
6070
  this.video.src = this.config.src;
5990
6071
  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;
5991
6072
  if (this.debug) {
5992
- console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
6073
+ adBehavior = this.isLiveStream ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
6074
+ console.log("[StormcloudVideoPlayer] Using native HLS playback:", {
5993
6075
  isLive: this.isLiveStream,
5994
6076
  allowNativeHls: this.config.allowNativeHls,
5995
- adBehavior: "vod (main video pauses during ads)"
6077
+ adBehavior: adBehavior
5996
6078
  });
5997
6079
  }
5998
6080
  if (!this.config.autoplay) return [
@@ -6401,6 +6483,14 @@ var HlsEngine = /*#__PURE__*/ function() {
6401
6483
  });
6402
6484
  }
6403
6485
  },
6486
+ {
6487
+ key: "getLiveSyncPosition",
6488
+ value: function getLiveSyncPosition() {
6489
+ var _this_hls;
6490
+ var pos = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.liveSyncPosition;
6491
+ return typeof pos === "number" && Number.isFinite(pos) ? pos : void 0;
6492
+ }
6493
+ },
6404
6494
  {
6405
6495
  key: "destroy",
6406
6496
  value: function destroy() {
@@ -7975,6 +8065,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7975
8065
  this.host.video.volume = restoredVolume;
7976
8066
  }
7977
8067
  if (this.host.shouldContinueLiveStreamDuringAds()) {
8068
+ var liveSyncPos = this.host.getLiveSyncPosition();
8069
+ if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8070
+ if (this.debug) {
8071
+ console.log("[StormcloudVideoPlayer] Live break end — snapping to live edge: ".concat(this.host.video.currentTime.toFixed(2), "s → ").concat(liveSyncPos.toFixed(2), "s"));
8072
+ }
8073
+ this.host.video.currentTime = liveSyncPos;
8074
+ }
7978
8075
  if (this.host.video.paused) {
7979
8076
  var _this_host_video_play;
7980
8077
  if (this.debug) console.log("[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback");
@@ -8117,6 +8214,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8117
8214
  shouldContinueLiveStreamDuringAds: function shouldContinueLiveStreamDuringAds() {
8118
8215
  return _this.shouldContinueLiveStreamDuringAds();
8119
8216
  },
8217
+ getLiveSyncPosition: function getLiveSyncPosition() {
8218
+ return _this.hlsEngine.getLiveSyncPosition();
8219
+ },
8120
8220
  generateVastUrls: function generateVastUrls(base, count) {
8121
8221
  return _this.generateVastUrls(base, count);
8122
8222
  }
@@ -8158,7 +8258,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8158
8258
  // ───────────────────────────────────────────────────────────────
8159
8259
  function load() {
8160
8260
  return _async_to_generator(function() {
8161
- var _this, _this_config_lowLatencyMode, error;
8261
+ var _this, _this_config_lowLatencyMode, error, continueLiveStreamDuringAds;
8162
8262
  return _ts_generator(this, function(_state) {
8163
8263
  switch(_state.label){
8164
8264
  case 0:
@@ -8212,15 +8312,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8212
8312
  3,
8213
8313
  6
8214
8314
  ];
8215
- this.adPlayer.destroy();
8216
- this.adPlayer = this.createAdPlayer(false);
8217
- this.adPlayer.initialize();
8218
8315
  return [
8219
8316
  4,
8220
8317
  this.hlsEngine.setupNativeHls()
8221
8318
  ];
8222
8319
  case 5:
8223
8320
  _state.sent();
8321
+ continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
8322
+ if (this.debug) {
8323
+ console.log("[StormcloudVideoPlayer] Native HLS ad behavior:", {
8324
+ isLive: this.hlsEngine.isLiveStream,
8325
+ continueLiveStreamDuringAds: continueLiveStreamDuringAds
8326
+ });
8327
+ }
8328
+ this.adPlayer.destroy();
8329
+ this.adPlayer = this.createAdPlayer(continueLiveStreamDuringAds);
8330
+ this.adPlayer.initialize();
8224
8331
  return [
8225
8332
  2
8226
8333
  ];
@@ -8328,9 +8435,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8328
8435
  {
8329
8436
  key: "shouldContinueLiveStreamDuringAds",
8330
8437
  value: function shouldContinueLiveStreamDuringAds() {
8331
- if (this.config.allowNativeHls) return false;
8332
- if (!this.hlsEngine.isLiveStream) return false;
8333
- return true;
8438
+ if (this.hlsEngine.isLiveStream) {
8439
+ return true;
8440
+ }
8441
+ var duration = this.video.duration;
8442
+ if (!Number.isFinite(duration) || duration === Infinity) {
8443
+ return true;
8444
+ }
8445
+ return false;
8334
8446
  }
8335
8447
  },
8336
8448
  {
@@ -8628,9 +8740,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8628
8740
  this.adBreak.showAds = true;
8629
8741
  this.adBreak.inAdBreak = true;
8630
8742
  this.timing.currentAdBreakStartWallClockMs = Date.now();
8631
- if (!this.video.paused) {
8632
- this.video.pause();
8633
- }
8634
8743
  _state.label = 1;
8635
8744
  case 1:
8636
8745
  _state.trys.push([
@@ -8891,6 +9000,7 @@ var HlsPlayer = /*#__PURE__*/ function(_import_react_Component) {
8891
9000
  if (_this1.props.muted !== void 0) config.muted = _this1.props.muted;
8892
9001
  if (_this1.props.lowLatencyMode !== void 0) config.lowLatencyMode = _this1.props.lowLatencyMode;
8893
9002
  if (_this1.props.allowNativeHls !== void 0) config.allowNativeHls = _this1.props.allowNativeHls;
9003
+ if (_this1.props.isLiveStream !== void 0) config.isLiveStream = _this1.props.isLiveStream;
8894
9004
  if (_this1.props.driftToleranceMs !== void 0) config.driftToleranceMs = _this1.props.driftToleranceMs;
8895
9005
  if (_this1.props.immediateManifestAds !== void 0) config.immediateManifestAds = _this1.props.immediateManifestAds;
8896
9006
  if (_this1.props.debugAdTiming !== void 0) config.debugAdTiming = _this1.props.debugAdTiming;