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.
@@ -5914,6 +5914,50 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5914
5914
  return min;
5915
5915
  }
5916
5916
  },
5917
+ {
5918
+ key: "getCurrentHlsSegmentDurationMs",
5919
+ value: function getCurrentHlsSegmentDurationMs() {
5920
+ var fallbackMs = 4e3;
5921
+ if (this.nativeHlsMode) {
5922
+ return fallbackMs;
5923
+ }
5924
+ var hls = this.hls;
5925
+ if (!hls) return null;
5926
+ var levelCandidates = [
5927
+ hls.currentLevel,
5928
+ hls.nextLoadLevel,
5929
+ hls.loadLevel
5930
+ ];
5931
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
5932
+ try {
5933
+ for(var _iterator = levelCandidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
5934
+ var levelIndex = _step.value;
5935
+ var _hls_levels_levelIndex, _hls_levels;
5936
+ if (typeof levelIndex !== "number" || levelIndex < 0) continue;
5937
+ 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;
5938
+ if (!details) continue;
5939
+ var targetDurationSec = typeof details.partTarget === "number" && details.partTarget > 0 ? details.partTarget : typeof details.targetduration === "number" && details.targetduration > 0 ? details.targetduration : void 0;
5940
+ if (targetDurationSec !== void 0) {
5941
+ return Math.max(800, Math.floor(targetDurationSec * 1e3));
5942
+ }
5943
+ }
5944
+ } catch (err) {
5945
+ _didIteratorError = true;
5946
+ _iteratorError = err;
5947
+ } finally{
5948
+ try {
5949
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
5950
+ _iterator.return();
5951
+ }
5952
+ } finally{
5953
+ if (_didIteratorError) {
5954
+ throw _iteratorError;
5955
+ }
5956
+ }
5957
+ }
5958
+ return fallbackMs;
5959
+ }
5960
+ },
5917
5961
  {
5918
5962
  key: "videoElement",
5919
5963
  get: function get() {
@@ -7090,7 +7134,12 @@ var CRITICAL_PROPS = [
7090
7134
  var CONTROLS_HIDE_DELAY = 3e3;
7091
7135
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
7092
7136
  var DEBUG_PANEL_MARKER_LIMIT = 12;
7137
+ var AI_CONTEXT_FALLBACK_POLL_MS = 4e3;
7138
+ var AI_CONTEXT_MIN_POLL_MS = 800;
7139
+ var PANEL_BASE_RIGHT_OFFSET = 10;
7093
7140
  var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props) {
7141
+ var _ref;
7142
+ var _aiLiveContext_context, _aiLiveContext_context_keywords, _aiLiveContext_context1;
7094
7143
  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, [
7095
7144
  "src",
7096
7145
  "autoplay",
@@ -7154,6 +7203,13 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7154
7203
  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];
7155
7204
  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];
7156
7205
  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];
7206
+ 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];
7207
+ var _import_react2_default_useState24 = _sliced_to_array(import_react2.default.useState({
7208
+ context: null,
7209
+ isLoading: false,
7210
+ error: null,
7211
+ lastPolledAt: null
7212
+ }), 2), aiLiveContext = _import_react2_default_useState24[0], setAiLiveContext = _import_react2_default_useState24[1];
7157
7213
  var getResponsiveScale = function getResponsiveScale() {
7158
7214
  if (viewportWidth < 480) return 0.7;
7159
7215
  if (viewportWidth < 768) return 0.8;
@@ -7183,6 +7239,18 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7183
7239
  if (typeof obj.splice_command_type === "number") return "binary splice";
7184
7240
  return "marker";
7185
7241
  };
