stormcloud-video-player 0.7.6 → 0.7.7

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.cjs CHANGED
@@ -6092,6 +6092,50 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6092
6092
  return min;
6093
6093
  }
6094
6094
  },
6095
+ {
6096
+ key: "getCurrentHlsSegmentDurationMs",
6097
+ value: function getCurrentHlsSegmentDurationMs() {
6098
+ var fallbackMs = 4e3;
6099
+ if (this.nativeHlsMode) {
6100
+ return fallbackMs;
6101
+ }
6102
+ var hls = this.hls;
6103
+ if (!hls) return null;
6104
+ var levelCandidates = [
6105
+ hls.currentLevel,
6106
+ hls.nextLoadLevel,
6107
+ hls.loadLevel
6108
+ ];
6109
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6110
+ try {
6111
+ for(var _iterator = levelCandidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6112
+ var levelIndex = _step.value;
6113
+ var _hls_levels_levelIndex, _hls_levels;
6114
+ if (typeof levelIndex !== "number" || levelIndex < 0) continue;
6115
+ var details = (_hls_levels = hls.levels) === null || _hls_levels === void 0 ? void 0 : (_hls_levels_levelIndex = _hls_levels[levelIndex]) === null || _hls_levels_levelIndex === void 0 ? void 0 : _hls_levels_levelIndex.details;
6116
+ if (!details) continue;
6117
+ var targetDurationSec = typeof details.partTarget === "number" && details.partTarget > 0 ? details.partTarget : typeof details.targetduration === "number" && details.targetduration > 0 ? details.targetduration : void 0;
6118
+ if (targetDurationSec !== void 0) {
6119
+ return Math.max(800, Math.floor(targetDurationSec * 1e3));
6120
+ }
6121
+ }
6122
+ } catch (err) {
6123
+ _didIteratorError = true;
6124
+ _iteratorError = err;
6125
+ } finally{
6126
+ try {
6127
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
6128
+ _iterator.return();
6129
+ }
6130
+ } finally{
6131
+ if (_didIteratorError) {
6132
+ throw _iteratorError;
6133
+ }
6134
+ }
6135
+ }
6136
+ return fallbackMs;
6137
+ }
6138
+ },
6095
6139
  {
6096
6140
  key: "videoElement",
6097
6141
  get: function get() {
@@ -7268,7 +7312,12 @@ var CRITICAL_PROPS = [
7268
7312
  var CONTROLS_HIDE_DELAY = 3e3;
7269
7313
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
7270
7314
  var DEBUG_PANEL_MARKER_LIMIT = 12;
7315
+ var AI_CONTEXT_FALLBACK_POLL_MS = 4e3;
7316
+ var AI_CONTEXT_MIN_POLL_MS = 800;
7317
+ var PANEL_BASE_RIGHT_OFFSET = 10;
7271
7318
  var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props) {
7319
+ var _ref;
7320
+ var _aiLiveContext_context, _aiLiveContext_context_keywords, _aiLiveContext_context1;
7272
7321
  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, minSegmentsBeforePlay = props.minSegmentsBeforePlay, disableAds = props.disableAds, disableFiller = props.disableFiller, swirlProjectId = props.swirlProjectId, restVideoAttrs = _object_without_properties(props, [
7273
7322
  "src",
7274
7323
  "autoplay",
@@ -7332,6 +7381,13 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7332
7381
  var _import_react2_default_useState20 = _sliced_to_array(import_react2.default.useState(DEFAULT_PLAYER_ASPECT_RATIO), 2), playerAspectRatio = _import_react2_default_useState20[0], setPlayerAspectRatio = _import_react2_default_useState20[1];
7333
7382
  var _import_react2_default_useState21 = _sliced_to_array(import_react2.default.useState(false), 2), showDebugPanel = _import_react2_default_useState21[0], setShowDebugPanel = _import_react2_default_useState21[1];
7334
7383
  var _import_react2_default_useState22 = _sliced_to_array(import_react2.default.useState([]), 2), debugMarkers = _import_react2_default_useState22[0], setDebugMarkers = _import_react2_default_useState22[1];
7384
+ var _import_react2_default_useState23 = _sliced_to_array(import_react2.default.useState(false), 2), showAiPanel = _import_react2_default_useState23[0], setShowAiPanel = _import_react2_default_useState23[1];
7385
+ var _import_react2_default_useState24 = _sliced_to_array(import_react2.default.useState({
7386
+ context: null,
7387
+ isLoading: false,
7388
+ error: null,
7389
+ lastPolledAt: null
7390
+ }), 2), aiLiveContext = _import_react2_default_useState24[0], setAiLiveContext = _import_react2_default_useState24[1];
7335
7391
  var getResponsiveScale = function getResponsiveScale() {
7336
7392
  if (viewportWidth < 480) return 0.7;
7337
7393
  if (viewportWidth < 768) return 0.8;
@@ -7361,6 +7417,18 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7361
7417
  if (typeof obj.splice_command_type === "number") return "binary splice";
7362
7418
  return "marker";
7363
7419
  };
7420
+ var formatAiRelativeTime = function formatAiRelativeTime(timestamp) {
7421
+ var epochMs = Date.parse(timestamp);
7422
+ if (!Number.isFinite(epochMs)) return "unknown";
7423
+ var diffSec = Math.max(0, Math.floor((Date.now() - epochMs) / 1e3));
7424
+ if (diffSec < 5) return "just now";
7425
+ if (diffSec < 60) return "".concat(diffSec, "s ago");
7426
+ var diffMin = Math.floor(diffSec / 60);
7427
+ if (diffMin < 60) return "".concat(diffMin, "m ago");
7428
+ var diffHr = Math.floor(diffMin / 60);
7429
+ if (diffHr < 24) return "".concat(diffHr, "h ago");
7430
+ return "".concat(Math.floor(diffHr / 24), "d ago");
7431
+ };
7364
7432
  var resetControlsTimer = (0, import_react2.useCallback)(function() {
7365
7433
  if (controlsTimerRef.current) {
7366
7434
  clearTimeout(controlsTimerRef.current);
@@ -7438,7 +7506,14 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7438
7506
  };
7439
7507
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
7440
7508
  var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
7509
+ var analyzerPanelWidth = Math.min(420, Math.max(320, viewportWidth * 0.41));
7510
+ var analyzerPanelHeight = isPortrait ? "52vh" : "420px";
7511
+ var analyzerPanelMaxHeight = "60vh";
7512
+ var panelGap = Math.max(8, 12 * responsiveScale);
7513
+ var shouldStackPanels = isPortrait || viewportWidth < 980;
7441
7514
  var debugPanelBottomOffset = shouldShowEnhancedControls ? Math.max(74, 92 * responsiveScale) : Math.max(52, 58 * responsiveScale);
7515
+ var panelBaseRight = PANEL_BASE_RIGHT_OFFSET * responsiveScale;
7516
+ var debugPanelRightOffset = showAiPanel && !shouldStackPanels ? panelBaseRight + analyzerPanelWidth + panelGap : panelBaseRight;
7442
7517
  var criticalPropsKey = (0, import_react2.useMemo)(function() {
7443
7518
  return CRITICAL_PROPS.map(function(prop) {
7444
7519
  return "".concat(prop, ":").concat(props[prop]);
@@ -7764,6 +7839,130 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7764
7839
  debugAdTiming,
7765
7840
  criticalPropsKey
7766
7841
  ]);
7842
+ (0, import_react2.useEffect)(function() {
7843
+ if (!swirlProjectId) {
7844
+ setShowAiPanel(false);
7845
+ setAiLiveContext({
7846
+ context: null,
7847
+ isLoading: false,
7848
+ error: null,
7849
+ lastPolledAt: null
7850
+ });
7851
+ }
7852
+ }, [
7853
+ swirlProjectId
7854
+ ]);
7855
+ (0, import_react2.useEffect)(function() {
7856
+ if (!showAiPanel || !swirlProjectId) return;
7857
+ var cancelled = false;
7858
+ var pollTimeoutId = null;
7859
+ var inFlight = false;
7860
+ var pollLiveContext = function pollLiveContext1() {
7861
+ return _async_to_generator(function() {
7862
+ var response, payload, error, message, _ref, _playerRef_current, segmentPollMs, nextPollMs;
7863
+ return _ts_generator(this, function(_state) {
7864
+ switch(_state.label){
7865
+ case 0:
7866
+ if (cancelled || inFlight) return [
7867
+ 2
7868
+ ];
7869
+ inFlight = true;
7870
+ setAiLiveContext(function(prev) {
7871
+ return _object_spread_props(_object_spread({}, prev), {
7872
+ isLoading: prev.context == null,
7873
+ error: null
7874
+ });
7875
+ });
7876
+ _state.label = 1;
7877
+ case 1:
7878
+ _state.trys.push([
7879
+ 1,
7880
+ 4,
7881
+ 5,
7882
+ 6
7883
+ ]);
7884
+ return [
7885
+ 4,
7886
+ fetch("https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/".concat(swirlProjectId, "/live-context"), {
7887
+ method: "GET",
7888
+ headers: {
7889
+ Accept: "application/json"
7890
+ }
7891
+ })
7892
+ ];
7893
+ case 2:
7894
+ response = _state.sent();
7895
+ if (!response.ok) {
7896
+ throw new Error("Live context request failed (".concat(response.status, " ").concat(response.statusText, ")"));
7897
+ }
7898
+ return [
7899
+ 4,
7900
+ response.json()
7901
+ ];
7902
+ case 3:
7903
+ payload = _state.sent();
7904
+ if (cancelled) return [
7905
+ 2
7906
+ ];
7907
+ setAiLiveContext({
7908
+ context: payload,
7909
+ isLoading: false,
7910
+ error: null,
7911
+ lastPolledAt: Date.now()
7912
+ });
7913
+ return [
7914
+ 3,
7915
+ 6
7916
+ ];
7917
+ case 4:
7918
+ error = _state.sent();
7919
+ if (cancelled) return [
7920
+ 2
7921
+ ];
7922
+ message = _instanceof(error, Error) ? error.message : "Unable to load AI live context.";
7923
+ setAiLiveContext(function(prev) {
7924
+ return _object_spread_props(_object_spread({}, prev), {
7925
+ isLoading: false,
7926
+ error: message,
7927
+ lastPolledAt: Date.now()
7928
+ });
7929
+ });
7930
+ return [
7931
+ 3,
7932
+ 6
7933
+ ];
7934
+ case 5:
7935
+ inFlight = false;
7936
+ if (!cancelled) {
7937
+ ;
7938
+ ;
7939
+ segmentPollMs = (_ref = (_playerRef_current = playerRef.current) === null || _playerRef_current === void 0 ? void 0 : _playerRef_current.getCurrentHlsSegmentDurationMs()) !== null && _ref !== void 0 ? _ref : AI_CONTEXT_FALLBACK_POLL_MS;
7940
+ nextPollMs = Math.max(AI_CONTEXT_MIN_POLL_MS, segmentPollMs);
7941
+ pollTimeoutId = window.setTimeout(pollLiveContext, nextPollMs);
7942
+ }
7943
+ return [
7944
+ 7
7945
+ ];
7946
+ case 6:
7947
+ return [
7948
+ 2
7949
+ ];
7950
+ }
7951
+ });
7952
+ })();
7953
+ };
7954
+ pollLiveContext();
7955
+ return function() {
7956
+ cancelled = true;
7957
+ if (pollTimeoutId != null) {
7958
+ clearTimeout(pollTimeoutId);
7959
+ }
7960
+ };
7961
+ }, [
7962
+ showAiPanel,
7963
+ swirlProjectId,
7964
+ criticalPropsKey
7965
+ ]);
7767
7966
  var handleWrapperMouseMove = (0, import_react2.useCallback)(function() {
7768
7967
  resetControlsTimer();
7769
7968
  }, [
@@ -7782,7 +7981,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7782
7981
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, {
7783
7982
  children: [
7784
7983
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", {
7785
- children: "\n @keyframes sc-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes sc-loading-glow {\n 0%, 100% { opacity: 0.85; transform: scale(1); }\n 50% { opacity: 1; transform: scale(1.05); }\n }\n @keyframes sc-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n @keyframes sc-fade-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .sc-wrapper:fullscreen,\n .sc-wrapper:has(*:fullscreen) {\n border-radius: 0 !important;\n box-shadow: none !important;\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw !important;\n max-height: 100vh !important;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 999999 !important;\n background: #000 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n }\n .sc-ctrl-btn {\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 8px;\n transition: background 0.15s ease, opacity 0.15s ease;\n opacity: 0.9;\n }\n .sc-ctrl-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .sc-ctrl-btn:active {\n opacity: 0.7;\n }\n .sc-controls-bar {\n transition: opacity 0.35s ease, transform 0.35s ease;\n }\n .sc-progress-track:hover .sc-progress-thumb {\n transform: translate(-50%, -50%) scale(1) !important;\n }\n .sc-loading-hidden .sc-loading-indicator {\n display: none !important;\n }\n .sc-debug-scroll::-webkit-scrollbar {\n width: 8px;\n }\n .sc-debug-scroll::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.22);\n border-radius: 4px;\n }\n .sc-debug-scroll {\n overflow-x: hidden !important;\n }\n "
7984
+ children: "\n @keyframes sc-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes sc-loading-glow {\n 0%, 100% { opacity: 0.85; transform: scale(1); }\n 50% { opacity: 1; transform: scale(1.05); }\n }\n @keyframes sc-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n @keyframes sc-fade-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .sc-wrapper:fullscreen,\n .sc-wrapper:has(*:fullscreen) {\n border-radius: 0 !important;\n box-shadow: none !important;\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw !important;\n max-height: 100vh !important;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 999999 !important;\n background: #000 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n }\n .sc-ctrl-btn {\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 8px;\n transition: background 0.15s ease, opacity 0.15s ease;\n opacity: 0.9;\n }\n .sc-ctrl-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .sc-ctrl-btn:active {\n opacity: 0.7;\n }\n .sc-controls-bar {\n transition: opacity 0.35s ease, transform 0.35s ease;\n }\n .sc-progress-track:hover .sc-progress-thumb {\n transform: translate(-50%, -50%) scale(1) !important;\n }\n .sc-loading-hidden .sc-loading-indicator {\n display: none !important;\n }\n .sc-debug-scroll::-webkit-scrollbar {\n width: 8px;\n }\n .sc-debug-scroll::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.22);\n border-radius: 4px;\n }\n .sc-debug-scroll {\n overflow-x: hidden !important;\n }\n .sc-ai-scroll::-webkit-scrollbar {\n width: 8px;\n }\n .sc-ai-scroll::-webkit-scrollbar-thumb {\n background: rgba(236, 72, 153, 0.34);\n border-radius: 4px;\n }\n .sc-ai-scroll {\n overflow-x: hidden !important;\n }\n "
7786
7985
  }),
7787
7986
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
7788
7987
  ref: wrapperRef,
@@ -8024,15 +8223,189 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8024
8223
  })
8025
8224
  ]
8026
8225
  }),
8226
+ showAiPanel && !showLicenseWarning && swirlProjectId && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8227
+ style: _object_spread_props(_object_spread({
8228
+ position: "absolute",
8229
+ right: "".concat(panelBaseRight, "px")
8230
+ }, shouldStackPanels && showDebugPanel ? {
8231
+ top: "".concat(12 * responsiveScale, "px")
8232
+ } : {
8233
+ bottom: "".concat(debugPanelBottomOffset, "px")
8234
+ }), {
8235
+ width: "".concat(analyzerPanelWidth, "px"),
8236
+ maxWidth: "92vw",
8237
+ height: analyzerPanelHeight,
8238
+ maxHeight: analyzerPanelMaxHeight,
8239
+ zIndex: 61,
8240
+ background: "linear-gradient(165deg, rgba(17, 24, 39, 0.94) 0%, rgba(41, 17, 63, 0.82) 52%, rgba(17, 24, 39, 0.9) 100%)",
8241
+ border: "1px solid rgba(236, 72, 153, 0.35)",
8242
+ borderRadius: "14px",
8243
+ boxShadow: "0 18px 56px rgba(4, 7, 20, 0.58), inset 0 1px 0 rgba(255, 255, 255, 0.09)",
8244
+ backdropFilter: "blur(20px)",
8245
+ WebkitBackdropFilter: "blur(20px)",
8246
+ color: "rgba(255,255,255,0.96)",
8247
+ overflow: "hidden"
8248
+ }),
8249
+ children: [
8250
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8251
+ style: {
8252
+ display: "flex",
8253
+ alignItems: "center",
8254
+ justifyContent: "space-between",
8255
+ padding: "11px 13px",
8256
+ borderBottom: "1px solid rgba(255,255,255,0.12)",
8257
+ background: "linear-gradient(90deg, rgba(236, 72, 153, 0.2) 0%, rgba(168, 85, 247, 0.18) 100%)"
8258
+ },
8259
+ children: [
8260
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8261
+ children: [
8262
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8263
+ style: {
8264
+ fontSize: "13px",
8265
+ fontWeight: 800,
8266
+ letterSpacing: "0.02em"
8267
+ },
8268
+ children: "AI Live Context Analyzer"
8269
+ }),
8270
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8271
+ style: {
8272
+ marginTop: "2px",
8273
+ fontSize: "11px",
8274
+ color: "rgba(255,255,255,0.72)"
8275
+ },
8276
+ children: aiLiveContext.lastPolledAt ? "Updated ".concat(formatDebugClock(aiLiveContext.lastPolledAt)) : "Waiting for first sample..."
8277
+ })
8278
+ ]
8279
+ }),
8280
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8281
+ className: "sc-ctrl-btn",
8282
+ onClick: function onClick() {
8283
+ return setShowAiPanel(false);
8284
+ },
8285
+ style: {
8286
+ padding: "4px",
8287
+ borderRadius: "6px",
8288
+ minWidth: "26px",
8289
+ minHeight: "26px"
8290
+ },
8291
+ title: "Close AI panel",
8292
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fa.FaTimes, {
8293
+ size: 12
8294
+ })
8295
+ })
8296
+ ]
8297
+ }),
8298
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8299
+ className: "sc-ai-scroll",
8300
+ style: {
8301
+ padding: "12px",
8302
+ overflowY: "auto",
8303
+ overflowX: "hidden",
8304
+ height: "calc(100% - 52px)",
8305
+ display: "grid",
8306
+ gap: "12px"
8307
+ },
8308
+ children: [
8309
+ aiLiveContext.error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8310
+ style: {
8311
+ fontSize: "12px",
8312
+ color: "#fecaca",
8313
+ background: "rgba(220, 38, 38, 0.2)",
8314
+ border: "1px solid rgba(248, 113, 113, 0.5)",
8315
+ borderRadius: "10px",
8316
+ padding: "9px 10px"
8317
+ },
8318
+ children: aiLiveContext.error
8319
+ }),
8320
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8321
+ style: {
8322
+ padding: "11px 12px",
8323
+ borderRadius: "10px",
8324
+ border: "1px solid rgba(236, 72, 153, 0.5)",
8325
+ background: "linear-gradient(155deg, rgba(88, 28, 135, 0.35) 0%, rgba(17, 24, 39, 0.62) 100%)",
8326
+ boxShadow: "0 8px 24px rgba(236, 72, 153, 0.12)"
8327
+ },
8328
+ children: [
8329
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8330
+ style: {
8331
+ display: "flex",
8332
+ alignItems: "center",
8333
+ justifyContent: "space-between",
8334
+ gap: "8px",
8335
+ marginBottom: "7px"
8336
+ },
8337
+ children: [
8338
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8339
+ style: {
8340
+ fontSize: "11px",
8341
+ fontWeight: 800,
8342
+ textTransform: "uppercase",
8343
+ letterSpacing: "0.1em",
8344
+ color: "#f9a8d4"
8345
+ },
8346
+ children: "AI Context"
8347
+ }),
8348
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8349
+ style: {
8350
+ fontSize: "10px",
8351
+ color: "rgba(255,255,255,0.72)",
8352
+ fontFamily: "'SF Mono', 'Cascadia Code', monospace"
8353
+ },
8354
+ children: aiLiveContext.context ? formatAiRelativeTime(aiLiveContext.context.updated_at) : "--"
8355
+ })
8356
+ ]
8357
+ }),
8358
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8359
+ style: {
8360
+ fontSize: "13px",
8361
+ lineHeight: "1.58",
8362
+ color: "rgba(255,255,255,0.95)",
8363
+ whiteSpace: "pre-wrap"
8364
+ },
8365
+ children: (_ref = (_aiLiveContext_context = aiLiveContext.context) === null || _aiLiveContext_context === void 0 ? void 0 : _aiLiveContext_context.context) !== null && _ref !== void 0 ? _ref : aiLiveContext.isLoading ? "Analyzing live stream..." : "Waiting for AI context response."
8366
+ }),
8367
+ ((_aiLiveContext_context1 = aiLiveContext.context) === null || _aiLiveContext_context1 === void 0 ? void 0 : (_aiLiveContext_context_keywords = _aiLiveContext_context1.keywords) === null || _aiLiveContext_context_keywords === void 0 ? void 0 : _aiLiveContext_context_keywords.length) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8368
+ style: {
8369
+ marginTop: "10px",
8370
+ display: "flex",
8371
+ flexWrap: "wrap",
8372
+ gap: "6px"
8373
+ },
8374
+ children: aiLiveContext.context.keywords.slice(0, 12).map(function(kw) {
8375
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8376
+ style: {
8377
+ fontSize: "10px",
8378
+ fontWeight: 600,
8379
+ padding: "4px 7px",
8380
+ borderRadius: "999px",
8381
+ background: "rgba(236, 72, 153, 0.2)",
8382
+ border: "1px solid rgba(244, 114, 182, 0.42)",
8383
+ color: "#fce7f3",
8384
+ maxWidth: "100%",
8385
+ overflow: "hidden",
8386
+ textOverflow: "ellipsis",
8387
+ whiteSpace: "nowrap"
8388
+ },
8389
+ title: kw,
8390
+ children: kw
8391
+ }, kw);
8392
+ })
8393
+ }) : null
8394
+ ]
8395
+ })
8396
+ ]
8397
+ })
8398
+ ]
8399
+ }),
8027
8400
  debugAdTiming && showDebugPanel && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8028
