itube-modern-player 0.7.0 → 0.7.2

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.
@@ -0,0 +1,5 @@
1
+ "use strict";function c(n,t,e){const i=document.createElement(n);if(t&&(i.className=t),e)for(const[o,r]of Object.entries(e))i.setAttribute(o,r);return i}function l(n,t){if(n.textContent="",typeof t=="object"){"url"in t?n.append(c("img","imp-icon-img",{src:t.url,alt:""})):n.innerHTML=t.svg;return}/^\s*</.test(t)?n.innerHTML=t:n.append(c("img","imp-icon-img",{src:t,alt:""}))}function g(n,t=""){const e=c("img","imp-cover-img",{alt:t,decoding:"async"});return e.src=n,e}function h(n,t,e){const i=c("button",`imp-btn ${n}`,{type:"button","aria-label":t,title:t});return l(i,e),i}function v(n,t){const e=c("div",`${t}__meta`);return n.forEach((i,o)=>{o>0&&e.append(document.createTextNode(" "));const r=typeof i=="string"?i:i.text,a=typeof i=="string"?void 0:i.icon,s=c("span",`${t}__meta-chunk`);if(a){const u=c("span",`${t}__meta-icon`);l(u,a),s.append(u)}s.append(document.createTextNode(r)),e.append(s)}),e}function b(n,t,e){l(n,t),e!==void 0&&(n.setAttribute("aria-label",e),n.setAttribute("title",e))}function x(n,t,e){return Math.min(e,Math.max(t,n))}function $(n){if(!Number.isFinite(n)||n<0)return"0:00";const t=Math.floor(n%60),e=Math.floor(n/60%60),i=Math.floor(n/3600),o=i>0?String(e).padStart(2,"0"):String(e),r=String(t).padStart(2,"0");return i>0?`${i}:${o}:${r}`:`${o}:${r}`}function f(n){const t=n.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:[.,](\d{1,3}))?$/);if(!t)return null;const e=t[1]?Number(t[1]):0,i=Number(t[2]),o=Number(t[3]),r=t[4]?Number(t[4].padEnd(3,"0")):0;return e*3600+i*60+o+r/1e3}function w(n){const t=[],e=n.replace(/\r\n?/g,`
2
+ `).split(/\n\n+/);for(const i of e){const o=i.split(`
3
+ `).filter(p=>p.trim()!=="");if(o.length===0)continue;let r=o.findIndex(p=>p.includes("-->"));if(r===-1)continue;const[a,s]=o[r].split("-->"),u=f(a),m=f((s??"").split(" ")[1]??s??"")??f(s??"");if(u===null||m===null)continue;const d=o.slice(r+1).join(`
4
+ `).trim();d&&t.push({start:u,end:m,text:d})}return t}function y(n,t){try{return new URL(n,new URL(t,window.location.href)).toString()}catch{return n}}exports.applyIcon=l;exports.clamp=x;exports.coverImg=g;exports.el=c;exports.formatTime=$;exports.iconButton=h;exports.parseVttCues=w;exports.previewMetaEl=v;exports.resolveUrl=y;exports.setIcon=b;
5
+ //# sourceMappingURL=dom-Bq7EQenh.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-Bq7EQenh.cjs","sources":["../src/core/dom.ts"],"sourcesContent":["/** DOM helpers. All player markup is built through these — no innerHTML templates. */\n\nimport type { IconSource, 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/**\n * Render an icon into `target`, honoring its kind: raw SVG (set as innerHTML)\n * or an image URL (an `<img class=\"imp-icon-img\">`). A bare string is raw SVG\n * when it starts with `<`, otherwise an image URL.\n */\nexport function applyIcon(target: HTMLElement, icon: IconSource): void {\n target.textContent = ''\n if (typeof icon === 'object') {\n if ('url' in icon) target.append(el('img', 'imp-icon-img', { src: icon.url, alt: '' }))\n else target.innerHTML = icon.svg\n return\n }\n if (/^\\s*</.test(icon)) target.innerHTML = icon\n else target.append(el('img', 'imp-icon-img', { src: icon, alt: '' }))\n}\n\n/**\n * Real `<img>` filling its (positioned, overflow-hidden) container like\n * `background-size: cover`. Used for every poster/preview surface — a real\n * element (not a CSS background) is lazy-loadable, LCP-eligible and keeps\n * the markup identical between the lazy placeholder and the live player.\n */\nexport function coverImg(src: string, alt = ''): HTMLImageElement {\n const img = el('img', 'imp-cover-img', { alt, decoding: 'async' }) as HTMLImageElement\n img.src = src\n return img\n}\n\n/** Icon-only button with an accessible label. */\nexport function iconButton(className: string, label: string, icon: IconSource): HTMLButtonElement {\n const btn = el('button', `imp-btn ${className}`, { type: 'button', 'aria-label': label, title: label })\n applyIcon(btn, icon)\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 applyIcon(ic, 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, icon: IconSource, label?: string): void {\n applyIcon(btn, icon)\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"],"names":["el","tag","className","attrs","node","key","value","applyIcon","target","icon","coverImg","src","alt","img","iconButton","label","btn","previewMetaEl","items","base","row","item","i","text","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"],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ function s(n, t, e) {
2
+ const i = document.createElement(n);
3
+ if (t && (i.className = t), e)
4
+ for (const [o, r] of Object.entries(e)) i.setAttribute(o, r);
5
+ return i;
6
+ }
7
+ function m(n, t) {
8
+ if (n.textContent = "", typeof t == "object") {
9
+ "url" in t ? n.append(s("img", "imp-icon-img", { src: t.url, alt: "" })) : n.innerHTML = t.svg;
10
+ return;
11
+ }
12
+ /^\s*</.test(t) ? n.innerHTML = t : n.append(s("img", "imp-icon-img", { src: t, alt: "" }));
13
+ }
14
+ function g(n, t = "") {
15
+ const e = s("img", "imp-cover-img", { alt: t, decoding: "async" });
16
+ return e.src = n, e;
17
+ }
18
+ function h(n, t, e) {
19
+ const i = s("button", `imp-btn ${n}`, { type: "button", "aria-label": t, title: t });
20
+ return m(i, e), i;
21
+ }
22
+ function b(n, t) {
23
+ const e = s("div", `${t}__meta`);
24
+ return n.forEach((i, o) => {
25
+ o > 0 && e.append(document.createTextNode(" "));
26
+ const r = typeof i == "string" ? i : i.text, a = typeof i == "string" ? void 0 : i.icon, c = s("span", `${t}__meta-chunk`);
27
+ if (a) {
28
+ const u = s("span", `${t}__meta-icon`);
29
+ m(u, a), c.append(u);
30
+ }
31
+ c.append(document.createTextNode(r)), e.append(c);
32
+ }), e;
33
+ }
34
+ function x(n, t, e) {
35
+ m(n, t), e !== void 0 && (n.setAttribute("aria-label", e), n.setAttribute("title", e));
36
+ }
37
+ function $(n, t, e) {
38
+ return Math.min(e, Math.max(t, n));
39
+ }
40
+ function v(n) {
41
+ if (!Number.isFinite(n) || n < 0) return "0:00";
42
+ const t = Math.floor(n % 60), e = Math.floor(n / 60 % 60), i = Math.floor(n / 3600), o = i > 0 ? String(e).padStart(2, "0") : String(e), r = String(t).padStart(2, "0");
43
+ return i > 0 ? `${i}:${o}:${r}` : `${o}:${r}`;
44
+ }
45
+ function p(n) {
46
+ const t = n.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:[.,](\d{1,3}))?$/);
47
+ if (!t) return null;
48
+ const e = t[1] ? Number(t[1]) : 0, i = Number(t[2]), o = Number(t[3]), r = t[4] ? Number(t[4].padEnd(3, "0")) : 0;
49
+ return e * 3600 + i * 60 + o + r / 1e3;
50
+ }
51
+ function w(n) {
52
+ const t = [], e = n.replace(/\r\n?/g, `
53
+ `).split(/\n\n+/);
54
+ for (const i of e) {
55
+ const o = i.split(`
56
+ `).filter((f) => f.trim() !== "");
57
+ if (o.length === 0) continue;
58
+ let r = o.findIndex((f) => f.includes("-->"));
59
+ if (r === -1) continue;
60
+ const [a, c] = o[r].split("-->"), u = p(a), l = p((c ?? "").split(" ")[1] ?? c ?? "") ?? p(c ?? "");
61
+ if (u === null || l === null) continue;
62
+ const d = o.slice(r + 1).join(`
63
+ `).trim();
64
+ d && t.push({ start: u, end: l, text: d });
65
+ }
66
+ return t;
67
+ }
68
+ function y(n, t) {
69
+ try {
70
+ return new URL(n, new URL(t, window.location.href)).toString();
71
+ } catch {
72
+ return n;
73
+ }
74
+ }
75
+ export {
76
+ m as a,
77
+ g as b,
78
+ $ as c,
79
+ b as d,
80
+ s as e,
81
+ v as f,
82
+ h as i,
83
+ w as p,
84
+ y as r,
85
+ x as s
86
+ };
87
+ //# sourceMappingURL=dom-DrpWbY0y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-DrpWbY0y.js","sources":["../src/core/dom.ts"],"sourcesContent":["/** DOM helpers. All player markup is built through these — no innerHTML templates. */\n\nimport type { IconSource, 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/**\n * Render an icon into `target`, honoring its kind: raw SVG (set as innerHTML)\n * or an image URL (an `<img class=\"imp-icon-img\">`). A bare string is raw SVG\n * when it starts with `<`, otherwise an image URL.\n */\nexport function applyIcon(target: HTMLElement, icon: IconSource): void {\n target.textContent = ''\n if (typeof icon === 'object') {\n if ('url' in icon) target.append(el('img', 'imp-icon-img', { src: icon.url, alt: '' }))\n else target.innerHTML = icon.svg\n return\n }\n if (/^\\s*</.test(icon)) target.innerHTML = icon\n else target.append(el('img', 'imp-icon-img', { src: icon, alt: '' }))\n}\n\n/**\n * Real `<img>` filling its (positioned, overflow-hidden) container like\n * `background-size: cover`. Used for every poster/preview surface — a real\n * element (not a CSS background) is lazy-loadable, LCP-eligible and keeps\n * the markup identical between the lazy placeholder and the live player.\n */\nexport function coverImg(src: string, alt = ''): HTMLImageElement {\n const img = el('img', 'imp-cover-img', { alt, decoding: 'async' }) as HTMLImageElement\n img.src = src\n return img\n}\n\n/** Icon-only button with an accessible label. */\nexport function iconButton(className: string, label: string, icon: IconSource): HTMLButtonElement {\n const btn = el('button', `imp-btn ${className}`, { type: 'button', 'aria-label': label, title: label })\n applyIcon(btn, icon)\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 applyIcon(ic, 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, icon: IconSource, label?: string): void {\n applyIcon(btn, icon)\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"],"names":["el","tag","className","attrs","node","key","value","applyIcon","target","icon","coverImg","src","alt","img","iconButton","label","btn","previewMetaEl","items","base","row","item","i","text","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"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),t=require("./labels-BOrrLImF.cjs"),a=require("./locales.cjs");e.registerLocales(a.locales);exports.Emitter=e.Emitter;exports.Player=e.Player;exports.ThumbnailTrack=e.ThumbnailTrack;exports.buildHeatmapValues=e.buildHeatmapValues;exports.chapterAt=e.chapterAt;exports.defaultIcons=e.defaultIcons;exports.formatTime=e.formatTime;exports.getLocale=e.getLocale;exports.heatmapPath=e.heatmapPath;exports.isHlsSource=e.isHlsSource;exports.loadChaptersVtt=e.loadChaptersVtt;exports.normalizeChapters=e.normalizeChapters;exports.registerLocale=e.registerLocale;exports.registerLocales=e.registerLocales;exports.registeredLanguages=e.registeredLanguages;exports.resolveVast=e.resolveVast;exports.defaultLabels=t.defaultLabels;exports.locales=a.locales;exports.supportedLanguages=a.supportedLanguages;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),t=require("./labels-BOrrLImF.cjs"),r=require("./dom-Bq7EQenh.cjs"),a=require("./locales.cjs");e.registerLocales(a.locales);exports.Emitter=e.Emitter;exports.Player=e.Player;exports.ThumbnailTrack=e.ThumbnailTrack;exports.buildHeatmapValues=e.buildHeatmapValues;exports.chapterAt=e.chapterAt;exports.defaultIcons=e.defaultIcons;exports.getLocale=e.getLocale;exports.heatmapPath=e.heatmapPath;exports.isHlsSource=e.isHlsSource;exports.loadChaptersVtt=e.loadChaptersVtt;exports.normalizeChapters=e.normalizeChapters;exports.registerLocale=e.registerLocale;exports.registerLocales=e.registerLocales;exports.registeredLanguages=e.registeredLanguages;exports.resolveVast=e.resolveVast;exports.defaultLabels=t.defaultLabels;exports.formatTime=r.formatTime;exports.locales=a.locales;exports.supportedLanguages=a.supportedLanguages;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * Main entry: the full player with all 11 built-in locales registered.\n * Size-conscious builds can use `itube-modern-player/core` instead and\n * register only the locales they need.\n */\nexport * from './coreEntry'\n\nimport { registerLocales } from './core/localeRegistry'\nimport { locales } from './core/locales'\n\nregisterLocales(locales)\n\nexport { locales, supportedLanguages } from './core/locales'\n"],"names":["registerLocales","locales"],"mappings":"4KAUAA,EAAAA,gBAAgBC,SAAO"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * Main entry: the full player with all 11 built-in locales registered.\n * Size-conscious builds can use `itube-modern-player/core` instead and\n * register only the locales they need.\n */\nexport * from './coreEntry'\n\nimport { registerLocales } from './core/localeRegistry'\nimport { locales } from './core/locales'\n\nregisterLocales(locales)\n\nexport { locales, supportedLanguages } from './core/locales'\n"],"names":["registerLocales","locales"],"mappings":"4MAUAA,EAAAA,gBAAgBC,SAAO"}
package/dist/index.js CHANGED
@@ -1,28 +1,29 @@
1
1
  import { registerLocales as e, Player as t } from "./core.js";
