@hopeplayer/core 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/HopePlayerElement.d.ts +29 -4
- package/dist/HopePlayerElement.d.ts.map +1 -1
- package/dist/chunks/NativeEme-CXosVcw8.js +80 -0
- package/dist/chunks/NativeEme-CXosVcw8.js.map +1 -0
- package/dist/chunks/{accessibility-CehDBG3h.js → accessibility-DFx4CE0H.js} +45 -41
- package/dist/chunks/accessibility-DFx4CE0H.js.map +1 -0
- package/dist/chunks/{ads-BFmyld9u.js → ads-C4tDPsUs.js} +3 -3
- package/dist/chunks/ads-C4tDPsUs.js.map +1 -0
- package/dist/chunks/analytics-DEjTAJO9.js +281 -0
- package/dist/chunks/analytics-DEjTAJO9.js.map +1 -0
- package/dist/chunks/{cast-DJXOJLEZ.js → cast-Baxvu76A.js} +2 -2
- package/dist/chunks/{cast-DJXOJLEZ.js.map → cast-Baxvu76A.js.map} +1 -1
- package/dist/chunks/dash-CWjy-y7B.js +22 -0
- package/dist/chunks/dash-CWjy-y7B.js.map +1 -0
- package/dist/chunks/{history-YQ9A8HBv.js → history-CvydU0aN.js} +2 -2
- package/dist/chunks/{history-YQ9A8HBv.js.map → history-CvydU0aN.js.map} +1 -1
- package/dist/chunks/keySystems-CNzjRq6e.js +70 -0
- package/dist/chunks/keySystems-CNzjRq6e.js.map +1 -0
- package/dist/chunks/{markers-BmcD53SJ.js → markers-Dr4-CCxE.js} +2 -2
- package/dist/chunks/{markers-BmcD53SJ.js.map → markers-Dr4-CCxE.js.map} +1 -1
- package/dist/chunks/{player-BVkwkn4b.js → player-DV4Hf5Cw.js} +1320 -993
- package/dist/chunks/player-DV4Hf5Cw.js.map +1 -0
- package/dist/chunks/{playlist-jDbObKz3.js → playlist-DJsdK6xm.js} +29 -21
- package/dist/chunks/playlist-DJsdK6xm.js.map +1 -0
- package/dist/chunks/pluginHost-GxNfyP5E.js +566 -0
- package/dist/chunks/pluginHost-GxNfyP5E.js.map +1 -0
- package/dist/chunks/{redirectScreen-CFZKtEdv.js → redirectScreen-BT_26-5g.js} +2 -2
- package/dist/chunks/{redirectScreen-CFZKtEdv.js.map → redirectScreen-BT_26-5g.js.map} +1 -1
- package/dist/chunks/{rewardedUnlock-Cn4_68a3.js → rewardedUnlock-jFOdzfSq.js} +2 -2
- package/dist/chunks/{rewardedUnlock-Cn4_68a3.js.map → rewardedUnlock-jFOdzfSq.js.map} +1 -1
- package/dist/chunks/{segments-DXARAkpS.js → segments--hl_QVrI.js} +2 -2
- package/dist/chunks/{segments-DXARAkpS.js.map → segments--hl_QVrI.js.map} +1 -1
- package/dist/chunks/{skipSegments-U0aUwoDt.js → skipSegments-vJMhdiJn.js} +55 -42
- package/dist/chunks/{skipSegments-U0aUwoDt.js.map → skipSegments-vJMhdiJn.js.map} +1 -1
- package/dist/chunks/{spriteThumbnails-DLfTFsPU.js → spriteThumbnails-BoxVY--_.js} +76 -53
- package/dist/chunks/spriteThumbnails-BoxVY--_.js.map +1 -0
- package/dist/chunks/{statsPanel-DSClIwA3.js → statsPanel-D0DtoFgS.js} +2 -2
- package/dist/chunks/statsPanel-D0DtoFgS.js.map +1 -0
- package/dist/chunks/{story-Ce56rEaN.js → story-BRkhSDhR.js} +2 -2
- package/dist/chunks/{story-Ce56rEaN.js.map → story-BRkhSDhR.js.map} +1 -1
- package/dist/controls/ControlBar.d.ts +2 -0
- package/dist/controls/ControlBar.d.ts.map +1 -1
- package/dist/controls/SeekBar.d.ts.map +1 -1
- package/dist/controls/SettingsMenu.d.ts +5 -0
- package/dist/controls/SettingsMenu.d.ts.map +1 -1
- package/dist/drm/NativeEme.d.ts +23 -0
- package/dist/drm/NativeEme.d.ts.map +1 -0
- package/dist/drm/keySystems.d.ts +18 -0
- package/dist/drm/keySystems.d.ts.map +1 -0
- package/dist/hls/SourceManager.d.ts +31 -5
- package/dist/hls/SourceManager.d.ts.map +1 -1
- package/dist/hls/dashEngine.d.ts +85 -0
- package/dist/hls/dashEngine.d.ts.map +1 -0
- package/dist/hls/sourceGroups.d.ts.map +1 -1
- package/dist/hope-player.js +6 -3
- 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 +3 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/keyboard/KeyboardController.d.ts +14 -0
- package/dist/keyboard/KeyboardController.d.ts.map +1 -1
- package/dist/plugin-api/PluginAds.d.ts +61 -0
- package/dist/plugin-api/PluginAds.d.ts.map +1 -0
- package/dist/plugin-api/PluginHost.d.ts +71 -0
- package/dist/plugin-api/PluginHost.d.ts.map +1 -0
- package/dist/plugin-api/registry.d.ts +10 -0
- package/dist/plugin-api/registry.d.ts.map +1 -0
- package/dist/plugin-api/types.d.ts +209 -0
- package/dist/plugin-api/types.d.ts.map +1 -0
- package/dist/plugins/accessibility/Accessibility.d.ts +5 -0
- package/dist/plugins/accessibility/Accessibility.d.ts.map +1 -1
- package/dist/plugins/ads/AdsController.d.ts +2 -0
- package/dist/plugins/ads/AdsController.d.ts.map +1 -1
- package/dist/plugins/analytics/QoeTracker.d.ts +71 -0
- package/dist/plugins/analytics/QoeTracker.d.ts.map +1 -0
- package/dist/plugins/analytics/index.d.ts +6 -0
- package/dist/plugins/analytics/index.d.ts.map +1 -0
- package/dist/plugins/playlist/PlaylistRunner.d.ts +2 -0
- package/dist/plugins/playlist/PlaylistRunner.d.ts.map +1 -1
- package/dist/plugins/skip-segments/index.d.ts +2 -0
- package/dist/plugins/skip-segments/index.d.ts.map +1 -1
- package/dist/plugins/sprite-thumbnails/SpriteThumbnails.d.ts +8 -0
- package/dist/plugins/sprite-thumbnails/SpriteThumbnails.d.ts.map +1 -1
- package/dist/screens/ErrorScreen.d.ts +1 -1
- package/dist/screens/ErrorScreen.d.ts.map +1 -1
- package/dist/types/index.d.ts +159 -4
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/chunks/accessibility-CehDBG3h.js.map +0 -1
- package/dist/chunks/ads-BFmyld9u.js.map +0 -1
- package/dist/chunks/player-BVkwkn4b.js.map +0 -1
- package/dist/chunks/playlist-jDbObKz3.js.map +0 -1
- package/dist/chunks/spriteThumbnails-DLfTFsPU.js.map +0 -1
- package/dist/chunks/statsPanel-DSClIwA3.js.map +0 -1
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
var c = Object.defineProperty;
|
|
2
|
-
var p = (
|
|
3
|
-
var
|
|
4
|
-
import { c as m, v } from "./player-
|
|
5
|
-
const
|
|
6
|
-
class
|
|
2
|
+
var p = (i, e, t) => e in i ? c(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
|
|
3
|
+
var h = (i, e, t) => p(i, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import { c as m, v, d as b } from "./player-DV4Hf5Cw.js";
|
|
5
|
+
const k = 0.25;
|
|
6
|
+
class g {
|
|
7
7
|
constructor(e, t) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
h(this, "active", null);
|
|
9
|
+
h(this, "button", null);
|
|
10
|
+
h(this, "labelEl", null);
|
|
11
11
|
/** Kullanıcının (bizim değil) yaptığı sarma — bir sonraki timeupdate'te işlenir. */
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
h(this, "userSeeked", !1);
|
|
13
|
+
h(this, "ownSeek", !1);
|
|
14
|
+
h(this, "onSeeking", () => {
|
|
15
15
|
this.ownSeek ? this.ownSeek = !1 : this.userSeeked = !0;
|
|
16
16
|
});
|
|
17
|
-
|
|
17
|
+
h(this, "onSourceChange", () => {
|
|
18
18
|
this.hide(), this.userSeeked = !1;
|
|
19
19
|
});
|
|
20
|
-
|
|
21
|
-
var
|
|
20
|
+
h(this, "update", () => {
|
|
21
|
+
var o;
|
|
22
22
|
const t = this.ctx.videoEl.currentTime, s = this.userSeeked;
|
|
23
23
|
this.userSeeked = !1;
|
|
24
|
-
let
|
|
24
|
+
let n = null;
|
|
25
25
|
if (!this.ctx.isAdActive())
|
|
26
|
-
for (let
|
|
27
|
-
const
|
|
28
|
-
if (l === null || !Number.isFinite(
|
|
29
|
-
const d = Math.max(
|
|
30
|
-
if (t >= d && t < u -
|
|
31
|
-
|
|
26
|
+
for (let a = 0; a < this.segments.length; a++) {
|
|
27
|
+
const r = this.segments[a], l = this.endOf(r);
|
|
28
|
+
if (l === null || !Number.isFinite(r.start)) continue;
|
|
29
|
+
const d = Math.max(r.start, Number.isFinite(r.showFrom) ? r.showFrom : r.start), u = Number.isFinite(r.showUntil) ? Math.min(r.showUntil, l) : l;
|
|
30
|
+
if (t >= d && t < u - k) {
|
|
31
|
+
n = { index: a, segment: r, end: l };
|
|
32
32
|
break;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
if (!
|
|
35
|
+
if (!n) {
|
|
36
36
|
this.hide();
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
((
|
|
39
|
+
((o = this.active) == null ? void 0 : o.index) !== n.index ? (this.hide(), this.active = { ...n, shownAt: t, autoCancelled: s }, this.show(), this.emit("shown")) : s && (this.active.autoCancelled = !0, this.active.shownAt = Math.min(this.active.shownAt, t)), this.tick(t);
|
|
40
40
|
});
|
|
41
41
|
this.ctx = e, this.segments = t;
|
|
42
42
|
const s = e.videoEl;
|
|
@@ -64,26 +64,26 @@ class k {
|
|
|
64
64
|
tick(e) {
|
|
65
65
|
const t = this.active;
|
|
66
66
|
if (!t || !this.button) return;
|
|
67
|
-
const s = Math.max(0, e - t.shownAt),
|
|
68
|
-
this.button.toggleAttribute("data-faded",
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
67
|
+
const s = Math.max(0, e - t.shownAt), n = t.segment.hideAfter ?? 0;
|
|
68
|
+
this.button.toggleAttribute("data-faded", n > 0 && s >= n);
|
|
69
|
+
const o = t.segment.autoSkip;
|
|
70
|
+
if (!o || t.autoCancelled) {
|
|
71
71
|
this.button.removeAttribute("data-auto");
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
|
-
const
|
|
75
|
-
if (s >=
|
|
74
|
+
const a = o === !0 ? 0 : Math.max(0, o);
|
|
75
|
+
if (s >= a) {
|
|
76
76
|
this.skip("auto");
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
|
-
this.button.setAttribute("data-auto", ""), this.button.style.setProperty("--hp-skip-progress", String(
|
|
79
|
+
this.button.setAttribute("data-auto", ""), this.button.style.setProperty("--hp-skip-progress", String(a ? s / a : 1));
|
|
80
80
|
}
|
|
81
81
|
show() {
|
|
82
82
|
const e = this.active, t = document.createElement("button");
|
|
83
83
|
t.type = "button", t.className = "hp-skip-segment", t.setAttribute("part", "skip-segment"), t.setAttribute("data-position", e.segment.position ?? "bottom-right"), t.setAttribute("data-type", e.segment.type ?? "intro");
|
|
84
84
|
const s = document.createElement("span");
|
|
85
85
|
s.className = "hp-skip-segment-label", s.textContent = this.label(e.segment), t.append(s, m("skip-forward", "hp-skip-segment-icon")), t.addEventListener("click", () => this.skip("click"));
|
|
86
|
-
for (const
|
|
86
|
+
for (const n of ["pointerdown", "pointerup", "click", "dblclick"]) t.addEventListener(n, (o) => o.stopPropagation());
|
|
87
87
|
this.ctx.overlayContainerEl.appendChild(t), this.button = t, this.labelEl = s;
|
|
88
88
|
}
|
|
89
89
|
hide() {
|
|
@@ -100,23 +100,36 @@ class k {
|
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
102
|
skip(e) {
|
|
103
|
-
var
|
|
103
|
+
var o, a;
|
|
104
104
|
const t = this.active;
|
|
105
105
|
if (!t) return;
|
|
106
|
-
const s = !!((
|
|
106
|
+
const s = !!((o = this.button) != null && o.matches(":focus"));
|
|
107
107
|
if (!this.emit("skip", e)) {
|
|
108
|
-
t.autoCancelled = !0, (
|
|
108
|
+
t.autoCancelled = !0, (a = this.button) == null || a.removeAttribute("data-auto");
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
|
-
const
|
|
112
|
-
this.hide(), this.ownSeek = !0,
|
|
111
|
+
const n = this.ctx.videoEl;
|
|
112
|
+
this.hide(), this.ownSeek = !0, n.currentTime = v(n, t.end), s && this.ctx.hostEl.focus({ preventScroll: !0 });
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
const S = b({
|
|
116
|
+
name: "hope:skip-segments",
|
|
117
|
+
setup(i, e) {
|
|
118
|
+
const t = i.ui.addLayer({ position: "fill" }), s = new g(
|
|
119
|
+
{
|
|
120
|
+
hostEl: i.element,
|
|
121
|
+
videoEl: i.video,
|
|
122
|
+
overlayContainerEl: t.el,
|
|
123
|
+
isAdActive: () => i.isAdPlaying,
|
|
124
|
+
i18n: i.labels
|
|
125
|
+
},
|
|
126
|
+
e
|
|
127
|
+
);
|
|
128
|
+
return i.onLocaleChange(() => s.refreshLabels()), () => s.destroy();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
118
131
|
export {
|
|
119
|
-
|
|
120
|
-
|
|
132
|
+
g as SkipSegments,
|
|
133
|
+
S as skipSegmentsPlugin
|
|
121
134
|
};
|
|
122
|
-
//# sourceMappingURL=skipSegments-
|
|
135
|
+
//# sourceMappingURL=skipSegments-vJMhdiJn.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skipSegments-U0aUwoDt.js","sources":["../../src/plugins/skip-segments/SkipSegments.ts","../../src/plugins/skip-segments/index.ts"],"sourcesContent":["import type { SkipSegment, SkipSegmentType } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { createIcon } from '../../icons/Icon';\nimport { vodSeekTarget } from '../../utils/seek-by';\n\nexport interface SkipSegmentsPlayerContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n overlayContainerEl: HTMLElement;\n isAdActive(): boolean;\n i18n: HopeLocaleStrings;\n}\n\n/** Bölüm sonuna bu kadar kala buton kalkar — sona yaklaşırken bir an görünüp kaybolmasın. */\nconst END_MARGIN_SEC = 0.25;\n\ninterface Active {\n index: number;\n segment: SkipSegment;\n end: number;\n /** Butonun göründüğü video zamanı — `hideAfter` / `autoSkip` geri sayımı video zamanıyla işler (duraklatınca durur). */\n shownAt: number;\n /** Kullanıcı bölüme sararak girdi ya da bölüm içinde geri sardı → bu gösterimde otomatik atlama yok. */\n autoCancelled: boolean;\n}\n\n/**\n * \"İntroyu atla\" / \"Özeti atla\" / \"Jeneriği atla\": bölüm oynarken köşede bir buton, basınca bölümün sonuna atlar.\n * `autoSkip` ile basılmadan (isteğe bağlı geri sayımla) atlar; `hideAfter` ile bir süre sonra çekilir, kontroller\n * açılınca geri gelir. Reklam sırasında görünmez. `hp:skip` (`skip`) iptal edilebilir.\n */\nexport class SkipSegments {\n private active: Active | null = null;\n private button: HTMLButtonElement | null = null;\n private labelEl: HTMLSpanElement | null = null;\n /** Kullanıcının (bizim değil) yaptığı sarma — bir sonraki timeupdate'te işlenir. */\n private userSeeked = false;\n private ownSeek = false;\n\n constructor(\n private readonly ctx: SkipSegmentsPlayerContext,\n private readonly segments: SkipSegment[]\n ) {\n const v = ctx.videoEl;\n v.addEventListener('timeupdate', this.update);\n v.addEventListener('seeking', this.onSeeking);\n v.addEventListener('seeked', this.update);\n v.addEventListener('loadstart', this.onSourceChange);\n ctx.hostEl.addEventListener('hp:adstart', this.update);\n ctx.hostEl.addEventListener('hp:adend', this.update);\n this.update();\n }\n\n destroy(): void {\n const v = this.ctx.videoEl;\n v.removeEventListener('timeupdate', this.update);\n v.removeEventListener('seeking', this.onSeeking);\n v.removeEventListener('seeked', this.update);\n v.removeEventListener('loadstart', this.onSourceChange);\n this.ctx.hostEl.removeEventListener('hp:adstart', this.update);\n this.ctx.hostEl.removeEventListener('hp:adend', this.update);\n this.hide();\n }\n\n refreshLabels(): void {\n if (this.active && this.labelEl) this.labelEl.textContent = this.label(this.active.segment);\n }\n\n private label(s: SkipSegment): string {\n if (s.label) return s.label;\n const t = this.ctx.i18n;\n const byType: Record<SkipSegmentType, string> = { intro: t.skipIntro, recap: t.skipRecap, credits: t.skipCredits, custom: t.skipSegment };\n return byType[s.type ?? 'intro'] ?? t.skipSegment;\n }\n\n /** Bölümün sonu: `end` yoksa videonun sonu (süre bilinmiyorsa bölüm yok sayılır). */\n private endOf(s: SkipSegment): number | null {\n if (Number.isFinite(s.end)) return s.end!;\n const d = this.ctx.videoEl.duration;\n return Number.isFinite(d) && d > 0 ? d : null;\n }\n\n private readonly onSeeking = (): void => {\n if (this.ownSeek) this.ownSeek = false;\n else this.userSeeked = true;\n };\n\n private readonly onSourceChange = (): void => {\n this.hide();\n this.userSeeked = false;\n };\n\n private readonly update = (): void => {\n const v = this.ctx.videoEl;\n const t = v.currentTime;\n const seeked = this.userSeeked;\n this.userSeeked = false;\n\n let found: { index: number; segment: SkipSegment; end: number } | null = null;\n if (!this.ctx.isAdActive()) {\n for (let i = 0; i < this.segments.length; i++) {\n const s = this.segments[i]!;\n const end = this.endOf(s);\n if (end === null || !Number.isFinite(s.start)) continue;\n const from = Math.max(s.start, Number.isFinite(s.showFrom) ? s.showFrom! : s.start);\n const until = Number.isFinite(s.showUntil) ? Math.min(s.showUntil!, end) : end;\n if (t >= from && t < until - END_MARGIN_SEC) {\n found = { index: i, segment: s, end };\n break;\n }\n }\n }\n\n if (!found) {\n this.hide();\n return;\n }\n if (this.active?.index !== found.index) {\n this.hide();\n this.active = { ...found, shownAt: t, autoCancelled: seeked };\n this.show();\n this.emit('shown');\n } else if (seeked) {\n // Bölüm içinde sarma: geri sardıysa (kullanıcı bölümü izlemek istiyor) otomatik atlama bu gösterimde kapanır.\n this.active.autoCancelled = true;\n this.active.shownAt = Math.min(this.active.shownAt, t);\n }\n this.tick(t);\n };\n\n /** `hideAfter` (çekilme) ve `autoSkip` geri sayımı. */\n private tick(t: number): void {\n const a = this.active;\n if (!a || !this.button) return;\n const elapsed = Math.max(0, t - a.shownAt);\n const hideAfter = a.segment.hideAfter ?? 0;\n this.button.toggleAttribute('data-faded', hideAfter > 0 && elapsed >= hideAfter);\n\n const auto = a.segment.autoSkip;\n if (!auto || a.autoCancelled) {\n this.button.removeAttribute('data-auto');\n return;\n }\n const delay = auto === true ? 0 : Math.max(0, auto);\n if (elapsed >= delay) {\n this.skip('auto');\n return;\n }\n this.button.setAttribute('data-auto', '');\n this.button.style.setProperty('--hp-skip-progress', String(delay ? elapsed / delay : 1));\n }\n\n private show(): void {\n const a = this.active!;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hp-skip-segment';\n btn.setAttribute('part', 'skip-segment');\n btn.setAttribute('data-position', a.segment.position ?? 'bottom-right');\n btn.setAttribute('data-type', a.segment.type ?? 'intro');\n const label = document.createElement('span');\n label.className = 'hp-skip-segment-label';\n label.textContent = this.label(a.segment);\n btn.append(label, createIcon('skip-forward', 'hp-skip-segment-icon'));\n btn.addEventListener('click', () => this.skip('click'));\n // Oynat/duraklat ve çift tık tam ekran alttaki video alanına geçmesin.\n for (const ev of ['pointerdown', 'pointerup', 'click', 'dblclick'] as const) btn.addEventListener(ev, (e) => e.stopPropagation());\n this.ctx.overlayContainerEl.appendChild(btn);\n this.button = btn;\n this.labelEl = label;\n }\n\n private hide(): void {\n this.button?.remove();\n this.button = null;\n this.labelEl = null;\n this.active = null;\n }\n\n private emit(state: 'shown' | 'skip', reason?: 'click' | 'auto'): boolean {\n const a = this.active!;\n return this.ctx.hostEl.dispatchEvent(\n new CustomEvent('hp:skip', {\n detail: { state, type: a.segment.type ?? 'intro', start: a.segment.start, end: a.end, reason },\n cancelable: state === 'skip',\n })\n );\n }\n\n private skip(reason: 'click' | 'auto'): void {\n const a = this.active;\n if (!a) return;\n const focused = !!this.button?.matches(':focus');\n if (!this.emit('skip', reason)) {\n // Entegratör kendisi halletti — bu gösterim için otomatik atlama tekrar tetiklenmesin.\n a.autoCancelled = true;\n this.button?.removeAttribute('data-auto');\n return;\n }\n const v = this.ctx.videoEl;\n this.hide();\n this.ownSeek = true;\n v.currentTime = vodSeekTarget(v, a.end);\n // Klavyeyle basıldıysa odak kaybolmasın — player'a dön (kısayollar çalışmaya devam etsin).\n if (focused) this.ctx.hostEl.focus({ preventScroll: true });\n }\n}\n","import { SkipSegments, type SkipSegmentsPlayerContext } from './SkipSegments';\nimport type { SkipSegment } from '../../types';\n\nexport function installSkipSegments(ctx: SkipSegmentsPlayerContext, segments: SkipSegment[]): SkipSegments {\n return new SkipSegments(ctx, segments);\n}\n\nexport { SkipSegments };\nexport type { SkipSegmentsPlayerContext };\n"],"names":["END_MARGIN_SEC","SkipSegments","ctx","segments","__publicField","seeked","found","i","s","end","from","until","_a","v","d","t","a","elapsed","hideAfter","auto","delay","btn","label","createIcon","ev","e","state","reason","focused","_b","vodSeekTarget","installSkipSegments"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skipSegments-vJMhdiJn.js","sources":["../../src/plugins/skip-segments/SkipSegments.ts","../../src/plugins/skip-segments/index.ts"],"sourcesContent":["import type { SkipSegment, SkipSegmentType } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { createIcon } from '../../icons/Icon';\nimport { vodSeekTarget } from '../../utils/seek-by';\n\nexport interface SkipSegmentsPlayerContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n overlayContainerEl: HTMLElement;\n isAdActive(): boolean;\n i18n: HopeLocaleStrings;\n}\n\n/** Bölüm sonuna bu kadar kala buton kalkar — sona yaklaşırken bir an görünüp kaybolmasın. */\nconst END_MARGIN_SEC = 0.25;\n\ninterface Active {\n index: number;\n segment: SkipSegment;\n end: number;\n /** Butonun göründüğü video zamanı — `hideAfter` / `autoSkip` geri sayımı video zamanıyla işler (duraklatınca durur). */\n shownAt: number;\n /** Kullanıcı bölüme sararak girdi ya da bölüm içinde geri sardı → bu gösterimde otomatik atlama yok. */\n autoCancelled: boolean;\n}\n\n/**\n * \"İntroyu atla\" / \"Özeti atla\" / \"Jeneriği atla\": bölüm oynarken köşede bir buton, basınca bölümün sonuna atlar.\n * `autoSkip` ile basılmadan (isteğe bağlı geri sayımla) atlar; `hideAfter` ile bir süre sonra çekilir, kontroller\n * açılınca geri gelir. Reklam sırasında görünmez. `hp:skip` (`skip`) iptal edilebilir.\n */\nexport class SkipSegments {\n private active: Active | null = null;\n private button: HTMLButtonElement | null = null;\n private labelEl: HTMLSpanElement | null = null;\n /** Kullanıcının (bizim değil) yaptığı sarma — bir sonraki timeupdate'te işlenir. */\n private userSeeked = false;\n private ownSeek = false;\n\n constructor(\n private readonly ctx: SkipSegmentsPlayerContext,\n private readonly segments: SkipSegment[]\n ) {\n const v = ctx.videoEl;\n v.addEventListener('timeupdate', this.update);\n v.addEventListener('seeking', this.onSeeking);\n v.addEventListener('seeked', this.update);\n v.addEventListener('loadstart', this.onSourceChange);\n ctx.hostEl.addEventListener('hp:adstart', this.update);\n ctx.hostEl.addEventListener('hp:adend', this.update);\n this.update();\n }\n\n destroy(): void {\n const v = this.ctx.videoEl;\n v.removeEventListener('timeupdate', this.update);\n v.removeEventListener('seeking', this.onSeeking);\n v.removeEventListener('seeked', this.update);\n v.removeEventListener('loadstart', this.onSourceChange);\n this.ctx.hostEl.removeEventListener('hp:adstart', this.update);\n this.ctx.hostEl.removeEventListener('hp:adend', this.update);\n this.hide();\n }\n\n refreshLabels(): void {\n if (this.active && this.labelEl) this.labelEl.textContent = this.label(this.active.segment);\n }\n\n private label(s: SkipSegment): string {\n if (s.label) return s.label;\n const t = this.ctx.i18n;\n const byType: Record<SkipSegmentType, string> = { intro: t.skipIntro, recap: t.skipRecap, credits: t.skipCredits, custom: t.skipSegment };\n return byType[s.type ?? 'intro'] ?? t.skipSegment;\n }\n\n /** Bölümün sonu: `end` yoksa videonun sonu (süre bilinmiyorsa bölüm yok sayılır). */\n private endOf(s: SkipSegment): number | null {\n if (Number.isFinite(s.end)) return s.end!;\n const d = this.ctx.videoEl.duration;\n return Number.isFinite(d) && d > 0 ? d : null;\n }\n\n private readonly onSeeking = (): void => {\n if (this.ownSeek) this.ownSeek = false;\n else this.userSeeked = true;\n };\n\n private readonly onSourceChange = (): void => {\n this.hide();\n this.userSeeked = false;\n };\n\n private readonly update = (): void => {\n const v = this.ctx.videoEl;\n const t = v.currentTime;\n const seeked = this.userSeeked;\n this.userSeeked = false;\n\n let found: { index: number; segment: SkipSegment; end: number } | null = null;\n if (!this.ctx.isAdActive()) {\n for (let i = 0; i < this.segments.length; i++) {\n const s = this.segments[i]!;\n const end = this.endOf(s);\n if (end === null || !Number.isFinite(s.start)) continue;\n const from = Math.max(s.start, Number.isFinite(s.showFrom) ? s.showFrom! : s.start);\n const until = Number.isFinite(s.showUntil) ? Math.min(s.showUntil!, end) : end;\n if (t >= from && t < until - END_MARGIN_SEC) {\n found = { index: i, segment: s, end };\n break;\n }\n }\n }\n\n if (!found) {\n this.hide();\n return;\n }\n if (this.active?.index !== found.index) {\n this.hide();\n this.active = { ...found, shownAt: t, autoCancelled: seeked };\n this.show();\n this.emit('shown');\n } else if (seeked) {\n // Bölüm içinde sarma: geri sardıysa (kullanıcı bölümü izlemek istiyor) otomatik atlama bu gösterimde kapanır.\n this.active.autoCancelled = true;\n this.active.shownAt = Math.min(this.active.shownAt, t);\n }\n this.tick(t);\n };\n\n /** `hideAfter` (çekilme) ve `autoSkip` geri sayımı. */\n private tick(t: number): void {\n const a = this.active;\n if (!a || !this.button) return;\n const elapsed = Math.max(0, t - a.shownAt);\n const hideAfter = a.segment.hideAfter ?? 0;\n this.button.toggleAttribute('data-faded', hideAfter > 0 && elapsed >= hideAfter);\n\n const auto = a.segment.autoSkip;\n if (!auto || a.autoCancelled) {\n this.button.removeAttribute('data-auto');\n return;\n }\n const delay = auto === true ? 0 : Math.max(0, auto);\n if (elapsed >= delay) {\n this.skip('auto');\n return;\n }\n this.button.setAttribute('data-auto', '');\n this.button.style.setProperty('--hp-skip-progress', String(delay ? elapsed / delay : 1));\n }\n\n private show(): void {\n const a = this.active!;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hp-skip-segment';\n btn.setAttribute('part', 'skip-segment');\n btn.setAttribute('data-position', a.segment.position ?? 'bottom-right');\n btn.setAttribute('data-type', a.segment.type ?? 'intro');\n const label = document.createElement('span');\n label.className = 'hp-skip-segment-label';\n label.textContent = this.label(a.segment);\n btn.append(label, createIcon('skip-forward', 'hp-skip-segment-icon'));\n btn.addEventListener('click', () => this.skip('click'));\n // Oynat/duraklat ve çift tık tam ekran alttaki video alanına geçmesin.\n for (const ev of ['pointerdown', 'pointerup', 'click', 'dblclick'] as const) btn.addEventListener(ev, (e) => e.stopPropagation());\n this.ctx.overlayContainerEl.appendChild(btn);\n this.button = btn;\n this.labelEl = label;\n }\n\n private hide(): void {\n this.button?.remove();\n this.button = null;\n this.labelEl = null;\n this.active = null;\n }\n\n private emit(state: 'shown' | 'skip', reason?: 'click' | 'auto'): boolean {\n const a = this.active!;\n return this.ctx.hostEl.dispatchEvent(\n new CustomEvent('hp:skip', {\n detail: { state, type: a.segment.type ?? 'intro', start: a.segment.start, end: a.end, reason },\n cancelable: state === 'skip',\n })\n );\n }\n\n private skip(reason: 'click' | 'auto'): void {\n const a = this.active;\n if (!a) return;\n const focused = !!this.button?.matches(':focus');\n if (!this.emit('skip', reason)) {\n // Entegratör kendisi halletti — bu gösterim için otomatik atlama tekrar tetiklenmesin.\n a.autoCancelled = true;\n this.button?.removeAttribute('data-auto');\n return;\n }\n const v = this.ctx.videoEl;\n this.hide();\n this.ownSeek = true;\n v.currentTime = vodSeekTarget(v, a.end);\n // Klavyeyle basıldıysa odak kaybolmasın — player'a dön (kısayollar çalışmaya devam etsin).\n if (focused) this.ctx.hostEl.focus({ preventScroll: true });\n }\n}\n","import { SkipSegments, type SkipSegmentsPlayerContext } from './SkipSegments';\nimport type { SkipSegment } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { definePlugin } from '../../plugin-api/registry';\n\nexport function installSkipSegments(ctx: SkipSegmentsPlayerContext, segments: SkipSegment[]): SkipSegments {\n return new SkipSegments(ctx, segments);\n}\n\n/** \"İntroyu atla\", herkese açık eklenti API'si üzerinden. */\nexport const skipSegmentsPlugin = definePlugin<SkipSegment[]>({\n name: 'hope:skip-segments',\n setup(player, segments) {\n const layer = player.ui.addLayer({ position: 'fill' });\n const skip = new SkipSegments(\n {\n hostEl: player.element,\n videoEl: player.video,\n overlayContainerEl: layer.el,\n isAdActive: () => player.isAdPlaying,\n i18n: player.labels as unknown as HopeLocaleStrings,\n },\n segments\n );\n player.onLocaleChange(() => skip.refreshLabels());\n return () => skip.destroy();\n },\n});\n\nexport { SkipSegments };\nexport type { SkipSegmentsPlayerContext };\n"],"names":["END_MARGIN_SEC","SkipSegments","ctx","segments","__publicField","seeked","found","i","s","end","from","until","_a","v","d","t","a","elapsed","hideAfter","auto","delay","btn","label","createIcon","ev","e","state","reason","focused","_b","vodSeekTarget","skipSegmentsPlugin","definePlugin","player","layer","skip"],"mappings":";;;;AAcA,MAAMA,IAAiB;AAiBhB,MAAMC,EAAa;AAAA,EAQtB,YACqBC,GACAC,GACnB;AAVM,IAAAC,EAAA,gBAAwB;AACxB,IAAAA,EAAA,gBAAmC;AACnC,IAAAA,EAAA,iBAAkC;AAElC;AAAA,IAAAA,EAAA,oBAAa;AACb,IAAAA,EAAA,iBAAU;AA6CD,IAAAA,EAAA,mBAAY,MAAY;AACrC,MAAI,KAAK,UAAS,KAAK,UAAU,UACvB,aAAa;AAAA,IAC3B;AAEiB,IAAAA,EAAA,wBAAiB,MAAY;AAC1C,WAAK,KAAA,GACL,KAAK,aAAa;AAAA,IACtB;AAEiB,IAAAA,EAAA,gBAAS,MAAY;;AAElC,YAAM,IADI,KAAK,IAAI,QACP,aACNC,IAAS,KAAK;AACpB,WAAK,aAAa;AAElB,UAAIC,IAAqE;AACzE,UAAI,CAAC,KAAK,IAAI;AACV,iBAASC,IAAI,GAAGA,IAAI,KAAK,SAAS,QAAQA,KAAK;AAC3C,gBAAMC,IAAI,KAAK,SAASD,CAAC,GACnBE,IAAM,KAAK,MAAMD,CAAC;AACxB,cAAIC,MAAQ,QAAQ,CAAC,OAAO,SAASD,EAAE,KAAK,EAAG;AAC/C,gBAAME,IAAO,KAAK,IAAIF,EAAE,OAAO,OAAO,SAASA,EAAE,QAAQ,IAAIA,EAAE,WAAYA,EAAE,KAAK,GAC5EG,IAAQ,OAAO,SAASH,EAAE,SAAS,IAAI,KAAK,IAAIA,EAAE,WAAYC,CAAG,IAAIA;AAC3E,cAAI,KAAKC,KAAQ,IAAIC,IAAQX,GAAgB;AACzC,YAAAM,IAAQ,EAAE,OAAOC,GAAG,SAASC,GAAG,KAAAC,EAAA;AAChC;AAAA,UACJ;AAAA,QACJ;AAGJ,UAAI,CAACH,GAAO;AACR,aAAK,KAAA;AACL;AAAA,MACJ;AACA,QAAIM,IAAA,KAAK,WAAL,gBAAAA,EAAa,WAAUN,EAAM,SAC7B,KAAK,KAAA,GACL,KAAK,SAAS,EAAE,GAAGA,GAAO,SAAS,GAAG,eAAeD,EAAA,GACrD,KAAK,KAAA,GACL,KAAK,KAAK,OAAO,KACVA,MAEP,KAAK,OAAO,gBAAgB,IAC5B,KAAK,OAAO,UAAU,KAAK,IAAI,KAAK,OAAO,SAAS,CAAC,IAEzD,KAAK,KAAK,CAAC;AAAA,IACf;AAxFqB,SAAA,MAAAH,GACA,KAAA,WAAAC;AAEjB,UAAMU,IAAIX,EAAI;AACd,IAAAW,EAAE,iBAAiB,cAAc,KAAK,MAAM,GAC5CA,EAAE,iBAAiB,WAAW,KAAK,SAAS,GAC5CA,EAAE,iBAAiB,UAAU,KAAK,MAAM,GACxCA,EAAE,iBAAiB,aAAa,KAAK,cAAc,GACnDX,EAAI,OAAO,iBAAiB,cAAc,KAAK,MAAM,GACrDA,EAAI,OAAO,iBAAiB,YAAY,KAAK,MAAM,GACnD,KAAK,OAAA;AAAA,EACT;AAAA,EAEA,UAAgB;AACZ,UAAMW,IAAI,KAAK,IAAI;AACnB,IAAAA,EAAE,oBAAoB,cAAc,KAAK,MAAM,GAC/CA,EAAE,oBAAoB,WAAW,KAAK,SAAS,GAC/CA,EAAE,oBAAoB,UAAU,KAAK,MAAM,GAC3CA,EAAE,oBAAoB,aAAa,KAAK,cAAc,GACtD,KAAK,IAAI,OAAO,oBAAoB,cAAc,KAAK,MAAM,GAC7D,KAAK,IAAI,OAAO,oBAAoB,YAAY,KAAK,MAAM,GAC3D,KAAK,KAAA;AAAA,EACT;AAAA,EAEA,gBAAsB;AAClB,IAAI,KAAK,UAAU,KAAK,YAAS,KAAK,QAAQ,cAAc,KAAK,MAAM,KAAK,OAAO,OAAO;AAAA,EAC9F;AAAA,EAEQ,MAAML,GAAwB;AAClC,QAAIA,EAAE,MAAO,QAAOA,EAAE;AACtB,UAAM,IAAI,KAAK,IAAI;AAEnB,WADgD,EAAE,OAAO,EAAE,WAAW,OAAO,EAAE,WAAW,SAAS,EAAE,aAAa,QAAQ,EAAE,YAAA,EAC9GA,EAAE,QAAQ,OAAO,KAAK,EAAE;AAAA,EAC1C;AAAA;AAAA,EAGQ,MAAMA,GAA+B;AACzC,QAAI,OAAO,SAASA,EAAE,GAAG,UAAUA,EAAE;AACrC,UAAMM,IAAI,KAAK,IAAI,QAAQ;AAC3B,WAAO,OAAO,SAASA,CAAC,KAAKA,IAAI,IAAIA,IAAI;AAAA,EAC7C;AAAA;AAAA,EAmDQ,KAAKC,GAAiB;AAC1B,UAAMC,IAAI,KAAK;AACf,QAAI,CAACA,KAAK,CAAC,KAAK,OAAQ;AACxB,UAAMC,IAAU,KAAK,IAAI,GAAGF,IAAIC,EAAE,OAAO,GACnCE,IAAYF,EAAE,QAAQ,aAAa;AACzC,SAAK,OAAO,gBAAgB,cAAcE,IAAY,KAAKD,KAAWC,CAAS;AAE/E,UAAMC,IAAOH,EAAE,QAAQ;AACvB,QAAI,CAACG,KAAQH,EAAE,eAAe;AAC1B,WAAK,OAAO,gBAAgB,WAAW;AACvC;AAAA,IACJ;AACA,UAAMI,IAAQD,MAAS,KAAO,IAAI,KAAK,IAAI,GAAGA,CAAI;AAClD,QAAIF,KAAWG,GAAO;AAClB,WAAK,KAAK,MAAM;AAChB;AAAA,IACJ;AACA,SAAK,OAAO,aAAa,aAAa,EAAE,GACxC,KAAK,OAAO,MAAM,YAAY,sBAAsB,OAAOA,IAAQH,IAAUG,IAAQ,CAAC,CAAC;AAAA,EAC3F;AAAA,EAEQ,OAAa;AACjB,UAAMJ,IAAI,KAAK,QACTK,IAAM,SAAS,cAAc,QAAQ;AAC3C,IAAAA,EAAI,OAAO,UACXA,EAAI,YAAY,mBAChBA,EAAI,aAAa,QAAQ,cAAc,GACvCA,EAAI,aAAa,iBAAiBL,EAAE,QAAQ,YAAY,cAAc,GACtEK,EAAI,aAAa,aAAaL,EAAE,QAAQ,QAAQ,OAAO;AACvD,UAAMM,IAAQ,SAAS,cAAc,MAAM;AAC3C,IAAAA,EAAM,YAAY,yBAClBA,EAAM,cAAc,KAAK,MAAMN,EAAE,OAAO,GACxCK,EAAI,OAAOC,GAAOC,EAAW,gBAAgB,sBAAsB,CAAC,GACpEF,EAAI,iBAAiB,SAAS,MAAM,KAAK,KAAK,OAAO,CAAC;AAEtD,eAAWG,KAAM,CAAC,eAAe,aAAa,SAAS,UAAU,EAAY,CAAAH,EAAI,iBAAiBG,GAAI,CAACC,MAAMA,EAAE,iBAAiB;AAChI,SAAK,IAAI,mBAAmB,YAAYJ,CAAG,GAC3C,KAAK,SAASA,GACd,KAAK,UAAUC;AAAA,EACnB;AAAA,EAEQ,OAAa;;AACjB,KAAAV,IAAA,KAAK,WAAL,QAAAA,EAAa,UACb,KAAK,SAAS,MACd,KAAK,UAAU,MACf,KAAK,SAAS;AAAA,EAClB;AAAA,EAEQ,KAAKc,GAAyBC,GAAoC;AACtE,UAAMX,IAAI,KAAK;AACf,WAAO,KAAK,IAAI,OAAO;AAAA,MACnB,IAAI,YAAY,WAAW;AAAA,QACvB,QAAQ,EAAE,OAAAU,GAAO,MAAMV,EAAE,QAAQ,QAAQ,SAAS,OAAOA,EAAE,QAAQ,OAAO,KAAKA,EAAE,KAAK,QAAAW,EAAA;AAAA,QACtF,YAAYD,MAAU;AAAA,MAAA,CACzB;AAAA,IAAA;AAAA,EAET;AAAA,EAEQ,KAAKC,GAAgC;;AACzC,UAAMX,IAAI,KAAK;AACf,QAAI,CAACA,EAAG;AACR,UAAMY,IAAU,CAAC,GAAChB,IAAA,KAAK,WAAL,QAAAA,EAAa,QAAQ;AACvC,QAAI,CAAC,KAAK,KAAK,QAAQe,CAAM,GAAG;AAE5B,MAAAX,EAAE,gBAAgB,KAClBa,IAAA,KAAK,WAAL,QAAAA,EAAa,gBAAgB;AAC7B;AAAA,IACJ;AACA,UAAMhB,IAAI,KAAK,IAAI;AACnB,SAAK,KAAA,GACL,KAAK,UAAU,IACfA,EAAE,cAAciB,EAAcjB,GAAGG,EAAE,GAAG,GAElCY,UAAc,IAAI,OAAO,MAAM,EAAE,eAAe,IAAM;AAAA,EAC9D;AACJ;ACpMO,MAAMG,IAAqBC,EAA4B;AAAA,EAC1D,MAAM;AAAA,EACN,MAAMC,GAAQ9B,GAAU;AACpB,UAAM+B,IAAQD,EAAO,GAAG,SAAS,EAAE,UAAU,QAAQ,GAC/CE,IAAO,IAAIlC;AAAA,MACb;AAAA,QACI,QAAQgC,EAAO;AAAA,QACf,SAASA,EAAO;AAAA,QAChB,oBAAoBC,EAAM;AAAA,QAC1B,YAAY,MAAMD,EAAO;AAAA,QACzB,MAAMA,EAAO;AAAA,MAAA;AAAA,MAEjB9B;AAAA,IAAA;AAEJ,WAAA8B,EAAO,eAAe,MAAME,EAAK,cAAA,CAAe,GACzC,MAAMA,EAAK,QAAA;AAAA,EACtB;AACJ,CAAC;"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var l = (
|
|
4
|
-
import { f as
|
|
5
|
-
const
|
|
6
|
-
class
|
|
1
|
+
var w = Object.defineProperty;
|
|
2
|
+
var E = (u, t, e) => t in u ? w(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
|
|
3
|
+
var l = (u, t, e) => E(u, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { f as y } from "./player-DV4Hf5Cw.js";
|
|
5
|
+
const x = 8, v = /%(0(\d+))?d/;
|
|
6
|
+
class S {
|
|
7
7
|
constructor(t, e) {
|
|
8
8
|
l(this, "tooltip");
|
|
9
9
|
l(this, "imageEl");
|
|
@@ -13,6 +13,10 @@ class M {
|
|
|
13
13
|
l(this, "vttLoading", null);
|
|
14
14
|
/** Çok parçalı modda otomatik hesaplanan sheet süresi (ilk sheet yüklenince). */
|
|
15
15
|
l(this, "derivedSheetDuration", null);
|
|
16
|
+
/** `lowRes` sheet'i — LRU dışında, hep bellekte. */
|
|
17
|
+
l(this, "lowSheet", null);
|
|
18
|
+
/** Son çizilen asıl karenin genişliği (VTT'de `width` yok). */
|
|
19
|
+
l(this, "lastFrameWidth", 0);
|
|
16
20
|
l(this, "warmed", !1);
|
|
17
21
|
l(this, "hovering", !1);
|
|
18
22
|
l(this, "lastClientX", 0);
|
|
@@ -30,8 +34,9 @@ class M {
|
|
|
30
34
|
});
|
|
31
35
|
/** İlk ihtiyaç anında (hover / oynatma) kaynağı hazırla — kurulumda hiçbir şey indirilmiyor. */
|
|
32
36
|
l(this, "warm", () => {
|
|
37
|
+
var i;
|
|
33
38
|
if (this.warmed || this.destroyed) return;
|
|
34
|
-
if (this.warmed = !0, this.options.vtt) {
|
|
39
|
+
if (this.warmed = !0, (i = this.options.lowRes) != null && i.url && (this.lowSheet = this.createSheet(this.options.lowRes.url, () => this.hovering && this.scheduleRender())), this.options.vtt) {
|
|
35
40
|
this.loadVtt();
|
|
36
41
|
return;
|
|
37
42
|
}
|
|
@@ -43,7 +48,7 @@ class M {
|
|
|
43
48
|
destroy() {
|
|
44
49
|
this.destroyed = !0, this.rafId !== null && cancelAnimationFrame(this.rafId), this.ctx.seekBar.el.removeEventListener("pointerenter", this.onPointerEnter), this.ctx.seekBar.el.removeEventListener("pointermove", this.onPointerMove), this.ctx.seekBar.el.removeEventListener("pointerleave", this.onPointerLeave), this.ctx.videoEl.removeEventListener("play", this.warm), this.tooltip.remove(), this.ctx.seekBar.suppressHoverTime("sprite", !1);
|
|
45
50
|
for (const t of this.sheets.values()) t.img.src = "";
|
|
46
|
-
this.sheets.clear();
|
|
51
|
+
this.lowSheet && (this.lowSheet.img.src = ""), this.sheets.clear();
|
|
47
52
|
}
|
|
48
53
|
scheduleRender() {
|
|
49
54
|
this.rafId === null && (this.rafId = requestAnimationFrame(() => {
|
|
@@ -52,19 +57,22 @@ class M {
|
|
|
52
57
|
}
|
|
53
58
|
// ── çizim ──
|
|
54
59
|
render() {
|
|
60
|
+
var h;
|
|
55
61
|
if (!this.hovering || this.destroyed) return;
|
|
56
62
|
const t = this.ctx.videoEl.duration;
|
|
57
63
|
if (!Number.isFinite(t) || t <= 0) return;
|
|
58
64
|
const e = this.ctx.seekBar.ratioAtClientX(this.lastClientX) * t;
|
|
59
|
-
this.timeEl.textContent =
|
|
60
|
-
const i = this.isNetworkEligible() ? this.frameAt(e, t) : null
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
this.timeEl.textContent = y(e);
|
|
66
|
+
const i = this.isNetworkEligible() ? this.frameAt(e, t) : null;
|
|
67
|
+
i && (this.lastFrameWidth = i.w);
|
|
68
|
+
const s = i ?? this.lowResFrameAt(e, t), n = i ? this.sheets.get(i.url).img : (h = this.lowSheet) == null ? void 0 : h.img;
|
|
69
|
+
if (s && n) {
|
|
70
|
+
const d = (this.options.displayWidth ?? (i ? i.w : this.options.width || this.lastFrameWidth || s.w)) * this.scale(), c = d / s.w;
|
|
71
|
+
this.imageEl.style.display = "", this.imageEl.toggleAttribute("data-lowres", !i), this.imageEl.style.width = `${d}px`, this.imageEl.style.height = `${s.h * c}px`, this.imageEl.style.backgroundImage = `url("${s.url}")`, this.imageEl.style.backgroundSize = `${n.naturalWidth * c}px ${n.naturalHeight * c}px`, this.imageEl.style.backgroundPosition = `${-s.x * c}px ${-s.y * c}px`;
|
|
64
72
|
} else this.imageEl.style.backgroundImage || (this.imageEl.style.display = "none");
|
|
65
73
|
this.tooltip.setAttribute("data-visible", "");
|
|
66
|
-
const
|
|
67
|
-
this.tooltip.style.transform = `translateX(${
|
|
74
|
+
const r = this.ctx.seekBar.el.getBoundingClientRect(), o = this.tooltip.offsetWidth, a = Math.min(Math.max(this.lastClientX - r.left - o / 2, 0), Math.max(r.width - o, 0));
|
|
75
|
+
this.tooltip.style.transform = `translateX(${a}px)`;
|
|
68
76
|
}
|
|
69
77
|
scale() {
|
|
70
78
|
const t = this.options.responsive, e = this.ctx.playerWidth();
|
|
@@ -76,13 +84,21 @@ class M {
|
|
|
76
84
|
return e === void 0 || e >= (this.options.downlink ?? 2) || i;
|
|
77
85
|
}
|
|
78
86
|
// ── kare çözümleme ──
|
|
87
|
+
/** `lowRes` sheet'inden saniyedeki kare (hazır değilse null). */
|
|
88
|
+
lowResFrameAt(t, e) {
|
|
89
|
+
var h;
|
|
90
|
+
const i = this.options.lowRes, s = (h = this.lowSheet) != null && h.ready ? this.lowSheet.img : null;
|
|
91
|
+
if (!i || !s || !i.width || !i.height) return null;
|
|
92
|
+
const n = Math.max(1, Math.floor(s.naturalWidth / i.width)), r = n * Math.max(1, Math.floor(s.naturalHeight / i.height)), o = i.interval || e / r, a = Math.min(r - 1, Math.max(0, Math.floor(t / o)));
|
|
93
|
+
return { url: i.url, x: a % n * i.width, y: Math.floor(a / n) * i.height, w: i.width, h: i.height };
|
|
94
|
+
}
|
|
79
95
|
/** Saniyedeki kareyi döner; gereken sheet hazır değilse yüklemeyi başlatıp null döner (yüklenince render tekrar çağrılır). */
|
|
80
96
|
frameAt(t, e) {
|
|
81
97
|
return this.options.vtt ? this.vttFrameAt(t) : this.gridFrameAt(t, e);
|
|
82
98
|
}
|
|
83
99
|
isMultiSheet() {
|
|
84
100
|
var t;
|
|
85
|
-
return !!((t = this.options.sheets) != null && t.length) ||
|
|
101
|
+
return !!((t = this.options.sheets) != null && t.length) || v.test(this.options.url ?? "");
|
|
86
102
|
}
|
|
87
103
|
/** Tek sheet → Infinity (tüm video); çok parçalı → verilen ya da ilk sheet'ten hesaplanan süre; henüz bilinmiyorsa null. */
|
|
88
104
|
sheetDuration() {
|
|
@@ -100,7 +116,7 @@ class M {
|
|
|
100
116
|
var s;
|
|
101
117
|
if ((s = this.options.sheets) != null && s.length) return this.options.sheets[Math.min(t, this.options.sheets.length - 1)];
|
|
102
118
|
const e = this.options.url ?? "", i = t + (this.options.firstSheetIndex ?? 1);
|
|
103
|
-
return e.replace(
|
|
119
|
+
return e.replace(v, (n, r, o) => String(i).padStart(o ? Number(o) : 0, "0"));
|
|
104
120
|
}
|
|
105
121
|
gridFrameAt(t, e) {
|
|
106
122
|
const { width: i, height: s } = this.options;
|
|
@@ -108,14 +124,14 @@ class M {
|
|
|
108
124
|
const n = this.options.interval || 1, r = this.sheetDuration();
|
|
109
125
|
if (r === null)
|
|
110
126
|
return this.ensureSheet(this.sheetUrl(0)), null;
|
|
111
|
-
const
|
|
112
|
-
this.preloadAround(
|
|
113
|
-
const d = this.sheets.get(
|
|
127
|
+
const o = r === 1 / 0 ? 0 : this.sheetIndexAt(Math.max(0, e - 1e-3)), a = Math.min(this.sheetIndexAt(t), o), h = this.sheetUrl(a);
|
|
128
|
+
this.preloadAround(a, o);
|
|
129
|
+
const d = this.sheets.get(h);
|
|
114
130
|
if (!(d != null && d.ready))
|
|
115
|
-
return this.ensureSheet(
|
|
116
|
-
this.touch(
|
|
117
|
-
const
|
|
118
|
-
return { url:
|
|
131
|
+
return this.ensureSheet(h), null;
|
|
132
|
+
this.touch(h);
|
|
133
|
+
const c = Math.max(1, Math.floor(d.img.naturalWidth / i)), p = Math.max(1, Math.floor(d.img.naturalHeight / s)), m = r === 1 / 0 ? t : t - a * r, f = Math.min(Math.max(0, Math.floor(m / n)), c * p - 1);
|
|
134
|
+
return { url: h, x: f % c * i, y: Math.floor(f / c) * s, w: i, h: s };
|
|
119
135
|
}
|
|
120
136
|
preloadAround(t, e) {
|
|
121
137
|
const i = this.options.preloadSheets ?? 1;
|
|
@@ -129,23 +145,30 @@ class M {
|
|
|
129
145
|
if (!e.length) return null;
|
|
130
146
|
let i = 0, s = e.length - 1;
|
|
131
147
|
for (; i < s; ) {
|
|
132
|
-
const
|
|
133
|
-
e[
|
|
148
|
+
const h = i + s + 1 >> 1;
|
|
149
|
+
e[h].start <= t ? i = h : s = h - 1;
|
|
134
150
|
}
|
|
135
151
|
const n = e[i];
|
|
136
|
-
[e[i + 1], e[i - 1]].filter((
|
|
137
|
-
const
|
|
138
|
-
if (!(
|
|
152
|
+
[e[i + 1], e[i - 1]].filter((h) => !!h && h.url !== n.url).forEach((h) => void this.ensureSheet(h.url));
|
|
153
|
+
const o = this.sheets.get(n.url);
|
|
154
|
+
if (!(o != null && o.ready))
|
|
139
155
|
return this.ensureSheet(n.url), null;
|
|
140
156
|
this.touch(n.url);
|
|
141
|
-
const
|
|
142
|
-
return { url: n.url, ...
|
|
157
|
+
const a = n.rect ?? { x: 0, y: 0, w: o.img.naturalWidth, h: o.img.naturalHeight };
|
|
158
|
+
return { url: n.url, ...a };
|
|
143
159
|
}
|
|
144
160
|
// ── yükleme / cache ──
|
|
145
161
|
ensureSheet(t) {
|
|
146
162
|
if (!t) return Promise.resolve();
|
|
147
163
|
const e = this.sheets.get(t);
|
|
148
164
|
if (e) return e.promise;
|
|
165
|
+
const i = this.createSheet(t, (s) => {
|
|
166
|
+
this.learnSheetDuration(s), this.hovering && this.scheduleRender();
|
|
167
|
+
});
|
|
168
|
+
return this.sheets.set(t, i), this.evict(), i.promise;
|
|
169
|
+
}
|
|
170
|
+
/** Görseli yükler; decode bitmeden hazır sayılmaz (sheet geçişinde titreme olmasın). */
|
|
171
|
+
createSheet(t, e) {
|
|
149
172
|
const i = new Image();
|
|
150
173
|
i.decoding = "async";
|
|
151
174
|
const s = { img: i, ready: !1, failed: !1, promise: Promise.resolve() };
|
|
@@ -153,13 +176,13 @@ class M {
|
|
|
153
176
|
i.onload = () => {
|
|
154
177
|
const r = () => {
|
|
155
178
|
if (this.destroyed) return n();
|
|
156
|
-
s.ready = !0,
|
|
179
|
+
s.ready = !0, e(i), n();
|
|
157
180
|
};
|
|
158
181
|
i.decode ? i.decode().then(r, r) : r();
|
|
159
182
|
}, i.onerror = () => {
|
|
160
183
|
s.failed = !0, n();
|
|
161
184
|
};
|
|
162
|
-
}), i.src = t,
|
|
185
|
+
}), i.src = t, s;
|
|
163
186
|
}
|
|
164
187
|
/** Çok parçalı modda `sheetDuration` verilmediyse ilk yüklenen sheet'in ızgara kapasitesinden hesapla. */
|
|
165
188
|
learnSheetDuration(t) {
|
|
@@ -175,7 +198,7 @@ class M {
|
|
|
175
198
|
e && (this.sheets.delete(t), this.sheets.set(t, e));
|
|
176
199
|
}
|
|
177
200
|
evict() {
|
|
178
|
-
for (; this.sheets.size >
|
|
201
|
+
for (; this.sheets.size > x; ) {
|
|
179
202
|
const t = this.sheets.keys().next().value, e = this.sheets.get(t);
|
|
180
203
|
e.img.onload = null, e.img.onerror = null, this.sheets.delete(t);
|
|
181
204
|
}
|
|
@@ -187,39 +210,39 @@ class M {
|
|
|
187
210
|
if (!e.ok) throw new Error(`HTTP ${e.status}`);
|
|
188
211
|
return e.text();
|
|
189
212
|
}).then((e) => {
|
|
190
|
-
this.destroyed || (this.vttCues =
|
|
213
|
+
this.destroyed || (this.vttCues = M(e, new URL(t, document.baseURI).href), this.vttCues.length && this.ensureSheet(this.vttCues[0].url), this.hovering && this.scheduleRender());
|
|
191
214
|
}).catch((e) => {
|
|
192
215
|
console.warn("[HopePlayer sprite-thumbnails] VTT yüklenemedi:", e), this.vttCues = [];
|
|
193
216
|
}), this.vttLoading;
|
|
194
217
|
}
|
|
195
218
|
}
|
|
196
|
-
function g(
|
|
197
|
-
return
|
|
219
|
+
function g(u) {
|
|
220
|
+
return u.trim().split(":").map(Number).reduce((e, i) => e * 60 + i, 0);
|
|
198
221
|
}
|
|
199
|
-
function
|
|
222
|
+
function M(u, t) {
|
|
200
223
|
var s;
|
|
201
|
-
const e = [], i =
|
|
224
|
+
const e = [], i = u.replace(/\r/g, "").split(/\n\n+/);
|
|
202
225
|
for (const n of i) {
|
|
203
226
|
const r = n.split(`
|
|
204
|
-
`).filter(Boolean),
|
|
205
|
-
if (
|
|
206
|
-
const [
|
|
207
|
-
if (!
|
|
208
|
-
const [
|
|
227
|
+
`).filter(Boolean), o = r.findIndex((f) => f.includes("-->"));
|
|
228
|
+
if (o === -1) continue;
|
|
229
|
+
const [a, h] = r[o].split("-->"), d = (s = r[o + 1]) == null ? void 0 : s.trim();
|
|
230
|
+
if (!a || !h || !d) continue;
|
|
231
|
+
const [c, p] = d.split("#"), m = p == null ? void 0 : p.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
|
|
209
232
|
e.push({
|
|
210
|
-
start: g(
|
|
211
|
-
end: g(
|
|
212
|
-
url: new URL(
|
|
213
|
-
rect:
|
|
233
|
+
start: g(a),
|
|
234
|
+
end: g(h.trim().split(/\s+/)[0]),
|
|
235
|
+
url: new URL(c, t).href,
|
|
236
|
+
rect: m ? { x: +m[1], y: +m[2], w: +m[3], h: +m[4] } : null
|
|
214
237
|
});
|
|
215
238
|
}
|
|
216
239
|
return e.sort((n, r) => n.start - r.start);
|
|
217
240
|
}
|
|
218
|
-
function
|
|
219
|
-
return new
|
|
241
|
+
function A(u, t) {
|
|
242
|
+
return new S(u, t);
|
|
220
243
|
}
|
|
221
244
|
export {
|
|
222
|
-
|
|
223
|
-
|
|
245
|
+
S as SpriteThumbnails,
|
|
246
|
+
A as installSpriteThumbnails
|
|
224
247
|
};
|
|
225
|
-
//# sourceMappingURL=spriteThumbnails-
|
|
248
|
+
//# sourceMappingURL=spriteThumbnails-BoxVY--_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spriteThumbnails-BoxVY--_.js","sources":["../../src/plugins/sprite-thumbnails/SpriteThumbnails.ts","../../src/plugins/sprite-thumbnails/index.ts"],"sourcesContent":["import type { SpriteThumbnailsOptions } from '../../types';\nimport { formatTime } from '../../utils/format-time';\n\nexport interface SpriteThumbnailsPlayerContext {\n videoEl: HTMLVideoElement;\n /** Önizlemenin bağlandığı seek bar — zaman eşlemesi (chapter boşlukları dahil) onun `ratioAtClientX`'inden. */\n seekBar: {\n readonly el: HTMLElement;\n ratioAtClientX(clientX: number): number;\n suppressHoverTime(key: string, suppressed: boolean): void;\n };\n /** Responsive ölçekleme için referans genişlik — genelde player/video alanının genişliği. */\n playerWidth(): number;\n}\n\n/** Bir önizleme karesi: hangi görselin hangi dikdörtgeni. */\ninterface Frame {\n url: string;\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\ninterface Sheet {\n img: HTMLImageElement;\n ready: boolean;\n failed: boolean;\n promise: Promise<void>;\n}\n\nexport interface VttCue {\n start: number;\n end: number;\n url: string;\n /** `#xywh` yoksa null → görselin tamamı. */\n rect: { x: number; y: number; w: number; h: number } | null;\n}\n\n/** Aynı anda bellekte (decode edilmiş) tutulan en fazla sheet — uzun videolarda bellek sınırsız büyümesin. */\nconst MAX_CACHED_SHEETS = 8;\n/** Sheet numarası şablonu: `%d` ya da sıfır dolgulu `%03d`. */\nconst SHEET_TEMPLATE = /%(0(\\d+))?d/;\n\n/**\n * Seek bar hover önizlemesi. Kaynak: tek görsel, çok parçalı (%d / %03d şablonu ya da sheets) veya WebVTT (#xywh).\n * sheetDuration verilmezse ilk sheet'in ızgarasından hesaplanır. Kurulumda hiçbir şey indirilmez; yalnızca imlecin\n * altındaki sheet + komşuları yüklenir, decode bitmeden gösterilmez, LRU cache.\n */\nexport class SpriteThumbnails {\n private readonly tooltip: HTMLElement;\n private readonly imageEl: HTMLElement;\n private readonly timeEl: HTMLElement;\n private readonly sheets = new Map<string, Sheet>();\n private vttCues: VttCue[] | null = null;\n private vttLoading: Promise<void> | null = null;\n /** Çok parçalı modda otomatik hesaplanan sheet süresi (ilk sheet yüklenince). */\n private derivedSheetDuration: number | null = null;\n /** `lowRes` sheet'i — LRU dışında, hep bellekte. */\n private lowSheet: Sheet | null = null;\n /** Son çizilen asıl karenin genişliği (VTT'de `width` yok). */\n private lastFrameWidth = 0;\n private warmed = false;\n private hovering = false;\n private lastClientX = 0;\n private rafId: number | null = null;\n private destroyed = false;\n\n constructor(\n private readonly ctx: SpriteThumbnailsPlayerContext,\n private readonly options: SpriteThumbnailsOptions\n ) {\n this.tooltip = document.createElement('div');\n this.tooltip.setAttribute('part', 'sprite-tooltip');\n this.tooltip.className = 'hp-sprite-tooltip';\n this.imageEl = document.createElement('div');\n this.imageEl.className = 'hp-sprite-image';\n this.timeEl = document.createElement('div');\n this.timeEl.className = 'hp-sprite-time';\n this.tooltip.append(this.imageEl, this.timeEl);\n ctx.seekBar.el.appendChild(this.tooltip);\n // Önizlemenin altında zaman zaten yazıyor — varsayılan hover zamanı ikinci kez göstermesin.\n ctx.seekBar.suppressHoverTime('sprite', true);\n\n ctx.seekBar.el.addEventListener('pointerenter', this.onPointerEnter);\n ctx.seekBar.el.addEventListener('pointermove', this.onPointerMove);\n ctx.seekBar.el.addEventListener('pointerleave', this.onPointerLeave);\n ctx.videoEl.addEventListener('play', this.warm);\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.ctx.seekBar.el.removeEventListener('pointerenter', this.onPointerEnter);\n this.ctx.seekBar.el.removeEventListener('pointermove', this.onPointerMove);\n this.ctx.seekBar.el.removeEventListener('pointerleave', this.onPointerLeave);\n this.ctx.videoEl.removeEventListener('play', this.warm);\n this.tooltip.remove();\n this.ctx.seekBar.suppressHoverTime('sprite', false);\n for (const sheet of this.sheets.values()) sheet.img.src = '';\n if (this.lowSheet) this.lowSheet.img.src = '';\n this.sheets.clear();\n }\n\n // ── olaylar ──\n\n private readonly onPointerEnter = (e: PointerEvent): void => {\n this.hovering = true;\n this.lastClientX = e.clientX;\n this.warm();\n this.scheduleRender();\n };\n\n private readonly onPointerMove = (e: PointerEvent): void => {\n this.hovering = true;\n this.lastClientX = e.clientX;\n this.scheduleRender();\n };\n\n private readonly onPointerLeave = (): void => {\n this.hovering = false;\n this.tooltip.removeAttribute('data-visible');\n };\n\n /** İlk ihtiyaç anında (hover / oynatma) kaynağı hazırla — kurulumda hiçbir şey indirilmiyor. */\n private readonly warm = (): void => {\n if (this.warmed || this.destroyed) return;\n this.warmed = true;\n // Küçük sheet bağlantı hızından bağımsız hemen iner.\n if (this.options.lowRes?.url) this.lowSheet = this.createSheet(this.options.lowRes.url, () => this.hovering && this.scheduleRender());\n if (this.options.vtt) {\n void this.loadVtt();\n return;\n }\n const duration = this.ctx.videoEl.duration;\n const t = Number.isFinite(duration) ? this.ctx.videoEl.currentTime : 0;\n // Şablonlu/çok parçalı modda sheet süresi henüz bilinmiyorsa ilk sheet'ten öğrenilecek.\n void this.ensureSheet(this.sheetUrl(this.isMultiSheet() && this.sheetDuration() === null ? 0 : this.sheetIndexAt(t)));\n };\n\n private scheduleRender(): void {\n if (this.rafId !== null) return;\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n this.render();\n });\n }\n\n // ── çizim ──\n\n private render(): void {\n if (!this.hovering || this.destroyed) return;\n const duration = this.ctx.videoEl.duration;\n if (!Number.isFinite(duration) || duration <= 0) return;\n\n const seconds = this.ctx.seekBar.ratioAtClientX(this.lastClientX) * duration;\n this.timeEl.textContent = formatTime(seconds);\n\n // Asıl kare hazır değilse küçük sheet'ten doğru zamanın karesi; o da yoksa son kare ekranda kalır.\n const hi = this.isNetworkEligible() ? this.frameAt(seconds, duration) : null;\n if (hi) this.lastFrameWidth = hi.w;\n const frame = hi ?? this.lowResFrameAt(seconds, duration);\n const img = hi ? this.sheets.get(hi.url)!.img : this.lowSheet?.img;\n if (frame && img) {\n // Hedef genişlik: displayWidth → kare genişliği; küçük kare aynı boyuta büyütülür.\n const target = (this.options.displayWidth ?? (hi ? hi.w : this.options.width || this.lastFrameWidth || frame.w)) * this.scale();\n const k = target / frame.w;\n this.imageEl.style.display = '';\n this.imageEl.toggleAttribute('data-lowres', !hi);\n this.imageEl.style.width = `${target}px`;\n this.imageEl.style.height = `${frame.h * k}px`;\n this.imageEl.style.backgroundImage = `url(\"${frame.url}\")`;\n this.imageEl.style.backgroundSize = `${img.naturalWidth * k}px ${img.naturalHeight * k}px`;\n this.imageEl.style.backgroundPosition = `${-frame.x * k}px ${-frame.y * k}px`;\n } else if (!this.imageEl.style.backgroundImage) {\n // Henüz hiçbir kare yüklenmedi — yalnızca zaman (yükleme bitince yeniden çizilir).\n this.imageEl.style.display = 'none';\n }\n\n // Kenarlarda taşmasın: imleci ortala ama seek bar sınırlarında kal.\n this.tooltip.setAttribute('data-visible', '');\n const barRect = this.ctx.seekBar.el.getBoundingClientRect();\n const tipWidth = this.tooltip.offsetWidth;\n const x = Math.min(Math.max(this.lastClientX - barRect.left - tipWidth / 2, 0), Math.max(barRect.width - tipWidth, 0));\n this.tooltip.style.transform = `translateX(${x}px)`;\n }\n\n private scale(): number {\n const responsive = this.options.responsive;\n const playerWidth = this.ctx.playerWidth();\n return responsive && playerWidth && playerWidth < responsive ? playerWidth / responsive : 1;\n }\n\n private isNetworkEligible(): boolean {\n const nav = navigator as Navigator & { connection?: { downlink?: number } };\n const downlink = nav.connection?.downlink;\n const anyReady = Array.from(this.sheets.values()).some((s) => s.ready);\n return downlink === undefined || downlink >= (this.options.downlink ?? 2) || anyReady;\n }\n\n // ── kare çözümleme ──\n\n /** `lowRes` sheet'inden saniyedeki kare (hazır değilse null). */\n private lowResFrameAt(seconds: number, duration: number): Frame | null {\n const o = this.options.lowRes;\n const img = this.lowSheet?.ready ? this.lowSheet.img : null;\n if (!o || !img || !o.width || !o.height) return null;\n const columns = Math.max(1, Math.floor(img.naturalWidth / o.width));\n const count = columns * Math.max(1, Math.floor(img.naturalHeight / o.height));\n const interval = o.interval || duration / count;\n const i = Math.min(count - 1, Math.max(0, Math.floor(seconds / interval)));\n return { url: o.url, x: (i % columns) * o.width, y: Math.floor(i / columns) * o.height, w: o.width, h: o.height };\n }\n\n /** Saniyedeki kareyi döner; gereken sheet hazır değilse yüklemeyi başlatıp null döner (yüklenince render tekrar çağrılır). */\n private frameAt(seconds: number, duration: number): Frame | null {\n return this.options.vtt ? this.vttFrameAt(seconds) : this.gridFrameAt(seconds, duration);\n }\n\n private isMultiSheet(): boolean {\n return !!this.options.sheets?.length || SHEET_TEMPLATE.test(this.options.url ?? '');\n }\n\n /** Tek sheet → Infinity (tüm video); çok parçalı → verilen ya da ilk sheet'ten hesaplanan süre; henüz bilinmiyorsa null. */\n private sheetDuration(): number | null {\n if (!this.isMultiSheet()) return Infinity;\n return this.options.sheetDuration ?? this.derivedSheetDuration;\n }\n\n private sheetIndexAt(seconds: number): number {\n const d = this.sheetDuration();\n if (d === null || d === Infinity) return 0;\n // floor (ceil DEĞİL): tam sınırda (ör. 60. sn) bir SONRAKİ sheet'in ilk karesi.\n let index = Math.floor(Math.max(0, seconds) / d);\n if (this.options.sheets?.length) index = Math.min(index, this.options.sheets.length - 1);\n return index;\n }\n\n /** 0 tabanlı sheet index'inden URL. */\n private sheetUrl(index: number): string {\n if (this.options.sheets?.length) return this.options.sheets[Math.min(index, this.options.sheets.length - 1)]!;\n const url = this.options.url ?? '';\n const number = index + (this.options.firstSheetIndex ?? 1);\n return url.replace(SHEET_TEMPLATE, (_m, _p, width?: string) => String(number).padStart(width ? Number(width) : 0, '0'));\n }\n\n private gridFrameAt(seconds: number, duration: number): Frame | null {\n const { width, height } = this.options;\n if (!width || !height) return null;\n const interval = this.options.interval || 1;\n\n const sheetDuration = this.sheetDuration();\n if (sheetDuration === null) {\n // Çok parçalı ama süre bilinmiyor — ilk sheet yüklenince hesaplanacak.\n void this.ensureSheet(this.sheetUrl(0));\n return null;\n }\n\n const lastIndex = sheetDuration === Infinity ? 0 : this.sheetIndexAt(Math.max(0, duration - 0.001));\n const index = Math.min(this.sheetIndexAt(seconds), lastIndex);\n const url = this.sheetUrl(index);\n this.preloadAround(index, lastIndex);\n\n const sheet = this.sheets.get(url);\n if (!sheet?.ready) {\n void this.ensureSheet(url);\n return null;\n }\n this.touch(url);\n\n // Her sheet'in KENDİ boyutu (son sheet daha kısa olabilir).\n const columns = Math.max(1, Math.floor(sheet.img.naturalWidth / width));\n const rows = Math.max(1, Math.floor(sheet.img.naturalHeight / height));\n const local = sheetDuration === Infinity ? seconds : seconds - index * sheetDuration;\n const frameIndex = Math.min(Math.max(0, Math.floor(local / interval)), columns * rows - 1);\n return { url, x: (frameIndex % columns) * width, y: Math.floor(frameIndex / columns) * height, w: width, h: height };\n }\n\n private preloadAround(index: number, lastIndex: number): void {\n const n = this.options.preloadSheets ?? 1;\n for (let d = 1; d <= n; d++) {\n if (index + d <= lastIndex) void this.ensureSheet(this.sheetUrl(index + d));\n if (index - d >= 0) void this.ensureSheet(this.sheetUrl(index - d));\n }\n }\n\n private vttFrameAt(seconds: number): Frame | null {\n if (!this.vttCues) {\n void this.loadVtt();\n return null;\n }\n const cues = this.vttCues;\n if (!cues.length) return null;\n // İkili arama — saatlerce süren videolarda binlerce cue olabilir.\n let lo = 0;\n let hi = cues.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (cues[mid]!.start <= seconds) lo = mid;\n else hi = mid - 1;\n }\n const cue = cues[lo]!;\n const neighbours = [cues[lo + 1], cues[lo - 1]].filter((c): c is VttCue => !!c && c.url !== cue.url);\n neighbours.forEach((c) => void this.ensureSheet(c.url));\n\n const sheet = this.sheets.get(cue.url);\n if (!sheet?.ready) {\n void this.ensureSheet(cue.url);\n return null;\n }\n this.touch(cue.url);\n const rect = cue.rect ?? { x: 0, y: 0, w: sheet.img.naturalWidth, h: sheet.img.naturalHeight };\n return { url: cue.url, ...rect };\n }\n\n // ── yükleme / cache ──\n\n private ensureSheet(url: string): Promise<void> {\n if (!url) return Promise.resolve();\n const existing = this.sheets.get(url);\n if (existing) return existing.promise;\n\n const sheet = this.createSheet(url, (img) => {\n this.learnSheetDuration(img);\n if (this.hovering) this.scheduleRender();\n });\n this.sheets.set(url, sheet);\n this.evict();\n return sheet.promise;\n }\n\n /** Görseli yükler; decode bitmeden hazır sayılmaz (sheet geçişinde titreme olmasın). */\n private createSheet(url: string, onReady: (img: HTMLImageElement) => void): Sheet {\n const img = new Image();\n img.decoding = 'async';\n const sheet: Sheet = { img, ready: false, failed: false, promise: Promise.resolve() };\n sheet.promise = new Promise<void>((resolve) => {\n img.onload = () => {\n const done = () => {\n if (this.destroyed) return resolve();\n sheet.ready = true;\n onReady(img);\n resolve();\n };\n img.decode ? img.decode().then(done, done) : done();\n };\n img.onerror = () => {\n sheet.failed = true;\n resolve();\n };\n });\n img.src = url;\n return sheet;\n }\n\n /** Çok parçalı modda `sheetDuration` verilmediyse ilk yüklenen sheet'in ızgara kapasitesinden hesapla. */\n private learnSheetDuration(img: HTMLImageElement): void {\n if (this.derivedSheetDuration !== null || this.options.vtt || !this.isMultiSheet() || this.options.sheetDuration) return;\n const { width, height } = this.options;\n if (!width || !height) return;\n const capacity = Math.max(1, Math.floor(img.naturalWidth / width)) * Math.max(1, Math.floor(img.naturalHeight / height));\n this.derivedSheetDuration = capacity * (this.options.interval || 1);\n }\n\n /** LRU: kullanılan sheet'i sona taşı. */\n private touch(url: string): void {\n const sheet = this.sheets.get(url);\n if (!sheet) return;\n this.sheets.delete(url);\n this.sheets.set(url, sheet);\n }\n\n private evict(): void {\n while (this.sheets.size > MAX_CACHED_SHEETS) {\n const oldest = this.sheets.keys().next().value as string;\n const sheet = this.sheets.get(oldest)!;\n sheet.img.onload = null;\n sheet.img.onerror = null;\n this.sheets.delete(oldest);\n }\n }\n\n private loadVtt(): Promise<void> {\n if (this.vttLoading) return this.vttLoading;\n const vttUrl = this.options.vtt!;\n this.vttLoading = fetch(vttUrl)\n .then((r) => {\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r.text();\n })\n .then((text) => {\n if (this.destroyed) return;\n this.vttCues = parseThumbnailVtt(text, new URL(vttUrl, document.baseURI).href);\n if (this.vttCues.length) void this.ensureSheet(this.vttCues[0]!.url);\n if (this.hovering) this.scheduleRender();\n })\n .catch((err) => {\n console.warn('[HopePlayer sprite-thumbnails] VTT yüklenemedi:', err);\n this.vttCues = [];\n });\n return this.vttLoading;\n }\n}\n\n/** \"01:02:03.500\" / \"02:03.500\" → saniye. */\nfunction parseVttTime(value: string): number {\n const parts = value.trim().split(':').map(Number);\n return parts.reduce((acc, n) => acc * 60 + n, 0);\n}\n\n/** WebVTT thumbnail dosyası → sıralı cue listesi. Görsel yolları VTT dosyasına göre çözümlenir. */\nexport function parseThumbnailVtt(text: string, baseUrl: string): VttCue[] {\n const cues: VttCue[] = [];\n const blocks = text.replace(/\\r/g, '').split(/\\n\\n+/);\n for (const block of blocks) {\n const lines = block.split('\\n').filter(Boolean);\n const timingIndex = lines.findIndex((l) => l.includes('-->'));\n if (timingIndex === -1) continue;\n const [startStr, endStr] = lines[timingIndex]!.split('-->');\n const target = lines[timingIndex + 1]?.trim();\n if (!startStr || !endStr || !target) continue;\n\n const [path, hash] = target.split('#');\n const match = hash?.match(/xywh=(\\d+),(\\d+),(\\d+),(\\d+)/);\n cues.push({\n start: parseVttTime(startStr),\n end: parseVttTime(endStr.trim().split(/\\s+/)[0]!),\n url: new URL(path!, baseUrl).href,\n rect: match ? { x: +match[1]!, y: +match[2]!, w: +match[3]!, h: +match[4]! } : null,\n });\n }\n return cues.sort((a, b) => a.start - b.start);\n}\n","import { SpriteThumbnails, type SpriteThumbnailsPlayerContext } from './SpriteThumbnails';\nimport type { SpriteThumbnailsOptions } from '../../types';\n\nexport function installSpriteThumbnails(ctx: SpriteThumbnailsPlayerContext, options: SpriteThumbnailsOptions): SpriteThumbnails {\n return new SpriteThumbnails(ctx, options);\n}\n\nexport { SpriteThumbnails };\nexport type { SpriteThumbnailsPlayerContext };\n"],"names":["MAX_CACHED_SHEETS","SHEET_TEMPLATE","SpriteThumbnails","ctx","options","__publicField","e","_a","duration","t","sheet","seconds","formatTime","hi","frame","img","target","k","barRect","tipWidth","x","responsive","playerWidth","downlink","anyReady","s","o","columns","count","interval","i","d","index","url","number","_m","_p","width","height","sheetDuration","lastIndex","rows","local","frameIndex","n","cues","lo","mid","cue","c","rect","existing","onReady","resolve","done","capacity","oldest","vttUrl","r","text","parseThumbnailVtt","err","parseVttTime","value","acc","baseUrl","blocks","block","lines","timingIndex","l","startStr","endStr","path","hash","match","a","b","installSpriteThumbnails"],"mappings":"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"}
|
|
@@ -37,7 +37,7 @@ class x {
|
|
|
37
37
|
for (let r = 0; r < t.buffered.length; r++)
|
|
38
38
|
t.buffered.start(r) <= t.currentTime + 0.5 && t.buffered.end(r) > t.currentTime && (u = t.buffered.end(r) - t.currentTime);
|
|
39
39
|
const f = [
|
|
40
|
-
[e.statsEngine, l.engine + (l.reason ? ` (${l.reason})` : "")],
|
|
40
|
+
[e.statsEngine, l.engine + (l.drm ? ` · ${l.drm}` : "") + (l.reason ? ` (${l.reason})` : "")],
|
|
41
41
|
[e.statsResolution, `${t.videoWidth}×${t.videoHeight} / ${Math.round(h.width * c)}×${Math.round(h.height * c)}`],
|
|
42
42
|
[e.statsQuality, i ? `${i.height}p · ${Math.round(i.bitrate / 1e3)} kbps${s.autoLevelEnabled ? " · auto" : ""}` : "—"],
|
|
43
43
|
[e.statsCodecs, i && [i.videoCodec, i.audioCodec].filter(Boolean).join(", ") || "—"],
|
|
@@ -67,4 +67,4 @@ export {
|
|
|
67
67
|
x as StatsPanel,
|
|
68
68
|
$ as installStats
|
|
69
69
|
};
|
|
70
|
-
//# sourceMappingURL=statsPanel-
|
|
70
|
+
//# sourceMappingURL=statsPanel-D0DtoFgS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statsPanel-D0DtoFgS.js","sources":["../../src/plugins/stats/StatsPanel.ts","../../src/plugins/stats/index.ts"],"sourcesContent":["import type { HopeLocaleStrings } from '../../i18n/types';\nimport type { PlaybackEngineInfo } from '../../hls/SourceManager';\n\n/** hls.js instance'ından okunan alanlar — tam tipi içe aktarmamak için. */\ninterface HlsStatsSource {\n currentLevel: number;\n autoLevelEnabled: boolean;\n levels: { height: number; width: number; bitrate: number; videoCodec?: string; audioCodec?: string; details?: { live: boolean } }[];\n bandwidthEstimate: number;\n latency: number;\n config: { maxBufferLength: number };\n}\n\nexport interface StatsPlayerContext {\n videoEl: HTMLVideoElement;\n containerEl: HTMLElement;\n i18n: HopeLocaleStrings;\n version: string;\n getEngine(): PlaybackEngineInfo;\n getHls(): HlsStatsSource | null;\n}\n\nconst REFRESH_MS = 500;\n\n/** Sağ tık menüsündeki \"İstatistikler\" — player üstünde canlı teknik bilgi paneli (YouTube'daki \"Stats for nerds\" gibi). */\nexport class StatsPanel {\n private readonly el: HTMLDivElement;\n private readonly titleEl: HTMLSpanElement;\n private readonly closeBtn: HTMLButtonElement;\n private readonly body: HTMLDListElement;\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(private readonly ctx: StatsPlayerContext) {\n this.el = document.createElement('div');\n this.el.className = 'hp-stats';\n this.el.setAttribute('part', 'stats-panel');\n this.el.setAttribute('role', 'dialog');\n\n const header = document.createElement('div');\n header.className = 'hp-stats-header';\n this.titleEl = document.createElement('span');\n this.closeBtn = document.createElement('button');\n this.closeBtn.type = 'button';\n this.closeBtn.className = 'hp-stats-close';\n this.closeBtn.innerHTML =\n '<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M6 6l12 12M18 6L6 18\"/></svg>';\n this.closeBtn.addEventListener('click', () => this.hide());\n header.append(this.titleEl, this.closeBtn);\n\n this.body = document.createElement('dl');\n this.body.className = 'hp-stats-body';\n this.el.append(header, this.body);\n // Panel tıklamaları videoyu oynat/duraklat yapmasın.\n this.el.addEventListener('pointerdown', (e) => e.stopPropagation());\n this.el.addEventListener('click', (e) => e.stopPropagation());\n this.refreshLabels();\n }\n\n get isVisible(): boolean {\n return this.el.isConnected;\n }\n\n show(): void {\n if (!this.isVisible) this.ctx.containerEl.appendChild(this.el);\n this.render();\n if (!this.timer) this.timer = setInterval(() => this.render(), REFRESH_MS);\n }\n\n hide(): void {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n this.el.remove();\n }\n\n toggle(force?: boolean): void {\n if (force ?? !this.isVisible) this.show();\n else this.hide();\n }\n\n refreshLabels(): void {\n this.titleEl.textContent = this.ctx.i18n.statsTitle;\n this.closeBtn.setAttribute('aria-label', this.ctx.i18n.statsClose);\n if (this.isVisible) this.render();\n }\n\n destroy(): void {\n this.hide();\n }\n\n private render(): void {\n const { videoEl: v, i18n: t } = this.ctx;\n const hls = this.ctx.getHls();\n const engine = this.ctx.getEngine();\n const level = hls && hls.currentLevel >= 0 ? hls.levels[hls.currentLevel] : undefined;\n const quality = v.getVideoPlaybackQuality?.();\n const rect = v.getBoundingClientRect();\n const dpr = window.devicePixelRatio || 1;\n\n let ahead = 0;\n for (let i = 0; i < v.buffered.length; i++) {\n if (v.buffered.start(i) <= v.currentTime + 0.5 && v.buffered.end(i) > v.currentTime) ahead = v.buffered.end(i) - v.currentTime;\n }\n\n const rows: [string, string][] = [\n [t.statsEngine, engine.engine + (engine.drm ? ` · ${engine.drm}` : '') + (engine.reason ? ` (${engine.reason})` : '')],\n [t.statsResolution, `${v.videoWidth}×${v.videoHeight} / ${Math.round(rect.width * dpr)}×${Math.round(rect.height * dpr)}`],\n [t.statsQuality, level ? `${level.height}p · ${Math.round(level.bitrate / 1000)} kbps${hls!.autoLevelEnabled ? ' · auto' : ''}` : '—'],\n [t.statsCodecs, level ? [level.videoCodec, level.audioCodec].filter(Boolean).join(', ') || '—' : '—'],\n [t.statsBandwidth, hls ? `${(hls.bandwidthEstimate / 1e6).toFixed(2)} Mbps` : '—'],\n [t.statsBuffer, `${ahead.toFixed(1)} s`],\n [t.statsDropped, quality ? `${quality.droppedVideoFrames} / ${quality.totalVideoFrames}` : '—'],\n // hls.js `latency`'yi VOD'da da hesaplıyor (süre - konum) — yalnızca canlı yayında anlamlı.\n [t.statsLatency, level?.details?.live && Number.isFinite(hls!.latency) ? `${hls!.latency.toFixed(1)} s` : '—'],\n [t.statsSpeedVolume, `${v.playbackRate}× · ${v.muted ? 0 : Math.round(v.volume * 100)}%`],\n [t.statsSource, v.currentSrc && !v.currentSrc.startsWith('blob:') ? v.currentSrc : v.currentSrc ? 'MediaSource (hls.js)' : '—'],\n [t.statsVersion, `HopeCorePlayer ${this.ctx.version}`],\n ];\n this.body.replaceChildren(\n ...rows.flatMap(([k, val]) => {\n const dt = document.createElement('dt');\n dt.textContent = k;\n const dd = document.createElement('dd');\n dd.textContent = val;\n dd.title = val;\n return [dt, dd];\n })\n );\n }\n}\n","import { StatsPanel, type StatsPlayerContext } from './StatsPanel';\n\nexport function installStats(ctx: StatsPlayerContext): StatsPanel {\n return new StatsPanel(ctx);\n}\n\nexport { StatsPanel };\nexport type { StatsPlayerContext };\n"],"names":["StatsPanel","ctx","__publicField","header","e","force","_a","_b","v","t","hls","engine","level","quality","rect","dpr","ahead","i","rows","k","val","dt","dd","installStats"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var A = Object.defineProperty;
|
|
2
2
|
var N = (h, t, e) => t in h ? A(h, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[t] = e;
|
|
3
3
|
var r = (h, t, e) => N(h, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
-
import { c as b } from "./player-
|
|
4
|
+
import { c as b } from "./player-DV4Hf5Cw.js";
|
|
5
5
|
const P = {
|
|
6
6
|
startIndex: 0,
|
|
7
7
|
loop: !0,
|
|
@@ -331,4 +331,4 @@ export {
|
|
|
331
331
|
L as HopeStory,
|
|
332
332
|
M as installStory
|
|
333
333
|
};
|
|
334
|
-
//# sourceMappingURL=story-
|
|
334
|
+
//# sourceMappingURL=story-BRkhSDhR.js.map
|