7242
+ var formatAiRelativeTime = function formatAiRelativeTime(timestamp) {
7243
+ var epochMs = Date.parse(timestamp);
7244
+ if (!Number.isFinite(epochMs)) return "unknown";
7245
+ var diffSec = Math.max(0, Math.floor((Date.now() - epochMs) / 1e3));
7246
+ if (diffSec < 5) return "just now";
7247
+ if (diffSec < 60) return "".concat(diffSec, "s ago");
7248
+ var diffMin = Math.floor(diffSec / 60);
7249
+ if (diffMin < 60) return "".concat(diffMin, "m ago");
7250
+ var diffHr = Math.floor(diffMin / 60);
7251
+ if (diffHr < 24) return "".concat(diffHr, "h ago");
7252
+ return "".concat(Math.floor(diffHr / 24), "d ago");
7253
+ };
7186
7254
  var resetControlsTimer = (0, import_react2.useCallback)(function() {
7187
7255
  if (controlsTimerRef.current) {
7188
7256
  clearTimeout(controlsTimerRef.current);
@@ -7260,7 +7328,14 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7260
7328
  };
7261
7329
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
7262
7330
  var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
7331
+ var analyzerPanelWidth = Math.min(420, Math.max(320, viewportWidth * 0.41));
7332
+ var analyzerPanelHeight = isPortrait ? "52vh" : "420px";
7333
+ var analyzerPanelMaxHeight = "60vh";
7334
+ var panelGap = Math.max(8, 12 * responsiveScale);
7335
+ var shouldStackPanels = isPortrait || viewportWidth < 980;
7263
7336
  var debugPanelBottomOffset = shouldShowEnhancedControls ? Math.max(74, 92 * responsiveScale) : Math.max(52, 58 * responsiveScale);
7337
+ var panelBaseRight = PANEL_BASE_RIGHT_OFFSET * responsiveScale;
7338
+ var debugPanelRightOffset = showAiPanel && !shouldStackPanels ? panelBaseRight + analyzerPanelWidth + panelGap : panelBaseRight;
7264
7339
  var criticalPropsKey = (0, import_react2.useMemo)(function() {
7265
7340
  return CRITICAL_PROPS.map(function(prop) {
7266
7341
  return "".concat(prop, ":").concat(props[prop]);
@@ -7586,6 +7661,130 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7586
7661
  debugAdTiming,
7587
7662
  criticalPropsKey
7588
7663
  ]);
7664
+ (0, import_react2.useEffect)(function() {
7665
+ if (!swirlProjectId) {
7666
+ setShowAiPanel(false);
7667
+ setAiLiveContext({
7668
+ context: null,
7669
+ isLoading: false,
7670
+ error: null,
7671
+ lastPolledAt: null
7672
+ });
7673
+ }
7674
+ }, [
7675
+ swirlProjectId
7676
+ ]);
7677
+ (0, import_react2.useEffect)(function() {
7678
+ if (!showAiPanel || !swirlProjectId) return;
7679
+ var cancelled = false;
7680
+ var pollTimeoutId = null;
7681
+ var inFlight = false;
7682
+ var pollLiveContext = function pollLiveContext1() {
7683
+ return _async_to_generator(function() {
7684
+ var response, payload, error, message, _ref, _playerRef_current, segmentPollMs, nextPollMs;
7685
+ return _ts_generator(this, function(_state) {
7686
+ switch(_state.label){
7687
+ case 0:
7688
+ if (cancelled || inFlight) return [
7689
+ 2
7690
+ ];
7691
+ inFlight = true;
7692
+ setAiLiveContext(function(prev) {
7693
+ return _object_spread_props(_object_spread({}, prev), {
7694
+ isLoading: prev.context == null,
7695
+ error: null
7696
+ });
7697
+ });
7698
+ _state.label = 1;
7699
+ case 1:
7700
+ _state.trys.push([
7701
+ 1,
7702
+ 4,
7703
+ 5,
7704
+ 6
7705
+ ]);
7706
+ return [
7707
+ 4,
7708
+ fetch("https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/".concat(swirlProjectId, "/live-context"), {
7709
+ method: "GET",
7710
+ headers: {
7711
+ Accept: "application/json"
7712
+ }
7713
+ })
7714
+ ];
7715
+ case 2:
7716
+ response = _state.sent();
7717
+ if (!response.ok) {
7718
+ throw new Error("Live context request failed (".concat(response.status, " ").concat(response.statusText, ")"));
7719
+ }
7720
+ return [
7721
+ 4,
7722
+ response.json()
7723
+ ];
7724
+ case 3:
7725
+ payload = _state.sent();
7726
+ if (cancelled) return [
7727
+ 2
7728
+ ];
7729
+ setAiLiveContext({
7730
+ context: payload,
7731
+ isLoading: false,
7732
+ error: null,
7733
+ lastPolledAt: Date.now()
7734
+ });
7735
+ return [
7736
+ 3,
7737
+ 6
7738
+ ];
7739
+ case 4:
7740
+ error = _state.sent();
7741
+ if (cancelled) return [
7742
+ 2
7743
+ ];
7744
+ message = _instanceof(error, Error) ? error.message : "Unable to load AI live context.";
7745
+ setAiLiveContext(function(prev) {
7746
+ return _object_spread_props(_object_spread({}, prev), {
7747
+ isLoading: false,
7748
+ error: message,
7749
+ lastPolledAt: Date.now()
7750
+ });
7751
+ });
7752
+ return [
7753
+ 3,
7754
+ 6
7755
+ ];
7756
+ case 5:
7757
+ inFlight = false;
7758
+ if (!cancelled) {
7759
+ ;
7760
+ ;
7761
+ 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;
7762
+ nextPollMs = Math.max(AI_CONTEXT_MIN_POLL_MS, segmentPollMs);
7763
+ pollTimeoutId = window.setTimeout(pollLiveContext, nextPollMs);
7764
+ }
7765
+ return [
7766
+ 7
7767
+ ];
7768
+ case 6:
7769
+ return [
7770
+ 2
7771
+ ];
7772
+ }
7773
+ });
7774
+ })();
7775
+ };
7776
+ pollLiveContext();
7777
+ return function() {
7778
+ cancelled = true;
7779
+ if (pollTimeoutId != null) {
7780
+ clearTimeout(pollTimeoutId);
7781
+ }
7782
+ };
7783
+ }, [
7784
+ showAiPanel,
7785
+ swirlProjectId,
7786
+ criticalPropsKey
7787
+ ]);
7589
7788
  var handleWrapperMouseMove = (0, import_react2.useCallback)(function() {
7590
7789
  resetControlsTimer();
7591
7790
  }, [
@@ -7604,7 +7803,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7604
7803
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, {
7605
7804
  children: [
7606
7805
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", {
7607
- 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 "
7806
+ 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 "
7608
7807
  }),
7609
7808
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
7610
7809
  ref: wrapperRef,
@@ -7846,15 +8045,189 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7846
8045
  })
7847
8046
  ]
7848
8047
  }),
8048
+ showAiPanel && !showLicenseWarning && swirlProjectId && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8049
+ style: _object_spread_props(_object_spread({
8050
+ position: "absolute",
8051
+ right: "".concat(panelBaseRight, "px")
8052
+ }, shouldStackPanels && showDebugPanel ? {
8053
+ top: "".concat(12 * responsiveScale, "px")
8054
+ } : {
8055
+ bottom: "".concat(debugPanelBottomOffset, "px")
8056
+ }), {
8057
+ width: "".concat(analyzerPanelWidth, "px"),
8058
+ maxWidth: "92vw",
8059
+ height: analyzerPanelHeight,
8060
+ maxHeight: analyzerPanelMaxHeight,
8061
+ zIndex: 61,
8062
+ 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%)",
8063
+ border: "1px solid rgba(236, 72, 153, 0.35)",
8064
+ borderRadius: "14px",
8065
+ boxShadow: "0 18px 56px rgba(4, 7, 20, 0.58), inset 0 1px 0 rgba(255, 255, 255, 0.09)",
8066
+ backdropFilter: "blur(20px)",
8067
+ WebkitBackdropFilter: "blur(20px)",
8068
+ color: "rgba(255,255,255,0.96)",
8069
+ overflow: "hidden"
8070
+ }),
8071
+ children: [
8072
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8073
+ style: {
8074
+ display: "flex",
8075
+ alignItems: "center",
8076
+ justifyContent: "space-between",
8077
+ padding: "11px 13px",
8078
+ borderBottom: "1px solid rgba(255,255,255,0.12)",
8079
+ background: "linear-gradient(90deg, rgba(236, 72, 153, 0.2) 0%, rgba(168, 85, 247, 0.18) 100%)"
8080
+ },
8081
+ children: [
8082
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8083
+ children: [
8084
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8085
+ style: {
8086
+ fontSize: "13px",
8087
+ fontWeight: 800,
8088
+ letterSpacing: "0.02em"
8089
+ },
8090
+ children: "AI Live Context Analyzer"
8091
+ }),
8092
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8093
+ style: {
8094
+ marginTop: "2px",
8095
+ fontSize: "11px",
8096
+ color: "rgba(255,255,255,0.72)"
8097
+ },
8098
+ children: aiLiveContext.lastPolledAt ? "Updated ".concat(formatDebugClock(aiLiveContext.lastPolledAt)) : "Waiting for first sample..."
8099
+ })
8100
+ ]
8101
+ }),
8102
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8103
+ className: "sc-ctrl-btn",
8104
+ onClick: function onClick() {
8105
+ return setShowAiPanel(false);
8106
+ },
8107
+ style: {
8108
+ padding: "4px",
8109
+ borderRadius: "6px",
8110
+ minWidth: "26px",
8111
+ minHeight: "26px"
8112
+ },
8113
+ title: "Close AI panel",
8114
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fa.FaTimes, {
8115
+ size: 12
8116
+ })
8117
+ })
8118
+ ]
8119
+ }),
8120
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8121
+ className: "sc-ai-scroll",
8122
+ style: {
8123
+ padding: "12px",
8124
+ overflowY: "auto",
8125
+ overflowX: "hidden",
8126
+ height: "calc(100% - 52px)",
8127
+ display: "grid",
8128
+ gap: "12px"
8129
+ },
8130
+ children: [
8131
+ aiLiveContext.error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8132
+ style: {
8133
+ fontSize: "12px",
8134
+ color: "#fecaca",
8135
+ background: "rgba(220, 38, 38, 0.2)",
8136
+ border: "1px solid rgba(248, 113, 113, 0.5)",
8137
+ borderRadius: "10px",
8138
+ padding: "9px 10px"
8139
+ },
8140
+ children: aiLiveContext.error
8141
+ }),
8142
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8143
+ style: {
8144
+ padding: "11px 12px",
8145
+ borderRadius: "10px",
8146
+ border: "1px solid rgba(236, 72, 153, 0.5)",
8147
+ background: "linear-gradient(155deg, rgba(88, 28, 135, 0.35) 0%, rgba(17, 24, 39, 0.62) 100%)",
8148
+ boxShadow: "0 8px 24px rgba(236, 72, 153, 0.12)"
8149
+ },
8150
+ children: [
8151
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8152
+ style: {
8153
+ display: "flex",
8154
+ alignItems: "center",
8155
+ justifyContent: "space-between",
8156
+ gap: "8px",
8157
+ marginBottom: "7px"
8158
+ },
8159
+ children: [
8160
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8161
+ style: {
8162
+ fontSize: "11px",
8163
+ fontWeight: 800,
8164
+ textTransform: "uppercase",
8165
+ letterSpacing: "0.1em",
8166
+ color: "#f9a8d4"
8167
+ },
8168
+ children: "AI Context"
8169
+ }),
8170
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8171
+ style: {
8172
+ fontSize: "10px",
8173
+ color: "rgba(255,255,255,0.72)",
8174
+ fontFamily: "'SF Mono', 'Cascadia Code', monospace"
8175
+ },
8176
+ children: aiLiveContext.context ? formatAiRelativeTime(aiLiveContext.context.updated_at) : "--"
8177
+ })
8178
+ ]
8179
+ }),
8180
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8181
+ style: {
8182
+ fontSize: "13px",
8183
+ lineHeight: "1.58",
8184
+ color: "rgba(255,255,255,0.95)",
8185
+ whiteSpace: "pre-wrap"
8186
+ },
8187
+ 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."
8188
+ }),
8189
+ ((_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", {
8190
+ style: {
8191
+ marginTop: "10px",
8192
+ display: "flex",
8193
+ flexWrap: "wrap",
8194
+ gap: "6px"
8195
+ },
8196
+ children: aiLiveContext.context.keywords.slice(0, 12).map(function(kw) {
8197
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8198
+ style: {
8199
+ fontSize: "10px",
8200
+ fontWeight: 600,
8201
+ padding: "4px 7px",
8202
+ borderRadius: "999px",
8203
+ background: "rgba(236, 72, 153, 0.2)",
8204
+ border: "1px solid rgba(244, 114, 182, 0.42)",
8205
+ color: "#fce7f3",
8206
+ maxWidth: "100%",
8207
+ overflow: "hidden",
8208
+ textOverflow: "ellipsis",
8209
+ whiteSpace: "nowrap"
8210
+ },
8211
+ title: kw,
8212
+ children: kw
8213
+ }, kw);
8214
+ })
8215
+ }) : null
8216
+ ]
8217
+ })
8218
+ ]
8219
+ })
8220
+ ]
8221
+ }),
7849
8222
  debugAdTiming && showDebugPanel && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
