itube-modern-player 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/dist/core/dom.d.ts +8 -1
- package/dist/core.cjs +3 -3
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +179 -176
- package/dist/core.js.map +1 -1
- package/dist/itube-modern-player.iife.js +3 -3
- package/dist/itube-modern-player.iife.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types.d.ts +12 -9
- package/dist/vue.d.ts +2 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"itube-modern-player.iife.js","sources":["../src/core/dom.ts","../src/core/events.ts","../src/core/icons.ts","../src/core/labels.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","../src/global.ts","../src/core/locales.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 // Thin circular-arrow (\"rotate\") icons — open center so the step number reads\n // clearly inside the ring (matches the reference skip ±N look).\n seekForward: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"23 4 23 10 17 10\"/><path d=\"M20.49 15a9 9 0 1 1-2.12-9.36L23 10\"/></svg>',\n seekBack: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>',\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 // Generic \"uploaded by a user\" glyph (head + shoulders) for preview meta.\n user: svg('<path d=\"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm0 2c-3.6 0-8 1.8-8 4.4V21h16v-2.6c0-2.6-4.4-4.4-8-4.4Z\"/>'),\n // Generic \"channel\" glyph (play badge) for preview meta when a channel is set.\n channel: svg('<path d=\"M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm7 3.5v7l6-3.5-6-3.5Z\"/>'),\n}\n","import type { PlayerLabels } from '../types'\n\nexport const defaultLabels: PlayerLabels = {\n play: 'Play',\n pause: 'Pause',\n replay: 'Replay',\n mute: 'Mute',\n unmute: 'Unmute',\n fullscreen: 'Fullscreen',\n exitFullscreen: 'Exit fullscreen',\n pip: 'Picture-in-picture',\n settings: 'Playback speed',\n scenes: 'Scenes',\n sceneTypes: 'Scene type',\n autoplay: 'Autoplay',\n playNext: 'Play next',\n shuffle: 'Shuffle',\n repeat: 'Repeat',\n subtitles: 'Subtitles',\n subtitlesOff: 'Off',\n speed: 'Speed',\n quality: 'Quality',\n qualityAuto: 'Auto',\n next: 'Next',\n nextVideo: 'Next video',\n previous: 'Previous',\n playlist: 'Playlist',\n like: 'Like',\n dislike: 'Dislike',\n addTo: 'Save to…',\n share: 'Share',\n report: 'Report',\n more: 'More actions',\n seekForward: 'Seek forward',\n seekBack: 'Seek back',\n secondsShort: 's',\n live: 'LIVE',\n related: 'More videos',\n adLabel: 'Ad',\n skipAd: 'Skip ad',\n skipAdIn: 'Skip in',\n visitAdvertiser: 'Visit advertiser',\n sponsored: 'Sponsored',\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 // The \"light\" build drops rarely-needed features (alt-audio, subtitles,\n // EME, low-latency) — far smaller than the full build for the common case\n // of plain VOD m3u8. Consumers who need them can provide window.Hls\n // (full build) which is picked up above.\n const mod = await import('hls.js/light')\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 * One row in the settings (gear) drill-down. Either a drill row (label + current\n * value → options) or a toggle row (label + on/off switch).\n */\nexport interface SettingEntry {\n key: string\n label: string\n /** Current value shown on a drill row, e.g. \"Auto\", \"1×\", \"Off\". */\n value?: string\n /** The options panel to drill into when a drill row is clicked. */\n section?(): MenuSection\n /** Present → render a toggle switch instead of a drill row. */\n toggle?: {\n value: boolean\n onChange(next: boolean): void\n }\n}\n\nconst CHEVRON_RIGHT = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"m9 6 6 6-6 6\"/></svg>'\nconst CHEVRON_LEFT = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"m15 6-6 6 6 6\"/></svg>'\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 this.root.append(this.renderSection(section))\n }\n this.reveal()\n }\n\n /** Settings (gear) drill-down: a root list of rows, each opening its options. */\n toggleSettings(title: string, entries: SettingEntry[]): void {\n if (this.open) this.close()\n else this.showSettings(title, entries)\n }\n\n showSettings(_title: string, entries: SettingEntry[]): void {\n this.root.classList.add('imp-menu--wide')\n this.renderSettingsRoot(entries)\n this.reveal()\n }\n\n private renderSettingsRoot(entries: SettingEntry[]): void {\n this.root.textContent = ''\n const block = el('div', 'imp-menu__section')\n for (const entry of entries) {\n if (entry.toggle) {\n block.append(this.buildToggleRow(entry, entry.toggle))\n continue\n }\n const row = el('button', 'imp-menu__item imp-menu__row', { type: 'button' })\n const label = el('span', 'imp-menu__label')\n label.textContent = entry.label\n const value = el('span', 'imp-menu__value')\n value.textContent = entry.value ?? ''\n const chevron = el('span', 'imp-menu__chevron')\n chevron.innerHTML = CHEVRON_RIGHT\n row.append(label, value, chevron)\n row.addEventListener('click', () => this.renderSettingsDetail(entries, entry))\n block.append(row)\n }\n this.root.append(block)\n }\n\n /** Toggle row: label + an on/off switch. Stays in the menu (no close). */\n private buildToggleRow(entry: SettingEntry, toggle: NonNullable<SettingEntry['toggle']>): HTMLElement {\n const row = el('button', 'imp-menu__item imp-menu__row imp-menu__toggle', {\n type: 'button', role: 'switch', 'aria-checked': String(toggle.value),\n })\n const label = el('span', 'imp-menu__label')\n label.textContent = entry.label\n const sw = el('span', 'imp-switch')\n sw.append(el('span', 'imp-switch__knob'))\n row.classList.toggle('imp-menu__toggle--on', toggle.value)\n row.append(label, sw)\n row.addEventListener('click', () => {\n const next = row.getAttribute('aria-checked') !== 'true'\n row.setAttribute('aria-checked', String(next))\n row.classList.toggle('imp-menu__toggle--on', next)\n toggle.onChange(next)\n })\n return row\n }\n\n private renderSettingsDetail(entries: SettingEntry[], entry: SettingEntry): void {\n if (!entry.section) return // toggle rows have no drill-down panel\n this.root.textContent = ''\n const back = el('button', 'imp-menu__item imp-menu__back', { type: 'button' })\n const chevron = el('span', 'imp-menu__chevron')\n chevron.innerHTML = CHEVRON_LEFT\n const label = el('span', 'imp-menu__label')\n label.textContent = entry.label\n back.append(chevron, label)\n back.addEventListener('click', () => this.renderSettingsRoot(entries))\n this.root.append(back)\n this.root.append(this.renderSection(entry.section()))\n this.root.scrollTop = 0\n }\n\n /** Build one option block (radio items) from a section. */\n private renderSection(section: MenuSection): HTMLElement {\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 return block\n }\n\n /** Reveal the populated menu + backdrop and arm the outside-click listener. */\n private reveal(): void {\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.root.classList.remove('imp-menu--wide')\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 type { NextPreviewOptions, SeekLabelFormat, SettingPlacement } from '../types'\nimport { Menu, type MenuSection, type SettingEntry } 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 /** What the ⋯ menu shows in its place — one section, several, or none. */\n section(): MenuSection | 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 private seekLabelFn?: SeekLabelFormat\n /** Right-cluster controls keyed for ordering; appended in `controls.order`. */\n private rightItems = new Map<string, 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 /** Unified ⚙ dropdown holding the settings placed in `\"gear\"`. */\n private gearBtn: HTMLButtonElement | null = null\n private gearMenu: Menu | null = null\n /** Which settings live in the gear menu (vs their own bar button / off). */\n private gear = { speed: false, quality: false, subtitles: false }\n /** Next-up hover preview (desktop). */\n private nextPreviewEl: HTMLElement | null = null\n private nextPreviewOpts: Required<NextPreviewOptions> | null = null\n private scenesBtn: HTMLButtonElement | null = null\n private sceneTypeBtn: HTMLButtonElement | null = null\n private sceneTypeMenu: Menu | 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\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 this.seekLabelFn = seekCfg.label\n\n // --- left cluster: prev · −Ns · play · +Ns · next · volume · time ---\n // The bar prev button is opt-in (hidePrev defaults true → bar shows only\n // next). The mobile center cluster still gets its own prev regardless.\n if (c.playlist && player.hasPlaylist && !c.hidePrev) {\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.addStepBadge(this.seekBackBtn, seekBack, 'back')\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.addStepBadge(this.seekFwdBtn, seekFwd, 'forward')\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()\n\n // Consumer actions placed directly in the bar (icon button, tooltip = title).\n for (const ca of (player.actionsOptions.custom ?? []).filter((a) => a.placement === 'bar')) {\n const btn = iconButton(`imp-btn--custom imp-btn--custom-${ca.id}`, ca.title, ca.icon ?? icons.more)\n btn.addEventListener('click', () => player.emit('customaction', { id: ca.id }))\n this.rightItems.set(`custom:${ca.id}`, btn)\n this.registerCollapsible({\n key: `custom:${ca.id}`, el: btn, priority: 55, available: () => true,\n section: () => this.simpleSection(`custom:${ca.id}`, ca.title, ca.icon ?? icons.more, () => player.emit('customaction', { id: ca.id })),\n })\n }\n\n // Settings placement: subtitles / quality / speed each live in the gear\n // dropdown ('gear', default), as their own bar button ('bar'), or off.\n const place = (v: SettingPlacement | undefined): 'gear' | 'bar' | 'off' =>\n v === false ? 'off' : v === 'bar' ? 'bar' : 'gear'\n const subsPlace = place(c.subtitles)\n const qualityPlace = place(c.quality)\n const speedPlace = place(c.speed)\n this.gear = { speed: speedPlace === 'gear', quality: qualityPlace === 'gear', subtitles: subsPlace === 'gear' }\n\n // Standalone (bar) settings buttons — only when explicitly pulled out.\n if (subsPlace === 'bar') {\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 this.rightItems.set('subtitles', wrap)\n this.registerCollapsible({\n key: 'subtitles', el: wrap, priority: 30,\n available: () => player.subtitleTracks.length > 0,\n section: () => this.subtitlesSection(),\n })\n }\n if (qualityPlace === 'bar') {\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 this.rightItems.set('quality', wrap)\n this.registerCollapsible({\n key: 'quality', el: wrap, priority: 10,\n available: () => player.qualityLevels.length > 0,\n section: () => this.qualitySection(),\n })\n }\n if (speedPlace === 'bar') {\n this.settingsBtn = iconButton('imp-btn--speed', labels.speed, 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 this.rightItems.set('speed', wrap)\n this.registerCollapsible({\n key: 'speed', el: wrap, priority: 40,\n available: () => true,\n section: () => this.speedSection(),\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 this.rightItems.set('scenes', 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 // Scene-type selector (icon + current type label, dropdown). Visible only\n // when the source carries typed scene groups.\n if (c.sceneTypes !== false) {\n this.sceneTypeBtn = el('button', 'imp-btn imp-btn--scene-types', { type: 'button' })\n this.sceneTypeMenu = new Menu(this.sceneTypeBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.sceneTypeBtn, this.sceneTypeMenu.root)\n this.sceneTypeBtn.addEventListener('click', () => this.toggleSceneTypeMenu())\n this.rightItems.set('sceneTypes', wrap)\n this.refreshSceneTypeButton()\n this.registerCollapsible({\n key: 'sceneTypes', el: wrap, priority: 26,\n available: () => player.sceneTypes.length > 0,\n section: () => this.sceneTypeSection(),\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 this.rightItems.set('playlist', 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 this.rightItems.set('pip', 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 this.rightItems.set('fullscreen', 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 this.addStepBadge(b, seekBack, 'back')\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 this.addStepBadge(f, seekFwd, 'forward')\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 // Next-up hover preview (desktop). Wired to whichever next buttons exist.\n this.setupNextPreview()\n\n // Unified ⚙ dropdown — placed immediately left of the ⋯ button. Holds\n // whatever is set to 'gear'; hidden entirely when it has no available\n // section (handled by `available()`).\n if (this.gear.speed || this.gear.quality || this.gear.subtitles) {\n this.gearBtn = iconButton('imp-btn--settings', labels.settings, icons.settings)\n this.gearMenu = new Menu(this.gearBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.gearBtn, this.gearMenu.root)\n this.gearBtn.addEventListener('click', () => this.toggleGearMenu())\n this.rightItems.set('gear', wrap)\n this.registerCollapsible({\n key: 'gear', el: wrap, priority: 40,\n available: () => this.gearSections().length > 0,\n section: () => this.gearSections(),\n })\n }\n\n // Append the right-cluster controls in the configured (or built-in) order.\n this.layoutRightCluster(right)\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 /**\n * Append the right-cluster controls. Built-in order = creation order; if\n * `controls.order` is set, its keys go first (in that order), then any\n * unlisted controls keep their default position. (⋯ is appended separately.)\n */\n private layoutRightCluster(right: HTMLElement): void {\n const insertion = [...this.rightItems.keys()]\n const requested = this.player.controlsOptions.order as string[]\n let keys = insertion\n if (requested.length > 0) {\n const seen = new Set<string>()\n keys = []\n for (const k of requested) {\n if (this.rightItems.has(k) && !seen.has(k)) {\n keys.push(k)\n seen.add(k)\n }\n }\n for (const k of insertion) if (!seen.has(k)) keys.push(k)\n }\n for (const k of keys) {\n const node = this.rightItems.get(k)\n if (node) right.append(node)\n }\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 /** Caption under the seek arrow. Default \"−15s\"/\"+15s\"; overridable via `controls.seekButtons.label`. */\n private addStepBadge(btn: HTMLButtonElement, step: number, dir: 'back' | 'forward'): void {\n const num = el('span', 'imp-seek-num')\n num.textContent = this.seekLabelFn\n ? this.seekLabelFn(step, dir)\n : `${dir === 'back' ? '−' : '+'}${step}${this.player.labels.secondsShort}`\n btn.append(num)\n }\n\n // === gear (unified settings) ==========================================\n\n /** Sections for the gear when overflowed into ⋯ (expanded, no drill-down). */\n private gearSections(): MenuSection[] {\n const p = this.player\n const out: MenuSection[] = []\n if (this.gear.quality && p.qualityLevels.length > 0) out.push(this.qualitySection())\n if (this.gear.speed) out.push(this.speedSection())\n if (this.gear.subtitles && p.subtitleTracks.length > 0) out.push(this.subtitlesSection())\n return out\n }\n\n /** Gear drill-down rows: one per setting, each showing its current value. */\n private gearEntries(): SettingEntry[] {\n const p = this.player\n const out: SettingEntry[] = []\n // Autoplay toggle — only meaningful with a playlist (next item to advance to).\n if (p.hasPlaylist) {\n out.push({\n key: 'autoplay',\n label: p.labels.autoplay,\n toggle: { value: p.autoAdvance, onChange: (v) => p.setAutoAdvance(v) },\n })\n }\n if (this.gear.quality && p.qualityLevels.length > 0) {\n const value = p.currentQuality === -1\n ? p.labels.qualityAuto\n : p.qualityLevels.find((l) => l.index === p.currentQuality)?.label ?? p.labels.qualityAuto\n out.push({ key: 'quality', label: p.labels.quality, value, section: () => this.qualitySection() })\n }\n if (this.gear.speed) {\n const r = p.playbackRate\n out.push({ key: 'speed', label: p.labels.speed, value: r === 1 ? '1×' : `${r}×`, section: () => this.speedSection() })\n }\n if (this.gear.subtitles && p.subtitleTracks.length > 0) {\n const value = p.activeSubtitle === -1\n ? p.labels.subtitlesOff\n : p.subtitleTracks[p.activeSubtitle]?.label ?? p.labels.subtitlesOff\n out.push({ key: 'subtitles', label: p.labels.subtitles, value, section: () => this.subtitlesSection() })\n }\n return out\n }\n\n // === scene types ======================================================\n\n /** Update the scene-type button to the active group's icon + title. */\n private refreshSceneTypeButton(): void {\n const btn = this.sceneTypeBtn\n if (!btn) return\n const active = this.player.activeSceneType\n btn.textContent = ''\n if (!active) return\n if (active.icon) {\n const iconBox = el('span', 'imp-scene-type__icon')\n if (active.icon.trimStart().startsWith('<svg')) iconBox.innerHTML = active.icon\n else iconBox.append(el('img', '', { src: active.icon, alt: '' }))\n btn.append(iconBox)\n }\n const label = el('span', 'imp-scene-type__label')\n label.textContent = active.title\n btn.append(label)\n btn.setAttribute('aria-label', `${this.player.labels.sceneTypes}: ${active.title}`)\n btn.title = active.title\n }\n\n private sceneTypeSection(): MenuSection {\n const p = this.player\n return {\n title: p.labels.sceneTypes,\n items: p.sceneTypes.map((g) => ({\n label: g.title,\n value: g.id,\n icon: g.icon,\n active: g.id === (p.activeSceneType?.id ?? ''),\n })),\n onSelect: (value) => {\n p.setSceneGroup(value)\n this.refreshSceneTypeButton()\n },\n }\n }\n\n private toggleSceneTypeMenu(): void {\n if (!this.sceneTypeMenu || this.player.sceneTypes.length === 0) return\n this.closeMenus(this.sceneTypeMenu)\n this.sceneTypeMenu.toggle([this.sceneTypeSection()])\n }\n\n private toggleGearMenu(): void {\n if (!this.gearMenu) return\n const entries = this.gearEntries()\n if (entries.length === 0) return\n this.closeMenus(this.gearMenu)\n this.gearMenu.toggleSettings(this.player.labels.settings, entries)\n }\n\n // === next-up hover preview ============================================\n\n private setupNextPreview(): void {\n const p = this.player\n const c = p.controlsOptions\n if (c.nextPreview === false || !c.playlist || !p.hasPlaylist) return\n const o = typeof c.nextPreview === 'object' ? c.nextPreview : {}\n this.nextPreviewOpts = {\n thumbnail: o.thumbnail ?? true,\n title: o.title ?? true,\n duration: o.duration ?? true,\n meta: o.meta ?? true,\n }\n this.nextPreviewEl = el('div', 'imp-next-preview')\n this.nextPreviewEl.hidden = true\n p.container.append(this.nextPreviewEl)\n if (this.nextBtn) this.bindNextPreview(this.nextBtn)\n if (this.centerNextBtn) this.bindNextPreview(this.centerNextBtn)\n }\n\n private bindNextPreview(btn: HTMLButtonElement): void {\n // Mouse only — touch has no hover, and a tap should just go to the next item.\n btn.addEventListener('pointerenter', (e) => {\n if (e.pointerType === 'mouse') this.showNextPreview(btn)\n })\n btn.addEventListener('pointerleave', () => this.hideNextPreview())\n btn.addEventListener('click', () => this.hideNextPreview())\n }\n\n private showNextPreview(btn: HTMLButtonElement): void {\n const card = this.nextPreviewEl\n const opts = this.nextPreviewOpts\n if (!card || !opts) return\n const src = this.player.nextSource\n if (!src) return\n\n card.textContent = ''\n const kicker = el('div', 'imp-next-preview__kicker')\n kicker.textContent = this.player.labels.next\n card.append(kicker)\n\n if (opts.thumbnail && src.poster) {\n const thumb = el('div', 'imp-next-preview__thumb')\n thumb.style.backgroundImage = `url(\"${src.poster}\")`\n if (opts.duration && src.duration) {\n const d = el('span', 'imp-next-preview__duration')\n d.textContent = formatTime(src.duration)\n thumb.append(d)\n }\n card.append(thumb)\n }\n if (opts.title && src.title) {\n const t = el('div', 'imp-next-preview__title')\n t.textContent = src.title\n card.append(t)\n }\n if (opts.meta && src.previewMeta?.length) {\n const m = el('div', 'imp-next-preview__meta')\n m.textContent = src.previewMeta.join(' · ')\n card.append(m)\n }\n\n // Anchor centered above the hovered button, then clamp inside the player so\n // the card never spills past (and gets clipped by) the player edges.\n card.hidden = false\n const cr = this.player.container.getBoundingClientRect()\n const r = btn.getBoundingClientRect()\n const pad = 8\n const cardW = card.offsetWidth\n const centered = r.left - cr.left + r.width / 2 - cardW / 2\n const left = Math.max(pad, Math.min(centered, cr.width - cardW - pad))\n card.style.left = `${left}px`\n card.style.bottom = `${cr.height - (r.top - cr.top) + 10}px`\n }\n\n private hideNextPreview(): void {\n if (this.nextPreviewEl) this.nextPreviewEl.hidden = true\n }\n\n /** like/dislike — visible buttons (collapsible), highlightable via `setLikeState`. */\n private buildLikeDislike(): 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 this.rightItems.set('like', 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 this.rightItems.set('dislike', 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 // Bar-placed custom actions render as their own buttons; only menu ones here.\n for (const custom of (a.custom ?? []).filter((ca) => ca.placement !== 'bar')) {\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', 'sceneTypes', 'pip', 'list', 'subtitles', 'speed', 'quality', 'gear']\n const rank = (key: string) => {\n const i = order.indexOf(key)\n return i === -1 ? order.length : i // custom:* etc. sort after known keys\n }\n const overflowedSorted = this.collapsibles\n .filter((c) => this.overflowed.has(c.key) && c.available())\n .sort((a, b) => rank(a.key) - rank(b.key))\n\n for (const c of overflowedSorted) {\n const result = c.section()\n if (!result) continue\n // A collapsible may contribute one section or several (the gear menu).\n for (const section of Array.isArray(result) ? result : [result]) {\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 }\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 // The seek ±N (and center play) live over the video when seekPlacement is\n // 'overlay' (default, every viewport) or always on mobile. In 'bar' mode on\n // desktop they stay in the bottom bar instead.\n const overlay = this.player.controlsOptions.seekPlacement !== 'bar'\n const useCenter = overlay || compact\n this.center.style.display = useCenter ? 'flex' : 'none'\n\n // prev/next sit in the center cluster ONLY on mobile; on desktop they live\n // in the bottom bar next to the bar play button. Seek ±N and the center\n // play show whenever the cluster is visible.\n if (this.centerPrevBtn) this.centerPrevBtn.style.display = compact ? '' : 'none'\n if (this.centerNextBtn) this.centerNextBtn.style.display = compact ? '' : 'none'\n\n // Bar play/pause: shown on desktop (with prev/next), hidden on mobile where\n // the center cluster owns playback.\n if (this.playBtn) this.playBtn.style.display = compact ? 'none' : ''\n\n // Which bar buttons are currently relocated into the center cluster:\n // - seek ±N → whenever the cluster is used (overlay desktop or mobile);\n // - prev/next → mobile only.\n const inCenter = (key: string): boolean => {\n if (key === 'seekBack' || key === 'seekFwd') return useCenter\n if (key === 'prev' || key === 'next') return compact\n return false\n }\n\n // Reset: availability first, clear forced-overflow hides.\n this.overflowed.clear()\n for (const c of this.collapsibles) {\n if (inCenter(c.key)) {\n // Relocated into the center cluster — hide its bottom-bar twin.\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() && !inCenter(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.refreshSceneTypeButton()\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.gearMenu, this.settingsMenu, this.subtitlesMenu, this.qualityMenu, this.sceneTypeMenu, 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.gearMenu?.destroy()\n this.sceneTypeMenu?.destroy()\n this.settingsMenu?.destroy()\n this.subtitlesMenu?.destroy()\n this.qualityMenu?.destroy()\n this.moreMenu?.destroy()\n this.nextPreviewEl?.remove()\n this.root.remove()\n }\n}\n","import { el, formatTime, 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 /** A real <img> (not a background) so it can be the LCP element the browser prioritizes. */\n private image: HTMLImageElement\n\n constructor(player: Player) {\n this.root = el('div', 'imp-poster')\n this.image = el('img', 'imp-poster__image', { alt: '', decoding: 'async' }) as HTMLImageElement\n this.image.hidden = true\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 if (source?.poster) {\n this.image.src = source.poster\n // First poster is the page's hero — hint the browser to load it eagerly.\n this.image.fetchPriority = 'high'\n this.image.hidden = false\n } else {\n this.image.removeAttribute('src')\n this.image.hidden = true\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/**\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 /** Which parts the consumer allows (a hidden part stays hidden even with data). */\n private visible = { title: true, description: true, sponsor: true }\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 ABOVE the title (the promo slot comes first),\n // shown only when set on the source.\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 // Order on the overlay: sponsor (ad link) → title → description.\n heading.append(this.sponsor, this.title, this.description)\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 /** Hide specific parts of the default overlay (consumer renders them itself). */\n setVisibility(parts: { title?: boolean; description?: boolean; sponsor?: boolean }): void {\n this.visible = {\n title: parts.title ?? this.visible.title,\n description: parts.description ?? this.visible.description,\n sponsor: parts.sponsor ?? this.visible.sponsor,\n }\n }\n\n setSource(source: VideoSource | null): void {\n this.title.textContent = source?.title ?? ''\n this.description.textContent = source?.description ?? ''\n this.title.hidden = !this.visible.title || !source?.title\n this.description.hidden = !this.visible.description || !source?.description\n\n // Sponsor link — only for sponsored videos (i.e. when provided) and allowed.\n const sponsor = this.visible.sponsor ? source?.sponsor : undefined\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 private clickBehavior: NonNullable<RelatedOptions['clickBehavior']> = 'player'\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.clickBehavior = options.clickBehavior ?? 'player'\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 // The event always fires — consumers can fully drive navigation themselves.\n this.player.emit('relatedclick', { item })\n this.hide()\n this.activate(item)\n })\n return card\n }\n\n /** Apply the configured click behavior. */\n private activate(item: RelatedItem): void {\n const url = item.url ?? item.source?.src\n switch (this.clickBehavior) {\n case 'newWindow':\n if (url) window.open(url, '_blank', 'noopener')\n break\n case 'currentTab':\n if (url) window.location.href = url\n break\n case 'player':\n default:\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 }\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\n/**\n * End-of-video \"up next\" overlay shown when autoplay is OFF and a next item\n * exists: a preview card of the next video + a \"Play next\" button.\n */\nexport class UpNextOverlay {\n readonly root: HTMLElement\n\n constructor(private player: Player) {\n this.root = el('div', 'imp-upnext')\n this.root.hidden = true\n }\n\n get visible(): boolean {\n return !this.root.hidden\n }\n\n show(): void {\n const src = this.player.nextSource\n if (!src) return\n const { labels } = this.player\n\n this.root.textContent = ''\n const card = el('div', 'imp-upnext__card')\n\n const kicker = el('div', 'imp-upnext__kicker')\n kicker.textContent = labels.nextVideo\n card.append(kicker)\n\n if (src.poster) {\n const thumb = el('button', 'imp-upnext__thumb', { type: 'button', 'aria-label': labels.playNext })\n thumb.style.backgroundImage = `url(\"${src.poster}\")`\n if (src.duration) {\n const dur = el('span', 'imp-upnext__duration')\n dur.textContent = formatTime(src.duration)\n thumb.append(dur)\n }\n const play = el('span', 'imp-upnext__thumb-play')\n play.innerHTML = this.player.icons.bigPlay\n thumb.append(play)\n thumb.addEventListener('click', () => this.player.next())\n card.append(thumb)\n }\n\n if (src.title) {\n const title = el('div', 'imp-upnext__title')\n title.textContent = src.title\n card.append(title)\n }\n if (src.previewMeta?.length) {\n const meta = el('div', 'imp-upnext__meta')\n // Leading uploader glyph: explicit override → channel icon (when a channel\n // is set) → generic user icon.\n const icon = el('span', 'imp-upnext__meta-icon')\n icon.innerHTML = src.metaIcon ?? (src.channel ? this.player.icons.channel : this.player.icons.user)\n const text = el('span', 'imp-upnext__meta-text')\n text.textContent = src.previewMeta.join(' · ')\n meta.append(icon, text)\n card.append(meta)\n }\n\n const btn = el('button', 'imp-upnext__btn', { type: 'button' })\n btn.textContent = labels.playNext\n btn.addEventListener('click', () => this.player.next())\n card.append(btn)\n\n this.root.append(card)\n this.root.hidden = false\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 // Mobile full-cover sheet: close on pick so the video shows at once.\n if (window.innerWidth <= 767) this.hide()\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 // On mobile the panel is a full-cover sheet — close it so the chosen\n // scene is visible immediately (no manual close). Desktop sidebar/strip\n // stays open: the video is visible alongside it.\n if (window.innerWidth <= 767) this.hide()\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, UpNextOverlay } 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 SceneGroup,\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-type controls default into the unified ⚙ dropdown.\n speed: 'gear',\n settings: 'gear', // legacy alias for `speed`; resolved in the constructor\n quality: 'gear',\n scenes: true,\n sceneTypes: true,\n heatmap: true,\n subtitles: 'gear',\n seekButtons: true,\n // Prev/seek/play/next as a centered overlay on every viewport.\n seekPlacement: 'overlay',\n order: [], // empty → built-in right-cluster order\n playlist: true,\n hidePrev: true,\n nextPreview: 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 /** Typed scene breakdowns; the active one drives `chapters`. */\n private sceneGroupList: SceneGroup[] = []\n private activeSceneGroupId = ''\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 upNext: UpNextOverlay\n /** Runtime autoplay-next toggle (gear switch); seeds from playlist.autoAdvance. */\n private autoAdvanceEnabled = true\n /** localStorage key for persisted prefs, or null when persistence is off. */\n private persistKey: string | null = null\n private persistVolume = false\n private persistAutoAdvance = false\n private playlistPanel: PlaylistPanel\n private scenesPanel: ScenesPanel\n private spinner: HTMLElement\n private errorBox!: HTMLElement\n private decodeRecoveries = 0\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 // Resolve the deprecated `settings` alias from the raw options (an explicit\n // `speed` wins; else legacy `settings`; else the 'gear' default).\n const rawControls = options.controls ?? {}\n const speed = rawControls.speed ?? rawControls.settings ?? 'gear'\n this.controlsOptions = { ...defaultControls, ...rawControls, speed, settings: speed }\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 ?? 15\n this.playlistOptions = { title: '', autoAdvance: true, loop: false, shuffle: false, startIndex: 0, layout: 'sidebar', ...options.playlist }\n this.shuffleMode = this.playlistOptions.shuffle\n\n // Persistence: set up before applying volume/autoAdvance so saved prefs win.\n if (options.persist) {\n const p = options.persist === true ? {} : options.persist\n this.persistKey = p.key ?? 'itube-player'\n this.persistVolume = p.volume !== false\n this.persistAutoAdvance = p.autoAdvance !== false\n }\n const saved = this.readPersisted()\n\n this.autoAdvanceEnabled = this.persistAutoAdvance && typeof saved?.autoAdvance === 'boolean'\n ? saved.autoAdvance\n : this.playlistOptions.autoAdvance\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 const styling = options.styling\n if (styling?.themeColor) this.container.style.setProperty('--imp-accent', styling.themeColor)\n if (styling?.likeColor) this.container.style.setProperty('--imp-like', styling.likeColor)\n if (styling?.dislikeColor) this.container.style.setProperty('--imp-dislike', styling.dislikeColor)\n if (styling?.borderRadius !== undefined) {\n const r = typeof styling.borderRadius === 'number' ? `${styling.borderRadius}px` : styling.borderRadius\n this.container.style.setProperty('--imp-radius', r)\n }\n if (styling?.playButtonStyle === 'inverted') this.container.classList.add('imp-player--play-inverted')\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 const savedAV = this.persistVolume ? saved : null\n this.video.volume = clamp(savedAV?.volume ?? options.volume ?? 1, 0, 1)\n if (savedAV?.muted ?? options.muted) this.video.muted = true\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.upNext = new UpNextOverlay(this)\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, this.upNext.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 } else if (options.pauseScreen && typeof options.pauseScreen === 'object') {\n // Plain config object: default overlay with some parts hidden.\n this.pauseScreen.setVisibility(options.pauseScreen)\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 // Tap/click on the video surface. Desktop (mouse): toggles playback, as\n // before. Touch (phones): a tap toggles *controls* visibility instead —\n // play/pause lives on the on-screen center button. This is the standard\n // mobile model and avoids the iOS problem where one tap fired both a\n // play-toggle (click) and a show-controls (pointerdown) at once.\n // We use pointerup (not click) so iOS doesn't also deliver a synthesized\n // mouse click that double-fires the handler.\n this.video.addEventListener('pointerup', (e) => {\n if (this.adPlaying || !this.playedOnce) return\n if (e.pointerType === 'mouse') {\n this.togglePlay()\n return\n }\n // Touch / pen: reveal controls if hidden, hide them if shown while\n // playing. When paused the controls (and pause screen) stay up.\n if (this.container.classList.contains('imp-player--idle')) {\n this.showControlsNow()\n this.scheduleIdle()\n } else if (!this.video.paused) {\n this.container.classList.add('imp-player--idle')\n }\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 // === persistence ======================================================\n\n /** Read persisted prefs (safe against private mode / SSR / bad JSON). */\n private readPersisted(): { volume?: number; muted?: boolean; autoAdvance?: boolean } | null {\n if (!this.persistKey) return null\n try {\n const raw = localStorage.getItem(this.persistKey)\n const data = raw ? JSON.parse(raw) : null\n return data && typeof data === 'object' ? data : null\n } catch {\n return null\n }\n }\n\n /** Write the enabled prefs to localStorage. No-op when persistence is off. */\n private persistState(): void {\n if (!this.persistKey) return\n try {\n const data: { volume?: number; muted?: boolean; autoAdvance?: boolean } = {}\n if (this.persistVolume) {\n data.volume = this.video.volume\n data.muted = this.video.muted\n }\n if (this.persistAutoAdvance) data.autoAdvance = this.autoAdvanceEnabled\n localStorage.setItem(this.persistKey, JSON.stringify(data))\n } catch {\n // private mode / quota / SSR — persistence is best-effort.\n }\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 /**\n * The item that `next()` would play in linear order (for the next-up preview).\n * `null` in shuffle mode (the pick is random) or when there is no next item.\n */\n get nextSource(): VideoSource | null {\n if (this.shuffleMode || this.sources.length < 2) return null\n const i = this.currentIndex + 1\n if (i < this.sources.length) return this.sources[i]\n return this.playlistOptions.loop ? this.sources[0] ?? null : 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 // === scene types (groups) =============================================\n\n /** Typed scene breakdowns attached to the current source (may be empty). */\n get sceneTypes(): SceneGroup[] {\n return this.sceneGroupList\n }\n\n /** Currently selected scene type, or null when there are no groups. */\n get activeSceneType(): SceneGroup | null {\n return this.sceneGroupList.find((g) => g.id === this.activeSceneGroupId) ?? null\n }\n\n /** Switch the active scene type — rebuilds the timeline segments + scenes panel. */\n setSceneGroup(id: string): void {\n if (id === this.activeSceneGroupId || !this.sceneGroupList.some((g) => g.id === id)) return\n this.activeSceneGroupId = id\n this.applyActiveSceneGroup()\n this.emitter.emit('scenetypechange', { group: this.activeSceneType })\n }\n\n /** Normalize the active group's scenes into `chapters` and refresh the UI. */\n private applyActiveSceneGroup(): void {\n this.chapters = normalizeChapters(this.activeSceneType?.scenes ?? [], this.video.duration)\n this.currentChapter = null\n this.controls.progress.setChapters(this.chapters)\n this.controls.syncFeatureButtons()\n if (this.scenesPanel.visible) this.scenesPanel.rebuild()\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.sceneGroupList = []\n this.activeSceneGroupId = ''\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.upNext.hide()\n this.pauseScreen.hide()\n this.scenesPanel.hide()\n this.thumbTrack = null\n this.errorBox.hidden = true\n this.decodeRecoveries = 0\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.sceneGroups && source.sceneGroups.length > 0) {\n // Typed scene breakdowns: pick the first group, build the timeline from it.\n this.sceneGroupList = source.sceneGroups\n this.activeSceneGroupId = source.sceneGroups[0].id\n const set = () => {\n if (token !== this.loadToken) return\n this.applyActiveSceneGroup()\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 } else 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.upNext.hide()\n // Playback requested but not enough buffered yet (e.g. switching to the\n // next playlist item on a slow connection): show the loader instead of a\n // frozen poster. 'playing' hides it once real frames arrive.\n if (v.readyState < 3 /* HAVE_FUTURE_DATA */) this.spinner.hidden = false\n this.emitter.emit('play', undefined)\n this.scheduleIdle()\n }, { signal })\n\n v.addEventListener('pause', () => {\n this.spinner.hidden = true\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 if (this.persistVolume) this.persistState()\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 // Playback recovered — clear any stale error overlay and the recovery counter.\n this.errorBox.hidden = true\n this.decodeRecoveries = 0\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) return\n\n // Native playback (incl. Safari/iOS HLS) can throw transient decode/parse\n // errors when seeking backward (DEMUXER_ERROR_COULD_NOT_PARSE). Try a\n // silent reload-and-restore a couple of times before surfacing an error.\n const decodeish = mediaError.code === MediaError.MEDIA_ERR_DECODE || /DEMUXER|PARSE|DECODE/i.test(mediaError.message || '')\n if (decodeish && this.decodeRecoveries < 2 && Number.isFinite(v.duration)) {\n this.decodeRecoveries++\n const at = v.currentTime\n const wasPlaying = !v.paused\n v.load()\n const restore = () => {\n try { v.currentTime = at } catch { /* range not ready yet */ }\n if (wasPlaying) void v.play().catch(() => {})\n }\n v.readyState >= 1 ? restore() : v.addEventListener('loadedmetadata', restore, { once: true, signal: this.abort.signal })\n return\n }\n\n this.emitter.emit('error', { message: mediaError.message || `Media error (code ${mediaError.code})`, cause: mediaError })\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.autoAdvanceEnabled && this.hasNext) {\n this.next()\n return\n }\n // Autoplay off: offer the next item with a \"play next\" card instead.\n if (!this.autoAdvanceEnabled && this.hasNext) {\n this.upNext.show()\n return\n }\n if (this.options.related?.showOn?.includes('ended') ?? Boolean(this.options.related)) {\n this.related.show()\n }\n }\n\n /** Autoplay-next state (gear switch). Off → show the up-next card on end. */\n get autoAdvance(): boolean {\n return this.autoAdvanceEnabled\n }\n\n setAutoAdvance(on: boolean): void {\n this.autoAdvanceEnabled = on\n if (on) this.upNext.hide()\n if (this.persistAutoAdvance) this.persistState()\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 // Mouse/keyboard reveal-on-activity. Touch is deliberately excluded here:\n // a tap is handled by the pointerup tap-toggle on the video, so letting\n // pointerdown also fire reset() would make one tap both show *and* (via the\n // tap handler) hide the controls — they'd never actually toggle.\n this.container.addEventListener('pointermove', (e) => {\n if (e.pointerType !== 'touch') reset()\n }, { signal })\n this.container.addEventListener('pointerdown', (e) => {\n if (e.pointerType !== 'touch') reset()\n }, { signal })\n this.container.addEventListener('keydown', reset, { signal })\n this.container.addEventListener('pointerleave', (e) => {\n if (e.pointerType === 'touch') return\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","/**\n * Entry for the standalone IIFE bundle (script-tag usage, no bundler):\n *\n * ```html\n * <link rel=\"stylesheet\" href=\"https://unpkg.com/itube-modern-player/dist/style.css\">\n * <!-- only needed for m3u8 sources: -->\n * <script src=\"https://unpkg.com/hls.js\"></script>\n * <script src=\"https://unpkg.com/itube-modern-player/dist/itube-modern-player.iife.js\"></script>\n * <script>\n * const player = new ITubePlayer('#mount', { source: { src: 'video.mp4' } })\n * </script>\n * ```\n */\nimport { Player, registerLocales } from './coreEntry'\nimport { locales } from './core/locales'\n\n// Register built-ins here, in the entry module itself — side effects of an\n// entry are never tree-shaken, unlike a re-exporting intermediate module.\nregisterLocales(locales)\n\nexport default Player\n","import type { LocaleCode, PlayerLabels } from '../types'\nimport { defaultLabels } from './labels'\n\n/**\n * Built-in static locales. Pick one with `options.language`; any individual\n * string can still be overridden via `options.labels`.\n *\n * The canonical term list is the `PlayerLabels` interface — `defaultLabels`\n * (English) is exported as the reference dictionary for translators.\n */\nexport const locales: Record<LocaleCode, PlayerLabels> = {\n en: defaultLabels,\n\n ru: {\n play: 'Воспроизвести',\n pause: 'Пауза',\n replay: 'Смотреть снова',\n mute: 'Выключить звук',\n unmute: 'Включить звук',\n fullscreen: 'Во весь экран',\n exitFullscreen: 'Выйти из полноэкранного режима',\n pip: 'Картинка в картинке',\n settings: 'Скорость воспроизведения',\n subtitles: 'Субтитры',\n subtitlesOff: 'Выкл.',\n speed: 'Скорость',\n quality: 'Качество',\n qualityAuto: 'Авто',\n next: 'Следующее',\n nextVideo: 'Следующее видео',\n previous: 'Предыдущее',\n playlist: 'Плейлист',\n scenes: 'Сцены',\n sceneTypes: 'Тип сцен',\n autoplay: 'Автовоспроизведение',\n playNext: 'Играть дальше',\n shuffle: 'Перемешать',\n repeat: 'Повтор',\n like: 'Нравится',\n dislike: 'Не нравится',\n addTo: 'Сохранить в…',\n share: 'Поделиться',\n report: 'Пожаловаться',\n more: 'Ещё',\n seekForward: 'Перемотать вперёд',\n seekBack: 'Перемотать назад',\n secondsShort: 'с',\n live: 'В ЭФИРЕ',\n related: 'Похожие видео',\n adLabel: 'Реклама',\n skipAd: 'Пропустить рекламу',\n skipAdIn: 'Пропуск через',\n visitAdvertiser: 'Перейти к рекламодателю',\n sponsored: 'Спонсор',\n },\n\n de: {\n play: 'Wiedergabe',\n pause: 'Pause',\n replay: 'Erneut abspielen',\n mute: 'Stummschalten',\n unmute: 'Ton einschalten',\n fullscreen: 'Vollbild',\n exitFullscreen: 'Vollbild beenden',\n pip: 'Bild im Bild',\n settings: 'Wiedergabegeschwindigkeit',\n subtitles: 'Untertitel',\n subtitlesOff: 'Aus',\n speed: 'Geschwindigkeit',\n quality: 'Qualität',\n qualityAuto: 'Automatisch',\n next: 'Weiter',\n nextVideo: 'Nächstes Video',\n previous: 'Zurück',\n playlist: 'Playlist',\n scenes: 'Szenen',\n sceneTypes: 'Szenentyp',\n autoplay: 'Autoplay',\n playNext: 'Weiter abspielen',\n shuffle: 'Zufallswiedergabe',\n repeat: 'Wiederholen',\n like: 'Mag ich',\n dislike: 'Mag ich nicht',\n addTo: 'Speichern in…',\n share: 'Teilen',\n report: 'Melden',\n more: 'Weitere Aktionen',\n seekForward: 'Vorspulen',\n seekBack: 'Zurückspulen',\n secondsShort: 's',\n live: 'LIVE',\n related: 'Weitere Videos',\n adLabel: 'Anzeige',\n skipAd: 'Werbung überspringen',\n skipAdIn: 'Überspringen in',\n visitAdvertiser: 'Zum Werbetreibenden',\n sponsored: 'Gesponsert',\n },\n\n es: {\n play: 'Reproducir',\n pause: 'Pausa',\n replay: 'Volver a reproducir',\n mute: 'Silenciar',\n unmute: 'Activar sonido',\n fullscreen: 'Pantalla completa',\n exitFullscreen: 'Salir de pantalla completa',\n pip: 'Imagen en imagen',\n settings: 'Velocidad de reproducción',\n subtitles: 'Subtítulos',\n subtitlesOff: 'Desactivados',\n speed: 'Velocidad',\n quality: 'Calidad',\n qualityAuto: 'Automática',\n next: 'Siguiente',\n nextVideo: 'Siguiente vídeo',\n previous: 'Anterior',\n playlist: 'Lista de reproducción',\n scenes: 'Escenas',\n sceneTypes: 'Tipo de escena',\n autoplay: 'Reproducción automática',\n playNext: 'Reproducir siguiente',\n shuffle: 'Aleatorio',\n repeat: 'Repetir',\n like: 'Me gusta',\n dislike: 'No me gusta',\n addTo: 'Guardar en…',\n share: 'Compartir',\n report: 'Denunciar',\n more: 'Más acciones',\n seekForward: 'Avanzar',\n seekBack: 'Retroceder',\n secondsShort: 's',\n live: 'EN VIVO',\n related: 'Más vídeos',\n adLabel: 'Anuncio',\n skipAd: 'Omitir anuncio',\n skipAdIn: 'Omitir en',\n visitAdvertiser: 'Visitar al anunciante',\n sponsored: 'Patrocinado',\n },\n\n it: {\n play: 'Riproduci',\n pause: 'Pausa',\n replay: 'Riproduci di nuovo',\n mute: 'Disattiva audio',\n unmute: 'Attiva audio',\n fullscreen: 'Schermo intero',\n exitFullscreen: 'Esci da schermo intero',\n pip: 'Picture-in-picture',\n settings: 'Velocità di riproduzione',\n subtitles: 'Sottotitoli',\n subtitlesOff: 'Disattivati',\n speed: 'Velocità',\n quality: 'Qualità',\n qualityAuto: 'Automatica',\n next: 'Successivo',\n nextVideo: 'Prossimo video',\n previous: 'Precedente',\n playlist: 'Playlist',\n scenes: 'Scene',\n sceneTypes: 'Tipo di scena',\n autoplay: 'Riproduzione automatica',\n playNext: 'Riproduci successivo',\n shuffle: 'Casuale',\n repeat: 'Ripeti',\n like: 'Mi piace',\n dislike: 'Non mi piace',\n addTo: 'Salva in…',\n share: 'Condividi',\n report: 'Segnala',\n more: 'Altre azioni',\n seekForward: 'Avanti veloce',\n seekBack: 'Indietro',\n secondsShort: 's',\n live: 'LIVE',\n related: 'Altri video',\n adLabel: 'Annuncio',\n skipAd: 'Salta annuncio',\n skipAdIn: 'Salta tra',\n visitAdvertiser: \"Visita l'inserzionista\",\n sponsored: 'Sponsorizzato',\n },\n\n ja: {\n play: '再生',\n pause: '一時停止',\n replay: 'もう一度見る',\n mute: 'ミュート',\n unmute: 'ミュート解除',\n fullscreen: '全画面',\n exitFullscreen: '全画面を終了',\n pip: 'ピクチャーインピクチャー',\n settings: '再生速度',\n subtitles: '字幕',\n subtitlesOff: 'オフ',\n speed: '速度',\n quality: '画質',\n qualityAuto: '自動',\n next: '次へ',\n nextVideo: '次の動画',\n previous: '前へ',\n playlist: 'プレイリスト',\n scenes: 'シーン',\n sceneTypes: 'シーンタイプ',\n autoplay: '自動再生',\n playNext: '次を再生',\n shuffle: 'シャッフル',\n repeat: 'リピート',\n like: '高く評価',\n dislike: '低く評価',\n addTo: '保存…',\n share: '共有',\n report: '報告',\n more: 'その他の操作',\n seekForward: '早送り',\n seekBack: '巻き戻し',\n secondsShort: '秒',\n live: 'ライブ',\n related: '関連動画',\n adLabel: '広告',\n skipAd: '広告をスキップ',\n skipAdIn: 'スキップまで',\n visitAdvertiser: '広告主のサイトへ',\n sponsored: 'スポンサー',\n },\n\n ko: {\n play: '재생',\n pause: '일시정지',\n replay: '다시 보기',\n mute: '음소거',\n unmute: '음소거 해제',\n fullscreen: '전체화면',\n exitFullscreen: '전체화면 종료',\n pip: 'PIP 모드',\n settings: '재생 속도',\n subtitles: '자막',\n subtitlesOff: '사용 안 함',\n speed: '속도',\n quality: '화질',\n qualityAuto: '자동',\n next: '다음',\n nextVideo: '다음 동영상',\n previous: '이전',\n playlist: '재생목록',\n scenes: '장면',\n sceneTypes: '장면 유형',\n autoplay: '자동 재생',\n playNext: '다음 재생',\n shuffle: '셔플',\n repeat: '반복',\n like: '좋아요',\n dislike: '싫어요',\n addTo: '저장…',\n share: '공유',\n report: '신고',\n more: '더보기',\n seekForward: '앞으로 감기',\n seekBack: '뒤로 감기',\n secondsShort: '초',\n live: '실시간',\n related: '관련 동영상',\n adLabel: '광고',\n skipAd: '광고 건너뛰기',\n skipAdIn: '건너뛰기까지',\n visitAdvertiser: '광고주 방문',\n sponsored: '스폰서',\n },\n\n zh: {\n play: '播放',\n pause: '暂停',\n replay: '重新播放',\n mute: '静音',\n unmute: '取消静音',\n fullscreen: '全屏',\n exitFullscreen: '退出全屏',\n pip: '画中画',\n settings: '播放速度',\n subtitles: '字幕',\n subtitlesOff: '关闭',\n speed: '速度',\n quality: '画质',\n qualityAuto: '自动',\n next: '下一个',\n nextVideo: '下一个视频',\n previous: '上一个',\n playlist: '播放列表',\n scenes: '场景',\n sceneTypes: '场景类型',\n autoplay: '自动播放',\n playNext: '播放下一个',\n shuffle: '随机播放',\n repeat: '循环播放',\n like: '赞',\n dislike: '踩',\n addTo: '保存到…',\n share: '分享',\n report: '举报',\n more: '更多操作',\n seekForward: '快进',\n seekBack: '快退',\n secondsShort: '秒',\n live: '直播',\n related: '更多视频',\n adLabel: '广告',\n skipAd: '跳过广告',\n skipAdIn: '可跳过',\n visitAdvertiser: '访问广告主',\n sponsored: '赞助',\n },\n\n pt: {\n play: 'Reproduzir',\n pause: 'Pausar',\n replay: 'Assistir novamente',\n mute: 'Sem som',\n unmute: 'Ativar som',\n fullscreen: 'Tela cheia',\n exitFullscreen: 'Sair da tela cheia',\n pip: 'Picture-in-picture',\n settings: 'Velocidade de reprodução',\n subtitles: 'Legendas',\n subtitlesOff: 'Desativadas',\n speed: 'Velocidade',\n quality: 'Qualidade',\n qualityAuto: 'Automática',\n next: 'Próximo',\n nextVideo: 'Próximo vídeo',\n previous: 'Anterior',\n playlist: 'Playlist',\n scenes: 'Cenas',\n sceneTypes: 'Tipo de cena',\n autoplay: 'Reprodução automática',\n playNext: 'Reproduzir próximo',\n shuffle: 'Aleatório',\n repeat: 'Repetir',\n like: 'Gostei',\n dislike: 'Não gostei',\n addTo: 'Salvar em…',\n share: 'Compartilhar',\n report: 'Denunciar',\n more: 'Mais ações',\n seekForward: 'Avançar',\n seekBack: 'Retroceder',\n secondsShort: 's',\n live: 'AO VIVO',\n related: 'Mais vídeos',\n adLabel: 'Anúncio',\n skipAd: 'Pular anúncio',\n skipAdIn: 'Pular em',\n visitAdvertiser: 'Visitar anunciante',\n sponsored: 'Patrocinado',\n },\n\n ar: {\n play: 'تشغيل',\n pause: 'إيقاف مؤقت',\n replay: 'إعادة التشغيل',\n mute: 'كتم الصوت',\n unmute: 'إلغاء كتم الصوت',\n fullscreen: 'ملء الشاشة',\n exitFullscreen: 'الخروج من ملء الشاشة',\n pip: 'صورة داخل صورة',\n settings: 'سرعة التشغيل',\n subtitles: 'الترجمة',\n subtitlesOff: 'إيقاف',\n speed: 'السرعة',\n quality: 'الجودة',\n qualityAuto: 'تلقائي',\n next: 'التالي',\n nextVideo: 'الفيديو التالي',\n previous: 'السابق',\n playlist: 'قائمة التشغيل',\n scenes: 'المشاهد',\n sceneTypes: 'نوع المشهد',\n autoplay: 'تشغيل تلقائي',\n playNext: 'تشغيل التالي',\n shuffle: 'تشغيل عشوائي',\n repeat: 'تكرار',\n like: 'أعجبني',\n dislike: 'لم يعجبني',\n addTo: 'حفظ في…',\n share: 'مشاركة',\n report: 'إبلاغ',\n more: 'المزيد من الإجراءات',\n seekForward: 'تقديم',\n seekBack: 'إرجاع',\n secondsShort: 'ث',\n live: 'مباشر',\n related: 'المزيد من الفيديوهات',\n adLabel: 'إعلان',\n skipAd: 'تخطي الإعلان',\n skipAdIn: 'التخطي بعد',\n visitAdvertiser: 'زيارة المعلن',\n sponsored: 'برعاية',\n },\n\n hi: {\n play: 'चलाएं',\n pause: 'रोकें',\n replay: 'फिर से चलाएं',\n mute: 'म्यूट करें',\n unmute: 'अनम्यूट करें',\n fullscreen: 'फ़ुल स्क्रीन',\n exitFullscreen: 'फ़ुल स्क्रीन से बाहर निकलें',\n pip: 'पिक्चर-इन-पिक्चर',\n settings: 'प्लेबैक गति',\n subtitles: 'सबटाइटल',\n subtitlesOff: 'बंद',\n speed: 'गति',\n quality: 'क्वालिटी',\n qualityAuto: 'ऑटो',\n next: 'अगला',\n nextVideo: 'अगला वीडियो',\n previous: 'पिछला',\n playlist: 'प्लेलिस्ट',\n scenes: 'दृश्य',\n sceneTypes: 'सीन प्रकार',\n autoplay: 'ऑटोप्ले',\n playNext: 'अगला चलाएं',\n shuffle: 'शफ़ल',\n repeat: 'दोहराएं',\n like: 'पसंद',\n dislike: 'नापसंद',\n addTo: 'इसमें सहेजें…',\n share: 'साझा करें',\n report: 'रिपोर्ट करें',\n more: 'अधिक कार्रवाइयां',\n seekForward: 'आगे बढ़ाएं',\n seekBack: 'पीछे करें',\n secondsShort: 's',\n live: 'लाइव',\n related: 'और वीडियो',\n adLabel: 'विज्ञापन',\n skipAd: 'विज्ञापन छोड़ें',\n skipAdIn: 'छोड़ें',\n visitAdvertiser: 'विज्ञापनदाता देखें',\n sponsored: 'प्रायोजित',\n },\n}\n\n/** Codes of all built-in locales. */\nexport const supportedLanguages = Object.keys(locales) as LocaleCode[]\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","defaultLabels","registry","registerLocales","map","code","labels","getLocale","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","CHEVRON_RIGHT","CHEVRON_LEFT","Menu","anchor","sections","section","title","entries","_title","row","chevron","toggle","sw","next","back","item","iconBox","target","ProgressBar","list","filled","cursor","ch","root","fill","track","bufferedEnd","ratio","span","progress","rect","x","half","Controls","player","icons","c","left","right","spacer","seekCfg","seekBack","seekFwd","volumeWrap","ca","place","subsPlace","qualityPlace","speedPlace","wrap","listBtn","pipBtn","insertion","requested","keys","seen","modifier","dir","num","p","out","r","active","g","o","card","kicker","thumb","cr","pad","cardW","centered","_btn","initial","tip","likeCount","dislikeCount","state","custom","moreBtn","runMap","simpleItems","order","rank","overflowedSorted","it","icon","rate","compact","useCenter","inCenter","ok","byPriority","guard","hasContent","rowRight","effective","except","menu","dispose","PosterOverlay","big","source","PauseScreen","heading","element","parts","sponsor","channel","RelatedOverlay","close","UpNextOverlay","dur","play","meta","PlaylistPanel","layout","playlistTitle","header","name","tools","itemTitle","ScenesPanel","thumbs","inner","current","normalizeSubtitles","input","defaultControls","Player","mount","rawControls","speed","saved","styling","savedAV","middle","bottom","adConfig","message","ranges","delta","volume","muted","qualities","q","tracks","on","startIndex","id","autoplay","token","sub","apply","parsed","applyHeatmap","eventName","mediaError","at","restore","reset","isButton"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"itube-modern-player.iife.js","sources":["../src/core/dom.ts","../src/core/events.ts","../src/core/icons.ts","../src/core/labels.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","../src/global.ts","../src/core/locales.ts"],"sourcesContent":["/** DOM helpers. All player markup is built through these — no innerHTML templates. */\n\nimport type { PreviewMetaItem } from '../types'\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\n/**\n * Build the preview-meta row (used by the next-video hover card and the end\n * overlay). Each chunk renders as a `<span>`; a chunk with an `icon` gets an\n * inline leading glyph (e.g. a user icon before \"Uploaded by user\"). Chunks are\n * separated by a `·` via CSS. `base` is the BEM block, e.g. `\"imp-upnext\"`.\n */\nexport function previewMetaEl(items: PreviewMetaItem[], base: string): HTMLElement {\n const row = el('div', `${base}__meta`)\n items.forEach((item, i) => {\n // A real space between chunks is the only line-break opportunity at the\n // separator: the `·` itself is glued to the end of the previous chunk (CSS\n // ::after), so it never orphans at the start of a wrapped line. Text inside\n // a chunk still wraps word-by-word at its own spaces.\n if (i > 0) row.append(document.createTextNode(' '))\n const text = typeof item === 'string' ? item : item.text\n const icon = typeof item === 'string' ? undefined : item.icon\n const chunk = el('span', `${base}__meta-chunk`)\n if (icon) {\n const ic = el('span', `${base}__meta-icon`)\n ic.innerHTML = icon\n chunk.append(ic)\n }\n chunk.append(document.createTextNode(text))\n row.append(chunk)\n })\n return row\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 // Thin circular-arrow (\"rotate\") icons — open center so the step number reads\n // clearly inside the ring (matches the reference skip ±N look).\n seekForward: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"23 4 23 10 17 10\"/><path d=\"M20.49 15a9 9 0 1 1-2.12-9.36L23 10\"/></svg>',\n seekBack: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>',\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 // Generic \"uploaded by a user\" glyph (head + shoulders) for preview meta.\n user: svg('<path d=\"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm0 2c-3.6 0-8 1.8-8 4.4V21h16v-2.6c0-2.6-4.4-4.4-8-4.4Z\"/>'),\n // Generic \"channel\" glyph (play badge) for preview meta when a channel is set.\n channel: svg('<path d=\"M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm7 3.5v7l6-3.5-6-3.5Z\"/>'),\n}\n","import type { PlayerLabels } from '../types'\n\nexport const defaultLabels: PlayerLabels = {\n play: 'Play',\n pause: 'Pause',\n replay: 'Replay',\n mute: 'Mute',\n unmute: 'Unmute',\n fullscreen: 'Fullscreen',\n exitFullscreen: 'Exit fullscreen',\n pip: 'Picture-in-picture',\n settings: 'Playback speed',\n scenes: 'Scenes',\n sceneTypes: 'Scene type',\n autoplay: 'Autoplay',\n playNext: 'Play next',\n shuffle: 'Shuffle',\n repeat: 'Repeat',\n subtitles: 'Subtitles',\n subtitlesOff: 'Off',\n speed: 'Speed',\n quality: 'Quality',\n qualityAuto: 'Auto',\n next: 'Next',\n nextVideo: 'Next video',\n previous: 'Previous',\n playlist: 'Playlist',\n like: 'Like',\n dislike: 'Dislike',\n addTo: 'Save to…',\n share: 'Share',\n report: 'Report',\n more: 'More actions',\n seekForward: 'Seek forward',\n seekBack: 'Seek back',\n secondsShort: 's',\n live: 'LIVE',\n related: 'More videos',\n adLabel: 'Ad',\n skipAd: 'Skip ad',\n skipAdIn: 'Skip in',\n visitAdvertiser: 'Visit advertiser',\n sponsored: 'Sponsored',\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 // The \"light\" build drops rarely-needed features (alt-audio, subtitles,\n // EME, low-latency) — far smaller than the full build for the common case\n // of plain VOD m3u8. Consumers who need them can provide window.Hls\n // (full build) which is picked up above.\n const mod = await import('hls.js/light')\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 * One row in the settings (gear) drill-down. Either a drill row (label + current\n * value → options) or a toggle row (label + on/off switch).\n */\nexport interface SettingEntry {\n key: string\n label: string\n /** Current value shown on a drill row, e.g. \"Auto\", \"1×\", \"Off\". */\n value?: string\n /** The options panel to drill into when a drill row is clicked. */\n section?(): MenuSection\n /** Present → render a toggle switch instead of a drill row. */\n toggle?: {\n value: boolean\n onChange(next: boolean): void\n }\n}\n\nconst CHEVRON_RIGHT = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"m9 6 6 6-6 6\"/></svg>'\nconst CHEVRON_LEFT = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"m15 6-6 6 6 6\"/></svg>'\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 this.root.append(this.renderSection(section))\n }\n this.reveal()\n }\n\n /** Settings (gear) drill-down: a root list of rows, each opening its options. */\n toggleSettings(title: string, entries: SettingEntry[]): void {\n if (this.open) this.close()\n else this.showSettings(title, entries)\n }\n\n showSettings(_title: string, entries: SettingEntry[]): void {\n this.root.classList.add('imp-menu--wide')\n this.renderSettingsRoot(entries)\n this.reveal()\n }\n\n private renderSettingsRoot(entries: SettingEntry[]): void {\n this.root.textContent = ''\n const block = el('div', 'imp-menu__section')\n for (const entry of entries) {\n if (entry.toggle) {\n block.append(this.buildToggleRow(entry, entry.toggle))\n continue\n }\n const row = el('button', 'imp-menu__item imp-menu__row', { type: 'button' })\n const label = el('span', 'imp-menu__label')\n label.textContent = entry.label\n const value = el('span', 'imp-menu__value')\n value.textContent = entry.value ?? ''\n const chevron = el('span', 'imp-menu__chevron')\n chevron.innerHTML = CHEVRON_RIGHT\n row.append(label, value, chevron)\n row.addEventListener('click', () => this.renderSettingsDetail(entries, entry))\n block.append(row)\n }\n this.root.append(block)\n }\n\n /** Toggle row: label + an on/off switch. Stays in the menu (no close). */\n private buildToggleRow(entry: SettingEntry, toggle: NonNullable<SettingEntry['toggle']>): HTMLElement {\n const row = el('button', 'imp-menu__item imp-menu__row imp-menu__toggle', {\n type: 'button', role: 'switch', 'aria-checked': String(toggle.value),\n })\n const label = el('span', 'imp-menu__label')\n label.textContent = entry.label\n const sw = el('span', 'imp-switch')\n sw.append(el('span', 'imp-switch__knob'))\n row.classList.toggle('imp-menu__toggle--on', toggle.value)\n row.append(label, sw)\n row.addEventListener('click', () => {\n const next = row.getAttribute('aria-checked') !== 'true'\n row.setAttribute('aria-checked', String(next))\n row.classList.toggle('imp-menu__toggle--on', next)\n toggle.onChange(next)\n })\n return row\n }\n\n private renderSettingsDetail(entries: SettingEntry[], entry: SettingEntry): void {\n if (!entry.section) return // toggle rows have no drill-down panel\n this.root.textContent = ''\n const back = el('button', 'imp-menu__item imp-menu__back', { type: 'button' })\n const chevron = el('span', 'imp-menu__chevron')\n chevron.innerHTML = CHEVRON_LEFT\n const label = el('span', 'imp-menu__label')\n label.textContent = entry.label\n back.append(chevron, label)\n back.addEventListener('click', () => this.renderSettingsRoot(entries))\n this.root.append(back)\n this.root.append(this.renderSection(entry.section()))\n this.root.scrollTop = 0\n }\n\n /** Build one option block (radio items) from a section. */\n private renderSection(section: MenuSection): HTMLElement {\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 return block\n }\n\n /** Reveal the populated menu + backdrop and arm the outside-click listener. */\n private reveal(): void {\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.root.classList.remove('imp-menu--wide')\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, previewMetaEl, setIcon } from '../core/dom'\nimport type { Player } from '../player'\nimport type { NextPreviewOptions, SeekLabelFormat, SettingPlacement } from '../types'\nimport { Menu, type MenuSection, type SettingEntry } 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 /** What the ⋯ menu shows in its place — one section, several, or none. */\n section(): MenuSection | 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 private seekLabelFn?: SeekLabelFormat\n /** Right-cluster controls keyed for ordering; appended in `controls.order`. */\n private rightItems = new Map<string, 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 /** Unified ⚙ dropdown holding the settings placed in `\"gear\"`. */\n private gearBtn: HTMLButtonElement | null = null\n private gearMenu: Menu | null = null\n /** Which settings live in the gear menu (vs their own bar button / off). */\n private gear = { speed: false, quality: false, subtitles: false }\n /** Next-up hover preview (desktop). */\n private nextPreviewEl: HTMLElement | null = null\n private nextPreviewOpts: Required<NextPreviewOptions> | null = null\n private scenesBtn: HTMLButtonElement | null = null\n private sceneTypeBtn: HTMLButtonElement | null = null\n private sceneTypeMenu: Menu | 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\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 this.seekLabelFn = seekCfg.label\n\n // --- left cluster: prev · −Ns · play · +Ns · next · volume · time ---\n // The bar prev button is opt-in (hidePrev defaults true → bar shows only\n // next). The mobile center cluster still gets its own prev regardless.\n if (c.playlist && player.hasPlaylist && !c.hidePrev) {\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.addStepBadge(this.seekBackBtn, seekBack, 'back')\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.addStepBadge(this.seekFwdBtn, seekFwd, 'forward')\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()\n\n // Consumer actions placed directly in the bar (icon button, tooltip = title).\n for (const ca of (player.actionsOptions.custom ?? []).filter((a) => a.placement === 'bar')) {\n const btn = iconButton(`imp-btn--custom imp-btn--custom-${ca.id}`, ca.title, ca.icon ?? icons.more)\n btn.addEventListener('click', () => player.emit('customaction', { id: ca.id }))\n this.rightItems.set(`custom:${ca.id}`, btn)\n this.registerCollapsible({\n key: `custom:${ca.id}`, el: btn, priority: 55, available: () => true,\n section: () => this.simpleSection(`custom:${ca.id}`, ca.title, ca.icon ?? icons.more, () => player.emit('customaction', { id: ca.id })),\n })\n }\n\n // Settings placement: subtitles / quality / speed each live in the gear\n // dropdown ('gear', default), as their own bar button ('bar'), or off.\n const place = (v: SettingPlacement | undefined): 'gear' | 'bar' | 'off' =>\n v === false ? 'off' : v === 'bar' ? 'bar' : 'gear'\n const subsPlace = place(c.subtitles)\n const qualityPlace = place(c.quality)\n const speedPlace = place(c.speed)\n this.gear = { speed: speedPlace === 'gear', quality: qualityPlace === 'gear', subtitles: subsPlace === 'gear' }\n\n // Standalone (bar) settings buttons — only when explicitly pulled out.\n if (subsPlace === 'bar') {\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 this.rightItems.set('subtitles', wrap)\n this.registerCollapsible({\n key: 'subtitles', el: wrap, priority: 30,\n available: () => player.subtitleTracks.length > 0,\n section: () => this.subtitlesSection(),\n })\n }\n if (qualityPlace === 'bar') {\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 this.rightItems.set('quality', wrap)\n this.registerCollapsible({\n key: 'quality', el: wrap, priority: 10,\n available: () => player.qualityLevels.length > 0,\n section: () => this.qualitySection(),\n })\n }\n if (speedPlace === 'bar') {\n this.settingsBtn = iconButton('imp-btn--speed', labels.speed, 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 this.rightItems.set('speed', wrap)\n this.registerCollapsible({\n key: 'speed', el: wrap, priority: 40,\n available: () => true,\n section: () => this.speedSection(),\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 this.rightItems.set('scenes', 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 // Scene-type selector (icon + current type label, dropdown). Visible only\n // when the source carries typed scene groups.\n if (c.sceneTypes !== false) {\n this.sceneTypeBtn = el('button', 'imp-btn imp-btn--scene-types', { type: 'button' })\n this.sceneTypeMenu = new Menu(this.sceneTypeBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.sceneTypeBtn, this.sceneTypeMenu.root)\n this.sceneTypeBtn.addEventListener('click', () => this.toggleSceneTypeMenu())\n this.rightItems.set('sceneTypes', wrap)\n this.refreshSceneTypeButton()\n this.registerCollapsible({\n key: 'sceneTypes', el: wrap, priority: 26,\n available: () => player.sceneTypes.length > 0,\n section: () => this.sceneTypeSection(),\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 this.rightItems.set('playlist', 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 this.rightItems.set('pip', 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 this.rightItems.set('fullscreen', 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 this.addStepBadge(b, seekBack, 'back')\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 this.addStepBadge(f, seekFwd, 'forward')\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 // Next-up hover preview (desktop). Wired to whichever next buttons exist.\n this.setupNextPreview()\n\n // Unified ⚙ dropdown — placed immediately left of the ⋯ button. Holds\n // whatever is set to 'gear'; hidden entirely when it has no available\n // section (handled by `available()`).\n if (this.gear.speed || this.gear.quality || this.gear.subtitles) {\n this.gearBtn = iconButton('imp-btn--settings', labels.settings, icons.settings)\n this.gearMenu = new Menu(this.gearBtn)\n const wrap = el('div', 'imp-controls__menu-anchor')\n wrap.append(this.gearBtn, this.gearMenu.root)\n this.gearBtn.addEventListener('click', () => this.toggleGearMenu())\n this.rightItems.set('gear', wrap)\n this.registerCollapsible({\n key: 'gear', el: wrap, priority: 40,\n available: () => this.gearSections().length > 0,\n section: () => this.gearSections(),\n })\n }\n\n // Append the right-cluster controls in the configured (or built-in) order.\n this.layoutRightCluster(right)\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 /**\n * Append the right-cluster controls. Built-in order = creation order; if\n * `controls.order` is set, its keys go first (in that order), then any\n * unlisted controls keep their default position. (⋯ is appended separately.)\n */\n private layoutRightCluster(right: HTMLElement): void {\n const insertion = [...this.rightItems.keys()]\n const requested = this.player.controlsOptions.order as string[]\n let keys = insertion\n if (requested.length > 0) {\n const seen = new Set<string>()\n keys = []\n for (const k of requested) {\n if (this.rightItems.has(k) && !seen.has(k)) {\n keys.push(k)\n seen.add(k)\n }\n }\n for (const k of insertion) if (!seen.has(k)) keys.push(k)\n }\n for (const k of keys) {\n const node = this.rightItems.get(k)\n if (node) right.append(node)\n }\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 /** Caption under the seek arrow. Default \"−15s\"/\"+15s\"; overridable via `controls.seekButtons.label`. */\n private addStepBadge(btn: HTMLButtonElement, step: number, dir: 'back' | 'forward'): void {\n const num = el('span', 'imp-seek-num')\n num.textContent = this.seekLabelFn\n ? this.seekLabelFn(step, dir)\n : `${dir === 'back' ? '−' : '+'}${step}${this.player.labels.secondsShort}`\n btn.append(num)\n }\n\n // === gear (unified settings) ==========================================\n\n /** Sections for the gear when overflowed into ⋯ (expanded, no drill-down). */\n private gearSections(): MenuSection[] {\n const p = this.player\n const out: MenuSection[] = []\n if (this.gear.quality && p.qualityLevels.length > 0) out.push(this.qualitySection())\n if (this.gear.speed) out.push(this.speedSection())\n if (this.gear.subtitles && p.subtitleTracks.length > 0) out.push(this.subtitlesSection())\n return out\n }\n\n /** Gear drill-down rows: one per setting, each showing its current value. */\n private gearEntries(): SettingEntry[] {\n const p = this.player\n const out: SettingEntry[] = []\n // Autoplay toggle — only meaningful with a playlist (next item to advance to).\n if (p.hasPlaylist) {\n out.push({\n key: 'autoplay',\n label: p.labels.autoplay,\n toggle: { value: p.autoAdvance, onChange: (v) => p.setAutoAdvance(v) },\n })\n }\n if (this.gear.quality && p.qualityLevels.length > 0) {\n const value = p.currentQuality === -1\n ? p.labels.qualityAuto\n : p.qualityLevels.find((l) => l.index === p.currentQuality)?.label ?? p.labels.qualityAuto\n out.push({ key: 'quality', label: p.labels.quality, value, section: () => this.qualitySection() })\n }\n if (this.gear.speed) {\n const r = p.playbackRate\n out.push({ key: 'speed', label: p.labels.speed, value: r === 1 ? '1×' : `${r}×`, section: () => this.speedSection() })\n }\n if (this.gear.subtitles && p.subtitleTracks.length > 0) {\n const value = p.activeSubtitle === -1\n ? p.labels.subtitlesOff\n : p.subtitleTracks[p.activeSubtitle]?.label ?? p.labels.subtitlesOff\n out.push({ key: 'subtitles', label: p.labels.subtitles, value, section: () => this.subtitlesSection() })\n }\n return out\n }\n\n // === scene types ======================================================\n\n /** Update the scene-type button to the active group's icon + title. */\n private refreshSceneTypeButton(): void {\n const btn = this.sceneTypeBtn\n if (!btn) return\n const active = this.player.activeSceneType\n btn.textContent = ''\n if (!active) return\n if (active.icon) {\n const iconBox = el('span', 'imp-scene-type__icon')\n if (active.icon.trimStart().startsWith('<svg')) iconBox.innerHTML = active.icon\n else iconBox.append(el('img', '', { src: active.icon, alt: '' }))\n btn.append(iconBox)\n }\n const label = el('span', 'imp-scene-type__label')\n label.textContent = active.title\n btn.append(label)\n btn.setAttribute('aria-label', `${this.player.labels.sceneTypes}: ${active.title}`)\n btn.title = active.title\n }\n\n private sceneTypeSection(): MenuSection {\n const p = this.player\n return {\n title: p.labels.sceneTypes,\n items: p.sceneTypes.map((g) => ({\n label: g.title,\n value: g.id,\n icon: g.icon,\n active: g.id === (p.activeSceneType?.id ?? ''),\n })),\n onSelect: (value) => {\n p.setSceneGroup(value)\n this.refreshSceneTypeButton()\n },\n }\n }\n\n private toggleSceneTypeMenu(): void {\n if (!this.sceneTypeMenu || this.player.sceneTypes.length === 0) return\n this.closeMenus(this.sceneTypeMenu)\n this.sceneTypeMenu.toggle([this.sceneTypeSection()])\n }\n\n private toggleGearMenu(): void {\n if (!this.gearMenu) return\n const entries = this.gearEntries()\n if (entries.length === 0) return\n this.closeMenus(this.gearMenu)\n this.gearMenu.toggleSettings(this.player.labels.settings, entries)\n }\n\n // === next-up hover preview ============================================\n\n private setupNextPreview(): void {\n const p = this.player\n const c = p.controlsOptions\n if (c.nextPreview === false || !c.playlist || !p.hasPlaylist) return\n const o = typeof c.nextPreview === 'object' ? c.nextPreview : {}\n this.nextPreviewOpts = {\n thumbnail: o.thumbnail ?? true,\n title: o.title ?? true,\n duration: o.duration ?? true,\n meta: o.meta ?? true,\n }\n this.nextPreviewEl = el('div', 'imp-next-preview')\n this.nextPreviewEl.hidden = true\n p.container.append(this.nextPreviewEl)\n if (this.nextBtn) this.bindNextPreview(this.nextBtn)\n if (this.centerNextBtn) this.bindNextPreview(this.centerNextBtn)\n }\n\n private bindNextPreview(btn: HTMLButtonElement): void {\n // Mouse only — touch has no hover, and a tap should just go to the next item.\n btn.addEventListener('pointerenter', (e) => {\n if (e.pointerType === 'mouse') this.showNextPreview(btn)\n })\n btn.addEventListener('pointerleave', () => this.hideNextPreview())\n btn.addEventListener('click', () => this.hideNextPreview())\n }\n\n private showNextPreview(btn: HTMLButtonElement): void {\n const card = this.nextPreviewEl\n const opts = this.nextPreviewOpts\n if (!card || !opts) return\n const src = this.player.nextSource\n if (!src) return\n\n card.textContent = ''\n const kicker = el('div', 'imp-next-preview__kicker')\n kicker.textContent = this.player.labels.next\n card.append(kicker)\n\n if (opts.thumbnail && src.poster) {\n const thumb = el('div', 'imp-next-preview__thumb')\n thumb.style.backgroundImage = `url(\"${src.poster}\")`\n if (opts.duration && src.duration) {\n const d = el('span', 'imp-next-preview__duration')\n d.textContent = formatTime(src.duration)\n thumb.append(d)\n }\n card.append(thumb)\n }\n if (opts.title && src.title) {\n const t = el('div', 'imp-next-preview__title')\n t.textContent = src.title\n card.append(t)\n }\n if (opts.meta && src.previewMeta?.length) {\n card.append(previewMetaEl(src.previewMeta, 'imp-next-preview'))\n }\n\n // Anchor centered above the hovered button, then clamp inside the player so\n // the card never spills past (and gets clipped by) the player edges.\n card.hidden = false\n const cr = this.player.container.getBoundingClientRect()\n const r = btn.getBoundingClientRect()\n const pad = 8\n const cardW = card.offsetWidth\n const centered = r.left - cr.left + r.width / 2 - cardW / 2\n const left = Math.max(pad, Math.min(centered, cr.width - cardW - pad))\n card.style.left = `${left}px`\n card.style.bottom = `${cr.height - (r.top - cr.top) + 10}px`\n }\n\n private hideNextPreview(): void {\n if (this.nextPreviewEl) this.nextPreviewEl.hidden = true\n }\n\n /** like/dislike — visible buttons (collapsible), highlightable via `setLikeState`. */\n private buildLikeDislike(): 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 this.rightItems.set('like', 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 this.rightItems.set('dislike', 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 // Bar-placed custom actions render as their own buttons; only menu ones here.\n for (const custom of (a.custom ?? []).filter((ca) => ca.placement !== 'bar')) {\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', 'sceneTypes', 'pip', 'list', 'subtitles', 'speed', 'quality', 'gear']\n const rank = (key: string) => {\n const i = order.indexOf(key)\n return i === -1 ? order.length : i // custom:* etc. sort after known keys\n }\n const overflowedSorted = this.collapsibles\n .filter((c) => this.overflowed.has(c.key) && c.available())\n .sort((a, b) => rank(a.key) - rank(b.key))\n\n for (const c of overflowedSorted) {\n const result = c.section()\n if (!result) continue\n // A collapsible may contribute one section or several (the gear menu).\n for (const section of Array.isArray(result) ? result : [result]) {\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 }\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 // The seek ±N (and center play) live over the video when seekPlacement is\n // 'overlay' (default, every viewport) or always on mobile. In 'bar' mode on\n // desktop they stay in the bottom bar instead.\n const overlay = this.player.controlsOptions.seekPlacement !== 'bar'\n const useCenter = overlay || compact\n this.center.style.display = useCenter ? 'flex' : 'none'\n\n // prev/next sit in the center cluster ONLY on mobile; on desktop they live\n // in the bottom bar next to the bar play button. Seek ±N and the center\n // play show whenever the cluster is visible.\n if (this.centerPrevBtn) this.centerPrevBtn.style.display = compact ? '' : 'none'\n if (this.centerNextBtn) this.centerNextBtn.style.display = compact ? '' : 'none'\n\n // Bar play/pause: shown on desktop (with prev/next), hidden on mobile where\n // the center cluster owns playback.\n if (this.playBtn) this.playBtn.style.display = compact ? 'none' : ''\n\n // Which bar buttons are currently relocated into the center cluster:\n // - seek ±N → whenever the cluster is used (overlay desktop or mobile);\n // - prev/next → mobile only.\n const inCenter = (key: string): boolean => {\n if (key === 'seekBack' || key === 'seekFwd') return useCenter\n if (key === 'prev' || key === 'next') return compact\n return false\n }\n\n // Reset: availability first, clear forced-overflow hides.\n this.overflowed.clear()\n for (const c of this.collapsibles) {\n if (inCenter(c.key)) {\n // Relocated into the center cluster — hide its bottom-bar twin.\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() && !inCenter(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.refreshSceneTypeButton()\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.gearMenu, this.settingsMenu, this.subtitlesMenu, this.qualityMenu, this.sceneTypeMenu, 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.gearMenu?.destroy()\n this.sceneTypeMenu?.destroy()\n this.settingsMenu?.destroy()\n this.subtitlesMenu?.destroy()\n this.qualityMenu?.destroy()\n this.moreMenu?.destroy()\n this.nextPreviewEl?.remove()\n this.root.remove()\n }\n}\n","import { el, formatTime, iconButton, previewMetaEl } 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 /** A real <img> (not a background) so it can be the LCP element the browser prioritizes. */\n private image: HTMLImageElement\n\n constructor(player: Player) {\n this.root = el('div', 'imp-poster')\n this.image = el('img', 'imp-poster__image', { alt: '', decoding: 'async' }) as HTMLImageElement\n this.image.hidden = true\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 if (source?.poster) {\n this.image.src = source.poster\n // First poster is the page's hero — hint the browser to load it eagerly.\n this.image.fetchPriority = 'high'\n this.image.hidden = false\n } else {\n this.image.removeAttribute('src')\n this.image.hidden = true\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/**\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 /** Which parts the consumer allows (a hidden part stays hidden even with data). */\n private visible = { title: true, description: true, sponsor: true }\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 ABOVE the title (the promo slot comes first),\n // shown only when set on the source.\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 // Order on the overlay: sponsor (ad link) → title → description.\n heading.append(this.sponsor, this.title, this.description)\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 /** Hide specific parts of the default overlay (consumer renders them itself). */\n setVisibility(parts: { title?: boolean; description?: boolean; sponsor?: boolean }): void {\n this.visible = {\n title: parts.title ?? this.visible.title,\n description: parts.description ?? this.visible.description,\n sponsor: parts.sponsor ?? this.visible.sponsor,\n }\n }\n\n setSource(source: VideoSource | null): void {\n this.title.textContent = source?.title ?? ''\n this.description.textContent = source?.description ?? ''\n this.title.hidden = !this.visible.title || !source?.title\n this.description.hidden = !this.visible.description || !source?.description\n\n // Sponsor link — only for sponsored videos (i.e. when provided) and allowed.\n const sponsor = this.visible.sponsor ? source?.sponsor : undefined\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 private clickBehavior: NonNullable<RelatedOptions['clickBehavior']> = 'player'\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.clickBehavior = options.clickBehavior ?? 'player'\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 // The event always fires — consumers can fully drive navigation themselves.\n this.player.emit('relatedclick', { item })\n this.hide()\n this.activate(item)\n })\n return card\n }\n\n /** Apply the configured click behavior. */\n private activate(item: RelatedItem): void {\n const url = item.url ?? item.source?.src\n switch (this.clickBehavior) {\n case 'newWindow':\n if (url) window.open(url, '_blank', 'noopener')\n break\n case 'currentTab':\n if (url) window.location.href = url\n break\n case 'player':\n default:\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 }\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\n/**\n * End-of-video \"up next\" overlay shown when autoplay is OFF and a next item\n * exists: a preview card of the next video + a \"Play next\" button.\n */\nexport class UpNextOverlay {\n readonly root: HTMLElement\n\n constructor(private player: Player) {\n this.root = el('div', 'imp-upnext')\n this.root.hidden = true\n }\n\n get visible(): boolean {\n return !this.root.hidden\n }\n\n show(): void {\n const src = this.player.nextSource\n if (!src) return\n const { labels } = this.player\n\n this.root.textContent = ''\n const card = el('div', 'imp-upnext__card')\n\n const kicker = el('div', 'imp-upnext__kicker')\n kicker.textContent = labels.nextVideo\n card.append(kicker)\n\n if (src.poster) {\n const thumb = el('button', 'imp-upnext__thumb', { type: 'button', 'aria-label': labels.playNext })\n thumb.style.backgroundImage = `url(\"${src.poster}\")`\n if (src.duration) {\n const dur = el('span', 'imp-upnext__duration')\n dur.textContent = formatTime(src.duration)\n thumb.append(dur)\n }\n const play = el('span', 'imp-upnext__thumb-play')\n play.innerHTML = this.player.icons.bigPlay\n thumb.append(play)\n thumb.addEventListener('click', () => this.player.next())\n card.append(thumb)\n }\n\n if (src.title) {\n const title = el('div', 'imp-upnext__title')\n title.textContent = src.title\n card.append(title)\n }\n if (src.previewMeta?.length) {\n card.append(previewMetaEl(src.previewMeta, 'imp-upnext'))\n }\n\n const btn = el('button', 'imp-upnext__btn', { type: 'button' })\n btn.textContent = labels.playNext\n btn.addEventListener('click', () => this.player.next())\n card.append(btn)\n\n this.root.append(card)\n this.root.hidden = false\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 // Mobile full-cover sheet: close on pick so the video shows at once.\n if (window.innerWidth <= 767) this.hide()\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 // On mobile the panel is a full-cover sheet — close it so the chosen\n // scene is visible immediately (no manual close). Desktop sidebar/strip\n // stays open: the video is visible alongside it.\n if (window.innerWidth <= 767) this.hide()\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, UpNextOverlay } 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 SceneGroup,\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-type controls default into the unified ⚙ dropdown.\n speed: 'gear',\n settings: 'gear', // legacy alias for `speed`; resolved in the constructor\n quality: 'gear',\n scenes: true,\n sceneTypes: true,\n heatmap: true,\n subtitles: 'gear',\n seekButtons: true,\n // Prev/seek/play/next as a centered overlay on every viewport.\n seekPlacement: 'overlay',\n order: [], // empty → built-in right-cluster order\n playlist: true,\n hidePrev: true,\n nextPreview: 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 /** Typed scene breakdowns; the active one drives `chapters`. */\n private sceneGroupList: SceneGroup[] = []\n private activeSceneGroupId = ''\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 upNext: UpNextOverlay\n /** Runtime autoplay-next toggle (gear switch); seeds from playlist.autoAdvance. */\n private autoAdvanceEnabled = true\n /** localStorage key for persisted prefs, or null when persistence is off. */\n private persistKey: string | null = null\n private persistVolume = false\n private persistAutoAdvance = false\n private playlistPanel: PlaylistPanel\n private scenesPanel: ScenesPanel\n private spinner: HTMLElement\n private errorBox!: HTMLElement\n private decodeRecoveries = 0\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 // Resolve the deprecated `settings` alias from the raw options (an explicit\n // `speed` wins; else legacy `settings`; else the 'gear' default).\n const rawControls = options.controls ?? {}\n const speed = rawControls.speed ?? rawControls.settings ?? 'gear'\n this.controlsOptions = { ...defaultControls, ...rawControls, speed, settings: speed }\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 ?? 15\n this.playlistOptions = { title: '', autoAdvance: true, loop: false, shuffle: false, startIndex: 0, layout: 'sidebar', ...options.playlist }\n this.shuffleMode = this.playlistOptions.shuffle\n\n // Persistence: set up before applying volume/autoAdvance so saved prefs win.\n if (options.persist) {\n const p = options.persist === true ? {} : options.persist\n this.persistKey = p.key ?? 'itube-player'\n this.persistVolume = p.volume !== false\n this.persistAutoAdvance = p.autoAdvance !== false\n }\n const saved = this.readPersisted()\n\n this.autoAdvanceEnabled = this.persistAutoAdvance && typeof saved?.autoAdvance === 'boolean'\n ? saved.autoAdvance\n : this.playlistOptions.autoAdvance\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 const styling = options.styling\n if (styling?.themeColor) this.container.style.setProperty('--imp-accent', styling.themeColor)\n if (styling?.likeColor) this.container.style.setProperty('--imp-like', styling.likeColor)\n if (styling?.dislikeColor) this.container.style.setProperty('--imp-dislike', styling.dislikeColor)\n if (styling?.borderRadius !== undefined) {\n const r = typeof styling.borderRadius === 'number' ? `${styling.borderRadius}px` : styling.borderRadius\n this.container.style.setProperty('--imp-radius', r)\n }\n if (styling?.playButtonStyle === 'inverted') this.container.classList.add('imp-player--play-inverted')\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 const savedAV = this.persistVolume ? saved : null\n this.video.volume = clamp(savedAV?.volume ?? options.volume ?? 1, 0, 1)\n if (savedAV?.muted ?? options.muted) this.video.muted = true\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.upNext = new UpNextOverlay(this)\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, this.upNext.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 } else if (options.pauseScreen && typeof options.pauseScreen === 'object') {\n // Plain config object: default overlay with some parts hidden.\n this.pauseScreen.setVisibility(options.pauseScreen)\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 // Tap/click on the video surface. Desktop (mouse): toggles playback, as\n // before. Touch (phones): a tap toggles *controls* visibility instead —\n // play/pause lives on the on-screen center button. This is the standard\n // mobile model and avoids the iOS problem where one tap fired both a\n // play-toggle (click) and a show-controls (pointerdown) at once.\n // We use pointerup (not click) so iOS doesn't also deliver a synthesized\n // mouse click that double-fires the handler.\n this.video.addEventListener('pointerup', (e) => {\n if (this.adPlaying || !this.playedOnce) return\n if (e.pointerType === 'mouse') {\n this.togglePlay()\n return\n }\n // Touch / pen: reveal controls if hidden, hide them if shown while\n // playing. When paused the controls (and pause screen) stay up.\n if (this.container.classList.contains('imp-player--idle')) {\n this.showControlsNow()\n this.scheduleIdle()\n } else if (!this.video.paused) {\n this.container.classList.add('imp-player--idle')\n }\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 // === persistence ======================================================\n\n /** Read persisted prefs (safe against private mode / SSR / bad JSON). */\n private readPersisted(): { volume?: number; muted?: boolean; autoAdvance?: boolean } | null {\n if (!this.persistKey) return null\n try {\n const raw = localStorage.getItem(this.persistKey)\n const data = raw ? JSON.parse(raw) : null\n return data && typeof data === 'object' ? data : null\n } catch {\n return null\n }\n }\n\n /** Write the enabled prefs to localStorage. No-op when persistence is off. */\n private persistState(): void {\n if (!this.persistKey) return\n try {\n const data: { volume?: number; muted?: boolean; autoAdvance?: boolean } = {}\n if (this.persistVolume) {\n data.volume = this.video.volume\n data.muted = this.video.muted\n }\n if (this.persistAutoAdvance) data.autoAdvance = this.autoAdvanceEnabled\n localStorage.setItem(this.persistKey, JSON.stringify(data))\n } catch {\n // private mode / quota / SSR — persistence is best-effort.\n }\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 /**\n * The item that `next()` would play in linear order (for the next-up preview).\n * `null` in shuffle mode (the pick is random) or when there is no next item.\n */\n get nextSource(): VideoSource | null {\n if (this.shuffleMode || this.sources.length < 2) return null\n const i = this.currentIndex + 1\n if (i < this.sources.length) return this.sources[i]\n return this.playlistOptions.loop ? this.sources[0] ?? null : 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 // === scene types (groups) =============================================\n\n /** Typed scene breakdowns attached to the current source (may be empty). */\n get sceneTypes(): SceneGroup[] {\n return this.sceneGroupList\n }\n\n /** Currently selected scene type, or null when there are no groups. */\n get activeSceneType(): SceneGroup | null {\n return this.sceneGroupList.find((g) => g.id === this.activeSceneGroupId) ?? null\n }\n\n /** Switch the active scene type — rebuilds the timeline segments + scenes panel. */\n setSceneGroup(id: string): void {\n if (id === this.activeSceneGroupId || !this.sceneGroupList.some((g) => g.id === id)) return\n this.activeSceneGroupId = id\n this.applyActiveSceneGroup()\n this.emitter.emit('scenetypechange', { group: this.activeSceneType })\n }\n\n /** Normalize the active group's scenes into `chapters` and refresh the UI. */\n private applyActiveSceneGroup(): void {\n this.chapters = normalizeChapters(this.activeSceneType?.scenes ?? [], this.video.duration)\n this.currentChapter = null\n this.controls.progress.setChapters(this.chapters)\n this.controls.syncFeatureButtons()\n if (this.scenesPanel.visible) this.scenesPanel.rebuild()\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.sceneGroupList = []\n this.activeSceneGroupId = ''\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.upNext.hide()\n this.pauseScreen.hide()\n this.scenesPanel.hide()\n this.thumbTrack = null\n this.errorBox.hidden = true\n this.decodeRecoveries = 0\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.sceneGroups && source.sceneGroups.length > 0) {\n // Typed scene breakdowns: pick the first group, build the timeline from it.\n this.sceneGroupList = source.sceneGroups\n this.activeSceneGroupId = source.sceneGroups[0].id\n const set = () => {\n if (token !== this.loadToken) return\n this.applyActiveSceneGroup()\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 } else 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.upNext.hide()\n // Playback requested but not enough buffered yet (e.g. switching to the\n // next playlist item on a slow connection): show the loader instead of a\n // frozen poster. 'playing' hides it once real frames arrive.\n if (v.readyState < 3 /* HAVE_FUTURE_DATA */) this.spinner.hidden = false\n this.emitter.emit('play', undefined)\n this.scheduleIdle()\n }, { signal })\n\n v.addEventListener('pause', () => {\n this.spinner.hidden = true\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 if (this.persistVolume) this.persistState()\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 // Playback recovered — clear any stale error overlay and the recovery counter.\n this.errorBox.hidden = true\n this.decodeRecoveries = 0\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) return\n\n // Native playback (incl. Safari/iOS HLS) can throw transient decode/parse\n // errors when seeking backward (DEMUXER_ERROR_COULD_NOT_PARSE). Try a\n // silent reload-and-restore a couple of times before surfacing an error.\n const decodeish = mediaError.code === MediaError.MEDIA_ERR_DECODE || /DEMUXER|PARSE|DECODE/i.test(mediaError.message || '')\n if (decodeish && this.decodeRecoveries < 2 && Number.isFinite(v.duration)) {\n this.decodeRecoveries++\n const at = v.currentTime\n const wasPlaying = !v.paused\n v.load()\n const restore = () => {\n try { v.currentTime = at } catch { /* range not ready yet */ }\n if (wasPlaying) void v.play().catch(() => {})\n }\n v.readyState >= 1 ? restore() : v.addEventListener('loadedmetadata', restore, { once: true, signal: this.abort.signal })\n return\n }\n\n this.emitter.emit('error', { message: mediaError.message || `Media error (code ${mediaError.code})`, cause: mediaError })\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.autoAdvanceEnabled && this.hasNext) {\n this.next()\n return\n }\n // Autoplay off: offer the next item with a \"play next\" card instead.\n if (!this.autoAdvanceEnabled && this.hasNext) {\n this.upNext.show()\n return\n }\n if (this.options.related?.showOn?.includes('ended') ?? Boolean(this.options.related)) {\n this.related.show()\n }\n }\n\n /** Autoplay-next state (gear switch). Off → show the up-next card on end. */\n get autoAdvance(): boolean {\n return this.autoAdvanceEnabled\n }\n\n setAutoAdvance(on: boolean): void {\n this.autoAdvanceEnabled = on\n if (on) this.upNext.hide()\n if (this.persistAutoAdvance) this.persistState()\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 // Mouse/keyboard reveal-on-activity. Touch is deliberately excluded here:\n // a tap is handled by the pointerup tap-toggle on the video, so letting\n // pointerdown also fire reset() would make one tap both show *and* (via the\n // tap handler) hide the controls — they'd never actually toggle.\n this.container.addEventListener('pointermove', (e) => {\n if (e.pointerType !== 'touch') reset()\n }, { signal })\n this.container.addEventListener('pointerdown', (e) => {\n if (e.pointerType !== 'touch') reset()\n }, { signal })\n this.container.addEventListener('keydown', reset, { signal })\n this.container.addEventListener('pointerleave', (e) => {\n if (e.pointerType === 'touch') return\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","/**\n * Entry for the standalone IIFE bundle (script-tag usage, no bundler):\n *\n * ```html\n * <link rel=\"stylesheet\" href=\"https://unpkg.com/itube-modern-player/dist/style.css\">\n * <!-- only needed for m3u8 sources: -->\n * <script src=\"https://unpkg.com/hls.js\"></script>\n * <script src=\"https://unpkg.com/itube-modern-player/dist/itube-modern-player.iife.js\"></script>\n * <script>\n * const player = new ITubePlayer('#mount', { source: { src: 'video.mp4' } })\n * </script>\n * ```\n */\nimport { Player, registerLocales } from './coreEntry'\nimport { locales } from './core/locales'\n\n// Register built-ins here, in the entry module itself — side effects of an\n// entry are never tree-shaken, unlike a re-exporting intermediate module.\nregisterLocales(locales)\n\nexport default Player\n","import type { LocaleCode, PlayerLabels } from '../types'\nimport { defaultLabels } from './labels'\n\n/**\n * Built-in static locales. Pick one with `options.language`; any individual\n * string can still be overridden via `options.labels`.\n *\n * The canonical term list is the `PlayerLabels` interface — `defaultLabels`\n * (English) is exported as the reference dictionary for translators.\n */\nexport const locales: Record<LocaleCode, PlayerLabels> = {\n en: defaultLabels,\n\n ru: {\n play: 'Воспроизвести',\n pause: 'Пауза',\n replay: 'Смотреть снова',\n mute: 'Выключить звук',\n unmute: 'Включить звук',\n fullscreen: 'Во весь экран',\n exitFullscreen: 'Выйти из полноэкранного режима',\n pip: 'Картинка в картинке',\n settings: 'Скорость воспроизведения',\n subtitles: 'Субтитры',\n subtitlesOff: 'Выкл.',\n speed: 'Скорость',\n quality: 'Качество',\n qualityAuto: 'Авто',\n next: 'Следующее',\n nextVideo: 'Следующее видео',\n previous: 'Предыдущее',\n playlist: 'Плейлист',\n scenes: 'Сцены',\n sceneTypes: 'Тип сцен',\n autoplay: 'Автовоспроизведение',\n playNext: 'Играть дальше',\n shuffle: 'Перемешать',\n repeat: 'Повтор',\n like: 'Нравится',\n dislike: 'Не нравится',\n addTo: 'Сохранить в…',\n share: 'Поделиться',\n report: 'Пожаловаться',\n more: 'Ещё',\n seekForward: 'Перемотать вперёд',\n seekBack: 'Перемотать назад',\n secondsShort: 'с',\n live: 'В ЭФИРЕ',\n related: 'Похожие видео',\n adLabel: 'Реклама',\n skipAd: 'Пропустить рекламу',\n skipAdIn: 'Пропуск через',\n visitAdvertiser: 'Перейти к рекламодателю',\n sponsored: 'Спонсор',\n },\n\n de: {\n play: 'Wiedergabe',\n pause: 'Pause',\n replay: 'Erneut abspielen',\n mute: 'Stummschalten',\n unmute: 'Ton einschalten',\n fullscreen: 'Vollbild',\n exitFullscreen: 'Vollbild beenden',\n pip: 'Bild im Bild',\n settings: 'Wiedergabegeschwindigkeit',\n subtitles: 'Untertitel',\n subtitlesOff: 'Aus',\n speed: 'Geschwindigkeit',\n quality: 'Qualität',\n qualityAuto: 'Automatisch',\n next: 'Weiter',\n nextVideo: 'Nächstes Video',\n previous: 'Zurück',\n playlist: 'Playlist',\n scenes: 'Szenen',\n sceneTypes: 'Szenentyp',\n autoplay: 'Autoplay',\n playNext: 'Weiter abspielen',\n shuffle: 'Zufallswiedergabe',\n repeat: 'Wiederholen',\n like: 'Mag ich',\n dislike: 'Mag ich nicht',\n addTo: 'Speichern in…',\n share: 'Teilen',\n report: 'Melden',\n more: 'Weitere Aktionen',\n seekForward: 'Vorspulen',\n seekBack: 'Zurückspulen',\n secondsShort: 's',\n live: 'LIVE',\n related: 'Weitere Videos',\n adLabel: 'Anzeige',\n skipAd: 'Werbung überspringen',\n skipAdIn: 'Überspringen in',\n visitAdvertiser: 'Zum Werbetreibenden',\n sponsored: 'Gesponsert',\n },\n\n es: {\n play: 'Reproducir',\n pause: 'Pausa',\n replay: 'Volver a reproducir',\n mute: 'Silenciar',\n unmute: 'Activar sonido',\n fullscreen: 'Pantalla completa',\n exitFullscreen: 'Salir de pantalla completa',\n pip: 'Imagen en imagen',\n settings: 'Velocidad de reproducción',\n subtitles: 'Subtítulos',\n subtitlesOff: 'Desactivados',\n speed: 'Velocidad',\n quality: 'Calidad',\n qualityAuto: 'Automática',\n next: 'Siguiente',\n nextVideo: 'Siguiente vídeo',\n previous: 'Anterior',\n playlist: 'Lista de reproducción',\n scenes: 'Escenas',\n sceneTypes: 'Tipo de escena',\n autoplay: 'Reproducción automática',\n playNext: 'Reproducir siguiente',\n shuffle: 'Aleatorio',\n repeat: 'Repetir',\n like: 'Me gusta',\n dislike: 'No me gusta',\n addTo: 'Guardar en…',\n share: 'Compartir',\n report: 'Denunciar',\n more: 'Más acciones',\n seekForward: 'Avanzar',\n seekBack: 'Retroceder',\n secondsShort: 's',\n live: 'EN VIVO',\n related: 'Más vídeos',\n adLabel: 'Anuncio',\n skipAd: 'Omitir anuncio',\n skipAdIn: 'Omitir en',\n visitAdvertiser: 'Visitar al anunciante',\n sponsored: 'Patrocinado',\n },\n\n it: {\n play: 'Riproduci',\n pause: 'Pausa',\n replay: 'Riproduci di nuovo',\n mute: 'Disattiva audio',\n unmute: 'Attiva audio',\n fullscreen: 'Schermo intero',\n exitFullscreen: 'Esci da schermo intero',\n pip: 'Picture-in-picture',\n settings: 'Velocità di riproduzione',\n subtitles: 'Sottotitoli',\n subtitlesOff: 'Disattivati',\n speed: 'Velocità',\n quality: 'Qualità',\n qualityAuto: 'Automatica',\n next: 'Successivo',\n nextVideo: 'Prossimo video',\n previous: 'Precedente',\n playlist: 'Playlist',\n scenes: 'Scene',\n sceneTypes: 'Tipo di scena',\n autoplay: 'Riproduzione automatica',\n playNext: 'Riproduci successivo',\n shuffle: 'Casuale',\n repeat: 'Ripeti',\n like: 'Mi piace',\n dislike: 'Non mi piace',\n addTo: 'Salva in…',\n share: 'Condividi',\n report: 'Segnala',\n more: 'Altre azioni',\n seekForward: 'Avanti veloce',\n seekBack: 'Indietro',\n secondsShort: 's',\n live: 'LIVE',\n related: 'Altri video',\n adLabel: 'Annuncio',\n skipAd: 'Salta annuncio',\n skipAdIn: 'Salta tra',\n visitAdvertiser: \"Visita l'inserzionista\",\n sponsored: 'Sponsorizzato',\n },\n\n ja: {\n play: '再生',\n pause: '一時停止',\n replay: 'もう一度見る',\n mute: 'ミュート',\n unmute: 'ミュート解除',\n fullscreen: '全画面',\n exitFullscreen: '全画面を終了',\n pip: 'ピクチャーインピクチャー',\n settings: '再生速度',\n subtitles: '字幕',\n subtitlesOff: 'オフ',\n speed: '速度',\n quality: '画質',\n qualityAuto: '自動',\n next: '次へ',\n nextVideo: '次の動画',\n previous: '前へ',\n playlist: 'プレイリスト',\n scenes: 'シーン',\n sceneTypes: 'シーンタイプ',\n autoplay: '自動再生',\n playNext: '次を再生',\n shuffle: 'シャッフル',\n repeat: 'リピート',\n like: '高く評価',\n dislike: '低く評価',\n addTo: '保存…',\n share: '共有',\n report: '報告',\n more: 'その他の操作',\n seekForward: '早送り',\n seekBack: '巻き戻し',\n secondsShort: '秒',\n live: 'ライブ',\n related: '関連動画',\n adLabel: '広告',\n skipAd: '広告をスキップ',\n skipAdIn: 'スキップまで',\n visitAdvertiser: '広告主のサイトへ',\n sponsored: 'スポンサー',\n },\n\n ko: {\n play: '재생',\n pause: '일시정지',\n replay: '다시 보기',\n mute: '음소거',\n unmute: '음소거 해제',\n fullscreen: '전체화면',\n exitFullscreen: '전체화면 종료',\n pip: 'PIP 모드',\n settings: '재생 속도',\n subtitles: '자막',\n subtitlesOff: '사용 안 함',\n speed: '속도',\n quality: '화질',\n qualityAuto: '자동',\n next: '다음',\n nextVideo: '다음 동영상',\n previous: '이전',\n playlist: '재생목록',\n scenes: '장면',\n sceneTypes: '장면 유형',\n autoplay: '자동 재생',\n playNext: '다음 재생',\n shuffle: '셔플',\n repeat: '반복',\n like: '좋아요',\n dislike: '싫어요',\n addTo: '저장…',\n share: '공유',\n report: '신고',\n more: '더보기',\n seekForward: '앞으로 감기',\n seekBack: '뒤로 감기',\n secondsShort: '초',\n live: '실시간',\n related: '관련 동영상',\n adLabel: '광고',\n skipAd: '광고 건너뛰기',\n skipAdIn: '건너뛰기까지',\n visitAdvertiser: '광고주 방문',\n sponsored: '스폰서',\n },\n\n zh: {\n play: '播放',\n pause: '暂停',\n replay: '重新播放',\n mute: '静音',\n unmute: '取消静音',\n fullscreen: '全屏',\n exitFullscreen: '退出全屏',\n pip: '画中画',\n settings: '播放速度',\n subtitles: '字幕',\n subtitlesOff: '关闭',\n speed: '速度',\n quality: '画质',\n qualityAuto: '自动',\n next: '下一个',\n nextVideo: '下一个视频',\n previous: '上一个',\n playlist: '播放列表',\n scenes: '场景',\n sceneTypes: '场景类型',\n autoplay: '自动播放',\n playNext: '播放下一个',\n shuffle: '随机播放',\n repeat: '循环播放',\n like: '赞',\n dislike: '踩',\n addTo: '保存到…',\n share: '分享',\n report: '举报',\n more: '更多操作',\n seekForward: '快进',\n seekBack: '快退',\n secondsShort: '秒',\n live: '直播',\n related: '更多视频',\n adLabel: '广告',\n skipAd: '跳过广告',\n skipAdIn: '可跳过',\n visitAdvertiser: '访问广告主',\n sponsored: '赞助',\n },\n\n pt: {\n play: 'Reproduzir',\n pause: 'Pausar',\n replay: 'Assistir novamente',\n mute: 'Sem som',\n unmute: 'Ativar som',\n fullscreen: 'Tela cheia',\n exitFullscreen: 'Sair da tela cheia',\n pip: 'Picture-in-picture',\n settings: 'Velocidade de reprodução',\n subtitles: 'Legendas',\n subtitlesOff: 'Desativadas',\n speed: 'Velocidade',\n quality: 'Qualidade',\n qualityAuto: 'Automática',\n next: 'Próximo',\n nextVideo: 'Próximo vídeo',\n previous: 'Anterior',\n playlist: 'Playlist',\n scenes: 'Cenas',\n sceneTypes: 'Tipo de cena',\n autoplay: 'Reprodução automática',\n playNext: 'Reproduzir próximo',\n shuffle: 'Aleatório',\n repeat: 'Repetir',\n like: 'Gostei',\n dislike: 'Não gostei',\n addTo: 'Salvar em…',\n share: 'Compartilhar',\n report: 'Denunciar',\n more: 'Mais ações',\n seekForward: 'Avançar',\n seekBack: 'Retroceder',\n secondsShort: 's',\n live: 'AO VIVO',\n related: 'Mais vídeos',\n adLabel: 'Anúncio',\n skipAd: 'Pular anúncio',\n skipAdIn: 'Pular em',\n visitAdvertiser: 'Visitar anunciante',\n sponsored: 'Patrocinado',\n },\n\n ar: {\n play: 'تشغيل',\n pause: 'إيقاف مؤقت',\n replay: 'إعادة التشغيل',\n mute: 'كتم الصوت',\n unmute: 'إلغاء كتم الصوت',\n fullscreen: 'ملء الشاشة',\n exitFullscreen: 'الخروج من ملء الشاشة',\n pip: 'صورة داخل صورة',\n settings: 'سرعة التشغيل',\n subtitles: 'الترجمة',\n subtitlesOff: 'إيقاف',\n speed: 'السرعة',\n quality: 'الجودة',\n qualityAuto: 'تلقائي',\n next: 'التالي',\n nextVideo: 'الفيديو التالي',\n previous: 'السابق',\n playlist: 'قائمة التشغيل',\n scenes: 'المشاهد',\n sceneTypes: 'نوع المشهد',\n autoplay: 'تشغيل تلقائي',\n playNext: 'تشغيل التالي',\n shuffle: 'تشغيل عشوائي',\n repeat: 'تكرار',\n like: 'أعجبني',\n dislike: 'لم يعجبني',\n addTo: 'حفظ في…',\n share: 'مشاركة',\n report: 'إبلاغ',\n more: 'المزيد من الإجراءات',\n seekForward: 'تقديم',\n seekBack: 'إرجاع',\n secondsShort: 'ث',\n live: 'مباشر',\n related: 'المزيد من الفيديوهات',\n adLabel: 'إعلان',\n skipAd: 'تخطي الإعلان',\n skipAdIn: 'التخطي بعد',\n visitAdvertiser: 'زيارة المعلن',\n sponsored: 'برعاية',\n },\n\n hi: {\n play: 'चलाएं',\n pause: 'रोकें',\n replay: 'फिर से चलाएं',\n mute: 'म्यूट करें',\n unmute: 'अनम्यूट करें',\n fullscreen: 'फ़ुल स्क्रीन',\n exitFullscreen: 'फ़ुल स्क्रीन से बाहर निकलें',\n pip: 'पिक्चर-इन-पिक्चर',\n settings: 'प्लेबैक गति',\n subtitles: 'सबटाइटल',\n subtitlesOff: 'बंद',\n speed: 'गति',\n quality: 'क्वालिटी',\n qualityAuto: 'ऑटो',\n next: 'अगला',\n nextVideo: 'अगला वीडियो',\n previous: 'पिछला',\n playlist: 'प्लेलिस्ट',\n scenes: 'दृश्य',\n sceneTypes: 'सीन प्रकार',\n autoplay: 'ऑटोप्ले',\n playNext: 'अगला चलाएं',\n shuffle: 'शफ़ल',\n repeat: 'दोहराएं',\n like: 'पसंद',\n dislike: 'नापसंद',\n addTo: 'इसमें सहेजें…',\n share: 'साझा करें',\n report: 'रिपोर्ट करें',\n more: 'अधिक कार्रवाइयां',\n seekForward: 'आगे बढ़ाएं',\n seekBack: 'पीछे करें',\n secondsShort: 's',\n live: 'लाइव',\n related: 'और वीडियो',\n adLabel: 'विज्ञापन',\n skipAd: 'विज्ञापन छोड़ें',\n skipAdIn: 'छोड़ें',\n visitAdvertiser: 'विज्ञापनदाता देखें',\n sponsored: 'प्रायोजित',\n },\n}\n\n/** Codes of all built-in locales. */\nexport const supportedLanguages = Object.keys(locales) as LocaleCode[]\n"],"names":["el","tag","className","attrs","node","key","value","iconButton","label","svg","btn","previewMetaEl","items","base","row","item","i","text","icon","chunk","ic","setIcon","clamp","min","max","formatTime","seconds","s","m","h","mm","ss","parseVttTime","raw","ms","parseVttCues","cues","blocks","block","lines","l","timingIndex","rawStart","rawEnd","start","end","cueText","resolveUrl","url","Emitter","event","fn","set","off","payload","err","body","viewBox","defaultIcons","defaultLabels","registry","registerLocales","map","code","labels","getLocale","buildHeatmapValues","points","duration","buckets","hasData","point","index","kernel","smooth","_","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","CHEVRON_RIGHT","CHEVRON_LEFT","Menu","anchor","sections","section","title","entries","_title","chevron","toggle","sw","next","back","iconBox","target","ProgressBar","list","filled","cursor","ch","root","fill","track","bufferedEnd","ratio","span","progress","rect","x","half","Controls","player","icons","c","left","right","spacer","seekCfg","seekBack","seekFwd","volumeWrap","ca","place","subsPlace","qualityPlace","speedPlace","wrap","listBtn","pipBtn","insertion","requested","keys","seen","modifier","dir","num","p","out","r","active","g","o","card","kicker","thumb","cr","pad","cardW","centered","_btn","initial","tip","likeCount","dislikeCount","state","custom","moreBtn","runMap","simpleItems","order","rank","overflowedSorted","it","rate","compact","useCenter","inCenter","ok","byPriority","guard","hasContent","rowRight","effective","except","menu","dispose","PosterOverlay","big","source","PauseScreen","heading","element","parts","sponsor","channel","RelatedOverlay","close","UpNextOverlay","dur","play","PlaylistPanel","layout","playlistTitle","header","name","tools","meta","itemTitle","ScenesPanel","thumbs","inner","current","normalizeSubtitles","input","defaultControls","Player","mount","rawControls","speed","saved","styling","savedAV","middle","bottom","adConfig","message","ranges","delta","volume","muted","qualities","q","tracks","on","startIndex","id","autoplay","token","sub","apply","parsed","applyHeatmap","eventName","mediaError","at","restore","reset","isButton"],"mappings":"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"}
|