2
- import { Emitter as m, ThumbnailTrack as p, buildHeatmapValues as i, chapterAt as u, defaultIcons as c, formatTime as f, getLocale as g, heatmapPath as d, isHlsSource as h, loadChaptersVtt as L, normalizeChapters as n, registerLocale as x, registeredLanguages as b, resolveVast as T } from "./core.js";
3
- import { d as C } from "./labels-CCjOCBKU.js";
4
- import { locales as a } from "./locales.js";
5
- import { supportedLanguages as P } from "./locales.js";
6
- e(a);
2
+ import { Emitter as m, ThumbnailTrack as p, buildHeatmapValues as i, chapterAt as f, defaultIcons as u, getLocale as c, heatmapPath as g, isHlsSource as d, loadChaptersVtt as h, normalizeChapters as L, registerLocale as n, registeredLanguages as x, resolveVast as b } from "./core.js";
3
+ import { d as V } from "./labels-CCjOCBKU.js";
4
+ import { f as H } from "./dom-DrpWbY0y.js";
5
+ import { locales as r } from "./locales.js";
6
+ import { supportedLanguages as k } from "./locales.js";
7
+ e(r);
7
8
  export {
8
9
  m as Emitter,
9
10
  t as Player,
10
11
  p as ThumbnailTrack,
11
12
  i as buildHeatmapValues,
12
- u as chapterAt,
13
- c as defaultIcons,
14
- C as defaultLabels,
15
- f as formatTime,
16
- g as getLocale,
17
- d as heatmapPath,
18
- h as isHlsSource,
19
- L as loadChaptersVtt,
20
- a as locales,
21
- n as normalizeChapters,
22
- x as registerLocale,
13
+ f as chapterAt,
14
+ u as defaultIcons,
15
+ V as defaultLabels,
16
+ H as formatTime,
17
+ c as getLocale,
18
+ g as heatmapPath,
19
+ d as isHlsSource,
20
+ h as loadChaptersVtt,
21
+ r as locales,
22
+ L as normalizeChapters,
23
+ n as registerLocale,
23
24
  e as registerLocales,
24
- b as registeredLanguages,
25
- T as resolveVast,
26
- P as supportedLanguages
25
+ x as registeredLanguages,
26
+ b as resolveVast,
27
+ k as supportedLanguages
27
28
  };
28
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * Main entry: the full player with all 11 built-in locales registered.\n * Size-conscious builds can use `itube-modern-player/core` instead and\n * register only the locales they need.\n */\nexport * from './coreEntry'\n\nimport { registerLocales } from './core/localeRegistry'\nimport { locales } from './core/locales'\n\nregisterLocales(locales)\n\nexport { locales, supportedLanguages } from './core/locales'\n"],"names":["registerLocales","locales"],"mappings":";;;;;AAUAA,EAAgBC,CAAO;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * Main entry: the full player with all 11 built-in locales registered.\n * Size-conscious builds can use `itube-modern-player/core` instead and\n * register only the locales they need.\n */\nexport * from './coreEntry'\n\nimport { registerLocales } from './core/localeRegistry'\nimport { locales } from './core/locales'\n\nregisterLocales(locales)\n\nexport { locales, supportedLanguages } from './core/locales'\n"],"names":["registerLocales","locales"],"mappings":";;;;;;AAUAA,EAAgBC,CAAO;"}