7850
8223
  style: {
7851
8224
  position: "absolute",
7852
- right: "".concat(10 * responsiveScale, "px"),
8225
+ right: "".concat(debugPanelRightOffset, "px"),
7853
8226
  bottom: "".concat(debugPanelBottomOffset, "px"),
7854
- width: "".concat(Math.min(440, Math.max(320, viewportWidth * 0.42)), "px"),
8227
+ width: "".concat(analyzerPanelWidth, "px"),
7855
8228
  maxWidth: "92vw",
7856
- height: isPortrait ? "52vh" : "420px",
7857
- maxHeight: "58vh",
8229
+ height: analyzerPanelHeight,
8230
+ maxHeight: analyzerPanelMaxHeight,
7858
8231
  zIndex: 60,
7859
8232
  background: "rgba(10, 10, 10, 0.74)",
7860
8233
  border: "1px solid rgba(255, 255, 255, 0.14)",
@@ -8238,6 +8611,28 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8238
8611
  gap: "".concat(8 * responsiveScale, "px")
8239
8612
  },
8240
8613
  children: [
8614
+ swirlProjectId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8615
+ className: "sc-ctrl-btn",
8616
+ onClick: function onClick() {
8617
+ setShowAiPanel(function(prev) {
8618
+ return !prev;
8619
+ });
8620
+ resetControlsTimer();
8621
+ },
8622
+ style: {
8623
+ padding: "".concat(8 * responsiveScale, "px"),
8624
+ borderRadius: "50%",
8625
+ minWidth: "".concat(36 * responsiveScale, "px"),
8626
+ minHeight: "".concat(36 * responsiveScale, "px"),
8627
+ background: showAiPanel ? "rgba(236, 72, 153, 0.34)" : "transparent",
8628
+ fontFamily: "'SF Mono', 'Cascadia Code', monospace",
8629
+ fontSize: "".concat(12 * responsiveScale, "px"),
8630
+ fontWeight: 700,
8631
+ letterSpacing: "0.03em"
8632
+ },
8633
+ title: showAiPanel ? "Hide AI context" : "Show AI context",
8634
+ children: "AI"
8635
+ }),
8241
8636
  debugAdTiming && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8242