8401
  style: {
8029
8402
  position: "absolute",
8030
- right: "".concat(10 * responsiveScale, "px"),
8403
+ right: "".concat(debugPanelRightOffset, "px"),
8031
8404
  bottom: "".concat(debugPanelBottomOffset, "px"),
8032
- width: "".concat(Math.min(440, Math.max(320, viewportWidth * 0.42)), "px"),
8405
+ width: "".concat(analyzerPanelWidth, "px"),
8033
8406
  maxWidth: "92vw",
8034
- height: isPortrait ? "52vh" : "420px",
8035
- maxHeight: "58vh",
8407
+ height: analyzerPanelHeight,
8408
+ maxHeight: analyzerPanelMaxHeight,
8036
8409
  zIndex: 60,
8037
8410
  background: "rgba(10, 10, 10, 0.74)",
8038
8411
  border: "1px solid rgba(255, 255, 255, 0.14)",
@@ -8416,6 +8789,28 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8416
8789
  gap: "".concat(8 * responsiveScale, "px")
8417
8790
  },
8418
8791
  children: [
8792
+ swirlProjectId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8793
+ className: "sc-ctrl-btn",
8794
+ onClick: function onClick() {
8795
+ setShowAiPanel(function(prev) {
8796
+ return !prev;
8797
+ });
8798
+ resetControlsTimer();
8799
+ },
8800
+ style: {
8801
+ padding: "".concat(8 * responsiveScale, "px"),
8802
+ borderRadius: "50%",
8803
+ minWidth: "".concat(36 * responsiveScale, "px"),
8804
+ minHeight: "".concat(36 * responsiveScale, "px"),
8805
+ background: showAiPanel ? "rgba(236, 72, 153, 0.34)" : "transparent",
8806
+ fontFamily: "'SF Mono', 'Cascadia Code', monospace",
8807
+ fontSize: "".concat(12 * responsiveScale, "px"),
8808
+ fontWeight: 700,
8809
+ letterSpacing: "0.03em"
8810
+ },
8811
+ title: showAiPanel ? "Hide AI context" : "Show AI context",
8812
+ children: "AI"
8813
+ }),
8419
8814
  debugAdTiming && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8420
