boss-web-player-sdk 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +340 -0
- package/dist/boss-web-player-sdk.css +2 -0
- package/dist/core.cjs +2 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.ts +482 -0
- package/dist/core.js +16 -0
- package/dist/core.js.map +1 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +693 -0
- package/dist/index.js +2827 -0
- package/dist/index.js.map +1 -0
- package/dist/src-4MqtK4Qy.js +19626 -0
- package/dist/src-4MqtK4Qy.js.map +1 -0
- package/dist/src-kY7Z_lKn.cjs +49 -0
- package/dist/src-kY7Z_lKn.cjs.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode"],"sources":["../../ui-controls/src/ErrorScreen.tsx","../../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs","../../../node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs","../../../node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs","../../../node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs","../../../node_modules/lucide-react/dist/esm/defaultAttributes.mjs","../../../node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs","../../../node_modules/lucide-react/dist/esm/context.mjs","../../../node_modules/lucide-react/dist/esm/Icon.mjs","../../../node_modules/lucide-react/dist/esm/createLucideIcon.mjs","../../../node_modules/lucide-react/dist/esm/icons/airplay.mjs","../../../node_modules/lucide-react/dist/esm/icons/captions.mjs","../../../node_modules/lucide-react/dist/esm/icons/cast.mjs","../../../node_modules/lucide-react/dist/esm/icons/check.mjs","../../../node_modules/lucide-react/dist/esm/icons/chevron-left.mjs","../../../node_modules/lucide-react/dist/esm/icons/gauge.mjs","../../../node_modules/lucide-react/dist/esm/icons/languages.mjs","../../../node_modules/lucide-react/dist/esm/icons/list-video.mjs","../../../node_modules/lucide-react/dist/esm/icons/maximize.mjs","../../../node_modules/lucide-react/dist/esm/icons/minimize.mjs","../../../node_modules/lucide-react/dist/esm/icons/pause.mjs","../../../node_modules/lucide-react/dist/esm/icons/picture-in-picture.mjs","../../../node_modules/lucide-react/dist/esm/icons/play.mjs","../../../node_modules/lucide-react/dist/esm/icons/rotate-ccw.mjs","../../../node_modules/lucide-react/dist/esm/icons/rotate-cw.mjs","../../../node_modules/lucide-react/dist/esm/icons/signal.mjs","../../../node_modules/lucide-react/dist/esm/icons/volume-1.mjs","../../../node_modules/lucide-react/dist/esm/icons/volume-2.mjs","../../../node_modules/lucide-react/dist/esm/icons/volume-x.mjs","../../../node_modules/lucide-react/dist/esm/icons/volume.mjs","../../ui-controls/src/WebVideoPlayer.tsx","../src/api.ts","../src/BossVideoPlayer.tsx","../src/create-player.ts"],"sourcesContent":["interface ErrorScreenProps {\r\n title?: string;\r\n subtitle?: string;\r\n onRetry: () => void;\r\n}\r\n\r\nexport function ErrorScreen({\r\n title = 'Something Went Wrong',\r\n subtitle = 'We encountered an error while playing this video.\\nPlease try again.',\r\n onRetry,\r\n}: ErrorScreenProps) {\r\n return (\r\n <>\r\n <div style={{\r\n width: 80, height: 80, borderRadius: '50%',\r\n background: 'rgba(255,255,255,0.08)',\r\n display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,\r\n }}>\r\n <svg width=\"36\" height=\"36\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"rgba(255,255,255,0.85)\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/>\r\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\r\n </svg>\r\n </div>\r\n <div style={{ textAlign: 'center', padding: '0 24px' }}>\r\n <p style={{ color: '#ffffff', fontSize: 22, fontWeight: 700, margin: '0 0 8px', letterSpacing: '-0.2px' }}>\r\n {title}\r\n </p>\r\n <p style={{ color: 'rgba(255,255,255,0.5)', fontSize: 14, margin: 0, lineHeight: 1.6, whiteSpace: 'pre-line' }}>\r\n {subtitle}\r\n </p>\r\n </div>\r\n <button\r\n onClick={onRetry}\r\n style={{\r\n display: 'flex', alignItems: 'center', gap: 10,\r\n background: '#ffffff', color: '#09090e',\r\n border: 'none', borderRadius: 10, padding: '14px 32px',\r\n fontSize: 16, fontWeight: 700, cursor: 'pointer', letterSpacing: '-0.1px',\r\n }}\r\n >\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 .49-3.51\"/>\r\n </svg>\r\n Retry Now\r\n </button>\r\n </>\r\n );\r\n}\r\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\n\nexport { mergeClasses };\n//# sourceMappingURL=mergeClasses.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n\nexport { toKebabCase };\n//# sourceMappingURL=toKebabCase.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\n\nexport { toCamelCase };\n//# sourceMappingURL=toCamelCase.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { toCamelCase } from './toCamelCase.mjs';\n\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\n\nexport { toPascalCase };\n//# sourceMappingURL=toPascalCase.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n return false;\n};\n\nexport { hasA11yProp };\n//# sourceMappingURL=hasA11yProp.mjs.map\n","\"use strict\";\n\"use client\";\n/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { createContext, useContext, useMemo, createElement } from 'react';\n\nconst LucideContext = createContext({});\nfunction LucideProvider({\n children,\n size,\n color,\n strokeWidth,\n absoluteStrokeWidth,\n className\n}) {\n const value = useMemo(\n () => ({\n size,\n color,\n strokeWidth,\n absoluteStrokeWidth,\n className\n }),\n [size, color, strokeWidth, absoluteStrokeWidth, className]\n );\n return createElement(LucideContext.Provider, { value }, children);\n}\nconst useLucideContext = () => useContext(LucideContext);\n\nexport { LucideProvider, useLucideContext };\n//# sourceMappingURL=context.mjs.map\n","\"use strict\";\n\"use client\";\n/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.mjs';\nimport { hasA11yProp } from './shared/src/utils/hasA11yProp.mjs';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.mjs';\nimport { useLucideContext } from './context.mjs';\n\nconst Icon = forwardRef(\n ({ color, size, strokeWidth, absoluteStrokeWidth, className = \"\", children, iconNode, ...rest }, ref) => {\n const {\n size: contextSize = 24,\n strokeWidth: contextStrokeWidth = 2,\n absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,\n color: contextColor = \"currentColor\",\n className: contextClass = \"\"\n } = useLucideContext() ?? {};\n const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;\n return createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size ?? contextSize ?? defaultAttributes.width,\n height: size ?? contextSize ?? defaultAttributes.height,\n stroke: color ?? contextColor,\n strokeWidth: calculatedStrokeWidth,\n className: mergeClasses(\"lucide\", contextClass, className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n );\n }\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.mjs';\nimport { toKebabCase } from './shared/src/utils/toKebabCase.mjs';\nimport { toPascalCase } from './shared/src/utils/toPascalCase.mjs';\nimport Icon from './Icon.mjs';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M5 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-1\",\n key: \"ns4c3b\"\n }\n ],\n [\"path\", { d: \"m12 15 5 6H7Z\", key: \"14qnn2\" }]\n];\nconst Airplay = createLucideIcon(\"airplay\", __iconNode);\n\nexport { __iconNode, Airplay as default };\n//# sourceMappingURL=airplay.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"14\", x: \"3\", y: \"5\", rx: \"2\", ry: \"2\", key: \"12ruh7\" }],\n [\"path\", { d: \"M7 15h4M15 15h2M7 11h2M13 11h4\", key: \"1ueiar\" }]\n];\nconst Captions = createLucideIcon(\"captions\", __iconNode);\n\nexport { __iconNode, Captions as default };\n//# sourceMappingURL=captions.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6\", key: \"3zrzxg\" }],\n [\"path\", { d: \"M2 12a9 9 0 0 1 8 8\", key: \"g6cvee\" }],\n [\"path\", { d: \"M2 16a5 5 0 0 1 4 4\", key: \"1y1dii\" }],\n [\"line\", { x1: \"2\", x2: \"2.01\", y1: \"20\", y2: \"20\", key: \"xu2jvo\" }]\n];\nconst Cast = createLucideIcon(\"cast\", __iconNode);\n\nexport { __iconNode, Cast as default };\n//# sourceMappingURL=cast.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [[\"path\", { d: \"M20 6 9 17l-5-5\", key: \"1gmf2c\" }]];\nconst Check = createLucideIcon(\"check\", __iconNode);\n\nexport { __iconNode, Check as default };\n//# sourceMappingURL=check.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [[\"path\", { d: \"m15 18-6-6 6-6\", key: \"1wnfg3\" }]];\nconst ChevronLeft = createLucideIcon(\"chevron-left\", __iconNode);\n\nexport { __iconNode, ChevronLeft as default };\n//# sourceMappingURL=chevron-left.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m12 14 4-4\", key: \"9kzdfg\" }],\n [\"path\", { d: \"M3.34 19a10 10 0 1 1 17.32 0\", key: \"19p75a\" }]\n];\nconst Gauge = createLucideIcon(\"gauge\", __iconNode);\n\nexport { __iconNode, Gauge as default };\n//# sourceMappingURL=gauge.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m5 8 6 6\", key: \"1wu5hv\" }],\n [\"path\", { d: \"m4 14 6-6 2-3\", key: \"1k1g8d\" }],\n [\"path\", { d: \"M2 5h12\", key: \"or177f\" }],\n [\"path\", { d: \"M7 2h1\", key: \"1t2jsx\" }],\n [\"path\", { d: \"m22 22-5-10-5 10\", key: \"don7ne\" }],\n [\"path\", { d: \"M14 18h6\", key: \"1m8k6r\" }]\n];\nconst Languages = createLucideIcon(\"languages\", __iconNode);\n\nexport { __iconNode, Languages as default };\n//# sourceMappingURL=languages.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M21 5H3\", key: \"1fi0y6\" }],\n [\"path\", { d: \"M10 12H3\", key: \"1ulcyk\" }],\n [\"path\", { d: \"M10 19H3\", key: \"108z41\" }],\n [\n \"path\",\n {\n d: \"M15 12.003a1 1 0 0 1 1.517-.859l4.997 2.997a1 1 0 0 1 0 1.718l-4.997 2.997a1 1 0 0 1-1.517-.86z\",\n key: \"ms4nik\"\n }\n ]\n];\nconst ListVideo = createLucideIcon(\"list-video\", __iconNode);\n\nexport { __iconNode, ListVideo as default };\n//# sourceMappingURL=list-video.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M8 3H5a2 2 0 0 0-2 2v3\", key: \"1dcmit\" }],\n [\"path\", { d: \"M21 8V5a2 2 0 0 0-2-2h-3\", key: \"1e4gt3\" }],\n [\"path\", { d: \"M3 16v3a2 2 0 0 0 2 2h3\", key: \"wsl5sc\" }],\n [\"path\", { d: \"M16 21h3a2 2 0 0 0 2-2v-3\", key: \"18trek\" }]\n];\nconst Maximize = createLucideIcon(\"maximize\", __iconNode);\n\nexport { __iconNode, Maximize as default };\n//# sourceMappingURL=maximize.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M8 3v3a2 2 0 0 1-2 2H3\", key: \"hohbtr\" }],\n [\"path\", { d: \"M21 8h-3a2 2 0 0 1-2-2V3\", key: \"5jw1f3\" }],\n [\"path\", { d: \"M3 16h3a2 2 0 0 1 2 2v3\", key: \"198tvr\" }],\n [\"path\", { d: \"M16 21v-3a2 2 0 0 1 2-2h3\", key: \"ph8mxp\" }]\n];\nconst Minimize = createLucideIcon(\"minimize\", __iconNode);\n\nexport { __iconNode, Minimize as default };\n//# sourceMappingURL=minimize.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { x: \"14\", y: \"3\", width: \"5\", height: \"18\", rx: \"1\", key: \"kaeet6\" }],\n [\"rect\", { x: \"5\", y: \"3\", width: \"5\", height: \"18\", rx: \"1\", key: \"1wsw3u\" }]\n];\nconst Pause = createLucideIcon(\"pause\", __iconNode);\n\nexport { __iconNode, Pause as default };\n//# sourceMappingURL=pause.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M2 10h6V4\", key: \"zwrco\" }],\n [\"path\", { d: \"m2 4 6 6\", key: \"ug085t\" }],\n [\"path\", { d: \"M21 10V7a2 2 0 0 0-2-2h-7\", key: \"git5jr\" }],\n [\"path\", { d: \"M3 14v2a2 2 0 0 0 2 2h3\", key: \"1f7fh3\" }],\n [\"rect\", { x: \"12\", y: \"14\", width: \"10\", height: \"7\", rx: \"1\", key: \"1wjs3o\" }]\n];\nconst PictureInPicture = createLucideIcon(\"picture-in-picture\", __iconNode);\n\nexport { __iconNode, PictureInPicture as default };\n//# sourceMappingURL=picture-in-picture.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\",\n key: \"10ikf1\"\n }\n ]\n];\nconst Play = createLucideIcon(\"play\", __iconNode);\n\nexport { __iconNode, Play as default };\n//# sourceMappingURL=play.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\", key: \"1357e3\" }],\n [\"path\", { d: \"M3 3v5h5\", key: \"1xhq8a\" }]\n];\nconst RotateCcw = createLucideIcon(\"rotate-ccw\", __iconNode);\n\nexport { __iconNode, RotateCcw as default };\n//# sourceMappingURL=rotate-ccw.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\", key: \"1p45f6\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }]\n];\nconst RotateCw = createLucideIcon(\"rotate-cw\", __iconNode);\n\nexport { __iconNode, RotateCw as default };\n//# sourceMappingURL=rotate-cw.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M2 20h.01\", key: \"4haj6o\" }],\n [\"path\", { d: \"M7 20v-4\", key: \"j294jx\" }],\n [\"path\", { d: \"M12 20v-8\", key: \"i3yub9\" }],\n [\"path\", { d: \"M17 20V8\", key: \"1tkaf5\" }],\n [\"path\", { d: \"M22 4v16\", key: \"sih9yq\" }]\n];\nconst Signal = createLucideIcon(\"signal\", __iconNode);\n\nexport { __iconNode, Signal as default };\n//# sourceMappingURL=signal.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\",\n key: \"uqj9uw\"\n }\n ],\n [\"path\", { d: \"M16 9a5 5 0 0 1 0 6\", key: \"1q6k2b\" }]\n];\nconst Volume1 = createLucideIcon(\"volume-1\", __iconNode);\n\nexport { __iconNode, Volume1 as default };\n//# sourceMappingURL=volume-1.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\",\n key: \"uqj9uw\"\n }\n ],\n [\"path\", { d: \"M16 9a5 5 0 0 1 0 6\", key: \"1q6k2b\" }],\n [\"path\", { d: \"M19.364 18.364a9 9 0 0 0 0-12.728\", key: \"ijwkga\" }]\n];\nconst Volume2 = createLucideIcon(\"volume-2\", __iconNode);\n\nexport { __iconNode, Volume2 as default };\n//# sourceMappingURL=volume-2.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\",\n key: \"uqj9uw\"\n }\n ],\n [\"line\", { x1: \"22\", x2: \"16\", y1: \"9\", y2: \"15\", key: \"1ewh16\" }],\n [\"line\", { x1: \"16\", x2: \"22\", y1: \"9\", y2: \"15\", key: \"5ykzw1\" }]\n];\nconst VolumeX = createLucideIcon(\"volume-x\", __iconNode);\n\nexport { __iconNode, VolumeX as default };\n//# sourceMappingURL=volume-x.mjs.map\n","/**\n * @license lucide-react v1.16.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\",\n key: \"uqj9uw\"\n }\n ]\n];\nconst Volume = createLucideIcon(\"volume\", __iconNode);\n\nexport { __iconNode, Volume as default };\n//# sourceMappingURL=volume.mjs.map\n","import React, { useRef, useState, useEffect, useMemo, useCallback } from 'react';\r\nimport { ErrorScreen } from './ErrorScreen';\r\nimport Hls from 'hls.js';\r\nimport {\r\n Play,\r\n Pause,\r\n RotateCcw,\r\n RotateCw,\r\n Volume2,\r\n VolumeX,\r\n Volume1,\r\n Volume,\r\n Subtitles,\r\n Maximize,\r\n Minimize,\r\n Cast,\r\n Airplay,\r\n ListVideo,\r\n Check,\r\n ChevronLeft,\r\n PictureInPicture,\r\n Languages,\r\n Gauge,\r\n Signal,\r\n} from 'lucide-react';\r\nimport { VideoPlayerSDK } from '@goboss/core-player';\r\nimport { FirebaseAnalyticsProvider } from '@goboss/analytics';\r\nimport type { FirebaseConfig } from '@goboss/analytics';\r\nimport type { VideoQuality, Chapter, KeyMoment, SubtitleTrack, AnalyticsEvent, SourceItem } from '@goboss/types';\r\nimport './player.css';\r\n\r\n// How long to wait for a switched-to source to actually start playing before\r\n// assuming the format is unsupported and falling back to the first source.\r\nconst SOURCE_FALLBACK_TIMEOUT_MS = 10000;\r\n\r\nconst extractTitleFromManifest = (text: string): string | null => {\r\n const titleTag = text.match(/#EXT-X-TITLE:(.+)/);\r\n if (titleTag?.[1]?.trim()) return titleTag[1].trim();\r\n const sessionData = text.match(/#EXT-X-SESSION-DATA:[^\\n]*DATA-ID=\"[^\"]*title[^\"]*\"[^\\n]*VALUE=\"([^\"]+)\"/i);\r\n if (sessionData?.[1]?.trim()) return sessionData[1].trim();\r\n return null;\r\n};\r\n\r\nconst parseID3Title = (data: Uint8Array): string | null => {\r\n if (!data || data.length < 10) return null;\r\n if (data[0] !== 0x49 || data[1] !== 0x44 || data[2] !== 0x33) return null;\r\n const version = data[3];\r\n const totalSize = ((data[6] & 0x7f) << 21) | ((data[7] & 0x7f) << 14) | ((data[8] & 0x7f) << 7) | (data[9] & 0x7f);\r\n const end = Math.min(10 + totalSize, data.length);\r\n let offset = 10;\r\n while (offset + 10 <= end) {\r\n const id = String.fromCharCode(data[offset], data[offset+1], data[offset+2], data[offset+3]);\r\n const frameSize = version >= 4\r\n ? ((data[offset+4] & 0x7f) << 21) | ((data[offset+5] & 0x7f) << 14) | ((data[offset+6] & 0x7f) << 7) | (data[offset+7] & 0x7f)\r\n : (data[offset+4] << 24) | (data[offset+5] << 16) | (data[offset+6] << 8) | data[offset+7];\r\n if (frameSize <= 0 || offset + 10 + frameSize > end) break;\r\n if (id === 'TIT2') {\r\n const enc = data[offset + 10];\r\n const raw = data.slice(offset + 11, offset + 10 + frameSize);\r\n const decoded = enc === 1 || enc === 2\r\n ? new TextDecoder('utf-16').decode(raw)\r\n : new TextDecoder(enc === 3 ? 'utf-8' : 'latin1').decode(raw);\r\n const result = decoded.replace(/\\0/g, '').trim();\r\n if (result) return result;\r\n }\r\n offset += 10 + frameSize;\r\n }\r\n return null;\r\n};\r\n\r\n\r\nconst HdIcon = ({ size = 20 }: { size?: number }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <rect x=\"2\" y=\"5\" width=\"20\" height=\"14\" rx=\"3\" />\r\n <path d=\"M7 9v6M7 12h3M10 9v6\" />\r\n <path d=\"M14 9h1.5a3 3 0 0 1 0 6H14z\" />\r\n </svg>\r\n);\r\n\r\nconst hexToRgb = (hex: string): string => {\r\n const cleanHex = hex.replace('#', '');\r\n if (cleanHex.length === 6) {\r\n const r = parseInt(cleanHex.substring(0, 2), 16);\r\n const g = parseInt(cleanHex.substring(2, 4), 16);\r\n const b = parseInt(cleanHex.substring(4, 6), 16);\r\n return `${r}, ${g}, ${b}`;\r\n } else if (cleanHex.length === 3) {\r\n const r = parseInt(cleanHex[0] + cleanHex[0], 16);\r\n const g = parseInt(cleanHex[1] + cleanHex[1], 16);\r\n const b = parseInt(cleanHex[2] + cleanHex[2], 16);\r\n return `${r}, ${g}, ${b}`;\r\n }\r\n return '99, 102, 241';\r\n};\r\n\r\nconst languageNameMap: Record<string, string> = {\r\n en: 'English',\r\n eng: 'English',\r\n fr: 'French',\r\n fre: 'French',\r\n fra: 'French',\r\n es: 'Spanish',\r\n spa: 'Spanish',\r\n de: 'German',\r\n ger: 'German',\r\n deu: 'German',\r\n it: 'Italian',\r\n ita: 'Italian',\r\n pt: 'Portuguese',\r\n por: 'Portuguese',\r\n ja: 'Japanese',\r\n zh: 'Chinese',\r\n ko: 'Korean',\r\n ru: 'Russian',\r\n ar: 'Arabic',\r\n hi: 'Hindi',\r\n ta: 'Tamil',\r\n tam: 'Tamil',\r\n};\r\n\r\nconst formatLanguageName = (value: string): string | null => {\r\n if (!value) return null;\r\n const normalized = value.trim().toLowerCase();\r\n const prefixMatch = normalized.match(/^(en|eng|fr|fre|fra|es|spa|de|ger|deu|it|ita|pt|por|ja|zh|ko|ru|ar|hi|ta|tam)/);\r\n if (prefixMatch && languageNameMap[prefixMatch[0]]) {\r\n return languageNameMap[prefixMatch[0]];\r\n }\r\n for (const [key, name] of Object.entries(languageNameMap)) {\r\n if (normalized.includes(key)) {\r\n return name;\r\n }\r\n }\r\n if (/english|anglais|ingles/i.test(normalized)) return 'English';\r\n if (/french|français/i.test(normalized)) return 'French';\r\n if (/spanish|español/i.test(normalized)) return 'Spanish';\r\n if (/german|deutsch/i.test(normalized)) return 'German';\r\n if (/italian|italiano/i.test(normalized)) return 'Italian';\r\n if (/portuguese|português/i.test(normalized)) return 'Portuguese';\r\n if (/japanese|nihongo/i.test(normalized)) return 'Japanese';\r\n if (/chinese|中文/i.test(normalized)) return 'Chinese';\r\n if (/korean|한국어/i.test(normalized)) return 'Korean';\r\n if (/tamil|தமிழ்/i.test(normalized)) return 'Tamil';\r\n if (/russian|русский/i.test(normalized)) return 'Russian';\r\n if (/arabic|العربية/i.test(normalized)) return 'Arabic';\r\n if (/hindi|हिन्दी/i.test(normalized)) return 'Hindi';\r\n return null;\r\n};\r\n\r\nconst getLanguageLabel = (track: { label: string; lang: string }): string => {\r\n if (track.lang) {\r\n const normalized = formatLanguageName(track.lang);\r\n if (normalized) return normalized;\r\n }\r\n\r\n if (track.label) {\r\n const label = track.label.trim();\r\n const parts = label.split(/[#\\d\\.\\s\\-_/|:]+/).filter(Boolean);\r\n for (let i = parts.length - 1; i >= 0; i -= 1) {\r\n const candidate = formatLanguageName(parts[i]);\r\n if (candidate) return candidate;\r\n }\r\n const cleaned = label.replace(/^[#\\d\\.\\s]+/, '').trim();\r\n return formatLanguageName(cleaned) || cleaned;\r\n }\r\n\r\n return 'Unknown';\r\n};\r\n\r\nconst dedupeSubtitleTracks = (tracks: SubtitleTrack[]): SubtitleTrack[] => {\r\n const seen = new Set<string>();\r\n return tracks.filter((track) => {\r\n const label = getLanguageLabel(track).toLowerCase();\r\n const lang = (track.lang || '').trim().toLowerCase();\r\n const key = `${label}|${lang}`;\r\n if (seen.has(key)) {\r\n return false;\r\n }\r\n seen.add(key);\r\n return true;\r\n });\r\n};\r\n\r\ninterface SubtitleStyle {\r\n size?: 'small' | 'medium' | 'large';\r\n background?: 'none' | 'dim' | 'solid';\r\n color?: string;\r\n}\r\n\r\ninterface OverlayAdItem {\r\n availId: string;\r\n startTimeSeconds: number;\r\n durationSeconds: number;\r\n imageUrl: string;\r\n imageWidth: number;\r\n imageHeight: number;\r\n title: string;\r\n clickThrough: string;\r\n clickTrackingUrl: string;\r\n impressionBeacons: string[];\r\n position: string;\r\n dismissible: boolean;\r\n}\r\n\r\nconst parseHHMMSS = (t: string): number => {\r\n const parts = (t ?? '').split(':').map(Number);\r\n return (parts[0] || 0) * 3600 + (parts[1] || 0) * 60 + (parts[2] || 0);\r\n};\r\n\r\ninterface AvailSkipInfo {\r\n startTimeSeconds: number;\r\n durationSeconds: number;\r\n skippable: boolean;\r\n skipOffsetSeconds: number;\r\n}\r\n\r\ninterface WebVideoPlayerProps {\r\n src: string;\r\n autoplay?: boolean;\r\n muted?: boolean;\r\n chapters?: Chapter[];\r\n keyMoments?: KeyMoment[];\r\n subtitles?: SubtitleTrack[];\r\n watermark?: string;\r\n themeColor?: string;\r\n drmConfig?: any;\r\n firebaseConfig?: FirebaseConfig;\r\n onAnalyticsEvent?: (event: AnalyticsEvent) => void;\r\n onAdBreakChange?: (active: boolean) => void;\r\n onKeyMomentsLoaded?: (keyMoments: KeyMoment[]) => void;\r\n enableControls?: boolean;\r\n enableChromecast?: boolean;\r\n enableKeyMoments?: boolean;\r\n enableSubtitles?: boolean;\r\n enableQuality?: boolean;\r\n enablePlaybackSpeed?: boolean;\r\n enablePiP?: boolean;\r\n enableFullscreen?: boolean;\r\n autoFullscreen?: boolean;\r\n watchProgressInterval?: number; // in seconds, default 30\r\n subtitleStyle?: SubtitleStyle;\r\n /**\r\n * Pre-resolved entitlement package from BossVideoPlayer.\r\n * When provided, features are determined exclusively by this package (API mode).\r\n * When absent, features fall back to explicit props with true defaults (standalone mode).\r\n */\r\n resolvedEntitlement?: { package: string; is_active: boolean; features: Record<string, boolean>; limits: { streaming_minutes: number } } | null;\r\n licenseKey?: string | null;\r\n title?: string;\r\n chaptersDisplayMode?: 'strip' | 'panel';\r\n volumeControlType?: 'slider' | 'button';\r\n urlTransformer?: (url: string) => string;\r\n pauseAdOnTabSwitch?: boolean;\r\n enableSkipAd?: boolean;\r\n skipAdAfterSeconds?: number;\r\n overlayAdUrl?: string;\r\n adTrackingUrl?: string;\r\n sources?: SourceItem[];\r\n activeSourceIndex?: number;\r\n onSourceChange?: (index: number) => void;\r\n /** Seek to this position (in seconds) as soon as the video is ready. Use for resume-playback. */\r\n initialTime?: number;\r\n /** Called on every timeupdate with the current playback position in seconds. Use to persist watch progress. */\r\n onTimeUpdate?: (currentTime: number) => void;\r\n}\r\n\r\nexport const WebVideoPlayer: React.FC<WebVideoPlayerProps> = ({\r\n src,\r\n autoplay = false,\r\n muted = false,\r\n chapters = [],\r\n keyMoments,\r\n subtitles = [],\r\n watermark,\r\n themeColor = '#6366f1',\r\n drmConfig,\r\n firebaseConfig,\r\n onAnalyticsEvent,\r\n onAdBreakChange,\r\n onKeyMomentsLoaded,\r\n enableControls = true,\r\n enableChromecast,\r\n enableKeyMoments,\r\n enableSubtitles,\r\n enableQuality,\r\n enablePlaybackSpeed,\r\n enablePiP,\r\n enableFullscreen = true,\r\n autoFullscreen = false,\r\n watchProgressInterval = 30,\r\n subtitleStyle = {},\r\n resolvedEntitlement,\r\n licenseKey,\r\n title,\r\n chaptersDisplayMode = 'strip',\r\n volumeControlType = 'slider',\r\n urlTransformer,\r\n pauseAdOnTabSwitch = true,\r\n enableSkipAd = false,\r\n skipAdAfterSeconds = 5,\r\n overlayAdUrl,\r\n adTrackingUrl,\r\n sources,\r\n activeSourceIndex = 0,\r\n onSourceChange,\r\n initialTime,\r\n onTimeUpdate,\r\n}) => {\r\n const transformUrl = urlTransformer ?? ((url: string) => url);\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const firebaseProviderRef = useRef<FirebaseAnalyticsProvider | null>(null);\r\n const hasAutoFullscreenedRef = useRef(false);\r\n const seekbarRef = useRef<HTMLDivElement>(null);\r\n const seekbarWidthRef = useRef(0);\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const hiddenVideoRef = useRef<HTMLVideoElement | null>(null);\r\n const hiddenHlsRef = useRef<Hls | null>(null);\r\n const hoverSeekTimer = useRef<number | null>(null);\r\n const isScrubbing = useRef(false);\r\n const isSeeking = useRef(false);\r\n const seekTargetTime = useRef<number | null>(null);\r\n const seekGuardTimeout = useRef<number | null>(null);\r\n const castButtonRef = useRef<HTMLDivElement>(null);\r\n const toggleFullscreenRef = useRef<() => void>(() => {});\r\n const adSkipCoverRef = useRef<HTMLDivElement | null>(null);\r\n const triggerAdSkipRef = useRef<((endTime: number) => void) | null>(null);\r\n const pendingSeekTargetRef = useRef<number | null>(null);\r\n const performSeekRef = useRef<((time: number) => void) | null>(null);\r\n const sourceChangeSeekRef = useRef<number | null>(null);\r\n const sourceChangeFallbackTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n // Tracks an in-flight source switch so the new player's effect can start a\r\n // \"did playback actually start?\" watchdog. Survives the player re-init because it's a ref.\r\n const pendingSourceSwitchRef = useRef<{ targetIdx: number } | null>(null);\r\n // Latest sources / onSourceChange, readable from inside the player effect closure\r\n // (whose deps are [src, watermark, retryKey], so it would otherwise capture stale values).\r\n const sourcesRef = useRef(sources);\r\n const onSourceChangeRef = useRef(onSourceChange);\r\n const initialSeekAppliedRef = useRef(false);\r\n\r\n const [isMobile, setIsMobile] = useState(false);\r\n const isMobileRef = useRef(false);\r\n const lastTapRef = useRef<{ time: number; x: number } | null>(null);\r\n const [doubleTapSide, setDoubleTapSide] = useState<'left' | 'right' | null>(null);\r\n\r\n useEffect(() => {\r\n const el = containerRef.current;\r\n if (!el) return;\r\n const ro = new ResizeObserver(entries => {\r\n for (const entry of entries) {\r\n setIsMobile(entry.contentRect.width <= 768);\r\n }\r\n });\r\n ro.observe(el);\r\n setIsMobile(el.getBoundingClientRect().width <= 768);\r\n return () => ro.disconnect();\r\n }, []);\r\n\r\n const [player, setPlayer] = useState<VideoPlayerSDK | null>(null);\r\n\r\n // Entitlement is always pre-resolved by BossVideoPlayer before this component mounts.\r\n // When resolvedEntitlement is provided (API mode): features come exclusively from the API.\r\n // When absent (standalone/test mode): features come from explicit props or true defaults.\r\n const entitlementPackage = resolvedEntitlement ?? null;\r\n const hasEntitlement = entitlementPackage != null;\r\n const ef = entitlementPackage?.features ?? {};\r\n\r\n // DRM: block playback if the plan requires a license key but none was provided.\r\n const isEntitlementBlocked = hasEntitlement\r\n ? Boolean(ef.drm_protection && !licenseKey)\r\n : false;\r\n\r\n // API-gated features — controlled by the init API when a playerKey is used.\r\n // In standalone mode (no resolvedEntitlement), fall back to explicit props or true defaults.\r\n const effectiveFeatures = {\r\n enableSubtitles: hasEntitlement ? Boolean(ef.subtitle_support) : (typeof enableSubtitles === 'boolean' ? enableSubtitles : true),\r\n enableChromecast: hasEntitlement ? Boolean(ef.chromecast) : (typeof enableChromecast === 'boolean' ? enableChromecast : true),\r\n enableKeyMoments: hasEntitlement ? Boolean(ef.key_moments) : (typeof enableKeyMoments === 'boolean' ? enableKeyMoments : true),\r\n enableQuality: hasEntitlement ? Boolean(ef.multiple_resolution) : (typeof enableQuality === 'boolean' ? enableQuality : true),\r\n enablePlaybackSpeed: hasEntitlement ? Boolean(ef.playback_speed) : (typeof enablePlaybackSpeed === 'boolean' ? enablePlaybackSpeed : true),\r\n enablePiP: hasEntitlement ? Boolean(ef.picture_in_picture) : (typeof enablePiP === 'boolean' ? enablePiP : true),\r\n allowAirplay: hasEntitlement ? Boolean(ef.airplay) : false,\r\n allowMultipleAudio: hasEntitlement ? Boolean(ef.multiple_audio) : true,\r\n m3u8_playback: hasEntitlement ? Boolean(ef.m3u8_playback) : true,\r\n drm_protection: hasEntitlement ? Boolean(ef.drm_protection) : false,\r\n };\r\n const [playerError, setPlayerError] = useState(false);\r\n const [retryKey, setRetryKey] = useState(0);\r\n const [isPlaying, setIsPlaying] = useState(false);\r\n const [currentTime, setCurrentTime] = useState(0);\r\n const [duration, setDuration] = useState(0);\r\n const [volume, setVolume] = useState(1);\r\n const [isMuted, setIsMuted] = useState(false);\r\n const [isBuffering, setIsBuffering] = useState(false);\r\n const [isFullscreen, setIsFullscreen] = useState(false);\r\n const [isSimulatedFullscreen, setIsSimulatedFullscreen] = useState(false);\r\n // Tracks whether the container was in mobile layout when fullscreen was entered.\r\n // Keeps mobile controls active during landscape rotation without affecting desktop fullscreen.\r\n const [wasMobileOnFullscreenEnter, setWasMobileOnFullscreenEnter] = useState(false);\r\n const useMobileLayout = isMobile || ((isFullscreen || isSimulatedFullscreen) && wasMobileOnFullscreenEnter);\r\n const [isPiP, setIsPiP] = useState(false);\r\n const [isEnded, setIsEnded] = useState(false);\r\n const [adBreaks, setAdBreaks] = useState<Array<{ startTime: number; endTime: number }>>([]);\r\n const adBreaksRef = useRef<Array<{ startTime: number; endTime: number }>>([]);\r\n const watchedAdBreaksRef = useRef<Set<number>>(new Set());\r\n // React state mirror of watchedAdBreaksRef — drives the cue-marker filter in render.\r\n // Reset during render (not in an effect) using the \"update during render\" pattern so\r\n // no setState call is ever needed inside a useEffect body.\r\n const [watchedAdBreaksSet, setWatchedAdBreaksSet] = useState<Set<number>>(new Set());\r\n const [watchedAdBreaksSrc, setWatchedAdBreaksSrc] = useState(src);\r\n if (watchedAdBreaksSrc !== src) {\r\n setWatchedAdBreaksSrc(src);\r\n setWatchedAdBreaksSet(new Set());\r\n }\r\n const activeAdBreakStartRef = useRef<number | null>(null);\r\n const wasAdPausedByVisibilityRef = useRef(false);\r\n\r\n // Overlay (non-linear) ads\r\n const [overlayAds, setOverlayAds] = useState<OverlayAdItem[]>([]);\r\n const [activeOverlay, setActiveOverlay] = useState<OverlayAdItem | null>(null);\r\n const overlayAdsRef = useRef<OverlayAdItem[]>([]);\r\n const activeOverlayRef = useRef<OverlayAdItem | null>(null);\r\n const dismissedOverlayIdsRef = useRef<Set<string>>(new Set());\r\n\r\n // Per-break skip info from avails metadata\r\n const [availsSkipInfo, setAvailsSkipInfo] = useState<AvailSkipInfo[]>([]);\r\n const availsSkipInfoRef = useRef<AvailSkipInfo[]>([]);\r\n\r\n // Total ad duration summed from all detected breaks\r\n const totalAdDuration = useMemo(\r\n () => adBreaks.reduce((sum, ab) => sum + (ab.endTime - ab.startTime), 0),\r\n [adBreaks]\r\n );\r\n\r\n // Content-only duration (video duration minus all spliced ad time).\r\n // Falls back to raw duration until adBreaks are loaded so the display is never blank.\r\n const contentDuration = duration > 0 ? Math.max(0, duration - totalAdDuration) : 0;\r\n const displayDuration = adBreaks.length > 0 && contentDuration > 0 ? contentDuration : duration;\r\n\r\n // Convert raw video time → content-only time (subtracts elapsed ad time before `t`).\r\n // During an ad the returned value is frozen at the content timestamp where the ad started.\r\n const videoTimeToContentTime = useCallback((t: number): number => {\r\n let ct = t;\r\n for (const ab of adBreaks) {\r\n if (t >= ab.endTime) {\r\n ct -= (ab.endTime - ab.startTime);\r\n } else if (t >= ab.startTime) {\r\n ct -= (t - ab.startTime);\r\n }\r\n }\r\n return Math.max(0, ct);\r\n }, [adBreaks]);\r\n\r\n // Convert content-only time → raw video time (adds back ad durations).\r\n // Used to translate a seekbar click position into the actual seek target.\r\n const contentTimeToVideoTime = useCallback((ct: number): number => {\r\n let vt = ct;\r\n for (const ab of adBreaks) {\r\n if (vt >= ab.startTime) {\r\n vt += (ab.endTime - ab.startTime);\r\n }\r\n }\r\n return vt;\r\n }, [adBreaks]);\r\n\r\n // Lists & Selections\r\n const [qualities, setQualities] = useState<VideoQuality[]>([]);\r\n const [activeQuality, setActiveQuality] = useState<VideoQuality>({\r\n id: -1,\r\n height: 0,\r\n width: 0,\r\n bitrate: 0,\r\n label: 'Auto',\r\n });\r\n const [subtitleText, setSubtitleText] = useState('');\r\n const [activeSubtitleTrack, setActiveSubtitleTrack] = useState('off');\r\n const [availableSubtitles, setAvailableSubtitles] = useState<SubtitleTrack[]>(dedupeSubtitleTracks(subtitles));\r\n const [audioTracks, setAudioTracks] = useState<Array<{ id: number; label: string; lang: string }>>([]);\r\n const [activeAudioTrack, setActiveAudioTrack] = useState<number>(0);\r\n\r\n // Stable key — avoids infinite loops when parent passes inline [] on every render\r\n const subtitlesKey = subtitles.map(s => s.id).join(',');\r\n\r\n // Sync external subtitles prop dynamically and merge with discovered tracks\r\n useEffect(() => {\r\n if (player) {\r\n const playerTracks = player.subtitles.getTracks();\r\n const merged = [...subtitles, ...playerTracks.filter(t => !subtitles.some(s => s.id === t.id))];\r\n setAvailableSubtitles(dedupeSubtitleTracks(merged));\r\n } else {\r\n setAvailableSubtitles(dedupeSubtitleTracks(subtitles));\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [subtitlesKey, player]);\r\n\r\n const [activeChapter, setActiveChapter] = useState<{ chapter: KeyMoment | null; index: number }>({\r\n chapter: null,\r\n index: -1,\r\n });\r\n\r\n const [localKeyMoments, setLocalKeyMoments] = useState<KeyMoment[]>(keyMoments || chapters || []);\r\n\r\n // UI Dropdowns\r\n const [activeMenu, setActiveMenu] = useState<'none' | 'quality' | 'speed' | 'subtitles' | 'chapters' | 'audio' | 'sources' | 'mobile-settings'>('none');\r\n const [playbackRate, setPlaybackRate] = useState(1);\r\n const [showChaptersSidebar, setShowChaptersSidebar] = useState(false);\r\n const [chapterThumbnails, setChapterThumbnails] = useState<Record<number, string>>({});\r\n\r\n // Accessibility: live-region announcement text\r\n const [announcement, setAnnouncement] = useState('');\r\n const [sourceFallbackNotice, setSourceFallbackNotice] = useState<string | null>(null);\r\n const announceMountedRef = useRef(false);\r\n\r\n const keyMomentsKey = JSON.stringify(localKeyMoments.map(c => ({ title: c.title, startTime: c.startTime })));\r\n\r\n // Stable key for incoming props — avoids infinite loops when parent passes inline [] on every render\r\n const keyMomentsPropsKey = (keyMoments || chapters || []).map(k => `${k.startTime}:${k.title}`).join(',');\r\n\r\n // Sync props to state dynamically\r\n useEffect(() => {\r\n setLocalKeyMoments(keyMoments || chapters || []);\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [keyMomentsPropsKey]);\r\n\r\n // Dynamically extract actual video frames at chapter start times\r\n useEffect(() => {\r\n if (!src || !localKeyMoments || localKeyMoments.length === 0) return;\r\n\r\n setChapterThumbnails({});\r\n\r\n const tempVideo = document.createElement('video');\r\n tempVideo.muted = true;\r\n tempVideo.preload = 'metadata';\r\n tempVideo.crossOrigin = 'anonymous';\r\n // position:fixed with opacity:0.01 forces the browser compositor to decode frames, bypassing display:none optimizations\r\n tempVideo.style.cssText = 'position:fixed;top:0;left:0;width:10px;height:10px;opacity:0.01;pointer-events:none;z-index:-9999;';\r\n document.body.appendChild(tempVideo);\r\n\r\n let tempHls: Hls | null = null;\r\n const isHls = src.includes('.m3u8');\r\n\r\n const tempCanvas = document.createElement('canvas');\r\n tempCanvas.width = 160;\r\n tempCanvas.height = 90;\r\n const ctx = tempCanvas.getContext('2d');\r\n\r\n let currentIndex = 0;\r\n let isStarted = false;\r\n\r\n const captureNext = () => {\r\n if (currentIndex >= localKeyMoments.length) {\r\n cleanup();\r\n return;\r\n }\r\n const targetTime = localKeyMoments[currentIndex].startTime;\r\n // Seek to target. If 0, seek to 0.01 to ensure the browser registers a currentTime change and triggers 'seeked'\r\n tempVideo.currentTime = targetTime === 0 ? 0.01 : targetTime;\r\n };\r\n\r\n const onSeeked = () => {\r\n if (ctx && tempVideo.readyState >= 2) {\r\n ctx.drawImage(tempVideo, 0, 0, tempCanvas.width, tempCanvas.height);\r\n const dataUrl = tempCanvas.toDataURL('image/jpeg', 0.8);\r\n setChapterThumbnails((prev) => ({ ...prev, [currentIndex]: dataUrl }));\r\n currentIndex++;\r\n captureNext();\r\n } else {\r\n // Fallback retry if video frame buffer wasn't ready\r\n setTimeout(onSeeked, 100);\r\n }\r\n };\r\n\r\n const startCapture = () => {\r\n if (isStarted) return;\r\n isStarted = true;\r\n captureNext();\r\n };\r\n\r\n tempVideo.addEventListener('seeked', onSeeked);\r\n tempVideo.addEventListener('canplay', startCapture);\r\n\r\n if (isHls && Hls.isSupported()) {\r\n tempHls = new Hls({\r\n enableWorker: false,\r\n maxBufferLength: 5,\r\n xhrSetup: (xhr, url) => {\r\n // Only use an explicit auth token passed via `drmConfig`.\r\n // Do NOT infer or parse tokens from the stream URL.\r\n const token = drmConfig?.authToken;\r\n try {\r\n const proxiedUrl = transformUrl(url);\r\n const urlObj = new URL(proxiedUrl, window.location.origin);\r\n if (token) {\r\n urlObj.searchParams.set('token', token);\r\n }\r\n xhr.open('GET', urlObj.toString(), true);\r\n } catch (e) {\r\n console.error('[WebVideoPlayer tempHls] xhrSetup error:', e);\r\n }\r\n }\r\n });\r\n tempHls.loadSource(transformUrl(src));\r\n tempHls.attachMedia(tempVideo);\r\n } else {\r\n tempVideo.src = src;\r\n }\r\n\r\n // If readyState is already satisfied, start capturing immediately\r\n if (tempVideo.readyState >= 2) {\r\n startCapture();\r\n }\r\n\r\n const cleanup = () => {\r\n tempVideo.removeEventListener('seeked', onSeeked);\r\n tempVideo.removeEventListener('canplay', startCapture);\r\n if (tempHls) {\r\n tempHls.destroy();\r\n }\r\n if (document.body.contains(tempVideo)) {\r\n document.body.removeChild(tempVideo);\r\n }\r\n };\r\n\r\n return cleanup;\r\n }, [src, keyMomentsKey]);\r\n\r\n // Cast state\r\n const [castDevice, setCastDevice] = useState<string | null>(null);\r\n const [remoteState, setRemoteState] = useState<{ currentTime: number; duration: number; isPaused: boolean; volumeLevel: number; isMuted: boolean } | null>(null);\r\n const preCastMutedRef = useRef<boolean>(false);\r\n const [isAirPlayAvailable, setIsAirPlayAvailable] = useState(false);\r\n const [isAirPlayConnected, setIsAirPlayConnected] = useState(false);\r\n const [airPlayTargetName, setAirPlayTargetName] = useState<string | null>(null);\r\n\r\n // Scrubber Hover\r\n const [hoverX, setHoverX] = useState<number | null>(null);\r\n const [tooltipLeft, setTooltipLeft] = useState(0);\r\n const [hoverTime, setHoverTime] = useState<number>(0);\r\n const [hoverThumbnail, setHoverThumbnail] = useState<string | null>(null);\r\n const [hoverChapter, setHoverChapter] = useState<KeyMoment | null>(null);\r\n const [scrubbingTime, setScrubbingTime] = useState<number | null>(null);\r\n\r\n // Inject Native Google Cast Button (Invisible Overlay)\r\n useEffect(() => {\r\n if (castButtonRef.current && !castButtonRef.current.querySelector('google-cast-launcher')) {\r\n const launcher = document.createElement('google-cast-launcher');\r\n launcher.style.cursor = 'pointer';\r\n launcher.style.width = '100%';\r\n launcher.style.height = '100%';\r\n launcher.style.display = 'block';\r\n castButtonRef.current.appendChild(launcher);\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!player) {\r\n setIsAirPlayAvailable(false);\r\n setIsAirPlayConnected(false);\r\n setAirPlayTargetName(null);\r\n return;\r\n }\r\n\r\n const updateAvailability = (available: boolean) => setIsAirPlayAvailable(available);\r\n const updateConnection = () => {\r\n const video = player.getVideoElement();\r\n const anyVideo = video as any;\r\n const connected = Boolean(anyVideo?.webkitCurrentPlaybackTargetIsWireless);\r\n setIsAirPlayConnected(connected);\r\n setAirPlayTargetName(\r\n connected\r\n ? anyVideo.webkitCurrentPlaybackTargetName || 'AirPlay device'\r\n : null\r\n );\r\n };\r\n\r\n updateAvailability(player.casting.isAirPlayAvailable());\r\n updateConnection();\r\n\r\n const video = player.getVideoElement();\r\n const availabilityHandler = (event: any) => {\r\n updateAvailability(event.availability === 'available');\r\n };\r\n const connectionHandler = () => {\r\n updateConnection();\r\n };\r\n\r\n if ('webkitShowPlaybackTargetPicker' in video) {\r\n video.addEventListener('webkitplaybacktargetavailabilitychanged', availabilityHandler as EventListener);\r\n video.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', connectionHandler as EventListener);\r\n }\r\n\r\n return () => {\r\n if ('webkitShowPlaybackTargetPicker' in video) {\r\n video.removeEventListener('webkitplaybacktargetavailabilitychanged', availabilityHandler as EventListener);\r\n video.removeEventListener('webkitcurrentplaybacktargetiswirelesschanged', connectionHandler as EventListener);\r\n }\r\n };\r\n }, [player]);\r\n\r\n // Control UI visibility timeout\r\n const [extractedTitle, setExtractedTitle] = useState('');\r\n const [controlsVisible, setControlsVisible] = useState(true);\r\n const [isAdPlaying, setIsAdPlaying] = useState(false);\r\n const controlsTimeoutRef = useRef<number | null>(null);\r\n // Ref so the timeout callback always reads the *current* isPlaying value (avoids stale closure)\r\n const isPlayingRef = useRef(false);\r\n const isAdPlayingRef = useRef(false);\r\n const activeMenuRef = useRef<typeof activeMenu>('none');\r\n const availableSubtitlesRef = useRef<SubtitleTrack[]>(subtitles);\r\n\r\n const resetControlsTimer = () => {\r\n setControlsVisible(true);\r\n if (controlsTimeoutRef.current) {\r\n window.clearTimeout(controlsTimeoutRef.current);\r\n }\r\n const delay = isMobileRef.current ? 3500 : 10000;\r\n controlsTimeoutRef.current = window.setTimeout(() => {\r\n if (isPlayingRef.current && activeMenuRef.current === 'none') {\r\n setControlsVisible(false);\r\n }\r\n }, delay);\r\n };\r\n\r\n // Falls back to the first source when the source the user switched to can't be played.\r\n // Uses refs only, so it's safe to call from inside the player effect closure regardless\r\n // of when it was captured. Keeps sourceChangeSeekRef intact so the fallback source\r\n // resumes at the position the user was watching.\r\n const runSourceFallback = useCallback((failedIdx: number) => {\r\n if (sourceChangeFallbackTimerRef.current) {\r\n clearTimeout(sourceChangeFallbackTimerRef.current);\r\n sourceChangeFallbackTimerRef.current = null;\r\n }\r\n const srcs = sourcesRef.current;\r\n const failedLabel = srcs?.[failedIdx]?.label ?? 'This format';\r\n const fallbackLabel = srcs?.[0]?.label ?? 'default';\r\n pendingSourceSwitchRef.current = null;\r\n setSourceFallbackNotice(`${failedLabel} isn't supported on this device. Switched to ${fallbackLabel}.`);\r\n window.setTimeout(() => setSourceFallbackNotice(null), 4000);\r\n onSourceChangeRef.current?.(0);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n // ── Hidden video for position-accurate thumbnail capture ──────────────\r\n const hiddenVideo = document.createElement('video');\r\n hiddenVideo.muted = true;\r\n hiddenVideo.preload = 'metadata';\r\n hiddenVideo.crossOrigin = 'anonymous';\r\n hiddenVideo.style.cssText = 'display:none;position:absolute;pointer-events:none;';\r\n document.body.appendChild(hiddenVideo);\r\n hiddenVideoRef.current = hiddenVideo;\r\n\r\n const isHls = src.includes('.m3u8');\r\n if (isHls && Hls.isSupported()) {\r\n const hls = new Hls({\r\n enableWorker: false,\r\n maxBufferLength: 5,\r\n xhrSetup: (xhr, url) => {\r\n const token = drmConfig?.authToken;\r\n try {\r\n const proxiedUrl = transformUrl(url);\r\n const urlObj = new URL(proxiedUrl, window.location.origin);\r\n if (token) {\r\n urlObj.searchParams.set('token', token);\r\n }\r\n xhr.open('GET', urlObj.toString(), true);\r\n } catch (e) {\r\n console.error('[WebVideoPlayer hiddenHls] xhrSetup error:', e);\r\n }\r\n }\r\n });\r\n hls.loadSource(transformUrl(src));\r\n hls.attachMedia(hiddenVideo);\r\n hiddenHlsRef.current = hls;\r\n\r\n hls.on(Hls.Events.MANIFEST_LOADED, (_e: string, data: { networkDetails?: { responseText?: string } }) => {\r\n if (title) return;\r\n const found = extractTitleFromManifest(data?.networkDetails?.responseText ?? '');\r\n if (found) setExtractedTitle(found);\r\n });\r\n\r\n hls.on(Hls.Events.FRAG_PARSING_METADATA, (_e: string, data: { samples?: Array<{ data: Uint8Array }> }) => {\r\n if (title || extractedTitle) return;\r\n for (const sample of data?.samples ?? []) {\r\n const found = parseID3Title(sample.data);\r\n if (found) { setExtractedTitle(found); break; }\r\n }\r\n });\r\n } else if (isHls && hiddenVideo.canPlayType('application/vnd.apple.mpegurl')) {\r\n hiddenVideo.src = src;\r\n } else {\r\n hiddenVideo.src = src;\r\n }\r\n\r\n const onSeeked = () => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (ctx && hiddenVideo.readyState >= 2) {\r\n ctx.drawImage(hiddenVideo, 0, 0, canvas.width, canvas.height);\r\n const dataUrl = canvas.toDataURL('image/jpeg', 0.82);\r\n setHoverThumbnail(dataUrl);\r\n }\r\n };\r\n hiddenVideo.addEventListener('seeked', onSeeked);\r\n\r\n // ── Firebase Analytics Provider ───────────────────────────────────────\r\n let firebaseCallback: ((event: import('@goboss/types').AnalyticsEvent) => void) | undefined;\r\n if (firebaseConfig) {\r\n const provider = new FirebaseAnalyticsProvider(firebaseConfig);\r\n firebaseProviderRef.current = provider;\r\n firebaseCallback = provider.createCallback();\r\n }\r\n\r\n // ── Main SDK player ───────────────────────────────────────────────────\r\n if (isEntitlementBlocked) {\r\n return;\r\n }\r\n\r\n const sdkInstance = new VideoPlayerSDK({\r\n container: containerRef.current,\r\n src,\r\n autoplay,\r\n muted,\r\n keyMoments: localKeyMoments,\r\n subtitles,\r\n drm: {\r\n watermarkText: watermark,\r\n allowedDomains: ['localhost', '127.0.0.1', window.location.hostname],\r\n ...drmConfig,\r\n },\r\n analyticsCallback: (event) => {\r\n firebaseCallback?.(event);\r\n if (onAnalyticsEvent) onAnalyticsEvent(event);\r\n },\r\n watchProgressInterval: watchProgressInterval * 1000,\r\n themeColor,\r\n urlTransformer,\r\n });\r\n\r\n sdkInstance.on('keymomentsloaded', (parsedKeyMoments: KeyMoment[]) => {\r\n setLocalKeyMoments(parsedKeyMoments);\r\n if (onKeyMomentsLoaded) {\r\n onKeyMomentsLoaded(parsedKeyMoments);\r\n }\r\n });\r\n\r\n sdkInstance.on('chaptersloaded', (parsedChapters: Chapter[]) => {\r\n setLocalKeyMoments(parsedChapters);\r\n if (onKeyMomentsLoaded) {\r\n onKeyMomentsLoaded(parsedChapters);\r\n }\r\n });\r\n\r\n // Subscriptions to core player events\r\n sdkInstance.on('play', () => {\r\n setIsPlaying(true);\r\n setIsEnded(false);\r\n });\r\n sdkInstance.on('pause', () => setIsPlaying(false));\r\n sdkInstance.on('ended', () => {\r\n setIsPlaying(false);\r\n setIsEnded(true);\r\n });\r\n // Shared helper — hide video, seek to endTime, restore once the seek lands.\r\n // All ad-skip paths (timeupdate pre-skip and adbreakchange fallback) use this\r\n // so opacity management and the guard timeout are always in sync.\r\n const showAdSkipCover = () => {\r\n // opacity change on a will-change:opacity element is a pure compositor operation —\r\n // no layout/paint required, takes effect in the current composite frame.\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '1';\r\n };\r\n\r\n const hideAdSkipCover = () => {\r\n // Double rAF: wait for the browser to commit a fresh post-seek content frame\r\n // before removing the cover, so no ad frame bleeds through.\r\n requestAnimationFrame(() => {\r\n requestAnimationFrame(() => {\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '0';\r\n });\r\n });\r\n };\r\n\r\n const triggerAdSkip = (endTime: number) => {\r\n isSeeking.current = true;\r\n // If this skip is part of a seek-forward redirect, jump straight to the user's original\r\n // target in one seek. This avoids a double-seek race: without this, triggerAdSkip would\r\n // seek to adEnd+0.5, then adbreakchange(false) would immediately seek again to the\r\n // pending target — the timeupdate from the first seek would fire between the two seeks\r\n // with seekTargetTime already updated to the second target, triggering a false \"landed\"\r\n // detection and prematurely hiding the cover before the second seek completes.\r\n const skipTarget = pendingSeekTargetRef.current ?? endTime + 0.5;\r\n pendingSeekTargetRef.current = null;\r\n seekTargetTime.current = skipTarget;\r\n showAdSkipCover();\r\n sdkInstance.seek(skipTarget);\r\n if (seekGuardTimeout.current) window.clearTimeout(seekGuardTimeout.current);\r\n seekGuardTimeout.current = window.setTimeout(() => {\r\n isSeeking.current = false;\r\n seekTargetTime.current = null;\r\n seekGuardTimeout.current = null;\r\n hideAdSkipCover();\r\n }, 3000);\r\n };\r\n\r\n triggerAdSkipRef.current = triggerAdSkip;\r\n\r\n sdkInstance.on('timeupdate', (time: number) => {\r\n // Pre-skip already-watched ad breaks. The 500 ms look-ahead guarantees the cover\r\n // goes up before the first ad frame even on slow systems where timeupdate fires as\r\n // infrequently as every 500 ms. The lower bound prevents repeat triggers while the\r\n // user is watching content well before the break.\r\n if (!isSeeking.current) {\r\n const watchedBreak = adBreaksRef.current.find(\r\n b => watchedAdBreaksRef.current.has(b.startTime)\r\n && time >= b.startTime - 0.5\r\n && time < b.endTime\r\n );\r\n if (watchedBreak) {\r\n triggerAdSkip(watchedBreak.endTime);\r\n return;\r\n }\r\n }\r\n\r\n // Guard against stale timeupdates while a seek is in progress.\r\n // One-sided check: consider the seek landed once time >= target - 2s.\r\n // This handles HLS keyframe snapping (typically ±2s) without the symmetric window\r\n // catching stale timeupdates that arrive well before the target.\r\n if (isSeeking.current && seekTargetTime.current !== null) {\r\n if (time >= seekTargetTime.current - 2.0) {\r\n // Seek landed — clear flag and allow normal updates.\r\n // Only restore opacity if we actually landed in content. HLS keyframe snapping\r\n // can place us slightly before endTime (still inside the ad); in that case keep\r\n // opacity at 0 — the watched-break check above will re-trigger the skip on the\r\n // very next timeupdate without any visible flash.\r\n isSeeking.current = false;\r\n seekTargetTime.current = null;\r\n if (seekGuardTimeout.current) {\r\n window.clearTimeout(seekGuardTimeout.current);\r\n seekGuardTimeout.current = null;\r\n }\r\n const landedInAd = adBreaksRef.current.some(\r\n b => time >= b.startTime && time < b.endTime\r\n );\r\n if (!landedInAd) {\r\n hideAdSkipCover();\r\n }\r\n } else {\r\n // Still seeking — skip this stale update\r\n return;\r\n }\r\n }\r\n\r\n setCurrentTime(time);\r\n const dur = sdkInstance.getDuration();\r\n setDuration(dur);\r\n\r\n // Apply one-time seek to resume position once the stream has a valid duration\r\n if (!initialSeekAppliedRef.current && initialTime && initialTime > 0 && dur > 0 && initialTime < dur) {\r\n initialSeekAppliedRef.current = true;\r\n sdkInstance.seek(initialTime);\r\n }\r\n\r\n onTimeUpdate?.(time);\r\n\r\n // Overlay (non-linear) ad: driven by content time, not wall-clock\r\n if (overlayAdsRef.current.length > 0) {\r\n if (activeOverlayRef.current) {\r\n const o = activeOverlayRef.current;\r\n const endTime = o.startTimeSeconds + o.durationSeconds;\r\n if (time >= endTime || time < o.startTimeSeconds) {\r\n setActiveOverlay(null);\r\n activeOverlayRef.current = null;\r\n }\r\n } else {\r\n const due = overlayAdsRef.current.find(\r\n o => time >= o.startTimeSeconds\r\n && time < o.startTimeSeconds + o.durationSeconds\r\n && !dismissedOverlayIdsRef.current.has(o.availId)\r\n );\r\n if (due) {\r\n setActiveOverlay(due);\r\n activeOverlayRef.current = due;\r\n due.impressionBeacons.forEach(url => { fetch(url, { mode: 'no-cors' }).catch(() => {}); });\r\n }\r\n }\r\n }\r\n\r\n // Update chapter badge\r\n const activeCh = sdkInstance.keyMoments.getCurrentMoment(time);\r\n setActiveChapter({ chapter: activeCh.keyMoment, index: activeCh.index });\r\n\r\n // Keep the browser's media-session position in sync so native PiP controls\r\n // (iOS Safari, macOS, etc.) display the correct timeline.\r\n // During an ad break, show ad-relative timing so the PiP seek bar reflects the ad's\r\n // duration and position. Outside ads, show content-relative timing as normal.\r\n if ('mediaSession' in navigator && navigator.mediaSession.setPositionState) {\r\n const rawDuration = sdkInstance.getDuration();\r\n const activeAdBreak = adBreaksRef.current.find(ab => time >= ab.startTime && time < ab.endTime);\r\n if (activeAdBreak) {\r\n const adDur = activeAdBreak.endTime - activeAdBreak.startTime;\r\n const adPos = Math.max(0, time - activeAdBreak.startTime);\r\n if (adDur > 0) {\r\n try {\r\n navigator.mediaSession.setPositionState({\r\n duration: adDur,\r\n playbackRate: 1,\r\n position: Math.min(adPos, adDur),\r\n });\r\n } catch (_) { /* unsupported browser */ }\r\n }\r\n } else {\r\n const totalAdDur = adBreaksRef.current.reduce((s, ab) => s + (ab.endTime - ab.startTime), 0);\r\n const contentDur = rawDuration > 0 ? Math.max(0, rawDuration - totalAdDur) : 0;\r\n let ct = time;\r\n for (const ab of adBreaksRef.current) {\r\n if (time >= ab.endTime) ct -= (ab.endTime - ab.startTime);\r\n else if (time >= ab.startTime) ct -= (time - ab.startTime);\r\n }\r\n ct = Math.max(0, ct);\r\n const dispDur = adBreaksRef.current.length > 0 && contentDur > 0 ? contentDur : rawDuration;\r\n if (dispDur > 0) {\r\n try {\r\n navigator.mediaSession.setPositionState({\r\n duration: dispDur,\r\n playbackRate: 1,\r\n position: Math.min(ct, dispDur),\r\n });\r\n } catch (_) { /* unsupported browser */ }\r\n }\r\n }\r\n }\r\n });\r\n\r\n sdkInstance.on('qualitylevels', (levels: VideoQuality[]) => {\r\n setQualities(levels);\r\n });\r\n\r\n sdkInstance.on('qualitychange', (quality: VideoQuality) => {\r\n setActiveQuality(quality);\r\n });\r\n\r\n sdkInstance.on('buffering', (buffering: boolean) => {\r\n setIsBuffering(buffering);\r\n // 'buffering: false' maps to the native 'playing' event — proof that frames are\r\n // actually rendering. This is the success signal for a source switch.\r\n if (!buffering) {\r\n // Playback started — cancel the unsupported-format watchdog\r\n if (sourceChangeFallbackTimerRef.current) {\r\n clearTimeout(sourceChangeFallbackTimerRef.current);\r\n sourceChangeFallbackTimerRef.current = null;\r\n }\r\n pendingSourceSwitchRef.current = null;\r\n // Restore the playback position the user was at before the switch\r\n if (sourceChangeSeekRef.current !== null) {\r\n const seekTarget = sourceChangeSeekRef.current;\r\n sourceChangeSeekRef.current = null;\r\n sdkInstance.seek(seekTarget);\r\n }\r\n }\r\n });\r\n\r\n sdkInstance.on('adbreakchange', (active: boolean) => {\r\n sdkInstance.analytics.setAdBreak(active, sdkInstance.getVideoElement());\r\n if (onAdBreakChange) onAdBreakChange(active);\r\n if (active) {\r\n const currentT = sdkInstance.getCurrentTime();\r\n const currentBreak = adBreaksRef.current.find(b => currentT >= b.startTime && currentT < b.endTime);\r\n if (currentBreak && watchedAdBreaksRef.current.has(currentBreak.startTime)) {\r\n // Already watched — cover immediately (belt-and-suspenders with the timeupdate\r\n // pre-skip: if the 500ms look-ahead somehow missed this frame, adbreakchange is\r\n // the last synchronous chance to block it before the next compositor pass).\r\n showAdSkipCover();\r\n if (!isSeeking.current) {\r\n triggerAdSkip(currentBreak.endTime);\r\n }\r\n return;\r\n }\r\n if (currentBreak) {\r\n activeAdBreakStartRef.current = currentBreak.startTime;\r\n }\r\n setIsAdPlaying(true);\r\n setActiveMenu('none');\r\n } else {\r\n // Ad finished naturally — mark this break as watched for the rest of the session\r\n if (activeAdBreakStartRef.current !== null) {\r\n watchedAdBreaksRef.current.add(activeAdBreakStartRef.current);\r\n setWatchedAdBreaksSet(new Set(watchedAdBreaksRef.current));\r\n activeAdBreakStartRef.current = null;\r\n }\r\n setIsAdPlaying(false);\r\n\r\n // If this ad was part of a seek-forward redirect, resume at the original target.\r\n // Only one (nearest) ad is ever enforced per seek, so no further queuing needed.\r\n if (pendingSeekTargetRef.current !== null) {\r\n const target = pendingSeekTargetRef.current;\r\n pendingSeekTargetRef.current = null;\r\n isSeeking.current = true;\r\n seekTargetTime.current = target;\r\n sdkInstance.seek(target);\r\n if (seekGuardTimeout.current) window.clearTimeout(seekGuardTimeout.current);\r\n seekGuardTimeout.current = window.setTimeout(() => {\r\n isSeeking.current = false;\r\n seekTargetTime.current = null;\r\n seekGuardTimeout.current = null;\r\n }, 3000);\r\n }\r\n }\r\n });\r\n\r\n sdkInstance.on('adbreaksloaded', (breaks: Array<{ startTime: number; endTime: number }>) => {\r\n // Sync the ref immediately so timeupdate/adbreakchange handlers don't read a stale empty array\r\n // during the React render cycle that follows setAdBreaks.\r\n adBreaksRef.current = breaks;\r\n setAdBreaks(breaks);\r\n });\r\n\r\n sdkInstance.on('volumechange', (data: { volume: number; muted: boolean }) => {\r\n setVolume(data.volume);\r\n setIsMuted(data.muted);\r\n });\r\n\r\n sdkInstance.on('pipchange', (active: boolean) => {\r\n setIsPiP(active);\r\n });\r\n\r\n sdkInstance.on('error', () => {\r\n setPlayerError(true);\r\n setIsBuffering(false);\r\n });\r\n\r\n // Layer 1 (primary): the browser reported this stream's codecs as undecodable.\r\n // Only auto-fall back when this player was created by a user switch to a non-default\r\n // source and there's a first source to fall back to. The default source loading\r\n // normally never emits this, so default playback is unaffected.\r\n sdkInstance.on('unsupportedcodec', () => {\r\n const pending = pendingSourceSwitchRef.current;\r\n if (pending && pending.targetIdx !== 0 && (sourcesRef.current?.length ?? 0) > 1) {\r\n runSourceFallback(pending.targetIdx);\r\n }\r\n });\r\n\r\n // Subtitles track rendering hook\r\n sdkInstance.subtitles.onSubtitleChange((text: string) => {\r\n setSubtitleText(text);\r\n });\r\n\r\n sdkInstance.on('subtitlesloaded', (tracks: SubtitleTrack[]) => {\r\n // Subtitles are gated by the player-key entitlement — skip entirely when not enabled.\r\n if (!effectiveFeatures.enableSubtitles) return;\r\n\r\n setAvailableSubtitles(dedupeSubtitleTracks([...tracks]));\r\n\r\n // Auto-select default subtitle track\r\n const defaultTrack = tracks.find((t) => t.isDefault);\r\n if (defaultTrack) {\r\n sdkInstance.subtitles.setActiveTrack(defaultTrack.id);\r\n setActiveSubtitleTrack(defaultTrack.id);\r\n }\r\n });\r\n\r\n // Audio track discovery\r\n sdkInstance.on('audiotracksloaded', (tracks: Array<{ id: number; label: string; lang: string }>) => {\r\n setAudioTracks(tracks);\r\n setActiveAudioTrack(tracks[0]?.id ?? 0);\r\n });\r\n\r\n sdkInstance.on('audiotrackchange', (id: number) => {\r\n setActiveAudioTrack(id);\r\n });\r\n\r\n // Cast state syncer — pauses local video on cast start, restores on stop\r\n sdkInstance.casting.onCastStateChange((isCasting: boolean, deviceName: string) => {\r\n if (isCasting) {\r\n preCastMutedRef.current = sdkInstance.isMuted();\r\n sdkInstance.pause();\r\n // Mute local element so audio doesn't double-play\r\n const vid = sdkInstance.getVideoElement();\r\n vid.muted = true;\r\n setCastDevice(deviceName);\r\n } else {\r\n // Restore local video from where remote cast left off\r\n const remoteSnap = sdkInstance.casting.getRemoteState();\r\n if (remoteSnap && remoteSnap.currentTime > 0) {\r\n sdkInstance.seek(remoteSnap.currentTime);\r\n }\r\n const vid = sdkInstance.getVideoElement();\r\n vid.muted = preCastMutedRef.current;\r\n setCastDevice(null);\r\n setRemoteState(null);\r\n }\r\n });\r\n\r\n sdkInstance.casting.onRemoteStateChange((state) => {\r\n setRemoteState(state);\r\n });\r\n\r\n // Sync HTML5 video volume initially\r\n setVolume(sdkInstance.getVolume());\r\n setIsMuted(sdkInstance.isMuted());\r\n\r\n // When the user seeks from the native PiP window the browser fires this action with\r\n // a seek time expressed in the content timeline (because we set setPositionState with\r\n // content duration). Convert it back to raw video time then route through performSeek\r\n // so ad-break enforcement (block during ads, redirect over missed breaks) applies\r\n // identically to PiP seeks and normal seekbar seeks.\r\n if ('mediaSession' in navigator) {\r\n try {\r\n navigator.mediaSession.setActionHandler('seekto', (details) => {\r\n if (details.seekTime == null || isAdPlayingRef.current) return;\r\n let rawT = details.seekTime;\r\n for (const ab of adBreaksRef.current) {\r\n if (rawT >= ab.startTime) rawT += (ab.endTime - ab.startTime);\r\n }\r\n performSeekRef.current?.(rawT);\r\n });\r\n } catch (_) { /* unsupported browser */ }\r\n }\r\n\r\n setPlayer(sdkInstance);\r\n\r\n // Layer 2 (backstop): watchdog for streams whose codecs aren't declared in the manifest,\r\n // so Layer 1 has nothing to inspect. If this player was created by a switch to a\r\n // non-default source and real playback ('buffering: false') hasn't fired by the deadline,\r\n // decide based on the buffer:\r\n // • buffer still empty → segments downloaded but couldn't be decoded → fall back.\r\n // • buffer has grown → it's just a slow network, the format IS loading → keep waiting.\r\n // This buffer check is what prevents a valid-but-slow stream from being misjudged.\r\n // The timer is started here (not in handleSourceChange) so the source-switch re-init's\r\n // own cleanup doesn't clear it before it can fire.\r\n const pendingSwitch = pendingSourceSwitchRef.current;\r\n if (pendingSwitch && pendingSwitch.targetIdx !== 0) {\r\n if (sourceChangeFallbackTimerRef.current) {\r\n clearTimeout(sourceChangeFallbackTimerRef.current);\r\n }\r\n sourceChangeFallbackTimerRef.current = setTimeout(() => {\r\n sourceChangeFallbackTimerRef.current = null;\r\n const buffered = sdkInstance.getBufferedRanges();\r\n const hasBufferedData = buffered.some((r) => r.end > r.start);\r\n // Slow network — the chosen format is genuinely loading; don't interrupt it.\r\n if (hasBufferedData) return;\r\n runSourceFallback(pendingSwitch.targetIdx);\r\n }, SOURCE_FALLBACK_TIMEOUT_MS);\r\n }\r\n\r\n // Attempt fullscreen immediately on player init when autoFullscreen is requested.\r\n // Browsers allow this when the page was opened by a user action (URL entry, link click).\r\n if (autoFullscreen && containerRef.current) {\r\n hasAutoFullscreenedRef.current = true;\r\n containerRef.current.requestFullscreen().catch(() => {\r\n // Browser denied — video still autoplays in normal mode, no harm done\r\n hasAutoFullscreenedRef.current = false;\r\n });\r\n }\r\n\r\n // Watch for fullscreen change globally to sync state and track analytics\r\n const handleFullscreenChange = () => {\r\n const anyDoc = document as any;\r\n const isFs = !!(document.fullscreenElement || anyDoc.webkitFullscreenElement);\r\n setIsFullscreen(isFs);\r\n // Clear simulated fullscreen flag when native fullscreen exits\r\n if (!isFs) setIsSimulatedFullscreen(false);\r\n const videoEl = sdkInstance.getVideoElement();\r\n sdkInstance.analytics.track(\r\n isFs ? 'fullscreen_enter' : 'fullscreen_exit',\r\n videoEl\r\n );\r\n };\r\n document.addEventListener('fullscreenchange', handleFullscreenChange);\r\n document.addEventListener('webkitfullscreenchange', handleFullscreenChange);\r\n\r\n // Global keyboard controls handler\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n const activeEl = document.activeElement;\r\n if (activeEl && (\r\n activeEl.tagName === 'INPUT' ||\r\n activeEl.tagName === 'TEXTAREA' ||\r\n activeEl.getAttribute('contenteditable') === 'true' ||\r\n activeEl.getAttribute('role') === 'slider'\r\n )) {\r\n return;\r\n }\r\n\r\n switch (e.key.toLowerCase()) {\r\n case ' ': // Space bar\r\n case 'k':\r\n e.preventDefault();\r\n if (sdkInstance.getVideoElement().paused) {\r\n sdkInstance.play();\r\n } else {\r\n sdkInstance.pause();\r\n try {\r\n const v = sdkInstance.getVideoElement();\r\n if (v && !v.paused) v.pause();\r\n } catch (e) {}\r\n if (hiddenVideoRef.current && !hiddenVideoRef.current.paused) {\r\n try { hiddenVideoRef.current.pause(); } catch (e) {}\r\n }\r\n }\r\n break;\r\n case 'arrowleft': // Seek back 10s\r\n case 'j': {\r\n e.preventDefault();\r\n if (!isAdPlayingRef.current) {\r\n const rawT = sdkInstance.getCurrentTime();\r\n let ct = rawT;\r\n for (const ab of adBreaksRef.current) {\r\n if (rawT >= ab.endTime) ct -= (ab.endTime - ab.startTime);\r\n else if (rawT >= ab.startTime) ct -= (rawT - ab.startTime);\r\n }\r\n const newCt = Math.max(0, ct - 10);\r\n let newRaw = newCt;\r\n for (const ab of adBreaksRef.current) {\r\n if (newRaw >= ab.startTime) newRaw += (ab.endTime - ab.startTime);\r\n }\r\n sdkInstance.seek(newRaw);\r\n }\r\n break;\r\n }\r\n case 'arrowright': // Seek forward 10s\r\n case 'l': {\r\n e.preventDefault();\r\n if (!isAdPlayingRef.current) {\r\n const rawT = sdkInstance.getCurrentTime();\r\n const totalAdDur = adBreaksRef.current.reduce((s, ab) => s + (ab.endTime - ab.startTime), 0);\r\n const contentDur = Math.max(0, sdkInstance.getDuration() - totalAdDur);\r\n let ct = rawT;\r\n for (const ab of adBreaksRef.current) {\r\n if (rawT >= ab.endTime) ct -= (ab.endTime - ab.startTime);\r\n else if (rawT >= ab.startTime) ct -= (rawT - ab.startTime);\r\n }\r\n const newCt = Math.min(contentDur, ct + 10);\r\n let newRaw = newCt;\r\n for (const ab of adBreaksRef.current) {\r\n if (newRaw >= ab.startTime) newRaw += (ab.endTime - ab.startTime);\r\n }\r\n // Route through performSeek so any unwatched ad break in the skipped\r\n // range is enforced — same validation as scrubber and mobile buttons.\r\n performSeekRef.current?.(newRaw);\r\n }\r\n break;\r\n }\r\n case 'arrowup': // Volume up 10%\r\n e.preventDefault();\r\n sdkInstance.setVolume(sdkInstance.getVolume() + 0.1);\r\n break;\r\n case 'arrowdown': // Volume down 10%\r\n e.preventDefault();\r\n sdkInstance.setVolume(sdkInstance.getVolume() - 0.1);\r\n break;\r\n case 'm': // Toggle Mute\r\n e.preventDefault();\r\n sdkInstance.setMute(!sdkInstance.isMuted());\r\n break;\r\n case 'f': // Toggle Fullscreen\r\n e.preventDefault();\r\n toggleFullscreenRef.current();\r\n break;\r\n case 'p': // Toggle Picture-in-Picture\r\n e.preventDefault();\r\n if (!isAdPlayingRef.current) sdkInstance.togglePictureInPicture();\r\n break;\r\n case 'c': // Toggle Subtitles\r\n e.preventDefault();\r\n if (effectiveFeatures.enableSubtitles && !isAdPlayingRef.current) {\r\n const activeTrackId = sdkInstance.subtitles.getActiveTrackId();\r\n if (activeTrackId !== 'off') {\r\n sdkInstance.subtitles.setActiveTrack('off');\r\n setActiveSubtitleTrack('off');\r\n } else {\r\n const tracks = availableSubtitlesRef.current;\r\n if (tracks && tracks.length > 0) {\r\n sdkInstance.subtitles.setActiveTrack(tracks[0].id);\r\n setActiveSubtitleTrack(tracks[0].id);\r\n }\r\n }\r\n }\r\n break;\r\n default:\r\n return;\r\n }\r\n resetControlsTimer();\r\n };\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n\r\n // Reset controls visibility timer\r\n resetControlsTimer();\r\n\r\n return () => {\r\n sdkInstance.destroy();\r\n firebaseProviderRef.current?.destroy();\r\n firebaseProviderRef.current = null;\r\n // Restore body scroll in case the component unmounts while simulated fullscreen is active\r\n document.body.style.overflow = '';\r\n document.body.style.touchAction = '';\r\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\r\n document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);\r\n document.removeEventListener('keydown', handleKeyDown);\r\n if (controlsTimeoutRef.current) {\r\n window.clearTimeout(controlsTimeoutRef.current);\r\n }\r\n // Cancel any in-flight ad-skip seek and remove the cover so the player is\r\n // never left blacked-out if the component unmounts mid-skip.\r\n if (seekGuardTimeout.current) {\r\n window.clearTimeout(seekGuardTimeout.current);\r\n seekGuardTimeout.current = null;\r\n }\r\n if (sourceChangeFallbackTimerRef.current) {\r\n clearTimeout(sourceChangeFallbackTimerRef.current);\r\n sourceChangeFallbackTimerRef.current = null;\r\n }\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '0';\r\n if ('mediaSession' in navigator) {\r\n try { navigator.mediaSession.setActionHandler('seekto', null); } catch (_) {}\r\n }\r\n if (hiddenHlsRef.current) {\r\n hiddenHlsRef.current.destroy();\r\n hiddenHlsRef.current = null;\r\n }\r\n if (hiddenVideoRef.current) {\r\n document.body.removeChild(hiddenVideoRef.current);\r\n hiddenVideoRef.current = null;\r\n }\r\n initialSeekAppliedRef.current = false;\r\n };\r\n }, [src, watermark, retryKey]);\r\n\r\n // Synchronize key moments prop dynamically to the running player instance\r\n useEffect(() => {\r\n if (player) {\r\n player.keyMoments.setKeyMoments(localKeyMoments);\r\n \r\n const video = containerRef.current?.querySelector('video');\r\n if (video) {\r\n const activeCh = player.keyMoments.getCurrentMoment(video.currentTime);\r\n setActiveChapter({ chapter: activeCh.keyMoment, index: activeCh.index });\r\n }\r\n }\r\n }, [keyMomentsKey, player]);\r\n\r\n // Close any open control drop-up menu when clicking outside of it\r\n useEffect(() => {\r\n const handleDocumentClick = (e: MouseEvent) => {\r\n if (activeMenu === 'none') return;\r\n\r\n const target = e.target as HTMLElement;\r\n if (target.closest('.sdk-menu-container')) {\r\n return;\r\n }\r\n\r\n setActiveMenu('none');\r\n };\r\n\r\n document.addEventListener('click', handleDocumentClick);\r\n return () => {\r\n document.removeEventListener('click', handleDocumentClick);\r\n };\r\n }, [activeMenu]);\r\n\r\n // Keep refs in sync with latest state so timeout callbacks are never stale\r\n useEffect(() => { isPlayingRef.current = isPlaying; }, [isPlaying]);\r\n useEffect(() => { isAdPlayingRef.current = isAdPlaying; }, [isAdPlaying]);\r\n useEffect(() => { activeMenuRef.current = activeMenu; }, [activeMenu]);\r\n useEffect(() => { availableSubtitlesRef.current = availableSubtitles; }, [availableSubtitles]);\r\n useEffect(() => { isMobileRef.current = isMobile; }, [isMobile]);\r\n useEffect(() => { adBreaksRef.current = adBreaks; }, [adBreaks]);\r\n useEffect(() => { overlayAdsRef.current = overlayAds; }, [overlayAds]);\r\n useEffect(() => { activeOverlayRef.current = activeOverlay; }, [activeOverlay]);\r\n useEffect(() => { availsSkipInfoRef.current = availsSkipInfo; }, [availsSkipInfo]);\r\n useEffect(() => { sourcesRef.current = sources; }, [sources]);\r\n useEffect(() => { onSourceChangeRef.current = onSourceChange; }, [onSourceChange]);\r\n useEffect(() => {\r\n watchedAdBreaksRef.current = new Set();\r\n // No setState needed — activeWatchedAdBreaks auto-resets because src changed.\r\n activeAdBreakStartRef.current = null;\r\n wasAdPausedByVisibilityRef.current = false;\r\n pendingSeekTargetRef.current = null;\r\n // Reset overlay ad state on source change\r\n setActiveOverlay(null);\r\n activeOverlayRef.current = null;\r\n dismissedOverlayIdsRef.current = new Set();\r\n setPlayerError(false);\r\n }, [src]);\r\n\r\n // Fetch and parse overlay (non-linear) ad metadata\r\n useEffect(() => {\r\n setOverlayAds([]);\r\n if (!overlayAdUrl) return;\r\n fetch(overlayAdUrl)\r\n .then(r => r.json())\r\n .then((data: any) => {\r\n const seen = new Set<string>();\r\n const parsed: OverlayAdItem[] = [];\r\n for (const avail of (data.nonLinearAvails ?? [])) {\r\n if (seen.has(avail.availId)) continue;\r\n seen.add(avail.availId);\r\n const adsList = avail.nonLinearAdsList?.[0];\r\n const ad = adsList?.nonLinearAdList?.[0];\r\n if (!ad?.staticResource) continue;\r\n const impressionBeacons: string[] = (adsList?.trackingEvents ?? [])\r\n .filter((e: any) => e.eventType === 'impression')\r\n .flatMap((e: any) => e.beaconUrls ?? []);\r\n let adParams: { position?: string; dismissible?: boolean } = {};\r\n try { adParams = JSON.parse(ad.adParameters ?? '{}'); } catch (_) {}\r\n const position = adParams.position ?? 'bottom_center';\r\n parsed.push({\r\n availId: avail.availId,\r\n startTimeSeconds: parseHHMMSS(avail.startTime ?? ''),\r\n durationSeconds: parseHHMMSS(ad.minSuggestedDuration ?? '00:00:15'),\r\n imageUrl: ad.staticResource,\r\n imageWidth: parseInt(ad.width ?? '320', 10),\r\n imageHeight: parseInt(ad.height ?? '50', 10),\r\n title: ad.adTitle ?? '',\r\n clickThrough: ad.clickThrough ?? '',\r\n clickTrackingUrl: ad.clickTracking ?? '',\r\n impressionBeacons,\r\n position,\r\n dismissible: adParams.dismissible === true,\r\n });\r\n }\r\n setOverlayAds(parsed);\r\n })\r\n .catch(() => {});\r\n }, [overlayAdUrl, src]);\r\n\r\n // Fetch and parse avails (linear ad) skip metadata\r\n useEffect(() => {\r\n setAvailsSkipInfo([]);\r\n if (!adTrackingUrl) return;\r\n fetch(adTrackingUrl)\r\n .then(r => r.json())\r\n .then((data: any) => {\r\n const parsed: AvailSkipInfo[] = (data.avails ?? []).map((avail: any) => {\r\n const skipOffset: string | null = avail.ads?.[0]?.skipOffset ?? null;\r\n const skippable = !!skipOffset;\r\n return {\r\n startTimeSeconds: avail.startTimeInSeconds ?? 0,\r\n durationSeconds: avail.durationInSeconds ?? 0,\r\n skippable,\r\n skipOffsetSeconds: skippable ? parseHHMMSS(skipOffset!) : 0,\r\n };\r\n });\r\n setAvailsSkipInfo(parsed);\r\n })\r\n .catch(() => {});\r\n }, [adTrackingUrl, src]);\r\n\r\n // Feed avails-derived ad breaks into core-player so adbreakchange, cue markers,\r\n // and ad mode all work even when the HLS manifest parser doesn't detect them.\r\n // Runs whenever the player initialises or avails data arrives (whichever is last).\r\n useEffect(() => {\r\n if (!player || availsSkipInfo.length === 0) return;\r\n const breaks = availsSkipInfo.map(a => ({\r\n startTime: a.startTimeSeconds,\r\n endTime: a.startTimeSeconds + a.durationSeconds,\r\n }));\r\n player.setAdBreaks(breaks);\r\n }, [player, availsSkipInfo]);\r\n\r\n useEffect(() => {\r\n if (!player) return;\r\n\r\n const handleVisibilityChange = () => {\r\n if (document.hidden) {\r\n if (pauseAdOnTabSwitch && isAdPlayingRef.current) {\r\n player.pause();\r\n wasAdPausedByVisibilityRef.current = true;\r\n }\r\n } else {\r\n if (wasAdPausedByVisibilityRef.current) {\r\n player.play();\r\n wasAdPausedByVisibilityRef.current = false;\r\n }\r\n }\r\n };\r\n\r\n document.addEventListener('visibilitychange', handleVisibilityChange);\r\n return () => {\r\n document.removeEventListener('visibilitychange', handleVisibilityChange);\r\n };\r\n }, [player, pauseAdOnTabSwitch]);\r\n\r\n const handleMouseMove = () => {\r\n resetControlsTimer();\r\n };\r\n\r\n const triggerAutoFullscreen = () => {\r\n if (autoFullscreen && !hasAutoFullscreenedRef.current && containerRef.current) {\r\n hasAutoFullscreenedRef.current = true;\r\n containerRef.current.requestFullscreen().catch(() => {});\r\n }\r\n };\r\n\r\n\r\n const togglePlay = () => {\r\n if (!player) return;\r\n if (castDevice) {\r\n player.casting.remotePlayPause();\r\n resetControlsTimer();\r\n return;\r\n }\r\n if (isEnded) {\r\n performSeek(0);\r\n triggerAutoFullscreen();\r\n player.play();\r\n setIsEnded(false);\r\n } else if (isPlaying) {\r\n player.pause();\r\n // Ensure all underlying HTMLMediaElements are paused as a defensive measure\r\n try {\r\n const videoEl = player.getVideoElement?.();\r\n if (videoEl && !videoEl.paused) videoEl.pause();\r\n } catch (e) {}\r\n if (containerRef.current) {\r\n const vids = containerRef.current.querySelectorAll('video');\r\n vids.forEach(v => { try { (v as HTMLVideoElement).pause(); } catch (e) {} });\r\n }\r\n if (hiddenVideoRef.current && !hiddenVideoRef.current.paused) {\r\n try { hiddenVideoRef.current.pause(); } catch (e) {}\r\n }\r\n } else {\r\n triggerAutoFullscreen();\r\n player.play();\r\n }\r\n resetControlsTimer();\r\n };\r\n\r\n const seekFromEvent = (e: React.MouseEvent<HTMLDivElement> | MouseEvent) => {\r\n if (!seekbarRef.current || !player || displayDuration === 0) return 0;\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));\r\n return contentTimeToVideoTime(percent * displayDuration);\r\n };\r\n\r\n const handleSeekMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {\r\n if (!player || isAdPlaying) return;\r\n isScrubbing.current = true;\r\n const initialTime = seekFromEvent(e);\r\n setScrubbingTime(initialTime);\r\n\r\n const onMouseMove = (ev: MouseEvent) => {\r\n if (!isScrubbing.current || !seekbarRef.current) return;\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n const percent = Math.max(0, Math.min(1, (ev.clientX - rect.left) / rect.width));\r\n const targetTime = contentTimeToVideoTime(percent * displayDuration);\r\n\r\n setScrubbingTime(targetTime);\r\n setHoverX(ev.clientX - rect.left);\r\n setHoverTime(targetTime);\r\n\r\n if (hiddenVideoRef.current) {\r\n hiddenVideoRef.current.currentTime = targetTime;\r\n }\r\n resetControlsTimer();\r\n };\r\n\r\n const onMouseUp = (ev: MouseEvent) => {\r\n isScrubbing.current = false;\r\n if (seekbarRef.current) {\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n const percent = Math.max(0, Math.min(1, (ev.clientX - rect.left) / rect.width));\r\n performSeek(contentTimeToVideoTime(percent * displayDuration));\r\n }\r\n setScrubbingTime(null);\r\n setHoverX(null);\r\n setHoverThumbnail(null);\r\n setHoverChapter(null);\r\n document.removeEventListener('mousemove', onMouseMove);\r\n document.removeEventListener('mouseup', onMouseUp);\r\n };\r\n\r\n document.addEventListener('mousemove', onMouseMove);\r\n document.addEventListener('mouseup', onMouseUp);\r\n };\r\n\r\n const performSeek = (time: number) => {\r\n if (!player) return;\r\n if (castDevice) {\r\n player.casting.remoteSeek(time);\r\n return;\r\n }\r\n // Clamp to valid range so time never goes negative or past duration\r\n const clampedTime = Math.max(0, duration > 0 ? Math.min(time, duration) : time);\r\n\r\n // Forward seek: enforce any unplayed ad breaks in the skipped range.\r\n // Find breaks whose startTime lies strictly between the current position and the\r\n // seek target and have not yet been watched this session.\r\n const rawCurrentTime = player.getCurrentTime();\r\n if (clampedTime > rawCurrentTime && adBreaksRef.current.length > 0) {\r\n const missed = adBreaksRef.current\r\n .filter(b =>\r\n b.startTime > rawCurrentTime &&\r\n b.startTime < clampedTime &&\r\n !watchedAdBreaksRef.current.has(b.startTime)\r\n )\r\n .sort((a, b) => a.startTime - b.startTime);\r\n\r\n if (missed.length > 0) {\r\n // Only enforce the nearest (last) missed ad before the target — earlier skipped\r\n // breaks are left unwatched. After that single ad plays, adbreakchange(false)\r\n // resumes at the original target directly.\r\n pendingSeekTargetRef.current = clampedTime;\r\n const redirectTarget = missed[missed.length - 1].startTime;\r\n isSeeking.current = true;\r\n seekTargetTime.current = redirectTarget;\r\n setCurrentTime(redirectTarget);\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '0';\r\n player.seek(redirectTarget);\r\n if (seekGuardTimeout.current) window.clearTimeout(seekGuardTimeout.current);\r\n seekGuardTimeout.current = window.setTimeout(() => {\r\n isSeeking.current = false;\r\n seekTargetTime.current = null;\r\n seekGuardTimeout.current = null;\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '0';\r\n }, 3000);\r\n return;\r\n }\r\n }\r\n\r\n // No missed ads (backward seek, or all breaks already watched) — seek normally.\r\n // Also clear any stale pending target so a previous queue doesn't interfere.\r\n pendingSeekTargetRef.current = null;\r\n isSeeking.current = true;\r\n seekTargetTime.current = clampedTime;\r\n setCurrentTime(clampedTime);\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '0';\r\n player.seek(clampedTime);\r\n if (seekGuardTimeout.current) window.clearTimeout(seekGuardTimeout.current);\r\n seekGuardTimeout.current = window.setTimeout(() => {\r\n isSeeking.current = false;\r\n seekTargetTime.current = null;\r\n seekGuardTimeout.current = null;\r\n if (adSkipCoverRef.current) adSkipCoverRef.current.style.opacity = '0';\r\n }, 3000);\r\n };\r\n\r\n // Keep ref current on every render so the keyboard handler (inside the useEffect\r\n // closure) always calls the latest performSeek with up-to-date state.\r\n performSeekRef.current = performSeek;\r\n\r\n const toggleMute = () => {\r\n if (!player) return;\r\n if (castDevice) {\r\n player.casting.remoteSetMute(!(remoteState?.isMuted ?? false));\r\n return;\r\n }\r\n const nextMute = !isMuted;\r\n player.setMute(nextMute);\r\n setIsMuted(nextMute);\r\n };\r\n\r\n const handleSpeedChange = (rate: number) => {\r\n if (!player) return;\r\n player.setPlaybackRate(rate);\r\n setPlaybackRate(rate);\r\n setActiveMenu('none');\r\n setAnnouncement(`Playback speed: ${rate === 1 ? 'Normal' : `${rate}x`}`);\r\n };\r\n\r\n const handleQualityChange = (qualityId: number) => {\r\n if (!player) return;\r\n player.setQuality(qualityId);\r\n\r\n const selected = qualities.find((q) => q.id === qualityId);\r\n if (selected) {\r\n setActiveQuality(selected);\r\n setAnnouncement(`Quality: ${selected.label}`);\r\n }\r\n setActiveMenu('none');\r\n };\r\n\r\n const handleSubtitleChange = (trackId: string) => {\r\n if (!player) return;\r\n player.subtitles.setActiveTrack(trackId);\r\n setActiveSubtitleTrack(trackId);\r\n setActiveMenu('none');\r\n if (trackId === 'off') {\r\n setAnnouncement('Captions off');\r\n } else {\r\n const track = availableSubtitles.find((t) => t.id === trackId);\r\n setAnnouncement(`Captions: ${track ? getLanguageLabel(track) : 'on'}`);\r\n }\r\n };\r\n\r\n const handleSourceChange = (idx: number) => {\r\n if (!player) return;\r\n // Clear any previous fallback watchdog before starting a new switch\r\n if (sourceChangeFallbackTimerRef.current) {\r\n clearTimeout(sourceChangeFallbackTimerRef.current);\r\n sourceChangeFallbackTimerRef.current = null;\r\n }\r\n setSourceFallbackNotice(null);\r\n // Save current position so the new source resumes where the user left off.\r\n // Only capture a fresh position if the previous switch already resolved — otherwise\r\n // the current player may be a stalled (unsupported) source sitting at 0, and we want\r\n // to keep the original position the user was actually watching.\r\n if (pendingSourceSwitchRef.current === null) {\r\n sourceChangeSeekRef.current = player.getCurrentTime();\r\n }\r\n // Flag the switch so the new player's effect starts the unsupported-format watchdog\r\n pendingSourceSwitchRef.current = { targetIdx: idx };\r\n setActiveMenu('none');\r\n setAnnouncement(`Source: ${sources?.[idx]?.label ?? ''}`);\r\n onSourceChange?.(idx);\r\n };\r\n\r\n const handleChapterClick = (startTime: number) => {\r\n performSeek(startTime);\r\n setActiveMenu('none');\r\n };\r\n\r\n const togglePiP = () => {\r\n if (!player) return;\r\n player.togglePictureInPicture();\r\n };\r\n\r\n const toggleFullscreen = () => {\r\n if (!containerRef.current) return;\r\n const container = containerRef.current;\r\n const anyDoc = document as any;\r\n const anyContainer = container as any;\r\n const isNativeFs = !!(document.fullscreenElement || anyDoc.webkitFullscreenElement);\r\n\r\n const enterSimulated = () => {\r\n setIsSimulatedFullscreen(true);\r\n setIsFullscreen(true);\r\n document.body.style.overflow = 'hidden';\r\n document.body.style.touchAction = 'none';\r\n player?.analytics.track('fullscreen_enter', player.getVideoElement());\r\n };\r\n\r\n const exitSimulated = () => {\r\n setIsSimulatedFullscreen(false);\r\n setIsFullscreen(false);\r\n document.body.style.overflow = '';\r\n document.body.style.touchAction = '';\r\n player?.analytics.track('fullscreen_exit', player.getVideoElement());\r\n };\r\n\r\n if (isNativeFs || isSimulatedFullscreen) {\r\n setWasMobileOnFullscreenEnter(false);\r\n if (document.fullscreenElement) {\r\n document.exitFullscreen();\r\n } else if (anyDoc.webkitFullscreenElement) {\r\n anyDoc.webkitExitFullscreen?.();\r\n } else {\r\n exitSimulated();\r\n }\r\n } else {\r\n setWasMobileOnFullscreenEnter(isMobileRef.current);\r\n const requestFs: (() => Promise<void>) | undefined =\r\n container.requestFullscreen?.bind(container) ??\r\n anyContainer.webkitRequestFullscreen?.bind(anyContainer);\r\n if (requestFs) {\r\n requestFs().catch(enterSimulated);\r\n } else {\r\n // iOS Safari: no Fullscreen API — use CSS fixed overlay\r\n enterSimulated();\r\n }\r\n }\r\n };\r\n\r\n // Keep ref current so the stale-closure-safe keyboard handler always calls the latest version\r\n useEffect(() => {\r\n toggleFullscreenRef.current = toggleFullscreen;\r\n });\r\n\r\n const handleSkipAd = () => {\r\n if (!isAdPlaying) return;\r\n const currentAdBreak = adBreaks.find(ab => currentTime >= ab.startTime && currentTime < ab.endTime);\r\n if (!currentAdBreak) return;\r\n triggerAdSkipRef.current?.(currentAdBreak.endTime);\r\n };\r\n\r\n const dismissOverlay = () => {\r\n if (activeOverlayRef.current) {\r\n dismissedOverlayIdsRef.current.add(activeOverlayRef.current.availId);\r\n }\r\n setActiveOverlay(null);\r\n activeOverlayRef.current = null;\r\n };\r\n\r\n const handleOverlayClick = (overlay: OverlayAdItem) => {\r\n if (overlay.clickTrackingUrl) fetch(overlay.clickTrackingUrl, { mode: 'no-cors' }).catch(() => {});\r\n if (overlay.clickThrough) window.open(overlay.clickThrough, '_blank', 'noopener,noreferrer');\r\n };\r\n\r\n const handleCastToggle = () => {\r\n if (!player) return;\r\n if (castDevice) {\r\n player.casting.stopCasting();\r\n } else {\r\n player.casting.requestSession(src, currentTime);\r\n }\r\n };\r\n\r\n const handleAirPlayToggle = () => {\r\n if (!player) return;\r\n const video = player.getVideoElement();\r\n\r\n if (isAirPlayConnected) {\r\n player.casting.stopAirPlay(video);\r\n return;\r\n }\r\n\r\n if (typeof (video as any).webkitShowPlaybackTargetPicker === 'function') {\r\n player.casting.requestAirPlaySession(video);\r\n } else if (player.casting.isAirPlayAvailable()) {\r\n player.casting.requestAirPlaySession(video);\r\n } else {\r\n console.warn('[PlayerSDK AirPlay] AirPlay is not available on this device.');\r\n }\r\n };\r\n\r\n const handleSeekbarHover = (e: React.MouseEvent<HTMLDivElement>) => {\r\n if (!seekbarRef.current || displayDuration === 0 || !player || isAdPlaying) return;\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n seekbarWidthRef.current = rect.width;\r\n const tooltipW = 192;\r\n setTooltipLeft(Math.max(tooltipW / 2, Math.min(e.clientX - rect.left, rect.width - tooltipW / 2)));\r\n const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));\r\n const videoTarget = contentTimeToVideoTime(percent * displayDuration);\r\n\r\n setHoverX(e.clientX - rect.left);\r\n setHoverTime(videoTarget);\r\n\r\n if (hoverSeekTimer.current) window.clearTimeout(hoverSeekTimer.current);\r\n hoverSeekTimer.current = window.setTimeout(() => {\r\n if (hiddenVideoRef.current) {\r\n hiddenVideoRef.current.currentTime = videoTarget;\r\n }\r\n }, 100);\r\n\r\n const hoverCh = player.keyMoments.getCurrentMoment(videoTarget);\r\n setHoverChapter(hoverCh.keyMoment);\r\n };\r\n\r\n const seekTimeFromTouch = (touch: React.Touch): number => {\r\n if (!seekbarRef.current || displayDuration === 0) return 0;\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n const percent = Math.max(0, Math.min(1, (touch.clientX - rect.left) / rect.width));\r\n return contentTimeToVideoTime(percent * displayDuration);\r\n };\r\n\r\n const handleSeekTouchStart = (e: React.TouchEvent<HTMLDivElement>) => {\r\n if (!player || isAdPlaying || displayDuration === 0) return;\r\n e.preventDefault();\r\n isScrubbing.current = true;\r\n const initialTime = seekTimeFromTouch(e.touches[0]);\r\n setScrubbingTime(initialTime);\r\n\r\n const onTouchMove = (ev: TouchEvent) => {\r\n if (!isScrubbing.current || !seekbarRef.current) return;\r\n const t = ev.touches[0];\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n const percent = Math.max(0, Math.min(1, (t.clientX - rect.left) / rect.width));\r\n const targetTime = contentTimeToVideoTime(percent * displayDuration);\r\n setScrubbingTime(targetTime);\r\n setHoverTime(targetTime);\r\n resetControlsTimer();\r\n };\r\n\r\n const onTouchEnd = (ev: TouchEvent) => {\r\n isScrubbing.current = false;\r\n if (seekbarRef.current && ev.changedTouches[0]) {\r\n const t = ev.changedTouches[0];\r\n const rect = seekbarRef.current.getBoundingClientRect();\r\n const percent = Math.max(0, Math.min(1, (t.clientX - rect.left) / rect.width));\r\n performSeek(contentTimeToVideoTime(percent * displayDuration));\r\n }\r\n setScrubbingTime(null);\r\n document.removeEventListener('touchmove', onTouchMove);\r\n document.removeEventListener('touchend', onTouchEnd);\r\n };\r\n\r\n document.addEventListener('touchmove', onTouchMove, { passive: false });\r\n document.addEventListener('touchend', onTouchEnd);\r\n };\r\n\r\n const handleSeekbarLeave = () => {\r\n setHoverX(null);\r\n setHoverThumbnail(null);\r\n setHoverChapter(null);\r\n if (hoverSeekTimer.current) {\r\n window.clearTimeout(hoverSeekTimer.current);\r\n }\r\n };\r\n\r\n const formatTime = (seconds: number) => {\r\n if (isNaN(seconds) || seconds < 0) return '00:00';\r\n const s = Math.floor(seconds);\r\n const hrs = Math.floor(s / 3600);\r\n const mins = Math.floor((s % 3600) / 60);\r\n const secs = s % 60;\r\n\r\n const pad = (num: number) => String(num).padStart(2, '0');\r\n\r\n if (hrs > 0) {\r\n return `${pad(hrs)}:${pad(mins)}:${pad(secs)}`;\r\n }\r\n return `${pad(mins)}:${pad(secs)}`;\r\n };\r\n\r\n // Announce play/pause and mute/unmute to screen readers via the live region.\r\n // announceMountedRef prevents false announcements on initial mount.\r\n useEffect(() => {\r\n if (!announceMountedRef.current) return;\r\n setAnnouncement(isPlaying ? 'Playing' : 'Paused');\r\n }, [isPlaying]);\r\n\r\n useEffect(() => {\r\n if (!announceMountedRef.current) return;\r\n setAnnouncement(isMuted ? 'Muted' : 'Unmuted');\r\n }, [isMuted]);\r\n\r\n useEffect(() => { announceMountedRef.current = true; }, []);\r\n\r\n // Close any open menu when Escape is pressed\r\n useEffect(() => {\r\n const handleEscape = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape' && activeMenuRef.current !== 'none') {\r\n e.preventDefault();\r\n setActiveMenu('none');\r\n }\r\n };\r\n document.addEventListener('keydown', handleEscape);\r\n return () => document.removeEventListener('keydown', handleEscape);\r\n }, []);\r\n\r\n // When casting, these reflect the remote device's state; otherwise local state\r\n const ctrlIsPlaying = castDevice ? !(remoteState?.isPaused ?? true) : isPlaying;\r\n const ctrlCurrentTime = castDevice ? (remoteState?.currentTime ?? 0) : currentTime;\r\n const ctrlDuration = castDevice ? (remoteState?.duration ?? 0) : displayDuration;\r\n const ctrlVolume = castDevice ? (remoteState?.volumeLevel ?? 1) : volume;\r\n const ctrlMuted = castDevice ? (remoteState?.isMuted ?? false) : isMuted;\r\n\r\n const handleMobileOverlayClick = useCallback((e: React.MouseEvent) => {\r\n if (isAdPlaying) return;\r\n if ((e.target as HTMLElement).closest('.sdk-mobile-ctrl')) return;\r\n const now = Date.now();\r\n const rect = containerRef.current?.getBoundingClientRect();\r\n const tapX = e.clientX - (rect?.left ?? 0);\r\n const last = lastTapRef.current;\r\n if (last && now - last.time < 300) {\r\n lastTapRef.current = null;\r\n const isLeft = tapX < (rect?.width ?? 0) / 2;\r\n const delta = isLeft ? -10 : 10;\r\n const newContentTime = Math.max(0, Math.min(displayDuration, videoTimeToContentTime(ctrlCurrentTime) + delta));\r\n performSeek(contentTimeToVideoTime(newContentTime));\r\n setDoubleTapSide(isLeft ? 'left' : 'right');\r\n window.setTimeout(() => setDoubleTapSide(null), 700);\r\n resetControlsTimer();\r\n } else {\r\n lastTapRef.current = { time: now, x: tapX };\r\n if (controlsVisible) {\r\n setControlsVisible(false);\r\n if (controlsTimeoutRef.current) window.clearTimeout(controlsTimeoutRef.current);\r\n } else {\r\n resetControlsTimer();\r\n }\r\n }\r\n }, [isAdPlaying, displayDuration, videoTimeToContentTime, ctrlCurrentTime, contentTimeToVideoTime, performSeek, controlsVisible]);\r\n\r\n const getVolumeIcon = () => {\r\n if (ctrlMuted || ctrlVolume === 0) return <VolumeX size={18} />;\r\n if (ctrlVolume < 0.3) return <Volume size={18} />;\r\n if (ctrlVolume < 0.7) return <Volume1 size={18} />;\r\n return <Volume2 size={18} />;\r\n };\r\n\r\n // Returns a keyboard handler for listbox option items (Enter/Space activates, Escape closes)\r\n const menuItemKeyDown = (action: () => void) => (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' || e.key === ' ') {\r\n e.preventDefault();\r\n action();\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n setActiveMenu('none');\r\n }\r\n };\r\n\r\n // Returns a keyboard handler for elements acting as buttons (e.g. chapter cards as divs)\r\n const cardKeyDown = (action: () => void) => (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' || e.key === ' ') {\r\n e.preventDefault();\r\n action();\r\n }\r\n };\r\n\r\n // Keyboard handler for the seek slider (role=\"slider\") — arrow keys seek ±5 s\r\n const handleSeekbarKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\r\n if (isAdPlaying) return;\r\n if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\r\n e.preventDefault();\r\n const delta = e.key === 'ArrowLeft' ? -5 : 5;\r\n const newCt = Math.max(0, Math.min(displayDuration, videoTimeToContentTime(ctrlCurrentTime) + delta));\r\n performSeek(contentTimeToVideoTime(newCt));\r\n } else if (e.key === 'Home') {\r\n e.preventDefault();\r\n performSeek(contentTimeToVideoTime(0));\r\n } else if (e.key === 'End') {\r\n e.preventDefault();\r\n performSeek(contentTimeToVideoTime(displayDuration));\r\n }\r\n };\r\n\r\n const menuToggle = (menu: typeof activeMenu) => {\r\n setActiveMenu(activeMenu === menu ? 'none' : menu);\r\n };\r\n\r\n // Keeps a drop-up menu inside the player bounds. Menus are centered on their\r\n // trigger by default; for triggers near an edge that centered box would be\r\n // clipped, so we nudge it horizontally by exactly the amount it overflows\r\n // (plus a small margin) — just enough to fit, no more. The ref callback runs\r\n // after layout but before paint, so the centered box is measured and the\r\n // shift applied before the open animation plays.\r\n const clampDropupMenu = useCallback((el: HTMLDivElement | null) => {\r\n if (!el) return;\r\n el.style.left = '';\r\n const container = containerRef.current;\r\n if (!container) return;\r\n const menuRect = el.getBoundingClientRect();\r\n const contRect = container.getBoundingClientRect();\r\n const margin = 8;\r\n const overflowRight = menuRect.right - (contRect.right - margin);\r\n const overflowLeft = (contRect.left + margin) - menuRect.left;\r\n if (overflowRight > 0) {\r\n el.style.left = `calc(50% - ${Math.ceil(overflowRight)}px)`;\r\n } else if (overflowLeft > 0) {\r\n el.style.left = `calc(50% + ${Math.ceil(overflowLeft)}px)`;\r\n }\r\n }, []);\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n role=\"region\"\r\n aria-label={title || extractedTitle ? `${title || extractedTitle} video player` : 'Video player'}\r\n className={`sdk-player-container ${controlsVisible ? 'controls-active' : ''} ${isSimulatedFullscreen ? 'sdk-fs-simulated' : ''}`}\r\n onMouseMove={handleMouseMove}\r\n onTouchStart={useMobileLayout ? undefined : resetControlsTimer}\r\n onMouseLeave={() => {\r\n // Don't snap-hide on mouse-leave; let the running 10s timer handle it naturally\r\n // This way controls stay visible briefly as the cursor exits the player\r\n }}\r\n style={{\r\n border: isSimulatedFullscreen ? 'none' : `1px solid rgba(255, 255, 255, 0.08)`,\r\n '--sdk-theme-color': themeColor,\r\n '--sdk-theme-color-rgb': hexToRgb(themeColor),\r\n } as React.CSSProperties}\r\n >\r\n <canvas\r\n ref={canvasRef}\r\n width={160}\r\n height={90}\r\n style={{ display: 'none', position: 'absolute', pointerEvents: 'none' }}\r\n aria-hidden=\"true\"\r\n />\r\n\r\n {/* Screen-reader live region for dynamic state announcements */}\r\n <div\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n aria-atomic=\"true\"\r\n className=\"sdk-sr-only\"\r\n >\r\n {announcement}\r\n </div>\r\n\r\n {/* Black cover used during ad-skip seeks to prevent any ad frame from bleeding through */}\r\n <div\r\n ref={adSkipCoverRef}\r\n style={{ opacity: 0, position: 'absolute', inset: 0, background: '#000', zIndex: 100, pointerEvents: 'none', willChange: 'opacity' }}\r\n aria-hidden=\"true\"\r\n />\r\n\r\n <div className={`sdk-spinner-overlay ${isBuffering ? 'active' : ''}`} aria-hidden=\"true\">\r\n <div className=\"sdk-spinner\"></div>\r\n </div>\r\n\r\n {playerError && (\r\n <div style={{\r\n position: 'absolute', inset: 0, zIndex: 50,\r\n background: 'rgba(9,9,14,0.96)',\r\n display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',\r\n gap: 20, padding: '0 24px',\r\n }}>\r\n <ErrorScreen\r\n onRetry={() => {\r\n setPlayerError(false);\r\n setRetryKey(k => k + 1);\r\n }}\r\n />\r\n </div>\r\n )}\r\n\r\n {sourceFallbackNotice && (\r\n <div style={{\r\n position: 'absolute', top: 16, left: '50%', transform: 'translateX(-50%)',\r\n background: 'rgba(0,0,0,0.82)', color: '#fff', fontSize: 13, fontWeight: 500,\r\n padding: '8px 16px', borderRadius: 8, zIndex: 80, pointerEvents: 'none',\r\n whiteSpace: 'nowrap', backdropFilter: 'blur(8px)',\r\n border: '1px solid rgba(255,255,255,0.12)',\r\n }}>\r\n {sourceFallbackNotice}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.enableSubtitles && subtitleText && activeSubtitleTrack !== 'off' && (\r\n <div className=\"sdk-subtitles-overlay\">\r\n <span\r\n className=\"sdk-subtitles-text\"\r\n style={{\r\n fontSize: subtitleStyle.size === 'small' ? '14px' : subtitleStyle.size === 'large' ? '24px' : '18px',\r\n color: subtitleStyle.color ?? '#ffffff',\r\n background: subtitleStyle.background === 'none'\r\n ? 'transparent'\r\n : subtitleStyle.background === 'solid'\r\n ? 'rgba(0, 0, 0, 0.92)'\r\n : 'rgba(15, 23, 42, 0.78)',\r\n border: subtitleStyle.background === 'none' ? 'none' : '1px solid rgba(255,255,255,0.08)',\r\n backdropFilter: subtitleStyle.background === 'none' ? 'none' : 'blur(8px)',\r\n }}\r\n dangerouslySetInnerHTML={{ __html: subtitleText }}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* Non-linear overlay ad banner */}\r\n {activeOverlay && (\r\n <div className={`sdk-overlay-ad sdk-overlay-ad--${activeOverlay.position}`} role=\"complementary\" aria-label=\"Advertisement\">\r\n <div className=\"sdk-overlay-ad-topbar\">\r\n <span className=\"sdk-overlay-ad-label\">Ad</span>\r\n {activeOverlay.dismissible && (\r\n <button\r\n className=\"sdk-overlay-ad-close\"\r\n onClick={dismissOverlay}\r\n aria-label=\"Close advertisement\"\r\n >\r\n ✕\r\n </button>\r\n )}\r\n </div>\r\n <img\r\n src={activeOverlay.imageUrl}\r\n width={activeOverlay.imageWidth}\r\n height={activeOverlay.imageHeight}\r\n alt={activeOverlay.title || 'Advertisement'}\r\n className=\"sdk-overlay-ad-img\"\r\n onClick={() => handleOverlayClick(activeOverlay)}\r\n />\r\n </div>\r\n )}\r\n\r\n {isAdPlaying && (() => {\r\n const currentAdBreak = adBreaks.find(ab => currentTime >= ab.startTime && currentTime < ab.endTime);\r\n const remainingAdTime = currentAdBreak ? Math.max(0, currentAdBreak.endTime - currentTime) : 0;\r\n const adPlayedSeconds = currentAdBreak ? currentTime - currentAdBreak.startTime : 0;\r\n const availSkip = availsSkipInfo.find(\r\n a => currentTime >= a.startTimeSeconds && currentTime < a.startTimeSeconds + a.durationSeconds\r\n );\r\n const effectiveSkippable = availSkip ? availSkip.skippable : enableSkipAd;\r\n const effectiveSkipAfter = availSkip ? availSkip.skipOffsetSeconds : skipAdAfterSeconds;\r\n const canSkip = effectiveSkippable && adPlayedSeconds >= effectiveSkipAfter;\r\n const skipCountdown = Math.ceil(effectiveSkipAfter - adPlayedSeconds);\r\n return (\r\n <>\r\n {/* Countdown badge */}\r\n <div\r\n className=\"sdk-ad-countdown\"\r\n role=\"timer\"\r\n aria-label={`Advertisement — ${formatTime(remainingAdTime)} remaining`}\r\n aria-live=\"off\"\r\n >\r\n <span className=\"sdk-ad-countdown-label\" aria-hidden=\"true\">Ad</span>\r\n <span className=\"sdk-ad-countdown-sep\" aria-hidden=\"true\">·</span>\r\n <span className=\"sdk-ad-countdown-time\" aria-hidden=\"true\">{formatTime(remainingAdTime)}</span>\r\n </div>\r\n\r\n {/* Skip Ad button — shown when ad is skippable per avails metadata or enableSkipAd prop */}\r\n {effectiveSkippable && (\r\n <button\r\n className={`sdk-skip-ad-btn ${canSkip ? 'sdk-skip-ad-btn--ready' : ''}`}\r\n onClick={canSkip ? handleSkipAd : undefined}\r\n disabled={!canSkip}\r\n aria-label={canSkip ? 'Skip advertisement' : `Skip advertisement available in ${skipCountdown} seconds`}\r\n aria-disabled={!canSkip}\r\n >\r\n {canSkip ? 'Skip Ad ›' : `Skip in ${skipCountdown}s`}\r\n </button>\r\n )}\r\n </>\r\n );\r\n })()}\r\n\r\n {isEntitlementBlocked && (\r\n <div style={{position:'absolute',inset:0,display:'flex',alignItems:'center',justifyContent:'center',background:'rgba(0,0,0,0.72)',color:'#fff',zIndex:60}}>\r\n <div style={{maxWidth:480,textAlign:'center',padding:24}}>\r\n <h3 style={{margin:'0 0 8px'}}>Playback restricted</h3>\r\n <p style={{margin:0}}>Your account is missing a required license key. Please contact your administrator.</p>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Dark background when casting — controls overlay renders on top */}\r\n {(castDevice || isAirPlayConnected) && (\r\n <div className=\"sdk-cast-bg\" />\r\n )}\r\n\r\n {/* ── Mobile layout ───────────────────────────────────────────── */}\r\n {useMobileLayout && (\r\n <div\r\n className={`sdk-mobile-overlay ${controlsVisible ? 'active' : ''}`}\r\n onClick={handleMobileOverlayClick}\r\n >\r\n {/* Double-tap seek indicator */}\r\n {doubleTapSide && (\r\n <div className={`sdk-mobile-doubletap ${doubleTapSide}`}>\r\n <div className=\"sdk-mobile-doubletap-icon\">\r\n {doubleTapSide === 'left'\r\n ? <RotateCcw size={26} />\r\n : <RotateCw size={26} />}\r\n <span className=\"sdk-mobile-doubletap-label\">10s</span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {enableControls && (\r\n <>\r\n {/* Header: back + title (landscape) | PiP + Cast + AirPlay */}\r\n <div className=\"sdk-mobile-header sdk-mobile-ctrl\">\r\n <div className=\"sdk-mobile-header-left\">\r\n {(isFullscreen || isSimulatedFullscreen) && (\r\n <button\r\n className=\"sdk-mobile-back-btn\"\r\n onClick={toggleFullscreen}\r\n aria-label=\"Exit fullscreen\"\r\n >\r\n <ChevronLeft size={22} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {(title || extractedTitle) && (\r\n <div className=\"sdk-mobile-title\">{title || extractedTitle}</div>\r\n )}\r\n </div>\r\n <div className=\"sdk-mobile-header-actions\">\r\n {effectiveFeatures.enablePiP && (\r\n <button\r\n className=\"sdk-mobile-hdr-btn\"\r\n onClick={() => { if (!isAdPlaying) togglePiP(); }}\r\n style={{ color: isPiP ? themeColor : '' }}\r\n aria-label={isPiP ? 'Exit picture-in-picture' : 'Enter picture-in-picture'}\r\n aria-pressed={isPiP}\r\n >\r\n <PictureInPicture size={20} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {effectiveFeatures.enableChromecast && !isAdPlaying && (\r\n <button\r\n className=\"sdk-mobile-hdr-btn\"\r\n onClick={handleCastToggle}\r\n title={castDevice ? `Casting to ${castDevice} — tap to disconnect` : 'Cast to device'}\r\n aria-label={castDevice ? `Stop casting to ${castDevice}` : 'Cast to device'}\r\n aria-pressed={!!castDevice}\r\n style={{ color: castDevice ? '#3b82f6' : '' }}\r\n >\r\n <Cast size={20} fill={castDevice ? 'currentColor' : 'none'} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {effectiveFeatures.allowAirplay && isAirPlayAvailable && (\r\n <button\r\n className=\"sdk-mobile-hdr-btn\"\r\n onClick={handleAirPlayToggle}\r\n aria-label={isAirPlayConnected ? `Stop AirPlay to ${airPlayTargetName || 'device'}` : 'AirPlay to device'}\r\n aria-pressed={isAirPlayConnected}\r\n style={{ color: isAirPlayConnected ? themeColor : '' }}\r\n >\r\n <Airplay size={20} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Center controls: rewind · play/pause · forward */}\r\n <div className=\"sdk-mobile-center-controls sdk-mobile-ctrl\">\r\n {!isAdPlaying && (\r\n <button\r\n className=\"sdk-mobile-seek-btn\"\r\n onClick={() => performSeek(contentTimeToVideoTime(Math.max(0, videoTimeToContentTime(ctrlCurrentTime) - 10)))}\r\n aria-label=\"Rewind 10 seconds\"\r\n >\r\n <RotateCcw size={22} aria-hidden=\"true\" />\r\n <span className=\"sdk-mobile-seek-label\" aria-hidden=\"true\">10</span>\r\n </button>\r\n )}\r\n <button\r\n className=\"sdk-mobile-play-btn\"\r\n onClick={togglePlay}\r\n aria-label={isEnded ? 'Replay' : ctrlIsPlaying ? 'Pause' : 'Play'}\r\n >\r\n {isEnded ? (\r\n <RotateCcw size={38} aria-hidden=\"true\" />\r\n ) : ctrlIsPlaying ? (\r\n <Pause size={38} fill=\"currentColor\" aria-hidden=\"true\" />\r\n ) : (\r\n <Play size={38} fill=\"currentColor\" style={{ marginLeft: '3px' }} aria-hidden=\"true\" />\r\n )}\r\n </button>\r\n {!isAdPlaying && (\r\n <button\r\n className=\"sdk-mobile-seek-btn\"\r\n onClick={() => performSeek(contentTimeToVideoTime(Math.min(displayDuration, videoTimeToContentTime(ctrlCurrentTime) + 10)))}\r\n aria-label=\"Skip forward 10 seconds\"\r\n >\r\n <RotateCw size={22} aria-hidden=\"true\" />\r\n <span className=\"sdk-mobile-seek-label\" aria-hidden=\"true\">10</span>\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Bottom: chapter strip + seekbar + controls row */}\r\n <div className=\"sdk-mobile-bottom-bar sdk-mobile-ctrl\">\r\n {/* Horizontal key moments strip */}\r\n {effectiveFeatures.enableKeyMoments && showChaptersSidebar && localKeyMoments.length > 0 && (\r\n <div className=\"sdk-mobile-chapters-scroll\">\r\n {localKeyMoments.map((ch, idx) => {\r\n const isActive = activeChapter.index === idx;\r\n return (\r\n <div\r\n key={idx}\r\n role=\"button\"\r\n tabIndex={0}\r\n className={`sdk-mobile-chapter-card${isActive ? ' active' : ''}`}\r\n style={{ borderColor: isActive ? themeColor : undefined }}\r\n aria-label={`${ch.title}, ${formatTime(ch.startTime)}${isActive ? ', current chapter' : ''}`}\r\n aria-current={isActive ? 'true' : undefined}\r\n onClick={() => { performSeek(ch.startTime); }}\r\n onKeyDown={cardKeyDown(() => performSeek(ch.startTime))}\r\n >\r\n <div className=\"sdk-mobile-chapter-thumb\">\r\n {(chapterThumbnails[idx] || ch.thumbnail) ? (\r\n <img\r\n src={chapterThumbnails[idx] || ch.thumbnail}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}\r\n />\r\n ) : (\r\n <ListVideo size={16} aria-hidden=\"true\" style={{ color: isActive ? themeColor : 'rgba(255,255,255,0.3)' }} />\r\n )}\r\n <span className=\"sdk-mobile-chapter-time-badge\" aria-hidden=\"true\">{formatTime(ch.startTime)}</span>\r\n </div>\r\n <div className=\"sdk-mobile-chapter-title\" style={{ color: isActive ? themeColor : undefined }}>\r\n {ch.title}\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* Seekbar / Ad Progress Bar — edge to edge */}\r\n <div\r\n ref={seekbarRef}\r\n role={isAdPlaying ? undefined : 'slider'}\r\n aria-label={isAdPlaying ? undefined : 'Seek'}\r\n aria-valuemin={isAdPlaying ? undefined : 0}\r\n aria-valuemax={isAdPlaying ? undefined : Math.round(displayDuration)}\r\n aria-valuenow={isAdPlaying ? undefined : Math.round(videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime))}\r\n aria-valuetext={isAdPlaying ? undefined : `${formatTime(videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime))} of ${formatTime(displayDuration)}`}\r\n tabIndex={isAdPlaying ? undefined : 0}\r\n className={`sdk-seekbar-container sdk-mobile-seekbar${isAdPlaying ? ' sdk-ad-mode' : ''}`}\r\n onMouseDown={isAdPlaying ? undefined : handleSeekMouseDown}\r\n onMouseMove={isAdPlaying ? undefined : handleSeekbarHover}\r\n onMouseLeave={isAdPlaying ? undefined : handleSeekbarLeave}\r\n onTouchStart={isAdPlaying ? undefined : handleSeekTouchStart}\r\n onKeyDown={isAdPlaying ? undefined : handleSeekbarKeyDown}\r\n style={{ pointerEvents: isAdPlaying ? 'none' : undefined, touchAction: 'none' }}\r\n >\r\n {isAdPlaying ? (\r\n <div\r\n className=\"sdk-ad-progress-fill\"\r\n style={{\r\n width: (() => {\r\n const ab = adBreaks.find(b => currentTime >= b.startTime && currentTime < b.endTime);\r\n return ab ? `${((currentTime - ab.startTime) / (ab.endTime - ab.startTime)) * 100}%` : '0%';\r\n })(),\r\n }}\r\n />\r\n ) : (\r\n <>\r\n <div\r\n className=\"sdk-seekbar-buffered\"\r\n style={{ width: `${duration ? (player ? (player.getBufferedRanges()[0]?.end || 0) : 0) / duration * 100 : 0}%` }}\r\n />\r\n {displayDuration > 0 && adBreaks.filter(ab => !watchedAdBreaksSet.has(ab.startTime)).map((ab, idx) => (\r\n <div\r\n key={idx}\r\n className=\"sdk-seekbar-adbreak\"\r\n style={{\r\n left: `${(videoTimeToContentTime(ab.startTime) / displayDuration) * 100}%`,\r\n width: '3px',\r\n }}\r\n />\r\n ))}\r\n <div\r\n className=\"sdk-seekbar-progress\"\r\n style={{\r\n width: castDevice\r\n ? `${ctrlDuration > 0 ? (ctrlCurrentTime / ctrlDuration) * 100 : 0}%`\r\n : `${displayDuration ? (videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime) / displayDuration) * 100 : 0}%`,\r\n background: '#ffffff',\r\n boxShadow: 'none',\r\n }}\r\n >\r\n <div className=\"sdk-seekbar-handle\" style={{ opacity: 1, transform: 'scale(1)' }} />\r\n </div>\r\n {effectiveFeatures.enableKeyMoments && localKeyMoments.map((ch, idx) => {\r\n if (displayDuration === 0) return null;\r\n return <div key={idx} className=\"sdk-seekbar-chapter-marker sdk-desktop-chapter-dot\" style={{ left: `${(videoTimeToContentTime(ch.startTime) / displayDuration) * 100}%` }} />;\r\n })}\r\n </>\r\n )}\r\n </div>\r\n\r\n {/* Controls row: time | icon buttons */}\r\n <div className=\"sdk-mobile-controls-row\">\r\n {!isAdPlaying && (\r\n <span className=\"sdk-time-display\">\r\n {castDevice\r\n ? `${formatTime(ctrlCurrentTime)} / ${formatTime(ctrlDuration)}`\r\n : `${formatTime(videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime))} / ${formatTime(displayDuration)}`}\r\n </span>\r\n )}\r\n <div className=\"sdk-mobile-bottom-icons\">\r\n {effectiveFeatures.enableKeyMoments && localKeyMoments.length > 0 && !isAdPlaying && (\r\n <button\r\n className={`sdk-mobile-icon-btn${showChaptersSidebar ? ' active' : ''}`}\r\n onClick={() => { setShowChaptersSidebar(!showChaptersSidebar); }}\r\n aria-label={showChaptersSidebar ? 'Hide chapters' : 'Show chapters'}\r\n aria-pressed={showChaptersSidebar}\r\n >\r\n <ListVideo size={18} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n\r\n {effectiveFeatures.enableSubtitles && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-mobile-icon-btn${activeSubtitleTrack !== 'off' ? ' active' : ''}`}\r\n onClick={() => { menuToggle('subtitles'); }}\r\n aria-label=\"Captions\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'subtitles'}\r\n >\r\n <Subtitles size={18} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'subtitles' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Captions\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Subtitles</div>\r\n <div\r\n role=\"option\"\r\n aria-selected={activeSubtitleTrack === 'off'}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeSubtitleTrack === 'off' ? 'active' : ''}`}\r\n onClick={() => handleSubtitleChange('off')}\r\n onKeyDown={menuItemKeyDown(() => handleSubtitleChange('off'))}\r\n >\r\n <span>Off</span>\r\n {activeSubtitleTrack === 'off' && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n {availableSubtitles.map((track) => (\r\n <div\r\n key={track.id}\r\n role=\"option\"\r\n aria-selected={activeSubtitleTrack === track.id}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeSubtitleTrack === track.id ? 'active' : ''}`}\r\n onClick={() => handleSubtitleChange(track.id)}\r\n onKeyDown={menuItemKeyDown(() => handleSubtitleChange(track.id))}\r\n >\r\n <span>{getLanguageLabel(track)}</span>\r\n {activeSubtitleTrack === track.id && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.allowMultipleAudio && audioTracks.length > 1 && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-mobile-icon-btn${activeMenu === 'audio' ? ' active' : ''}`}\r\n onClick={() => { menuToggle('audio'); }}\r\n aria-label=\"Audio track\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'audio'}\r\n >\r\n <Languages size={18} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'audio' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Audio track\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Audio Track</div>\r\n {audioTracks.map((track) => (\r\n <div\r\n key={track.id}\r\n role=\"option\"\r\n aria-selected={activeAudioTrack === track.id}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeAudioTrack === track.id ? 'active' : ''}`}\r\n onClick={() => { player?.setAudioTrack(track.id); setActiveAudioTrack(track.id); setActiveMenu('none'); setAnnouncement(`Audio: ${getLanguageLabel(track)}`); }}\r\n onKeyDown={menuItemKeyDown(() => { player?.setAudioTrack(track.id); setActiveAudioTrack(track.id); setActiveMenu('none'); setAnnouncement(`Audio: ${getLanguageLabel(track)}`); })}\r\n >\r\n <span>{getLanguageLabel(track)}</span>\r\n {activeAudioTrack === track.id && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.enablePlaybackSpeed && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-mobile-icon-btn${activeMenu === 'speed' ? ' active' : ''}`}\r\n onClick={() => { menuToggle('speed'); }}\r\n aria-label=\"Playback speed\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'speed'}\r\n >\r\n <Gauge size={18} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'speed' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Playback speed\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Speed</div>\r\n {[0.5, 0.75, 1, 1.25, 1.5, 2].map((rate) => (\r\n <div\r\n key={rate}\r\n role=\"option\"\r\n aria-selected={playbackRate === rate}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${playbackRate === rate ? 'active' : ''}`}\r\n onClick={() => handleSpeedChange(rate)}\r\n onKeyDown={menuItemKeyDown(() => handleSpeedChange(rate))}\r\n >\r\n <span>{rate === 1 ? 'Normal' : `${rate}x`}</span>\r\n {playbackRate === rate && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.enableQuality && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-mobile-icon-btn${activeQuality.id !== -1 ? ' active' : ''}`}\r\n onClick={() => { menuToggle('quality'); }}\r\n aria-label=\"Video quality\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'quality'}\r\n >\r\n <HdIcon size={18} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'quality' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu large\" role=\"listbox\" aria-label=\"Video quality\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Quality</div>\r\n {qualities.map((q) => (\r\n <div\r\n key={q.id}\r\n role=\"option\"\r\n aria-selected={activeQuality.id === q.id}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeQuality.id === q.id ? 'active' : ''}`}\r\n onClick={() => handleQualityChange(q.id)}\r\n onKeyDown={menuItemKeyDown(() => handleQualityChange(q.id))}\r\n >\r\n <span>{q.label}</span>\r\n {activeQuality.id === q.id && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {sources && sources.length > 1 && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-mobile-icon-btn${activeMenu === 'sources' ? ' active' : ''}`}\r\n onClick={() => { menuToggle('sources'); }}\r\n aria-label=\"Select source\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'sources'}\r\n >\r\n <Signal size={18} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'sources' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Select source\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Source</div>\r\n {sources.map((s, idx) => (\r\n <div\r\n key={idx}\r\n role=\"option\"\r\n aria-selected={activeSourceIndex === idx}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeSourceIndex === idx ? 'active' : ''}`}\r\n onClick={() => handleSourceChange(idx)}\r\n onKeyDown={menuItemKeyDown(() => handleSourceChange(idx))}\r\n >\r\n <span>{s.label}</span>\r\n {activeSourceIndex === idx && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n <button\r\n className=\"sdk-mobile-icon-btn\"\r\n onClick={toggleFullscreen}\r\n aria-label={isFullscreen || isSimulatedFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\r\n aria-pressed={isFullscreen || isSimulatedFullscreen}\r\n >\r\n {isFullscreen ? <Minimize size={18} aria-hidden=\"true\" /> : <Maximize size={18} aria-hidden=\"true\" />}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* ── Desktop layout ──────────────────────────────────────────── */}\r\n {!useMobileLayout && (\r\n <div\r\n className=\"sdk-controls-overlay\"\r\n onClick={(e) => {\r\n if (isAdPlaying) return;\r\n if ((e.target as HTMLElement).closest('.sdk-desktop-header') ||\r\n (e.target as HTMLElement).closest('.sdk-desktop-center-controls') ||\r\n (e.target as HTMLElement).closest('.sdk-desktop-bottom')) return;\r\n togglePlay();\r\n }}\r\n >\r\n {/* Top header */}\r\n <div className=\"sdk-desktop-header\">\r\n <div className=\"sdk-desktop-header-left\">\r\n {(isFullscreen || isSimulatedFullscreen) && (\r\n <button\r\n className=\"sdk-desktop-back-btn\"\r\n onClick={(e) => { e.stopPropagation(); toggleFullscreen(); }}\r\n aria-label=\"Exit fullscreen\"\r\n >\r\n <ChevronLeft size={22} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {(title || extractedTitle) && <span className=\"sdk-desktop-title\">{title || extractedTitle}</span>}\r\n </div>\r\n <div className=\"sdk-desktop-header-right\">\r\n {effectiveFeatures.enableChromecast && !isAdPlaying && (\r\n <button\r\n className=\"sdk-desktop-hdr-btn\"\r\n onClick={(e) => { e.stopPropagation(); handleCastToggle(); }}\r\n title={castDevice ? `Casting to ${castDevice} — click to disconnect` : 'Cast to device'}\r\n aria-label={castDevice ? `Stop casting to ${castDevice}` : 'Cast to device'}\r\n aria-pressed={!!castDevice}\r\n style={{ color: castDevice ? '#3b82f6' : '' }}\r\n >\r\n <Cast size={20} fill={castDevice ? 'currentColor' : 'none'} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {castDevice && (\r\n <span className=\"sdk-cast-indicator\" aria-hidden=\"true\">\r\n <Cast size={10} fill=\"currentColor\" aria-hidden=\"true\" />\r\n {castDevice}\r\n </span>\r\n )}\r\n {effectiveFeatures.allowAirplay && isAirPlayAvailable && (\r\n <button\r\n className=\"sdk-desktop-hdr-btn\"\r\n onClick={(e) => { e.stopPropagation(); handleAirPlayToggle(); }}\r\n title={isAirPlayConnected ? `AirPlay to ${airPlayTargetName || 'device'} — click to disconnect` : 'AirPlay to device'}\r\n aria-label={isAirPlayConnected ? `Stop AirPlay to ${airPlayTargetName || 'device'}` : 'AirPlay to device'}\r\n aria-pressed={isAirPlayConnected}\r\n style={{ color: isAirPlayConnected ? themeColor : '' }}\r\n >\r\n <Airplay size={20} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {enableControls && (\r\n <>\r\n {/* Center play / seek controls */}\r\n <div className=\"sdk-desktop-center-controls\" style={{ pointerEvents: 'none' }}>\r\n {!isAdPlaying && (\r\n <button\r\n className=\"sdk-desktop-seek-btn\"\r\n style={{ pointerEvents: 'auto' }}\r\n onClick={(e) => { e.stopPropagation(); performSeek(contentTimeToVideoTime(Math.max(0, videoTimeToContentTime(ctrlCurrentTime) - 10))); }}\r\n title=\"Rewind 10s\"\r\n aria-label=\"Rewind 10 seconds\"\r\n >\r\n <div style={{ position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\r\n <RotateCcw size={30} aria-hidden=\"true\" />\r\n <span className=\"sdk-desktop-seek-label\" aria-hidden=\"true\">10</span>\r\n </div>\r\n </button>\r\n )}\r\n <button\r\n className=\"sdk-desktop-play-btn\"\r\n style={{ pointerEvents: 'auto' }}\r\n onClick={(e) => { e.stopPropagation(); togglePlay(); }}\r\n title={isEnded ? 'Replay' : ctrlIsPlaying ? 'Pause' : 'Play'}\r\n aria-label={isEnded ? 'Replay' : ctrlIsPlaying ? 'Pause' : 'Play'}\r\n >\r\n {isEnded\r\n ? <RotateCcw size={38} aria-hidden=\"true\" />\r\n : ctrlIsPlaying\r\n ? <Pause size={38} fill=\"currentColor\" aria-hidden=\"true\" />\r\n : <Play size={38} fill=\"currentColor\" style={{ marginLeft: '4px' }} aria-hidden=\"true\" />}\r\n </button>\r\n {!isAdPlaying && (\r\n <button\r\n className=\"sdk-desktop-seek-btn\"\r\n style={{ pointerEvents: 'auto' }}\r\n onClick={(e) => { e.stopPropagation(); performSeek(contentTimeToVideoTime(Math.min(displayDuration, videoTimeToContentTime(ctrlCurrentTime) + 10))); }}\r\n title=\"Forward 10s\"\r\n aria-label=\"Skip forward 10 seconds\"\r\n >\r\n <div style={{ position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\r\n <RotateCw size={30} aria-hidden=\"true\" />\r\n <span className=\"sdk-desktop-seek-label\" aria-hidden=\"true\">10</span>\r\n </div>\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Panel-style chapter list (absolute overlay, right side) */}\r\n {effectiveFeatures.enableKeyMoments && showChaptersSidebar && localKeyMoments.length > 0 && chaptersDisplayMode === 'panel' && (\r\n <div className=\"sdk-chapters-panel\" onClick={(e) => e.stopPropagation()}>\r\n <div className=\"sdk-chapters-panel-header\">\r\n <span className=\"sdk-chapters-panel-title\">Chapters</span>\r\n </div>\r\n <div className=\"sdk-chapters-panel-list\">\r\n {localKeyMoments.map((ch, idx) => {\r\n const isActive = activeChapter.index === idx;\r\n return (\r\n <div\r\n key={idx}\r\n role=\"button\"\r\n tabIndex={0}\r\n className={`sdk-chapters-panel-item${isActive ? ' active' : ''}`}\r\n aria-label={`${ch.title}, ${formatTime(ch.startTime)}${isActive ? ', current chapter' : ''}`}\r\n aria-current={isActive ? 'true' : undefined}\r\n onClick={() => handleChapterClick(ch.startTime)}\r\n onKeyDown={cardKeyDown(() => handleChapterClick(ch.startTime))}\r\n >\r\n <div className=\"sdk-chapters-panel-thumb\">\r\n {(chapterThumbnails[idx] || ch.thumbnail) ? (\r\n <img\r\n src={chapterThumbnails[idx] || ch.thumbnail}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}\r\n />\r\n ) : (\r\n <ListVideo size={18} aria-hidden=\"true\" style={{ color: 'rgba(255,255,255,0.3)' }} />\r\n )}\r\n </div>\r\n <div className=\"sdk-chapters-panel-info\">\r\n <div className=\"sdk-chapters-panel-item-title\">{ch.title}</div>\r\n {ch.description && (\r\n <div className=\"sdk-chapters-panel-item-desc\">{ch.description}</div>\r\n )}\r\n <div className=\"sdk-chapters-panel-item-time\" aria-hidden=\"true\">{formatTime(ch.startTime)}</div>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Bottom area: chapters strip + seekbar + controls row */}\r\n <div className=\"sdk-desktop-bottom\">\r\n {/* Chapter thumbnail strip (strip mode only) */}\r\n {effectiveFeatures.enableKeyMoments && showChaptersSidebar && localKeyMoments.length > 0 && chaptersDisplayMode === 'strip' && (\r\n <div className=\"sdk-desktop-chapters-strip\">\r\n {localKeyMoments.map((ch, idx) => {\r\n const isActive = activeChapter.index === idx;\r\n return (\r\n <div\r\n key={idx}\r\n role=\"button\"\r\n tabIndex={0}\r\n className={`sdk-desktop-chapter-card${isActive ? ' active' : ''}`}\r\n aria-label={`${ch.title}, ${formatTime(ch.startTime)}${isActive ? ', current chapter' : ''}`}\r\n aria-current={isActive ? 'true' : undefined}\r\n onClick={(e) => { e.stopPropagation(); handleChapterClick(ch.startTime); }}\r\n onKeyDown={cardKeyDown(() => handleChapterClick(ch.startTime))}\r\n >\r\n <div className=\"sdk-desktop-chapter-thumb\">\r\n {(chapterThumbnails[idx] || ch.thumbnail) ? (\r\n <img\r\n src={chapterThumbnails[idx] || ch.thumbnail}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}\r\n />\r\n ) : (\r\n <ListVideo size={18} aria-hidden=\"true\" style={{ color: 'rgba(255,255,255,0.35)' }} />\r\n )}\r\n </div>\r\n <div className=\"sdk-desktop-chapter-title\">{ch.title}</div>\r\n <div className=\"sdk-desktop-chapter-time\" aria-hidden=\"true\">{formatTime(ch.startTime)}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* Seekbar / Ad Progress Bar */}\r\n <div\r\n ref={seekbarRef}\r\n role={isAdPlaying ? undefined : 'slider'}\r\n aria-label={isAdPlaying ? undefined : 'Seek'}\r\n aria-valuemin={isAdPlaying ? undefined : 0}\r\n aria-valuemax={isAdPlaying ? undefined : Math.round(displayDuration)}\r\n aria-valuenow={isAdPlaying ? undefined : Math.round(videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime))}\r\n aria-valuetext={isAdPlaying ? undefined : `${formatTime(videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime))} of ${formatTime(displayDuration)}`}\r\n tabIndex={isAdPlaying ? undefined : 0}\r\n className={`sdk-seekbar-container sdk-desktop-seekbar${isAdPlaying ? ' sdk-ad-mode' : ''}`}\r\n onMouseDown={isAdPlaying ? undefined : handleSeekMouseDown}\r\n onMouseMove={isAdPlaying ? undefined : handleSeekbarHover}\r\n onMouseLeave={isAdPlaying ? undefined : handleSeekbarLeave}\r\n onTouchStart={isAdPlaying ? undefined : handleSeekTouchStart}\r\n onKeyDown={isAdPlaying ? undefined : handleSeekbarKeyDown}\r\n style={{ pointerEvents: isAdPlaying ? 'none' : undefined }}\r\n >\r\n {isAdPlaying ? (\r\n <div\r\n className=\"sdk-ad-progress-fill\"\r\n style={{\r\n width: (() => {\r\n const ab = adBreaks.find(b => currentTime >= b.startTime && currentTime < b.endTime);\r\n return ab ? `${((currentTime - ab.startTime) / (ab.endTime - ab.startTime)) * 100}%` : '0%';\r\n })(),\r\n }}\r\n />\r\n ) : (\r\n <>\r\n <div\r\n className=\"sdk-seekbar-buffered\"\r\n style={{ width: `${duration ? (player ? (player.getBufferedRanges()[0]?.end || 0) : 0) / duration * 100 : 0}%` }}\r\n />\r\n {displayDuration > 0 && adBreaks.filter(ab => !watchedAdBreaksSet.has(ab.startTime)).map((ab, idx) => (\r\n <div\r\n key={idx}\r\n className=\"sdk-seekbar-adbreak\"\r\n style={{\r\n left: `${(videoTimeToContentTime(ab.startTime) / displayDuration) * 100}%`,\r\n width: '3px',\r\n }}\r\n />\r\n ))}\r\n <div\r\n className=\"sdk-seekbar-progress\"\r\n style={{\r\n width: castDevice\r\n ? `${ctrlDuration > 0 ? (ctrlCurrentTime / ctrlDuration) * 100 : 0}%`\r\n : `${displayDuration ? (videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime) / displayDuration) * 100 : 0}%`,\r\n background: '#ffffff',\r\n boxShadow: 'none',\r\n }}\r\n >\r\n <div className=\"sdk-seekbar-handle\" />\r\n </div>\r\n {effectiveFeatures.enableKeyMoments && localKeyMoments.map((ch, idx) => {\r\n if (displayDuration === 0) return null;\r\n return (\r\n <div\r\n key={idx}\r\n className=\"sdk-seekbar-chapter-marker sdk-desktop-chapter-dot\"\r\n style={{ left: `${(videoTimeToContentTime(ch.startTime) / displayDuration) * 100}%` }}\r\n />\r\n );\r\n })}\r\n {hoverX !== null && hoverThumbnail && (\r\n <div className=\"sdk-thumbnail-tooltip\" style={{ left: `${tooltipLeft}px` }}>\r\n <div className=\"sdk-thumbnail-preview\">\r\n <img\r\n src={hoverThumbnail}\r\n alt=\"preview\"\r\n style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: '8px', display: 'block' }}\r\n />\r\n </div>\r\n {hoverChapter && (\r\n <div className=\"sdk-thumbnail-chapter-name\">{hoverChapter.title}</div>\r\n )}\r\n <div className=\"sdk-thumbnail-time-label\">{formatTime(videoTimeToContentTime(hoverTime))}</div>\r\n </div>\r\n )}\r\n </>\r\n )}\r\n </div>\r\n\r\n {/* Controls row */}\r\n <div className=\"sdk-desktop-controls-row\">\r\n {/* Left: time + optional volume slider */}\r\n <div className=\"sdk-desktop-left-controls\">\r\n {!isAdPlaying && (\r\n <div className=\"sdk-time-display\">\r\n {castDevice\r\n ? `${formatTime(ctrlCurrentTime)} / ${formatTime(ctrlDuration)}`\r\n : `${formatTime(videoTimeToContentTime(scrubbingTime !== null ? scrubbingTime : currentTime))} / ${formatTime(displayDuration)}`}\r\n </div>\r\n )}\r\n {volumeControlType === 'slider' && (\r\n <div className=\"sdk-volume-control\">\r\n <button\r\n className=\"sdk-desktop-icon-btn\"\r\n onClick={(e) => { e.stopPropagation(); toggleMute(); }}\r\n title={ctrlMuted ? 'Unmute' : 'Mute'}\r\n aria-label={ctrlMuted ? 'Unmute' : 'Mute'}\r\n aria-pressed={ctrlMuted}\r\n >\r\n {getVolumeIcon()}\r\n </button>\r\n <input\r\n type=\"range\"\r\n className=\"sdk-volume-slider\"\r\n min={0}\r\n max={1}\r\n step={0.02}\r\n value={ctrlMuted ? 0 : ctrlVolume}\r\n aria-label=\"Volume\"\r\n aria-valuetext={ctrlMuted ? 'Muted' : `${Math.round(ctrlVolume * 100)}%`}\r\n style={{ '--vol-pct': Math.round((ctrlMuted ? 0 : ctrlVolume) * 100) } as React.CSSProperties}\r\n onChange={(e) => {\r\n const val = parseFloat(e.target.value);\r\n if (castDevice) {\r\n player?.casting.remoteSetVolume(val);\r\n if (val > 0) player?.casting.remoteSetMute(false);\r\n } else {\r\n player?.setVolume(val);\r\n if (val > 0 && isMuted) player?.setMute(false);\r\n }\r\n }}\r\n onClick={(e) => e.stopPropagation()}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Right: icon buttons */}\r\n <div className=\"sdk-desktop-right-icons\">\r\n {effectiveFeatures.enableKeyMoments && localKeyMoments.length > 0 && !isAdPlaying && (\r\n <button\r\n className={`sdk-desktop-icon-btn${showChaptersSidebar ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); setShowChaptersSidebar(!showChaptersSidebar); }}\r\n title=\"Key Moments\"\r\n aria-label={showChaptersSidebar ? 'Hide chapters' : 'Show chapters'}\r\n aria-pressed={showChaptersSidebar}\r\n >\r\n <ListVideo size={20} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n\r\n {effectiveFeatures.enableSubtitles && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-desktop-icon-btn${activeSubtitleTrack !== 'off' ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); menuToggle('subtitles'); }}\r\n title=\"Captions\"\r\n aria-label=\"Captions\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'subtitles'}\r\n >\r\n <Subtitles size={20} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'subtitles' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Captions\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Subtitles</div>\r\n <div\r\n role=\"option\"\r\n aria-selected={activeSubtitleTrack === 'off'}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeSubtitleTrack === 'off' ? 'active' : ''}`}\r\n onClick={() => handleSubtitleChange('off')}\r\n onKeyDown={menuItemKeyDown(() => handleSubtitleChange('off'))}\r\n >\r\n <span>Off</span>\r\n {activeSubtitleTrack === 'off' && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n {availableSubtitles.map((track) => (\r\n <div\r\n key={track.id}\r\n role=\"option\"\r\n aria-selected={activeSubtitleTrack === track.id}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeSubtitleTrack === track.id ? 'active' : ''}`}\r\n onClick={() => handleSubtitleChange(track.id)}\r\n onKeyDown={menuItemKeyDown(() => handleSubtitleChange(track.id))}\r\n >\r\n <span>{getLanguageLabel(track)}</span>\r\n {activeSubtitleTrack === track.id && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.allowMultipleAudio && audioTracks.length > 1 && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-desktop-icon-btn${activeMenu === 'audio' ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); menuToggle('audio'); }}\r\n title=\"Audio Track\"\r\n aria-label=\"Audio track\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'audio'}\r\n >\r\n <Languages size={20} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'audio' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Audio track\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Audio Track</div>\r\n {audioTracks.map((track) => (\r\n <div\r\n key={track.id}\r\n role=\"option\"\r\n aria-selected={activeAudioTrack === track.id}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeAudioTrack === track.id ? 'active' : ''}`}\r\n onClick={() => {\r\n player?.setAudioTrack(track.id);\r\n setActiveAudioTrack(track.id);\r\n setActiveMenu('none');\r\n setAnnouncement(`Audio: ${getLanguageLabel(track)}`);\r\n }}\r\n onKeyDown={menuItemKeyDown(() => {\r\n player?.setAudioTrack(track.id);\r\n setActiveAudioTrack(track.id);\r\n setActiveMenu('none');\r\n setAnnouncement(`Audio: ${getLanguageLabel(track)}`);\r\n })}\r\n >\r\n <span>{getLanguageLabel(track)}</span>\r\n {activeAudioTrack === track.id && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.enablePlaybackSpeed && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-desktop-icon-btn${activeMenu === 'speed' ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); menuToggle('speed'); }}\r\n title=\"Playback Speed\"\r\n aria-label=\"Playback speed\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'speed'}\r\n >\r\n <Gauge size={20} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'speed' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Playback speed\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Speed</div>\r\n {[0.5, 0.75, 1, 1.25, 1.5, 2].map((rate) => (\r\n <div\r\n key={rate}\r\n role=\"option\"\r\n aria-selected={playbackRate === rate}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${playbackRate === rate ? 'active' : ''}`}\r\n onClick={() => handleSpeedChange(rate)}\r\n onKeyDown={menuItemKeyDown(() => handleSpeedChange(rate))}\r\n >\r\n <span>{rate === 1 ? 'Normal' : `${rate}x`}</span>\r\n {playbackRate === rate && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.enableQuality && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-desktop-icon-btn${activeQuality.id !== -1 ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); menuToggle('quality'); }}\r\n title=\"Quality\"\r\n aria-label=\"Video quality\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'quality'}\r\n >\r\n <HdIcon size={20} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'quality' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu large\" role=\"listbox\" aria-label=\"Video quality\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Quality</div>\r\n {qualities.map((q) => (\r\n <div\r\n key={q.id}\r\n role=\"option\"\r\n aria-selected={activeQuality.id === q.id}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeQuality.id === q.id ? 'active' : ''}`}\r\n onClick={() => handleQualityChange(q.id)}\r\n onKeyDown={menuItemKeyDown(() => handleQualityChange(q.id))}\r\n >\r\n <span>{q.label}</span>\r\n {activeQuality.id === q.id && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {sources && sources.length > 1 && !isAdPlaying && (\r\n <div className=\"sdk-menu-container\">\r\n <button\r\n className={`sdk-desktop-icon-btn${activeMenu === 'sources' ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); menuToggle('sources'); }}\r\n title=\"Select Source\"\r\n aria-label=\"Select source\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={activeMenu === 'sources'}\r\n >\r\n <Signal size={20} aria-hidden=\"true\" />\r\n </button>\r\n {activeMenu === 'sources' && (\r\n <div ref={clampDropupMenu} className=\"sdk-dropup-menu\" role=\"listbox\" aria-label=\"Select source\">\r\n <div className=\"sdk-dropup-header\" aria-hidden=\"true\">Source</div>\r\n {sources.map((s, idx) => (\r\n <div\r\n key={idx}\r\n role=\"option\"\r\n aria-selected={activeSourceIndex === idx}\r\n tabIndex={0}\r\n className={`sdk-dropup-item ${activeSourceIndex === idx ? 'active' : ''}`}\r\n onClick={() => handleSourceChange(idx)}\r\n onKeyDown={menuItemKeyDown(() => handleSourceChange(idx))}\r\n >\r\n <span>{s.label}</span>\r\n {activeSourceIndex === idx && <Check size={12} aria-hidden=\"true\" />}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {effectiveFeatures.enablePiP && !isAdPlaying && (\r\n <button\r\n className={`sdk-desktop-icon-btn${isPiP ? ' active' : ''}`}\r\n onClick={(e) => { e.stopPropagation(); togglePiP(); }}\r\n title=\"Picture-in-Picture\"\r\n aria-label={isPiP ? 'Exit picture-in-picture' : 'Enter picture-in-picture'}\r\n aria-pressed={isPiP}\r\n >\r\n <PictureInPicture size={20} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n\r\n {volumeControlType === 'button' && (\r\n <button\r\n className=\"sdk-desktop-icon-btn\"\r\n onClick={(e) => { e.stopPropagation(); toggleMute(); }}\r\n title={ctrlMuted ? 'Unmute' : 'Mute'}\r\n aria-label={ctrlMuted ? 'Unmute' : 'Mute'}\r\n aria-pressed={ctrlMuted}\r\n >\r\n {getVolumeIcon()}\r\n </button>\r\n )}\r\n\r\n {enableFullscreen && (\r\n <button\r\n className=\"sdk-desktop-icon-btn\"\r\n onClick={(e) => { e.stopPropagation(); toggleFullscreen(); }}\r\n title={isFullscreen || isSimulatedFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\r\n aria-label={isFullscreen || isSimulatedFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\r\n aria-pressed={isFullscreen || isSimulatedFullscreen}\r\n >\r\n {isFullscreen ? <Minimize size={20} aria-hidden=\"true\" /> : <Maximize size={20} aria-hidden=\"true\" />}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import type { SdkInitResponse } from './types';\r\n\r\nexport const DEFAULT_API_BASE = 'https://dev-api.go-boss.com';\r\n\r\nfunction buildHeaders(playerKey: string): HeadersInit {\r\n return {\r\n 'x-player-key': playerKey,\r\n 'Content-Type': 'application/json',\r\n }\r\n}\r\n\r\nexport async function initSdk(playerKey: string, apiBase = DEFAULT_API_BASE): Promise<SdkInitResponse> {\r\n const res = await fetch(`${apiBase}/api/player/sdk/init`, {\r\n method: 'POST',\r\n headers: buildHeaders(playerKey),\r\n body: JSON.stringify({}),\r\n });\r\n if (!res.ok) throw new Error(`SDK init failed: ${res.status}`);\r\n const data = await res.json() as SdkInitResponse;\r\n console.log('[SDK] Init response:', data);\r\n return data;\r\n}\r\n\r\nexport async function startSession(\r\n playerKey: string,\r\n sessionId: string,\r\n videoId: string,\r\n apiBase = DEFAULT_API_BASE,\r\n): Promise<void> {\r\n const res = await fetch(`${apiBase}/api/player/sdk/session/start`, {\r\n method: 'POST',\r\n headers: buildHeaders(playerKey),\r\n body: JSON.stringify({ sessionId, videoId }),\r\n });\r\n if (!res.ok) throw new Error(`Session start failed: ${res.status}`);\r\n const data = await res.json().catch(() => null);\r\n console.log('[SDK] Session start response:', data);\r\n}\r\n\r\nexport async function sendHeartbeat(\r\n playerKey: string,\r\n sessionId: string,\r\n currentTime: number,\r\n duration: number,\r\n apiBase = DEFAULT_API_BASE,\r\n): Promise<void> {\r\n const payload = { sessionId, currentTime, duration };\r\n console.log('[SDK] Heartbeat request:', payload);\r\n const res = await fetch(`${apiBase}/api/player/sdk/session/heartbeat`, {\r\n method: 'POST',\r\n headers: buildHeaders(playerKey),\r\n body: JSON.stringify(payload),\r\n });\r\n if (!res.ok) throw new Error(`Heartbeat failed: ${res.status}`);\r\n const data = await res.json().catch(() => null);\r\n console.log('[SDK] Heartbeat response:', data);\r\n}\r\n\r\nexport async function endSession(\r\n playerKey: string,\r\n sessionId: string,\r\n apiBase = DEFAULT_API_BASE,\r\n): Promise<void> {\r\n const res = await fetch(`${apiBase}/api/player/sdk/session/end`, {\r\n method: 'POST',\r\n headers: buildHeaders(playerKey),\r\n body: JSON.stringify({ sessionId }),\r\n });\r\n if (!res.ok) throw new Error(`Session end failed: ${res.status}`);\r\n const data = await res.json().catch(() => null);\r\n console.log('[SDK] Session end response:', data);\r\n}\r\n\r\nexport function endSessionKeepalive(playerKey: string, sessionId: string, apiBase = DEFAULT_API_BASE): void {\r\n fetch(`${apiBase}/api/player/sdk/session/end`, {\r\n method: 'POST',\r\n headers: buildHeaders(playerKey),\r\n body: JSON.stringify({ sessionId }),\r\n keepalive: true,\r\n });\r\n}\r\n","import { useState, useEffect, useRef, useCallback } from 'react';\r\nimport { WebVideoPlayer, ErrorScreen } from '@goboss/ui-controls';\r\nimport type { FirebaseConfig } from '@goboss/analytics';\r\nimport type { Chapter, AnalyticsEvent } from '@goboss/types';\r\nimport { initSdk, startSession, sendHeartbeat, endSession, endSessionKeepalive } from './api';\r\nimport type { SdkInitResponse, SdkInitFeatures, SdkPackage, FeatureFlags, SubtitleStyle } from './types';\r\nimport type { DRMConfig, SubtitleTrack, SourceItem } from '@goboss/types';\r\n\r\n// Maps API feature names → player FeatureFlags keys.\r\n// Add a new entry here whenever the API adds a new feature.\r\nconst API_FEATURE_MAP: Record<string, keyof FeatureFlags> = {\r\n subtitles: 'subtitle_support',\r\n ads: 'ad_support',\r\n chapterMarkers: 'key_moments',\r\n playbackSpeed: 'playback_speed',\r\n airplay: 'airplay',\r\n chromecast: 'chromecast',\r\n pictureInPicture: 'picture_in_picture',\r\n multipleResolution: 'multiple_resolution',\r\n multipleAudio: 'multiple_audio',\r\n drmProtection: 'drm_protection',\r\n screenRecordingPrevention: 'screen_recording_prevention',\r\n signalStrength: 'signal_strength',\r\n};\r\n\r\nfunction mapApiFeatures(apiFeatures: SdkInitFeatures): FeatureFlags {\r\n const flags: FeatureFlags = {\r\n m3u8_playback: true,\r\n subtitle_support: false,\r\n playback_speed: false,\r\n airplay: false,\r\n chromecast: false,\r\n picture_in_picture: false,\r\n multiple_resolution: false,\r\n multiple_audio: false,\r\n key_moments: false,\r\n drm_protection: false,\r\n screen_recording_prevention: false,\r\n signal_strength: false,\r\n ad_support: false,\r\n };\r\n for (const [apiKey, playerKey] of Object.entries(API_FEATURE_MAP)) {\r\n if (apiKey in apiFeatures) {\r\n flags[playerKey] = apiFeatures[apiKey];\r\n }\r\n }\r\n return flags;\r\n}\r\n\r\n// Builds a URL transformer from a \"hostname=/proxyPath,hostname2=/proxyPath2\" string.\r\nfunction buildUrlTransformer(proxyDomains?: string): (url: string) => string {\r\n if (!proxyDomains) return (url) => url;\r\n const map: Array<{ domain: string; proxyPath: string }> = [];\r\n for (const entry of proxyDomains.split(',')) {\r\n const [domain, proxyPath] = entry.split('=');\r\n if (domain?.trim() && proxyPath?.trim()) {\r\n map.push({ domain: domain.trim(), proxyPath: proxyPath.trim() });\r\n }\r\n }\r\n return (url: string) => {\r\n for (const { domain, proxyPath } of map) {\r\n if (url.includes(domain)) {\r\n try {\r\n const urlObj = new URL(url);\r\n return `${proxyPath}${urlObj.pathname}${urlObj.search}`;\r\n } catch {\r\n return url.replace(`https://${domain}`, proxyPath);\r\n }\r\n }\r\n }\r\n return url;\r\n };\r\n}\r\n\r\nconst HEARTBEAT_WINDOW_MS = 30_000;\r\n\r\nexport interface BossVideoPlayerProps {\r\n /** Player key from the GoBOSS dashboard — identifies your tenant. */\r\n playerKey: string;\r\n /**\r\n * Stream source(s) to play.\r\n * - Pass a single URL string for standard single-stream playback.\r\n * - Pass an array of `{ label, url }` objects to let the user switch between\r\n * multiple streams at runtime (e.g. 4K, Dolby, Stereo). The first item plays by default.\r\n */\r\n src: string | SourceItem[];\r\n /**\r\n * External subtitle tracks (WebVTT/SRT) to load alongside any tracks\r\n * auto-detected from the M3U8 manifest. Merged into a single subtitle menu.\r\n */\r\n subtitles?: SubtitleTrack[];\r\n /** License key for playback authorization. */\r\n licenseKey?: string;\r\n /** Accent color for the player UI (hex). Defaults to '#6366f1'. */\r\n themeColor?: string;\r\n /** Firebase config for analytics. */\r\n firebaseConfig?: FirebaseConfig;\r\n /**\r\n * CDN proxy domain mappings as a comma-separated string.\r\n * Format: \"cdn.example.com=/my-proxy,other.cdn.com=/other-proxy\"\r\n * Any request URL matching a domain is rewritten to the proxy path.\r\n */\r\n proxyDomains?: string;\r\n /**\r\n * Base URL for the GoBOSS API. Defaults to 'https://dev-api.go-boss.com'.\r\n * Override this if you need to route through a reverse proxy.\r\n */\r\n apiBaseUrl?: string;\r\n /** AWS MediaTailor ad tracking URL for skip-ad flow. */\r\n adTrackingUrl?: string;\r\n /** AWS MediaTailor overlay ad tracking URL. */\r\n overlayAdUrl?: string;\r\n /** Video title shown in the player UI. */\r\n title?: string;\r\n /** Watermark text stamped on the video. */\r\n watermark?: string;\r\n autoplay?: boolean;\r\n muted?: boolean;\r\n autoFullscreen?: boolean;\r\n enableControls?: boolean;\r\n enableSkipAd?: boolean;\r\n skipAdAfterSeconds?: number;\r\n chaptersDisplayMode?: 'strip' | 'panel';\r\n volumeControlType?: 'slider' | 'button';\r\n subtitleStyle?: SubtitleStyle;\r\n drmConfig?: DRMConfig;\r\n /** Called for every analytics event — lets consumers add custom tracking. */\r\n onAnalyticsEvent?: (event: AnalyticsEvent) => void;\r\n /** Called when chapter/key-moment data is parsed from the stream. */\r\n onKeyMomentsLoaded?: (keyMoments: Chapter[]) => void;\r\n /** Seek to this position (in seconds) when the video is ready. Use for resume-playback. */\r\n initialTime?: number;\r\n /** Called on every timeupdate with the current playback position in seconds. Use to persist watch progress. */\r\n onTimeUpdate?: (currentTime: number) => void;\r\n}\r\n\r\nexport function BossVideoPlayer({\r\n playerKey,\r\n src,\r\n subtitles,\r\n licenseKey,\r\n themeColor = '#6366f1',\r\n firebaseConfig,\r\n proxyDomains,\r\n apiBaseUrl,\r\n adTrackingUrl,\r\n overlayAdUrl,\r\n title,\r\n watermark,\r\n autoplay = false,\r\n muted = false,\r\n autoFullscreen = false,\r\n enableControls = true,\r\n enableSkipAd,\r\n skipAdAfterSeconds,\r\n chaptersDisplayMode = 'strip',\r\n volumeControlType = 'slider',\r\n subtitleStyle,\r\n drmConfig,\r\n onAnalyticsEvent,\r\n onKeyMomentsLoaded,\r\n initialTime,\r\n onTimeUpdate,\r\n}: BossVideoPlayerProps) {\r\n const [keyMoments, setKeyMoments] = useState<Chapter[]>([]);\r\n const [activeSourceIdx, setActiveSourceIdx] = useState(0);\r\n\r\n // Normalize src into a SourceItem array so the rest of the component is uniform\r\n const normalizedSources: SourceItem[] = Array.isArray(src)\r\n ? src\r\n : [{ label: 'Default', url: src }];\r\n const activeSrc: string = normalizedSources[activeSourceIdx]?.url ?? normalizedSources[0]?.url ?? '';\r\n\r\n // ── Player key validation state ─────────────────────────────────────────────\r\n // 'loading': waiting for /sdk/init API response\r\n // 'ready': API confirmed — resolvedPackage holds the feature set\r\n // 'error': API rejected the key or network failed\r\n const [sdkStatus, setSdkStatus] = useState<'loading' | 'ready' | 'error'>('loading');\r\n const [resolvedPackage, setResolvedPackage] = useState<SdkPackage | null>(null);\r\n const [retryCount, setRetryCount] = useState(0);\r\n const [errorKind, setErrorKind] = useState<'auth' | 'network'>('network');\r\n\r\n const sdkDataRef = useRef<SdkInitResponse | null>(null);\r\n const isInAdBreakRef = useRef(false);\r\n const sessionIdRef = useRef('');\r\n const sessionStartedRef = useRef(false);\r\n // True from the moment the user switches source until real content actually plays again.\r\n // While true, the heartbeat window stays paused so the blank detection/fallback period of\r\n // an unsupported source (which fires no buffering events, only a hollow `play`) is never\r\n // counted as watched content.\r\n const awaitingSourcePlaybackRef = useRef(false);\r\n\r\n // Tracks real content time toward the 30s heartbeat window (excludes ads + pauses)\r\n const heartbeatTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n const elapsedInWindowRef = useRef(0);\r\n const windowStartRef = useRef<number | null>(null);\r\n const latestPlaybackRef = useRef({ currentTime: 0, duration: 0 });\r\n const startHeartbeatTimerRef = useRef<() => void>(() => {});\r\n\r\n // Derive a stable videoId from the last path segment of the active stream URL\r\n const srcSegments = activeSrc.split('/').filter(Boolean);\r\n const videoId = (srcSegments[srcSegments.length - 1] ?? '').replace(/\\.m3u8.*$/, '') || 'video';\r\n\r\n // Build URL transformer once when proxyDomains changes\r\n const urlTransformer = useCallback(\r\n () => buildUrlTransformer(proxyDomains),\r\n [proxyDomains],\r\n )();\r\n\r\n // Apply themeColor CSS variables\r\n useEffect(() => {\r\n document.documentElement.style.setProperty('--accent-indigo', themeColor);\r\n const cleanHex = themeColor.replace('#', '');\r\n let rgb = '99, 102, 241';\r\n if (cleanHex.length === 6) {\r\n const r = parseInt(cleanHex.substring(0, 2), 16);\r\n const g = parseInt(cleanHex.substring(2, 4), 16);\r\n const b = parseInt(cleanHex.substring(4, 6), 16);\r\n rgb = `${r}, ${g}, ${b}`;\r\n }\r\n document.documentElement.style.setProperty('--accent-indigo-rgb', rgb);\r\n }, [themeColor]);\r\n\r\n // Validate player key — blocks video until the API confirms the key and returns features.\r\n // Cleanup resets to 'loading' so playerKey/retryCount changes show a fresh loading state.\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n initSdk(playerKey, apiBaseUrl)\r\n .then(data => {\r\n if (cancelled) return;\r\n sdkDataRef.current = data;\r\n const { features, planTier } = data.result.data;\r\n const pkg: SdkPackage = {\r\n package: planTier,\r\n is_active: true,\r\n features: mapApiFeatures(features),\r\n limits: { streaming_minutes: 0 },\r\n };\r\n console.log('[SDK] Player key validated. Features:', pkg.features);\r\n setResolvedPackage(pkg);\r\n setSdkStatus('ready');\r\n })\r\n .catch(err => {\r\n if (cancelled) return;\r\n console.error('[SDK] Player key validation failed:', err);\r\n const msg = (err as Error).message ?? '';\r\n setErrorKind(/init failed: 4\\d\\d/.test(msg) ? 'auth' : 'network');\r\n setSdkStatus('error');\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n if (heartbeatTimerRef.current) {\r\n clearTimeout(heartbeatTimerRef.current);\r\n heartbeatTimerRef.current = null;\r\n }\r\n elapsedInWindowRef.current = 0;\r\n windowStartRef.current = null;\r\n setSdkStatus('loading');\r\n setResolvedPackage(null);\r\n sessionStartedRef.current = false;\r\n sessionIdRef.current = '';\r\n };\r\n }, [playerKey, apiBaseUrl, retryCount]);\r\n\r\n // Pauses the timer, saving accumulated time in current window\r\n const pauseHeartbeatTimer = useCallback(() => {\r\n if (!heartbeatTimerRef.current) return;\r\n clearTimeout(heartbeatTimerRef.current);\r\n heartbeatTimerRef.current = null;\r\n if (windowStartRef.current !== null) {\r\n elapsedInWindowRef.current += Date.now() - windowStartRef.current;\r\n windowStartRef.current = null;\r\n }\r\n }, []);\r\n\r\n // Stops the timer and resets the window\r\n const stopHeartbeatTimer = useCallback(() => {\r\n if (heartbeatTimerRef.current) {\r\n clearTimeout(heartbeatTimerRef.current);\r\n heartbeatTimerRef.current = null;\r\n }\r\n elapsedInWindowRef.current = 0;\r\n windowStartRef.current = null;\r\n }, []);\r\n\r\n // Starts (or resumes) the 30s real-content-time timer\r\n const startHeartbeatTimer = useCallback(() => {\r\n if (heartbeatTimerRef.current || !sessionIdRef.current) return;\r\n windowStartRef.current = Date.now();\r\n const remaining = HEARTBEAT_WINDOW_MS - elapsedInWindowRef.current;\r\n heartbeatTimerRef.current = setTimeout(() => {\r\n heartbeatTimerRef.current = null;\r\n elapsedInWindowRef.current = 0;\r\n windowStartRef.current = null;\r\n const { currentTime, duration } = latestPlaybackRef.current;\r\n console.log('[SDK] Heartbeat timer fired — 30s of real content elapsed');\r\n sendHeartbeat(playerKey, sessionIdRef.current, currentTime, duration, apiBaseUrl).catch(err =>\r\n console.warn('[SDK] Heartbeat failed:', (err as Error).message),\r\n );\r\n startHeartbeatTimerRef.current();\r\n }, remaining);\r\n }, [playerKey, apiBaseUrl]);\r\n\r\n useEffect(() => {\r\n startHeartbeatTimerRef.current = startHeartbeatTimer;\r\n }, [startHeartbeatTimer]);\r\n\r\n // Deterministic source-switch handling: the moment the user picks a different source,\r\n // pause the heartbeat window and mark that we're awaiting real playback. The new stream\r\n // (especially an unsupported one like Dolby/Atmos) emits no buffering events during its\r\n // blank detection period — only a hollow `play` — so this is the only reliable way to\r\n // stop counting that time. The window resumes when `buffering_end` confirms real frames\r\n // are rendering (in handleAnalytics). The first run (initial mount) is skipped.\r\n const isInitialSourceRef = useRef(true);\r\n useEffect(() => {\r\n if (isInitialSourceRef.current) {\r\n isInitialSourceRef.current = false;\r\n return;\r\n }\r\n awaitingSourcePlaybackRef.current = true;\r\n pauseHeartbeatTimer();\r\n }, [activeSourceIdx, pauseHeartbeatTimer]);\r\n\r\n // beforeunload: fire session end with keepalive so the request survives tab close\r\n useEffect(() => {\r\n const handleUnload = () => {\r\n if (!sessionIdRef.current) return;\r\n stopHeartbeatTimer();\r\n endSessionKeepalive(playerKey, sessionIdRef.current, apiBaseUrl);\r\n };\r\n window.addEventListener('beforeunload', handleUnload);\r\n return () => {\r\n window.removeEventListener('beforeunload', handleUnload);\r\n stopHeartbeatTimer();\r\n };\r\n }, [playerKey, apiBaseUrl, stopHeartbeatTimer]);\r\n\r\n const handleAnalytics = useCallback((event: AnalyticsEvent) => {\r\n const e = event as unknown as Record<string, unknown>;\r\n\r\n if (event.currentTime !== undefined) {\r\n latestPlaybackRef.current = { currentTime: event.currentTime, duration: event.duration };\r\n }\r\n\r\n if (event.eventType === 'session_start' && !sessionStartedRef.current) {\r\n sessionStartedRef.current = true;\r\n sessionIdRef.current = typeof e.sessionId === 'string' ? e.sessionId : '';\r\n startSession(playerKey, sessionIdRef.current, videoId, apiBaseUrl).catch(err =>\r\n console.warn('[SDK] Session start failed:', (err as Error).message),\r\n );\r\n if (!isInAdBreakRef.current) {\r\n startHeartbeatTimer();\r\n }\r\n }\r\n\r\n // `play` is also fired by an unsupported source's hollow autoplay attempt, so while a\r\n // source switch is awaiting real playback we must NOT let it resume the window.\r\n if (\r\n event.eventType === 'play' &&\r\n sessionStartedRef.current &&\r\n !isInAdBreakRef.current &&\r\n !awaitingSourcePlaybackRef.current\r\n ) {\r\n startHeartbeatTimer();\r\n }\r\n\r\n if (event.eventType === 'pause') {\r\n pauseHeartbeatTimer();\r\n }\r\n\r\n // Normal buffering is not \"real content played\" — pause during it.\r\n if (event.eventType === 'buffering_start') {\r\n pauseHeartbeatTimer();\r\n }\r\n\r\n // `buffering_end` only fires when frames actually render (it's gated by a real\r\n // buffering→playing transition), so it's the reliable \"content is truly playing again\"\r\n // signal. Clear the source-switch wait and resume the window here.\r\n if (event.eventType === 'buffering_end' && sessionStartedRef.current && !isInAdBreakRef.current) {\r\n awaitingSourcePlaybackRef.current = false;\r\n startHeartbeatTimer();\r\n }\r\n\r\n if (event.eventType === 'ended') {\r\n stopHeartbeatTimer();\r\n if (sessionIdRef.current) {\r\n endSession(playerKey, sessionIdRef.current).catch(err =>\r\n console.warn('[SDK] Session end failed:', (err as Error).message),\r\n );\r\n }\r\n }\r\n\r\n console.log('[SDK Analytics]', event);\r\n onAnalyticsEvent?.(event);\r\n }, [playerKey, apiBaseUrl, videoId, startHeartbeatTimer, pauseHeartbeatTimer, stopHeartbeatTimer, onAnalyticsEvent]);\r\n\r\n const handleAdBreakChange = useCallback((active: boolean) => {\r\n isInAdBreakRef.current = active;\r\n if (active) {\r\n pauseHeartbeatTimer();\r\n console.log('[SDK] Ad break started — heartbeat timer paused');\r\n } else {\r\n if (sessionStartedRef.current) startHeartbeatTimer();\r\n console.log('[SDK] Ad break ended — heartbeat timer resumed');\r\n }\r\n }, [pauseHeartbeatTimer, startHeartbeatTimer]);\r\n\r\n const handleKeyMomentsLoaded = useCallback((parsed: Chapter[]) => {\r\n setKeyMoments(parsed);\r\n onKeyMomentsLoaded?.(parsed);\r\n }, [onKeyMomentsLoaded]);\r\n\r\n if (sdkStatus === 'loading') {\r\n return (\r\n <div style={{\r\n width: '100%', aspectRatio: '16 / 9', background: '#000', borderRadius: 8,\r\n display: 'flex', alignItems: 'center', justifyContent: 'center',\r\n }}>\r\n <style>{`@keyframes boss-sdk-spin{to{transform:rotate(360deg)}}`}</style>\r\n <div style={{\r\n width: 32, height: 32, borderRadius: '50%',\r\n border: `3px solid rgba(255,255,255,0.12)`,\r\n borderTopColor: themeColor,\r\n animation: 'boss-sdk-spin 0.7s linear infinite',\r\n }} />\r\n </div>\r\n );\r\n }\r\n\r\n if (sdkStatus === 'error') {\r\n const isAuth = errorKind === 'auth';\r\n return (\r\n <div style={{\r\n width: '100%', aspectRatio: '16 / 9', background: '#09090e', borderRadius: 8,\r\n display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 20,\r\n }}>\r\n <ErrorScreen\r\n title={isAuth ? 'Invalid Player Key' : 'Something Went Wrong'}\r\n subtitle={\r\n isAuth\r\n ? 'Your player key is invalid or expired.\\nPlease check your configuration.'\r\n : 'We encountered an error while connecting.\\nPlease try again.'\r\n }\r\n onRetry={() => setRetryCount(c => c + 1)}\r\n />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <WebVideoPlayer\r\n src={activeSrc}\r\n sources={normalizedSources}\r\n activeSourceIndex={activeSourceIdx}\r\n onSourceChange={(idx: number) => setActiveSourceIdx(idx)}\r\n subtitles={subtitles}\r\n keyMoments={keyMoments}\r\n themeColor={themeColor}\r\n firebaseConfig={firebaseConfig}\r\n resolvedEntitlement={resolvedPackage}\r\n licenseKey={licenseKey}\r\n title={title}\r\n watermark={watermark}\r\n autoplay={autoplay}\r\n muted={muted}\r\n autoFullscreen={autoFullscreen}\r\n enableControls={enableControls}\r\n enableSkipAd={enableSkipAd}\r\n skipAdAfterSeconds={skipAdAfterSeconds}\r\n chaptersDisplayMode={chaptersDisplayMode}\r\n volumeControlType={volumeControlType}\r\n subtitleStyle={subtitleStyle}\r\n drmConfig={drmConfig}\r\n overlayAdUrl={overlayAdUrl}\r\n adTrackingUrl={adTrackingUrl}\r\n urlTransformer={urlTransformer}\r\n onAnalyticsEvent={handleAnalytics}\r\n onAdBreakChange={handleAdBreakChange}\r\n onKeyMomentsLoaded={handleKeyMomentsLoaded}\r\n initialTime={initialTime}\r\n onTimeUpdate={onTimeUpdate}\r\n />\r\n );\r\n}\r\n","import React, { createElement } from 'react';\r\nimport { createRoot } from 'react-dom/client';\r\nimport { BossVideoPlayer } from './BossVideoPlayer';\r\nimport type { BossVideoPlayerProps } from './BossVideoPlayer';\r\n\r\nexport interface PlayerProps extends BossVideoPlayerProps {}\r\n\r\nexport interface PlayerInstance {\r\n /** Re-render the player with updated props (src change, theme, etc.) */\r\n update(props: Partial<PlayerProps>): void;\r\n /** Unmounts the player and releases all resources */\r\n destroy(): void;\r\n}\r\n\r\n/**\r\n * Mounts the full video player into any DOM element.\r\n * Identical to <BossVideoPlayer> — handles player key validation, feature gating,\r\n * session tracking, and heartbeat automatically.\r\n *\r\n * Use this in Vue, Angular, Vanilla JS, or any environment where JSX is unavailable.\r\n *\r\n * @example Vanilla JS\r\n * const player = createPlayer(document.getElementById('player'), {\r\n * playerKey: 'bsp_abc123',\r\n * src: 'https://my-cdn.com/video.m3u8',\r\n * });\r\n * player.destroy(); // cleanup\r\n *\r\n * @example Vue 3\r\n * const player = createPlayer(containerRef.value, { playerKey: 'bsp_abc123', src: props.src });\r\n * onUnmounted(() => player.destroy());\r\n *\r\n * @example Angular\r\n * const player = createPlayer(this.containerRef.nativeElement, { playerKey: 'bsp_abc123', src: this.src });\r\n * ngOnDestroy() { this.player.destroy(); }\r\n */\r\nexport function createPlayer(container: HTMLElement, props: PlayerProps): PlayerInstance {\r\n const root = createRoot(container);\r\n let currentProps = props;\r\n\r\n root.render(createElement(BossVideoPlayer as React.FC<PlayerProps>, currentProps));\r\n\r\n return {\r\n update(newProps: Partial<PlayerProps>) {\r\n currentProps = { ...currentProps, ...newProps };\r\n root.render(createElement(BossVideoPlayer as React.FC<PlayerProps>, currentProps));\r\n },\r\n destroy() {\r\n root.unmount();\r\n },\r\n };\r\n}\r\n"],"x_google_ignoreList":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29],"mappings":"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"}
|