8637
  className: "sc-ctrl-btn",
8243
8638
  onClick: function onClick() {
@@ -8509,6 +8904,28 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8509
8904
  })
8510
8905
  ]
8511
8906
  }),
8907
+ swirlProjectId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8908
+ className: "sc-ctrl-btn",
8909
+ onClick: function onClick() {
8910
+ setShowAiPanel(function(prev) {
8911
+ return !prev;
8912
+ });
8913
+ resetControlsTimer();
8914
+ },
8915
+ style: {
8916
+ padding: "".concat(8 * responsiveScale, "px"),
8917
+ borderRadius: "50%",
8918
+ minWidth: "".concat(36 * responsiveScale, "px"),
8919
+ minHeight: "".concat(36 * responsiveScale, "px"),
8920
+ background: showAiPanel ? "rgba(236, 72, 153, 0.34)" : "rgba(0, 0, 0, 0.6)",
8921
+ fontFamily: "'SF Mono', 'Cascadia Code', monospace",
8922
+ fontSize: "".concat(12 * responsiveScale, "px"),
8923
+ fontWeight: 700,
8924
+ letterSpacing: "0.03em"
8925
+ },
8926
+ title: showAiPanel ? "Hide AI context" : "Show AI context",
8927
+ children: "AI"
8928
+ }),
8512
8929
  debugAdTiming && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8513
8930
  className: "sc-ctrl-btn",
8514
8931
  onClick: function onClick() {