8815
  className: "sc-ctrl-btn",
8421
8816
  onClick: function onClick() {
@@ -8687,6 +9082,28 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8687
9082
  })
8688
9083
  ]
8689
9084
  }),
9085
+ swirlProjectId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
9086
+ className: "sc-ctrl-btn",
9087
+ onClick: function onClick() {
9088
+ setShowAiPanel(function(prev) {
9089
+ return !prev;
9090
+ });
9091
+ resetControlsTimer();
9092
+ },
9093
+ style: {
9094
+ padding: "".concat(8 * responsiveScale, "px"),
9095
+ borderRadius: "50%",
9096
+ minWidth: "".concat(36 * responsiveScale, "px"),
9097
+ minHeight: "".concat(36 * responsiveScale, "px"),
9098
+ background: showAiPanel ? "rgba(236, 72, 153, 0.34)" : "rgba(0, 0, 0, 0.6)",
9099
+ fontFamily: "'SF Mono', 'Cascadia Code', monospace",
9100
+ fontSize: "".concat(12 * responsiveScale, "px"),
9101
+ fontWeight: 700,
9102
+ letterSpacing: "0.03em"
9103
+ },
9104
+ title: showAiPanel ? "Hide AI context" : "Show AI context",
9105
+ children: "AI"
9106
+ }),
8690
9107
  debugAdTiming && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8691
9108
  className: "sc-ctrl-btn",
8692
9109
  onClick: function onClick() {