itube-modern-player 0.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +630 -0
  3. package/dist/core/dom.d.ts +18 -0
  4. package/dist/core/events.d.ts +10 -0
  5. package/dist/core/icons.d.ts +3 -0
  6. package/dist/core/labels.d.ts +2 -0
  7. package/dist/core/localeRegistry.d.ts +7 -0
  8. package/dist/core/locales.d.ts +11 -0
  9. package/dist/core.cjs +5 -0
  10. package/dist/core.cjs.map +1 -0
  11. package/dist/core.js +1668 -0
  12. package/dist/core.js.map +1 -0
  13. package/dist/coreEntry.d.ts +14 -0
  14. package/dist/features/ads/manager.d.ts +48 -0
  15. package/dist/features/ads/vast.d.ts +9 -0
  16. package/dist/features/chapters.d.ts +12 -0
  17. package/dist/features/heatmap.d.ts +17 -0
  18. package/dist/features/hls.d.ts +26 -0
  19. package/dist/features/thumbnails.d.ts +11 -0
  20. package/dist/global.d.ts +2 -0
  21. package/dist/index.cjs +2 -0
  22. package/dist/index.cjs.map +1 -0
  23. package/dist/index.d.ts +7 -0
  24. package/dist/index.js +28 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/itube-modern-player.iife.js +5 -0
  27. package/dist/itube-modern-player.iife.js.map +1 -0
  28. package/dist/labels-C3gAZEm-.js +41 -0
  29. package/dist/labels-C3gAZEm-.js.map +1 -0
  30. package/dist/labels-DTgTxMuq.cjs +2 -0
  31. package/dist/labels-DTgTxMuq.cjs.map +1 -0
  32. package/dist/lazy.cjs +2 -0
  33. package/dist/lazy.cjs.map +1 -0
  34. package/dist/lazy.d.ts +23 -0
  35. package/dist/lazy.js +60 -0
  36. package/dist/lazy.js.map +1 -0
  37. package/dist/locales.cjs +2 -0
  38. package/dist/locales.cjs.map +1 -0
  39. package/dist/locales.js +380 -0
  40. package/dist/locales.js.map +1 -0
  41. package/dist/localesEntry.d.ts +8 -0
  42. package/dist/player.d.ts +142 -0
  43. package/dist/style.css +1 -0
  44. package/dist/types.d.ts +443 -0
  45. package/dist/ui/controls.d.ts +90 -0
  46. package/dist/ui/menu.d.ts +29 -0
  47. package/dist/ui/overlays.d.ts +51 -0
  48. package/dist/ui/playlistPanel.d.ts +16 -0
  49. package/dist/ui/progress.d.ts +41 -0
  50. package/dist/ui/scenesPanel.d.ts +19 -0
  51. package/dist/vue.cjs +2 -0
  52. package/dist/vue.cjs.map +1 -0
  53. package/dist/vue.d.ts +67 -0
  54. package/dist/vue.js +89 -0
  55. package/dist/vue.js.map +1 -0
  56. package/package.json +86 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sources":["../src/core/dom.ts","../src/core/events.ts","../src/core/icons.ts","../src/core/localeRegistry.ts","../src/features/heatmap.ts","../src/features/ads/vast.ts","../src/features/ads/manager.ts","../src/features/chapters.ts","../src/features/hls.ts","../src/features/thumbnails.ts","../src/ui/menu.ts","../src/ui/progress.ts","../src/ui/controls.ts","../src/ui/overlays.ts","../src/ui/playlistPanel.ts","../src/ui/scenesPanel.ts","../src/player.ts"],"sourcesContent":["/** DOM helpers. All player markup is built through these — no innerHTML templates. */\n\nexport function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n className?: string,\n attrs?: Record<string, string>,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag)\n if (className) node.className = className\n if (attrs) {\n for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, value)\n }\n return node\n}\n\n/** Icon-only button with an accessible label. */\nexport function iconButton(className: string, label: string, svg: string): HTMLButtonElement {\n const btn = el('button', `imp-btn ${className}`, { type: 'button', 'aria-label': label, title: label })\n btn.innerHTML = svg\n return btn\n}\n\nexport function setIcon(btn: HTMLButtonElement, svg: string, label?: string): void {\n btn.innerHTML = svg\n if (label !== undefined) {\n btn.setAttribute('aria-label', label)\n btn.setAttribute('title', label)\n }\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value))\n}\n\n/** `73` → `\"1:13\"`, `3673` → `\"1:01:13\"`. Infinity/NaN → `\"0:00\"`. */\nexport function formatTime(seconds: number): string {\n if (!Number.isFinite(seconds) || seconds < 0) return '0:00'\n const s = Math.floor(seconds % 60)\n const m = Math.floor((seconds / 60) % 60)\n const h = Math.floor(seconds / 3600)\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m)\n const ss = String(s).padStart(2, '0')\n return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`\n}\n\n/** Parse `\"00:01:02.500\"` / `\"01:02.500\"` VTT timestamps into seconds. */\nexport function parseVttTime(raw: string): number | null {\n const m = raw.trim().match(/^(?:(\\d+):)?(\\d{1,2}):(\\d{2})(?:[.,](\\d{1,3}))?$/)\n if (!m) return null\n const h = m[1] ? Number(m[1]) : 0\n const min = Number(m[2])\n const s = Number(m[3])\n const ms = m[4] ? Number(m[4].padEnd(3, '0')) : 0\n return h * 3600 + min * 60 + s + ms / 1000\n}\n\n/** Tiny WebVTT cue parser — enough for chapters and thumbnail tracks. */\nexport function parseVttCues(text: string): Array<{ start: number; end: number; text: string }> {\n const cues: Array<{ start: number; end: number; text: string }> = []\n // Normalize newlines, drop the WEBVTT header block, split into cue blocks.\n const blocks = text.replace(/\\r\\n?/g, '\\n').split(/\\n\\n+/)\n for (const block of blocks) {\n const lines = block.split('\\n').filter((l) => l.trim() !== '')\n if (lines.length === 0) continue\n let timingIndex = lines.findIndex((l) => l.includes('-->'))\n if (timingIndex === -1) continue\n const [rawStart, rawEnd] = lines[timingIndex].split('-->')\n const start = parseVttTime(rawStart)\n const end = parseVttTime((rawEnd ?? '').split(' ')[1] ?? rawEnd ?? '')\n ?? parseVttTime(rawEnd ?? '')\n if (start === null || end === null) continue\n const cueText = lines.slice(timingIndex + 1).join('\\n').trim()\n if (cueText) cues.push({ start, end, text: cueText })\n }\n return cues\n}\n\n/** Resolve `url` against the location of the VTT file it came from. */\nexport function resolveUrl(url: string, base: string): string {\n try {\n return new URL(url, new URL(base, window.location.href)).toString()\n } catch {\n return url\n }\n}\n","/** Minimal strictly-typed event emitter. No globals, no wildcard magic. */\nexport class Emitter<M> {\n private listeners = new Map<keyof M, Set<(payload: never) => void>>()\n\n /** Subscribe. Returns an unsubscribe function. */\n on<K extends keyof M>(event: K, fn: (payload: M[K]) => void): () => void {\n let set = this.listeners.get(event)\n if (!set) {\n set = new Set()\n this.listeners.set(event, set)\n }\n set.add(fn as (payload: never) => void)\n return () => this.off(event, fn)\n }\n\n once<K extends keyof M>(event: K, fn: (payload: M[K]) => void): () => void {\n const off = this.on(event, (payload) => {\n off()\n fn(payload)\n })\n return off\n }\n\n off<K extends keyof M>(event: K, fn: (payload: M[K]) => void): void {\n this.listeners.get(event)?.delete(fn as (payload: never) => void)\n }\n\n emit<K extends keyof M>(event: K, payload: M[K]): void {\n const set = this.listeners.get(event)\n if (!set) return\n for (const fn of [...set]) {\n try {\n ;(fn as (payload: M[K]) => void)(payload)\n } catch (err) {\n // A broken consumer listener must not break the player.\n console.error('[itube-player] listener error', err)\n }\n }\n }\n\n removeAll(): void {\n this.listeners.clear()\n }\n}\n","import type { IconName } from '../types'\n\nconst svg = (body: string, viewBox = '0 0 24 24') =>\n `<svg viewBox=\"${viewBox}\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">${body}</svg>`\n\n/** Default icon set. Every icon can be replaced via `options.icons`. */\nexport const defaultIcons: Record<IconName, string> = {\n play: svg('<path d=\"M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z\"/>'),\n pause: svg('<rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\"/><rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\"/>'),\n replay: svg('<path d=\"M12 5V2.5L7.5 6 12 9.5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7Z\"/>'),\n bigPlay: svg('<path d=\"M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z\"/>'),\n volumeHigh: svg('<path d=\"M4 9v6h3.5L12 19.5v-15L7.5 9H4Z\"/><path d=\"M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z\"/><path d=\"M14.5 5.2a8 8 0 0 1 0 13.6v-2a6 6 0 0 0 0-9.6v-2Z\"/>'),\n volumeLow: svg('<path d=\"M4 9v6h3.5L12 19.5v-15L7.5 9H4Z\"/><path d=\"M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z\"/>'),\n volumeMute: svg('<path d=\"M4 9v6h3.5L12 19.5v-15L7.5 9H4Z\"/><path d=\"m15.3 9.3 1.4 1.4 1.4-1.4 1.4 1.4-1.4 1.4 1.4 1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4Z\"/>'),\n fullscreen: svg('<path d=\"M5 5h5v2H7v3H5V5Zm9 0h5v5h-2V7h-3V5ZM5 14h2v3h3v2H5v-5Zm12 0h2v5h-5v-2h3v-3Z\"/>'),\n fullscreenExit: svg('<path d=\"M10 10H5V8h3V5h2v5Zm4 0V5h2v3h3v2h-5Zm-4 4v5H8v-3H5v-2h5Zm4 0h5v2h-3v3h-2v-5Z\"/>'),\n pip: svg('<path d=\"M3 5h18v14H3V5Zm2 2v10h14V7H5Z\"/><rect x=\"12\" y=\"11\" width=\"6\" height=\"4\"/>'),\n settings: svg('<path d=\"M12 8.5A3.5 3.5 0 1 0 12 15.5 3.5 3.5 0 0 0 12 8.5Zm0 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z\"/><path d=\"M10.3 2.8 9.9 5.1a7 7 0 0 0-1.5.86l-2.2-.8-1.7 3 1.8 1.5a7 7 0 0 0 0 1.7l-1.8 1.5 1.7 3 2.2-.8c.46.36.97.65 1.5.86l.4 2.3h3.4l.4-2.3a7 7 0 0 0 1.5-.86l2.2.8 1.7-3-1.8-1.5a7 7 0 0 0 0-1.7l1.8-1.5-1.7-3-2.2.8a7 7 0 0 0-1.5-.86l-.4-2.3h-3.4Zm1.7 5.7a3.5 3.5 0 1 1 0 7 3.5 3.5 0 0 1 0-7Z\"/>'),\n speed: svg('<path d=\"M12 4a9 9 0 0 0-9 9 8.96 8.96 0 0 0 1.62 5.16l1.64-1.15A7 7 0 0 1 5 13a7 7 0 1 1 12.74 4.01l1.64 1.15A8.96 8.96 0 0 0 21 13a9 9 0 0 0-9-9Z\"/><path d=\"m15.6 8.3-3.95 3.13a1.5 1.5 0 1 0 1.92 1.92L16.7 9.4a.78.78 0 0 0-1.1-1.1Z\"/>'),\n scenes: svg('<path d=\"M3 5h18v14H3V5Zm2 2v10h3V7H5Zm5 0v10h9V7h-9Zm-5 3h3v1H5v-1Zm0 3h3v1H5v-1Z\"/>'),\n shuffle: svg('<path d=\"M4 6h2.6c1.5 0 2.9.7 3.8 1.9l4.1 5.4a2.75 2.75 0 0 0 2.2 1.1H19l-1.8-1.8 1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 16.4h-2.3a4.75 4.75 0 0 1-3.8-1.9L8.8 9.1A2.75 2.75 0 0 0 6.6 8H4V6Z\"/><path d=\"M19 7.6h-2.3c-.86 0-1.67.41-2.18 1.1l-.93 1.23-1.25-1.65.58-.77A4.75 4.75 0 0 1 16.7 5.6H19L17.2 3.8l1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 7.6Z\" transform=\"translate(0 1.2)\"/>'),\n repeat: svg('<path d=\"M7 7h10v2.5L21 6l-4-3.5V5H5v6h2V7Zm10 10H7v-2.5L3 18l4 3.5V19h12v-6h-2v4Z\"/>'),\n subtitles: svg('<path d=\"M3 5h18v14H3V5Zm2 2v10h14V7H5Zm2 3h6v2H7v-2Zm8 0h2v2h-2v-2ZM7 14h2v2H7v-2Zm4 0h6v2h-6v-2Z\"/>'),\n list: svg('<path d=\"M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z\"/>'),\n next: svg('<path d=\"M6 5.5v13c0 .77.84 1.25 1.5.85l9-6.5a1 1 0 0 0 0-1.7l-9-6.5c-.66-.4-1.5.08-1.5.85Z\"/><rect x=\"17\" y=\"5\" width=\"2.5\" height=\"14\" rx=\"1\"/>'),\n previous: svg('<path d=\"M18 5.5v13c0 .77-.84 1.25-1.5.85l-9-6.5a1 1 0 0 1 0-1.7l9-6.5c.66-.4 1.5.08 1.5.85Z\"/><rect x=\"4.5\" y=\"5\" width=\"2.5\" height=\"14\" rx=\"1\"/>'),\n seekForward: svg('<path d=\"M12 4V1.5L17 5.5 12 9.5V7a5.5 5.5 0 1 0 5.5 5.5H20A8 8 0 1 1 12 4Z\"/>'),\n seekBack: svg('<path d=\"M12 4V1.5L7 5.5 12 9.5V7a5.5 5.5 0 1 1-5.5 5.5H4A8 8 0 1 0 12 4Z\"/>'),\n like: svg('<path d=\"M9 21H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h4v11Zm2 0h7.1a2 2 0 0 0 2-1.6l1.3-7a2 2 0 0 0-2-2.4H14V5.5A2.5 2.5 0 0 0 11.5 3l-.5.1V10h-.9L11 21Z\"/>'),\n dislike: svg('<path d=\"M15 3h4a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-4V3Zm-2 0H5.9a2 2 0 0 0-2 1.6l-1.3 7a2 2 0 0 0 2 2.4H10v4.5A2.5 2.5 0 0 0 12.5 21l.5-.1V14h.9L13 3Z\"/>'),\n addTo: svg('<path d=\"M4 6h12v2H4V6Zm0 4h12v2H4v-2Zm0 4h8v2H4v-2Zm14 0v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4Z\"/>'),\n share: svg('<path d=\"M18 8a3 3 0 1 0-2.83-4H15a3 3 0 0 0 .14 1.06L8.4 8.94a3 3 0 1 0 0 6.12l6.74 3.88A3 3 0 1 0 16 16.6l-6.74-3.88a3.03 3.03 0 0 0 0-1.44L16 7.4c.55.38 1.24.6 2 .6Z\"/>'),\n report: svg('<path d=\"M5 3h2v18H5V3Zm4 1h10l-2.5 4L19 12H9V4Z\"/>'),\n more: svg('<circle cx=\"12\" cy=\"5\" r=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/><circle cx=\"12\" cy=\"19\" r=\"2\"/>'),\n close: svg('<path d=\"m6.4 5 5.6 5.6L17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6 10.6 12 5 6.4 6.4 5Z\"/>'),\n}\n","import type { PlayerLabels } from '../types'\nimport { defaultLabels } from './labels'\n\n/**\n * Locale registry. The core only ships English; the main package entry\n * registers all built-in dictionaries, while `itube-modern-player/core`\n * leaves them out so size-conscious builds can register just one:\n *\n * ```ts\n * import { Player, registerLocale } from 'itube-modern-player/core'\n * import { locales } from 'itube-modern-player/locales'\n * registerLocale('ru', locales.ru)\n * ```\n */\nconst registry: Partial<Record<string, PlayerLabels>> = { en: defaultLabels }\n\nexport function registerLocale(code: string, labels: PlayerLabels): void {\n registry[code] = labels\n}\n\nexport function registerLocales(map: Partial<Record<string, PlayerLabels>>): void {\n for (const [code, labels] of Object.entries(map)) {\n if (labels) registry[code] = labels\n }\n}\n\n/** Resolve a registered locale with graceful fallback to English. */\nexport function getLocale(code: string | undefined): PlayerLabels {\n return (code && registry[code]) || defaultLabels\n}\n\n/** Codes currently registered (built-ins and custom). */\nexport function registeredLanguages(): string[] {\n return Object.keys(registry)\n}\n","import type { HeatmapPoint } from '../types'\n\n/**\n * Popularity heatmap (\"most replayed\") math.\n *\n * Input is sparse: only the moments the backend has data for. Pipeline:\n * 1. bucket the duration into `buckets` slots and sum the samples into them;\n * 2. gaussian-ish smoothing (±2 window) so isolated spikes become hills;\n * 3. normalize by the maximum, with a base floor so the curve never collapses\n * to zero — flat areas read as \"watched\", not \"missing data\".\n */\nexport function buildHeatmapValues(points: HeatmapPoint[], duration: number, buckets = 100): number[] {\n if (points.length === 0 || !Number.isFinite(duration) || duration <= 0) return []\n\n const raw = new Array<number>(buckets).fill(0)\n let hasData = false\n for (const point of points) {\n if (!Number.isFinite(point.time) || point.time < 0 || point.time > duration) continue\n const value = Math.max(0, point.value)\n if (value === 0) continue\n const index = Math.min(buckets - 1, Math.floor((point.time / duration) * buckets))\n raw[index] += value\n hasData = true\n }\n if (!hasData) return []\n\n const kernel = [0.06, 0.24, 0.4, 0.24, 0.06]\n const smooth = raw.map((_, i) =>\n kernel.reduce((acc, k, j) => acc + k * (raw[i + j - 2] ?? 0), 0),\n )\n\n const max = Math.max(...smooth)\n if (max <= 0) return []\n const FLOOR = 0.08\n return smooth.map((v) => FLOOR + (1 - FLOOR) * (v / max))\n}\n\n/**\n * Build an SVG area path for normalized values (0..1) in a `width`×`height`\n * viewBox. Rendered with `preserveAspectRatio=\"none\"`, so the numbers are\n * arbitrary units, not pixels.\n */\nexport function heatmapPath(values: number[], width = 1000, height = 100): string {\n if (values.length === 0) return ''\n const step = width / (values.length - 1 || 1)\n let d = `M 0 ${height}`\n values.forEach((v, i) => {\n d += ` L ${(i * step).toFixed(1)} ${(height - v * height).toFixed(1)}`\n })\n d += ` L ${width} ${height} Z`\n return d\n}\n","import type { AdRoll, AdsOptions, ResolvedAd } from '../../types'\n\n/**\n * Minimal VAST 2/3/4 resolver — the same subset fluid-player consumes:\n * InLine Linear creatives, Wrapper redirects, MediaFiles, ClickThrough,\n * Impression and quartile tracking, skipoffset.\n */\nexport async function resolveVast(roll: AdRoll, opts: Required<Pick<AdsOptions, 'maxWrapperDepth' | 'requestTimeout'>>): Promise<ResolvedAd> {\n if (roll.src) {\n // Direct media file — no VAST round-trip needed.\n return {\n roll: roll.roll,\n mediaUrl: roll.src,\n clickThrough: roll.clickUrl,\n impressions: [],\n tracking: {},\n }\n }\n if (!roll.vastTag) throw new Error('Ad roll has neither \"vastTag\" nor \"src\"')\n return fetchAndParse(roll, roll.vastTag, opts, 0, { impressions: [], tracking: {} })\n}\n\ninterface Accumulated {\n impressions: string[]\n tracking: ResolvedAd['tracking']\n}\n\nasync function fetchAndParse(\n roll: AdRoll,\n tagUrl: string,\n opts: { maxWrapperDepth: number; requestTimeout: number },\n depth: number,\n acc: Accumulated,\n): Promise<ResolvedAd> {\n if (depth > opts.maxWrapperDepth) throw new Error('VAST wrapper depth limit exceeded')\n\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), opts.requestTimeout)\n let xmlText: string\n try {\n const res = await fetch(tagUrl, { signal: controller.signal, credentials: 'omit' })\n if (!res.ok) throw new Error(`VAST request failed (${res.status})`)\n xmlText = await res.text()\n } finally {\n clearTimeout(timer)\n }\n\n const doc = new DOMParser().parseFromString(xmlText, 'text/xml')\n if (doc.querySelector('parsererror')) throw new Error('VAST response is not valid XML')\n\n const ad = doc.querySelector('VAST > Ad')\n if (!ad) throw new Error('VAST response contains no ads')\n\n collectTracking(ad, acc)\n\n const wrapper = ad.querySelector(':scope > Wrapper')\n if (wrapper) {\n const nextTag = textOf(wrapper.querySelector('VASTAdTagURI'))\n if (!nextTag) throw new Error('VAST wrapper without VASTAdTagURI')\n return fetchAndParse(roll, nextTag, opts, depth + 1, acc)\n }\n\n const inline = ad.querySelector(':scope > InLine')\n if (!inline) throw new Error('VAST ad has neither InLine nor Wrapper')\n\n const linear = inline.querySelector('Creatives > Creative > Linear')\n if (!linear) throw new Error('VAST ad has no Linear creative')\n\n const media = pickMediaFile(linear)\n if (!media) throw new Error('VAST ad has no playable MediaFile')\n\n return {\n roll: roll.roll,\n mediaUrl: media.url,\n mediaType: media.type,\n clickThrough: textOf(linear.querySelector('VideoClicks > ClickThrough')) ?? roll.clickUrl,\n duration: parseDuration(textOf(linear.querySelector(':scope > Duration'))),\n skipOffset: parseSkipOffset(\n linear.getAttribute('skipoffset'),\n parseDuration(textOf(linear.querySelector(':scope > Duration'))),\n ),\n impressions: acc.impressions,\n tracking: acc.tracking,\n adTitle: textOf(inline.querySelector(':scope > AdTitle')) ?? undefined,\n }\n}\n\n/** Impressions, quartile tracking and click tracking accumulate across wrappers. */\nfunction collectTracking(ad: Element, acc: Accumulated): void {\n for (const node of ad.querySelectorAll('Impression')) {\n const url = textOf(node)\n if (url) acc.impressions.push(url)\n }\n for (const node of ad.querySelectorAll('Linear > TrackingEvents > Tracking')) {\n const event = node.getAttribute('event') as keyof ResolvedAd['tracking'] | null\n const url = textOf(node)\n if (!event || !url) continue\n if (!['start', 'firstQuartile', 'midpoint', 'thirdQuartile', 'complete', 'skip', 'pause', 'resume'].includes(event)) continue\n ;(acc.tracking[event] ??= []).push(url)\n }\n for (const node of ad.querySelectorAll('Linear > VideoClicks > ClickTracking')) {\n const url = textOf(node)\n if (url) (acc.tracking.click ??= []).push(url)\n }\n}\n\nfunction pickMediaFile(linear: Element): { url: string; type?: string } | null {\n const files = [...linear.querySelectorAll('MediaFiles > MediaFile')]\n .map((node) => ({\n url: textOf(node) ?? '',\n type: node.getAttribute('type') ?? undefined,\n delivery: node.getAttribute('delivery') ?? '',\n bitrate: Number(node.getAttribute('bitrate') ?? 0),\n apiFramework: node.getAttribute('apiFramework') ?? '',\n }))\n // VPAID needs a JS runtime we deliberately do not ship.\n .filter((f) => f.url && f.apiFramework.toUpperCase() !== 'VPAID')\n\n const playable = files.filter(\n (f) => !f.type || /(video\\/(mp4|webm|ogg)|application\\/(x-mpegurl|vnd\\.apple\\.mpegurl))/i.test(f.type),\n )\n if (playable.length === 0) return null\n // Mid-bitrate progressive file is the safest default.\n playable.sort((a, b) => a.bitrate - b.bitrate)\n const progressive = playable.filter((f) => f.delivery !== 'streaming')\n const pool = progressive.length > 0 ? progressive : playable\n const pick = pool[Math.floor(pool.length / 2)]\n return { url: pick.url, type: pick.type }\n}\n\n/** `\"00:00:15\"` / `\"00:15.250\"` → seconds. */\nfunction parseDuration(raw: string | null): number | undefined {\n if (!raw) return undefined\n const m = raw.trim().match(/^(?:(\\d+):)?(\\d{1,2}):(\\d{2})(?:\\.(\\d{1,3}))?$/)\n if (!m) return undefined\n return (m[1] ? Number(m[1]) * 3600 : 0) + Number(m[2]) * 60 + Number(m[3]) + (m[4] ? Number(m[4].padEnd(3, '0')) / 1000 : 0)\n}\n\n/** skipoffset is either a timestamp or a percentage of the ad duration. */\nfunction parseSkipOffset(raw: string | null, duration: number | undefined): number | undefined {\n if (!raw) return undefined\n const pct = raw.trim().match(/^(\\d+(?:\\.\\d+)?)%$/)\n if (pct) return duration !== undefined ? (Number(pct[1]) / 100) * duration : undefined\n return parseDuration(raw)\n}\n\n/** Fire a tracking pixel without caring about the response. */\nexport function firePixels(urls: string[] | undefined): void {\n if (!urls) return\n for (const url of urls) {\n try {\n new Image().src = url\n } catch {\n /* tracking must never throw */\n }\n }\n}\n\nfunction textOf(node: Element | null): string | null {\n const text = node?.textContent?.trim().replace(/^<!\\[CDATA\\[|\\]\\]>$/g, '').trim()\n return text || null\n}\n","import { el, formatTime } from '../../core/dom'\nimport type { Emitter } from '../../core/events'\nimport type { AdRoll, AdsOptions, PlayerEventMap, PlayerLabels, ResolvedAd } from '../../types'\nimport { firePixels, resolveVast } from './vast'\n\ninterface AdHost {\n container: HTMLElement\n contentVideo: HTMLVideoElement\n emitter: Emitter<PlayerEventMap>\n labels: PlayerLabels\n closeIcon: string\n}\n\n/**\n * Plays pre/mid/post rolls in a dedicated <video> layered over the content.\n * The content element is never touched, so its position, HLS session and\n * text tracks survive every ad break.\n */\nexport class AdManager {\n private opts: Required<Pick<AdsOptions, 'skipDelay' | 'maxWrapperDepth' | 'requestTimeout' | 'mediaTimeout' | 'playOn'>> & AdsOptions\n private playedRolls = new Set<AdRoll>()\n private sourcesSeen = 0\n private activeBreak: Promise<void> | null = null\n private layer: HTMLElement | null = null\n private adVideo: HTMLVideoElement | null = null\n private destroyed = false\n\n /**\n * Create (once) and \"bless\" the ad <video> synchronously inside the user\n * gesture that started playback. A bare `load()` during the gesture lets\n * the later `play()` succeed even though VAST fetches happen in between —\n * the same trick every ad SDK uses for iOS/strict autoplay policies.\n */\n private ensureAdVideo(): HTMLVideoElement {\n if (!this.adVideo) {\n this.adVideo = el('video', 'imp-ad__video', { playsinline: '' })\n try {\n this.adVideo.load()\n } catch {\n /* some engines throw on load() without src — harmless */\n }\n }\n return this.adVideo\n }\n\n constructor(private host: AdHost, options: AdsOptions) {\n this.opts = {\n skipDelay: 5,\n maxWrapperDepth: 3,\n requestTimeout: 8000,\n mediaTimeout: 10000,\n playOn: 'every',\n ...options,\n }\n }\n\n get adPlaying(): boolean {\n return this.activeBreak !== null\n }\n\n /** True while a pre-roll is still due for the current source. */\n get hasPendingPreRoll(): boolean {\n return this.pending('preRoll').length > 0\n }\n\n /** Called on every source change. Honors the `playOn` frequency setting. */\n resetForNewSource(): void {\n this.sourcesSeen++\n if (this.opts.playOn === 'first' && this.sourcesSeen > 1) {\n // Ads ran (or had their chance) on the first video — mute them for the rest.\n for (const roll of this.opts.adList) this.playedRolls.add(roll)\n return\n }\n this.playedRolls.clear()\n }\n\n async playPreRoll(): Promise<void> {\n await this.playRolls(this.pending('preRoll'))\n }\n\n async playPostRoll(): Promise<void> {\n await this.playRolls(this.pending('postRoll'))\n }\n\n /** Called from timeupdate; fires due mid-rolls. */\n checkMidRolls(currentTime: number): void {\n if (this.adPlaying) return\n const due = this.pending('midRoll').filter((roll) => roll.timer !== undefined && currentTime >= roll.timer)\n if (due.length > 0) void this.playRolls(due)\n }\n\n private pending(kind: AdRoll['roll']): AdRoll[] {\n return this.opts.adList.filter((roll) => roll.roll === kind && !this.playedRolls.has(roll))\n }\n\n private async playRolls(rolls: AdRoll[]): Promise<void> {\n if (rolls.length === 0 || this.destroyed) return\n if (this.activeBreak) return this.activeBreak\n\n // Synchronously, while we may still be inside a user gesture.\n this.ensureAdVideo()\n\n const run = (async () => {\n const content = this.host.contentVideo\n const wasPlaying = !content.paused && !content.ended\n content.pause()\n for (const roll of rolls) {\n this.playedRolls.add(roll)\n try {\n const ad = await resolveVast(roll, this.opts)\n await this.playAd(ad)\n } catch (cause) {\n const error = cause instanceof Error ? cause : new Error(String(cause))\n this.host.emitter.emit('aderror', { roll, error })\n }\n if (this.destroyed) return\n }\n if (wasPlaying || rolls[0].roll === 'preRoll') {\n void content.play().catch(() => {})\n }\n })()\n\n this.activeBreak = run.finally(() => {\n this.activeBreak = null\n })\n return this.activeBreak\n }\n\n private playAd(ad: ResolvedAd): Promise<void> {\n return new Promise<void>((resolve) => {\n const { labels } = this.host\n const layer = el('div', 'imp-ad')\n // One persistent (gesture-blessed) element, fresh listeners per ad.\n const video = this.ensureAdVideo()\n const ac = new AbortController()\n const signal = ac.signal\n video.src = ad.mediaUrl\n video.muted = this.host.contentVideo.muted\n video.volume = this.host.contentVideo.volume\n\n const spinner = el('div', 'imp-spinner imp-ad__spinner')\n\n const hud = el('div', 'imp-ad__hud')\n const badge = el('span', 'imp-ad__badge')\n badge.textContent = ad.adTitle ? `${labels.adLabel} · ${ad.adTitle}` : labels.adLabel\n const countdown = el('span', 'imp-ad__countdown')\n hud.append(badge, countdown)\n\n const actions = el('div', 'imp-ad__actions')\n let visitBtn: HTMLButtonElement | null = null\n if (ad.clickThrough) {\n visitBtn = el('button', 'imp-ad__visit', { type: 'button' })\n visitBtn.textContent = labels.visitAdvertiser\n actions.append(visitBtn)\n }\n const skipBtn = el('button', 'imp-ad__skip', { type: 'button' })\n skipBtn.hidden = true\n actions.append(skipBtn)\n\n layer.append(video, spinner, hud, actions)\n this.host.container.append(layer)\n this.layer = layer\n\n const skipAfter = ad.skipOffset ?? this.opts.skipDelay\n const fired = new Set<string>()\n const fireOnce = (event: keyof ResolvedAd['tracking']) => {\n if (fired.has(event)) return\n fired.add(event)\n firePixels(ad.tracking[event])\n }\n\n // Watchdog: a creative that never starts (dead-slow ad CDN) or stalls\n // mid-play must not hold the content hostage with a black screen.\n let lastProgress = Date.now()\n let lastTime = -1\n const watchdog = setInterval(() => {\n // A deliberately paused ad (click-through, tap-to-play) is not a stall.\n if (video.paused) {\n lastProgress = Date.now()\n return\n }\n if (video.currentTime !== lastTime) {\n lastTime = video.currentTime\n lastProgress = Date.now()\n return\n }\n if (Date.now() - lastProgress >= this.opts.mediaTimeout) {\n this.host.emitter.emit('aderror', {\n roll: { roll: ad.roll },\n error: new Error(`Ad media stalled for ${this.opts.mediaTimeout} ms — skipping`),\n })\n cleanup()\n }\n }, 500)\n\n const cleanup = () => {\n clearInterval(watchdog)\n ac.abort()\n video.pause()\n video.removeAttribute('src')\n video.load()\n layer.remove()\n this.layer = null\n resolve()\n }\n\n const finish = (skipped: boolean) => {\n if (skipped) {\n fireOnce('skip')\n this.host.emitter.emit('adskip', { ad })\n } else {\n fireOnce('complete')\n }\n this.host.emitter.emit('adend', { ad })\n cleanup()\n }\n\n video.addEventListener('playing', () => {\n firePixels(ad.impressions)\n fireOnce('start')\n this.host.emitter.emit('adstart', { ad })\n }, { once: true, signal })\n\n video.addEventListener('playing', () => {\n spinner.hidden = true\n }, { signal })\n video.addEventListener('waiting', () => {\n spinner.hidden = false\n }, { signal })\n\n video.addEventListener('timeupdate', () => {\n const t = video.currentTime\n const d = video.duration\n if (Number.isFinite(d) && d > 0) {\n countdown.textContent = formatTime(Math.max(0, d - t))\n if (t / d >= 0.25) fireOnce('firstQuartile')\n if (t / d >= 0.5) fireOnce('midpoint')\n if (t / d >= 0.75) fireOnce('thirdQuartile')\n }\n if (skipAfter >= 0) {\n const remaining = Math.ceil(skipAfter - t)\n if (remaining > 0) {\n skipBtn.hidden = false\n skipBtn.disabled = true\n skipBtn.textContent = `${labels.skipAdIn} ${remaining}`\n } else {\n skipBtn.hidden = false\n skipBtn.disabled = false\n skipBtn.textContent = labels.skipAd\n }\n }\n }, { signal })\n\n video.addEventListener('ended', () => finish(false), { signal })\n video.addEventListener('error', () => {\n this.host.emitter.emit('aderror', {\n roll: { roll: ad.roll },\n error: new Error('Ad media failed to play'),\n })\n cleanup()\n }, { signal })\n\n skipBtn.addEventListener('click', () => finish(true))\n\n const onAdClick = () => {\n if (!ad.clickThrough) return\n fireOnce('click')\n this.host.emitter.emit('adclick', { ad })\n window.open(ad.clickThrough, '_blank', 'noopener')\n video.pause()\n }\n video.addEventListener('click', onAdClick, { signal })\n visitBtn?.addEventListener('click', onAdClick)\n\n // pause / resume: player events + VAST tracking pixels. Only after the\n // creative actually started, and never for the teardown pause.\n let adStarted = false\n let pauseEmitted = false\n video.addEventListener('playing', () => {\n adStarted = true\n }, { once: true, signal })\n video.addEventListener('pause', () => {\n if (video.ended || !layer.isConnected) return\n layer.classList.add('imp-ad--paused')\n if (adStarted && !pauseEmitted) {\n pauseEmitted = true\n firePixels(ad.tracking.pause)\n this.host.emitter.emit('adpause', { ad })\n }\n }, { signal })\n video.addEventListener('play', () => {\n layer.classList.remove('imp-ad--paused')\n if (pauseEmitted) {\n pauseEmitted = false\n firePixels(ad.tracking.resume)\n this.host.emitter.emit('adresume', { ad })\n }\n }, { signal })\n layer.addEventListener('click', (e) => {\n if (e.target === layer || layer.classList.contains('imp-ad--paused')) {\n if (video.paused) void video.play().catch(() => {})\n }\n })\n\n void video.play().catch(() => {\n // Autoplay rejected (no gesture) — surface the ad with a tap-to-play state.\n layer.classList.add('imp-ad--paused')\n })\n })\n }\n\n /** Skip-button icon access for potential theming. */\n get closeIcon(): string {\n return this.host.closeIcon\n }\n\n destroy(): void {\n this.destroyed = true\n this.adVideo?.pause()\n this.layer?.remove()\n this.layer = null\n this.adVideo = null\n }\n}\n","import { parseVttCues } from '../core/dom'\nimport type { Chapter } from '../types'\n\n/** Chapter with a guaranteed `end`, ready for rendering. */\nexport interface NormalizedChapter extends Chapter {\n end: number\n}\n\n/**\n * Sort chapters, fill missing `end` values from the next chapter (or video duration).\n * Out-of-range chapters are clamped, empty ones dropped.\n */\nexport function normalizeChapters(chapters: Chapter[], duration: number): NormalizedChapter[] {\n const sorted = [...chapters].sort((a, b) => a.start - b.start)\n const result: NormalizedChapter[] = []\n for (let i = 0; i < sorted.length; i++) {\n const start = Math.max(0, sorted[i].start)\n if (Number.isFinite(duration) && start >= duration) continue\n let end = sorted[i].end ?? sorted[i + 1]?.start ?? duration\n if (Number.isFinite(duration)) end = Math.min(end, duration)\n if (end <= start) continue\n result.push({ start, end, title: sorted[i].title })\n }\n return result\n}\n\nexport async function loadChaptersVtt(url: string): Promise<Chapter[]> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`Failed to load chapters VTT (${res.status})`)\n const text = await res.text()\n return parseVttCues(text).map((cue) => ({ start: cue.start, end: cue.end, title: cue.text }))\n}\n\nexport function chapterAt(chapters: NormalizedChapter[], time: number): NormalizedChapter | null {\n for (const chapter of chapters) {\n if (time >= chapter.start && time < chapter.end) return chapter\n }\n return null\n}\n","import type Hls from 'hls.js'\n\n/** A selectable rendition (HLS level or progressive quality). */\nexport interface Level {\n /** Index understood by `setLevel`. `-1` is reserved for \"auto\". */\n index: number\n label: string\n}\n\n/** Wraps whatever is feeding the <video> so the player can switch quality and tear down. */\nexport interface SourceController {\n kind: 'hls' | 'native'\n levels: Level[]\n /** Currently *selected* level (-1 = auto). */\n selected: number\n setLevel(index: number): void\n destroy(): void\n}\n\nexport function isHlsSource(src: string, type?: string): boolean {\n if (type) return /application\\/(x-mpegurl|vnd\\.apple\\.mpegurl)/i.test(type)\n return /\\.m3u8(\\?|#|$)/i.test(src)\n}\n\nlet hlsModule: typeof Hls | null | undefined\n\nasync function loadHls(): Promise<typeof Hls | null> {\n if (hlsModule !== undefined) return hlsModule\n // Script-tag setups (IIFE bundle) provide hls.js as a global instead.\n const globalHls = (globalThis as { Hls?: typeof Hls }).Hls\n if (globalHls) {\n hlsModule = globalHls\n return hlsModule\n }\n try {\n const mod = await import('hls.js')\n hlsModule = mod.default\n } catch {\n hlsModule = null\n }\n return hlsModule\n}\n\nexport interface AttachCallbacks {\n onLevels(levels: Level[]): void\n onLevelSwitch(label: string): void\n onError(message: string, cause?: unknown): void\n}\n\n/**\n * Point the <video> at `src`. m3u8 goes through hls.js (or native HLS on Safari),\n * everything else is plain `video.src`.\n */\nexport async function attachSource(\n video: HTMLVideoElement,\n src: string,\n type: string | undefined,\n cb: AttachCallbacks,\n): Promise<SourceController> {\n if (isHlsSource(src, type)) {\n const native = video.canPlayType('application/vnd.apple.mpegurl')\n const HlsCtor = native ? null : await loadHls()\n if (HlsCtor && HlsCtor.isSupported()) {\n return attachHls(HlsCtor, video, src, cb)\n }\n if (native) {\n video.src = src\n return nativeController(video)\n }\n cb.onError('HLS is not supported in this browser and hls.js could not be loaded.')\n return nativeController(video)\n }\n video.src = src\n return nativeController(video)\n}\n\nfunction nativeController(video: HTMLVideoElement): SourceController {\n return {\n kind: 'native',\n levels: [],\n selected: -1,\n setLevel() {},\n destroy() {\n video.removeAttribute('src')\n video.load()\n },\n }\n}\n\nfunction attachHls(\n HlsCtor: typeof Hls,\n video: HTMLVideoElement,\n src: string,\n cb: AttachCallbacks,\n): SourceController {\n const hls = new HlsCtor({ enableWorker: true })\n const controller: SourceController = {\n kind: 'hls',\n levels: [],\n selected: -1,\n setLevel(index: number) {\n controller.selected = index\n hls.currentLevel = index\n },\n destroy() {\n hls.destroy()\n video.removeAttribute('src')\n video.load()\n },\n }\n\n hls.on(HlsCtor.Events.MANIFEST_PARSED, () => {\n controller.levels = hls.levels\n .map((level, index) => ({\n index,\n label: level.height ? `${level.height}p` : `${Math.round(level.bitrate / 1000)} kbps`,\n }))\n .reverse()\n cb.onLevels(controller.levels)\n })\n\n hls.on(HlsCtor.Events.LEVEL_SWITCHED, (_e, data) => {\n const level = hls.levels[data.level]\n if (level) cb.onLevelSwitch(level.height ? `${level.height}p` : `${Math.round(level.bitrate / 1000)} kbps`)\n })\n\n // Bounded recovery so a persistently broken stream can't loop forever, but\n // transient fatals (e.g. a layout/visibility change toggling buffering) get\n // a real chance to self-heal before we surface an error.\n let mediaRecoveries = 0\n let otherRecovered = false\n\n hls.on(HlsCtor.Events.ERROR, (_e, data) => {\n if (!data.fatal) return\n switch (data.type) {\n case HlsCtor.ErrorTypes.NETWORK_ERROR:\n hls.startLoad()\n break\n case HlsCtor.ErrorTypes.MEDIA_ERROR:\n if (mediaRecoveries < 3) {\n mediaRecoveries++\n hls.recoverMediaError()\n } else {\n cb.onError(`HLS media error: ${data.details}`, data)\n hls.destroy()\n }\n break\n default:\n // Try a single full reload before declaring the stream dead.\n if (!otherRecovered) {\n otherRecovered = true\n try {\n hls.loadSource(src)\n hls.startLoad()\n } catch {\n cb.onError(`HLS fatal error: ${data.details}`, data)\n hls.destroy()\n }\n } else {\n cb.onError(`HLS fatal error: ${data.details}`, data)\n hls.destroy()\n }\n }\n })\n\n hls.loadSource(src)\n hls.attachMedia(video)\n return controller\n}\n","import { parseVttCues, resolveUrl } from '../core/dom'\nimport type { ThumbnailCue } from '../types'\n\n/**\n * Preview thumbnails described by a WebVTT file. Supports both sprite sheets\n * (`sprite.jpg#xywh=160,0,160,90`) and one-image-per-cue tracks.\n */\nexport class ThumbnailTrack {\n private constructor(private cues: ThumbnailCue[]) {}\n\n static async load(vttUrl: string): Promise<ThumbnailTrack> {\n const res = await fetch(vttUrl)\n if (!res.ok) throw new Error(`Failed to load thumbnails VTT (${res.status})`)\n const text = await res.text()\n const cues: ThumbnailCue[] = []\n for (const cue of parseVttCues(text)) {\n const [rawSrc, fragment] = cue.text.trim().split('#')\n if (!rawSrc) continue\n const entry: ThumbnailCue = {\n start: cue.start,\n end: cue.end,\n src: resolveUrl(rawSrc, vttUrl),\n }\n const m = fragment?.match(/xywh=(\\d+),(\\d+),(\\d+),(\\d+)/)\n if (m) entry.xywh = { x: Number(m[1]), y: Number(m[2]), w: Number(m[3]), h: Number(m[4]) }\n cues.push(entry)\n }\n cues.sort((a, b) => a.start - b.start)\n return new ThumbnailTrack(cues)\n }\n\n cueAt(time: number): ThumbnailCue | null {\n // Binary search — thumbnail tracks for long videos can hold thousands of cues.\n let lo = 0\n let hi = this.cues.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const cue = this.cues[mid]\n if (time < cue.start) hi = mid - 1\n else if (time >= cue.end) lo = mid + 1\n else return cue\n }\n return null\n }\n}\n","import { el } from '../core/dom'\n\nexport interface MenuItem {\n label: string\n value: string\n active: boolean\n /** Optional icon: raw `<svg>` markup or an image URL. */\n icon?: string\n}\n\nexport interface MenuSection {\n title: string\n items: MenuItem[]\n onSelect(value: string): void\n}\n\n/**\n * Popup menu anchored above a control button. One instance per button;\n * rebuilt from data on every open, closed on outside click / Escape.\n */\nexport class Menu {\n readonly root: HTMLElement\n /** Dim layer behind the mobile bottom-sheet; tap to dismiss. Hidden on desktop. */\n private backdrop: HTMLElement\n private outsideListener: ((e: Event) => void) | null = null\n\n constructor(private anchor: HTMLElement) {\n this.root = el('div', 'imp-menu')\n this.root.hidden = true\n this.backdrop = el('div', 'imp-menu__backdrop')\n this.backdrop.hidden = true\n this.backdrop.addEventListener('pointerdown', (e) => {\n e.preventDefault()\n this.close()\n })\n anchor.append(this.backdrop)\n }\n\n get open(): boolean {\n return !this.root.hidden\n }\n\n toggle(sections: MenuSection[]): void {\n if (this.open) this.close()\n else this.show(sections)\n }\n\n show(sections: MenuSection[]): void {\n this.root.textContent = ''\n for (const section of sections) {\n if (section.items.length === 0) continue\n const block = el('div', 'imp-menu__section')\n if (section.title) {\n const title = el('div', 'imp-menu__title')\n title.textContent = section.title\n block.append(title)\n }\n for (const item of section.items) {\n const btn = el('button', 'imp-menu__item', { type: 'button', role: 'menuitemradio' })\n btn.setAttribute('aria-checked', String(item.active))\n if (item.active) btn.classList.add('imp-menu__item--active')\n if (item.icon) {\n const iconBox = el('span', 'imp-menu__icon')\n if (item.icon.trimStart().startsWith('<svg')) iconBox.innerHTML = item.icon\n else iconBox.append(el('img', '', { src: item.icon, alt: '' }))\n btn.append(iconBox)\n }\n const text = el('span', 'imp-menu__label')\n text.textContent = item.label\n btn.append(text)\n btn.addEventListener('click', () => {\n section.onSelect(item.value)\n this.close()\n })\n block.append(btn)\n }\n this.root.append(block)\n }\n this.root.hidden = false\n this.backdrop.hidden = false\n this.outsideListener = (e: Event) => {\n const target = e.target as Node\n if (!this.root.contains(target) && !this.anchor.contains(target)) this.close()\n }\n // Defer so the click that opened the menu does not immediately close it.\n setTimeout(() => {\n if (this.outsideListener) document.addEventListener('pointerdown', this.outsideListener)\n }, 0)\n }\n\n close(): void {\n this.root.hidden = true\n this.backdrop.hidden = true\n if (this.outsideListener) {\n document.removeEventListener('pointerdown', this.outsideListener)\n this.outsideListener = null\n }\n }\n\n destroy(): void {\n this.close()\n this.root.remove()\n }\n}\n","import { clamp, el, formatTime } from '../core/dom'\nimport type { NormalizedChapter } from '../features/chapters'\nimport { chapterAt } from '../features/chapters'\nimport { heatmapPath } from '../features/heatmap'\nimport type { ThumbnailTrack } from '../features/thumbnails'\n\ninterface ProgressCallbacks {\n onSeek(time: number): void\n onScrubStart(): void\n onScrubEnd(): void\n}\n\ninterface Segment {\n chapter: NormalizedChapter\n root: HTMLElement\n fill: HTMLElement\n}\n\n/**\n * Seek bar. Chapters render as flex segments (YouTube-style), each with its\n * own fill — no absolutely positioned tick marks.\n */\nexport class ProgressBar {\n readonly root: HTMLElement\n private track: HTMLElement\n private buffered: HTMLElement\n private segments: Segment[] = []\n private handle: HTMLElement\n private heatmap!: HTMLElement\n private tooltip: HTMLElement\n private tooltipThumb: HTMLElement\n private tooltipChapter: HTMLElement\n private tooltipTime: HTMLElement\n\n private duration = 0\n private chapters: NormalizedChapter[] = []\n private thumbnails: ThumbnailTrack | null = null\n private scrubbing = false\n\n constructor(private cb: ProgressCallbacks) {\n this.root = el('div', 'imp-progress', { role: 'slider', 'aria-label': 'Seek', tabindex: '-1' })\n this.buffered = el('div', 'imp-progress__buffered')\n this.track = el('div', 'imp-progress__track')\n this.handle = el('div', 'imp-progress__handle')\n\n this.tooltipThumb = el('div', 'imp-progress__thumb')\n this.tooltipChapter = el('div', 'imp-progress__tooltip-chapter')\n this.tooltipTime = el('div', 'imp-progress__tooltip-time')\n this.tooltip = el('div', 'imp-progress__tooltip')\n this.tooltip.append(this.tooltipThumb, this.tooltipChapter, this.tooltipTime)\n\n this.heatmap = el('div', 'imp-progress__heatmap')\n this.heatmap.hidden = true\n\n this.root.append(this.heatmap, this.buffered, this.track, this.handle, this.tooltip)\n this.setChapters([])\n this.bindPointer()\n }\n\n /** Render the popularity curve (empty array hides it). */\n setHeatmap(values: number[]): void {\n if (values.length === 0) {\n this.heatmap.hidden = true\n this.heatmap.textContent = ''\n return\n }\n this.heatmap.innerHTML =\n `<svg viewBox=\"0 0 1000 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">` +\n `<path d=\"${heatmapPath(values)}\"/></svg>`\n this.heatmap.hidden = false\n }\n\n setDuration(duration: number): void {\n this.duration = Number.isFinite(duration) ? duration : 0\n this.root.classList.toggle('imp-progress--live', !Number.isFinite(duration))\n if (this.chapters.length === 0) this.setChapters([])\n }\n\n setChapters(chapters: NormalizedChapter[]): void {\n this.chapters = chapters\n this.track.textContent = ''\n this.segments = []\n const list: NormalizedChapter[] = chapters.length > 0\n ? chapters\n : [{ start: 0, end: this.duration || 1, title: '' }]\n // Fill gaps between chapters so the bar always spans the full duration.\n const filled: NormalizedChapter[] = []\n let cursor = 0\n for (const ch of list) {\n if (ch.start > cursor) filled.push({ start: cursor, end: ch.start, title: '' })\n filled.push(ch)\n cursor = ch.end\n }\n if (this.duration > 0 && cursor < this.duration) {\n filled.push({ start: cursor, end: this.duration, title: '' })\n }\n for (const chapter of filled) {\n const root = el('div', 'imp-progress__segment')\n root.style.flexGrow = String(Math.max(chapter.end - chapter.start, 0.01))\n const fill = el('div', 'imp-progress__fill')\n root.append(fill)\n this.track.append(root)\n this.segments.push({ chapter, root, fill })\n }\n }\n\n setThumbnails(track: ThumbnailTrack | null): void {\n this.thumbnails = track\n }\n\n update(currentTime: number, duration: number, bufferedEnd: number): void {\n if (duration !== this.duration && Number.isFinite(duration)) this.setDuration(duration)\n if (this.scrubbing) return\n this.render(currentTime)\n const ratio = this.duration > 0 ? clamp(bufferedEnd / this.duration, 0, 1) : 0\n this.buffered.style.width = `${ratio * 100}%`\n this.root.setAttribute('aria-valuemin', '0')\n this.root.setAttribute('aria-valuemax', String(Math.round(this.duration)))\n this.root.setAttribute('aria-valuenow', String(Math.round(currentTime)))\n this.root.setAttribute('aria-valuetext', `${formatTime(currentTime)} / ${formatTime(this.duration)}`)\n }\n\n private render(time: number): void {\n for (const { chapter, fill } of this.segments) {\n const span = chapter.end - chapter.start\n const progress = span > 0 ? clamp((time - chapter.start) / span, 0, 1) : 0\n fill.style.transform = `scaleX(${progress})`\n }\n const ratio = this.duration > 0 ? clamp(time / this.duration, 0, 1) : 0\n this.handle.style.left = `${ratio * 100}%`\n }\n\n private timeFromEvent(e: PointerEvent): number {\n const rect = this.root.getBoundingClientRect()\n const ratio = rect.width > 0 ? clamp((e.clientX - rect.left) / rect.width, 0, 1) : 0\n return ratio * this.duration\n }\n\n private bindPointer(): void {\n this.root.addEventListener('pointerdown', (e) => {\n if (this.duration <= 0) return\n e.preventDefault()\n this.scrubbing = true\n this.root.classList.add('imp-progress--scrubbing')\n this.root.setPointerCapture(e.pointerId)\n this.cb.onScrubStart()\n this.render(this.timeFromEvent(e))\n this.showTooltip(e)\n })\n this.root.addEventListener('pointermove', (e) => {\n if (this.duration <= 0) return\n this.showTooltip(e)\n if (this.scrubbing) this.render(this.timeFromEvent(e))\n })\n this.root.addEventListener('pointerup', (e) => {\n if (!this.scrubbing) return\n this.scrubbing = false\n this.root.classList.remove('imp-progress--scrubbing')\n this.cb.onSeek(this.timeFromEvent(e))\n this.cb.onScrubEnd()\n })\n this.root.addEventListener('pointercancel', () => {\n this.scrubbing = false\n this.root.classList.remove('imp-progress--scrubbing')\n this.cb.onScrubEnd()\n })\n this.root.addEventListener('pointerleave', () => this.hideTooltip())\n }\n\n private showTooltip(e: PointerEvent): void {\n const time = this.timeFromEvent(e)\n this.tooltipTime.textContent = formatTime(time)\n const chapter = chapterAt(this.chapters, time)\n this.tooltipChapter.textContent = chapter?.title ?? ''\n this.tooltipChapter.hidden = !chapter?.title\n\n const cue = this.thumbnails?.cueAt(time) ?? null\n if (cue) {\n this.tooltipThumb.hidden = false\n this.tooltipThumb.style.backgroundImage = `url(\"${cue.src}\")`\n if (cue.xywh) {\n this.tooltipThumb.style.width = `${cue.xywh.w}px`\n this.tooltipThumb.style.height = `${cue.xywh.h}px`\n this.tooltipThumb.style.backgroundPosition = `-${cue.xywh.x}px -${cue.xywh.y}px`\n this.tooltipThumb.style.backgroundSize = 'auto'\n } else {\n this.tooltipThumb.style.width = '160px'\n this.tooltipThumb.style.height = '90px'\n this.tooltipThumb.style.backgroundPosition = 'center'\n this.tooltipThumb.style.backgroundSize = 'cover'\n }\n } else {\n this.tooltipThumb.hidden = true\n }\n\n this.tooltip.classList.add('imp-progress__tooltip--visible')\n const rect = this.root.getBoundingClientRect()\n const x = clamp(e.clientX - rect.left, 0, rect.width)\n const half = this.tooltip.offsetWidth / 2\n this.tooltip.style.left = `${clamp(x, half, Math.max(half, rect.width - half))}px`\n }\n\n private hideTooltip(): void {\n this.tooltip.classList.remove('imp-progress__tooltip--visible')\n }\n}\n","import { el, formatTime, iconButton, setIcon } from '../core/dom'\nimport type { Player } from '../player'\nimport { Menu, type MenuSection } from './menu'\nimport { ProgressBar } from './progress'\n\n/**\n * A control that can be collapsed into the ⋯ overflow menu when the bar runs\n * out of room. `el` is the element hidden in the bar; `section()` returns what\n * the ⋯ menu shows in its place (or null when currently unavailable).\n */\ninterface Collapsible {\n key: string\n el: HTMLElement\n /** Lower = collapses first (least important to keep as a dedicated button). */\n priority: number\n available(): boolean\n section(): MenuSection | null\n}\n\n/**\n * Control bar. A single flex row inside the overlay grid. When the player is\n * too narrow, lower-priority controls collapse into the ⋯ menu dynamically\n * (ResizeObserver-driven) so nothing ever overflows the player edge.\n */\nexport class Controls {\n readonly root: HTMLElement\n readonly progress: ProgressBar\n\n private playBtn!: HTMLButtonElement\n private muteBtn!: HTMLButtonElement\n private volumeSlider!: HTMLInputElement\n private timeLabel!: HTMLElement\n private chapterLabel!: HTMLElement\n private liveBadge!: HTMLElement\n private fullscreenBtn!: HTMLButtonElement\n private row!: HTMLElement\n private rightGroup!: HTMLElement\n\n private subtitlesBtn: HTMLButtonElement | null = null\n private settingsBtn: HTMLButtonElement | null = null\n private settingsMenu: Menu | null = null\n private subtitlesMenu: Menu | null = null\n private moreMenu: Menu | null = null\n private moreWrap: HTMLElement | null = null\n private qualityBtn: HTMLButtonElement | null = null\n private qualityMenu: Menu | null = null\n private scenesBtn: HTMLButtonElement | null = null\n private likeBtn: HTMLButtonElement | null = null\n private dislikeBtn: HTMLButtonElement | null = null\n private likeCountEl: HTMLElement | null = null\n private dislikeCountEl: HTMLElement | null = null\n private prevBtn: HTMLButtonElement | null = null\n private nextBtn: HTMLButtonElement | null = null\n private seekBackBtn: HTMLButtonElement | null = null\n private seekFwdBtn: HTMLButtonElement | null = null\n\n /** Center overlay cluster (prev · −Ns · play · +Ns · next), shown on mobile. */\n readonly center: HTMLElement\n private centerPlayBtn: HTMLButtonElement | null = null\n private centerPrevBtn: HTMLButtonElement | null = null\n private centerNextBtn: HTMLButtonElement | null = null\n /** Controls that live in the center cluster on mobile (not in the bottom bar). */\n private static readonly CENTER_KEYS = new Set(['seekBack', 'seekFwd', 'prev', 'next'])\n\n private collapsibles: Collapsible[] = []\n private overflowed = new Set<string>()\n private resizeObserver: ResizeObserver | null = null\n private reflowScheduled = false\n /** Consumer actions (share/report/…) always live in the ⋯ menu. */\n private actionItems: Array<{ value: string; label: string; icon?: string; run(): void }> = []\n\n private wasPlayingBeforeScrub = false\n private disposers: Array<() => void> = []\n\n constructor(private player: Player) {\n const { labels, icons } = player\n const c = player.controlsOptions\n\n this.root = el('div', 'imp-controls')\n\n this.progress = new ProgressBar({\n onSeek: (t) => player.seek(t),\n onScrubStart: () => {\n this.wasPlayingBeforeScrub = !player.paused\n player.pause()\n },\n onScrubEnd: () => {\n if (this.wasPlayingBeforeScrub) void player.play()\n },\n })\n if (c.progress) this.root.append(this.progress.root)\n\n const row = el('div', 'imp-controls__row')\n this.row = row\n this.root.append(row)\n\n const left = el('div', 'imp-controls__group')\n const right = el('div', 'imp-controls__group')\n this.rightGroup = right\n const spacer = el('div', 'imp-controls__spacer')\n\n this.chapterLabel = el('div', 'imp-controls__chapter')\n row.append(left, spacer, right)\n spacer.append(this.chapterLabel)\n\n // Seek step values (used by both buttons and the ⋯ fallback items).\n const seekCfg = typeof c.seekButtons === 'object' ? c.seekButtons : {}\n const seekBack = seekCfg.back ?? player.seekStep\n const seekFwd = seekCfg.forward ?? player.seekStep\n\n // --- left cluster: prev · −Ns · play · +Ns · next · volume · time ---\n if (c.playlist && player.hasPlaylist) {\n this.prevBtn = iconButton('imp-btn--prev', labels.previous, icons.previous)\n this.prevBtn.addEventListener('click', () => player.previous())\n left.append(this.prevBtn)\n }\n\n if (c.seekButtons) {\n this.seekBackBtn = iconButton('imp-btn--seek-back', `${labels.seekBack} ${seekBack}s`, icons.seekBack)\n this.seekBackBtn.addEventListener('click', () => player.skip(-seekBack))\n left.append(this.seekBackBtn)\n }\n\n if (c.play) {\n this.playBtn = iconButton('imp-btn--play', labels.play, icons.play)\n this.playBtn.addEventListener('click', () => player.togglePlay())\n left.append(this.playBtn)\n }\n\n if (c.seekButtons) {\n this.seekFwdBtn = iconButton('imp-btn--seek-forward', `${labels.seekForward} ${seekFwd}s`, icons.seekForward)\n this.seekFwdBtn.addEventListener('click', () => player.skip(seekFwd))\n left.append(this.seekFwdBtn)\n }\n\n if (c.playlist && player.hasPlaylist) {\n this.nextBtn = iconButton('imp-btn--next', labels.next, icons.next)\n this.nextBtn.addEventListener('click', () => player.next())\n left.append(this.nextBtn)\n }\n\n if (c.volume) {\n const volumeWrap = el('div', 'imp-volume')\n this.muteBtn = iconButton('imp-btn--mute', labels.mute, icons.volumeHigh)\n this.muteBtn.addEventListener('click', () => player.toggleMute())\n this.volumeSlider = el('input', 'imp-volume__slider', {\n type: 'range', min: '0', max: '1', step: '0.05', 'aria-label': 'Volume',\n })\n this.volumeSlider.addEventListener('input', () => {\n player.setVolume(Number(this.volumeSlider.value))\n })\n volumeWrap.append(this.muteBtn, this.volumeSlider)\n left.append(volumeWrap)\n }\n\n if (c.time) {\n this.timeLabel = el('div', 'imp-controls__time')\n this.liveBadge = el('span', 'imp-controls__live')\n this.liveBadge.textContent = labels.live\n this.liveBadge.hidden = true\n left.append(this.timeLabel, this.liveBadge)\n }\n\n // --- right cluster -------------------------------------------------\n this.buildLikeDislike(right)\n\n if (c.subtitles) {\n this.subtitlesBtn = iconButton('imp-btn--subtitles', labels.subtitles, icons.subtitles)\n this.subtitlesMenu = new Menu(this.subtitlesBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.subtitlesBtn, this.subtitlesMenu.root)\n this.subtitlesBtn.addEventListener('click', () => this.toggleSubtitlesMenu())\n right.append(wrap)\n this.registerCollapsible({\n key: 'subtitles', el: wrap, priority: 30,\n available: () => player.subtitleTracks.length > 0,\n section: () => this.subtitlesSection(),\n })\n }\n\n if (c.settings) {\n this.settingsBtn = iconButton('imp-btn--settings', labels.settings, icons.speed)\n this.settingsMenu = new Menu(this.settingsBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.settingsBtn, this.settingsMenu.root)\n this.settingsBtn.addEventListener('click', () => this.toggleSettingsMenu())\n right.append(wrap)\n this.registerCollapsible({\n key: 'settings', el: wrap, priority: 40,\n available: () => true,\n section: () => this.speedSection(),\n })\n }\n\n if (c.quality) {\n this.qualityBtn = iconButton('imp-btn--quality', labels.quality, icons.settings)\n this.qualityMenu = new Menu(this.qualityBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.qualityBtn, this.qualityMenu.root)\n this.qualityBtn.addEventListener('click', () => this.toggleQualityMenu())\n right.append(wrap)\n this.registerCollapsible({\n key: 'quality', el: wrap, priority: 10,\n available: () => player.qualityLevels.length > 0,\n section: () => this.qualitySection(),\n })\n }\n\n if (c.scenes) {\n this.scenesBtn = iconButton('imp-btn--scenes', labels.scenes, icons.scenes)\n this.scenesBtn.addEventListener('click', () => player.toggleScenesPanel())\n right.append(this.scenesBtn)\n this.registerCollapsible({\n key: 'scenes', el: this.scenesBtn, priority: 25,\n available: () => player.chapterList.length > 0,\n section: () => this.simpleSection('scenes', labels.scenes, icons.scenes, () => player.toggleScenesPanel()),\n })\n }\n\n if (c.playlist && player.hasPlaylist) {\n const listBtn = iconButton('imp-btn--list', labels.playlist, icons.list)\n listBtn.addEventListener('click', () => player.togglePlaylistPanel())\n right.append(listBtn)\n this.registerCollapsible({\n key: 'list', el: listBtn, priority: 50,\n available: () => true,\n section: () => this.simpleSection('list', labels.playlist, icons.list, () => player.togglePlaylistPanel()),\n })\n }\n\n if (c.pip && 'requestPictureInPicture' in HTMLVideoElement.prototype) {\n const pipBtn = iconButton('imp-btn--pip', labels.pip, icons.pip)\n pipBtn.addEventListener('click', () => void player.togglePip())\n right.append(pipBtn)\n this.registerCollapsible({\n key: 'pip', el: pipBtn, priority: 20,\n available: () => true,\n section: () => this.simpleSection('pip', labels.pip, icons.pip, () => void player.togglePip()),\n })\n }\n\n if (c.fullscreen) {\n this.fullscreenBtn = iconButton('imp-btn--fullscreen', labels.fullscreen, icons.fullscreen)\n this.fullscreenBtn.addEventListener('click', () => void player.toggleFullscreen())\n right.append(this.fullscreenBtn)\n }\n\n // Playlist nav and seek can also collapse (lower priority kept than submenus).\n if (this.prevBtn) {\n this.registerCollapsible({\n key: 'prev', el: this.prevBtn, priority: 70,\n available: () => true,\n section: () => player.hasPrevious ? this.simpleSection('prev', labels.previous, icons.previous, () => player.previous()) : null,\n })\n }\n if (this.nextBtn) {\n this.registerCollapsible({\n key: 'next', el: this.nextBtn, priority: 72,\n available: () => true,\n section: () => player.hasNext ? this.simpleSection('next', labels.next, icons.next, () => player.next()) : null,\n })\n }\n if (this.seekBackBtn) {\n const b = this.seekBackBtn\n this.registerCollapsible({\n key: 'seekBack', el: b, priority: 80,\n available: () => Number.isFinite(player.duration) && player.duration > 0,\n section: () => this.simpleSection('seekBack', `${labels.seekBack} ${seekBack}s`, icons.seekBack, () => player.skip(-seekBack)),\n })\n }\n if (this.seekFwdBtn) {\n const f = this.seekFwdBtn\n this.registerCollapsible({\n key: 'seekFwd', el: f, priority: 82,\n available: () => Number.isFinite(player.duration) && player.duration > 0,\n section: () => this.simpleSection('seekFwd', `${labels.seekForward} ${seekFwd}s`, icons.seekForward, () => player.skip(seekFwd)),\n })\n }\n\n // --- center overlay cluster (prev · −Ns · play · +Ns · next) -----------\n // Shown on mobile in the middle of the video; the matching bottom-bar\n // buttons are hidden there. Big tap targets, less crowded bar.\n this.center = el('div', 'imp-center-controls')\n if (c.playlist && player.hasPlaylist) {\n this.centerPrevBtn = this.makeCenterButton('prev', labels.previous, icons.previous)\n this.centerPrevBtn.addEventListener('click', () => player.previous())\n this.center.append(this.centerPrevBtn)\n }\n if (c.seekButtons) {\n const b = this.makeCenterButton('seek-back', `${labels.seekBack} ${seekBack}s`, icons.seekBack)\n b.addEventListener('click', () => player.skip(-seekBack))\n this.center.append(b)\n }\n if (c.play) {\n this.centerPlayBtn = this.makeCenterButton('play', labels.play, icons.play)\n this.centerPlayBtn.addEventListener('click', () => player.togglePlay())\n this.center.append(this.centerPlayBtn)\n }\n if (c.seekButtons) {\n const f = this.makeCenterButton('seek-forward', `${labels.seekForward} ${seekFwd}s`, icons.seekForward)\n f.addEventListener('click', () => player.skip(seekFwd))\n this.center.append(f)\n }\n if (c.playlist && player.hasPlaylist) {\n this.centerNextBtn = this.makeCenterButton('next', labels.next, icons.next)\n this.centerNextBtn.addEventListener('click', () => player.next())\n this.center.append(this.centerNextBtn)\n }\n this.center.style.display = 'none'\n\n // ⋯ dropdown — overflow target + consumer actions. Always last.\n this.buildMoreDropdown(right)\n\n this.bind()\n this.syncVolume()\n this.syncPlayState()\n this.setLikeState(player.actionsOptions.likeState ?? null)\n\n // React to the player resizing (fullscreen, layout) ...\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => this.scheduleReflow())\n this.resizeObserver.observe(player.container)\n }\n // ... and to viewport changes crossing the 767px mobile breakpoint.\n this.onWindowResize = () => this.scheduleReflow()\n window.addEventListener('resize', this.onWindowResize)\n }\n\n private onWindowResize: (() => void) | null = null\n\n private registerCollapsible(c: Collapsible): void {\n this.collapsibles.push(c)\n }\n\n /** Center-cluster button — deliberately NOT `.imp-btn` (own sizing/look). */\n private makeCenterButton(modifier: string, label: string, svg: string): HTMLButtonElement {\n const btn = el('button', `imp-center-btn imp-center-btn--${modifier}`, { type: 'button', 'aria-label': label, title: label })\n btn.innerHTML = svg\n return btn\n }\n\n /** like/dislike — visible buttons (collapsible), highlightable via `setLikeState`. */\n private buildLikeDislike(right: HTMLElement): void {\n const p = this.player\n const a = p.actionsOptions\n const { labels, icons } = p\n\n if (a.like) {\n this.likeBtn = iconButton('imp-btn--like', labels.like, icons.like)\n this.likeBtn.addEventListener('click', () => p.emit('action', { id: 'like' }))\n this.likeCountEl = this.attachCountTooltip(this.likeBtn, a.likeCount)\n const wrap = this.wrapWithTooltip(this.likeBtn, this.likeCountEl)\n right.append(wrap)\n this.registerCollapsible({\n key: 'like', el: wrap, priority: 62, available: () => true,\n section: () => this.simpleSection('like', labels.like, icons.like, () => p.emit('action', { id: 'like' })),\n })\n }\n if (a.dislike) {\n this.dislikeBtn = iconButton('imp-btn--dislike', labels.dislike, icons.dislike)\n this.dislikeBtn.addEventListener('click', () => p.emit('action', { id: 'dislike' }))\n this.dislikeCountEl = this.attachCountTooltip(this.dislikeBtn, a.dislikeCount)\n const wrap = this.wrapWithTooltip(this.dislikeBtn, this.dislikeCountEl)\n right.append(wrap)\n this.registerCollapsible({\n key: 'dislike', el: wrap, priority: 60, available: () => true,\n section: () => this.simpleSection('dislike', labels.dislike, icons.dislike, () => p.emit('action', { id: 'dislike' })),\n })\n }\n }\n\n private attachCountTooltip(_btn: HTMLButtonElement, initial: number | string | undefined): HTMLElement {\n const tip = el('span', 'imp-count-tooltip')\n this.setCountText(tip, initial)\n return tip\n }\n\n private wrapWithTooltip(btn: HTMLButtonElement, tip: HTMLElement): HTMLElement {\n const wrap = el('div', 'imp-action')\n wrap.append(btn, tip)\n return wrap\n }\n\n private setCountText(tip: HTMLElement, value: number | string | undefined): void {\n const text = value === undefined || value === null || value === '' ? '' : String(value)\n tip.textContent = text\n tip.hidden = text === ''\n }\n\n setLikeCounts(likeCount?: number | string, dislikeCount?: number | string): void {\n if (this.likeCountEl && likeCount !== undefined) this.setCountText(this.likeCountEl, likeCount)\n if (this.dislikeCountEl && dislikeCount !== undefined) this.setCountText(this.dislikeCountEl, dislikeCount)\n }\n\n setLikeState(state: 'like' | 'dislike' | null): void {\n this.likeBtn?.classList.toggle('imp-btn--active', state === 'like')\n this.dislikeBtn?.classList.toggle('imp-btn--active', state === 'dislike')\n }\n\n // === ⋯ menu ===========================================================\n\n private buildMoreDropdown(right: HTMLElement): void {\n const p = this.player\n const a = p.actionsOptions\n const { labels, icons } = p\n\n if (a.addTo) this.actionItems.push({ value: 'addTo', label: labels.addTo, icon: icons.addTo, run: () => p.emit('action', { id: 'addTo' }) })\n if (a.share) this.actionItems.push({ value: 'share', label: labels.share, icon: icons.share, run: () => void p.share() })\n if (a.report) this.actionItems.push({ value: 'report', label: labels.report, icon: icons.report, run: () => p.emit('action', { id: 'report' }) })\n for (const custom of a.custom ?? []) {\n this.actionItems.push({ value: `custom:${custom.id}`, label: custom.title, icon: custom.icon, run: () => p.emit('customaction', { id: custom.id }) })\n }\n\n const moreBtn = iconButton('imp-btn--more', labels.more, icons.more)\n this.moreMenu = new Menu(moreBtn)\n const wrap = el('div', 'imp-controls__menu-anchor imp-controls__more')\n wrap.append(moreBtn, this.moreMenu.root)\n moreBtn.addEventListener('click', () => {\n this.closeMenus(this.moreMenu)\n this.moreMenu?.toggle(this.buildMoreSections())\n })\n right.append(wrap)\n this.moreWrap = wrap\n }\n\n /** ⋯ menu = overflowed controls (in display order) + consumer actions. */\n private buildMoreSections(): MenuSection[] {\n const sections: MenuSection[] = []\n const runMap = new Map<string, () => void>()\n const simpleItems: Array<{ label: string; value: string; icon?: string; active: boolean }> = []\n\n // Overflowed controls, ordered for reading (nav → toggles → submenus).\n const order = ['prev', 'next', 'seekBack', 'seekFwd', 'like', 'dislike', 'scenes', 'pip', 'list', 'subtitles', 'settings', 'quality']\n const overflowedSorted = this.collapsibles\n .filter((c) => this.overflowed.has(c.key) && c.available())\n .sort((a, b) => order.indexOf(a.key) - order.indexOf(b.key))\n\n for (const c of overflowedSorted) {\n const section = c.section()\n if (!section) continue\n // Single-item, no-title contributions merge into one block; titled ones stand alone.\n if (!section.title && section.items.length === 1) {\n const it = section.items[0]\n simpleItems.push(it)\n runMap.set(it.value, () => section.onSelect(it.value))\n } else {\n sections.push(section)\n }\n }\n if (simpleItems.length > 0) {\n sections.unshift({ title: '', items: simpleItems, onSelect: (v) => runMap.get(v)?.() })\n }\n\n if (this.actionItems.length > 0) {\n const map = new Map(this.actionItems.map((a) => [a.value, a.run]))\n sections.push({\n title: '',\n items: this.actionItems.map(({ value, label, icon }) => ({ value, label, icon, active: false })),\n onSelect: (v) => map.get(v)?.(),\n })\n }\n return sections\n }\n\n private simpleSection(value: string, label: string, icon: string, run: () => void): MenuSection {\n return { title: '', items: [{ value, label, icon, active: false }], onSelect: () => run() }\n }\n\n private speedSection(): MenuSection {\n const p = this.player\n return {\n title: p.labels.speed,\n items: p.playbackRates.map((rate) => ({\n label: rate === 1 ? '1× (normal)' : `${rate}×`,\n value: String(rate),\n active: p.playbackRate === rate,\n })),\n onSelect: (value) => p.setPlaybackRate(Number(value)),\n }\n }\n\n private qualitySection(): MenuSection {\n const p = this.player\n return {\n title: p.labels.quality,\n items: [\n ...(p.qualityAutoAvailable ? [{ label: p.labels.qualityAuto, value: '-1', active: p.currentQuality === -1 }] : []),\n ...p.qualityLevels.map((level) => ({ label: level.label, value: String(level.index), active: p.currentQuality === level.index })),\n ],\n onSelect: (value) => p.setQuality(Number(value)),\n }\n }\n\n private subtitlesSection(): MenuSection {\n const p = this.player\n return {\n title: p.labels.subtitles,\n items: [\n { label: p.labels.subtitlesOff, value: '-1', active: p.activeSubtitle === -1 },\n ...p.subtitleTracks.map((track, index) => ({ label: track.label, value: String(index), active: p.activeSubtitle === index })),\n ],\n onSelect: (value) => p.setSubtitle(Number(value)),\n }\n }\n\n // === dynamic overflow =================================================\n\n private scheduleReflow(): void {\n if (this.reflowScheduled) return\n this.reflowScheduled = true\n requestAnimationFrame(() => {\n this.reflowScheduled = false\n this.reflow()\n })\n }\n\n /**\n * Hide controls that don't fit (lowest priority first) and remember them so\n * the ⋯ menu can offer them. Unavailable controls are hidden outright.\n */\n private reflow(): void {\n // Mobile layout up to the site's 767px breakpoint (viewport-based).\n const compact = window.innerWidth <= 767\n\n // On mobile, prev/seek/play/next live in the center cluster, not the bar.\n this.center.style.display = compact ? 'flex' : 'none'\n if (this.playBtn) this.playBtn.style.display = compact ? 'none' : ''\n\n // Reset: availability first, clear forced-overflow hides.\n this.overflowed.clear()\n for (const c of this.collapsibles) {\n if (compact && Controls.CENTER_KEYS.has(c.key)) {\n // Moved to the center cluster — hide its bottom-bar twin entirely.\n c.el.style.display = 'none'\n continue\n }\n const ok = c.available()\n c.el.style.display = ok ? '' : 'none'\n c.el.classList.remove('imp-collapsed')\n }\n\n const byPriority = this.collapsibles\n .filter((c) => c.available() && !(compact && Controls.CENTER_KEYS.has(c.key)))\n .sort((a, b) => a.priority - b.priority)\n\n // Greedily collapse while the right cluster spills past the row's edge.\n let guard = byPriority.length\n while (guard-- > 0 && this.overflowsRow()) {\n const next = byPriority.find((c) => !this.overflowed.has(c.key))\n if (!next) break\n next.el.style.display = 'none'\n next.el.classList.add('imp-collapsed')\n this.overflowed.add(next.key)\n }\n\n // ⋯ visible if it has anything to show.\n if (this.moreWrap) {\n const hasContent = this.actionItems.length > 0 || this.overflowed.size > 0\n this.moreWrap.style.display = hasContent ? '' : 'none'\n }\n }\n\n private overflowsRow(): boolean {\n const rowRight = this.row.getBoundingClientRect().right\n const groupRight = this.rightGroup.getBoundingClientRect().right\n return groupRight > rowRight + 1\n }\n\n private bind(): void {\n const p = this.player\n this.disposers.push(\n p.on('timeupdate', ({ currentTime, duration }) => {\n this.progress.update(currentTime, duration, p.bufferedEnd)\n if (this.timeLabel) {\n if (p.live) {\n this.timeLabel.hidden = true\n this.liveBadge.hidden = false\n } else {\n this.timeLabel.hidden = false\n this.liveBadge.hidden = true\n this.timeLabel.textContent = `${formatTime(currentTime)} / ${formatTime(duration)}`\n }\n }\n }),\n p.on('play', () => this.syncPlayState()),\n p.on('pause', () => this.syncPlayState()),\n p.on('ended', () => this.syncPlayState()),\n p.on('volumechange', () => this.syncVolume()),\n p.on('chapterchange', ({ chapter }) => {\n this.chapterLabel.textContent = chapter?.title ?? ''\n }),\n p.on('fullscreenchange', ({ active }) => {\n if (this.fullscreenBtn) {\n setIcon(this.fullscreenBtn, active ? p.icons.fullscreenExit : p.icons.fullscreen, active ? p.labels.exitFullscreen : p.labels.fullscreen)\n }\n this.scheduleReflow()\n }),\n p.on('playlistitemchange', () => {\n this.syncPlaylistButtons()\n this.scheduleReflow()\n }),\n p.on('sourcechange', () => {\n this.syncPlaylistButtons()\n this.scheduleReflow()\n }),\n )\n this.syncPlaylistButtons()\n this.reflow()\n }\n\n private syncPlayState(): void {\n const p = this.player\n const [icon, label] = p.ended\n ? [p.icons.replay, p.labels.replay]\n : p.paused\n ? [p.icons.play, p.labels.play]\n : [p.icons.pause, p.labels.pause]\n if (this.playBtn) setIcon(this.playBtn, icon, label)\n if (this.centerPlayBtn) setIcon(this.centerPlayBtn, icon, label)\n }\n\n private syncVolume(): void {\n if (!this.muteBtn) return\n const p = this.player\n const effective = p.muted ? 0 : p.volume\n const icon = effective === 0 ? p.icons.volumeMute : effective < 0.5 ? p.icons.volumeLow : p.icons.volumeHigh\n setIcon(this.muteBtn, icon, p.muted ? p.labels.unmute : p.labels.mute)\n this.volumeSlider.value = String(effective)\n this.volumeSlider.style.setProperty('--imp-volume-fill', `${effective * 100}%`)\n }\n\n /** Called by the player when per-source data (chapters/quality/subtitles) changes. */\n syncFeatureButtons(): void {\n this.scheduleReflow()\n }\n\n private syncPlaylistButtons(): void {\n const p = this.player\n if (this.prevBtn) this.prevBtn.disabled = !p.hasPrevious\n if (this.nextBtn) this.nextBtn.disabled = !p.hasNext\n if (this.centerPrevBtn) this.centerPrevBtn.disabled = !p.hasPrevious\n if (this.centerNextBtn) this.centerNextBtn.disabled = !p.hasNext\n }\n\n private closeMenus(except?: Menu | null): void {\n for (const menu of [this.settingsMenu, this.subtitlesMenu, this.qualityMenu, this.moreMenu]) {\n if (menu && menu !== except) menu.close()\n }\n }\n\n private toggleSettingsMenu(): void {\n if (!this.settingsMenu) return\n this.closeMenus(this.settingsMenu)\n this.settingsMenu.toggle([this.speedSection()])\n }\n\n private toggleQualityMenu(): void {\n if (!this.qualityMenu || this.player.qualityLevels.length === 0) return\n this.closeMenus(this.qualityMenu)\n this.qualityMenu.toggle([this.qualitySection()])\n }\n\n private toggleSubtitlesMenu(): void {\n if (!this.subtitlesMenu || this.player.subtitleTracks.length === 0) return\n this.closeMenus(this.subtitlesMenu)\n this.subtitlesMenu.toggle([this.subtitlesSection()])\n }\n\n destroy(): void {\n for (const dispose of this.disposers) dispose()\n this.disposers = []\n this.resizeObserver?.disconnect()\n if (this.onWindowResize) window.removeEventListener('resize', this.onWindowResize)\n this.settingsMenu?.destroy()\n this.subtitlesMenu?.destroy()\n this.qualityMenu?.destroy()\n this.moreMenu?.destroy()\n this.root.remove()\n }\n}\n","import { el, iconButton } from '../core/dom'\nimport type { Player } from '../player'\nimport type { PlayerLabels, RelatedItem, RelatedOptions, VideoSource } from '../types'\n\n/** Preview poster: cover image + big play button, shown until the first play. */\nexport class PosterOverlay {\n readonly root: HTMLElement\n private image: HTMLElement\n\n constructor(player: Player) {\n this.root = el('div', 'imp-poster')\n this.image = el('div', 'imp-poster__image')\n const big = iconButton('imp-poster__play', player.labels.play, player.icons.bigPlay)\n big.addEventListener('click', () => void player.play())\n this.root.append(this.image, big)\n this.root.addEventListener('click', (e) => {\n if (e.target === this.root || e.target === this.image) void player.play()\n })\n }\n\n setSource(source: VideoSource | null): void {\n this.image.style.backgroundImage = source?.poster ? `url(\"${source.poster}\")` : ''\n }\n\n show(): void {\n this.root.hidden = false\n }\n\n hide(): void {\n this.root.hidden = true\n }\n}\n\n/**\n * Pause screen \"slot\". Default content is title + description of the current\n * source; consumers can replace it with any element (or a factory), and the\n * Vue wrapper feeds a real <slot> through the same API.\n */\nexport class PauseScreen {\n readonly root: HTMLElement\n private defaultContent: HTMLElement\n private channel: HTMLElement\n private channelAvatar: HTMLElement\n private channelName: HTMLElement\n private channelUrl: string | null = null\n private title: HTMLElement\n private description: HTMLElement\n private sponsor: HTMLAnchorElement\n private sponsorLabel: HTMLElement\n private sponsorText: HTMLElement\n private custom: HTMLElement | null = null\n\n constructor(private labels: PlayerLabels) {\n this.root = el('div', 'imp-pause-screen')\n this.root.hidden = true\n this.defaultContent = el('div', 'imp-pause-screen__default')\n\n this.channel = el('button', 'imp-channel', { type: 'button' })\n this.channel.hidden = true\n this.channelAvatar = el('div', 'imp-channel__avatar')\n this.channelName = el('div', 'imp-channel__name')\n // The plate sits at the right edge — text first, avatar at the outer edge.\n this.channel.append(this.channelName, this.channelAvatar)\n this.channel.addEventListener('click', () => {\n if (this.channelUrl) window.open(this.channelUrl, '_blank', 'noopener')\n })\n\n const heading = el('div', 'imp-pause-screen__heading')\n this.title = el('div', 'imp-pause-screen__title')\n this.description = el('div', 'imp-pause-screen__description')\n\n // Sponsor / promo link — sits under the description, shown only when set.\n this.sponsor = el('a', 'imp-sponsor', { target: '_blank', rel: 'nofollow noopener' }) as HTMLAnchorElement\n this.sponsor.hidden = true\n this.sponsorLabel = el('span', 'imp-sponsor__label')\n this.sponsorText = el('span', 'imp-sponsor__text')\n this.sponsor.append(this.sponsorLabel, this.sponsorText)\n // Don't let a click on the link bubble to the pause-screen play toggle.\n this.sponsor.addEventListener('click', (e) => e.stopPropagation())\n\n heading.append(this.title, this.description, this.sponsor)\n // Title block on the left, channel pinned to the right edge.\n this.defaultContent.append(heading, this.channel)\n this.root.append(this.defaultContent)\n }\n\n setCustomContent(element: HTMLElement | null): void {\n this.custom?.remove()\n this.custom = element\n if (element) {\n element.classList.add('imp-pause-screen__custom')\n this.root.append(element)\n }\n this.defaultContent.hidden = element !== null\n // Custom content renders as a full-cover centered overlay (ad use-case),\n // not the top info strip.\n this.root.classList.toggle('imp-pause-screen--custom', element !== null)\n }\n\n /** True while consumer-provided custom content is mounted. */\n get hasCustom(): boolean {\n return this.custom !== null\n }\n\n setSource(source: VideoSource | null): void {\n this.title.textContent = source?.title ?? ''\n this.description.textContent = source?.description ?? ''\n\n // Sponsor link — only for sponsored videos (i.e. when provided).\n const sponsor = source?.sponsor\n this.sponsor.hidden = !sponsor\n if (sponsor) {\n this.sponsor.href = sponsor.url\n this.sponsorText.textContent = sponsor.text\n this.sponsorLabel.textContent = sponsor.label ?? this.labels.sponsored\n }\n\n const channel = source?.channel\n this.channel.hidden = !channel\n this.channelUrl = channel?.url ?? null\n this.channel.classList.toggle('imp-channel--link', Boolean(channel?.url))\n if (channel) {\n this.channelName.textContent = channel.name\n this.channelAvatar.className = `imp-channel__avatar imp-channel__avatar--${channel.avatarShape ?? 'circle'}`\n if (channel.avatar) {\n this.channelAvatar.textContent = ''\n this.channelAvatar.style.backgroundImage = `url(\"${channel.avatar}\")`\n } else {\n // Styled first-letter placeholder when there is no avatar.\n this.channelAvatar.style.backgroundImage = ''\n this.channelAvatar.textContent = (channel.name.trim()[0] ?? '?').toUpperCase()\n }\n }\n }\n\n show(): void {\n this.root.hidden = false\n }\n\n hide(): void {\n this.root.hidden = true\n }\n}\n\n/** Grid of related videos, shown on pause and/or ended. */\nexport class RelatedOverlay {\n readonly root: HTMLElement\n private grid: HTMLElement\n private heading: HTMLElement\n\n constructor(private player: Player) {\n this.root = el('div', 'imp-related')\n this.root.hidden = true\n this.heading = el('div', 'imp-related__title')\n this.grid = el('div', 'imp-related__grid')\n const close = iconButton('imp-related__close', 'Close', player.icons.close)\n close.addEventListener('click', () => this.hide())\n this.root.append(close, this.heading, this.grid)\n }\n\n setOptions(options: RelatedOptions | undefined): void {\n this.grid.textContent = ''\n if (!options) return\n this.heading.textContent = options.title ?? this.player.labels.related\n for (const item of options.items) {\n this.grid.append(this.buildCard(item))\n }\n }\n\n private buildCard(item: RelatedItem): HTMLElement {\n const card = el('button', 'imp-related__card', { type: 'button' })\n const thumb = el('div', 'imp-related__thumb')\n if (item.poster) thumb.style.backgroundImage = `url(\"${item.poster}\")`\n if (item.duration) {\n const badge = el('span', 'imp-related__duration')\n badge.textContent = item.duration\n thumb.append(badge)\n }\n const title = el('div', 'imp-related__card-title')\n title.textContent = item.title\n card.append(thumb, title)\n card.addEventListener('click', () => {\n this.player.emit('relatedclick', { item })\n this.hide()\n if (item.source) {\n this.player.load(item.source)\n void this.player.play()\n } else if (item.url) {\n window.open(item.url, '_blank', 'noopener')\n }\n })\n return card\n }\n\n get visible(): boolean {\n return !this.root.hidden\n }\n\n show(): void {\n if (this.grid.childElementCount === 0) return\n this.root.hidden = false\n this.player.emit('relatedshow', undefined)\n }\n\n hide(): void {\n this.root.hidden = true\n }\n}\n","import { el, formatTime, iconButton } from '../core/dom'\nimport type { Player } from '../player'\n\n/** Slide-in panel listing playlist items; survives source changes. */\nexport class PlaylistPanel {\n readonly root: HTMLElement\n private list: HTMLElement\n private shuffleBtn: HTMLButtonElement\n private repeatBtn: HTMLButtonElement\n\n constructor(private player: Player, layout: 'sidebar' | 'bottom' = 'sidebar', playlistTitle?: string) {\n this.root = el('div', `imp-playlist imp-playlist--${layout}`)\n this.root.hidden = true\n const header = el('div', 'imp-playlist__header')\n const title = el('div', 'imp-playlist__heading')\n if (playlistTitle) {\n // Named playlist: small \"Playlist\" kicker + the name in the primary font.\n const kicker = el('div', 'imp-playlist__kicker')\n kicker.textContent = player.labels.playlist\n const name = el('div', 'imp-playlist__name')\n name.textContent = playlistTitle\n title.append(kicker, name)\n } else {\n title.textContent = player.labels.playlist\n }\n\n const tools = el('div', 'imp-playlist__tools')\n this.shuffleBtn = iconButton('imp-playlist__shuffle', player.labels.shuffle, player.icons.shuffle)\n this.shuffleBtn.addEventListener('click', () => {\n player.setShuffle(!player.shuffle)\n this.syncModes()\n })\n this.repeatBtn = iconButton('imp-playlist__repeat', player.labels.repeat, player.icons.repeat)\n this.repeatBtn.addEventListener('click', () => {\n player.setRepeat(!player.repeat)\n this.syncModes()\n })\n const close = iconButton('imp-playlist__close', 'Close', player.icons.close)\n close.addEventListener('click', () => this.hide())\n tools.append(this.shuffleBtn, this.repeatBtn, close)\n\n header.append(title, tools)\n this.list = el('div', 'imp-playlist__list')\n this.root.append(header, this.list)\n this.rebuild()\n this.syncModes()\n }\n\n private syncModes(): void {\n this.shuffleBtn.classList.toggle('imp-btn--active', this.player.shuffle)\n this.repeatBtn.classList.toggle('imp-btn--active', this.player.repeat)\n }\n\n rebuild(): void {\n this.list.textContent = ''\n this.player.playlist.forEach((source, index) => {\n const item = el('button', 'imp-playlist__item', { type: 'button' })\n if (index === this.player.index) item.classList.add('imp-playlist__item--active')\n const thumb = el('div', 'imp-playlist__thumb')\n if (source.poster) thumb.style.backgroundImage = `url(\"${source.poster}\")`\n const meta = el('div', 'imp-playlist__meta')\n const itemTitle = el('div', 'imp-playlist__title')\n itemTitle.textContent = source.title ?? `#${index + 1}`\n meta.append(itemTitle)\n if (source.duration) {\n const dur = el('div', 'imp-playlist__duration')\n dur.textContent = formatTime(source.duration)\n meta.append(dur)\n }\n item.append(thumb, meta)\n item.addEventListener('click', () => {\n this.player.playItem(index)\n })\n this.list.append(item)\n })\n }\n\n get visible(): boolean {\n return !this.root.hidden\n }\n\n show(): void {\n this.rebuild()\n this.root.hidden = false\n }\n\n hide(): void {\n this.root.hidden = true\n }\n\n toggle(): void {\n if (this.visible) this.hide()\n else this.show()\n }\n}\n","import { el, formatTime, iconButton } from '../core/dom'\nimport type { Player } from '../player'\n\n/**\n * Scene list — the chapters of the current video as a clickable panel, each\n * with a preview cropped from the VTT sprite at the scene start.\n */\nexport class ScenesPanel {\n readonly root: HTMLElement\n private list: HTMLElement\n private items: HTMLButtonElement[] = []\n\n constructor(private player: Player, layout: 'sidebar' | 'bottom' = 'bottom') {\n this.root = el('div', `imp-playlist imp-scenes imp-playlist--${layout}`)\n this.root.hidden = true\n const header = el('div', 'imp-playlist__header')\n const title = el('span')\n title.textContent = player.labels.scenes\n const close = iconButton('imp-playlist__close', 'Close', player.icons.close)\n close.addEventListener('click', () => this.hide())\n header.append(title, close)\n this.list = el('div', 'imp-playlist__list')\n this.root.append(header, this.list)\n\n player.on('chapterchange', () => this.syncActive())\n }\n\n /** Re-render from the player's current chapters + thumbnail track. */\n rebuild(): void {\n this.list.textContent = ''\n this.items = []\n const thumbs = this.player.thumbnails\n for (const chapter of this.player.chapterList) {\n const item = el('button', 'imp-playlist__item', { type: 'button' })\n const thumb = el('div', 'imp-playlist__thumb')\n\n const cue = thumbs?.cueAt(chapter.start + 0.01) ?? null\n if (cue?.xywh) {\n // Crop the sprite region and scale it into the thumb box.\n const inner = el('div', 'imp-scenes__sprite')\n inner.style.width = `${cue.xywh.w}px`\n inner.style.height = `${cue.xywh.h}px`\n inner.style.backgroundImage = `url(\"${cue.src}\")`\n inner.style.backgroundPosition = `-${cue.xywh.x}px -${cue.xywh.y}px`\n inner.style.setProperty('--imp-sprite-w', String(cue.xywh.w))\n thumb.append(inner)\n } else if (cue) {\n thumb.style.backgroundImage = `url(\"${cue.src}\")`\n }\n\n const meta = el('div', 'imp-playlist__meta')\n const itemTitle = el('div', 'imp-playlist__title')\n itemTitle.textContent = chapter.title || formatTime(chapter.start)\n const time = el('div', 'imp-playlist__duration')\n time.textContent = formatTime(chapter.start)\n meta.append(itemTitle, time)\n\n item.append(thumb, meta)\n item.addEventListener('click', () => {\n this.player.seek(chapter.start)\n void this.player.play()\n })\n this.list.append(item)\n this.items.push(item)\n }\n this.syncActive()\n }\n\n private syncActive(): void {\n const current = this.player.chapter\n const chapters = this.player.chapterList\n this.items.forEach((item, i) => {\n item.classList.toggle('imp-playlist__item--active', current !== null && chapters[i] === current)\n })\n }\n\n get visible(): boolean {\n return !this.root.hidden\n }\n\n show(): void {\n this.rebuild()\n this.root.hidden = false\n }\n\n hide(): void {\n this.root.hidden = true\n }\n\n toggle(): void {\n if (this.visible) this.hide()\n else this.show()\n }\n}\n","import { clamp, el } from './core/dom'\nimport { Emitter } from './core/events'\nimport { defaultIcons } from './core/icons'\nimport { defaultLabels } from './core/labels'\nimport { getLocale } from './core/localeRegistry'\nimport { buildHeatmapValues } from './features/heatmap'\nimport { AdManager } from './features/ads/manager'\nimport { chapterAt, loadChaptersVtt, normalizeChapters, type NormalizedChapter } from './features/chapters'\nimport { attachSource, type Level, type SourceController } from './features/hls'\nimport { ThumbnailTrack } from './features/thumbnails'\nimport { Controls } from './ui/controls'\nimport { PauseScreen, PosterOverlay, RelatedOverlay } from './ui/overlays'\nimport { PlaylistPanel } from './ui/playlistPanel'\nimport { ScenesPanel } from './ui/scenesPanel'\nimport type {\n ActionsOptions,\n ControlsOptions,\n IconName,\n PlayerEventMap,\n PlayerLabels,\n PlayerOptions,\n PlaylistOptions,\n SubtitleTrack,\n VideoSource,\n} from './types'\n\n/** `subtitles` accepts a URL, one track, or an array — normalize to an array. */\nfunction normalizeSubtitles(input: VideoSource['subtitles']): SubtitleTrack[] {\n if (!input) return []\n if (typeof input === 'string') return [{ src: input, label: 'Subtitles' }]\n return Array.isArray(input) ? input : [input]\n}\n\nconst defaultControls: Required<ControlsOptions> = {\n play: true,\n progress: true,\n time: true,\n volume: true,\n fullscreen: true,\n pip: true,\n settings: true,\n quality: false,\n scenes: true,\n heatmap: true,\n subtitles: true,\n seekButtons: true,\n playlist: true,\n hideDelay: 2500,\n}\n\n/**\n * Framework-agnostic video player.\n *\n * ```ts\n * import { Player } from 'itube-modern-player'\n * import 'itube-modern-player/style.css'\n *\n * const player = new Player('#mount', { source: { src: 'video.m3u8', title: 'Demo' } })\n * ```\n *\n * Design rules this codebase follows (deliberately unlike fluid-player):\n * - no globals, no instance registry — `new Player()` as many times as you like;\n * - one overlay layer laid out with grid/flex, not a pile of absolute elements;\n * - `destroy()` returns the mount node to its original state;\n * - every event is typed, every string and icon is replaceable.\n */\nexport class Player {\n readonly container: HTMLElement\n readonly video: HTMLVideoElement\n\n readonly labels: PlayerLabels\n readonly icons: Record<IconName, string>\n readonly controlsOptions: Required<ControlsOptions>\n readonly actionsOptions: ActionsOptions\n readonly playbackRates: number[]\n readonly seekStep: number\n\n /** Set by the controls while the user drags the seek bar. */\n scrubbing = false\n\n private emitter = new Emitter<PlayerEventMap>()\n private mount: HTMLElement\n private options: PlayerOptions\n private playlistOptions: Required<PlaylistOptions>\n private abort = new AbortController()\n\n private sources: VideoSource[] = []\n private currentIndex = -1\n private sourceController: SourceController | null = null\n private loadToken = 0\n\n private chapters: NormalizedChapter[] = []\n private currentChapter: NormalizedChapter | null = null\n private progressiveQuality = -1\n private thumbTrack: ThumbnailTrack | null = null\n private shuffleMode = false\n\n private controls: Controls\n private poster: PosterOverlay\n private pauseScreen: PauseScreen\n private related: RelatedOverlay\n private playlistPanel: PlaylistPanel\n private scenesPanel: ScenesPanel\n private spinner: HTMLElement\n private errorBox!: HTMLElement\n private adManager: AdManager | null = null\n\n private playedOnce = false\n private idleTimer: ReturnType<typeof setTimeout> | null = null\n private destroyed = false\n\n constructor(target: string | HTMLElement, options: PlayerOptions = {}) {\n const mount = typeof target === 'string' ? document.querySelector<HTMLElement>(target) : target\n if (!mount) throw new Error(`[itube-player] mount target not found: ${String(target)}`)\n this.mount = mount\n this.options = options\n\n this.labels = { ...defaultLabels, ...getLocale(options.language), ...options.labels }\n this.icons = { ...defaultIcons, ...options.icons }\n this.controlsOptions = { ...defaultControls, ...options.controls }\n this.actionsOptions = options.actions ?? {}\n this.playbackRates = options.playbackRates ?? [0.5, 0.75, 1, 1.25, 1.5, 2]\n this.seekStep = options.seekStep ?? 10\n this.playlistOptions = { title: '', autoAdvance: true, loop: false, shuffle: false, startIndex: 0, layout: 'sidebar', ...options.playlist }\n this.shuffleMode = this.playlistOptions.shuffle\n\n this.sources = options.source ? (Array.isArray(options.source) ? [...options.source] : [options.source]) : []\n\n // --- DOM ----------------------------------------------------------\n this.container = el('div', 'imp-player', { tabindex: '0' })\n if (options.className) this.container.classList.add(options.className)\n\n // Custom styling → CSS variables on the container (overridable per instance).\n if (options.styling?.themeColor) this.container.style.setProperty('--imp-accent', options.styling.themeColor)\n if (options.styling?.likeColor) this.container.style.setProperty('--imp-like', options.styling.likeColor)\n if (options.styling?.dislikeColor) this.container.style.setProperty('--imp-dislike', options.styling.dislikeColor)\n\n this.video = el('video', 'imp-video')\n if (options.playsInline !== false) this.video.setAttribute('playsinline', '')\n if (options.crossOrigin !== undefined) this.video.crossOrigin = options.crossOrigin\n this.video.preload = 'metadata'\n if (options.loop) this.video.loop = true\n if (options.muted) this.video.muted = true\n this.video.volume = clamp(options.volume ?? 1, 0, 1)\n\n const layer = el('div', 'imp-layer')\n this.spinner = el('div', 'imp-spinner')\n this.spinner.hidden = true\n this.errorBox = el('div', 'imp-error')\n this.errorBox.hidden = true\n\n this.pauseScreen = new PauseScreen(this.labels)\n this.poster = new PosterOverlay(this)\n this.related = new RelatedOverlay(this)\n this.related.setOptions(options.related)\n this.controls = new Controls(this)\n this.playlistPanel = new PlaylistPanel(this, this.playlistOptions.layout, this.playlistOptions.title || undefined)\n this.scenesPanel = new ScenesPanel(this, options.scenes?.layout ?? 'bottom')\n\n const middle = el('div', 'imp-layer__middle')\n middle.append(this.spinner, this.errorBox, this.controls.center)\n const bottom = el('div', 'imp-layer__bottom')\n bottom.append(this.controls.root)\n layer.append(this.pauseScreen.root, this.related.root, middle, bottom)\n\n this.container.append(this.video, layer, this.poster.root, this.playlistPanel.root, this.scenesPanel.root)\n this.mount.append(this.container)\n\n if (options.pauseScreen instanceof HTMLElement) {\n this.pauseScreen.setCustomContent(options.pauseScreen)\n } else if (typeof options.pauseScreen === 'function') {\n this.pauseScreen.setCustomContent(options.pauseScreen(this))\n }\n\n const adConfig = options.adConfig ?? options.ads\n if (adConfig && adConfig.adList.length > 0) {\n this.adManager = new AdManager(\n { container: this.container, contentVideo: this.video, emitter: this.emitter, labels: this.labels, closeIcon: this.icons.close },\n adConfig,\n )\n }\n\n this.emitter.on('error', ({ message }) => {\n this.errorBox.textContent = message\n this.errorBox.hidden = false\n this.spinner.hidden = true\n this.poster.hide()\n })\n\n this.bindVideoEvents()\n this.bindIdleHide()\n if (options.keyboard !== false) this.bindKeyboard()\n\n // Click on empty space toggles playback (after the first play).\n this.video.addEventListener('click', () => {\n if (this.playedOnce && !this.adPlaying) this.togglePlay()\n }, { signal: this.abort.signal })\n this.pauseScreen.root.addEventListener('click', (e) => {\n // With custom content (e.g. an ad block) the backdrop must not resume —\n // the consumer's own \"close & continue\" control owns that.\n if (this.pauseScreen.hasCustom) return\n if (e.target === this.pauseScreen.root) this.togglePlay()\n }, { signal: this.abort.signal })\n\n if (this.sources.length > 0) {\n void this.loadItem(clamp(this.playlistOptions.startIndex, 0, this.sources.length - 1), Boolean(options.autoplay))\n }\n this.emitter.emit('ready', { player: this })\n }\n\n // === events ===========================================================\n\n on<K extends keyof PlayerEventMap>(event: K, fn: (payload: PlayerEventMap[K]) => void): () => void {\n return this.emitter.on(event, fn)\n }\n\n once<K extends keyof PlayerEventMap>(event: K, fn: (payload: PlayerEventMap[K]) => void): () => void {\n return this.emitter.once(event, fn)\n }\n\n off<K extends keyof PlayerEventMap>(event: K, fn: (payload: PlayerEventMap[K]) => void): void {\n this.emitter.off(event, fn)\n }\n\n /** @internal — UI modules emit through the player. */\n emit<K extends keyof PlayerEventMap>(event: K, payload: PlayerEventMap[K]): void {\n this.emitter.emit(event, payload)\n }\n\n // === playback =========================================================\n\n get paused(): boolean {\n return this.video.paused\n }\n\n get ended(): boolean {\n return this.video.ended\n }\n\n get currentTime(): number {\n return this.video.currentTime\n }\n\n get duration(): number {\n return this.video.duration || 0\n }\n\n get live(): boolean {\n return this.video.duration === Infinity\n }\n\n get bufferedEnd(): number {\n const ranges = this.video.buffered\n return ranges.length > 0 ? ranges.end(ranges.length - 1) : 0\n }\n\n get adPlaying(): boolean {\n return this.adManager?.adPlaying ?? false\n }\n\n async play(): Promise<void> {\n if (this.destroyed || this.adPlaying) return\n if (this.adManager) {\n await this.adManager.playPreRoll()\n if (this.destroyed) return\n // The pre-roll resumes content itself; if there was none, fall through.\n if (!this.video.paused) return\n }\n await this.video.play()\n }\n\n pause(): void {\n if (this.adPlaying) return\n this.video.pause()\n }\n\n togglePlay(): void {\n if (this.video.paused || this.video.ended) void this.play()\n else this.pause()\n }\n\n seek(time: number): void {\n if (!Number.isFinite(this.video.duration)) return\n this.video.currentTime = clamp(time, 0, this.video.duration)\n }\n\n /** Relative seek, e.g. `skip(-10)`. */\n skip(delta: number): void {\n this.seek(this.video.currentTime + delta)\n }\n\n // === volume ===========================================================\n\n get volume(): number {\n return this.video.volume\n }\n\n get muted(): boolean {\n return this.video.muted\n }\n\n setVolume(volume: number): void {\n this.video.volume = clamp(volume, 0, 1)\n if (volume > 0) this.video.muted = false\n }\n\n setMuted(muted: boolean): void {\n this.video.muted = muted\n }\n\n toggleMute(): void {\n this.video.muted = !this.video.muted\n }\n\n // === rate / quality ===================================================\n\n get playbackRate(): number {\n return this.video.playbackRate\n }\n\n setPlaybackRate(rate: number): void {\n this.video.playbackRate = rate\n this.emitter.emit('ratechange', { rate })\n }\n\n get qualityLevels(): Level[] {\n if (this.sourceController?.kind === 'hls') return this.sourceController.levels\n const qualities = this.source?.qualities\n return qualities\n ? qualities.map((q, index) => ({ index, label: q.label ?? String(q.quality ?? index) }))\n : []\n }\n\n get qualityAutoAvailable(): boolean {\n return this.sourceController?.kind === 'hls'\n }\n\n get currentQuality(): number {\n if (this.sourceController?.kind === 'hls') return this.sourceController.selected\n return this.progressiveQuality\n }\n\n setQuality(index: number): void {\n if (this.sourceController?.kind === 'hls') {\n this.sourceController.setLevel(index)\n const label = index === -1\n ? this.labels.qualityAuto\n : this.sourceController.levels.find((l) => l.index === index)?.label ?? String(index)\n this.emitter.emit('qualitychange', { label })\n return\n }\n const qualities = this.source?.qualities\n if (!qualities || !qualities[index] || index === this.progressiveQuality) return\n const time = this.video.currentTime\n const wasPlaying = !this.video.paused && !this.video.ended\n this.progressiveQuality = index\n this.video.src = qualities[index].src\n this.video.currentTime = time\n if (wasPlaying) void this.video.play().catch(() => {})\n this.emitter.emit('qualitychange', { label: qualities[index].label ?? String(qualities[index].quality ?? index) })\n }\n\n // === subtitles ========================================================\n\n get subtitleTracks(): SubtitleTrack[] {\n return normalizeSubtitles(this.source?.subtitles)\n }\n\n get activeSubtitle(): number {\n const tracks = this.video.textTracks\n for (let i = 0; i < tracks.length; i++) {\n if (tracks[i].mode === 'showing') return i\n }\n return -1\n }\n\n setSubtitle(index: number): void {\n const tracks = this.video.textTracks\n for (let i = 0; i < tracks.length; i++) {\n tracks[i].mode = i === index ? 'showing' : 'disabled'\n }\n this.emitter.emit('subtitlechange', { track: this.subtitleTracks[index] ?? null })\n }\n\n // === playlist =========================================================\n\n get playlist(): VideoSource[] {\n return this.sources\n }\n\n get index(): number {\n return this.currentIndex\n }\n\n get source(): VideoSource | null {\n return this.sources[this.currentIndex] ?? null\n }\n\n get hasPlaylist(): boolean {\n return this.sources.length > 1\n }\n\n get hasNext(): boolean {\n if (this.shuffleMode || this.playlistOptions.loop) return this.sources.length > 1\n return this.currentIndex < this.sources.length - 1\n }\n\n get hasPrevious(): boolean {\n return this.playlistOptions.loop ? this.sources.length > 1 : this.currentIndex > 0\n }\n\n /** Shuffle mode: `next()` and auto-advance pick a random item. */\n get shuffle(): boolean {\n return this.shuffleMode\n }\n\n setShuffle(on: boolean): void {\n this.shuffleMode = on\n }\n\n /** Repeat mode: after the last item the list starts over instead of ending. */\n get repeat(): boolean {\n return this.playlistOptions.loop\n }\n\n setRepeat(on: boolean): void {\n this.playlistOptions.loop = on\n }\n\n next(): void {\n if (!this.hasNext) return\n if (this.shuffleMode && this.sources.length > 1) {\n let index = this.currentIndex\n while (index === this.currentIndex) index = Math.floor(Math.random() * this.sources.length)\n this.playItem(index)\n return\n }\n this.playItem((this.currentIndex + 1) % this.sources.length)\n }\n\n previous(): void {\n if (!this.hasPrevious) return\n this.playItem((this.currentIndex - 1 + this.sources.length) % this.sources.length)\n }\n\n /** Jump to a playlist item and start playback. */\n playItem(index: number): void {\n if (index < 0 || index >= this.sources.length) return\n void this.loadItem(index, true).then(() => {\n this.emitter.emit('playlistitemchange', { source: this.sources[index], index })\n })\n }\n\n togglePlaylistPanel(): void {\n this.scenesPanel.hide()\n this.playlistPanel.toggle()\n }\n\n toggleScenesPanel(): void {\n this.playlistPanel.hide()\n this.scenesPanel.toggle()\n }\n\n /** Thumbnail track of the current source (used by the seek tooltip and the scenes panel). */\n get thumbnails(): ThumbnailTrack | null {\n return this.thumbTrack\n }\n\n /**\n * Replace what the player is playing. A single source resets the playlist\n * to one item; an array installs a new playlist.\n */\n load(source: VideoSource | VideoSource[], startIndex = 0): void {\n this.sources = Array.isArray(source) ? [...source] : [source]\n this.playlistPanel.rebuild()\n void this.loadItem(clamp(startIndex, 0, this.sources.length - 1), false)\n }\n\n // === fullscreen / pip =================================================\n\n get isFullscreen(): boolean {\n return document.fullscreenElement === this.container\n }\n\n async toggleFullscreen(): Promise<void> {\n if (this.isFullscreen) {\n await document.exitFullscreen()\n } else if (this.container.requestFullscreen) {\n await this.container.requestFullscreen()\n } else {\n // iOS Safari: only the video element can go fullscreen.\n const v = this.video as HTMLVideoElement & { webkitEnterFullscreen?: () => void }\n v.webkitEnterFullscreen?.()\n }\n }\n\n async togglePip(): Promise<void> {\n if (document.pictureInPictureElement === this.video) {\n await document.exitPictureInPicture()\n } else {\n await this.video.requestPictureInPicture()\n }\n }\n\n // === chapters =========================================================\n\n /** Normalized chapters of the current source (after metadata is known). */\n get chapterList(): NormalizedChapter[] {\n return this.chapters\n }\n\n get chapter(): NormalizedChapter | null {\n return this.currentChapter\n }\n\n // === actions ==========================================================\n\n /**\n * Share the current video: native share sheet when the device has one,\n * otherwise the `action` event with `id: \"share\"` so the app can show\n * its own dialog.\n */\n async share(): Promise<void> {\n const data = {\n title: this.source?.title ?? document.title,\n url: window.location.href,\n }\n if (typeof navigator.share === 'function') {\n try {\n await navigator.share(data)\n } catch {\n /* user dismissed the sheet — not an error */\n }\n return\n }\n this.emitter.emit('action', { id: 'share' })\n }\n\n /** Highlight the like or dislike button (`null` clears both). */\n setLikeState(state: 'like' | 'dislike' | null): void {\n this.controls.setLikeState(state)\n }\n\n /** Update like/dislike counters shown as tooltips above the buttons (`undefined` leaves one untouched). */\n setLikeCounts(likeCount?: number | string, dislikeCount?: number | string): void {\n this.controls.setLikeCounts(likeCount, dislikeCount)\n }\n\n // === pause screen =====================================================\n\n /** Inject custom pause-screen content (used by the Vue wrapper's slot). */\n setPauseScreenContent(element: HTMLElement | null): void {\n this.pauseScreen.setCustomContent(element)\n }\n\n // === teardown =========================================================\n\n destroy(): void {\n if (this.destroyed) return\n this.destroyed = true\n this.loadToken++\n this.adManager?.destroy()\n this.controls.destroy()\n this.sourceController?.destroy()\n this.abort.abort()\n if (this.idleTimer) clearTimeout(this.idleTimer)\n this.container.remove()\n this.emitter.emit('destroy', undefined)\n this.emitter.removeAll()\n }\n\n // === internals ========================================================\n\n private async loadItem(index: number, autoplay: boolean): Promise<void> {\n const token = ++this.loadToken\n const source = this.sources[index]\n if (!source) return\n this.currentIndex = index\n\n // Tear down the previous source.\n this.sourceController?.destroy()\n this.sourceController = null\n this.chapters = []\n this.currentChapter = null\n this.progressiveQuality = -1\n this.playedOnce = false\n for (const track of [...this.video.querySelectorAll('track')]) track.remove()\n this.adManager?.resetForNewSource()\n this.related.hide()\n this.pauseScreen.hide()\n this.scenesPanel.hide()\n this.thumbTrack = null\n this.errorBox.hidden = true\n\n // Per-source UI state.\n this.video.poster = source.poster ?? ''\n this.poster.setSource(source)\n this.pauseScreen.setSource(source)\n this.controls.progress.setChapters([])\n this.controls.progress.setThumbnails(null)\n this.controls.progress.setHeatmap([])\n if (autoplay) this.poster.hide()\n else this.poster.show()\n this.playlistPanel.rebuild()\n\n // Subtitle <track> elements (native rendering). Disabled by default —\n // a track only starts visible when it carries `default: true`.\n for (const sub of normalizeSubtitles(source.subtitles)) {\n const track = el('track', '', {\n kind: 'subtitles',\n src: sub.src,\n label: sub.label,\n ...(sub.srclang ? { srclang: sub.srclang } : {}),\n })\n if (sub.default) track.setAttribute('default', '')\n this.video.append(track)\n }\n\n // Effective media URL: progressive quality list wins over plain src.\n let src = source.src\n let type = source.type\n if (source.qualities && source.qualities.length > 0) {\n const initial = Math.max(0, source.qualities.findIndex((q) => q.src === source.src))\n this.progressiveQuality = initial\n src = source.qualities[initial].src\n type = source.qualities[initial].type ?? type\n }\n\n // While a pre-roll occupies the screen, let the browser buffer the first\n // fragments of the content in the background (hls.js does this on its\n // own; `auto` covers progressive sources).\n this.video.preload = this.adManager?.hasPendingPreRoll ? 'auto' : 'metadata'\n\n const controller = await attachSource(this.video, src, type, {\n onLevels: () => {\n if (token === this.loadToken) this.controls.syncFeatureButtons()\n },\n onLevelSwitch: (label) => this.emitter.emit('qualitychange', { label }),\n onError: (message, cause) => this.emitter.emit('error', { message, cause }),\n })\n if (token !== this.loadToken) {\n controller.destroy()\n return\n }\n this.sourceController = controller\n\n this.emitter.emit('sourcechange', { source, index })\n\n // Async extras — each guarded by the load token.\n if (source.thumbnails) {\n ThumbnailTrack.load(source.thumbnails)\n .then((track) => {\n if (token !== this.loadToken) return\n this.thumbTrack = track\n this.controls.progress.setThumbnails(track)\n if (this.scenesPanel.visible) this.scenesPanel.rebuild()\n })\n .catch((cause) => this.emitter.emit('error', { message: 'Failed to load thumbnails track', cause }))\n }\n if (source.chapters) {\n const apply = (raw: Parameters<typeof normalizeChapters>[0]) => {\n const set = () => {\n if (token !== this.loadToken) return\n this.chapters = normalizeChapters(raw, this.video.duration)\n this.controls.progress.setChapters(this.chapters)\n this.controls.syncFeatureButtons()\n if (this.scenesPanel.visible) this.scenesPanel.rebuild()\n }\n if (Number.isFinite(this.video.duration) && this.video.duration > 0) set()\n else this.video.addEventListener('loadedmetadata', set, { once: true, signal: this.abort.signal })\n }\n if (typeof source.chapters === 'string') {\n loadChaptersVtt(source.chapters)\n .then((parsed) => apply(parsed))\n .catch((cause) => this.emitter.emit('error', { message: 'Failed to load chapters track', cause }))\n } else {\n apply(source.chapters)\n }\n }\n\n if (source.heatmap && source.heatmap.length > 0 && this.controlsOptions.heatmap) {\n const points = source.heatmap\n const applyHeatmap = () => {\n if (token !== this.loadToken) return\n this.controls.progress.setHeatmap(buildHeatmapValues(points, this.video.duration))\n }\n if (Number.isFinite(this.video.duration) && this.video.duration > 0) applyHeatmap()\n else this.video.addEventListener('loadedmetadata', applyHeatmap, { once: true, signal: this.abort.signal })\n }\n\n if (autoplay) {\n void this.play().catch(() => {\n // Autoplay blocked — fall back to the poster with a play button.\n if (token === this.loadToken) this.poster.show()\n })\n }\n }\n\n private bindVideoEvents(): void {\n const { signal } = this.abort\n const v = this.video\n\n v.addEventListener('play', () => {\n this.playedOnce = true\n this.poster.hide()\n this.pauseScreen.hide()\n if (!this.related.visible) this.related.hide()\n this.related.hide()\n this.emitter.emit('play', undefined)\n this.scheduleIdle()\n }, { signal })\n\n v.addEventListener('pause', () => {\n this.emitter.emit('pause', undefined)\n this.showControlsNow()\n if (this.video.ended || this.scrubbing || this.adPlaying || !this.playedOnce) return\n if (this.options.pauseScreen !== false) this.pauseScreen.show()\n if (this.options.related?.showOn?.includes('pause')) this.related.show()\n }, { signal })\n\n v.addEventListener('ended', () => {\n void this.handleEnded()\n }, { signal })\n\n v.addEventListener('timeupdate', () => {\n this.emitter.emit('timeupdate', { currentTime: v.currentTime, duration: v.duration || 0 })\n this.adManager?.checkMidRolls(v.currentTime)\n const chapter = chapterAt(this.chapters, v.currentTime)\n if (chapter !== this.currentChapter) {\n this.currentChapter = chapter\n this.emitter.emit('chapterchange', { chapter })\n }\n }, { signal })\n\n v.addEventListener('progress', () => {\n this.emitter.emit('progress', { buffered: this.bufferedEnd })\n }, { signal })\n\n v.addEventListener('volumechange', () => {\n this.emitter.emit('volumechange', { volume: v.volume, muted: v.muted })\n }, { signal })\n\n v.addEventListener('seeking', () => this.emitter.emit('seeking', { currentTime: v.currentTime }), { signal })\n v.addEventListener('seeked', () => this.emitter.emit('seeked', { currentTime: v.currentTime }), { signal })\n\n v.addEventListener('waiting', () => {\n this.spinner.hidden = false\n }, { signal })\n for (const eventName of ['playing', 'canplay', 'seeked'] as const) {\n v.addEventListener(eventName, () => {\n this.spinner.hidden = true\n }, { signal })\n }\n\n v.addEventListener('error', () => {\n const mediaError = v.error\n if (!mediaError) return\n // While hls.js drives the element (MSE), the native <video> can emit\n // transient decode errors (e.g. DEMUXER_ERROR_COULD_NOT_PARSE on a\n // viewport/visibility change) that hls.js recovers from on its own via\n // its ERROR event. Surfacing those as fatal here is wrong — let the HLS\n // controller own error handling and only react to native sources.\n if (this.sourceController?.kind === 'hls') return\n // No src attribute → the error came from our own teardown, ignore it.\n if (v.getAttribute('src') !== null || v.currentSrc) {\n this.emitter.emit('error', { message: mediaError.message || `Media error (code ${mediaError.code})`, cause: mediaError })\n }\n }, { signal })\n\n v.addEventListener('enterpictureinpicture', () => this.emitter.emit('pipchange', { active: true }), { signal })\n v.addEventListener('leavepictureinpicture', () => this.emitter.emit('pipchange', { active: false }), { signal })\n\n document.addEventListener('fullscreenchange', () => {\n this.emitter.emit('fullscreenchange', { active: this.isFullscreen })\n this.container.classList.toggle('imp-player--fullscreen', this.isFullscreen)\n }, { signal })\n }\n\n private async handleEnded(): Promise<void> {\n this.emitter.emit('ended', undefined)\n this.showControlsNow()\n if (this.adManager) {\n await this.adManager.playPostRoll()\n if (this.destroyed) return\n }\n if (this.playlistOptions.autoAdvance && this.hasNext) {\n this.next()\n return\n }\n if (this.options.related?.showOn?.includes('ended') ?? Boolean(this.options.related)) {\n this.related.show()\n }\n }\n\n // === controls visibility ==============================================\n\n private bindIdleHide(): void {\n const { signal } = this.abort\n const reset = () => {\n this.showControlsNow()\n this.scheduleIdle()\n }\n this.container.addEventListener('pointermove', reset, { signal })\n this.container.addEventListener('pointerdown', reset, { signal })\n this.container.addEventListener('keydown', reset, { signal })\n this.container.addEventListener('pointerleave', () => {\n if (!this.video.paused) this.container.classList.add('imp-player--idle')\n }, { signal })\n }\n\n private showControlsNow(): void {\n this.container.classList.remove('imp-player--idle')\n }\n\n private scheduleIdle(): void {\n if (this.idleTimer) clearTimeout(this.idleTimer)\n this.idleTimer = setTimeout(() => {\n if (!this.video.paused && !this.destroyed) {\n this.container.classList.add('imp-player--idle')\n }\n }, this.controlsOptions.hideDelay)\n }\n\n // === keyboard =========================================================\n\n private bindKeyboard(): void {\n this.container.addEventListener('keydown', (e) => {\n const target = e.target as HTMLElement\n const interactive = target.closest('input, select, textarea, [contenteditable]')\n if (interactive) return\n const isButton = target.closest('button') !== null\n\n switch (e.key) {\n case ' ':\n case 'k':\n if (e.key === ' ' && isButton) return\n e.preventDefault()\n this.togglePlay()\n break\n case 'ArrowLeft':\n e.preventDefault()\n this.skip(-this.seekStep)\n break\n case 'ArrowRight':\n e.preventDefault()\n this.skip(this.seekStep)\n break\n case 'ArrowUp':\n e.preventDefault()\n this.setVolume(this.volume + 0.1)\n break\n case 'ArrowDown':\n e.preventDefault()\n this.setVolume(this.volume - 0.1)\n break\n case 'm':\n this.toggleMute()\n break\n case 'f':\n void this.toggleFullscreen()\n break\n case 'Home':\n this.seek(0)\n break\n case 'End':\n this.seek(this.duration)\n break\n default:\n if (/^[0-9]$/.test(e.key) && Number.isFinite(this.video.duration)) {\n this.seek((Number(e.key) / 10) * this.video.duration)\n }\n }\n }, { signal: this.abort.signal })\n }\n}\n"],"names":["el","tag","className","attrs","node","key","value","iconButton","label","svg","btn","setIcon","clamp","min","max","formatTime","seconds","s","m","h","mm","ss","parseVttTime","raw","ms","parseVttCues","text","cues","blocks","block","lines","l","timingIndex","rawStart","rawEnd","start","end","cueText","resolveUrl","url","base","Emitter","event","fn","set","off","payload","err","body","viewBox","defaultIcons","registry","defaultLabels","registerLocale","code","labels","registerLocales","map","getLocale","registeredLanguages","buildHeatmapValues","points","duration","buckets","hasData","point","index","kernel","smooth","_","i","acc","k","j","FLOOR","v","heatmapPath","values","width","height","step","d","resolveVast","roll","opts","fetchAndParse","tagUrl","depth","controller","timer","xmlText","res","doc","ad","collectTracking","wrapper","nextTag","textOf","inline","linear","media","pickMediaFile","parseDuration","parseSkipOffset","_a","_b","playable","f","a","b","progressive","pool","pick","pct","firePixels","urls","AdManager","host","options","currentTime","due","kind","rolls","run","content","wasPlaying","cause","error","resolve","layer","video","ac","signal","spinner","hud","badge","countdown","actions","visitBtn","skipBtn","skipAfter","fired","fireOnce","lastProgress","lastTime","watchdog","cleanup","finish","skipped","t","remaining","onAdClick","adStarted","pauseEmitted","e","normalizeChapters","chapters","sorted","result","loadChaptersVtt","cue","chapterAt","time","chapter","isHlsSource","src","type","hlsModule","loadHls","globalHls","attachSource","cb","native","HlsCtor","attachHls","nativeController","hls","level","_e","data","mediaRecoveries","otherRecovered","ThumbnailTrack","vttUrl","rawSrc","fragment","entry","lo","hi","mid","Menu","anchor","sections","section","title","item","iconBox","target","ProgressBar","list","filled","cursor","ch","root","fill","track","bufferedEnd","ratio","span","progress","rect","x","half","_Controls","player","icons","c","row","left","right","spacer","seekCfg","seekBack","seekFwd","volumeWrap","wrap","listBtn","pipBtn","modifier","p","_btn","initial","tip","likeCount","dislikeCount","state","custom","moreBtn","runMap","simpleItems","order","overflowedSorted","it","icon","rate","compact","ok","byPriority","guard","next","hasContent","rowRight","active","effective","except","menu","dispose","Controls","PosterOverlay","big","source","PauseScreen","heading","element","sponsor","channel","RelatedOverlay","close","card","thumb","PlaylistPanel","layout","playlistTitle","header","kicker","name","tools","meta","itemTitle","dur","ScenesPanel","thumbs","inner","current","normalizeSubtitles","input","defaultControls","Player","mount","middle","bottom","adConfig","message","ranges","delta","volume","muted","qualities","q","tracks","on","startIndex","autoplay","token","sub","apply","parsed","applyHeatmap","eventName","mediaError","reset","isButton"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export { Player } from './player';
2
+ export { Emitter } from './core/events';
3
+ export { defaultIcons } from './core/icons';
4
+ export { defaultLabels } from './core/labels';
5
+ export { getLocale, registerLocale, registerLocales, registeredLanguages } from './core/localeRegistry';
6
+ export { buildHeatmapValues, heatmapPath } from './features/heatmap';
7
+ export { formatTime } from './core/dom';
8
+ export { normalizeChapters, loadChaptersVtt, chapterAt } from './features/chapters';
9
+ export type { NormalizedChapter } from './features/chapters';
10
+ export { ThumbnailTrack } from './features/thumbnails';
11
+ export { isHlsSource } from './features/hls';
12
+ export type { Level, SourceController } from './features/hls';
13
+ export { resolveVast } from './features/ads/vast';
14
+ export type { ActionsOptions, AdRoll, AdsOptions, BuiltinActionId, CustomAction, ChannelInfo, Chapter, ControlsOptions, HeatmapPoint, IconName, LocaleCode, PlayerEvent, PlayerEventMap, PlayerLabels, PlayerOptions, PlaylistOptions, QualityLevel, RelatedItem, RelatedOptions, ResolvedAd, ScenesOptions, StylingOptions, SponsorLink, SubtitleTrack, ThumbnailCue, VideoSource, } from './types';
@@ -0,0 +1,48 @@
1
+ import { Emitter } from '../../core/events';
2
+ import { AdsOptions, PlayerEventMap, PlayerLabels } from '../../types';
3
+ interface AdHost {
4
+ container: HTMLElement;
5
+ contentVideo: HTMLVideoElement;
6
+ emitter: Emitter<PlayerEventMap>;
7
+ labels: PlayerLabels;
8
+ closeIcon: string;
9
+ }
10
+ /**
11
+ * Plays pre/mid/post rolls in a dedicated <video> layered over the content.
12
+ * The content element is never touched, so its position, HLS session and
13
+ * text tracks survive every ad break.
14
+ */
15
+ export declare class AdManager {
16
+ private host;
17
+ private opts;
18
+ private playedRolls;
19
+ private sourcesSeen;
20
+ private activeBreak;
21
+ private layer;
22
+ private adVideo;
23
+ private destroyed;
24
+ /**
25
+ * Create (once) and "bless" the ad <video> synchronously inside the user
26
+ * gesture that started playback. A bare `load()` during the gesture lets
27
+ * the later `play()` succeed even though VAST fetches happen in between —
28
+ * the same trick every ad SDK uses for iOS/strict autoplay policies.
29
+ */
30
+ private ensureAdVideo;
31
+ constructor(host: AdHost, options: AdsOptions);
32
+ get adPlaying(): boolean;
33
+ /** True while a pre-roll is still due for the current source. */
34
+ get hasPendingPreRoll(): boolean;
35
+ /** Called on every source change. Honors the `playOn` frequency setting. */
36
+ resetForNewSource(): void;
37
+ playPreRoll(): Promise<void>;
38
+ playPostRoll(): Promise<void>;
39
+ /** Called from timeupdate; fires due mid-rolls. */
40
+ checkMidRolls(currentTime: number): void;
41
+ private pending;
42
+ private playRolls;
43
+ private playAd;
44
+ /** Skip-button icon access for potential theming. */
45
+ get closeIcon(): string;
46
+ destroy(): void;
47
+ }
48
+ export {};
@@ -0,0 +1,9 @@
1
+ import { AdRoll, AdsOptions, ResolvedAd } from '../../types';
2
+ /**
3
+ * Minimal VAST 2/3/4 resolver — the same subset fluid-player consumes:
4
+ * InLine Linear creatives, Wrapper redirects, MediaFiles, ClickThrough,
5
+ * Impression and quartile tracking, skipoffset.
6
+ */
7
+ export declare function resolveVast(roll: AdRoll, opts: Required<Pick<AdsOptions, 'maxWrapperDepth' | 'requestTimeout'>>): Promise<ResolvedAd>;
8
+ /** Fire a tracking pixel without caring about the response. */
9
+ export declare function firePixels(urls: string[] | undefined): void;
@@ -0,0 +1,12 @@
1
+ import { Chapter } from '../types';
2
+ /** Chapter with a guaranteed `end`, ready for rendering. */
3
+ export interface NormalizedChapter extends Chapter {
4
+ end: number;
5
+ }
6
+ /**
7
+ * Sort chapters, fill missing `end` values from the next chapter (or video duration).
8
+ * Out-of-range chapters are clamped, empty ones dropped.
9
+ */
10
+ export declare function normalizeChapters(chapters: Chapter[], duration: number): NormalizedChapter[];
11
+ export declare function loadChaptersVtt(url: string): Promise<Chapter[]>;
12
+ export declare function chapterAt(chapters: NormalizedChapter[], time: number): NormalizedChapter | null;
@@ -0,0 +1,17 @@
1
+ import { HeatmapPoint } from '../types';
2
+ /**
3
+ * Popularity heatmap ("most replayed") math.
4
+ *
5
+ * Input is sparse: only the moments the backend has data for. Pipeline:
6
+ * 1. bucket the duration into `buckets` slots and sum the samples into them;
7
+ * 2. gaussian-ish smoothing (±2 window) so isolated spikes become hills;
8
+ * 3. normalize by the maximum, with a base floor so the curve never collapses
9
+ * to zero — flat areas read as "watched", not "missing data".
10
+ */
11
+ export declare function buildHeatmapValues(points: HeatmapPoint[], duration: number, buckets?: number): number[];
12
+ /**
13
+ * Build an SVG area path for normalized values (0..1) in a `width`×`height`
14
+ * viewBox. Rendered with `preserveAspectRatio="none"`, so the numbers are
15
+ * arbitrary units, not pixels.
16
+ */
17
+ export declare function heatmapPath(values: number[], width?: number, height?: number): string;