stormcloud-video-player 0.7.0 → 0.7.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/ui/OverlayRenderer.cjs","../../src/ui/OverlayRenderer.tsx","../../src/utils/overlays.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","OverlayRenderer_exports","OverlayRenderer","module","exports","import_react","require","OVERLAY_API_BASE","timeStringToSeconds","timeStr","parts","split","length","hours","parseInt","minutes","secStr","dotIdx","indexOf","seconds","substring","msFrag","ms","padEnd","isFinite","num","Math","max","isOverlayActive","overlay","currentTime","visible","startSec","durationSec","start_time","duration","resolveImageUrl","imageUrl","apiBaseUrl","startsWith","url","URL","origin","import_jsx_runtime","nativeWidth","video","videoWidth","nativeHeight","videoHeight","displayWidth","offsetWidth","displayHeight","offsetHeight","videoAspect","displayAspect","renderWidth","renderHeight","offsetX","offsetY","scaleX","scaleY","ImageOverlay","src","image_url","jsx","alt","draggable","style","width","height","objectFit","display","pointerEvents","userSelect","TextOverlay","text","content","justifyContent","fontSize","fontFamily","fontWeight","textAlign","padding","boxSizing","wordBreak","textShadow","lineHeight","children","ScrollerOverlay","cfg","scroller_config","use_custom_text","custom_text","scrollSpeed","scroll_speed","direction","font_size","font_family","font_weight","textColor","text_color","bgColor","background_color","bgOpacity","background_opacity","borderColor","border_color","borderWidth","border_width","borderRadius","border_radius","isVertical","isReverse","animId","id","keyframes","jsxs","Fragment","overflow","alignItems","backgroundColor","hexToRgb","border","whiteSpace","color","animation","hex","clean","slice","replace","overlays","videoRef","coordinateSpace","useState","dims","setDims","rafRef","useRef","updateDims","useCallback","current","computed","computeVideoDimensions","prev"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/ui/OverlayRenderer.tsx\nvar OverlayRenderer_exports = {};\n__export(OverlayRenderer_exports, {\n OverlayRenderer: () => OverlayRenderer\n});\nmodule.exports = __toCommonJS(OverlayRenderer_exports);\nvar import_react = require(\"react\");\n\n// src/utils/overlays.ts\nvar OVERLAY_API_BASE = \"https://adstorm.co/api-adstorm-dev\";\nfunction timeStringToSeconds(timeStr) {\n if (!timeStr) return 0;\n const parts = timeStr.split(\":\");\n if (parts.length >= 3) {\n const hours = parseInt(parts[0] ?? \"0\", 10) || 0;\n const minutes = parseInt(parts[1] ?? \"0\", 10) || 0;\n const secStr = parts[2] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds = parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return hours * 3600 + minutes * 60 + seconds + ms / 1e3;\n }\n if (parts.length === 2) {\n const minutes = parseInt(parts[0] ?? \"0\", 10) || 0;\n const secStr = parts[1] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds = parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return minutes * 60 + seconds + ms / 1e3;\n }\n const num = parseFloat(timeStr);\n return isFinite(num) ? Math.max(0, num) : 0;\n}\nfunction isOverlayActive(overlay, currentTime) {\n if (!overlay.visible) return false;\n const startSec = timeStringToSeconds(overlay.start_time);\n const durationSec = timeStringToSeconds(overlay.duration);\n if (durationSec <= 0) return false;\n return currentTime >= startSec && currentTime < startSec + durationSec;\n}\nfunction resolveImageUrl(imageUrl, apiBaseUrl = OVERLAY_API_BASE) {\n if (!imageUrl) return \"\";\n if (imageUrl.startsWith(\"http://\") || imageUrl.startsWith(\"https://\")) {\n return imageUrl;\n }\n if (imageUrl.startsWith(\"/\")) {\n try {\n const url = new URL(apiBaseUrl);\n return `${url.origin}${imageUrl}`;\n } catch {\n return imageUrl;\n }\n }\n return `${apiBaseUrl}/${imageUrl}`;\n}\n\n// src/ui/OverlayRenderer.tsx\nvar import_jsx_runtime = require(\"react/jsx-runtime\");\nfunction computeVideoDimensions(video) {\n const nativeWidth = video.videoWidth;\n const nativeHeight = video.videoHeight;\n if (!nativeWidth || !nativeHeight) return null;\n const displayWidth = video.offsetWidth;\n const displayHeight = video.offsetHeight;\n if (!displayWidth || !displayHeight) return null;\n const videoAspect = nativeWidth / nativeHeight;\n const displayAspect = displayWidth / displayHeight;\n let renderWidth;\n let renderHeight;\n let offsetX;\n let offsetY;\n if (videoAspect > displayAspect) {\n renderWidth = displayWidth;\n renderHeight = displayWidth / videoAspect;\n offsetX = 0;\n offsetY = (displayHeight - renderHeight) / 2;\n } else {\n renderHeight = displayHeight;\n renderWidth = displayHeight * videoAspect;\n offsetX = (displayWidth - renderWidth) / 2;\n offsetY = 0;\n }\n return {\n nativeWidth,\n nativeHeight,\n displayWidth: renderWidth,\n displayHeight: renderHeight,\n offsetX,\n offsetY,\n scaleX: renderWidth / nativeWidth,\n scaleY: renderHeight / nativeHeight\n };\n}\nfunction ImageOverlay({ overlay }) {\n const src = resolveImageUrl(overlay.image_url || \"\");\n if (!src) return null;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"img\",\n {\n src,\n alt: overlay.name,\n draggable: false,\n style: {\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n pointerEvents: \"none\",\n userSelect: \"none\"\n }\n }\n );\n}\nfunction TextOverlay({ overlay }) {\n const text = overlay.content || \"\";\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n style: {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n fontSize: \"clamp(10px, 1.4vw, 20px)\",\n fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\",\n fontWeight: 600,\n textAlign: \"center\",\n padding: \"4px 8px\",\n boxSizing: \"border-box\",\n wordBreak: \"break-word\",\n textShadow: \"0 1px 4px rgba(0,0,0,0.7)\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n lineHeight: 1.3\n },\n children: text\n }\n );\n}\nfunction ScrollerOverlay({ overlay }) {\n const cfg = overlay.scroller_config;\n const text = cfg?.use_custom_text && cfg.custom_text ? cfg.custom_text : overlay.content || cfg?.custom_text || \"\";\n const scrollSpeed = cfg?.scroll_speed ?? 50;\n const direction = cfg?.direction ?? \"left\";\n const fontSize = cfg?.font_size ? `${cfg.font_size}px` : \"clamp(10px, 1.2vw, 18px)\";\n const fontFamily = cfg?.font_family || \"Roboto, 'Segoe UI', Arial, sans-serif\";\n const fontWeight = cfg?.font_weight || \"600\";\n const textColor = cfg?.text_color || \"#ffffff\";\n const bgColor = cfg?.background_color || \"transparent\";\n const bgOpacity = cfg?.background_opacity !== void 0 ? cfg.background_opacity / 100 : 0;\n const borderColor = cfg?.border_color || \"transparent\";\n const borderWidth = cfg?.border_width ?? 0;\n const borderRadius = cfg?.border_radius ?? 0;\n const padding = cfg?.padding ?? 4;\n const isVertical = direction === \"up\" || direction === \"down\";\n const isReverse = direction === \"right\" || direction === \"down\";\n const durationSec = Math.max(3, 120 - scrollSpeed);\n const animId = `sc-scroller-${overlay.id}`;\n const keyframes = isVertical ? `@keyframes ${animId} {\n 0% { transform: translateY(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateY(${isReverse ? \"100%\" : \"-100%\"}); }\n }` : `@keyframes ${animId} {\n 0% { transform: translateX(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateX(${isReverse ? \"100%\" : \"-100%\"}); }\n }`;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"style\", { children: keyframes }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n style: {\n width: \"100%\",\n height: \"100%\",\n overflow: \"hidden\",\n display: \"flex\",\n alignItems: \"center\",\n backgroundColor: bgOpacity > 0 ? `rgba(${hexToRgb(bgColor)}, ${bgOpacity})` : void 0,\n border: borderWidth > 0 ? `${borderWidth}px solid ${borderColor}` : void 0,\n borderRadius: borderRadius > 0 ? `${borderRadius}px` : void 0,\n padding: `${padding}px`,\n boxSizing: \"border-box\",\n pointerEvents: \"none\"\n },\n children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n style: {\n whiteSpace: \"nowrap\",\n fontSize,\n fontFamily,\n fontWeight,\n color: textColor,\n animation: `${animId} ${durationSec}s linear infinite`,\n textShadow: \"0 1px 4px rgba(0,0,0,0.5)\",\n userSelect: \"none\"\n },\n children: text\n }\n )\n }\n )\n ] });\n}\nfunction hexToRgb(hex) {\n if (!hex || !hex.startsWith(\"#\")) return \"0,0,0\";\n const clean = hex.slice(1);\n const num = parseInt(clean.length === 3 ? clean.replace(/./g, \"$&$&\") : clean, 16);\n return `${num >> 16 & 255},${num >> 8 & 255},${num & 255}`;\n}\nvar OverlayRenderer = ({\n overlays,\n currentTime,\n videoRef,\n coordinateSpace\n}) => {\n const [dims, setDims] = (0, import_react.useState)(null);\n const rafRef = (0, import_react.useRef)(null);\n const updateDims = (0, import_react.useCallback)(() => {\n const video = videoRef.current;\n if (video) {\n const computed = computeVideoDimensions(video);\n setDims((prev) => {\n if (!computed || prev && prev.nativeWidth === computed.nativeWidth && prev.nativeHeight === computed.nativeHeight && prev.displayWidth === computed.displayWidth && prev.displayHeight === computed.displayHeight && prev.offsetX === computed.offsetX && prev.offsetY === computed.offsetY) {\n return prev;\n }\n return computed;\n });\n }\n }, [videoRef]);\n (0, import_react.useEffect)(() => {\n updateDims();\n const interval = setInterval(updateDims, 500);\n const handleResize = () => {\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(updateDims);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => {\n clearInterval(interval);\n window.removeEventListener(\"resize\", handleResize);\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n };\n }, [updateDims]);\n const activeOverlays = overlays.filter(\n (o) => isOverlayActive(o, currentTime)\n );\n if (!dims || activeOverlays.length === 0) return null;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n \"aria-hidden\": \"true\",\n style: {\n position: \"absolute\",\n left: `${dims.offsetX}px`,\n top: `${dims.offsetY}px`,\n width: `${dims.displayWidth}px`,\n height: `${dims.displayHeight}px`,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n zIndex: 8\n },\n children: activeOverlays.map((overlay) => {\n const scaleX = coordinateSpace?.width ? dims.displayWidth / coordinateSpace.width : dims.scaleX;\n const scaleY = coordinateSpace?.height ? dims.displayHeight / coordinateSpace.height : dims.scaleY;\n const left = overlay.x * scaleX;\n const top = overlay.y * scaleY;\n const width = overlay.width * scaleX;\n const height = overlay.height * scaleY;\n const opacity = Math.max(0, Math.min(100, overlay.opacity)) / 100;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\n \"div\",\n {\n style: {\n position: \"absolute\",\n left: `${left}px`,\n top: `${top}px`,\n width: `${width}px`,\n height: `${height}px`,\n opacity,\n zIndex: overlay.z_index,\n overflow: \"hidden\"\n },\n children: [\n overlay.type === \"image\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageOverlay, { overlay }),\n overlay.type === \"text\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextOverlay, { overlay }),\n overlay.type === \"scroller\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollerOverlay, { overlay })\n ]\n },\n overlay.id\n );\n })\n }\n );\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n OverlayRenderer\n});\n","import React, { useEffect, useRef, useState, useCallback } from \"react\";\nimport {\n type SwirlOverlay,\n isOverlayActive,\n resolveImageUrl,\n} from \"../utils/overlays\";\n\ninterface VideoDimensions {\n nativeWidth: number;\n nativeHeight: number;\n displayWidth: number;\n displayHeight: number;\n offsetX: number;\n offsetY: number;\n scaleX: number;\n scaleY: number;\n}\n\ninterface OverlayRendererProps {\n overlays: SwirlOverlay[];\n currentTime: number;\n videoRef: React.RefObject<HTMLVideoElement | null>;\n coordinateSpace?: { width: number; height: number } | null;\n}\n\nfunction computeVideoDimensions(\n video: HTMLVideoElement\n): VideoDimensions | null {\n const nativeWidth = video.videoWidth;\n const nativeHeight = video.videoHeight;\n if (!nativeWidth || !nativeHeight) return null;\n\n const displayWidth = video.offsetWidth;\n const displayHeight = video.offsetHeight;\n if (!displayWidth || !displayHeight) return null;\n\n const videoAspect = nativeWidth / nativeHeight;\n const displayAspect = displayWidth / displayHeight;\n\n let renderWidth: number;\n let renderHeight: number;\n let offsetX: number;\n let offsetY: number;\n\n if (videoAspect > displayAspect) {\n renderWidth = displayWidth;\n renderHeight = displayWidth / videoAspect;\n offsetX = 0;\n offsetY = (displayHeight - renderHeight) / 2;\n } else {\n renderHeight = displayHeight;\n renderWidth = displayHeight * videoAspect;\n offsetX = (displayWidth - renderWidth) / 2;\n offsetY = 0;\n }\n\n return {\n nativeWidth,\n nativeHeight,\n displayWidth: renderWidth,\n displayHeight: renderHeight,\n offsetX,\n offsetY,\n scaleX: renderWidth / nativeWidth,\n scaleY: renderHeight / nativeHeight,\n };\n}\n\nfunction ImageOverlay({ overlay }: { overlay: SwirlOverlay }) {\n const src = resolveImageUrl(overlay.image_url || \"\");\n if (!src) return null;\n return (\n <img\n src={src}\n alt={overlay.name}\n draggable={false}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n }}\n />\n );\n}\n\nfunction TextOverlay({ overlay }: { overlay: SwirlOverlay }) {\n const text = overlay.content || \"\";\n return (\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n fontSize: \"clamp(10px, 1.4vw, 20px)\",\n fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\",\n fontWeight: 600,\n textAlign: \"center\",\n padding: \"4px 8px\",\n boxSizing: \"border-box\",\n wordBreak: \"break-word\",\n textShadow: \"0 1px 4px rgba(0,0,0,0.7)\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n lineHeight: 1.3,\n }}\n >\n {text}\n </div>\n );\n}\n\nfunction ScrollerOverlay({ overlay }: { overlay: SwirlOverlay }) {\n const cfg = overlay.scroller_config;\n const text =\n cfg?.use_custom_text && cfg.custom_text\n ? cfg.custom_text\n : overlay.content || cfg?.custom_text || \"\";\n\n const scrollSpeed = cfg?.scroll_speed ?? 50;\n const direction = cfg?.direction ?? \"left\";\n const fontSize = cfg?.font_size ? `${cfg.font_size}px` : \"clamp(10px, 1.2vw, 18px)\";\n const fontFamily = cfg?.font_family || \"Roboto, 'Segoe UI', Arial, sans-serif\";\n const fontWeight = cfg?.font_weight || \"600\";\n const textColor = cfg?.text_color || \"#ffffff\";\n const bgColor = cfg?.background_color || \"transparent\";\n const bgOpacity = cfg?.background_opacity !== undefined ? cfg.background_opacity / 100 : 0;\n const borderColor = cfg?.border_color || \"transparent\";\n const borderWidth = cfg?.border_width ?? 0;\n const borderRadius = cfg?.border_radius ?? 0;\n const padding = cfg?.padding ?? 4;\n\n const isVertical = direction === \"up\" || direction === \"down\";\n const isReverse = direction === \"right\" || direction === \"down\";\n\n const durationSec = Math.max(3, 120 - scrollSpeed);\n\n const animId = `sc-scroller-${overlay.id}`;\n const keyframes = isVertical\n ? `@keyframes ${animId} {\n 0% { transform: translateY(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateY(${isReverse ? \"100%\" : \"-100%\"}); }\n }`\n : `@keyframes ${animId} {\n 0% { transform: translateX(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateX(${isReverse ? \"100%\" : \"-100%\"}); }\n }`;\n\n return (\n <>\n <style>{keyframes}</style>\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n overflow: \"hidden\",\n display: \"flex\",\n alignItems: \"center\",\n backgroundColor:\n bgOpacity > 0\n ? `rgba(${hexToRgb(bgColor)}, ${bgOpacity})`\n : undefined,\n border:\n borderWidth > 0 ? `${borderWidth}px solid ${borderColor}` : undefined,\n borderRadius: borderRadius > 0 ? `${borderRadius}px` : undefined,\n padding: `${padding}px`,\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n whiteSpace: \"nowrap\",\n fontSize,\n fontFamily,\n fontWeight,\n color: textColor,\n animation: `${animId} ${durationSec}s linear infinite`,\n textShadow: \"0 1px 4px rgba(0,0,0,0.5)\",\n userSelect: \"none\",\n }}\n >\n {text}\n </div>\n </div>\n </>\n );\n}\n\nfunction hexToRgb(hex: string): string {\n if (!hex || !hex.startsWith(\"#\")) return \"0,0,0\";\n const clean = hex.slice(1);\n const num = parseInt(clean.length === 3 ? clean.replace(/./g, \"$&$&\") : clean, 16);\n return `${(num >> 16) & 255},${(num >> 8) & 255},${num & 255}`;\n}\n\nexport const OverlayRenderer: React.FC<OverlayRendererProps> = ({\n overlays,\n currentTime,\n videoRef,\n coordinateSpace,\n}) => {\n const [dims, setDims] = useState<VideoDimensions | null>(null);\n const rafRef = useRef<number | null>(null);\n\n const updateDims = useCallback(() => {\n const video = videoRef.current;\n if (video) {\n const computed = computeVideoDimensions(video);\n setDims((prev) => {\n if (\n !computed ||\n (prev &&\n prev.nativeWidth === computed.nativeWidth &&\n prev.nativeHeight === computed.nativeHeight &&\n prev.displayWidth === computed.displayWidth &&\n prev.displayHeight === computed.displayHeight &&\n prev.offsetX === computed.offsetX &&\n prev.offsetY === computed.offsetY)\n ) {\n return prev;\n }\n return computed;\n });\n }\n }, [videoRef]);\n\n useEffect(() => {\n updateDims();\n const interval = setInterval(updateDims, 500);\n\n const handleResize = () => {\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(updateDims);\n };\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n clearInterval(interval);\n window.removeEventListener(\"resize\", handleResize);\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n };\n }, [updateDims]);\n\n const activeOverlays = overlays.filter((o) =>\n isOverlayActive(o, currentTime)\n );\n\n if (!dims || activeOverlays.length === 0) return null;\n\n return (\n <div\n aria-hidden=\"true\"\n style={{\n position: \"absolute\",\n left: `${dims.offsetX}px`,\n top: `${dims.offsetY}px`,\n width: `${dims.displayWidth}px`,\n height: `${dims.displayHeight}px`,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n zIndex: 8,\n }}\n >\n {activeOverlays.map((overlay) => {\n const scaleX =\n coordinateSpace?.width\n ? dims.displayWidth / coordinateSpace.width\n : dims.scaleX;\n const scaleY =\n coordinateSpace?.height\n ? dims.displayHeight / coordinateSpace.height\n : dims.scaleY;\n const left = overlay.x * scaleX;\n const top = overlay.y * scaleY;\n const width = overlay.width * scaleX;\n const height = overlay.height * scaleY;\n const opacity = Math.max(0, Math.min(100, overlay.opacity)) / 100;\n\n return (\n <div\n key={overlay.id}\n style={{\n position: \"absolute\",\n left: `${left}px`,\n top: `${top}px`,\n width: `${width}px`,\n height: `${height}px`,\n opacity,\n zIndex: overlay.z_index,\n overflow: \"hidden\",\n }}\n >\n {overlay.type === \"image\" && (\n <ImageOverlay overlay={overlay} />\n )}\n {overlay.type === \"text\" && <TextOverlay overlay={overlay} />}\n {overlay.type === \"scroller\" && (\n <ScrollerOverlay overlay={overlay} />\n )}\n </div>\n );\n })}\n </div>\n );\n};\n","const OVERLAY_API_BASE = \"https://adstorm.co/api-adstorm-dev\";\n\nexport interface OverlayCoordinateSpace {\n width: number;\n height: number;\n}\n\nexport interface SwirlScrollerConfig {\n rss_url?: string;\n update_interval?: number;\n scroll_speed?: number;\n direction?: string;\n font_size?: number;\n font_family?: string;\n font_weight?: string;\n text_color?: string;\n background_color?: string;\n background_opacity?: number;\n border_color?: string;\n border_width?: number;\n border_radius?: number;\n padding?: number;\n margin?: number;\n show_title?: boolean;\n show_description?: boolean;\n show_timestamp?: boolean;\n show_author?: boolean;\n show_category?: boolean;\n max_items?: number;\n item_spacing?: number;\n fade_in_out?: boolean;\n fade_distance?: number;\n auto_refresh?: boolean;\n use_custom_text?: boolean;\n custom_text?: string;\n}\n\nexport interface SwirlOverlay {\n id: number;\n project_id: number;\n name: string;\n type: \"image\" | \"text\" | \"scroller\" | string;\n visible: boolean;\n x: number;\n y: number;\n width: number;\n height: number;\n opacity: number;\n start_time: string;\n duration: string;\n content?: string;\n image_url?: string;\n scroller_config?: SwirlScrollerConfig;\n z_index: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport function timeStringToSeconds(timeStr: string): number {\n if (!timeStr) return 0;\n\n const parts = timeStr.split(\":\");\n\n if (parts.length >= 3) {\n const hours = parseInt(parts[0] ?? \"0\", 10) || 0;\n const minutes = parseInt(parts[1] ?? \"0\", 10) || 0;\n const secStr = parts[2] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds =\n parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return hours * 3600 + minutes * 60 + seconds + ms / 1000;\n }\n\n if (parts.length === 2) {\n const minutes = parseInt(parts[0] ?? \"0\", 10) || 0;\n const secStr = parts[1] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds =\n parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return minutes * 60 + seconds + ms / 1000;\n }\n\n const num = parseFloat(timeStr);\n return isFinite(num) ? Math.max(0, num) : 0;\n}\n\nexport function isOverlayActive(\n overlay: SwirlOverlay,\n currentTime: number\n): boolean {\n if (!overlay.visible) return false;\n const startSec = timeStringToSeconds(overlay.start_time);\n const durationSec = timeStringToSeconds(overlay.duration);\n if (durationSec <= 0) return false;\n return currentTime >= startSec && currentTime < startSec + durationSec;\n}\n\nexport async function fetchProjectOverlays(\n projectId: number,\n apiBaseUrl: string = OVERLAY_API_BASE\n): Promise<SwirlOverlay[]> {\n const response = await fetch(\n `${apiBaseUrl}/adstorm/swirl/projects/${projectId}/overlays`\n );\n if (!response.ok) {\n throw new Error(\n `Failed to fetch overlays: ${response.status} ${response.statusText}`\n );\n }\n const data = await response.json();\n return Array.isArray(data) ? data : [];\n}\n\nexport function resolveImageUrl(\n imageUrl: string,\n apiBaseUrl: string = OVERLAY_API_BASE\n): string {\n if (!imageUrl) return \"\";\n if (imageUrl.startsWith(\"http://\") || imageUrl.startsWith(\"https://\")) {\n return imageUrl;\n }\n if (imageUrl.startsWith(\"/\")) {\n try {\n const url = new URL(apiBaseUrl);\n return `${url.origin}${imageUrl}`;\n } catch {\n return imageUrl;\n }\n }\n return `${apiBaseUrl}/${imageUrl}`;\n}\n"]}
1
+ {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/ui/OverlayRenderer.cjs","../../src/ui/OverlayRenderer.tsx","../../src/utils/overlays.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropNames","__getOwnPropDesc","getOwnPropertyDescriptor","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","OverlayRenderer_exports","OverlayRenderer","module","exports","import_react","require","OVERLAY_API_BASE","timeStringToSeconds","timeStr","parts","split","length","hours","parseInt","minutes","secStr","dotIdx","seconds","indexOf","substring","msFrag","ms","padEnd","num","parseFloat","isFinite","Math","max","isOverlayActive","overlay","visible","currentTime","startSec","start_time","durationSec","duration","resolveImageUrl","imageUrl","apiBaseUrl","startsWith","url","URL","origin","import_jsx_runtime","computeVideoDimensions","video","nativeWidth","videoWidth","nativeHeight","videoHeight","displayWidth","offsetWidth","displayHeight","offsetHeight","videoAspect","displayAspect","renderWidth","renderHeight","offsetX","offsetY","scaleX","scaleY","ImageOverlay","src","image_url","jsx","alt","draggable","style","width","height","objectFit","display","pointerEvents","userSelect","TextOverlay","text","content","justifyContent","color","fontSize","fontFamily","fontWeight","textAlign","padding","boxSizing","wordBreak","textShadow","lineHeight","children","ScrollerOverlay","cfg","scroller_config","use_custom_text","custom_text","scrollSpeed","scroll_speed","direction","font_size","font_family","font_weight","textColor","text_color","bgColor","background_color","bgOpacity","background_opacity","borderColor","border_color","borderWidth","border_width","borderRadius","border_radius","isVertical","isReverse","animId","id","keyframes","jsxs","Fragment","overflow","alignItems","backgroundColor","hexToRgb","border","whiteSpace","animation","parseConfig","JSON","parse","ScoreBugOverlay","size","f","w","flexDirection","background","flex","gap","homeTeam","homeScore","opacity","period","clock","awayTeam","awayScore","sponsorText","borderTop","accentColor","LowerThirdOverlay","h","headline","marginTop","subtitle","QrCodeOverlay"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n // If the importer is in node compatibility mode or this is not an ESM\n // file that has been converted to a CommonJS file using a Babel-\n // compatible transform (i.e. \"__esModule\" has not been set), then set\n // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n mod\n));\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/ui/OverlayRenderer.tsx\nvar OverlayRenderer_exports = {};\n__export(OverlayRenderer_exports, {\n OverlayRenderer: () => OverlayRenderer\n});\nmodule.exports = __toCommonJS(OverlayRenderer_exports);\nvar import_react = __toESM(require(\"react\"), 1);\n\n// src/utils/overlays.ts\nvar OVERLAY_API_BASE = \"https://adstorm.co/api-adstorm-dev\";\nfunction timeStringToSeconds(timeStr) {\n if (!timeStr) return 0;\n const parts = timeStr.split(\":\");\n if (parts.length >= 3) {\n const hours = parseInt(parts[0] ?? \"0\", 10) || 0;\n const minutes = parseInt(parts[1] ?? \"0\", 10) || 0;\n const secStr = parts[2] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds = parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return hours * 3600 + minutes * 60 + seconds + ms / 1e3;\n }\n if (parts.length === 2) {\n const minutes = parseInt(parts[0] ?? \"0\", 10) || 0;\n const secStr = parts[1] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds = parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return minutes * 60 + seconds + ms / 1e3;\n }\n const num = parseFloat(timeStr);\n return isFinite(num) ? Math.max(0, num) : 0;\n}\nfunction isOverlayActive(overlay, currentTime) {\n if (!overlay.visible) return false;\n const startSec = timeStringToSeconds(overlay.start_time);\n const durationSec = timeStringToSeconds(overlay.duration);\n if (durationSec <= 0) return false;\n return currentTime >= startSec && currentTime < startSec + durationSec;\n}\nfunction resolveImageUrl(imageUrl, apiBaseUrl = OVERLAY_API_BASE) {\n if (!imageUrl) return \"\";\n if (imageUrl.startsWith(\"http://\") || imageUrl.startsWith(\"https://\")) {\n return imageUrl;\n }\n if (imageUrl.startsWith(\"/\")) {\n try {\n const url = new URL(apiBaseUrl);\n return `${url.origin}${imageUrl}`;\n } catch {\n return imageUrl;\n }\n }\n return `${apiBaseUrl}/${imageUrl}`;\n}\n\n// src/ui/OverlayRenderer.tsx\nvar import_jsx_runtime = require(\"react/jsx-runtime\");\nfunction computeVideoDimensions(video) {\n const nativeWidth = video.videoWidth;\n const nativeHeight = video.videoHeight;\n if (!nativeWidth || !nativeHeight) return null;\n const displayWidth = video.offsetWidth;\n const displayHeight = video.offsetHeight;\n if (!displayWidth || !displayHeight) return null;\n const videoAspect = nativeWidth / nativeHeight;\n const displayAspect = displayWidth / displayHeight;\n let renderWidth;\n let renderHeight;\n let offsetX;\n let offsetY;\n if (videoAspect > displayAspect) {\n renderWidth = displayWidth;\n renderHeight = displayWidth / videoAspect;\n offsetX = 0;\n offsetY = (displayHeight - renderHeight) / 2;\n } else {\n renderHeight = displayHeight;\n renderWidth = displayHeight * videoAspect;\n offsetX = (displayWidth - renderWidth) / 2;\n offsetY = 0;\n }\n return {\n nativeWidth,\n nativeHeight,\n displayWidth: renderWidth,\n displayHeight: renderHeight,\n offsetX,\n offsetY,\n scaleX: renderWidth / nativeWidth,\n scaleY: renderHeight / nativeHeight\n };\n}\nfunction ImageOverlay({ overlay }) {\n const src = resolveImageUrl(overlay.image_url || \"\");\n if (!src) return null;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"img\",\n {\n src,\n alt: overlay.name,\n draggable: false,\n style: {\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n pointerEvents: \"none\",\n userSelect: \"none\"\n }\n }\n );\n}\nfunction TextOverlay({ overlay }) {\n const text = overlay.content || \"\";\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n style: {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n fontSize: \"clamp(10px, 1.4vw, 20px)\",\n fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\",\n fontWeight: 600,\n textAlign: \"center\",\n padding: \"4px 8px\",\n boxSizing: \"border-box\",\n wordBreak: \"break-word\",\n textShadow: \"0 1px 4px rgba(0,0,0,0.7)\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n lineHeight: 1.3\n },\n children: text\n }\n );\n}\nfunction ScrollerOverlay({ overlay }) {\n const cfg = overlay.scroller_config;\n const text = cfg?.use_custom_text && cfg.custom_text ? cfg.custom_text : overlay.content || cfg?.custom_text || \"\";\n const scrollSpeed = cfg?.scroll_speed ?? 50;\n const direction = cfg?.direction ?? \"left\";\n const fontSize = cfg?.font_size ? `${cfg.font_size}px` : \"clamp(10px, 1.2vw, 18px)\";\n const fontFamily = cfg?.font_family || \"Roboto, 'Segoe UI', Arial, sans-serif\";\n const fontWeight = cfg?.font_weight || \"600\";\n const textColor = cfg?.text_color || \"#ffffff\";\n const bgColor = cfg?.background_color || \"transparent\";\n const bgOpacity = cfg?.background_opacity !== void 0 ? cfg.background_opacity / 100 : 0;\n const borderColor = cfg?.border_color || \"transparent\";\n const borderWidth = cfg?.border_width ?? 0;\n const borderRadius = cfg?.border_radius ?? 0;\n const padding = cfg?.padding ?? 4;\n const isVertical = direction === \"up\" || direction === \"down\";\n const isReverse = direction === \"right\" || direction === \"down\";\n const durationSec = Math.max(3, 120 - scrollSpeed);\n const animId = `sc-scroller-${overlay.id}`;\n const keyframes = isVertical ? `@keyframes ${animId} {\n 0% { transform: translateY(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateY(${isReverse ? \"100%\" : \"-100%\"}); }\n }` : `@keyframes ${animId} {\n 0% { transform: translateX(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateX(${isReverse ? \"100%\" : \"-100%\"}); }\n }`;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"style\", { children: keyframes }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n style: {\n width: \"100%\",\n height: \"100%\",\n overflow: \"hidden\",\n display: \"flex\",\n alignItems: \"center\",\n backgroundColor: bgOpacity > 0 ? `rgba(${hexToRgb(bgColor)}, ${bgOpacity})` : void 0,\n border: borderWidth > 0 ? `${borderWidth}px solid ${borderColor}` : void 0,\n borderRadius: borderRadius > 0 ? `${borderRadius}px` : void 0,\n padding: `${padding}px`,\n boxSizing: \"border-box\",\n pointerEvents: \"none\"\n },\n children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n style: {\n whiteSpace: \"nowrap\",\n fontSize,\n fontFamily,\n fontWeight,\n color: textColor,\n animation: `${animId} ${durationSec}s linear infinite`,\n textShadow: \"0 1px 4px rgba(0,0,0,0.5)\",\n userSelect: \"none\"\n },\n children: text\n }\n )\n }\n )\n ] });\n}\nfunction parseConfig(content) {\n if (!content) return null;\n try {\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\nfunction ScoreBugOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.058);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, display: \"flex\", alignItems: \"center\", padding: `0 ${f * 0.8}px`, gap: f * 0.4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, textAlign: \"center\" }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1em\", fontWeight: 700 }, children: cfg.homeTeam }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.8em\", fontWeight: 900, lineHeight: 1 }, children: cfg.homeScore })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { fontSize: \"0.8em\", textAlign: \"center\", opacity: 0.7, padding: `0 ${f * 0.4}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { children: cfg.period }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { children: cfg.clock })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, textAlign: \"center\" }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1em\", fontWeight: 700 }, children: cfg.awayTeam }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.8em\", fontWeight: 900, lineHeight: 1 }, children: cfg.awayScore })\n ] })\n ] }),\n cfg.sponsorText && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.7em\", textAlign: \"center\", opacity: 0.5, padding: `${f * 0.2}px 0`, borderTop: `1px solid ${cfg.accentColor}40` }, children: cfg.sponsorText })\n ] });\n}\nfunction LowerThirdOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.055);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.02), display: \"flex\", flexDirection: \"column\", justifyContent: \"flex-end\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { width: \"100%\", height: Math.max(2, size.h * 0.06), backgroundColor: cfg.accentColor } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, display: \"flex\", flexDirection: \"column\", justifyContent: \"center\", padding: `${f * 0.5}px ${f * 1.2}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.4em\", fontWeight: 700, lineHeight: 1.2, textShadow: \"0 1px 4px rgba(0,0,0,0.5)\" }, children: cfg.headline }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1em\", opacity: 0.7, marginTop: f * 0.2 }, children: cfg.subtitle })\n ] }),\n cfg.sponsorText && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.7em\", opacity: 0.4, padding: `0 ${f * 1.2}px ${f * 0.4}px` }, children: cfg.sponsorText })\n ] });\n}\nfunction QrCodeOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const qrSide = Math.max(32, Math.min(size.w, size.h) * 0.55);\n const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${Math.round(qrSide * 2)}x${Math.round(qrSide * 2)}&data=${encodeURIComponent(cfg.url || \"https://example.com\")}`;\n const f = Math.max(6, size.w * 0.06);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", gap: f * 0.4, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", padding: f * 0.6, boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", overflow: \"hidden\" }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { flexShrink: 0, background: \"#fff\", borderRadius: Math.max(2, qrSide * 0.06), padding: Math.max(2, qrSide * 0.06), lineHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"img\", { src: qrUrl, alt: \"QR Code\", style: { width: `${qrSide}px`, height: `${qrSide}px`, display: \"block\" } }) }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: `${f * 1.1}px`, fontWeight: 700, textAlign: \"center\", color: cfg.accentColor, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", width: \"100%\" }, children: cfg.ctaText }),\n cfg.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: `${f * 0.75}px`, opacity: 0.6, textAlign: \"center\", overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", width: \"100%\" }, children: cfg.description })\n ] });\n}\nfunction ComingUpNextOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.05);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { width: Math.max(2, size.w * 0.015), flexShrink: 0, backgroundColor: cfg.accentColor } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, display: \"flex\", flexDirection: \"column\", justifyContent: \"center\", padding: `${f * 0.6}px ${f * 1}px`, minWidth: 0 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.8em\", fontWeight: 600, textTransform: \"uppercase\", letterSpacing: \"0.05em\", color: cfg.accentColor }, children: \"Coming Up Next\" }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.5em\", fontWeight: 700, lineHeight: 1.2, marginTop: f * 0.2, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }, children: cfg.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.9em\", opacity: 0.6, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }, children: cfg.subtitle }),\n cfg.scheduledTime && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1em\", fontWeight: 600, marginTop: f * 0.4, color: cfg.accentColor }, children: cfg.scheduledTime })\n ] })\n ] });\n}\nfunction ContextualTriggerOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const icons = { alert: \"\\u26A0\\uFE0F\", celebration: \"\\u{1F389}\", info: \"\\u2139\\uFE0F\", warning: \"\\u{1F514}\" };\n const f = Math.max(6, size.w * 0.05);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", alignItems: \"center\", gap: f * 0.8, padding: `0 ${f * 1.2}px`, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", borderLeft: `${Math.max(2, size.w * 0.02)}px solid ${cfg.accentColor}`, boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"span\", { style: { fontSize: \"2em\", flexShrink: 0 }, children: icons[cfg.iconType] || \"\\u26A1\" }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, minWidth: 0 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.3em\", fontWeight: 700, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }, children: cfg.headline }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.9em\", opacity: 0.7, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }, children: cfg.message })\n ] })\n ] });\n}\nfunction OddsBettingOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.052);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", padding: f * 0.8, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.9em\", fontWeight: 700, textTransform: \"uppercase\", letterSpacing: \"0.05em\", color: cfg.accentColor, marginBottom: f * 0.4 }, children: cfg.eventTitle }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { flex: 1, display: \"flex\", flexDirection: \"column\", gap: f * 0.2, justifyContent: \"center\" }, children: (cfg.options || []).slice(0, 5).map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", padding: `${f * 0.2}px ${f * 0.6}px`, borderRadius: Math.max(2, f * 0.3), background: `${cfg.accentColor}15`, fontSize: \"1em\" }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"span\", { style: { overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1 }, children: opt.label }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"span\", { style: { fontWeight: 700, marginLeft: f * 0.8, flexShrink: 0, color: cfg.accentColor }, children: opt.odds })\n ] }, i)) }),\n cfg.sponsorText && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.7em\", opacity: 0.4, textAlign: \"center\", marginTop: f * 0.4 }, children: cfg.sponsorText })\n ] });\n}\nfunction BreakingNewsOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n if (!cfg) return null;\n const urgencyColors = { breaking: \"#dc2626\", urgent: \"#ea580c\", normal: \"#2563eb\" };\n const labelBg = urgencyColors[cfg.urgency] || urgencyColors.normal;\n const label = cfg.urgency === \"breaking\" ? \"BREAKING\" : cfg.urgency === \"urgent\" ? \"URGENT\" : \"NEWS\";\n const f = Math.max(6, size.w * 0.05);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.02), display: \"flex\", alignItems: \"center\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { padding: `0 ${f * 0.8}px`, height: \"100%\", display: \"flex\", alignItems: \"center\", background: labelBg, color: \"#fff\", fontSize: \"1em\", fontWeight: 900, textTransform: \"uppercase\", letterSpacing: \"0.05em\", flexShrink: 0 }, children: label }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { flex: 1, padding: `0 ${f * 1}px`, minWidth: 0 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.3em\", fontWeight: 700, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }, children: cfg.headline }),\n cfg.body && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.9em\", opacity: 0.7, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }, children: cfg.body })\n ] })\n ] });\n}\nfunction CountdownOverlay({ overlay, size }) {\n const cfg = parseConfig(overlay.content);\n const [remaining, setRemaining] = (0, import_react.useState)({ d: 0, h: 0, m: 0, s: 0 });\n (0, import_react.useEffect)(() => {\n if (!cfg) return;\n const update = () => {\n const target = new Date(cfg.targetTime).getTime();\n const now = Date.now();\n const diff = Math.max(0, target - now);\n setRemaining({\n d: Math.floor(diff / 864e5),\n h: Math.floor(diff % 864e5 / 36e5),\n m: Math.floor(diff % 36e5 / 6e4),\n s: Math.floor(diff % 6e4 / 1e3)\n });\n };\n update();\n const id = setInterval(update, 1e3);\n return () => clearInterval(id);\n }, [cfg?.targetTime]);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.055);\n const pad = (n) => String(n).padStart(2, \"0\");\n const units = [\n { show: cfg.showDays, value: pad(remaining.d), label: \"DAYS\" },\n { show: cfg.showHours, value: pad(remaining.h), label: \"HRS\" },\n { show: cfg.showMinutes, value: pad(remaining.m), label: \"MIN\" },\n { show: cfg.showSeconds, value: pad(remaining.s), label: \"SEC\" }\n ];\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", padding: f * 0.8, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.8em\", fontWeight: 600, textTransform: \"uppercase\", letterSpacing: \"0.05em\", color: cfg.accentColor, marginBottom: f * 0.4 }, children: cfg.eventName }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { display: \"flex\", gap: f * 0.6, alignItems: \"center\" }, children: units.filter((u) => u.show).map((u, i, arr) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\"div\", { style: { textAlign: \"center\" }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"2em\", fontWeight: 900, lineHeight: 1, borderRadius: Math.max(2, f * 0.4), padding: `${f * 0.2}px ${f * 0.4}px`, background: `${cfg.accentColor}20` }, children: u.value }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.5em\", opacity: 0.5, marginTop: f * 0.2 }, children: u.label })\n ] }),\n i < arr.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"1.8em\", fontWeight: 700, opacity: 0.3 }, children: \":\" })\n ] }, u.label)) }),\n cfg.message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: \"0.8em\", opacity: 0.6, marginTop: f * 0.4, textAlign: \"center\" }, children: cfg.message })\n ] });\n}\nfunction ShapeOverlay({ overlay, size }) {\n const f = Math.max(6, size.w * 0.05);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.03), background: \"rgba(99, 102, 241, 0.2)\", border: \"2px solid rgba(99, 102, 241, 0.4)\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", pointerEvents: \"none\", userSelect: \"none\" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\"div\", { style: { fontSize: `${f}px`, fontWeight: 500, color: \"rgba(163, 163, 163, 0.8)\", textTransform: \"uppercase\" }, children: overlay.name }) });\n}\nfunction hexToRgb(hex) {\n if (!hex || !hex.startsWith(\"#\")) return \"0,0,0\";\n const clean = hex.slice(1);\n const num = parseInt(clean.length === 3 ? clean.replace(/./g, \"$&$&\") : clean, 16);\n return `${num >> 16 & 255},${num >> 8 & 255},${num & 255}`;\n}\nvar OverlayRenderer = ({\n overlays,\n currentTime,\n videoRef,\n coordinateSpace\n}) => {\n const [dims, setDims] = (0, import_react.useState)(null);\n const rafRef = (0, import_react.useRef)(null);\n const updateDims = (0, import_react.useCallback)(() => {\n const video = videoRef.current;\n if (video) {\n const computed = computeVideoDimensions(video);\n setDims((prev) => {\n if (!computed || prev && prev.nativeWidth === computed.nativeWidth && prev.nativeHeight === computed.nativeHeight && prev.displayWidth === computed.displayWidth && prev.displayHeight === computed.displayHeight && prev.offsetX === computed.offsetX && prev.offsetY === computed.offsetY) {\n return prev;\n }\n return computed;\n });\n }\n }, [videoRef]);\n (0, import_react.useEffect)(() => {\n updateDims();\n const interval = setInterval(updateDims, 500);\n const handleResize = () => {\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(updateDims);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => {\n clearInterval(interval);\n window.removeEventListener(\"resize\", handleResize);\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n };\n }, [updateDims]);\n const activeOverlays = overlays.filter(\n (o) => isOverlayActive(o, currentTime)\n );\n if (!dims || activeOverlays.length === 0) return null;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n \"div\",\n {\n \"aria-hidden\": \"true\",\n style: {\n position: \"absolute\",\n left: `${dims.offsetX}px`,\n top: `${dims.offsetY}px`,\n width: `${dims.displayWidth}px`,\n height: `${dims.displayHeight}px`,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n zIndex: 8\n },\n children: activeOverlays.map((overlay) => {\n const scaleX = coordinateSpace?.width ? dims.displayWidth / coordinateSpace.width : dims.scaleX;\n const scaleY = coordinateSpace?.height ? dims.displayHeight / coordinateSpace.height : dims.scaleY;\n const left = overlay.x * scaleX;\n const top = overlay.y * scaleY;\n const width = overlay.width * scaleX;\n const height = overlay.height * scaleY;\n const opacity = Math.max(0, Math.min(100, overlay.opacity)) / 100;\n const sz = { w: width, h: height };\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(\n \"div\",\n {\n style: {\n position: \"absolute\",\n left: `${left}px`,\n top: `${top}px`,\n width: `${width}px`,\n height: `${height}px`,\n opacity,\n zIndex: overlay.z_index,\n overflow: \"hidden\"\n },\n children: [\n overlay.type === \"image\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageOverlay, { overlay }),\n overlay.type === \"text\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextOverlay, { overlay }),\n overlay.type === \"scroller\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollerOverlay, { overlay }),\n overlay.type === \"shape\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShapeOverlay, { overlay, size: sz }),\n overlay.type === \"score_bug\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScoreBugOverlay, { overlay, size: sz }),\n overlay.type === \"lower_third\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LowerThirdOverlay, { overlay, size: sz }),\n overlay.type === \"qr_code\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(QrCodeOverlay, { overlay, size: sz }),\n overlay.type === \"coming_up_next\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComingUpNextOverlay, { overlay, size: sz }),\n overlay.type === \"contextual_trigger\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextualTriggerOverlay, { overlay, size: sz }),\n overlay.type === \"odds_betting\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OddsBettingOverlay, { overlay, size: sz }),\n overlay.type === \"breaking_news\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BreakingNewsOverlay, { overlay, size: sz }),\n overlay.type === \"countdown\" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountdownOverlay, { overlay, size: sz })\n ]\n },\n overlay.id\n );\n })\n }\n );\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n OverlayRenderer\n});\n","import React, { useEffect, useRef, useState, useCallback } from \"react\";\nimport {\n type SwirlOverlay,\n isOverlayActive,\n resolveImageUrl,\n} from \"../utils/overlays\";\n\ninterface VideoDimensions {\n nativeWidth: number;\n nativeHeight: number;\n displayWidth: number;\n displayHeight: number;\n offsetX: number;\n offsetY: number;\n scaleX: number;\n scaleY: number;\n}\n\ninterface OverlayRendererProps {\n overlays: SwirlOverlay[];\n currentTime: number;\n videoRef: React.RefObject<HTMLVideoElement | null>;\n coordinateSpace?: { width: number; height: number } | null;\n}\n\nfunction computeVideoDimensions(\n video: HTMLVideoElement\n): VideoDimensions | null {\n const nativeWidth = video.videoWidth;\n const nativeHeight = video.videoHeight;\n if (!nativeWidth || !nativeHeight) return null;\n\n const displayWidth = video.offsetWidth;\n const displayHeight = video.offsetHeight;\n if (!displayWidth || !displayHeight) return null;\n\n const videoAspect = nativeWidth / nativeHeight;\n const displayAspect = displayWidth / displayHeight;\n\n let renderWidth: number;\n let renderHeight: number;\n let offsetX: number;\n let offsetY: number;\n\n if (videoAspect > displayAspect) {\n renderWidth = displayWidth;\n renderHeight = displayWidth / videoAspect;\n offsetX = 0;\n offsetY = (displayHeight - renderHeight) / 2;\n } else {\n renderHeight = displayHeight;\n renderWidth = displayHeight * videoAspect;\n offsetX = (displayWidth - renderWidth) / 2;\n offsetY = 0;\n }\n\n return {\n nativeWidth,\n nativeHeight,\n displayWidth: renderWidth,\n displayHeight: renderHeight,\n offsetX,\n offsetY,\n scaleX: renderWidth / nativeWidth,\n scaleY: renderHeight / nativeHeight,\n };\n}\n\nfunction ImageOverlay({ overlay }: { overlay: SwirlOverlay }) {\n const src = resolveImageUrl(overlay.image_url || \"\");\n if (!src) return null;\n return (\n <img\n src={src}\n alt={overlay.name}\n draggable={false}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n }}\n />\n );\n}\n\nfunction TextOverlay({ overlay }: { overlay: SwirlOverlay }) {\n const text = overlay.content || \"\";\n return (\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n fontSize: \"clamp(10px, 1.4vw, 20px)\",\n fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\",\n fontWeight: 600,\n textAlign: \"center\",\n padding: \"4px 8px\",\n boxSizing: \"border-box\",\n wordBreak: \"break-word\",\n textShadow: \"0 1px 4px rgba(0,0,0,0.7)\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n lineHeight: 1.3,\n }}\n >\n {text}\n </div>\n );\n}\n\nfunction ScrollerOverlay({ overlay }: { overlay: SwirlOverlay }) {\n const cfg = overlay.scroller_config;\n const text =\n cfg?.use_custom_text && cfg.custom_text\n ? cfg.custom_text\n : overlay.content || cfg?.custom_text || \"\";\n\n const scrollSpeed = cfg?.scroll_speed ?? 50;\n const direction = cfg?.direction ?? \"left\";\n const fontSize = cfg?.font_size ? `${cfg.font_size}px` : \"clamp(10px, 1.2vw, 18px)\";\n const fontFamily = cfg?.font_family || \"Roboto, 'Segoe UI', Arial, sans-serif\";\n const fontWeight = cfg?.font_weight || \"600\";\n const textColor = cfg?.text_color || \"#ffffff\";\n const bgColor = cfg?.background_color || \"transparent\";\n const bgOpacity = cfg?.background_opacity !== undefined ? cfg.background_opacity / 100 : 0;\n const borderColor = cfg?.border_color || \"transparent\";\n const borderWidth = cfg?.border_width ?? 0;\n const borderRadius = cfg?.border_radius ?? 0;\n const padding = cfg?.padding ?? 4;\n\n const isVertical = direction === \"up\" || direction === \"down\";\n const isReverse = direction === \"right\" || direction === \"down\";\n\n const durationSec = Math.max(3, 120 - scrollSpeed);\n\n const animId = `sc-scroller-${overlay.id}`;\n const keyframes = isVertical\n ? `@keyframes ${animId} {\n 0% { transform: translateY(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateY(${isReverse ? \"100%\" : \"-100%\"}); }\n }`\n : `@keyframes ${animId} {\n 0% { transform: translateX(${isReverse ? \"-100%\" : \"100%\"}); }\n 100% { transform: translateX(${isReverse ? \"100%\" : \"-100%\"}); }\n }`;\n\n return (\n <>\n <style>{keyframes}</style>\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n overflow: \"hidden\",\n display: \"flex\",\n alignItems: \"center\",\n backgroundColor:\n bgOpacity > 0\n ? `rgba(${hexToRgb(bgColor)}, ${bgOpacity})`\n : undefined,\n border:\n borderWidth > 0 ? `${borderWidth}px solid ${borderColor}` : undefined,\n borderRadius: borderRadius > 0 ? `${borderRadius}px` : undefined,\n padding: `${padding}px`,\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n whiteSpace: \"nowrap\",\n fontSize,\n fontFamily,\n fontWeight,\n color: textColor,\n animation: `${animId} ${durationSec}s linear infinite`,\n textShadow: \"0 1px 4px rgba(0,0,0,0.5)\",\n userSelect: \"none\",\n }}\n >\n {text}\n </div>\n </div>\n </>\n );\n}\n\nfunction parseConfig<T>(content?: string): T | null {\n if (!content) return null;\n try { return JSON.parse(content) as T; } catch { return null; }\n}\n\ninterface OverlaySize { w: number; h: number; }\n\ninterface ScoreBugCfg { homeTeam: string; awayTeam: string; homeScore: number; awayScore: number; period: string; clock: string; sponsorText: string; sponsorImageUrl: string; backgroundColor: string; textColor: string; accentColor: string; }\ninterface LowerThirdCfg { headline: string; subtitle: string; sponsorText: string; sponsorImageUrl: string; backgroundColor: string; textColor: string; accentColor: string; style: string; }\ninterface QrCodeCfg { url: string; ctaText: string; description: string; size: number; backgroundColor: string; textColor: string; accentColor: string; }\ninterface ComingUpNextCfg { title: string; subtitle: string; scheduledTime: string; thumbnailUrl: string; backgroundColor: string; textColor: string; accentColor: string; }\ninterface ContextualTriggerCfg { triggerType: string; headline: string; message: string; iconType: string; backgroundColor: string; textColor: string; accentColor: string; animationStyle: string; }\ninterface OddsBettingCfg { eventTitle: string; options: Array<{ label: string; odds: string }>; sponsorText: string; backgroundColor: string; textColor: string; accentColor: string; oddsFormat: string; }\ninterface BreakingNewsCfg { headline: string; body: string; urgency: string; backgroundColor: string; textColor: string; accentColor: string; }\ninterface CountdownCfg { eventName: string; targetTime: string; message: string; showDays: boolean; showHours: boolean; showMinutes: boolean; showSeconds: boolean; backgroundColor: string; textColor: string; accentColor: string; }\n\nfunction ScoreBugOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<ScoreBugCfg>(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.058);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <div style={{ flex: 1, display: \"flex\", alignItems: \"center\", padding: `0 ${f * 0.8}px`, gap: f * 0.4 }}>\n <div style={{ flex: 1, textAlign: \"center\" }}>\n <div style={{ fontSize: \"1em\", fontWeight: 700 }}>{cfg.homeTeam}</div>\n <div style={{ fontSize: \"1.8em\", fontWeight: 900, lineHeight: 1 }}>{cfg.homeScore}</div>\n </div>\n <div style={{ fontSize: \"0.8em\", textAlign: \"center\", opacity: 0.7, padding: `0 ${f * 0.4}px` }}>\n <div>{cfg.period}</div>\n <div>{cfg.clock}</div>\n </div>\n <div style={{ flex: 1, textAlign: \"center\" }}>\n <div style={{ fontSize: \"1em\", fontWeight: 700 }}>{cfg.awayTeam}</div>\n <div style={{ fontSize: \"1.8em\", fontWeight: 900, lineHeight: 1 }}>{cfg.awayScore}</div>\n </div>\n </div>\n {cfg.sponsorText && (\n <div style={{ fontSize: \"0.7em\", textAlign: \"center\", opacity: 0.5, padding: `${f * 0.2}px 0`, borderTop: `1px solid ${cfg.accentColor}40` }}>{cfg.sponsorText}</div>\n )}\n </div>\n );\n}\n\nfunction LowerThirdOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<LowerThirdCfg>(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.055);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.02), display: \"flex\", flexDirection: \"column\", justifyContent: \"flex-end\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <div style={{ width: \"100%\", height: Math.max(2, size.h * 0.06), backgroundColor: cfg.accentColor }} />\n <div style={{ flex: 1, display: \"flex\", flexDirection: \"column\", justifyContent: \"center\", padding: `${f * 0.5}px ${f * 1.2}px` }}>\n <div style={{ fontSize: \"1.4em\", fontWeight: 700, lineHeight: 1.2, textShadow: \"0 1px 4px rgba(0,0,0,0.5)\" }}>{cfg.headline}</div>\n <div style={{ fontSize: \"1em\", opacity: 0.7, marginTop: f * 0.2 }}>{cfg.subtitle}</div>\n </div>\n {cfg.sponsorText && (\n <div style={{ fontSize: \"0.7em\", opacity: 0.4, padding: `0 ${f * 1.2}px ${f * 0.4}px` }}>{cfg.sponsorText}</div>\n )}\n </div>\n );\n}\n\nfunction QrCodeOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<QrCodeCfg>(overlay.content);\n if (!cfg) return null;\n const qrSide = Math.max(32, Math.min(size.w, size.h) * 0.55);\n const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${Math.round(qrSide * 2)}x${Math.round(qrSide * 2)}&data=${encodeURIComponent(cfg.url || \"https://example.com\")}`;\n const f = Math.max(6, size.w * 0.06);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", gap: f * 0.4, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", padding: f * 0.6, boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", overflow: \"hidden\" }}>\n <div style={{ flexShrink: 0, background: \"#fff\", borderRadius: Math.max(2, qrSide * 0.06), padding: Math.max(2, qrSide * 0.06), lineHeight: 0 }}>\n <img src={qrUrl} alt=\"QR Code\" style={{ width: `${qrSide}px`, height: `${qrSide}px`, display: \"block\" }} />\n </div>\n <div style={{ fontSize: `${f * 1.1}px`, fontWeight: 700, textAlign: \"center\", color: cfg.accentColor, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", width: \"100%\" }}>{cfg.ctaText}</div>\n {cfg.description && <div style={{ fontSize: `${f * 0.75}px`, opacity: 0.6, textAlign: \"center\", overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", width: \"100%\" }}>{cfg.description}</div>}\n </div>\n );\n}\n\nfunction ComingUpNextOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<ComingUpNextCfg>(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.05);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <div style={{ width: Math.max(2, size.w * 0.015), flexShrink: 0, backgroundColor: cfg.accentColor }} />\n <div style={{ flex: 1, display: \"flex\", flexDirection: \"column\", justifyContent: \"center\", padding: `${f * 0.6}px ${f * 1.0}px`, minWidth: 0 }}>\n <div style={{ fontSize: \"0.8em\", fontWeight: 600, textTransform: \"uppercase\", letterSpacing: \"0.05em\", color: cfg.accentColor }}>Coming Up Next</div>\n <div style={{ fontSize: \"1.5em\", fontWeight: 700, lineHeight: 1.2, marginTop: f * 0.2, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{cfg.title}</div>\n <div style={{ fontSize: \"0.9em\", opacity: 0.6, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{cfg.subtitle}</div>\n {cfg.scheduledTime && <div style={{ fontSize: \"1em\", fontWeight: 600, marginTop: f * 0.4, color: cfg.accentColor }}>{cfg.scheduledTime}</div>}\n </div>\n </div>\n );\n}\n\nfunction ContextualTriggerOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<ContextualTriggerCfg>(overlay.content);\n if (!cfg) return null;\n const icons: Record<string, string> = { alert: \"\\u26A0\\uFE0F\", celebration: \"\\uD83C\\uDF89\", info: \"\\u2139\\uFE0F\", warning: \"\\uD83D\\uDD14\" };\n const f = Math.max(6, size.w * 0.05);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", alignItems: \"center\", gap: f * 0.8, padding: `0 ${f * 1.2}px`, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", borderLeft: `${Math.max(2, size.w * 0.02)}px solid ${cfg.accentColor}`, boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <span style={{ fontSize: \"2em\", flexShrink: 0 }}>{icons[cfg.iconType] || \"\\u26A1\"}</span>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontSize: \"1.3em\", fontWeight: 700, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{cfg.headline}</div>\n <div style={{ fontSize: \"0.9em\", opacity: 0.7, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{cfg.message}</div>\n </div>\n </div>\n );\n}\n\nfunction OddsBettingOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<OddsBettingCfg>(overlay.content);\n if (!cfg) return null;\n const f = Math.max(6, size.w * 0.052);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", padding: f * 0.8, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <div style={{ fontSize: \"0.9em\", fontWeight: 700, textTransform: \"uppercase\", letterSpacing: \"0.05em\", color: cfg.accentColor, marginBottom: f * 0.4 }}>{cfg.eventTitle}</div>\n <div style={{ flex: 1, display: \"flex\", flexDirection: \"column\", gap: f * 0.2, justifyContent: \"center\" }}>\n {(cfg.options || []).slice(0, 5).map((opt, i) => (\n <div key={i} style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", padding: `${f * 0.2}px ${f * 0.6}px`, borderRadius: Math.max(2, f * 0.3), background: `${cfg.accentColor}15`, fontSize: \"1em\" }}>\n <span style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1 }}>{opt.label}</span>\n <span style={{ fontWeight: 700, marginLeft: f * 0.8, flexShrink: 0, color: cfg.accentColor }}>{opt.odds}</span>\n </div>\n ))}\n </div>\n {cfg.sponsorText && <div style={{ fontSize: \"0.7em\", opacity: 0.4, textAlign: \"center\", marginTop: f * 0.4 }}>{cfg.sponsorText}</div>}\n </div>\n );\n}\n\nfunction BreakingNewsOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<BreakingNewsCfg>(overlay.content);\n if (!cfg) return null;\n const urgencyColors: Record<string, string> = { breaking: \"#dc2626\", urgent: \"#ea580c\", normal: \"#2563eb\" };\n const labelBg = urgencyColors[cfg.urgency] || urgencyColors.normal;\n const label = cfg.urgency === \"breaking\" ? \"BREAKING\" : cfg.urgency === \"urgent\" ? \"URGENT\" : \"NEWS\";\n const f = Math.max(6, size.w * 0.05);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.02), display: \"flex\", alignItems: \"center\", background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", overflow: \"hidden\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <div style={{ padding: `0 ${f * 0.8}px`, height: \"100%\", display: \"flex\", alignItems: \"center\", background: labelBg, color: \"#fff\", fontSize: \"1em\", fontWeight: 900, textTransform: \"uppercase\", letterSpacing: \"0.05em\", flexShrink: 0 }}>{label}</div>\n <div style={{ flex: 1, padding: `0 ${f * 1.0}px`, minWidth: 0 }}>\n <div style={{ fontSize: \"1.3em\", fontWeight: 700, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{cfg.headline}</div>\n {cfg.body && <div style={{ fontSize: \"0.9em\", opacity: 0.7, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{cfg.body}</div>}\n </div>\n </div>\n );\n}\n\nfunction CountdownOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const cfg = parseConfig<CountdownCfg>(overlay.content);\n const [remaining, setRemaining] = useState({ d: 0, h: 0, m: 0, s: 0 });\n\n useEffect(() => {\n if (!cfg) return;\n const update = () => {\n const target = new Date(cfg.targetTime).getTime();\n const now = Date.now();\n const diff = Math.max(0, target - now);\n setRemaining({\n d: Math.floor(diff / 86400000),\n h: Math.floor((diff % 86400000) / 3600000),\n m: Math.floor((diff % 3600000) / 60000),\n s: Math.floor((diff % 60000) / 1000),\n });\n };\n update();\n const id = setInterval(update, 1000);\n return () => clearInterval(id);\n }, [cfg?.targetTime]);\n\n if (!cfg) return null;\n\n const f = Math.max(6, size.w * 0.055);\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const units: Array<{ show: boolean; value: string; label: string }> = [\n { show: cfg.showDays, value: pad(remaining.d), label: \"DAYS\" },\n { show: cfg.showHours, value: pad(remaining.h), label: \"HRS\" },\n { show: cfg.showMinutes, value: pad(remaining.m), label: \"MIN\" },\n { show: cfg.showSeconds, value: pad(remaining.s), label: \"SEC\" },\n ];\n\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.035), display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", padding: f * 0.8, background: cfg.backgroundColor, color: cfg.textColor, fontFamily: \"Roboto, 'Segoe UI', Arial, sans-serif\", boxSizing: \"border-box\", pointerEvents: \"none\", userSelect: \"none\", fontSize: `${f}px` }}>\n <div style={{ fontSize: \"0.8em\", fontWeight: 600, textTransform: \"uppercase\", letterSpacing: \"0.05em\", color: cfg.accentColor, marginBottom: f * 0.4 }}>{cfg.eventName}</div>\n <div style={{ display: \"flex\", gap: f * 0.6, alignItems: \"center\" }}>\n {units.filter(u => u.show).map((u, i, arr) => (\n <React.Fragment key={u.label}>\n <div style={{ textAlign: \"center\" }}>\n <div style={{ fontSize: \"2em\", fontWeight: 900, lineHeight: 1, borderRadius: Math.max(2, f * 0.4), padding: `${f * 0.2}px ${f * 0.4}px`, background: `${cfg.accentColor}20` }}>{u.value}</div>\n <div style={{ fontSize: \"0.5em\", opacity: 0.5, marginTop: f * 0.2 }}>{u.label}</div>\n </div>\n {i < arr.length - 1 && <div style={{ fontSize: \"1.8em\", fontWeight: 700, opacity: 0.3 }}>:</div>}\n </React.Fragment>\n ))}\n </div>\n {cfg.message && <div style={{ fontSize: \"0.8em\", opacity: 0.6, marginTop: f * 0.4, textAlign: \"center\" }}>{cfg.message}</div>}\n </div>\n );\n}\n\nfunction ShapeOverlay({ overlay, size }: { overlay: SwirlOverlay; size: OverlaySize }) {\n const f = Math.max(6, size.w * 0.05);\n return (\n <div style={{ width: \"100%\", height: \"100%\", borderRadius: Math.max(2, size.w * 0.03), background: \"rgba(99, 102, 241, 0.2)\", border: \"2px solid rgba(99, 102, 241, 0.4)\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", pointerEvents: \"none\", userSelect: \"none\" }}>\n <div style={{ fontSize: `${f}px`, fontWeight: 500, color: \"rgba(163, 163, 163, 0.8)\", textTransform: \"uppercase\" }}>{overlay.name}</div>\n </div>\n );\n}\n\nfunction hexToRgb(hex: string): string {\n if (!hex || !hex.startsWith(\"#\")) return \"0,0,0\";\n const clean = hex.slice(1);\n const num = parseInt(clean.length === 3 ? clean.replace(/./g, \"$&$&\") : clean, 16);\n return `${(num >> 16) & 255},${(num >> 8) & 255},${num & 255}`;\n}\n\nexport const OverlayRenderer: React.FC<OverlayRendererProps> = ({\n overlays,\n currentTime,\n videoRef,\n coordinateSpace,\n}) => {\n const [dims, setDims] = useState<VideoDimensions | null>(null);\n const rafRef = useRef<number | null>(null);\n\n const updateDims = useCallback(() => {\n const video = videoRef.current;\n if (video) {\n const computed = computeVideoDimensions(video);\n setDims((prev) => {\n if (\n !computed ||\n (prev &&\n prev.nativeWidth === computed.nativeWidth &&\n prev.nativeHeight === computed.nativeHeight &&\n prev.displayWidth === computed.displayWidth &&\n prev.displayHeight === computed.displayHeight &&\n prev.offsetX === computed.offsetX &&\n prev.offsetY === computed.offsetY)\n ) {\n return prev;\n }\n return computed;\n });\n }\n }, [videoRef]);\n\n useEffect(() => {\n updateDims();\n const interval = setInterval(updateDims, 500);\n\n const handleResize = () => {\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(updateDims);\n };\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n clearInterval(interval);\n window.removeEventListener(\"resize\", handleResize);\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n };\n }, [updateDims]);\n\n const activeOverlays = overlays.filter((o) =>\n isOverlayActive(o, currentTime)\n );\n\n if (!dims || activeOverlays.length === 0) return null;\n\n return (\n <div\n aria-hidden=\"true\"\n style={{\n position: \"absolute\",\n left: `${dims.offsetX}px`,\n top: `${dims.offsetY}px`,\n width: `${dims.displayWidth}px`,\n height: `${dims.displayHeight}px`,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n zIndex: 8,\n }}\n >\n {activeOverlays.map((overlay) => {\n const scaleX =\n coordinateSpace?.width\n ? dims.displayWidth / coordinateSpace.width\n : dims.scaleX;\n const scaleY =\n coordinateSpace?.height\n ? dims.displayHeight / coordinateSpace.height\n : dims.scaleY;\n const left = overlay.x * scaleX;\n const top = overlay.y * scaleY;\n const width = overlay.width * scaleX;\n const height = overlay.height * scaleY;\n const opacity = Math.max(0, Math.min(100, overlay.opacity)) / 100;\n const sz: OverlaySize = { w: width, h: height };\n\n return (\n <div\n key={overlay.id}\n style={{\n position: \"absolute\",\n left: `${left}px`,\n top: `${top}px`,\n width: `${width}px`,\n height: `${height}px`,\n opacity,\n zIndex: overlay.z_index,\n overflow: \"hidden\",\n }}\n >\n {overlay.type === \"image\" && <ImageOverlay overlay={overlay} />}\n {overlay.type === \"text\" && <TextOverlay overlay={overlay} />}\n {overlay.type === \"scroller\" && <ScrollerOverlay overlay={overlay} />}\n {overlay.type === \"shape\" && <ShapeOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"score_bug\" && <ScoreBugOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"lower_third\" && <LowerThirdOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"qr_code\" && <QrCodeOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"coming_up_next\" && <ComingUpNextOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"contextual_trigger\" && <ContextualTriggerOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"odds_betting\" && <OddsBettingOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"breaking_news\" && <BreakingNewsOverlay overlay={overlay} size={sz} />}\n {overlay.type === \"countdown\" && <CountdownOverlay overlay={overlay} size={sz} />}\n </div>\n );\n })}\n </div>\n );\n};\n","const OVERLAY_API_BASE = \"https://adstorm.co/api-adstorm-dev\";\n\nexport interface OverlayCoordinateSpace {\n width: number;\n height: number;\n}\n\nexport interface SwirlScrollerConfig {\n rss_url?: string;\n update_interval?: number;\n scroll_speed?: number;\n direction?: string;\n font_size?: number;\n font_family?: string;\n font_weight?: string;\n text_color?: string;\n background_color?: string;\n background_opacity?: number;\n border_color?: string;\n border_width?: number;\n border_radius?: number;\n padding?: number;\n margin?: number;\n show_title?: boolean;\n show_description?: boolean;\n show_timestamp?: boolean;\n show_author?: boolean;\n show_category?: boolean;\n max_items?: number;\n item_spacing?: number;\n fade_in_out?: boolean;\n fade_distance?: number;\n auto_refresh?: boolean;\n use_custom_text?: boolean;\n custom_text?: string;\n}\n\nexport type SwirlOverlayType =\n | \"image\"\n | \"text\"\n | \"scroller\"\n | \"shape\"\n | \"score_bug\"\n | \"lower_third\"\n | \"qr_code\"\n | \"coming_up_next\"\n | \"contextual_trigger\"\n | \"odds_betting\"\n | \"breaking_news\"\n | \"countdown\";\n\nexport interface SwirlOverlay {\n id: number;\n project_id: number;\n name: string;\n type: SwirlOverlayType | string;\n visible: boolean;\n x: number;\n y: number;\n width: number;\n height: number;\n opacity: number;\n start_time: string;\n duration: string;\n content?: string;\n image_url?: string;\n scroller_config?: SwirlScrollerConfig;\n z_index: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport function timeStringToSeconds(timeStr: string): number {\n if (!timeStr) return 0;\n\n const parts = timeStr.split(\":\");\n\n if (parts.length >= 3) {\n const hours = parseInt(parts[0] ?? \"0\", 10) || 0;\n const minutes = parseInt(parts[1] ?? \"0\", 10) || 0;\n const secStr = parts[2] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds =\n parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return hours * 3600 + minutes * 60 + seconds + ms / 1000;\n }\n\n if (parts.length === 2) {\n const minutes = parseInt(parts[0] ?? \"0\", 10) || 0;\n const secStr = parts[1] ?? \"0\";\n const dotIdx = secStr.indexOf(\".\");\n const seconds =\n parseInt(dotIdx >= 0 ? secStr.substring(0, dotIdx) : secStr, 10) || 0;\n const msFrag = dotIdx >= 0 ? secStr.substring(dotIdx + 1) : \"\";\n const ms = msFrag ? parseInt(msFrag.padEnd(3, \"0\").substring(0, 3), 10) || 0 : 0;\n return minutes * 60 + seconds + ms / 1000;\n }\n\n const num = parseFloat(timeStr);\n return isFinite(num) ? Math.max(0, num) : 0;\n}\n\nexport function isOverlayActive(\n overlay: SwirlOverlay,\n currentTime: number\n): boolean {\n if (!overlay.visible) return false;\n const startSec = timeStringToSeconds(overlay.start_time);\n const durationSec = timeStringToSeconds(overlay.duration);\n if (durationSec <= 0) return false;\n return currentTime >= startSec && currentTime < startSec + durationSec;\n}\n\nexport async function fetchProjectOverlays(\n projectId: number,\n apiBaseUrl: string = OVERLAY_API_BASE\n): Promise<SwirlOverlay[]> {\n const response = await fetch(\n `${apiBaseUrl}/adstorm/swirl/projects/${projectId}/overlays`\n );\n if (!response.ok) {\n throw new Error(\n `Failed to fetch overlays: ${response.status} ${response.statusText}`\n );\n }\n const data = await response.json();\n return Array.isArray(data) ? data : [];\n}\n\nexport function resolveImageUrl(\n imageUrl: string,\n apiBaseUrl: string = OVERLAY_API_BASE\n): string {\n if (!imageUrl) return \"\";\n if (imageUrl.startsWith(\"http://\") || imageUrl.startsWith(\"https://\")) {\n return imageUrl;\n }\n if (imageUrl.startsWith(\"/\")) {\n try {\n const url = new URL(apiBaseUrl);\n return `${url.origin}${imageUrl}`;\n } catch {\n return imageUrl;\n }\n }\n return `${apiBaseUrl}/${imageUrl}`;\n}\n"]}