@hopeplayer/core 1.0.14 → 1.0.15
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/dist/HopePlayerElement.d.ts +21 -0
- package/dist/HopePlayerElement.d.ts.map +1 -1
- package/dist/chunks/{index-C2c71cGP.js → index-BOoNcKeR.js} +2 -2
- package/dist/chunks/{index-C2c71cGP.js.map → index-BOoNcKeR.js.map} +1 -1
- package/dist/chunks/{index-BTBAxNjr.js → index-BvoB2O1p.js} +2 -2
- package/dist/chunks/{index-BTBAxNjr.js.map → index-BvoB2O1p.js.map} +1 -1
- package/dist/chunks/{index-Dy0Th0is.js → index-ClQg_X1N.js} +2 -2
- package/dist/chunks/{index-Dy0Th0is.js.map → index-ClQg_X1N.js.map} +1 -1
- package/dist/chunks/index-D5P-LWbg.js +245 -0
- package/dist/chunks/index-D5P-LWbg.js.map +1 -0
- package/dist/chunks/{index-DcVUXkXo.js → index-DRlQC-ev.js} +2 -2
- package/dist/chunks/{index-DcVUXkXo.js.map → index-DRlQC-ev.js.map} +1 -1
- package/dist/chunks/{index-DtqNHU7Y.js → index-DpUZXNJS.js} +2 -2
- package/dist/chunks/{index-DtqNHU7Y.js.map → index-DpUZXNJS.js.map} +1 -1
- package/dist/chunks/index-TkG8IO6q.js +239 -0
- package/dist/chunks/index-TkG8IO6q.js.map +1 -0
- package/dist/chunks/{index-Dz0E1YPE.js → index-w7pACyTw.js} +575 -416
- package/dist/chunks/index-w7pACyTw.js.map +1 -0
- package/dist/controls/SettingsMenu.d.ts +4 -0
- package/dist/controls/SettingsMenu.d.ts.map +1 -1
- package/dist/hls/SourceManager.d.ts +2 -0
- package/dist/hls/SourceManager.d.ts.map +1 -1
- package/dist/hope-player.js +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/types.d.ts +13 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/plugins/rewarded/RewardedUnlock.d.ts +66 -0
- package/dist/plugins/rewarded/RewardedUnlock.d.ts.map +1 -0
- package/dist/plugins/rewarded/gpt.d.ts +8 -0
- package/dist/plugins/rewarded/gpt.d.ts.map +1 -0
- package/dist/plugins/rewarded/index.d.ts +7 -0
- package/dist/plugins/rewarded/index.d.ts.map +1 -0
- package/dist/plugins/sponsorship/SponsorshipLayer.d.ts +73 -0
- package/dist/plugins/sponsorship/SponsorshipLayer.d.ts.map +1 -0
- package/dist/plugins/sponsorship/index.d.ts +7 -0
- package/dist/plugins/sponsorship/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +115 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/index-Dz0E1YPE.js.map +0 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
var k = Object.defineProperty;
|
|
2
|
+
var w = (i, t, e) => t in i ? k(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
|
|
3
|
+
var a = (i, t, e) => w(i, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
const T = {
|
|
5
|
+
accent: "--hp-color-accent",
|
|
6
|
+
onAccent: "--hp-color-on-accent",
|
|
7
|
+
surface: "--hp-color-surface",
|
|
8
|
+
onSurface: "--hp-color-on-surface"
|
|
9
|
+
}, S = ["top-left", "top-right", "bottom-left", "bottom-right"];
|
|
10
|
+
function m(i) {
|
|
11
|
+
if (typeof i != "string" || !i.trim()) return null;
|
|
12
|
+
try {
|
|
13
|
+
const t = new URL(i, document.baseURI);
|
|
14
|
+
return t.protocol === "https:" || t.protocol === "http:" ? t.href : null;
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function x(i) {
|
|
20
|
+
return typeof i == "string" && i.length < 64 && CSS.supports("color", i) ? i : null;
|
|
21
|
+
}
|
|
22
|
+
function f(i, t, e, o) {
|
|
23
|
+
return typeof i == "number" && Number.isFinite(i) ? Math.min(e, Math.max(t, i)) : o;
|
|
24
|
+
}
|
|
25
|
+
function A(i) {
|
|
26
|
+
var c, l, n, p, v, E, y, b;
|
|
27
|
+
if (!i || typeof i != "object") return null;
|
|
28
|
+
const t = i;
|
|
29
|
+
if (t.active !== !0 || !t.sponsor || typeof t.sponsor.name != "string" || !t.sponsor.name.trim()) return null;
|
|
30
|
+
const e = Date.now(), o = t.validFrom ? Date.parse(t.validFrom) : NaN, s = t.validUntil ? Date.parse(t.validUntil) : NaN;
|
|
31
|
+
if (Number.isFinite(o) && e < o || Number.isFinite(s) && e > s) return null;
|
|
32
|
+
const r = {};
|
|
33
|
+
for (const d of Object.keys(T)) {
|
|
34
|
+
const u = x((c = t.theme) == null ? void 0 : c[d]);
|
|
35
|
+
u && (r[d] = u);
|
|
36
|
+
}
|
|
37
|
+
const h = (d) => Array.isArray(d) ? d.map(m).filter((u) => !!u).slice(0, 10) : [];
|
|
38
|
+
return {
|
|
39
|
+
active: !0,
|
|
40
|
+
id: typeof t.id == "string" ? t.id.slice(0, 120) : void 0,
|
|
41
|
+
sponsor: {
|
|
42
|
+
name: t.sponsor.name.slice(0, 80),
|
|
43
|
+
logo: m(t.sponsor.logo) ?? void 0,
|
|
44
|
+
url: m(t.sponsor.url) ?? void 0
|
|
45
|
+
},
|
|
46
|
+
theme: r,
|
|
47
|
+
logo: {
|
|
48
|
+
position: S.includes((l = t.logo) == null ? void 0 : l.position) ? t.logo.position : "top-left",
|
|
49
|
+
width: f((n = t.logo) == null ? void 0 : n.width, 32, 240, 96),
|
|
50
|
+
opacity: f((p = t.logo) == null ? void 0 : p.opacity, 0.2, 1, 0.9),
|
|
51
|
+
label: typeof ((v = t.logo) == null ? void 0 : v.label) == "string" ? t.logo.label.slice(0, 40) : void 0
|
|
52
|
+
},
|
|
53
|
+
intro: t.intro ? {
|
|
54
|
+
text: typeof t.intro.text == "string" ? t.intro.text.slice(0, 120) : void 0,
|
|
55
|
+
durationMs: f(t.intro.durationMs, 1e3, 15e3, 3500),
|
|
56
|
+
repeatMinutes: typeof t.intro.repeatMinutes == "number" && t.intro.repeatMinutes > 0 ? Math.min(240, Math.max(1, t.intro.repeatMinutes)) : void 0,
|
|
57
|
+
maxShows: typeof t.intro.maxShows == "number" && t.intro.maxShows >= 1 ? Math.min(100, Math.floor(t.intro.maxShows)) : void 0
|
|
58
|
+
} : void 0,
|
|
59
|
+
tracking: { impression: h((E = t.tracking) == null ? void 0 : E.impression), click: h((y = t.tracking) == null ? void 0 : y.click), intro: h((b = t.tracking) == null ? void 0 : b.intro) }
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function g(i) {
|
|
63
|
+
for (const t of i ?? []) {
|
|
64
|
+
const e = new Image();
|
|
65
|
+
e.referrerPolicy = "no-referrer-when-downgrade", e.src = t;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class L {
|
|
69
|
+
constructor(t, e) {
|
|
70
|
+
a(this, "options");
|
|
71
|
+
a(this, "config", null);
|
|
72
|
+
a(this, "logoEl", null);
|
|
73
|
+
a(this, "introEl", null);
|
|
74
|
+
a(this, "introTimer", null);
|
|
75
|
+
a(this, "refreshTimer", null);
|
|
76
|
+
/** Player boyutu / kontrol düzeni değişince logo kontrollerin üstüne binmesin diye yeniden konumlanır. */
|
|
77
|
+
a(this, "resizeObserver");
|
|
78
|
+
/** Uygulanan tema değişkenlerinin önceki satır içi değerleri — katman kalkınca geri yüklenir. */
|
|
79
|
+
a(this, "previousTokens", /* @__PURE__ */ new Map());
|
|
80
|
+
/** Gösterim pikseli kampanya başına bir kez. */
|
|
81
|
+
a(this, "impressed", /* @__PURE__ */ new Set());
|
|
82
|
+
/** Kampanya başına giriş gösterim sayısı. */
|
|
83
|
+
a(this, "introCount", /* @__PURE__ */ new Map());
|
|
84
|
+
/** Son girişten bu yana gerçek izleme süresi (ms) — intro.repeatMinutes için. */
|
|
85
|
+
a(this, "watchedSinceIntro", 0);
|
|
86
|
+
a(this, "lastTick", 0);
|
|
87
|
+
a(this, "tickTimer");
|
|
88
|
+
a(this, "destroyed", !1);
|
|
89
|
+
a(this, "requestSeq", 0);
|
|
90
|
+
/** Oynatma başladı: kampanya başına bir kez gösterim pikseli + "X sunar" kartı. */
|
|
91
|
+
a(this, "onPlay", () => {
|
|
92
|
+
var o;
|
|
93
|
+
const t = this.config;
|
|
94
|
+
if (!t) return;
|
|
95
|
+
const e = this.key(t);
|
|
96
|
+
this.impressed.has(e) || (this.impressed.add(e), g((o = t.tracking) == null ? void 0 : o.impression), this.ctx.hostEl.dispatchEvent(new CustomEvent("hp:sponsorimpression", { detail: { id: t.id, sponsor: t.sponsor.name } }))), t.intro && !this.introCount.has(e) && this.showIntro(t);
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* intro.repeatMinutes: yalnızca gerçekten izlenirken sayar (oynuyor, sekme önde, reklam yok); süre dolunca giriş
|
|
100
|
+
* tekrar gösterilir — maxShows'a kadar.
|
|
101
|
+
*/
|
|
102
|
+
a(this, "tick", () => {
|
|
103
|
+
var c, l;
|
|
104
|
+
const t = performance.now(), e = Math.min(2e3, Math.max(0, t - this.lastTick));
|
|
105
|
+
this.lastTick = t;
|
|
106
|
+
const o = this.config, s = (c = o == null ? void 0 : o.intro) == null ? void 0 : c.repeatMinutes;
|
|
107
|
+
if (!o || !s || !(!this.ctx.videoEl.paused && !this.ctx.videoEl.ended && !document.hidden && !this.ctx.hostEl.hasAttribute("data-sponsor-hidden")) || !this.introCount.has(this.key(o)) || (this.watchedSinceIntro += e, this.watchedSinceIntro < s * 6e4)) return;
|
|
108
|
+
const h = (l = o.intro) == null ? void 0 : l.maxShows;
|
|
109
|
+
h && (this.introCount.get(this.key(o)) ?? 0) >= h || this.showIntro(o);
|
|
110
|
+
});
|
|
111
|
+
/** Lineer reklam sırasında logo / giriş gizlenir (reklamın üstüne binmesin). */
|
|
112
|
+
a(this, "onAdStart", (t) => {
|
|
113
|
+
var e;
|
|
114
|
+
((e = t.detail) == null ? void 0 : e.linear) !== !1 && this.ctx.hostEl.setAttribute("data-sponsor-hidden", "");
|
|
115
|
+
});
|
|
116
|
+
a(this, "onAdEnd", (t) => {
|
|
117
|
+
var e;
|
|
118
|
+
((e = t.detail) == null ? void 0 : e.linear) !== !1 && this.ctx.hostEl.removeAttribute("data-sponsor-hidden");
|
|
119
|
+
});
|
|
120
|
+
var s, r;
|
|
121
|
+
this.ctx = t, this.options = e, t.videoEl.addEventListener("play", this.onPlay), t.hostEl.addEventListener("hp:adstart", this.onAdStart), t.hostEl.addEventListener("hp:adend", this.onAdEnd), this.lastTick = performance.now(), this.tickTimer = setInterval(this.tick, 1e3), this.resizeObserver = typeof ResizeObserver < "u" ? new ResizeObserver(() => this.positionLogo()) : null, (s = this.resizeObserver) == null || s.observe(t.overlayEl);
|
|
122
|
+
const o = t.overlayEl.querySelector(".hp-top-bar");
|
|
123
|
+
o && ((r = this.resizeObserver) == null || r.observe(o)), this.load(), this.scheduleRefresh();
|
|
124
|
+
}
|
|
125
|
+
update(t) {
|
|
126
|
+
const e = t.endpoint !== this.options.endpoint || JSON.stringify(t.params) !== JSON.stringify(this.options.params), o = t.refreshSeconds !== this.options.refreshSeconds;
|
|
127
|
+
this.options = t, e && this.load(), o && this.scheduleRefresh();
|
|
128
|
+
}
|
|
129
|
+
/** Şu an uygulanan kampanya (yoksa null). */
|
|
130
|
+
get current() {
|
|
131
|
+
return this.config;
|
|
132
|
+
}
|
|
133
|
+
scheduleRefresh() {
|
|
134
|
+
this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = null;
|
|
135
|
+
const t = this.options.refreshSeconds;
|
|
136
|
+
typeof t == "number" && t >= 10 && (this.refreshTimer = setInterval(() => void this.load(), t * 1e3));
|
|
137
|
+
}
|
|
138
|
+
buildUrl() {
|
|
139
|
+
const t = new URL(this.options.endpoint, document.baseURI);
|
|
140
|
+
for (const [e, o] of Object.entries(this.options.params ?? {})) t.searchParams.set(e, o);
|
|
141
|
+
return t.href;
|
|
142
|
+
}
|
|
143
|
+
async load() {
|
|
144
|
+
const t = ++this.requestSeq, e = typeof AbortController < "u" ? new AbortController() : null, o = setTimeout(() => e == null ? void 0 : e.abort(), this.options.timeoutMs ?? 5e3);
|
|
145
|
+
let s = "";
|
|
146
|
+
try {
|
|
147
|
+
s = this.buildUrl();
|
|
148
|
+
const r = await fetch(s, { ...this.options.fetchInit, signal: e == null ? void 0 : e.signal });
|
|
149
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
150
|
+
const h = await r.json();
|
|
151
|
+
if (this.destroyed || t !== this.requestSeq) return;
|
|
152
|
+
this.apply(A(h));
|
|
153
|
+
} catch (r) {
|
|
154
|
+
if (this.destroyed || t !== this.requestSeq) return;
|
|
155
|
+
this.ctx.log({ message: `Sponsorship API failed: ${String(r)}`, details: { url: s } });
|
|
156
|
+
} finally {
|
|
157
|
+
clearTimeout(o);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
apply(t) {
|
|
161
|
+
const e = this.key(this.config);
|
|
162
|
+
this.config = t, this.applyTheme((t == null ? void 0 : t.theme) ?? null), this.renderLogo(), this.ctx.hostEl.toggleAttribute("data-sponsored", !!t), this.key(t) !== e && (this.watchedSinceIntro = 0, this.ctx.hostEl.dispatchEvent(new CustomEvent("hp:sponsorship", { detail: { config: t } })), t && !this.ctx.videoEl.paused && this.onPlay());
|
|
163
|
+
}
|
|
164
|
+
key(t) {
|
|
165
|
+
return t ? t.id || t.sponsor.name : "";
|
|
166
|
+
}
|
|
167
|
+
applyTheme(t) {
|
|
168
|
+
const e = this.ctx.hostEl.style;
|
|
169
|
+
for (const [o, s] of this.previousTokens)
|
|
170
|
+
s ? e.setProperty(o, s) : e.removeProperty(o);
|
|
171
|
+
if (this.previousTokens.clear(), !!t)
|
|
172
|
+
for (const [o, s] of Object.entries(T)) {
|
|
173
|
+
const r = t[o];
|
|
174
|
+
r && (this.previousTokens.set(s, e.getPropertyValue(s)), e.setProperty(s, r));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
renderLogo() {
|
|
178
|
+
var o, s, r, h, c, l;
|
|
179
|
+
(o = this.logoEl) == null || o.remove(), this.logoEl = null;
|
|
180
|
+
const t = this.config;
|
|
181
|
+
if (!t || !t.sponsor.logo && !((s = t.logo) != null && s.label)) return;
|
|
182
|
+
const e = t.sponsor.url ? document.createElement("a") : document.createElement("div");
|
|
183
|
+
if (e.className = "hp-sponsor-logo", e.setAttribute("part", "sponsor-logo"), e.setAttribute("data-position", ((r = t.logo) == null ? void 0 : r.position) ?? "top-left"), e.style.setProperty("--hp-sponsor-logo-w", `${((h = t.logo) == null ? void 0 : h.width) ?? 96}px`), e.style.opacity = String(((c = t.logo) == null ? void 0 : c.opacity) ?? 0.9), e instanceof HTMLAnchorElement && (e.href = t.sponsor.url, e.target = "_blank", e.rel = "noopener sponsored", e.addEventListener("click", (n) => {
|
|
184
|
+
var p;
|
|
185
|
+
n.stopPropagation(), g((p = t.tracking) == null ? void 0 : p.click), this.ctx.hostEl.dispatchEvent(new CustomEvent("hp:sponsorclick", { detail: { id: t.id, sponsor: t.sponsor.name } }));
|
|
186
|
+
})), e.setAttribute("aria-label", t.sponsor.name), t.sponsor.logo) {
|
|
187
|
+
const n = document.createElement("img");
|
|
188
|
+
n.src = t.sponsor.logo, n.alt = t.sponsor.name, n.decoding = "async", n.addEventListener("error", () => n.remove()), e.appendChild(n);
|
|
189
|
+
}
|
|
190
|
+
if ((l = t.logo) != null && l.label) {
|
|
191
|
+
const n = document.createElement("span");
|
|
192
|
+
n.className = "hp-sponsor-label", n.textContent = t.logo.label, e.appendChild(n);
|
|
193
|
+
}
|
|
194
|
+
for (const n of ["pointerdown", "dblclick"]) e.addEventListener(n, (p) => p.stopPropagation());
|
|
195
|
+
this.ctx.overlayEl.appendChild(e), this.logoEl = e, this.positionLogo();
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Logo kontrollerin üstüne binmesin: sağ üstte (dar player'da ayarlar / PiP oraya taşınır) üst çubuğun soluna,
|
|
199
|
+
* altta seek bar'ın hemen üstüne yerleşir. Dar player'da logo en fazla 48 px.
|
|
200
|
+
*/
|
|
201
|
+
positionLogo() {
|
|
202
|
+
var h, c;
|
|
203
|
+
const t = this.logoEl;
|
|
204
|
+
if (!t) return;
|
|
205
|
+
const e = this.ctx.overlayEl, o = e.hasAttribute("data-compact"), s = t.getAttribute("data-position");
|
|
206
|
+
t.style.removeProperty("right"), t.style.removeProperty("bottom"), t.toggleAttribute("data-compact", o);
|
|
207
|
+
const r = e.getBoundingClientRect();
|
|
208
|
+
if (s === "top-right") {
|
|
209
|
+
const l = (h = e.querySelector(".hp-top-bar")) == null ? void 0 : h.getBoundingClientRect();
|
|
210
|
+
l && l.width > 0 && (t.style.right = `${Math.round(r.right - l.left + 8)}px`);
|
|
211
|
+
} else if (s === "bottom-left" || s === "bottom-right") {
|
|
212
|
+
const l = (c = e.querySelector('[part="seek-bar"]')) == null ? void 0 : c.getBoundingClientRect();
|
|
213
|
+
l && l.height > 0 && (t.style.bottom = `${Math.round(r.bottom - l.top + 6)}px`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
showIntro(t) {
|
|
217
|
+
var h, c, l, n;
|
|
218
|
+
const e = this.key(t), o = (this.introCount.get(e) ?? 0) + 1;
|
|
219
|
+
this.introCount.set(e, o), this.watchedSinceIntro = 0, g((h = t.tracking) == null ? void 0 : h.intro), this.ctx.hostEl.dispatchEvent(new CustomEvent("hp:sponsorintro", { detail: { id: t.id, sponsor: t.sponsor.name, count: o } })), this.introTimer && clearTimeout(this.introTimer), (c = this.introEl) == null || c.remove();
|
|
220
|
+
const s = document.createElement("div");
|
|
221
|
+
if (s.className = "hp-sponsor-intro", s.setAttribute("part", "sponsor-intro"), s.setAttribute("role", "status"), t.sponsor.logo) {
|
|
222
|
+
const p = document.createElement("img");
|
|
223
|
+
p.src = t.sponsor.logo, p.alt = "", p.addEventListener("error", () => p.remove()), s.appendChild(p);
|
|
224
|
+
}
|
|
225
|
+
const r = document.createElement("span");
|
|
226
|
+
r.textContent = ((l = t.intro) == null ? void 0 : l.text) || this.ctx.i18n.sponsorPresents.replace("{name}", t.sponsor.name), s.appendChild(r), this.ctx.overlayEl.appendChild(s), this.introEl = s, this.ctx.hostEl.setAttribute("data-sponsor-intro", ""), this.introTimer = setTimeout(() => {
|
|
227
|
+
s.setAttribute("data-leaving", ""), this.ctx.hostEl.removeAttribute("data-sponsor-intro"), this.introTimer = setTimeout(() => {
|
|
228
|
+
s.remove(), this.introEl === s && (this.introEl = null);
|
|
229
|
+
}, 400);
|
|
230
|
+
}, ((n = t.intro) == null ? void 0 : n.durationMs) ?? 3500);
|
|
231
|
+
}
|
|
232
|
+
destroy() {
|
|
233
|
+
var t, e, o;
|
|
234
|
+
this.destroyed = !0, clearInterval(this.tickTimer), (t = this.resizeObserver) == null || t.disconnect(), this.refreshTimer && clearInterval(this.refreshTimer), this.introTimer && clearTimeout(this.introTimer), this.ctx.videoEl.removeEventListener("play", this.onPlay), this.ctx.hostEl.removeEventListener("hp:adstart", this.onAdStart), this.ctx.hostEl.removeEventListener("hp:adend", this.onAdEnd), this.applyTheme(null), (e = this.logoEl) == null || e.remove(), (o = this.introEl) == null || o.remove(), this.ctx.hostEl.removeAttribute("data-sponsored"), this.ctx.hostEl.removeAttribute("data-sponsor-hidden"), this.ctx.hostEl.removeAttribute("data-sponsor-intro");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function I(i, t) {
|
|
238
|
+
return new L(i, t);
|
|
239
|
+
}
|
|
240
|
+
export {
|
|
241
|
+
L as SponsorshipLayer,
|
|
242
|
+
I as installSponsorship,
|
|
243
|
+
A as normalizeSponsorship
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=index-D5P-LWbg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-D5P-LWbg.js","sources":["../../src/plugins/sponsorship/SponsorshipLayer.ts","../../src/plugins/sponsorship/index.ts"],"sourcesContent":["import type { SponsorshipConfig, SponsorshipOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\n\nexport interface SponsorshipContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n /** Logo ve giriş kartının ekleneceği alan (video alanı). */\n overlayEl: HTMLElement;\n i18n: HopeLocaleStrings;\n log(entry: { message: string; fatal?: boolean; details?: Record<string, string | number | boolean | undefined> }): void;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_LOGO_WIDTH = 96;\nconst DEFAULT_INTRO_MS = 3500;\n/** API'den gelen tema değerleri → player'ın CSS değişkenleri. */\nconst THEME_TOKENS: Record<keyof NonNullable<SponsorshipConfig['theme']>, string> = {\n accent: '--hp-color-accent',\n onAccent: '--hp-color-on-accent',\n surface: '--hp-color-surface',\n onSurface: '--hp-color-on-surface',\n};\nconst POSITIONS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'] as const;\n\n/** Yalnızca http(s) ya da göreli adresler — `javascript:` / `data:` gibi şemalar reddedilir. */\nfunction safeUrl(value: unknown): string | null {\n if (typeof value !== 'string' || !value.trim()) return null;\n try {\n const u = new URL(value, document.baseURI);\n return u.protocol === 'https:' || u.protocol === 'http:' ? u.href : null;\n } catch {\n return null;\n }\n}\n\nfunction safeColor(value: unknown): string | null {\n return typeof value === 'string' && value.length < 64 && CSS.supports('color', value) ? value : null;\n}\n\nfunction clamp(n: unknown, min: number, max: number, fallback: number): number {\n return typeof n === 'number' && Number.isFinite(n) ? Math.min(max, Math.max(min, n)) : fallback;\n}\n\n/** API yanıtını doğrular, geçersiz alanları atar; katman kapalıysa null. */\nexport function normalizeSponsorship(raw: unknown): SponsorshipConfig | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Partial<SponsorshipConfig>;\n if (r.active !== true || !r.sponsor || typeof r.sponsor.name !== 'string' || !r.sponsor.name.trim()) return null;\n const now = Date.now();\n const from = r.validFrom ? Date.parse(r.validFrom) : NaN;\n const until = r.validUntil ? Date.parse(r.validUntil) : NaN;\n if ((Number.isFinite(from) && now < from) || (Number.isFinite(until) && now > until)) return null;\n const theme: NonNullable<SponsorshipConfig['theme']> = {};\n for (const key of Object.keys(THEME_TOKENS) as Array<keyof typeof THEME_TOKENS>) {\n const c = safeColor(r.theme?.[key]);\n if (c) theme[key] = c;\n }\n const urls = (list: unknown): string[] => (Array.isArray(list) ? list.map(safeUrl).filter((u): u is string => !!u).slice(0, 10) : []);\n return {\n active: true,\n id: typeof r.id === 'string' ? r.id.slice(0, 120) : undefined,\n sponsor: {\n name: r.sponsor.name.slice(0, 80),\n logo: safeUrl(r.sponsor.logo) ?? undefined,\n url: safeUrl(r.sponsor.url) ?? undefined,\n },\n theme,\n logo: {\n position: POSITIONS.includes(r.logo?.position as (typeof POSITIONS)[number]) ? r.logo!.position : 'top-left',\n width: clamp(r.logo?.width, 32, 240, DEFAULT_LOGO_WIDTH),\n opacity: clamp(r.logo?.opacity, 0.2, 1, 0.9),\n label: typeof r.logo?.label === 'string' ? r.logo.label.slice(0, 40) : undefined,\n },\n intro: r.intro\n ? {\n text: typeof r.intro.text === 'string' ? r.intro.text.slice(0, 120) : undefined,\n durationMs: clamp(r.intro.durationMs, 1000, 15000, DEFAULT_INTRO_MS),\n repeatMinutes: typeof r.intro.repeatMinutes === 'number' && r.intro.repeatMinutes > 0 ? Math.min(240, Math.max(1, r.intro.repeatMinutes)) : undefined,\n maxShows: typeof r.intro.maxShows === 'number' && r.intro.maxShows >= 1 ? Math.min(100, Math.floor(r.intro.maxShows)) : undefined,\n }\n : undefined,\n tracking: { impression: urls(r.tracking?.impression), click: urls(r.tracking?.click), intro: urls(r.tracking?.intro) },\n };\n}\n\n/** Takip pikseli: yanıtı beklenmeyen GET (img beacon). */\nfunction fire(urls: string[] | undefined): void {\n for (const u of urls ?? []) {\n const img = new Image();\n img.referrerPolicy = 'no-referrer-when-downgrade';\n img.src = u;\n }\n}\n\n/**\n * Sponsorluk katmanı: `endpoint`'ten JSON çeker (SponsorshipConfig), player renklerini değiştirir, köşeye logo koyar,\n * oynatma başlarken \"X sunar\" kartını gösterir. Canlıda `refreshSeconds` ile kampanya değişimi izlenir. API hatasında\n * son geçerli ayar korunur; hiç alınamadıysa katman kapalı kalır — player normal çalışır.\n */\nexport class SponsorshipLayer {\n private options: SponsorshipOptions;\n private config: SponsorshipConfig | null = null;\n private logoEl: HTMLAnchorElement | HTMLDivElement | null = null;\n private introEl: HTMLDivElement | null = null;\n private introTimer: ReturnType<typeof setTimeout> | null = null;\n private refreshTimer: ReturnType<typeof setInterval> | null = null;\n /** Player boyutu / kontrol düzeni değişince logo kontrollerin üstüne binmesin diye yeniden konumlanır. */\n private readonly resizeObserver: ResizeObserver | null;\n /** Uygulanan tema değişkenlerinin önceki satır içi değerleri — katman kalkınca geri yüklenir. */\n private previousTokens = new Map<string, string>();\n /** Gösterim pikseli kampanya başına bir kez. */\n private impressed = new Set<string>();\n /** Kampanya başına giriş gösterim sayısı. */\n private introCount = new Map<string, number>();\n /** Son girişten bu yana gerçek izleme süresi (ms) — intro.repeatMinutes için. */\n private watchedSinceIntro = 0;\n private lastTick = 0;\n private readonly tickTimer: ReturnType<typeof setInterval>;\n private destroyed = false;\n private requestSeq = 0;\n\n constructor(\n private readonly ctx: SponsorshipContext,\n options: SponsorshipOptions\n ) {\n this.options = options;\n ctx.videoEl.addEventListener('play', this.onPlay);\n ctx.hostEl.addEventListener('hp:adstart', this.onAdStart);\n ctx.hostEl.addEventListener('hp:adend', this.onAdEnd);\n this.lastTick = performance.now();\n this.tickTimer = setInterval(this.tick, 1000);\n this.resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => this.positionLogo()) : null;\n this.resizeObserver?.observe(ctx.overlayEl);\n const topBar = ctx.overlayEl.querySelector('.hp-top-bar');\n if (topBar) this.resizeObserver?.observe(topBar);\n void this.load();\n this.scheduleRefresh();\n }\n\n update(options: SponsorshipOptions): void {\n const changed = options.endpoint !== this.options.endpoint || JSON.stringify(options.params) !== JSON.stringify(this.options.params);\n const refreshChanged = options.refreshSeconds !== this.options.refreshSeconds;\n this.options = options;\n if (changed) void this.load();\n if (refreshChanged) this.scheduleRefresh();\n }\n\n /** Şu an uygulanan kampanya (yoksa null). */\n get current(): SponsorshipConfig | null {\n return this.config;\n }\n\n private scheduleRefresh(): void {\n if (this.refreshTimer) clearInterval(this.refreshTimer);\n this.refreshTimer = null;\n const s = this.options.refreshSeconds;\n if (typeof s === 'number' && s >= 10) this.refreshTimer = setInterval(() => void this.load(), s * 1000);\n }\n\n private buildUrl(): string {\n const u = new URL(this.options.endpoint, document.baseURI);\n for (const [k, v] of Object.entries(this.options.params ?? {})) u.searchParams.set(k, v);\n return u.href;\n }\n\n private async load(): Promise<void> {\n const seq = ++this.requestSeq;\n const ctrl = typeof AbortController !== 'undefined' ? new AbortController() : null;\n const timer = setTimeout(() => ctrl?.abort(), this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n let url = '';\n try {\n url = this.buildUrl();\n const res = await fetch(url, { ...this.options.fetchInit, signal: ctrl?.signal });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const json: unknown = await res.json();\n if (this.destroyed || seq !== this.requestSeq) return; // daha yeni bir istek var\n this.apply(normalizeSponsorship(json));\n } catch (err) {\n if (this.destroyed || seq !== this.requestSeq) return;\n // Son geçerli kampanya korunur — geçici API hatası katmanı söndürmesin.\n this.ctx.log({ message: `Sponsorship API failed: ${String(err)}`, details: { url } });\n } finally {\n clearTimeout(timer);\n }\n }\n\n private apply(config: SponsorshipConfig | null): void {\n const prevKey = this.key(this.config);\n this.config = config;\n this.applyTheme(config?.theme ?? null);\n this.renderLogo();\n this.ctx.hostEl.toggleAttribute('data-sponsored', !!config);\n if (this.key(config) !== prevKey) {\n this.watchedSinceIntro = 0;\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:sponsorship', { detail: { config } }));\n // Yeni kampanya oynarken geldiyse (canlı yenileme) girişi hemen göster.\n if (config && !this.ctx.videoEl.paused) this.onPlay();\n }\n }\n\n private key(c: SponsorshipConfig | null): string {\n return c ? c.id || c.sponsor.name : '';\n }\n\n private applyTheme(theme: SponsorshipConfig['theme'] | null): void {\n const style = this.ctx.hostEl.style;\n // Önce önceki kampanyanın değerlerini geri al.\n for (const [prop, value] of this.previousTokens) {\n if (value) style.setProperty(prop, value);\n else style.removeProperty(prop);\n }\n this.previousTokens.clear();\n if (!theme) return;\n for (const [key, prop] of Object.entries(THEME_TOKENS) as Array<[keyof typeof THEME_TOKENS, string]>) {\n const value = theme[key];\n if (!value) continue;\n this.previousTokens.set(prop, style.getPropertyValue(prop));\n style.setProperty(prop, value);\n }\n }\n\n private renderLogo(): void {\n this.logoEl?.remove();\n this.logoEl = null;\n const c = this.config;\n if (!c || (!c.sponsor.logo && !c.logo?.label)) return;\n const el = c.sponsor.url ? document.createElement('a') : document.createElement('div');\n el.className = 'hp-sponsor-logo';\n el.setAttribute('part', 'sponsor-logo');\n el.setAttribute('data-position', c.logo?.position ?? 'top-left');\n el.style.setProperty('--hp-sponsor-logo-w', `${c.logo?.width ?? DEFAULT_LOGO_WIDTH}px`);\n el.style.opacity = String(c.logo?.opacity ?? 0.9);\n if (el instanceof HTMLAnchorElement) {\n el.href = c.sponsor.url!;\n el.target = '_blank';\n el.rel = 'noopener sponsored';\n el.addEventListener('click', (e) => {\n e.stopPropagation();\n fire(c.tracking?.click);\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:sponsorclick', { detail: { id: c.id, sponsor: c.sponsor.name } }));\n });\n }\n el.setAttribute('aria-label', c.sponsor.name);\n if (c.sponsor.logo) {\n const img = document.createElement('img');\n img.src = c.sponsor.logo;\n img.alt = c.sponsor.name;\n img.decoding = 'async';\n img.addEventListener('error', () => img.remove());\n el.appendChild(img);\n }\n // Etiket logonun altında, ortalı.\n if (c.logo?.label) {\n const label = document.createElement('span');\n label.className = 'hp-sponsor-label';\n label.textContent = c.logo.label;\n el.appendChild(label);\n }\n for (const t of ['pointerdown', 'dblclick'] as const) el.addEventListener(t, (e) => e.stopPropagation());\n this.ctx.overlayEl.appendChild(el);\n this.logoEl = el;\n this.positionLogo();\n }\n\n /**\n * Logo kontrollerin üstüne binmesin: sağ üstte (dar player'da ayarlar / PiP oraya taşınır) üst çubuğun soluna,\n * altta seek bar'ın hemen üstüne yerleşir. Dar player'da logo en fazla 48 px.\n */\n private positionLogo(): void {\n const el = this.logoEl;\n if (!el) return;\n const area = this.ctx.overlayEl;\n const compact = area.hasAttribute('data-compact');\n const position = el.getAttribute('data-position');\n el.style.removeProperty('right');\n el.style.removeProperty('bottom');\n el.toggleAttribute('data-compact', compact);\n const a = area.getBoundingClientRect();\n if (position === 'top-right') {\n const bar = area.querySelector('.hp-top-bar')?.getBoundingClientRect();\n if (bar && bar.width > 0) el.style.right = `${Math.round(a.right - bar.left + 8)}px`;\n } else if (position === 'bottom-left' || position === 'bottom-right') {\n const seek = area.querySelector('[part=\"seek-bar\"]')?.getBoundingClientRect();\n if (seek && seek.height > 0) el.style.bottom = `${Math.round(a.bottom - seek.top + 6)}px`;\n }\n }\n\n /** Oynatma başladı: kampanya başına bir kez gösterim pikseli + \"X sunar\" kartı. */\n private readonly onPlay = (): void => {\n const c = this.config;\n if (!c) return;\n const key = this.key(c);\n if (!this.impressed.has(key)) {\n this.impressed.add(key);\n fire(c.tracking?.impression);\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:sponsorimpression', { detail: { id: c.id, sponsor: c.sponsor.name } }));\n }\n if (c.intro && !this.introCount.has(key)) this.showIntro(c);\n };\n\n /**\n * intro.repeatMinutes: yalnızca gerçekten izlenirken sayar (oynuyor, sekme önde, reklam yok); süre dolunca giriş\n * tekrar gösterilir — maxShows'a kadar.\n */\n private readonly tick = (): void => {\n const now = performance.now();\n // Sekme uyuyunca setInterval seyrekleşir — tek seferde en fazla 2 sn sayılır.\n const delta = Math.min(2000, Math.max(0, now - this.lastTick));\n this.lastTick = now;\n const c = this.config;\n const repeat = c?.intro?.repeatMinutes;\n if (!c || !repeat) return;\n const watching =\n !this.ctx.videoEl.paused && !this.ctx.videoEl.ended && !document.hidden && !this.ctx.hostEl.hasAttribute('data-sponsor-hidden');\n if (!watching || !this.introCount.has(this.key(c))) return;\n this.watchedSinceIntro += delta;\n if (this.watchedSinceIntro < repeat * 60_000) return;\n const max = c.intro?.maxShows;\n if (max && (this.introCount.get(this.key(c)) ?? 0) >= max) return;\n this.showIntro(c);\n };\n\n private showIntro(c: SponsorshipConfig): void {\n const key = this.key(c);\n const count = (this.introCount.get(key) ?? 0) + 1;\n this.introCount.set(key, count);\n this.watchedSinceIntro = 0;\n fire(c.tracking?.intro);\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:sponsorintro', { detail: { id: c.id, sponsor: c.sponsor.name, count } }));\n if (this.introTimer) clearTimeout(this.introTimer);\n this.introEl?.remove();\n const el = document.createElement('div');\n el.className = 'hp-sponsor-intro';\n el.setAttribute('part', 'sponsor-intro');\n el.setAttribute('role', 'status');\n if (c.sponsor.logo) {\n const img = document.createElement('img');\n img.src = c.sponsor.logo;\n img.alt = '';\n img.addEventListener('error', () => img.remove());\n el.appendChild(img);\n }\n const text = document.createElement('span');\n text.textContent = c.intro?.text || this.ctx.i18n.sponsorPresents.replace('{name}', c.sponsor.name);\n el.appendChild(text);\n this.ctx.overlayEl.appendChild(el);\n this.introEl = el;\n // Giriş kartı sponsoru zaten gösteriyor — kart görünürken köşe logosu gizli (küçük player'da üst üste binmesin).\n this.ctx.hostEl.setAttribute('data-sponsor-intro', '');\n this.introTimer = setTimeout(() => {\n el.setAttribute('data-leaving', '');\n this.ctx.hostEl.removeAttribute('data-sponsor-intro');\n this.introTimer = setTimeout(() => {\n el.remove();\n if (this.introEl === el) this.introEl = null;\n }, 400);\n }, c.intro?.durationMs ?? DEFAULT_INTRO_MS);\n }\n\n /** Lineer reklam sırasında logo / giriş gizlenir (reklamın üstüne binmesin). */\n private readonly onAdStart = (e: Event): void => {\n if ((e as CustomEvent<{ linear?: boolean }>).detail?.linear === false) return;\n this.ctx.hostEl.setAttribute('data-sponsor-hidden', '');\n };\n\n private readonly onAdEnd = (e: Event): void => {\n if ((e as CustomEvent<{ linear?: boolean }>).detail?.linear === false) return;\n this.ctx.hostEl.removeAttribute('data-sponsor-hidden');\n };\n\n destroy(): void {\n this.destroyed = true;\n clearInterval(this.tickTimer);\n this.resizeObserver?.disconnect();\n if (this.refreshTimer) clearInterval(this.refreshTimer);\n if (this.introTimer) clearTimeout(this.introTimer);\n this.ctx.videoEl.removeEventListener('play', this.onPlay);\n this.ctx.hostEl.removeEventListener('hp:adstart', this.onAdStart);\n this.ctx.hostEl.removeEventListener('hp:adend', this.onAdEnd);\n this.applyTheme(null);\n this.logoEl?.remove();\n this.introEl?.remove();\n this.ctx.hostEl.removeAttribute('data-sponsored');\n this.ctx.hostEl.removeAttribute('data-sponsor-hidden');\n this.ctx.hostEl.removeAttribute('data-sponsor-intro');\n }\n}\n","import { SponsorshipLayer, normalizeSponsorship, type SponsorshipContext } from './SponsorshipLayer';\nimport type { SponsorshipOptions } from '../../types';\n\n/** Sponsorluk katmanını kurar (ayarları `endpoint`'ten alır). */\nexport function installSponsorship(ctx: SponsorshipContext, options: SponsorshipOptions): SponsorshipLayer {\n return new SponsorshipLayer(ctx, options);\n}\n\nexport { SponsorshipLayer, normalizeSponsorship };\nexport type { SponsorshipContext };\n"],"names":["THEME_TOKENS","POSITIONS","safeUrl","value","u","safeColor","clamp","n","min","max","fallback","normalizeSponsorship","raw","_a","_b","_c","_d","_e","_f","_g","_h","r","now","from","until","theme","key","c","urls","list","fire","img","SponsorshipLayer","ctx","options","__publicField","delta","repeat","e","topBar","changed","refreshChanged","s","k","v","seq","ctrl","timer","url","res","json","err","config","prevKey","style","prop","el","label","t","area","compact","position","a","bar","seek","count","text","installSponsorship"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var u = Object.defineProperty;
|
|
2
2
|
var m = (p, e, t) => e in p ? u(p, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : p[e] = t;
|
|
3
3
|
var o = (p, e, t) => m(p, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
-
import { c as b } from "./index-
|
|
4
|
+
import { c as b } from "./index-w7pACyTw.js";
|
|
5
5
|
const f = {
|
|
6
6
|
enabled: !1,
|
|
7
7
|
mode: "rich",
|
|
@@ -202,4 +202,4 @@ export {
|
|
|
202
202
|
v as MarkProgress,
|
|
203
203
|
y as installMarkers
|
|
204
204
|
};
|
|
205
|
-
//# sourceMappingURL=index-
|
|
205
|
+
//# sourceMappingURL=index-DRlQC-ev.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DcVUXkXo.js","sources":["../../src/plugins/markers/MarkProgress.ts","../../src/plugins/markers/index.ts"],"sourcesContent":["import { createIcon } from '../../icons/Icon';\nimport type { MarkerItem, MarkerPingOptions, MarkerPopupOptions, MarkersOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\n\nexport interface MarkersPlayerContext {\n videoEl: HTMLVideoElement;\n /** Popup overlay'in ekleneceği katman (shadow root içinde, video üzerinde). */\n overlayContainerEl: HTMLElement;\n /** Seek bar üzerinde işaretçi çizmek için — SeekBar.addMarker ile aynı imza. */\n addSeekBarMarker(ratio: number, extraClass?: string): HTMLDivElement;\n i18n: HopeLocaleStrings;\n}\n\ninterface NormalizedMarker extends Required<Pick<MarkerItem, 'time'>> {\n idx: number;\n color?: string;\n label: string;\n pauseOnHit: boolean;\n once: boolean;\n tolerance: number;\n cooldownMs: number;\n action?: MarkerItem['action'];\n popup: MarkerPopupOptions | null;\n pingUrl: string;\n el?: HTMLElement;\n}\n\nconst POPUP_DEFAULTS: Required<MarkerPopupOptions> = {\n enabled: false,\n mode: 'rich',\n text: '',\n imageUrl: '',\n imageAlt: '',\n linkUrl: '',\n // Boş bırakılıyor (sentinel) — gerçek varsayılan metin showPopup()'ta\n // `ctx.i18n.markerLearnMore`/`markerContinue`'dan okunuyor, dil\n // değişimini takip edebilsin diye burada SABİT bir dilde gömülü değil.\n linkText: '',\n continueText: '',\n showContinue: true,\n showClose: true,\n autoplayOnClose: true,\n autoplayOnContinue: true,\n};\n\nconst PING_DEFAULTS: Required<MarkerPingOptions> = { enabled: false, url: '', method: 'GET', includeMarker: false };\n\n/** Zaman tabanlı seek bar işaretçileri — seek/jump koruması, once/cooldown, popup/ping/aksiyon. */\nexport class MarkProgress {\n private readonly markers: NormalizedMarker[];\n private readonly popupGlobal: Required<MarkerPopupOptions>;\n private readonly pingGlobal: Required<MarkerPingOptions>;\n private readonly triggerOnSeek: boolean;\n private readonly seekJumpThresholdSec: number;\n private readonly seekIgnoreWindowMs: number;\n\n private hitSet = new Set<string>();\n private lastHitAt = new Map<string, number>();\n private lastTime = 0;\n private isSeeking = false;\n private ignoreUntilTs = 0;\n private popupEl: HTMLElement | null = null;\n\n constructor(\n private readonly ctx: MarkersPlayerContext,\n options: MarkersOptions\n ) {\n this.triggerOnSeek = options.triggerOnSeek === true;\n this.seekJumpThresholdSec = options.seekJumpThresholdSec ?? 1;\n this.seekIgnoreWindowMs = options.seekIgnoreWindowMs ?? 250;\n this.popupGlobal = { ...POPUP_DEFAULTS, ...options.popup };\n this.pingGlobal = { ...PING_DEFAULTS, ...options.ping };\n\n this.markers = (options.items || [])\n .map((m, idx) => this.normalize(m, idx))\n .filter((m) => Number.isFinite(m.time) && m.time >= 0)\n .sort((a, b) => a.time - b.time);\n\n ctx.videoEl.addEventListener('loadedmetadata', this.onLoadedMetadata);\n ctx.videoEl.addEventListener('timeupdate', this.onTimeUpdate);\n ctx.videoEl.addEventListener('seeking', this.onSeeking);\n ctx.videoEl.addEventListener('seeked', this.onSeeked);\n\n if (ctx.videoEl.readyState >= 1) this.onLoadedMetadata();\n }\n\n /** Popup lazy oluşturulup yeniden kullanılıyor (`ensurePopup`) — zaten açıksa close butonunun statik etiketini tazeler. */\n refreshLabels(): void {\n const closeBtn = this.popupEl?.querySelector('button') as HTMLButtonElement | null;\n if (closeBtn) {\n closeBtn.setAttribute('aria-label', this.ctx.i18n.close);\n }\n }\n\n destroy(): void {\n this.ctx.videoEl.removeEventListener('loadedmetadata', this.onLoadedMetadata);\n this.ctx.videoEl.removeEventListener('timeupdate', this.onTimeUpdate);\n this.ctx.videoEl.removeEventListener('seeking', this.onSeeking);\n this.ctx.videoEl.removeEventListener('seeked', this.onSeeked);\n this.markers.forEach((m) => m.el?.remove());\n this.popupEl?.remove();\n this.popupEl = null;\n this.hitSet.clear();\n this.lastHitAt.clear();\n }\n\n private normalize(m: MarkerItem, idx: number): NormalizedMarker {\n return {\n idx,\n time: Number(m.time),\n color: m.color,\n label: m.label ?? '',\n pauseOnHit: m.pauseOnHit ?? true,\n once: m.once ?? true,\n tolerance: m.tolerance ?? 0.25,\n cooldownMs: m.cooldownMs ?? 600,\n action: m.action,\n popup: m.popup ?? null,\n pingUrl: m.pingUrl ?? '',\n };\n }\n\n private readonly onLoadedMetadata = (): void => {\n const duration = this.ctx.videoEl.duration;\n if (!Number.isFinite(duration) || duration <= 0) return;\n\n this.markers.forEach((m) => {\n if (m.el) return;\n const el = this.ctx.addSeekBarMarker(m.time / duration);\n if (m.color) el.style.backgroundColor = m.color;\n if (m.label) el.title = m.label;\n m.el = el;\n });\n\n this.lastTime = this.ctx.videoEl.currentTime || 0;\n };\n\n private readonly onSeeking = (): void => {\n this.isSeeking = true;\n this.ignoreUntilTs = Date.now() + this.seekIgnoreWindowMs;\n this.lastTime = this.ctx.videoEl.currentTime || 0;\n };\n\n private readonly onSeeked = (): void => {\n this.lastTime = this.ctx.videoEl.currentTime || 0;\n this.isSeeking = false;\n this.ignoreUntilTs = Date.now() + this.seekIgnoreWindowMs;\n };\n\n private readonly onTimeUpdate = (): void => {\n const now = Date.now();\n if (now < this.ignoreUntilTs) return;\n if (this.isSeeking) return;\n\n const t = this.ctx.videoEl.currentTime;\n if (!Number.isFinite(t)) return;\n\n const jumped = Math.abs(t - this.lastTime) >= this.seekJumpThresholdSec;\n if (jumped && !this.triggerOnSeek) {\n this.lastTime = t;\n return;\n }\n\n for (const m of this.markers) {\n const key = `${m.time}-${m.idx}`;\n if (m.once && this.hitSet.has(key)) continue;\n if (!m.once) {\n const last = this.lastHitAt.get(key) || 0;\n if (now - last < m.cooldownMs) continue;\n }\n\n const crossed = this.lastTime < m.time && t >= m.time - m.tolerance;\n if (!crossed) continue;\n\n if (m.once) this.hitSet.add(key);\n else this.lastHitAt.set(key, now);\n\n if (m.pauseOnHit) this.ctx.videoEl.pause();\n\n this.firePing(m);\n this.fireAction(m);\n\n const popupCfg = m.popup ? { ...this.popupGlobal, ...m.popup } : this.popupGlobal;\n if (popupCfg.enabled) {\n this.ctx.videoEl.pause();\n this.showPopup(popupCfg);\n }\n break;\n }\n\n this.lastTime = t;\n };\n\n private resolveUrlTemplate(url: string, m: NormalizedMarker): string {\n if (!url) return '';\n return url.replaceAll('{time}', encodeURIComponent(String(m.time))).replaceAll('{label}', encodeURIComponent(m.label));\n }\n\n private firePing(m: NormalizedMarker): void {\n const baseUrl = m.pingUrl || this.pingGlobal.url;\n const url = this.resolveUrlTemplate(baseUrl, m);\n if (!this.pingGlobal.enabled || !url) return;\n\n try {\n if (this.pingGlobal.method === 'POST') {\n fetch(url, {\n method: 'POST',\n keepalive: true,\n headers: this.pingGlobal.includeMarker ? { 'Content-Type': 'application/json' } : undefined,\n body: this.pingGlobal.includeMarker ? JSON.stringify({ time: m.time, label: m.label, ts: Date.now() }) : undefined,\n }).catch(() => {});\n } else {\n fetch(url, { method: 'GET', keepalive: true }).catch(() => {});\n }\n } catch {\n /* no-op */\n }\n }\n\n private fireAction(m: NormalizedMarker): void {\n const a = m.action;\n if (!a) return;\n\n if (a.type === 'log') {\n console.log('[HopePlayer markers]', a.name || 'marker_hit', { time: m.time, label: m.label }, a.payload);\n return;\n }\n\n if (a.type === 'datalayer') {\n try {\n const w = window as unknown as { dataLayer?: unknown[] };\n w.dataLayer = w.dataLayer || [];\n w.dataLayer.push({\n event: 'HopePlayerVideoEvents',\n trigger: a.name || 'marker_hit',\n marker: { time: m.time, label: m.label, color: m.color },\n payload: a.payload ?? {},\n ts: Date.now(),\n });\n } catch {\n /* no-op */\n }\n return;\n }\n\n if (a.type === 'custom') {\n const fn = a.name ? (window as unknown as Record<string, unknown>)[a.name] : null;\n if (typeof fn === 'function') {\n try {\n (fn as (ctx: unknown) => void)({ marker: m, payload: a.payload });\n } catch (err) {\n console.warn('[HopePlayer markers] custom action fonksiyonu hata verdi:', err);\n }\n } else {\n console.warn('[HopePlayer markers] custom action fonksiyonu bulunamadı: window.' + a.name);\n }\n }\n }\n\n private ensurePopup(): HTMLElement {\n if (this.popupEl) return this.popupEl;\n\n const overlay = document.createElement('div');\n overlay.setAttribute('part', 'marker-popup');\n overlay.className = 'hp:hidden hp:absolute hp:inset-0 hp:z-30 hp:items-center hp:justify-center hp:bg-black/70';\n\n const panel = document.createElement('div');\n panel.className = 'hp:relative hp:max-w-[85%] hp:bg-surface-elev hp:text-on-surface hp:rounded-lg hp:p-4 hp:text-center hp:shadow-xl';\n panel.setAttribute('role', 'dialog');\n panel.setAttribute('aria-modal', 'true');\n\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.setAttribute('aria-label', this.ctx.i18n.close);\n closeBtn.className = 'hp:absolute hp:top-1 hp:right-1 hp:w-6 hp:h-6 hp:flex hp:items-center hp:justify-center hp:bg-transparent hp:border-0 hp:cursor-pointer hp:text-on-surface';\n closeBtn.appendChild(createIcon('close', 'hp:text-sm'));\n\n const mediaWrap = document.createElement('div');\n mediaWrap.className = 'hp:hidden hp:mb-2';\n const img = document.createElement('img');\n img.className = 'hp:max-w-full hp:rounded';\n mediaWrap.appendChild(img);\n\n const textEl = document.createElement('div');\n textEl.className = 'hp:text-sm hp:mb-2';\n\n const linkEl = document.createElement('a');\n linkEl.target = '_blank';\n linkEl.rel = 'noopener noreferrer';\n linkEl.className = 'hp:hidden hp:text-accent hp:underline hp:text-sm hp:block hp:mb-2';\n\n const continueBtn = document.createElement('button');\n continueBtn.type = 'button';\n continueBtn.className = 'hp:hidden hp:px-4 hp:py-1.5 hp:rounded hp:bg-accent hp:text-on-accent hp:border-0 hp:cursor-pointer hp:text-sm';\n\n panel.append(closeBtn, mediaWrap, textEl, linkEl, continueBtn);\n overlay.appendChild(panel);\n this.ctx.overlayContainerEl.appendChild(overlay);\n this.popupEl = overlay;\n return overlay;\n }\n\n private hidePopup(): void {\n this.popupEl?.classList.add('hp:hidden');\n this.popupEl?.classList.remove('hp:flex');\n }\n\n private safePlay(): void {\n void this.ctx.videoEl.play().catch(() => {});\n }\n\n private showPopup(cfg: Required<MarkerPopupOptions>): void {\n const el = this.ensurePopup();\n const textEl = el.querySelector('div.hp\\\\:text-sm.hp\\\\:mb-2:not(.hp\\\\:hidden)') as HTMLElement | null;\n const mediaWrap = el.querySelector('div.hp\\\\:mb-2') as HTMLElement | null;\n const img = el.querySelector('img') as HTMLImageElement | null;\n const linkEl = el.querySelector('a') as HTMLAnchorElement | null;\n const continueBtn = el.querySelectorAll('button')[1] as HTMLButtonElement | null;\n const closeBtn = el.querySelector('button') as HTMLButtonElement | null;\n\n if (closeBtn) closeBtn.style.display = cfg.showClose === false ? 'none' : '';\n if (textEl) textEl.textContent = cfg.text || '';\n\n const isRich = cfg.mode === 'rich';\n if (mediaWrap && img) {\n if (isRich && cfg.imageUrl) {\n mediaWrap.classList.remove('hp:hidden');\n img.src = cfg.imageUrl;\n img.alt = cfg.imageAlt || '';\n } else {\n mediaWrap.classList.add('hp:hidden');\n img.removeAttribute('src');\n }\n }\n\n if (linkEl) {\n if (isRich && cfg.linkUrl) {\n linkEl.classList.remove('hp:hidden');\n linkEl.href = cfg.linkUrl;\n linkEl.textContent = cfg.linkText || this.ctx.i18n.markerLearnMore;\n } else {\n linkEl.classList.add('hp:hidden');\n linkEl.removeAttribute('href');\n }\n }\n\n if (continueBtn) {\n if (cfg.showContinue) {\n continueBtn.classList.remove('hp:hidden');\n continueBtn.textContent = cfg.continueText || this.ctx.i18n.markerContinue;\n } else {\n continueBtn.classList.add('hp:hidden');\n }\n }\n\n const newClose = closeBtn?.cloneNode(true) as HTMLButtonElement | undefined;\n if (closeBtn && newClose) closeBtn.replaceWith(newClose);\n const newCont = continueBtn?.cloneNode(true) as HTMLButtonElement | undefined;\n if (continueBtn && newCont) continueBtn.replaceWith(newCont);\n\n newClose?.addEventListener('click', () => {\n this.hidePopup();\n if (cfg.autoplayOnClose) this.safePlay();\n });\n newCont?.addEventListener('click', () => {\n this.hidePopup();\n if (cfg.autoplayOnContinue) this.safePlay();\n });\n\n el.classList.remove('hp:hidden');\n el.classList.add('hp:flex');\n }\n}\n","import { MarkProgress, type MarkersPlayerContext } from './MarkProgress';\nimport type { MarkersOptions } from '../../types';\n\nexport function installMarkers(ctx: MarkersPlayerContext, options: MarkersOptions): MarkProgress {\n return new MarkProgress(ctx, options);\n}\n\nexport { MarkProgress };\nexport type { MarkersPlayerContext };\n"],"names":["POPUP_DEFAULTS","PING_DEFAULTS","MarkProgress","ctx","options","__publicField","duration","m","el","now","key","last","popupCfg","idx","a","b","closeBtn","_a","url","baseUrl","w","fn","err","overlay","panel","createIcon","mediaWrap","img","textEl","linkEl","continueBtn","_b","cfg","isRich","newClose","newCont","installMarkers"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-DRlQC-ev.js","sources":["../../src/plugins/markers/MarkProgress.ts","../../src/plugins/markers/index.ts"],"sourcesContent":["import { createIcon } from '../../icons/Icon';\nimport type { MarkerItem, MarkerPingOptions, MarkerPopupOptions, MarkersOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\n\nexport interface MarkersPlayerContext {\n videoEl: HTMLVideoElement;\n /** Popup overlay'in ekleneceği katman (shadow root içinde, video üzerinde). */\n overlayContainerEl: HTMLElement;\n /** Seek bar üzerinde işaretçi çizmek için — SeekBar.addMarker ile aynı imza. */\n addSeekBarMarker(ratio: number, extraClass?: string): HTMLDivElement;\n i18n: HopeLocaleStrings;\n}\n\ninterface NormalizedMarker extends Required<Pick<MarkerItem, 'time'>> {\n idx: number;\n color?: string;\n label: string;\n pauseOnHit: boolean;\n once: boolean;\n tolerance: number;\n cooldownMs: number;\n action?: MarkerItem['action'];\n popup: MarkerPopupOptions | null;\n pingUrl: string;\n el?: HTMLElement;\n}\n\nconst POPUP_DEFAULTS: Required<MarkerPopupOptions> = {\n enabled: false,\n mode: 'rich',\n text: '',\n imageUrl: '',\n imageAlt: '',\n linkUrl: '',\n // Boş bırakılıyor (sentinel) — gerçek varsayılan metin showPopup()'ta\n // `ctx.i18n.markerLearnMore`/`markerContinue`'dan okunuyor, dil\n // değişimini takip edebilsin diye burada SABİT bir dilde gömülü değil.\n linkText: '',\n continueText: '',\n showContinue: true,\n showClose: true,\n autoplayOnClose: true,\n autoplayOnContinue: true,\n};\n\nconst PING_DEFAULTS: Required<MarkerPingOptions> = { enabled: false, url: '', method: 'GET', includeMarker: false };\n\n/** Zaman tabanlı seek bar işaretçileri — seek/jump koruması, once/cooldown, popup/ping/aksiyon. */\nexport class MarkProgress {\n private readonly markers: NormalizedMarker[];\n private readonly popupGlobal: Required<MarkerPopupOptions>;\n private readonly pingGlobal: Required<MarkerPingOptions>;\n private readonly triggerOnSeek: boolean;\n private readonly seekJumpThresholdSec: number;\n private readonly seekIgnoreWindowMs: number;\n\n private hitSet = new Set<string>();\n private lastHitAt = new Map<string, number>();\n private lastTime = 0;\n private isSeeking = false;\n private ignoreUntilTs = 0;\n private popupEl: HTMLElement | null = null;\n\n constructor(\n private readonly ctx: MarkersPlayerContext,\n options: MarkersOptions\n ) {\n this.triggerOnSeek = options.triggerOnSeek === true;\n this.seekJumpThresholdSec = options.seekJumpThresholdSec ?? 1;\n this.seekIgnoreWindowMs = options.seekIgnoreWindowMs ?? 250;\n this.popupGlobal = { ...POPUP_DEFAULTS, ...options.popup };\n this.pingGlobal = { ...PING_DEFAULTS, ...options.ping };\n\n this.markers = (options.items || [])\n .map((m, idx) => this.normalize(m, idx))\n .filter((m) => Number.isFinite(m.time) && m.time >= 0)\n .sort((a, b) => a.time - b.time);\n\n ctx.videoEl.addEventListener('loadedmetadata', this.onLoadedMetadata);\n ctx.videoEl.addEventListener('timeupdate', this.onTimeUpdate);\n ctx.videoEl.addEventListener('seeking', this.onSeeking);\n ctx.videoEl.addEventListener('seeked', this.onSeeked);\n\n if (ctx.videoEl.readyState >= 1) this.onLoadedMetadata();\n }\n\n /** Popup lazy oluşturulup yeniden kullanılıyor (`ensurePopup`) — zaten açıksa close butonunun statik etiketini tazeler. */\n refreshLabels(): void {\n const closeBtn = this.popupEl?.querySelector('button') as HTMLButtonElement | null;\n if (closeBtn) {\n closeBtn.setAttribute('aria-label', this.ctx.i18n.close);\n }\n }\n\n destroy(): void {\n this.ctx.videoEl.removeEventListener('loadedmetadata', this.onLoadedMetadata);\n this.ctx.videoEl.removeEventListener('timeupdate', this.onTimeUpdate);\n this.ctx.videoEl.removeEventListener('seeking', this.onSeeking);\n this.ctx.videoEl.removeEventListener('seeked', this.onSeeked);\n this.markers.forEach((m) => m.el?.remove());\n this.popupEl?.remove();\n this.popupEl = null;\n this.hitSet.clear();\n this.lastHitAt.clear();\n }\n\n private normalize(m: MarkerItem, idx: number): NormalizedMarker {\n return {\n idx,\n time: Number(m.time),\n color: m.color,\n label: m.label ?? '',\n pauseOnHit: m.pauseOnHit ?? true,\n once: m.once ?? true,\n tolerance: m.tolerance ?? 0.25,\n cooldownMs: m.cooldownMs ?? 600,\n action: m.action,\n popup: m.popup ?? null,\n pingUrl: m.pingUrl ?? '',\n };\n }\n\n private readonly onLoadedMetadata = (): void => {\n const duration = this.ctx.videoEl.duration;\n if (!Number.isFinite(duration) || duration <= 0) return;\n\n this.markers.forEach((m) => {\n if (m.el) return;\n const el = this.ctx.addSeekBarMarker(m.time / duration);\n if (m.color) el.style.backgroundColor = m.color;\n if (m.label) el.title = m.label;\n m.el = el;\n });\n\n this.lastTime = this.ctx.videoEl.currentTime || 0;\n };\n\n private readonly onSeeking = (): void => {\n this.isSeeking = true;\n this.ignoreUntilTs = Date.now() + this.seekIgnoreWindowMs;\n this.lastTime = this.ctx.videoEl.currentTime || 0;\n };\n\n private readonly onSeeked = (): void => {\n this.lastTime = this.ctx.videoEl.currentTime || 0;\n this.isSeeking = false;\n this.ignoreUntilTs = Date.now() + this.seekIgnoreWindowMs;\n };\n\n private readonly onTimeUpdate = (): void => {\n const now = Date.now();\n if (now < this.ignoreUntilTs) return;\n if (this.isSeeking) return;\n\n const t = this.ctx.videoEl.currentTime;\n if (!Number.isFinite(t)) return;\n\n const jumped = Math.abs(t - this.lastTime) >= this.seekJumpThresholdSec;\n if (jumped && !this.triggerOnSeek) {\n this.lastTime = t;\n return;\n }\n\n for (const m of this.markers) {\n const key = `${m.time}-${m.idx}`;\n if (m.once && this.hitSet.has(key)) continue;\n if (!m.once) {\n const last = this.lastHitAt.get(key) || 0;\n if (now - last < m.cooldownMs) continue;\n }\n\n const crossed = this.lastTime < m.time && t >= m.time - m.tolerance;\n if (!crossed) continue;\n\n if (m.once) this.hitSet.add(key);\n else this.lastHitAt.set(key, now);\n\n if (m.pauseOnHit) this.ctx.videoEl.pause();\n\n this.firePing(m);\n this.fireAction(m);\n\n const popupCfg = m.popup ? { ...this.popupGlobal, ...m.popup } : this.popupGlobal;\n if (popupCfg.enabled) {\n this.ctx.videoEl.pause();\n this.showPopup(popupCfg);\n }\n break;\n }\n\n this.lastTime = t;\n };\n\n private resolveUrlTemplate(url: string, m: NormalizedMarker): string {\n if (!url) return '';\n return url.replaceAll('{time}', encodeURIComponent(String(m.time))).replaceAll('{label}', encodeURIComponent(m.label));\n }\n\n private firePing(m: NormalizedMarker): void {\n const baseUrl = m.pingUrl || this.pingGlobal.url;\n const url = this.resolveUrlTemplate(baseUrl, m);\n if (!this.pingGlobal.enabled || !url) return;\n\n try {\n if (this.pingGlobal.method === 'POST') {\n fetch(url, {\n method: 'POST',\n keepalive: true,\n headers: this.pingGlobal.includeMarker ? { 'Content-Type': 'application/json' } : undefined,\n body: this.pingGlobal.includeMarker ? JSON.stringify({ time: m.time, label: m.label, ts: Date.now() }) : undefined,\n }).catch(() => {});\n } else {\n fetch(url, { method: 'GET', keepalive: true }).catch(() => {});\n }\n } catch {\n /* no-op */\n }\n }\n\n private fireAction(m: NormalizedMarker): void {\n const a = m.action;\n if (!a) return;\n\n if (a.type === 'log') {\n console.log('[HopePlayer markers]', a.name || 'marker_hit', { time: m.time, label: m.label }, a.payload);\n return;\n }\n\n if (a.type === 'datalayer') {\n try {\n const w = window as unknown as { dataLayer?: unknown[] };\n w.dataLayer = w.dataLayer || [];\n w.dataLayer.push({\n event: 'HopePlayerVideoEvents',\n trigger: a.name || 'marker_hit',\n marker: { time: m.time, label: m.label, color: m.color },\n payload: a.payload ?? {},\n ts: Date.now(),\n });\n } catch {\n /* no-op */\n }\n return;\n }\n\n if (a.type === 'custom') {\n const fn = a.name ? (window as unknown as Record<string, unknown>)[a.name] : null;\n if (typeof fn === 'function') {\n try {\n (fn as (ctx: unknown) => void)({ marker: m, payload: a.payload });\n } catch (err) {\n console.warn('[HopePlayer markers] custom action fonksiyonu hata verdi:', err);\n }\n } else {\n console.warn('[HopePlayer markers] custom action fonksiyonu bulunamadı: window.' + a.name);\n }\n }\n }\n\n private ensurePopup(): HTMLElement {\n if (this.popupEl) return this.popupEl;\n\n const overlay = document.createElement('div');\n overlay.setAttribute('part', 'marker-popup');\n overlay.className = 'hp:hidden hp:absolute hp:inset-0 hp:z-30 hp:items-center hp:justify-center hp:bg-black/70';\n\n const panel = document.createElement('div');\n panel.className = 'hp:relative hp:max-w-[85%] hp:bg-surface-elev hp:text-on-surface hp:rounded-lg hp:p-4 hp:text-center hp:shadow-xl';\n panel.setAttribute('role', 'dialog');\n panel.setAttribute('aria-modal', 'true');\n\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.setAttribute('aria-label', this.ctx.i18n.close);\n closeBtn.className = 'hp:absolute hp:top-1 hp:right-1 hp:w-6 hp:h-6 hp:flex hp:items-center hp:justify-center hp:bg-transparent hp:border-0 hp:cursor-pointer hp:text-on-surface';\n closeBtn.appendChild(createIcon('close', 'hp:text-sm'));\n\n const mediaWrap = document.createElement('div');\n mediaWrap.className = 'hp:hidden hp:mb-2';\n const img = document.createElement('img');\n img.className = 'hp:max-w-full hp:rounded';\n mediaWrap.appendChild(img);\n\n const textEl = document.createElement('div');\n textEl.className = 'hp:text-sm hp:mb-2';\n\n const linkEl = document.createElement('a');\n linkEl.target = '_blank';\n linkEl.rel = 'noopener noreferrer';\n linkEl.className = 'hp:hidden hp:text-accent hp:underline hp:text-sm hp:block hp:mb-2';\n\n const continueBtn = document.createElement('button');\n continueBtn.type = 'button';\n continueBtn.className = 'hp:hidden hp:px-4 hp:py-1.5 hp:rounded hp:bg-accent hp:text-on-accent hp:border-0 hp:cursor-pointer hp:text-sm';\n\n panel.append(closeBtn, mediaWrap, textEl, linkEl, continueBtn);\n overlay.appendChild(panel);\n this.ctx.overlayContainerEl.appendChild(overlay);\n this.popupEl = overlay;\n return overlay;\n }\n\n private hidePopup(): void {\n this.popupEl?.classList.add('hp:hidden');\n this.popupEl?.classList.remove('hp:flex');\n }\n\n private safePlay(): void {\n void this.ctx.videoEl.play().catch(() => {});\n }\n\n private showPopup(cfg: Required<MarkerPopupOptions>): void {\n const el = this.ensurePopup();\n const textEl = el.querySelector('div.hp\\\\:text-sm.hp\\\\:mb-2:not(.hp\\\\:hidden)') as HTMLElement | null;\n const mediaWrap = el.querySelector('div.hp\\\\:mb-2') as HTMLElement | null;\n const img = el.querySelector('img') as HTMLImageElement | null;\n const linkEl = el.querySelector('a') as HTMLAnchorElement | null;\n const continueBtn = el.querySelectorAll('button')[1] as HTMLButtonElement | null;\n const closeBtn = el.querySelector('button') as HTMLButtonElement | null;\n\n if (closeBtn) closeBtn.style.display = cfg.showClose === false ? 'none' : '';\n if (textEl) textEl.textContent = cfg.text || '';\n\n const isRich = cfg.mode === 'rich';\n if (mediaWrap && img) {\n if (isRich && cfg.imageUrl) {\n mediaWrap.classList.remove('hp:hidden');\n img.src = cfg.imageUrl;\n img.alt = cfg.imageAlt || '';\n } else {\n mediaWrap.classList.add('hp:hidden');\n img.removeAttribute('src');\n }\n }\n\n if (linkEl) {\n if (isRich && cfg.linkUrl) {\n linkEl.classList.remove('hp:hidden');\n linkEl.href = cfg.linkUrl;\n linkEl.textContent = cfg.linkText || this.ctx.i18n.markerLearnMore;\n } else {\n linkEl.classList.add('hp:hidden');\n linkEl.removeAttribute('href');\n }\n }\n\n if (continueBtn) {\n if (cfg.showContinue) {\n continueBtn.classList.remove('hp:hidden');\n continueBtn.textContent = cfg.continueText || this.ctx.i18n.markerContinue;\n } else {\n continueBtn.classList.add('hp:hidden');\n }\n }\n\n const newClose = closeBtn?.cloneNode(true) as HTMLButtonElement | undefined;\n if (closeBtn && newClose) closeBtn.replaceWith(newClose);\n const newCont = continueBtn?.cloneNode(true) as HTMLButtonElement | undefined;\n if (continueBtn && newCont) continueBtn.replaceWith(newCont);\n\n newClose?.addEventListener('click', () => {\n this.hidePopup();\n if (cfg.autoplayOnClose) this.safePlay();\n });\n newCont?.addEventListener('click', () => {\n this.hidePopup();\n if (cfg.autoplayOnContinue) this.safePlay();\n });\n\n el.classList.remove('hp:hidden');\n el.classList.add('hp:flex');\n }\n}\n","import { MarkProgress, type MarkersPlayerContext } from './MarkProgress';\nimport type { MarkersOptions } from '../../types';\n\nexport function installMarkers(ctx: MarkersPlayerContext, options: MarkersOptions): MarkProgress {\n return new MarkProgress(ctx, options);\n}\n\nexport { MarkProgress };\nexport type { MarkersPlayerContext };\n"],"names":["POPUP_DEFAULTS","PING_DEFAULTS","MarkProgress","ctx","options","__publicField","duration","m","el","now","key","last","popupCfg","idx","a","b","closeBtn","_a","url","baseUrl","w","fn","err","overlay","panel","createIcon","mediaWrap","img","textEl","linkEl","continueBtn","_b","cfg","isRich","newClose","newCont","installMarkers"],"mappings":";;;;AA2BA,MAAMA,IAA+C;AAAA,EACjD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AAAA,EACV,SAAS;AAAA;AAAA;AAAA;AAAA,EAIT,UAAU;AAAA,EACV,cAAc;AAAA,EACd,cAAc;AAAA,EACd,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,oBAAoB;AACxB,GAEMC,IAA6C,EAAE,SAAS,IAAO,KAAK,IAAI,QAAQ,OAAO,eAAe,GAAA;AAGrG,MAAMC,EAAa;AAAA,EAetB,YACqBC,GACjBC,GACF;AAjBe,IAAAC,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAET,IAAAA,EAAA,oCAAa,IAAA;AACb,IAAAA,EAAA,uCAAgB,IAAA;AAChB,IAAAA,EAAA,kBAAW;AACX,IAAAA,EAAA,mBAAY;AACZ,IAAAA,EAAA,uBAAgB;AAChB,IAAAA,EAAA,iBAA8B;AA6DrB,IAAAA,EAAA,0BAAmB,MAAY;AAC5C,YAAMC,IAAW,KAAK,IAAI,QAAQ;AAClC,MAAI,CAAC,OAAO,SAASA,CAAQ,KAAKA,KAAY,MAE9C,KAAK,QAAQ,QAAQ,CAACC,MAAM;AACxB,YAAIA,EAAE,GAAI;AACV,cAAMC,IAAK,KAAK,IAAI,iBAAiBD,EAAE,OAAOD,CAAQ;AACtD,QAAIC,EAAE,UAAOC,EAAG,MAAM,kBAAkBD,EAAE,QACtCA,EAAE,UAAOC,EAAG,QAAQD,EAAE,QAC1BA,EAAE,KAAKC;AAAA,MACX,CAAC,GAED,KAAK,WAAW,KAAK,IAAI,QAAQ,eAAe;AAAA,IACpD;AAEiB,IAAAH,EAAA,mBAAY,MAAY;AACrC,WAAK,YAAY,IACjB,KAAK,gBAAgB,KAAK,IAAA,IAAQ,KAAK,oBACvC,KAAK,WAAW,KAAK,IAAI,QAAQ,eAAe;AAAA,IACpD;AAEiB,IAAAA,EAAA,kBAAW,MAAY;AACpC,WAAK,WAAW,KAAK,IAAI,QAAQ,eAAe,GAChD,KAAK,YAAY,IACjB,KAAK,gBAAgB,KAAK,IAAA,IAAQ,KAAK;AAAA,IAC3C;AAEiB,IAAAA,EAAA,sBAAe,MAAY;AACxC,YAAMI,IAAM,KAAK,IAAA;AAEjB,UADIA,IAAM,KAAK,iBACX,KAAK,UAAW;AAEpB,YAAM,IAAI,KAAK,IAAI,QAAQ;AAC3B,UAAI,CAAC,OAAO,SAAS,CAAC,EAAG;AAGzB,UADe,KAAK,IAAI,IAAI,KAAK,QAAQ,KAAK,KAAK,wBACrC,CAAC,KAAK,eAAe;AAC/B,aAAK,WAAW;AAChB;AAAA,MACJ;AAEA,iBAAWF,KAAK,KAAK,SAAS;AAC1B,cAAMG,IAAM,GAAGH,EAAE,IAAI,IAAIA,EAAE,GAAG;AAC9B,YAAIA,EAAE,QAAQ,KAAK,OAAO,IAAIG,CAAG,EAAG;AACpC,YAAI,CAACH,EAAE,MAAM;AACT,gBAAMI,IAAO,KAAK,UAAU,IAAID,CAAG,KAAK;AACxC,cAAID,IAAME,IAAOJ,EAAE,WAAY;AAAA,QACnC;AAGA,YAAI,EADY,KAAK,WAAWA,EAAE,QAAQ,KAAKA,EAAE,OAAOA,EAAE,WAC5C;AAEd,QAAIA,EAAE,OAAM,KAAK,OAAO,IAAIG,CAAG,IAC1B,KAAK,UAAU,IAAIA,GAAKD,CAAG,GAE5BF,EAAE,cAAY,KAAK,IAAI,QAAQ,MAAA,GAEnC,KAAK,SAASA,CAAC,GACf,KAAK,WAAWA,CAAC;AAEjB,cAAMK,IAAWL,EAAE,QAAQ,EAAE,GAAG,KAAK,aAAa,GAAGA,EAAE,MAAA,IAAU,KAAK;AACtE,QAAIK,EAAS,YACT,KAAK,IAAI,QAAQ,MAAA,GACjB,KAAK,UAAUA,CAAQ;AAE3B;AAAA,MACJ;AAEA,WAAK,WAAW;AAAA,IACpB;AA/HqB,SAAA,MAAAT,GAGjB,KAAK,gBAAgBC,EAAQ,kBAAkB,IAC/C,KAAK,uBAAuBA,EAAQ,wBAAwB,GAC5D,KAAK,qBAAqBA,EAAQ,sBAAsB,KACxD,KAAK,cAAc,EAAE,GAAGJ,GAAgB,GAAGI,EAAQ,MAAA,GACnD,KAAK,aAAa,EAAE,GAAGH,GAAe,GAAGG,EAAQ,KAAA,GAEjD,KAAK,WAAWA,EAAQ,SAAS,CAAA,GAC5B,IAAI,CAACG,GAAGM,MAAQ,KAAK,UAAUN,GAAGM,CAAG,CAAC,EACtC,OAAO,CAACN,MAAM,OAAO,SAASA,EAAE,IAAI,KAAKA,EAAE,QAAQ,CAAC,EACpD,KAAK,CAACO,GAAGC,MAAMD,EAAE,OAAOC,EAAE,IAAI,GAEnCZ,EAAI,QAAQ,iBAAiB,kBAAkB,KAAK,gBAAgB,GACpEA,EAAI,QAAQ,iBAAiB,cAAc,KAAK,YAAY,GAC5DA,EAAI,QAAQ,iBAAiB,WAAW,KAAK,SAAS,GACtDA,EAAI,QAAQ,iBAAiB,UAAU,KAAK,QAAQ,GAEhDA,EAAI,QAAQ,cAAc,UAAQ,iBAAA;AAAA,EAC1C;AAAA;AAAA,EAGA,gBAAsB;;AAClB,UAAMa,KAAWC,IAAA,KAAK,YAAL,gBAAAA,EAAc,cAAc;AAC7C,IAAID,KACAA,EAAS,aAAa,cAAc,KAAK,IAAI,KAAK,KAAK;AAAA,EAE/D;AAAA,EAEA,UAAgB;;AACZ,SAAK,IAAI,QAAQ,oBAAoB,kBAAkB,KAAK,gBAAgB,GAC5E,KAAK,IAAI,QAAQ,oBAAoB,cAAc,KAAK,YAAY,GACpE,KAAK,IAAI,QAAQ,oBAAoB,WAAW,KAAK,SAAS,GAC9D,KAAK,IAAI,QAAQ,oBAAoB,UAAU,KAAK,QAAQ,GAC5D,KAAK,QAAQ,QAAQ,CAACT;;AAAM,cAAAU,IAAAV,EAAE,OAAF,gBAAAU,EAAM;AAAA,KAAQ,IAC1CA,IAAA,KAAK,YAAL,QAAAA,EAAc,UACd,KAAK,UAAU,MACf,KAAK,OAAO,MAAA,GACZ,KAAK,UAAU,MAAA;AAAA,EACnB;AAAA,EAEQ,UAAUV,GAAeM,GAA+B;AAC5D,WAAO;AAAA,MACH,KAAAA;AAAA,MACA,MAAM,OAAON,EAAE,IAAI;AAAA,MACnB,OAAOA,EAAE;AAAA,MACT,OAAOA,EAAE,SAAS;AAAA,MAClB,YAAYA,EAAE,cAAc;AAAA,MAC5B,MAAMA,EAAE,QAAQ;AAAA,MAChB,WAAWA,EAAE,aAAa;AAAA,MAC1B,YAAYA,EAAE,cAAc;AAAA,MAC5B,QAAQA,EAAE;AAAA,MACV,OAAOA,EAAE,SAAS;AAAA,MAClB,SAASA,EAAE,WAAW;AAAA,IAAA;AAAA,EAE9B;AAAA,EAyEQ,mBAAmBW,GAAaX,GAA6B;AACjE,WAAKW,IACEA,EAAI,WAAW,UAAU,mBAAmB,OAAOX,EAAE,IAAI,CAAC,CAAC,EAAE,WAAW,WAAW,mBAAmBA,EAAE,KAAK,CAAC,IADpG;AAAA,EAErB;AAAA,EAEQ,SAASA,GAA2B;AACxC,UAAMY,IAAUZ,EAAE,WAAW,KAAK,WAAW,KACvCW,IAAM,KAAK,mBAAmBC,GAASZ,CAAC;AAC9C,QAAI,GAAC,KAAK,WAAW,WAAW,CAACW;AAEjC,UAAI;AACA,QAAI,KAAK,WAAW,WAAW,SAC3B,MAAMA,GAAK;AAAA,UACP,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,SAAS,KAAK,WAAW,gBAAgB,EAAE,gBAAgB,uBAAuB;AAAA,UAClF,MAAM,KAAK,WAAW,gBAAgB,KAAK,UAAU,EAAE,MAAMX,EAAE,MAAM,OAAOA,EAAE,OAAO,IAAI,KAAK,IAAA,EAAI,CAAG,IAAI;AAAA,QAAA,CAC5G,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC,IAEjB,MAAMW,GAAK,EAAE,QAAQ,OAAO,WAAW,GAAA,CAAM,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAErE,QAAQ;AAAA,MAER;AAAA,EACJ;AAAA,EAEQ,WAAWX,GAA2B;AAC1C,UAAMO,IAAIP,EAAE;AACZ,QAAKO,GAEL;AAAA,UAAIA,EAAE,SAAS,OAAO;AAClB,gBAAQ,IAAI,wBAAwBA,EAAE,QAAQ,cAAc,EAAE,MAAMP,EAAE,MAAM,OAAOA,EAAE,MAAA,GAASO,EAAE,OAAO;AACvG;AAAA,MACJ;AAEA,UAAIA,EAAE,SAAS,aAAa;AACxB,YAAI;AACA,gBAAMM,IAAI;AACV,UAAAA,EAAE,YAAYA,EAAE,aAAa,CAAA,GAC7BA,EAAE,UAAU,KAAK;AAAA,YACb,OAAO;AAAA,YACP,SAASN,EAAE,QAAQ;AAAA,YACnB,QAAQ,EAAE,MAAMP,EAAE,MAAM,OAAOA,EAAE,OAAO,OAAOA,EAAE,MAAA;AAAA,YACjD,SAASO,EAAE,WAAW,CAAA;AAAA,YACtB,IAAI,KAAK,IAAA;AAAA,UAAI,CAChB;AAAA,QACL,QAAQ;AAAA,QAER;AACA;AAAA,MACJ;AAEA,UAAIA,EAAE,SAAS,UAAU;AACrB,cAAMO,IAAKP,EAAE,OAAQ,OAA8CA,EAAE,IAAI,IAAI;AAC7E,YAAI,OAAOO,KAAO;AACd,cAAI;AACC,YAAAA,EAA8B,EAAE,QAAQd,GAAG,SAASO,EAAE,SAAS;AAAA,UACpE,SAASQ,GAAK;AACV,oBAAQ,KAAK,6DAA6DA,CAAG;AAAA,UACjF;AAAA;AAEA,kBAAQ,KAAK,sEAAsER,EAAE,IAAI;AAAA,MAEjG;AAAA;AAAA,EACJ;AAAA,EAEQ,cAA2B;AAC/B,QAAI,KAAK,QAAS,QAAO,KAAK;AAE9B,UAAMS,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,aAAa,QAAQ,cAAc,GAC3CA,EAAQ,YAAY;AAEpB,UAAMC,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY,qHAClBA,EAAM,aAAa,QAAQ,QAAQ,GACnCA,EAAM,aAAa,cAAc,MAAM;AAEvC,UAAMR,IAAW,SAAS,cAAc,QAAQ;AAChD,IAAAA,EAAS,OAAO,UAChBA,EAAS,aAAa,cAAc,KAAK,IAAI,KAAK,KAAK,GACvDA,EAAS,YAAY,8JACrBA,EAAS,YAAYS,EAAW,SAAS,YAAY,CAAC;AAEtD,UAAMC,IAAY,SAAS,cAAc,KAAK;AAC9C,IAAAA,EAAU,YAAY;AACtB,UAAMC,IAAM,SAAS,cAAc,KAAK;AACxC,IAAAA,EAAI,YAAY,4BAChBD,EAAU,YAAYC,CAAG;AAEzB,UAAMC,IAAS,SAAS,cAAc,KAAK;AAC3C,IAAAA,EAAO,YAAY;AAEnB,UAAMC,IAAS,SAAS,cAAc,GAAG;AACzC,IAAAA,EAAO,SAAS,UAChBA,EAAO,MAAM,uBACbA,EAAO,YAAY;AAEnB,UAAMC,IAAc,SAAS,cAAc,QAAQ;AACnD,WAAAA,EAAY,OAAO,UACnBA,EAAY,YAAY,kHAExBN,EAAM,OAAOR,GAAUU,GAAWE,GAAQC,GAAQC,CAAW,GAC7DP,EAAQ,YAAYC,CAAK,GACzB,KAAK,IAAI,mBAAmB,YAAYD,CAAO,GAC/C,KAAK,UAAUA,GACRA;AAAA,EACX;AAAA,EAEQ,YAAkB;;AACtB,KAAAN,IAAA,KAAK,YAAL,QAAAA,EAAc,UAAU,IAAI,eAC5Bc,IAAA,KAAK,YAAL,QAAAA,EAAc,UAAU,OAAO;AAAA,EACnC;AAAA,EAEQ,WAAiB;AACrB,IAAK,KAAK,IAAI,QAAQ,KAAA,EAAO,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC/C;AAAA,EAEQ,UAAUC,GAAyC;AACvD,UAAMxB,IAAK,KAAK,YAAA,GACVoB,IAASpB,EAAG,cAAc,8CAA8C,GACxEkB,IAAYlB,EAAG,cAAc,eAAe,GAC5CmB,IAAMnB,EAAG,cAAc,KAAK,GAC5BqB,IAASrB,EAAG,cAAc,GAAG,GAC7BsB,IAActB,EAAG,iBAAiB,QAAQ,EAAE,CAAC,GAC7CQ,IAAWR,EAAG,cAAc,QAAQ;AAE1C,IAAIQ,MAAUA,EAAS,MAAM,UAAUgB,EAAI,cAAc,KAAQ,SAAS,KACtEJ,MAAQA,EAAO,cAAcI,EAAI,QAAQ;AAE7C,UAAMC,IAASD,EAAI,SAAS;AAC5B,IAAIN,KAAaC,MACTM,KAAUD,EAAI,YACdN,EAAU,UAAU,OAAO,WAAW,GACtCC,EAAI,MAAMK,EAAI,UACdL,EAAI,MAAMK,EAAI,YAAY,OAE1BN,EAAU,UAAU,IAAI,WAAW,GACnCC,EAAI,gBAAgB,KAAK,KAI7BE,MACII,KAAUD,EAAI,WACdH,EAAO,UAAU,OAAO,WAAW,GACnCA,EAAO,OAAOG,EAAI,SAClBH,EAAO,cAAcG,EAAI,YAAY,KAAK,IAAI,KAAK,oBAEnDH,EAAO,UAAU,IAAI,WAAW,GAChCA,EAAO,gBAAgB,MAAM,KAIjCC,MACIE,EAAI,gBACJF,EAAY,UAAU,OAAO,WAAW,GACxCA,EAAY,cAAcE,EAAI,gBAAgB,KAAK,IAAI,KAAK,kBAE5DF,EAAY,UAAU,IAAI,WAAW;AAI7C,UAAMI,IAAWlB,KAAA,gBAAAA,EAAU,UAAU;AACrC,IAAIA,KAAYkB,KAAUlB,EAAS,YAAYkB,CAAQ;AACvD,UAAMC,IAAUL,KAAA,gBAAAA,EAAa,UAAU;AACvC,IAAIA,KAAeK,KAASL,EAAY,YAAYK,CAAO,GAE3DD,KAAA,QAAAA,EAAU,iBAAiB,SAAS,MAAM;AACtC,WAAK,UAAA,GACDF,EAAI,mBAAiB,KAAK,SAAA;AAAA,IAClC,IACAG,KAAA,QAAAA,EAAS,iBAAiB,SAAS,MAAM;AACrC,WAAK,UAAA,GACDH,EAAI,sBAAoB,KAAK,SAAA;AAAA,IACrC,IAEAxB,EAAG,UAAU,OAAO,WAAW,GAC/BA,EAAG,UAAU,IAAI,SAAS;AAAA,EAC9B;AACJ;ACjXO,SAAS4B,EAAejC,GAA2BC,GAAuC;AAC7F,SAAO,IAAIF,EAAaC,GAAKC,CAAO;AACxC;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var A = Object.defineProperty;
|
|
2
2
|
var g = (h, t, e) => t in h ? A(h, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[t] = e;
|
|
3
3
|
var n = (h, t, e) => g(h, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
-
import { c as b } from "./index-
|
|
4
|
+
import { c as b } from "./index-w7pACyTw.js";
|
|
5
5
|
const P = {
|
|
6
6
|
startMode: "after_current",
|
|
7
7
|
startIndex: 0,
|
|
@@ -233,4 +233,4 @@ export {
|
|
|
233
233
|
I as PlaylistRunner,
|
|
234
234
|
M as installPlaylist
|
|
235
235
|
};
|
|
236
|
-
//# sourceMappingURL=index-
|
|
236
|
+
//# sourceMappingURL=index-DpUZXNJS.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DtqNHU7Y.js","sources":["../../src/plugins/playlist/PlaylistRunner.ts","../../src/plugins/playlist/index.ts"],"sourcesContent":["import { createIcon } from '../../icons/Icon';\nimport type { PlayableItem, PlaylistOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\n\nexport interface PlaylistPlayerContext {\n videoEl: HTMLVideoElement;\n hostEl: HTMLElement;\n /** Liste UI'ının monte edileceği, shadow root içindeki panel. */\n panelEl: HTMLElement;\n loadSource(src: string, type?: string): Promise<void>;\n setPoster(url: string): void;\n /** AdsController varsa retry/VMAP durumunu sıfırlayıp item'ın (varsa) kendi adTagPreroll'üyle yeniden reklam ister — yoksa no-op. */\n requestFreshAd(prerollTag?: string): void;\n i18n: HopeLocaleStrings;\n}\n\ntype SourceMode = 'hls' | 'mp4';\n\ninterface Attempt {\n id: number;\n index: number;\n mode: SourceMode;\n tried: Set<SourceMode>;\n mp4Index: number;\n}\n\nconst DEFAULTS: Required<Omit<PlaylistOptions, 'items' | 'adTagPreroll' | 'ui'>> = {\n startMode: 'after_current',\n startIndex: 0,\n loop: false,\n autoplayNext: true,\n preferHls: true,\n adsOnItemChange: true,\n};\n\n/** Tek player üzerinde sıralı oynatma listesi (startMode, loop, hata fallback zinciri). */\nexport class PlaylistRunner {\n private readonly options: Required<Omit<PlaylistOptions, 'items' | 'adTagPreroll' | 'ui'>>;\n private readonly items: PlayableItem[];\n\n private index: number;\n private destroyed = false;\n private switching = false;\n private playlistActive = false;\n private startPendingAfterCurrent = false;\n private attemptId = 0;\n private attempt: Attempt | null = null;\n private lastErrorAt = 0;\n private lastAdsIndex: number | null = null;\n private lastDispatchedIndex: number | null = null;\n private userHasStartedPlayback = false;\n\n private readonly ui: {\n root: HTMLElement;\n titleEl: HTMLElement;\n listEl: HTMLElement;\n prevBtn: HTMLButtonElement;\n nextBtn: HTMLButtonElement;\n itemEls: Array<{ li: HTMLElement; titleRow: HTMLElement; progressFill: HTMLElement | null; timeEl: HTMLElement | null }>;\n };\n\n constructor(\n private readonly ctx: PlaylistPlayerContext,\n private readonly rawOptions: PlaylistOptions\n ) {\n this.options = { ...DEFAULTS, ...rawOptions };\n this.items = Array.isArray(rawOptions.items) ? rawOptions.items : [];\n this.index = this.clampIndex(this.options.startIndex);\n\n this.ui = this.buildUi();\n this.bindPlayerEvents();\n this.init();\n }\n\n // ── lifecycle ──\n\n private init(): void {\n if (!this.items.length) return;\n\n if (this.options.startMode === 'after_current') {\n this.startPendingAfterCurrent = true;\n this.playlistActive = false;\n this.setActive(this.index);\n return;\n }\n\n this.playlistActive = true;\n void this.loadAndPlay(this.index, { userInitiated: false, isPlaylistStart: true });\n }\n\n refreshLabels(): void {\n this.ui.titleEl.textContent = this.playlistTitleText();\n this.ui.prevBtn.setAttribute('aria-label', this.ctx.i18n.playlistPrev);\n this.ui.nextBtn.setAttribute('aria-label', this.ctx.i18n.playlistNext);\n this.ui.itemEls.forEach((entry, idx) => {\n const item = this.items[idx];\n if (item && !item.title) entry.titleRow.textContent = this.ctx.i18n.videoFallbackTitle(idx);\n });\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.ctx.videoEl.removeEventListener('ended', this.onEnded);\n this.ctx.videoEl.removeEventListener('error', this.onError);\n this.ctx.videoEl.removeEventListener('play', this.onUserPlay);\n this.ui.root.remove();\n }\n\n // ── public api ──\n\n start(opts: { index?: number } = {}): void {\n if (this.destroyed || !this.items.length) return;\n this.startPendingAfterCurrent = false;\n this.playlistActive = true;\n this.index = this.clampIndex(opts.index ?? this.index);\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: false, isPlaylistStart: true });\n }\n\n next(): void {\n if (this.destroyed || !this.items.length) return;\n if (!this.playlistActive) return this.start({ index: this.index });\n\n if (this.index < this.items.length - 1) this.index++;\n else if (this.options.loop) this.index = 0;\n else return;\n\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: true });\n }\n\n prev(): void {\n if (this.destroyed || !this.items.length) return;\n if (!this.playlistActive) return this.start({ index: this.index });\n if (this.index === 0) return;\n this.index--;\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: true });\n }\n\n setIndex(i: number): void {\n if (this.destroyed || !this.items.length) return;\n this.index = this.clampIndex(i);\n this.setActive(this.index);\n if (!this.playlistActive) return this.start({ index: this.index });\n void this.loadAndPlay(this.index, { userInitiated: true });\n }\n\n getIndex(): number {\n return this.index;\n }\n\n isActive(): boolean {\n return this.playlistActive;\n }\n\n // ── player events ──\n\n private bindPlayerEvents(): void {\n this.ctx.videoEl.addEventListener('ended', this.onEnded);\n this.ctx.videoEl.addEventListener('error', this.onError);\n this.ctx.videoEl.addEventListener('play', this.onUserPlay);\n this.ctx.videoEl.addEventListener('timeupdate', this.onTimeUpdate);\n }\n\n private readonly onUserPlay = (): void => {\n this.userHasStartedPlayback = true;\n };\n\n private readonly onEnded = (): void => {\n if (this.startPendingAfterCurrent && !this.playlistActive) {\n this.startPendingAfterCurrent = false;\n this.playlistActive = true;\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: true, isPlaylistStart: true });\n return;\n }\n if (this.playlistActive) this.next();\n };\n\n private readonly onError = (): void => {\n if (this.destroyed || !this.playlistActive) return;\n const now = Date.now();\n if (now - this.lastErrorAt < 200) return;\n this.lastErrorAt = now;\n void this.fallbackOrSkip();\n };\n\n private readonly onTimeUpdate = (): void => {\n this.updateProgress();\n };\n\n // ── core load ──\n\n private async loadAndPlay(\n i: number,\n opts: { userInitiated?: boolean; forceMode?: SourceMode | null; forceMp4Index?: number | null; isFallback?: boolean; isPlaylistStart?: boolean } = {}\n ): Promise<void> {\n if (this.destroyed || this.switching || !this.playlistActive) return;\n this.switching = true;\n\n const item = this.items[i];\n if (!item) {\n this.switching = false;\n return;\n }\n const attemptId = ++this.attemptId;\n const mode = opts.forceMode ?? this.resolveMode(item);\n\n let tried = new Set<SourceMode>([mode]);\n let mp4Index = opts.forceMp4Index ?? 0;\n if (opts.isFallback && this.attempt?.index === i && this.attempt?.tried) {\n tried = new Set(this.attempt.tried);\n tried.add(mode);\n if (opts.forceMp4Index == null) mp4Index = this.attempt.mp4Index ?? 0;\n }\n this.attempt = { id: attemptId, index: i, mode, tried, mp4Index };\n\n try {\n const payload = this.buildPayload(item, mode, mp4Index);\n if (!payload) throw new Error('No playable source');\n\n this.setActive(i);\n this.ctx.videoEl.pause();\n if (item.image) this.ctx.setPoster(item.image);\n await this.ctx.loadSource(payload.src, payload.type);\n\n if (this.options.adsOnItemChange) this.maybeRequestAds(i, item, !!opts.isFallback);\n\n if (this.shouldAutoPlay(!!opts.userInitiated)) {\n try {\n await this.ctx.videoEl.play();\n } catch {\n /* autoplay engellendi — sessizce geç */\n }\n }\n this.updateProgress();\n } finally {\n this.switching = false;\n }\n }\n\n private async fallbackOrSkip(): Promise<void> {\n if (this.destroyed || !this.attempt) return;\n const item = this.items[this.attempt.index];\n if (!item) return;\n\n if (this.attempt.mode === 'mp4') {\n const mp4List = (item.mp4 || []).filter((v) => v?.src);\n const nextMp4 = (this.attempt.mp4Index ?? 0) + 1;\n if (nextMp4 < mp4List.length) {\n await this.loadAndPlay(this.attempt.index, { forceMode: 'mp4', forceMp4Index: nextMp4, isFallback: true });\n return;\n }\n }\n\n const otherMode: SourceMode = this.attempt.mode === 'hls' ? 'mp4' : 'hls';\n if (this.hasMode(item, otherMode) && !this.attempt.tried.has(otherMode)) {\n await this.loadAndPlay(this.attempt.index, { forceMode: otherMode, isFallback: true });\n return;\n }\n\n this.next();\n }\n\n // ── ads ──\n\n private maybeRequestAds(index: number, item: PlayableItem, _isFallback: boolean): void {\n if (this.lastAdsIndex === index) return;\n this.lastAdsIndex = index;\n this.ctx.requestFreshAd(item.adTagPreroll || this.rawOptions.adTagPreroll);\n }\n\n // ── sources ──\n\n private resolveMode(item: PlayableItem): SourceMode {\n if (this.options.preferHls) return this.hasMode(item, 'hls') ? 'hls' : this.hasMode(item, 'mp4') ? 'mp4' : 'hls';\n return this.hasMode(item, 'mp4') ? 'mp4' : this.hasMode(item, 'hls') ? 'hls' : 'mp4';\n }\n\n private hasMode(item: PlayableItem, mode: SourceMode): boolean {\n return Array.isArray(item[mode]) && item[mode]!.some((v) => v?.src);\n }\n\n private buildPayload(item: PlayableItem, mode: SourceMode, mp4Index = 0): { src: string; type?: string } | null {\n const list = (item[mode] || []).filter((v) => v?.src);\n if (!list.length) return null;\n\n let src;\n if (mode === 'mp4') {\n src = mp4Index > 0 ? list[mp4Index] || list[0] : list.find((v) => v.selected) || list[0];\n } else {\n src = list[0];\n }\n return { src: src!.src, type: src!.type || (mode === 'hls' ? 'application/x-mpegURL' : 'video/mp4') };\n }\n\n private shouldAutoPlay(userInitiated: boolean): boolean {\n if (userInitiated) return true;\n return this.options.autoplayNext && this.userHasStartedPlayback;\n }\n\n private clampIndex(i: number): number {\n if (!Number.isFinite(i) || !this.items.length) return 0;\n return Math.max(0, Math.min(this.items.length - 1, Math.trunc(i)));\n }\n\n // ── ui ──\n\n private buildUi() {\n const ui = this.rawOptions.ui ?? {};\n const root = document.createElement('div');\n root.setAttribute('part', 'playlist-panel');\n root.className = 'hp:flex hp:flex-col hp:gap-2 hp:p-3 hp:bg-surface-elev hp:max-h-80 hp:overflow-y-auto';\n\n const header = document.createElement('div');\n header.className = 'hp:flex hp:items-center hp:justify-between hp:gap-2 hp:mb-1';\n\n const titleEl = document.createElement('div');\n titleEl.className = 'hp:text-sm hp:font-semibold hp:text-on-surface';\n titleEl.textContent = this.playlistTitleText();\n header.appendChild(titleEl);\n\n const navWrap = document.createElement('div');\n navWrap.className = 'hp:flex hp:gap-1';\n const prevBtn = this.navButton('chevron-left', this.ctx.i18n.playlistPrev, () => this.prev());\n const nextBtn = this.navButton('chevron-left', this.ctx.i18n.playlistNext, () => this.next());\n nextBtn.style.transform = 'rotate(180deg)';\n navWrap.append(prevBtn, nextBtn);\n header.appendChild(navWrap);\n\n root.appendChild(header);\n\n const listEl = document.createElement('ul');\n listEl.className = 'hp:flex hp:flex-col hp:gap-1 hp:list-none hp:m-0 hp:p-0';\n root.appendChild(listEl);\n\n const itemEls: Array<{ li: HTMLElement; titleRow: HTMLElement; progressFill: HTMLElement | null; timeEl: HTMLElement | null }> = [];\n this.items.forEach((item, idx) => {\n const li = document.createElement('li');\n li.className =\n 'hp:flex hp:items-center hp:gap-2 hp:p-2 hp:rounded hp:cursor-pointer hp:text-on-surface-muted hp:text-sm ' +\n 'hp:hover:bg-on-surface/5 hp:data-[active=true]:bg-accent/15 hp:data-[active=true]:text-on-surface';\n\n if (item.image) {\n const img = document.createElement('img');\n img.src = item.image;\n img.loading = 'lazy';\n img.className = 'hp:w-16 hp:aspect-video hp:object-cover hp:rounded hp:shrink-0';\n li.appendChild(img);\n }\n\n const body = document.createElement('div');\n body.className = 'hp:flex-1 hp:min-w-0';\n const titleRow = document.createElement('div');\n titleRow.className = 'hp:truncate hp:font-medium';\n titleRow.textContent = item.title || this.ctx.i18n.videoFallbackTitle(idx);\n body.appendChild(titleRow);\n\n let progressFill: HTMLElement | null = null;\n let timeEl: HTMLElement | null = null;\n if (ui.showMeta !== false) {\n const metaRow = document.createElement('div');\n metaRow.className = 'hp:flex hp:items-center hp:gap-2 hp:text-xs hp:opacity-70 hp:mt-0.5';\n timeEl = document.createElement('span');\n timeEl.textContent = '';\n metaRow.appendChild(timeEl);\n\n const bar = document.createElement('div');\n bar.className = 'hp:flex-1 hp:h-0.5 hp:bg-on-surface/20 hp:rounded-full hp:overflow-hidden';\n progressFill = document.createElement('div');\n progressFill.className = 'hp:h-full hp:bg-accent';\n progressFill.style.width = '0%';\n bar.appendChild(progressFill);\n metaRow.appendChild(bar);\n body.appendChild(metaRow);\n }\n\n li.appendChild(body);\n li.addEventListener('click', () => this.setIndex(idx));\n listEl.appendChild(li);\n itemEls.push({ li, titleRow, progressFill, timeEl });\n });\n\n this.ctx.panelEl.appendChild(root);\n return { root, titleEl, listEl, prevBtn, nextBtn, itemEls };\n }\n\n private playlistTitleText(): string {\n const ui = this.rawOptions.ui ?? {};\n const title = ui.title || this.ctx.i18n.playlistTitle;\n return ui.showCount === false ? title : `${title} (${this.items.length})`;\n }\n\n private navButton(iconName: string, label: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.setAttribute('aria-label', label);\n btn.className = 'hp:flex hp:items-center hp:justify-center hp:w-6 hp:h-6 hp:text-on-surface hp:bg-transparent hp:border-0 hp:cursor-pointer';\n btn.appendChild(createIcon(iconName, 'hp:text-sm'));\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n private setActive(index: number): void {\n this.ui.itemEls.forEach((entry, idx) => {\n if (idx === index) entry.li.setAttribute('data-active', 'true');\n else entry.li.removeAttribute('data-active');\n });\n // loadAndPlay() hem anlık UI geri bildirimi için önceden (next/prev/setIndex\n // içinden) hem de kaynak gerçekten yüklendiğinde setActive() çağırıyor —\n // aynı index için event'i yalnızca BİR kez yaymak için guard.\n if (this.lastDispatchedIndex !== index) {\n this.lastDispatchedIndex = index;\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:itemchange', { detail: { index, source: 'playlist' } }));\n }\n }\n\n private updateProgress(): void {\n const active = this.ui.itemEls[this.index];\n if (!active) return;\n const duration = this.ctx.videoEl.duration;\n const current = this.ctx.videoEl.currentTime;\n if (active.timeEl) active.timeEl.textContent = this.formatTime(current);\n if (active.progressFill && Number.isFinite(duration) && duration > 0) {\n active.progressFill.style.width = `${Math.min(100, (current / duration) * 100)}%`;\n }\n }\n\n private formatTime(sec: number): string {\n const s = Math.max(0, Math.floor(sec || 0));\n const m = Math.floor(s / 60);\n const r = s % 60;\n return `${m}:${String(r).padStart(2, '0')}`;\n }\n}\n","import { PlaylistRunner, type PlaylistPlayerContext } from './PlaylistRunner';\nimport type { PlaylistOptions } from '../../types';\n\nexport function installPlaylist(ctx: PlaylistPlayerContext, options: PlaylistOptions): PlaylistRunner {\n return new PlaylistRunner(ctx, options);\n}\n\nexport { PlaylistRunner };\nexport type { PlaylistPlayerContext };\n"],"names":["DEFAULTS","PlaylistRunner","ctx","rawOptions","__publicField","now","entry","idx","item","opts","i","attemptId","mode","tried","mp4Index","_a","_b","payload","mp4List","v","nextMp4","otherMode","index","_isFallback","list","src","userInitiated","ui","root","header","titleEl","navWrap","prevBtn","nextBtn","listEl","itemEls","li","img","body","titleRow","progressFill","timeEl","metaRow","bar","title","iconName","label","onClick","btn","createIcon","active","duration","current","sec","s","m","r","installPlaylist","options"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-DpUZXNJS.js","sources":["../../src/plugins/playlist/PlaylistRunner.ts","../../src/plugins/playlist/index.ts"],"sourcesContent":["import { createIcon } from '../../icons/Icon';\nimport type { PlayableItem, PlaylistOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\n\nexport interface PlaylistPlayerContext {\n videoEl: HTMLVideoElement;\n hostEl: HTMLElement;\n /** Liste UI'ının monte edileceği, shadow root içindeki panel. */\n panelEl: HTMLElement;\n loadSource(src: string, type?: string): Promise<void>;\n setPoster(url: string): void;\n /** AdsController varsa retry/VMAP durumunu sıfırlayıp item'ın (varsa) kendi adTagPreroll'üyle yeniden reklam ister — yoksa no-op. */\n requestFreshAd(prerollTag?: string): void;\n i18n: HopeLocaleStrings;\n}\n\ntype SourceMode = 'hls' | 'mp4';\n\ninterface Attempt {\n id: number;\n index: number;\n mode: SourceMode;\n tried: Set<SourceMode>;\n mp4Index: number;\n}\n\nconst DEFAULTS: Required<Omit<PlaylistOptions, 'items' | 'adTagPreroll' | 'ui'>> = {\n startMode: 'after_current',\n startIndex: 0,\n loop: false,\n autoplayNext: true,\n preferHls: true,\n adsOnItemChange: true,\n};\n\n/** Tek player üzerinde sıralı oynatma listesi (startMode, loop, hata fallback zinciri). */\nexport class PlaylistRunner {\n private readonly options: Required<Omit<PlaylistOptions, 'items' | 'adTagPreroll' | 'ui'>>;\n private readonly items: PlayableItem[];\n\n private index: number;\n private destroyed = false;\n private switching = false;\n private playlistActive = false;\n private startPendingAfterCurrent = false;\n private attemptId = 0;\n private attempt: Attempt | null = null;\n private lastErrorAt = 0;\n private lastAdsIndex: number | null = null;\n private lastDispatchedIndex: number | null = null;\n private userHasStartedPlayback = false;\n\n private readonly ui: {\n root: HTMLElement;\n titleEl: HTMLElement;\n listEl: HTMLElement;\n prevBtn: HTMLButtonElement;\n nextBtn: HTMLButtonElement;\n itemEls: Array<{ li: HTMLElement; titleRow: HTMLElement; progressFill: HTMLElement | null; timeEl: HTMLElement | null }>;\n };\n\n constructor(\n private readonly ctx: PlaylistPlayerContext,\n private readonly rawOptions: PlaylistOptions\n ) {\n this.options = { ...DEFAULTS, ...rawOptions };\n this.items = Array.isArray(rawOptions.items) ? rawOptions.items : [];\n this.index = this.clampIndex(this.options.startIndex);\n\n this.ui = this.buildUi();\n this.bindPlayerEvents();\n this.init();\n }\n\n // ── lifecycle ──\n\n private init(): void {\n if (!this.items.length) return;\n\n if (this.options.startMode === 'after_current') {\n this.startPendingAfterCurrent = true;\n this.playlistActive = false;\n this.setActive(this.index);\n return;\n }\n\n this.playlistActive = true;\n void this.loadAndPlay(this.index, { userInitiated: false, isPlaylistStart: true });\n }\n\n refreshLabels(): void {\n this.ui.titleEl.textContent = this.playlistTitleText();\n this.ui.prevBtn.setAttribute('aria-label', this.ctx.i18n.playlistPrev);\n this.ui.nextBtn.setAttribute('aria-label', this.ctx.i18n.playlistNext);\n this.ui.itemEls.forEach((entry, idx) => {\n const item = this.items[idx];\n if (item && !item.title) entry.titleRow.textContent = this.ctx.i18n.videoFallbackTitle(idx);\n });\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.ctx.videoEl.removeEventListener('ended', this.onEnded);\n this.ctx.videoEl.removeEventListener('error', this.onError);\n this.ctx.videoEl.removeEventListener('play', this.onUserPlay);\n this.ui.root.remove();\n }\n\n // ── public api ──\n\n start(opts: { index?: number } = {}): void {\n if (this.destroyed || !this.items.length) return;\n this.startPendingAfterCurrent = false;\n this.playlistActive = true;\n this.index = this.clampIndex(opts.index ?? this.index);\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: false, isPlaylistStart: true });\n }\n\n next(): void {\n if (this.destroyed || !this.items.length) return;\n if (!this.playlistActive) return this.start({ index: this.index });\n\n if (this.index < this.items.length - 1) this.index++;\n else if (this.options.loop) this.index = 0;\n else return;\n\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: true });\n }\n\n prev(): void {\n if (this.destroyed || !this.items.length) return;\n if (!this.playlistActive) return this.start({ index: this.index });\n if (this.index === 0) return;\n this.index--;\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: true });\n }\n\n setIndex(i: number): void {\n if (this.destroyed || !this.items.length) return;\n this.index = this.clampIndex(i);\n this.setActive(this.index);\n if (!this.playlistActive) return this.start({ index: this.index });\n void this.loadAndPlay(this.index, { userInitiated: true });\n }\n\n getIndex(): number {\n return this.index;\n }\n\n isActive(): boolean {\n return this.playlistActive;\n }\n\n // ── player events ──\n\n private bindPlayerEvents(): void {\n this.ctx.videoEl.addEventListener('ended', this.onEnded);\n this.ctx.videoEl.addEventListener('error', this.onError);\n this.ctx.videoEl.addEventListener('play', this.onUserPlay);\n this.ctx.videoEl.addEventListener('timeupdate', this.onTimeUpdate);\n }\n\n private readonly onUserPlay = (): void => {\n this.userHasStartedPlayback = true;\n };\n\n private readonly onEnded = (): void => {\n if (this.startPendingAfterCurrent && !this.playlistActive) {\n this.startPendingAfterCurrent = false;\n this.playlistActive = true;\n this.setActive(this.index);\n void this.loadAndPlay(this.index, { userInitiated: true, isPlaylistStart: true });\n return;\n }\n if (this.playlistActive) this.next();\n };\n\n private readonly onError = (): void => {\n if (this.destroyed || !this.playlistActive) return;\n const now = Date.now();\n if (now - this.lastErrorAt < 200) return;\n this.lastErrorAt = now;\n void this.fallbackOrSkip();\n };\n\n private readonly onTimeUpdate = (): void => {\n this.updateProgress();\n };\n\n // ── core load ──\n\n private async loadAndPlay(\n i: number,\n opts: { userInitiated?: boolean; forceMode?: SourceMode | null; forceMp4Index?: number | null; isFallback?: boolean; isPlaylistStart?: boolean } = {}\n ): Promise<void> {\n if (this.destroyed || this.switching || !this.playlistActive) return;\n this.switching = true;\n\n const item = this.items[i];\n if (!item) {\n this.switching = false;\n return;\n }\n const attemptId = ++this.attemptId;\n const mode = opts.forceMode ?? this.resolveMode(item);\n\n let tried = new Set<SourceMode>([mode]);\n let mp4Index = opts.forceMp4Index ?? 0;\n if (opts.isFallback && this.attempt?.index === i && this.attempt?.tried) {\n tried = new Set(this.attempt.tried);\n tried.add(mode);\n if (opts.forceMp4Index == null) mp4Index = this.attempt.mp4Index ?? 0;\n }\n this.attempt = { id: attemptId, index: i, mode, tried, mp4Index };\n\n try {\n const payload = this.buildPayload(item, mode, mp4Index);\n if (!payload) throw new Error('No playable source');\n\n this.setActive(i);\n this.ctx.videoEl.pause();\n if (item.image) this.ctx.setPoster(item.image);\n await this.ctx.loadSource(payload.src, payload.type);\n\n if (this.options.adsOnItemChange) this.maybeRequestAds(i, item, !!opts.isFallback);\n\n if (this.shouldAutoPlay(!!opts.userInitiated)) {\n try {\n await this.ctx.videoEl.play();\n } catch {\n /* autoplay engellendi — sessizce geç */\n }\n }\n this.updateProgress();\n } finally {\n this.switching = false;\n }\n }\n\n private async fallbackOrSkip(): Promise<void> {\n if (this.destroyed || !this.attempt) return;\n const item = this.items[this.attempt.index];\n if (!item) return;\n\n if (this.attempt.mode === 'mp4') {\n const mp4List = (item.mp4 || []).filter((v) => v?.src);\n const nextMp4 = (this.attempt.mp4Index ?? 0) + 1;\n if (nextMp4 < mp4List.length) {\n await this.loadAndPlay(this.attempt.index, { forceMode: 'mp4', forceMp4Index: nextMp4, isFallback: true });\n return;\n }\n }\n\n const otherMode: SourceMode = this.attempt.mode === 'hls' ? 'mp4' : 'hls';\n if (this.hasMode(item, otherMode) && !this.attempt.tried.has(otherMode)) {\n await this.loadAndPlay(this.attempt.index, { forceMode: otherMode, isFallback: true });\n return;\n }\n\n this.next();\n }\n\n // ── ads ──\n\n private maybeRequestAds(index: number, item: PlayableItem, _isFallback: boolean): void {\n if (this.lastAdsIndex === index) return;\n this.lastAdsIndex = index;\n this.ctx.requestFreshAd(item.adTagPreroll || this.rawOptions.adTagPreroll);\n }\n\n // ── sources ──\n\n private resolveMode(item: PlayableItem): SourceMode {\n if (this.options.preferHls) return this.hasMode(item, 'hls') ? 'hls' : this.hasMode(item, 'mp4') ? 'mp4' : 'hls';\n return this.hasMode(item, 'mp4') ? 'mp4' : this.hasMode(item, 'hls') ? 'hls' : 'mp4';\n }\n\n private hasMode(item: PlayableItem, mode: SourceMode): boolean {\n return Array.isArray(item[mode]) && item[mode]!.some((v) => v?.src);\n }\n\n private buildPayload(item: PlayableItem, mode: SourceMode, mp4Index = 0): { src: string; type?: string } | null {\n const list = (item[mode] || []).filter((v) => v?.src);\n if (!list.length) return null;\n\n let src;\n if (mode === 'mp4') {\n src = mp4Index > 0 ? list[mp4Index] || list[0] : list.find((v) => v.selected) || list[0];\n } else {\n src = list[0];\n }\n return { src: src!.src, type: src!.type || (mode === 'hls' ? 'application/x-mpegURL' : 'video/mp4') };\n }\n\n private shouldAutoPlay(userInitiated: boolean): boolean {\n if (userInitiated) return true;\n return this.options.autoplayNext && this.userHasStartedPlayback;\n }\n\n private clampIndex(i: number): number {\n if (!Number.isFinite(i) || !this.items.length) return 0;\n return Math.max(0, Math.min(this.items.length - 1, Math.trunc(i)));\n }\n\n // ── ui ──\n\n private buildUi() {\n const ui = this.rawOptions.ui ?? {};\n const root = document.createElement('div');\n root.setAttribute('part', 'playlist-panel');\n root.className = 'hp:flex hp:flex-col hp:gap-2 hp:p-3 hp:bg-surface-elev hp:max-h-80 hp:overflow-y-auto';\n\n const header = document.createElement('div');\n header.className = 'hp:flex hp:items-center hp:justify-between hp:gap-2 hp:mb-1';\n\n const titleEl = document.createElement('div');\n titleEl.className = 'hp:text-sm hp:font-semibold hp:text-on-surface';\n titleEl.textContent = this.playlistTitleText();\n header.appendChild(titleEl);\n\n const navWrap = document.createElement('div');\n navWrap.className = 'hp:flex hp:gap-1';\n const prevBtn = this.navButton('chevron-left', this.ctx.i18n.playlistPrev, () => this.prev());\n const nextBtn = this.navButton('chevron-left', this.ctx.i18n.playlistNext, () => this.next());\n nextBtn.style.transform = 'rotate(180deg)';\n navWrap.append(prevBtn, nextBtn);\n header.appendChild(navWrap);\n\n root.appendChild(header);\n\n const listEl = document.createElement('ul');\n listEl.className = 'hp:flex hp:flex-col hp:gap-1 hp:list-none hp:m-0 hp:p-0';\n root.appendChild(listEl);\n\n const itemEls: Array<{ li: HTMLElement; titleRow: HTMLElement; progressFill: HTMLElement | null; timeEl: HTMLElement | null }> = [];\n this.items.forEach((item, idx) => {\n const li = document.createElement('li');\n li.className =\n 'hp:flex hp:items-center hp:gap-2 hp:p-2 hp:rounded hp:cursor-pointer hp:text-on-surface-muted hp:text-sm ' +\n 'hp:hover:bg-on-surface/5 hp:data-[active=true]:bg-accent/15 hp:data-[active=true]:text-on-surface';\n\n if (item.image) {\n const img = document.createElement('img');\n img.src = item.image;\n img.loading = 'lazy';\n img.className = 'hp:w-16 hp:aspect-video hp:object-cover hp:rounded hp:shrink-0';\n li.appendChild(img);\n }\n\n const body = document.createElement('div');\n body.className = 'hp:flex-1 hp:min-w-0';\n const titleRow = document.createElement('div');\n titleRow.className = 'hp:truncate hp:font-medium';\n titleRow.textContent = item.title || this.ctx.i18n.videoFallbackTitle(idx);\n body.appendChild(titleRow);\n\n let progressFill: HTMLElement | null = null;\n let timeEl: HTMLElement | null = null;\n if (ui.showMeta !== false) {\n const metaRow = document.createElement('div');\n metaRow.className = 'hp:flex hp:items-center hp:gap-2 hp:text-xs hp:opacity-70 hp:mt-0.5';\n timeEl = document.createElement('span');\n timeEl.textContent = '';\n metaRow.appendChild(timeEl);\n\n const bar = document.createElement('div');\n bar.className = 'hp:flex-1 hp:h-0.5 hp:bg-on-surface/20 hp:rounded-full hp:overflow-hidden';\n progressFill = document.createElement('div');\n progressFill.className = 'hp:h-full hp:bg-accent';\n progressFill.style.width = '0%';\n bar.appendChild(progressFill);\n metaRow.appendChild(bar);\n body.appendChild(metaRow);\n }\n\n li.appendChild(body);\n li.addEventListener('click', () => this.setIndex(idx));\n listEl.appendChild(li);\n itemEls.push({ li, titleRow, progressFill, timeEl });\n });\n\n this.ctx.panelEl.appendChild(root);\n return { root, titleEl, listEl, prevBtn, nextBtn, itemEls };\n }\n\n private playlistTitleText(): string {\n const ui = this.rawOptions.ui ?? {};\n const title = ui.title || this.ctx.i18n.playlistTitle;\n return ui.showCount === false ? title : `${title} (${this.items.length})`;\n }\n\n private navButton(iconName: string, label: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.setAttribute('aria-label', label);\n btn.className = 'hp:flex hp:items-center hp:justify-center hp:w-6 hp:h-6 hp:text-on-surface hp:bg-transparent hp:border-0 hp:cursor-pointer';\n btn.appendChild(createIcon(iconName, 'hp:text-sm'));\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n private setActive(index: number): void {\n this.ui.itemEls.forEach((entry, idx) => {\n if (idx === index) entry.li.setAttribute('data-active', 'true');\n else entry.li.removeAttribute('data-active');\n });\n // loadAndPlay() hem anlık UI geri bildirimi için önceden (next/prev/setIndex\n // içinden) hem de kaynak gerçekten yüklendiğinde setActive() çağırıyor —\n // aynı index için event'i yalnızca BİR kez yaymak için guard.\n if (this.lastDispatchedIndex !== index) {\n this.lastDispatchedIndex = index;\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:itemchange', { detail: { index, source: 'playlist' } }));\n }\n }\n\n private updateProgress(): void {\n const active = this.ui.itemEls[this.index];\n if (!active) return;\n const duration = this.ctx.videoEl.duration;\n const current = this.ctx.videoEl.currentTime;\n if (active.timeEl) active.timeEl.textContent = this.formatTime(current);\n if (active.progressFill && Number.isFinite(duration) && duration > 0) {\n active.progressFill.style.width = `${Math.min(100, (current / duration) * 100)}%`;\n }\n }\n\n private formatTime(sec: number): string {\n const s = Math.max(0, Math.floor(sec || 0));\n const m = Math.floor(s / 60);\n const r = s % 60;\n return `${m}:${String(r).padStart(2, '0')}`;\n }\n}\n","import { PlaylistRunner, type PlaylistPlayerContext } from './PlaylistRunner';\nimport type { PlaylistOptions } from '../../types';\n\nexport function installPlaylist(ctx: PlaylistPlayerContext, options: PlaylistOptions): PlaylistRunner {\n return new PlaylistRunner(ctx, options);\n}\n\nexport { PlaylistRunner };\nexport type { PlaylistPlayerContext };\n"],"names":["DEFAULTS","PlaylistRunner","ctx","rawOptions","__publicField","now","entry","idx","item","opts","i","attemptId","mode","tried","mp4Index","_a","_b","payload","mp4List","v","nextMp4","otherMode","index","_isFallback","list","src","userInitiated","ui","root","header","titleEl","navWrap","prevBtn","nextBtn","listEl","itemEls","li","img","body","titleRow","progressFill","timeEl","metaRow","bar","title","iconName","label","onClick","btn","createIcon","active","duration","current","sec","s","m","r","installPlaylist","options"],"mappings":"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"}
|