@hopeplayer/core 1.0.15 → 1.0.17
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 +24 -14
- package/dist/HopePlayerElement.d.ts +37 -0
- package/dist/HopePlayerElement.d.ts.map +1 -1
- package/dist/chunks/adTriggers-4SueRFgK.js +415 -0
- package/dist/chunks/adTriggers-4SueRFgK.js.map +1 -0
- package/dist/chunks/{index-BCMVXNL0.js → ads-DPL7m9PV.js} +135 -158
- package/dist/chunks/ads-DPL7m9PV.js.map +1 -0
- package/dist/chunks/{index-BeJNpAyx.js → audio-LkYgd5Wq.js} +7 -7
- package/dist/chunks/audio-LkYgd5Wq.js.map +1 -0
- package/dist/chunks/{ScratchSound-0XKHUcJK.js → audioScratchSound-7XkwCCDm.js} +1 -1
- package/dist/chunks/audioScratchSound-7XkwCCDm.js.map +1 -0
- package/dist/chunks/cast-DCAT2agI.js +387 -0
- package/dist/chunks/cast-DCAT2agI.js.map +1 -0
- package/dist/chunks/{index-rENB3n9O.js → countdownScreen-CI-u6jjA.js} +1 -1
- package/dist/chunks/countdownScreen-CI-u6jjA.js.map +1 -0
- package/dist/chunks/{index-Q8FMOHj0.js → dai-B9Tth1Iv.js} +1 -1
- package/dist/chunks/dai-B9Tth1Iv.js.map +1 -0
- package/dist/chunks/{index-DCXX1ZJG.js → debugPanel-Bnc_7GOn.js} +1 -1
- package/dist/chunks/debugPanel-Bnc_7GOn.js.map +1 -0
- package/dist/chunks/{index-DXWK4EFa.js → dubbing-kNMPpyHl.js} +1 -1
- package/dist/chunks/dubbing-kNMPpyHl.js.map +1 -0
- package/dist/chunks/{index-BBmuCtKu.js → geoChecker-BRtvHwI-.js} +1 -1
- package/dist/chunks/geoChecker-BRtvHwI-.js.map +1 -0
- package/dist/chunks/{index-Ca8hocby.js → gesture-BzPCgi87.js} +1 -1
- package/dist/chunks/gesture-BzPCgi87.js.map +1 -0
- package/dist/chunks/gpt-CGXHTG_H.js +18 -0
- package/dist/chunks/gpt-CGXHTG_H.js.map +1 -0
- package/dist/chunks/{index-3QALpwsf.js → inViewAutoplay-CRJe7GA4.js} +1 -1
- package/dist/chunks/inViewAutoplay-CRJe7GA4.js.map +1 -0
- package/dist/chunks/{index-7IBf8Y-R.js → liveWallClock-ChUTtzLD.js} +1 -1
- package/dist/chunks/liveWallClock-ChUTtzLD.js.map +1 -0
- package/dist/chunks/{index-f0vSgRIK.js → loopSection-CvF4l5uf.js} +1 -1
- package/dist/chunks/loopSection-CvF4l5uf.js.map +1 -0
- package/dist/chunks/{index-DRlQC-ev.js → markers-DE4O8xbw.js} +2 -2
- package/dist/chunks/markers-DE4O8xbw.js.map +1 -0
- package/dist/chunks/{index-CaMVTgh0.js → pauseAd-BQQe21X4.js} +55 -68
- package/dist/chunks/pauseAd-BQQe21X4.js.map +1 -0
- package/dist/chunks/{index-w7pACyTw.js → player-C886oKP-.js} +726 -391
- package/dist/chunks/player-C886oKP-.js.map +1 -0
- package/dist/chunks/{index-DpUZXNJS.js → playlist-CI3mRZjo.js} +2 -2
- package/dist/chunks/playlist-CI3mRZjo.js.map +1 -0
- package/dist/chunks/{VideoPrebid-CpckFzSq.js → prebid-CRY3i2OT.js} +1 -1
- package/dist/chunks/prebid-CRY3i2OT.js.map +1 -0
- package/dist/chunks/{index-DT8-oMPm.js → qrResume-BNy8XCp_.js} +1 -1
- package/dist/chunks/qrResume-BNy8XCp_.js.map +1 -0
- package/dist/chunks/redirectScreen-CJ3q9OX4.js +208 -0
- package/dist/chunks/redirectScreen-CJ3q9OX4.js.map +1 -0
- package/dist/chunks/rewardedUnlock-EyGMB9PK.js +264 -0
- package/dist/chunks/rewardedUnlock-EyGMB9PK.js.map +1 -0
- package/dist/chunks/{index-BOoNcKeR.js → segments-C2HKU6XK.js} +2 -2
- package/dist/chunks/segments-C2HKU6XK.js.map +1 -0
- package/dist/chunks/{index-D5P-LWbg.js → sponsorship-DyFwGmEb.js} +20 -20
- package/dist/chunks/sponsorship-DyFwGmEb.js.map +1 -0
- package/dist/chunks/{index-BvoB2O1p.js → spriteThumbnails-D0NQ5CCp.js} +2 -2
- package/dist/chunks/spriteThumbnails-D0NQ5CCp.js.map +1 -0
- package/dist/chunks/{index-DGtpFgHV.js → statsPanel-DSClIwA3.js} +1 -1
- package/dist/chunks/statsPanel-DSClIwA3.js.map +1 -0
- package/dist/chunks/{index-CDDke5rz.js → sticky-D_eLCNFk.js} +1 -1
- package/dist/chunks/sticky-D_eLCNFk.js.map +1 -0
- package/dist/chunks/{index-ClQg_X1N.js → story-D5Got6-6.js} +2 -2
- package/dist/chunks/{index-ClQg_X1N.js.map → story-D5Got6-6.js.map} +1 -1
- package/dist/chunks/{index-C5oGMHF_.js → tapGestures-DrC42DiI.js} +1 -1
- package/dist/chunks/tapGestures-DrC42DiI.js.map +1 -0
- package/dist/hls/SourceManager.d.ts +8 -0
- package/dist/hls/SourceManager.d.ts.map +1 -1
- package/dist/hls/sourceGroups.d.ts +19 -0
- package/dist/hls/sourceGroups.d.ts.map +1 -0
- 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 +12 -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/ad-triggers/AdTriggers.d.ts +99 -0
- package/dist/plugins/ad-triggers/AdTriggers.d.ts.map +1 -0
- package/dist/plugins/ad-triggers/index.d.ts +7 -0
- package/dist/plugins/ad-triggers/index.d.ts.map +1 -0
- package/dist/plugins/ads/AdsController.d.ts +8 -0
- package/dist/plugins/ads/AdsController.d.ts.map +1 -1
- package/dist/plugins/ads/generateVastUrl.d.ts +10 -0
- package/dist/plugins/ads/generateVastUrl.d.ts.map +1 -1
- package/dist/plugins/cast/CastController.d.ts +107 -0
- package/dist/plugins/cast/CastController.d.ts.map +1 -0
- package/dist/plugins/cast/RemoteMediaProxy.d.ts +41 -0
- package/dist/plugins/cast/RemoteMediaProxy.d.ts.map +1 -0
- package/dist/plugins/cast/castSdk.d.ts +160 -0
- package/dist/plugins/cast/castSdk.d.ts.map +1 -0
- package/dist/plugins/cast/index.d.ts +7 -0
- package/dist/plugins/cast/index.d.ts.map +1 -0
- package/dist/plugins/pause-ad/loadGpt.d.ts +2 -0
- package/dist/plugins/pause-ad/loadGpt.d.ts.map +1 -1
- package/dist/plugins/redirect-screen/RedirectScreen.d.ts +26 -3
- package/dist/plugins/redirect-screen/RedirectScreen.d.ts.map +1 -1
- package/dist/plugins/rewarded/RewardedUnlock.d.ts +2 -5
- package/dist/plugins/rewarded/RewardedUnlock.d.ts.map +1 -1
- package/dist/plugins/rewarded/gpt.d.ts +6 -2
- package/dist/plugins/rewarded/gpt.d.ts.map +1 -1
- package/dist/plugins/sponsorship/SponsorshipLayer.d.ts.map +1 -1
- package/dist/types/index.d.ts +308 -3
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -1
- package/dist/chunks/ScratchSound-0XKHUcJK.js.map +0 -1
- package/dist/chunks/VideoPrebid-CpckFzSq.js.map +0 -1
- package/dist/chunks/index-3QALpwsf.js.map +0 -1
- package/dist/chunks/index-7IBf8Y-R.js.map +0 -1
- package/dist/chunks/index-BBmuCtKu.js.map +0 -1
- package/dist/chunks/index-BCMVXNL0.js.map +0 -1
- package/dist/chunks/index-BOoNcKeR.js.map +0 -1
- package/dist/chunks/index-BeJNpAyx.js.map +0 -1
- package/dist/chunks/index-BvoB2O1p.js.map +0 -1
- package/dist/chunks/index-C5oGMHF_.js.map +0 -1
- package/dist/chunks/index-CDDke5rz.js.map +0 -1
- package/dist/chunks/index-Ca8hocby.js.map +0 -1
- package/dist/chunks/index-CaMVTgh0.js.map +0 -1
- package/dist/chunks/index-D5P-LWbg.js.map +0 -1
- package/dist/chunks/index-D6r-BGAV.js +0 -77
- package/dist/chunks/index-D6r-BGAV.js.map +0 -1
- package/dist/chunks/index-DCXX1ZJG.js.map +0 -1
- package/dist/chunks/index-DGtpFgHV.js.map +0 -1
- package/dist/chunks/index-DRlQC-ev.js.map +0 -1
- package/dist/chunks/index-DT8-oMPm.js.map +0 -1
- package/dist/chunks/index-DXWK4EFa.js.map +0 -1
- package/dist/chunks/index-DpUZXNJS.js.map +0 -1
- package/dist/chunks/index-Q8FMOHj0.js.map +0 -1
- package/dist/chunks/index-TkG8IO6q.js +0 -239
- package/dist/chunks/index-TkG8IO6q.js.map +0 -1
- package/dist/chunks/index-f0vSgRIK.js.map +0 -1
- package/dist/chunks/index-rENB3n9O.js.map +0 -1
- package/dist/chunks/index-w7pACyTw.js.map +0 -1
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
var k = Object.defineProperty;
|
|
2
|
+
var x = (l, t, e) => t in l ? k(l, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[t] = e;
|
|
3
|
+
var r = (l, t, e) => x(l, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { s as E } from "./player-C886oKP-.js";
|
|
5
|
+
const T = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1", C = 1e4;
|
|
6
|
+
let g = null;
|
|
7
|
+
function b() {
|
|
8
|
+
var t, e;
|
|
9
|
+
const l = window;
|
|
10
|
+
return (t = l.cast) != null && t.framework && ((e = l.chrome) != null && e.cast) ? { framework: l.cast.framework, chrome: l.chrome.cast } : null;
|
|
11
|
+
}
|
|
12
|
+
function w() {
|
|
13
|
+
if (g) return g;
|
|
14
|
+
const l = window;
|
|
15
|
+
return b() ? g = Promise.resolve(b()) : !l.chrome || !window.isSecureContext ? g = Promise.resolve(null) : (g = new Promise((t) => {
|
|
16
|
+
const e = l.__onGCastApiAvailable, s = setTimeout(() => t(null), C);
|
|
17
|
+
if (l.__onGCastApiAvailable = (i, a) => {
|
|
18
|
+
e == null || e(i, a), clearTimeout(s), t(i ? b() : null);
|
|
19
|
+
}, !document.querySelector('script[src*="cast_sender.js"]')) {
|
|
20
|
+
const i = document.createElement("script");
|
|
21
|
+
i.async = !0, i.src = T, i.onerror = () => {
|
|
22
|
+
clearTimeout(s), g = null, t(null);
|
|
23
|
+
}, document.head.appendChild(i);
|
|
24
|
+
}
|
|
25
|
+
}), g);
|
|
26
|
+
}
|
|
27
|
+
const I = ["paused", "currentTime", "duration", "ended", "volume", "muted", "readyState", "seeking", "buffered", "play", "pause"], M = {
|
|
28
|
+
length: 0,
|
|
29
|
+
start: () => {
|
|
30
|
+
throw new DOMException("Index out of range", "IndexSizeError");
|
|
31
|
+
},
|
|
32
|
+
end: () => {
|
|
33
|
+
throw new DOMException("Index out of range", "IndexSizeError");
|
|
34
|
+
}
|
|
35
|
+
}, P = 150;
|
|
36
|
+
function A(l, t) {
|
|
37
|
+
return Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, t).get.call(l);
|
|
38
|
+
}
|
|
39
|
+
class N {
|
|
40
|
+
constructor(t, e, s) {
|
|
41
|
+
r(this, "state");
|
|
42
|
+
r(this, "pendingSeek", null);
|
|
43
|
+
r(this, "seekTimer", null);
|
|
44
|
+
r(this, "installed", !1);
|
|
45
|
+
this.video = t, this.commands = e, this.state = { ...s };
|
|
46
|
+
}
|
|
47
|
+
get current() {
|
|
48
|
+
return this.state;
|
|
49
|
+
}
|
|
50
|
+
install() {
|
|
51
|
+
if (this.installed) return;
|
|
52
|
+
this.installed = !0;
|
|
53
|
+
const t = this.video, e = () => this.state, s = (i, a) => {
|
|
54
|
+
Object.defineProperty(t, i, { configurable: !0, enumerable: !1, ...a });
|
|
55
|
+
};
|
|
56
|
+
s("paused", { get: () => e().paused }), s("ended", { get: () => e().ended }), s("duration", { get: () => e().duration }), s("readyState", { get: () => 4 }), s("seeking", { get: () => this.pendingSeek !== null }), s("buffered", { get: () => M }), s("currentTime", {
|
|
57
|
+
get: () => this.pendingSeek ?? e().currentTime,
|
|
58
|
+
set: (i) => this.seek(i)
|
|
59
|
+
}), s("volume", {
|
|
60
|
+
get: () => e().volume,
|
|
61
|
+
set: (i) => {
|
|
62
|
+
const a = Math.min(1, Math.max(0, Number(i) || 0));
|
|
63
|
+
this.state.volume = a, this.commands.setVolume(a), this.fire("volumechange");
|
|
64
|
+
}
|
|
65
|
+
}), s("muted", {
|
|
66
|
+
get: () => e().muted,
|
|
67
|
+
set: (i) => {
|
|
68
|
+
this.state.muted = !!i, this.commands.setMuted(!!i), this.fire("volumechange");
|
|
69
|
+
}
|
|
70
|
+
}), s("play", {
|
|
71
|
+
value: () => (this.state.ended && this.seek(0), this.commands.play(), Promise.resolve())
|
|
72
|
+
}), s("pause", { value: () => this.commands.pause() });
|
|
73
|
+
}
|
|
74
|
+
uninstall() {
|
|
75
|
+
if (this.installed) {
|
|
76
|
+
this.installed = !1, this.seekTimer && clearTimeout(this.seekTimer), this.seekTimer = null, this.pendingSeek = null;
|
|
77
|
+
for (const t of I) delete this.video[t];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** TV'den gelen durum — değişen alanlar için olay yayar. */
|
|
81
|
+
update(t) {
|
|
82
|
+
const e = this.state;
|
|
83
|
+
this.state = { ...e, ...t };
|
|
84
|
+
const s = this.state;
|
|
85
|
+
t.duration !== void 0 && t.duration !== e.duration && this.fire("durationchange"), t.currentTime !== void 0 && t.currentTime !== e.currentTime && this.pendingSeek === null && this.fire("timeupdate"), (t.volume !== void 0 || t.muted !== void 0) && (s.volume !== e.volume || s.muted !== e.muted) && this.fire("volumechange"), t.paused !== void 0 && t.paused !== e.paused && (s.paused ? this.fire("pause") : (this.fire("play"), this.fire("playing"))), t.ended && !e.ended && this.fire("ended");
|
|
86
|
+
}
|
|
87
|
+
seek(t) {
|
|
88
|
+
const e = Math.max(0, Number(t) || 0), s = this.pendingSeek === null;
|
|
89
|
+
this.pendingSeek = e, s && this.fire("seeking"), this.fire("timeupdate"), this.seekTimer && clearTimeout(this.seekTimer), this.seekTimer = setTimeout(() => {
|
|
90
|
+
this.seekTimer = null;
|
|
91
|
+
const i = this.pendingSeek ?? e;
|
|
92
|
+
this.commands.seek(i), this.state = { ...this.state, currentTime: i, ended: !1 }, this.pendingSeek = null, this.fire("seeked"), this.fire("timeupdate");
|
|
93
|
+
}, P);
|
|
94
|
+
}
|
|
95
|
+
fire(t) {
|
|
96
|
+
this.video.dispatchEvent(new Event(t));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
let y = null, m = null;
|
|
100
|
+
const B = 20, _ = 5;
|
|
101
|
+
class L {
|
|
102
|
+
constructor(t, e) {
|
|
103
|
+
r(this, "options");
|
|
104
|
+
r(this, "api", null);
|
|
105
|
+
r(this, "context", null);
|
|
106
|
+
r(this, "session", null);
|
|
107
|
+
r(this, "player", null);
|
|
108
|
+
r(this, "controller", null);
|
|
109
|
+
r(this, "proxy", null);
|
|
110
|
+
r(this, "castBtn", null);
|
|
111
|
+
r(this, "castIcon", null);
|
|
112
|
+
r(this, "airplayBtn", null);
|
|
113
|
+
r(this, "remoteBtn", null);
|
|
114
|
+
r(this, "overlay", null);
|
|
115
|
+
r(this, "loadedSrc", "");
|
|
116
|
+
r(this, "loadedContent", "");
|
|
117
|
+
r(this, "savedAutoplay", !1);
|
|
118
|
+
r(this, "airplayActive", !1);
|
|
119
|
+
r(this, "destroyed", !1);
|
|
120
|
+
r(this, "remoteWatchId", null);
|
|
121
|
+
r(this, "onCastState", (t) => {
|
|
122
|
+
var s;
|
|
123
|
+
const e = t.castState ?? "NO_DEVICES_AVAILABLE";
|
|
124
|
+
this.castBtn && (this.castBtn.hidden = e === "NO_DEVICES_AVAILABLE"), (s = this.castBtn) == null || s.toggleAttribute("data-connecting", e === "CONNECTING"), this.proxy || this.emit(e === "NO_DEVICES_AVAILABLE" ? "unavailable" : e === "CONNECTING" ? "connecting" : "available", "chromecast");
|
|
125
|
+
});
|
|
126
|
+
r(this, "onSessionState", (t) => {
|
|
127
|
+
const e = t.sessionState;
|
|
128
|
+
(e === "SESSION_STARTED" || e === "SESSION_RESUMED") && t.session ? y === this ? (y = null, this.attach(t.session, !0)) : e === "SESSION_RESUMED" && !m && this.tryResume(t.session) : (e === "SESSION_ENDED" || e === "SESSION_START_FAILED") && (y === this && (y = null), m === this && this.detach());
|
|
129
|
+
});
|
|
130
|
+
r(this, "onRemoteChange", (t) => {
|
|
131
|
+
var i;
|
|
132
|
+
const e = this.player, s = this.proxy;
|
|
133
|
+
if (!(!e || !s))
|
|
134
|
+
switch (t.field) {
|
|
135
|
+
case "isPaused":
|
|
136
|
+
s.update({ paused: !!t.value });
|
|
137
|
+
break;
|
|
138
|
+
case "currentTime":
|
|
139
|
+
s.update({ currentTime: Number(t.value) || 0 });
|
|
140
|
+
break;
|
|
141
|
+
case "duration":
|
|
142
|
+
s.update({ duration: Number(t.value) > 0 ? Number(t.value) : s.current.duration });
|
|
143
|
+
break;
|
|
144
|
+
case "volumeLevel":
|
|
145
|
+
s.update({ volume: Number(t.value) });
|
|
146
|
+
break;
|
|
147
|
+
case "isMuted":
|
|
148
|
+
s.update({ muted: !!t.value });
|
|
149
|
+
break;
|
|
150
|
+
case "playerState":
|
|
151
|
+
t.value === "IDLE" && e.isMediaLoaded === !1 && s.current.currentTime > 0 ? s.update({ ended: !0, paused: !0 }) : t.value === "PLAYING" && s.update({ ended: !1, paused: !1 });
|
|
152
|
+
break;
|
|
153
|
+
case "isPlayingBreak":
|
|
154
|
+
(i = this.overlay) == null || i.toggleAttribute("data-break", !!t.value);
|
|
155
|
+
break;
|
|
156
|
+
case "isConnected":
|
|
157
|
+
!t.value && m === this && this.detach();
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
/** Cast sırasında player başka bir kaynağa geçti (playlist sonraki öğe, kalite, yedek kaynak) → TV'ye de gönder. */
|
|
162
|
+
r(this, "onLocalSourceChange", () => {
|
|
163
|
+
if (!this.proxy) return;
|
|
164
|
+
HTMLMediaElement.prototype.pause.call(this.ctx.videoEl);
|
|
165
|
+
const t = this.ctx.getMedia();
|
|
166
|
+
if (!t || t.src === this.loadedSrc) return;
|
|
167
|
+
const e = this.ctx.contentKey() === this.loadedContent;
|
|
168
|
+
this.loadMedia(e ? this.proxy.current.currentTime : 0, !0);
|
|
169
|
+
});
|
|
170
|
+
this.ctx = t, this.options = e, e.chromecast && this.initChromecast(), e.airplay && this.initAirPlay(), e.remotePlayback && this.initRemotePlayback();
|
|
171
|
+
}
|
|
172
|
+
update(t) {
|
|
173
|
+
const e = this.options;
|
|
174
|
+
this.options = t, t.chromecast && !e.chromecast && this.initChromecast(), t.airplay && !e.airplay && this.initAirPlay(), t.remotePlayback && !e.remotePlayback && this.initRemotePlayback(), this.castBtn && (this.castBtn.hidden = !t.chromecast || this.castBtn.hidden), this.airplayBtn && !t.airplay && (this.airplayBtn.hidden = !0), this.remoteBtn && !t.remotePlayback && (this.remoteBtn.hidden = !0);
|
|
175
|
+
}
|
|
176
|
+
/** İçerik şu an TV'de mi (herhangi bir yoldan). */
|
|
177
|
+
get casting() {
|
|
178
|
+
var t;
|
|
179
|
+
return !!this.proxy || this.airplayActive || ((t = this.ctx.videoEl.remote) == null ? void 0 : t.state) === "connected";
|
|
180
|
+
}
|
|
181
|
+
emit(t, e, s) {
|
|
182
|
+
this.ctx.hostEl.dispatchEvent(new CustomEvent("hp:cast", { detail: { state: t, via: e, device: s } }));
|
|
183
|
+
}
|
|
184
|
+
button(t, e, s) {
|
|
185
|
+
const i = this.ctx.addButton(t, e, s);
|
|
186
|
+
return i.btn.hidden = !0, i;
|
|
187
|
+
}
|
|
188
|
+
// ── Google Cast ─────────────────────────────────────────────────────────
|
|
189
|
+
async initChromecast() {
|
|
190
|
+
if (this.castBtn) return;
|
|
191
|
+
const { btn: t, icon: e } = this.button(this.ctx.i18n.castButton, "cast", () => this.requestCast());
|
|
192
|
+
t.setAttribute("part", "cast-button"), this.castBtn = t, this.castIcon = e;
|
|
193
|
+
const s = await w();
|
|
194
|
+
if (!s || this.destroyed) {
|
|
195
|
+
s || this.ctx.log({ message: "Google Cast is not available in this browser (Chrome / Edge over HTTPS needed)" });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
this.api = s;
|
|
199
|
+
const i = s.framework.CastContext.getInstance();
|
|
200
|
+
this.context = i, i.setOptions({
|
|
201
|
+
receiverApplicationId: this.options.receiverAppId || s.chrome.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
|
|
202
|
+
autoJoinPolicy: s.chrome.AutoJoinPolicy.ORIGIN_SCOPED
|
|
203
|
+
});
|
|
204
|
+
const a = s.framework.CastContextEventType;
|
|
205
|
+
i.addEventListener(a.CAST_STATE_CHANGED, this.onCastState), i.addEventListener(a.SESSION_STATE_CHANGED, this.onSessionState), this.onCastState({ castState: i.getCastState() });
|
|
206
|
+
const n = i.getCurrentSession();
|
|
207
|
+
n && !m && this.tryResume(n);
|
|
208
|
+
}
|
|
209
|
+
requestCast() {
|
|
210
|
+
if (this.context) {
|
|
211
|
+
if (this.ctx.isAdPlaying()) {
|
|
212
|
+
this.ctx.log({ message: "Cast: wait for the ad to finish" });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
y = this, this.context.requestSession().catch((t) => {
|
|
216
|
+
y === this && (y = null), String(t) !== "cancel" && this.ctx.log({ message: `Cast session failed: ${String(t)}` });
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
tryResume(t) {
|
|
221
|
+
var i, a;
|
|
222
|
+
const e = this.ctx.getMedia(), s = (a = (i = t.getMediaSession()) == null ? void 0 : i.media) == null ? void 0 : a.contentId;
|
|
223
|
+
e && s && s === e.src && this.attach(t, !1);
|
|
224
|
+
}
|
|
225
|
+
async attach(t, e) {
|
|
226
|
+
var p, c, h, u;
|
|
227
|
+
const s = this.api;
|
|
228
|
+
if (!s || this.destroyed) return;
|
|
229
|
+
m && m !== this && m.detach(), m = this, this.session = t;
|
|
230
|
+
const i = this.ctx.videoEl, a = A(i, "currentTime"), n = A(i, "duration");
|
|
231
|
+
HTMLMediaElement.prototype.pause.call(i), this.savedAutoplay = i.autoplay, i.autoplay = !1;
|
|
232
|
+
const o = new s.framework.RemotePlayer(), d = new s.framework.RemotePlayerController(o);
|
|
233
|
+
this.player = o, this.controller = d, this.proxy = new N(
|
|
234
|
+
i,
|
|
235
|
+
{
|
|
236
|
+
play: () => o.isPaused && d.playOrPause(),
|
|
237
|
+
pause: () => !o.isPaused && d.playOrPause(),
|
|
238
|
+
seek: (f) => {
|
|
239
|
+
o.currentTime = f, d.seek();
|
|
240
|
+
},
|
|
241
|
+
setVolume: (f) => {
|
|
242
|
+
o.volumeLevel = f, d.setVolumeLevel();
|
|
243
|
+
},
|
|
244
|
+
setMuted: (f) => o.isMuted !== f && d.muteOrUnmute()
|
|
245
|
+
},
|
|
246
|
+
{ paused: !1, currentTime: a, duration: n, volume: i.volume, muted: i.muted, ended: !1 }
|
|
247
|
+
), this.proxy.install(), d.addEventListener(s.framework.RemotePlayerEventType.ANY_CHANGE, this.onRemoteChange), i.addEventListener("loadstart", this.onLocalSourceChange), this.ctx.onRemoteChange(!0);
|
|
248
|
+
const v = ((p = t.getCastDevice()) == null ? void 0 : p.friendlyName) || this.ctx.i18n.castDeviceFallback;
|
|
249
|
+
this.showOverlay(this.ctx.i18n.castPlayingOn.replace("{device}", v)), (c = this.castBtn) == null || c.setAttribute("aria-pressed", "true"), this.castIcon && E(this.castIcon, "cast-connected"), this.emit("connected", "chromecast", v), e ? await this.loadMedia(a, !0) : (this.loadedSrc = ((u = (h = t.getMediaSession()) == null ? void 0 : h.media) == null ? void 0 : u.contentId) ?? "", this.loadedContent = this.ctx.contentKey());
|
|
250
|
+
}
|
|
251
|
+
/** O an çalan içeriği TV'ye yükler (reklam araları ve altyazılarla). */
|
|
252
|
+
async loadMedia(t, e) {
|
|
253
|
+
const s = this.api, i = this.session, a = this.ctx.getMedia();
|
|
254
|
+
if (!s || !i || !a) {
|
|
255
|
+
this.ctx.log({ message: "Cast: nothing to send (no playable source)" });
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const n = s.chrome.media, o = new n.MediaInfo(a.src, a.contentType);
|
|
259
|
+
o.streamType = a.live ? n.StreamType.LIVE : n.StreamType.BUFFERED;
|
|
260
|
+
const d = a.music ? new n.MusicTrackMediaMetadata() : new n.GenericMediaMetadata();
|
|
261
|
+
d.title = a.title, a.music ? d.artist = a.subtitle : d.subtitle = a.subtitle, a.image && (d.images = [new s.chrome.Image(a.image)]), o.metadata = d, /mpegurl/i.test(a.contentType) && this.options.hlsSegmentFormat === "fmp4" && (n.HlsSegmentFormat && (o.hlsSegmentFormat = n.HlsSegmentFormat.FMP4), n.HlsVideoSegmentFormat && (o.hlsVideoSegmentFormat = n.HlsVideoSegmentFormat.FMP4));
|
|
262
|
+
const v = [];
|
|
263
|
+
o.tracks = a.subtitles.map((c, h) => {
|
|
264
|
+
const u = new n.Track(h + 1, n.TrackType.TEXT);
|
|
265
|
+
return u.trackContentId = c.src, u.trackContentType = "text/vtt", u.subtype = n.TextTrackType.SUBTITLES, u.name = c.label, u.language = c.lang, c.default && v.push(h + 1), u;
|
|
266
|
+
}), this.applyAds(o, a);
|
|
267
|
+
const p = new n.LoadRequest(o);
|
|
268
|
+
p.currentTime = a.live ? void 0 : t, p.autoplay = e, v.length && (p.activeTrackIds = v), this.loadedSrc = a.src, this.loadedContent = this.ctx.contentKey();
|
|
269
|
+
try {
|
|
270
|
+
await i.loadMedia(p), this.ctx.log({ message: "Cast: media loaded on the TV", details: { src: a.src, ads: a.ads ? a.ads.vmap ? "vmap" : "vast" : "none" } });
|
|
271
|
+
} catch (c) {
|
|
272
|
+
this.ctx.log({ message: `Cast: the TV could not load the media: ${String(c)}`, fatal: !0, details: { src: a.src } });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Reklamlar TV'de: VMAP verilmişse receiver tüm araları kendisi planlar (vmapAdsRequest); yoksa VAST tag'leri
|
|
277
|
+
* ara olarak eklenir — preroll (0), aralıklı midroll'lar, postroll (-1). Reklamları receiver oynatır ve sayar.
|
|
278
|
+
*/
|
|
279
|
+
applyAds(t, e) {
|
|
280
|
+
var p;
|
|
281
|
+
const s = e.ads, i = this.api.chrome.media;
|
|
282
|
+
if (!s) return;
|
|
283
|
+
if (s.vmap) {
|
|
284
|
+
const c = new i.VastAdsRequest();
|
|
285
|
+
c.adTagUrl = s.vmap, t.vmapAdsRequest = c;
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const a = [], n = [], o = (c, h, u) => {
|
|
289
|
+
const f = new i.BreakClip(`clip-${c}`), S = new i.VastAdsRequest();
|
|
290
|
+
S.adTagUrl = h, f.vastAdsRequest = S, a.push(f), n.push(new i.Break(`break-${c}`, [`clip-${c}`], u));
|
|
291
|
+
};
|
|
292
|
+
s.preroll && o("pre", s.preroll, 0);
|
|
293
|
+
const d = s.midrollIntervalSeconds ?? 0, v = ((p = this.proxy) == null ? void 0 : p.current.duration) ?? NaN;
|
|
294
|
+
if (s.midroll && d > 0 && !e.live && Number.isFinite(v))
|
|
295
|
+
for (let c = d, h = 1; c < v - _ && h <= B; c += d, h++) o(`mid-${h}`, s.midroll, c);
|
|
296
|
+
s.postroll && !e.live && o("post", s.postroll, -1), a.length && (t.breakClips = a, t.breaks = n);
|
|
297
|
+
}
|
|
298
|
+
detach() {
|
|
299
|
+
var n, o;
|
|
300
|
+
const t = this.proxy;
|
|
301
|
+
if (!t) return;
|
|
302
|
+
m === this && (m = null);
|
|
303
|
+
const { currentTime: e, paused: s, ended: i } = t.current, a = this.ctx.videoEl;
|
|
304
|
+
(n = this.controller) == null || n.removeEventListener(this.api.framework.RemotePlayerEventType.ANY_CHANGE, this.onRemoteChange), a.removeEventListener("loadstart", this.onLocalSourceChange), t.uninstall(), this.proxy = null, this.player = null, this.controller = null, this.session = null, this.loadedSrc = "", a.autoplay = this.savedAutoplay, this.ctx.onRemoteChange(!1), this.hideOverlay(), (o = this.castBtn) == null || o.setAttribute("aria-pressed", "false"), this.castIcon && E(this.castIcon, "cast"), Number.isFinite(e) && e > 0 && !i && (a.currentTime = e), !s && !i && a.play().catch(() => {
|
|
305
|
+
}), this.emit("disconnected", "chromecast");
|
|
306
|
+
}
|
|
307
|
+
// ── AirPlay (Safari) ────────────────────────────────────────────────────
|
|
308
|
+
initAirPlay() {
|
|
309
|
+
if (this.airplayBtn || !("WebKitPlaybackTargetAvailabilityEvent" in window)) return;
|
|
310
|
+
const t = this.ctx.videoEl;
|
|
311
|
+
t.setAttribute("x-webkit-airplay", "allow");
|
|
312
|
+
const { btn: e } = this.button(this.ctx.i18n.airplayButton, "airplay", () => {
|
|
313
|
+
var s;
|
|
314
|
+
if (this.ctx.isMse()) {
|
|
315
|
+
this.ctx.log({ message: 'AirPlay: this source plays through hls.js (MSE) — use hls.engine: "auto" / "native" on Safari for AirPlay' });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
(s = t.webkitShowPlaybackTargetPicker) == null || s.call(t);
|
|
319
|
+
});
|
|
320
|
+
e.setAttribute("part", "airplay-button"), this.airplayBtn = e, t.addEventListener("webkitplaybacktargetavailabilitychanged", ((s) => {
|
|
321
|
+
const i = s.availability === "available";
|
|
322
|
+
e.hidden = !i || !this.options.airplay, this.airplayActive || this.emit(i ? "available" : "unavailable", "airplay");
|
|
323
|
+
})), t.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", () => {
|
|
324
|
+
const s = !!t.webkitCurrentPlaybackTargetIsWireless;
|
|
325
|
+
s !== this.airplayActive && (this.airplayActive = s, e.setAttribute("aria-pressed", String(s)), s ? this.showOverlay(this.ctx.i18n.airplayPlaying) : this.hideOverlay(), this.emit(s ? "connected" : "disconnected", "airplay"));
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
// ── Remote Playback API ─────────────────────────────────────────────────
|
|
329
|
+
initRemotePlayback() {
|
|
330
|
+
const t = this.ctx.videoEl, e = t.remote;
|
|
331
|
+
if (this.remoteBtn || !e) return;
|
|
332
|
+
t.disableRemotePlayback = !1;
|
|
333
|
+
const { btn: s } = this.button(this.ctx.i18n.castButton, "cast", () => {
|
|
334
|
+
if (this.ctx.isMse()) {
|
|
335
|
+
this.ctx.log({ message: "Remote playback: hls.js (MSE) sources cannot be sent to the device" });
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
e.prompt().catch((i) => this.ctx.log({ message: `Remote playback: ${String(i)}` }));
|
|
339
|
+
});
|
|
340
|
+
s.setAttribute("part", "remote-playback-button"), this.remoteBtn = s, e.watchAvailability((i) => {
|
|
341
|
+
s.hidden = !i || this.ctx.isMse() || !!(this.castBtn && !this.castBtn.hidden), e.state === "disconnected" && this.emit(i ? "available" : "unavailable", "remote");
|
|
342
|
+
}).then((i) => this.remoteWatchId = i).catch(() => s.hidden = !0), e.addEventListener("connecting", () => this.emit("connecting", "remote")), e.addEventListener("connect", () => {
|
|
343
|
+
s.setAttribute("aria-pressed", "true"), this.showOverlay(this.ctx.i18n.castPlayingOn.replace("{device}", this.ctx.i18n.castDeviceFallback)), this.emit("connected", "remote");
|
|
344
|
+
}), e.addEventListener("disconnect", () => {
|
|
345
|
+
s.setAttribute("aria-pressed", "false"), this.hideOverlay(), this.emit("disconnected", "remote");
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
// ── "TV'de oynatılıyor" katmanı ─────────────────────────────────────────
|
|
349
|
+
showOverlay(t) {
|
|
350
|
+
if (!this.overlay) {
|
|
351
|
+
const e = document.createElement("div");
|
|
352
|
+
e.className = "hp-cast-overlay", e.setAttribute("part", "cast-overlay"), e.setAttribute("role", "status");
|
|
353
|
+
const s = document.createElement("i");
|
|
354
|
+
s.className = "hp-icon hp-icon-cast-connected", s.setAttribute("aria-hidden", "true");
|
|
355
|
+
const i = document.createElement("span");
|
|
356
|
+
i.className = "hp-cast-overlay-text";
|
|
357
|
+
const a = document.createElement("span");
|
|
358
|
+
a.className = "hp-cast-overlay-ad", e.append(s, i, a), this.ctx.overlayEl.appendChild(e), this.overlay = e;
|
|
359
|
+
}
|
|
360
|
+
this.overlay.querySelector(".hp-cast-overlay-text").textContent = t, this.overlay.querySelector(".hp-cast-overlay-ad").textContent = this.ctx.i18n.castAdOnTv, this.overlay.removeAttribute("data-break"), this.overlay.setAttribute("data-open", ""), this.ctx.overlayEl.setAttribute("data-casting", "");
|
|
361
|
+
}
|
|
362
|
+
hideOverlay() {
|
|
363
|
+
var t;
|
|
364
|
+
(t = this.overlay) == null || t.removeAttribute("data-open"), this.ctx.overlayEl.removeAttribute("data-casting");
|
|
365
|
+
}
|
|
366
|
+
refreshLabels() {
|
|
367
|
+
var t, e, s;
|
|
368
|
+
(t = this.castBtn) == null || t.setAttribute("aria-label", this.ctx.i18n.castButton), (e = this.airplayBtn) == null || e.setAttribute("aria-label", this.ctx.i18n.airplayButton), (s = this.remoteBtn) == null || s.setAttribute("aria-label", this.ctx.i18n.castButton);
|
|
369
|
+
}
|
|
370
|
+
destroy() {
|
|
371
|
+
var t, e, s, i, a;
|
|
372
|
+
if (this.destroyed = !0, m === this && this.detach(), y === this && (y = null), this.context && this.api) {
|
|
373
|
+
const n = this.api.framework.CastContextEventType;
|
|
374
|
+
this.context.removeEventListener(n.CAST_STATE_CHANGED, this.onCastState), this.context.removeEventListener(n.SESSION_STATE_CHANGED, this.onSessionState);
|
|
375
|
+
}
|
|
376
|
+
this.remoteWatchId !== null && ((t = this.ctx.videoEl.remote) == null || t.cancelWatchAvailability(this.remoteWatchId).catch(() => {
|
|
377
|
+
})), (e = this.castBtn) == null || e.remove(), (s = this.airplayBtn) == null || s.remove(), (i = this.remoteBtn) == null || i.remove(), (a = this.overlay) == null || a.remove();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function D(l, t) {
|
|
381
|
+
return new L(l, t);
|
|
382
|
+
}
|
|
383
|
+
export {
|
|
384
|
+
L as CastController,
|
|
385
|
+
D as installCast
|
|
386
|
+
};
|
|
387
|
+
//# sourceMappingURL=cast-DCAT2agI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cast-DCAT2agI.js","sources":["../../src/plugins/cast/castSdk.ts","../../src/plugins/cast/RemoteMediaProxy.ts","../../src/plugins/cast/CastController.ts","../../src/plugins/cast/index.ts"],"sourcesContent":["/**\n * Google Cast Web Sender SDK (CAF) — kullanılan yüzeyin minimal tipleri ve yükleyicisi.\n * https://developers.google.com/cast/docs/web_sender\n */\n\nexport interface CastImage {\n url: string;\n}\n\nexport interface CastMediaMetadata {\n metadataType?: number;\n title?: string;\n subtitle?: string;\n artist?: string;\n albumName?: string;\n images?: CastImage[];\n}\n\nexport interface CastTrack {\n trackContentId?: string;\n trackContentType?: string;\n subtype?: string;\n name?: string;\n language?: string;\n}\n\nexport interface CastVastAdsRequest {\n adTagUrl?: string;\n}\n\nexport interface CastBreakClip {\n vastAdsRequest?: CastVastAdsRequest;\n}\n\nexport interface CastMediaInfo {\n contentId: string;\n contentType: string;\n streamType?: string;\n metadata?: CastMediaMetadata;\n tracks?: CastTrack[];\n hlsSegmentFormat?: string;\n hlsVideoSegmentFormat?: string;\n vmapAdsRequest?: CastVastAdsRequest;\n breakClips?: CastBreakClip[];\n breaks?: unknown[];\n}\n\nexport interface CastLoadRequest {\n currentTime?: number;\n autoplay?: boolean;\n activeTrackIds?: number[];\n}\n\nexport interface CastSessionLike {\n loadMedia(request: CastLoadRequest): Promise<unknown>;\n getCastDevice(): { friendlyName?: string };\n getMediaSession(): { media?: { contentId?: string } } | null;\n}\n\nexport interface RemotePlayerLike {\n isConnected: boolean;\n isMediaLoaded: boolean;\n isPaused: boolean;\n currentTime: number;\n duration: number;\n volumeLevel: number;\n isMuted: boolean;\n playerState: string | null;\n isPlayingBreak: boolean;\n}\n\nexport interface RemotePlayerControllerLike {\n addEventListener(type: string, fn: (e: { field: string; value: unknown }) => void): void;\n removeEventListener(type: string, fn: (e: { field: string; value: unknown }) => void): void;\n playOrPause(): void;\n seek(): void;\n setVolumeLevel(): void;\n muteOrUnmute(): void;\n stop(): void;\n}\n\nexport interface CastContextLike {\n setOptions(options: Record<string, unknown>): void;\n addEventListener(type: string, fn: (e: { castState?: string; sessionState?: string; session?: CastSessionLike }) => void): void;\n removeEventListener(type: string, fn: (e: { castState?: string; sessionState?: string; session?: CastSessionLike }) => void): void;\n requestSession(): Promise<unknown>;\n getCurrentSession(): CastSessionLike | null;\n getCastState(): string;\n endCurrentSession(stopCasting: boolean): void;\n}\n\ntype Ctor<T> = new (...args: never[]) => T;\n\n/** `window.cast.framework` + `window.chrome.cast` — yalnızca kullandıklarımız. */\nexport interface CastApi {\n framework: {\n CastContext: { getInstance(): CastContextLike };\n CastContextEventType: { CAST_STATE_CHANGED: string; SESSION_STATE_CHANGED: string };\n RemotePlayer: Ctor<RemotePlayerLike>;\n RemotePlayerController: new (player: RemotePlayerLike) => RemotePlayerControllerLike;\n RemotePlayerEventType: { ANY_CHANGE: string };\n };\n chrome: {\n AutoJoinPolicy: { ORIGIN_SCOPED: string };\n media: {\n DEFAULT_MEDIA_RECEIVER_APP_ID: string;\n MediaInfo: new (contentId: string, contentType: string) => CastMediaInfo;\n GenericMediaMetadata: Ctor<CastMediaMetadata>;\n MusicTrackMediaMetadata: Ctor<CastMediaMetadata>;\n LoadRequest: new (media: CastMediaInfo) => CastLoadRequest;\n Track: new (trackId: number, type: string) => CastTrack;\n TrackType: { TEXT: string };\n TextTrackType: { SUBTITLES: string };\n StreamType: { BUFFERED: string; LIVE: string };\n VastAdsRequest: Ctor<CastVastAdsRequest>;\n BreakClip: new (id: string) => CastBreakClip;\n Break: new (id: string, breakClipIds: string[], position: number) => unknown;\n HlsSegmentFormat?: { TS: string; FMP4: string; AAC: string };\n HlsVideoSegmentFormat?: { MPEG2_TS: string; FMP4: string };\n };\n Image: new (url: string) => CastImage;\n };\n}\n\nconst CAST_SDK_SRC = 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1';\nconst LOAD_TIMEOUT_MS = 10_000;\nlet loading: Promise<CastApi | null> | null = null;\n\nfunction current(): CastApi | null {\n const w = window as unknown as { cast?: { framework?: CastApi['framework'] }; chrome?: { cast?: CastApi['chrome'] } };\n return w.cast?.framework && w.chrome?.cast ? { framework: w.cast.framework, chrome: w.chrome.cast } : null;\n}\n\n/**\n * Cast SDK'yı bir kez yükler. Yalnızca Chromium tarayıcılarda (Chrome / Edge) ve güvenli bağlamda (HTTPS) denenir;\n * diğerlerinde ya da SDK \"Cast yok\" derse null — buton hiç görünmez.\n */\nexport function loadCastSdk(): Promise<CastApi | null> {\n if (loading) return loading;\n const w = window as unknown as { chrome?: unknown; __onGCastApiAvailable?: (available: boolean, reason?: string) => void };\n if (current()) return (loading = Promise.resolve(current()));\n if (!w.chrome || !window.isSecureContext) return (loading = Promise.resolve(null));\n loading = new Promise<CastApi | null>((resolve) => {\n const previous = w.__onGCastApiAvailable;\n const timer = setTimeout(() => resolve(null), LOAD_TIMEOUT_MS);\n // SDK hazır olunca bu global geri çağrıyı çağırır — sayfa kendi kurduysa onu da çağır.\n w.__onGCastApiAvailable = (available, reason) => {\n previous?.(available, reason);\n clearTimeout(timer);\n resolve(available ? current() : null);\n };\n if (!document.querySelector('script[src*=\"cast_sender.js\"]')) {\n const s = document.createElement('script');\n s.async = true;\n s.src = CAST_SDK_SRC;\n s.onerror = () => {\n clearTimeout(timer);\n loading = null;\n resolve(null);\n };\n document.head.appendChild(s);\n }\n });\n return loading;\n}\n","/** Uzak oynatıcıya (TV) giden komutlar. */\nexport interface RemoteCommands {\n play(): void;\n pause(): void;\n seek(time: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n}\n\nexport interface RemoteState {\n paused: boolean;\n currentTime: number;\n duration: number;\n volume: number;\n muted: boolean;\n ended: boolean;\n}\n\nconst PROXIED = ['paused', 'currentTime', 'duration', 'ended', 'volume', 'muted', 'readyState', 'seeking', 'buffered', 'play', 'pause'] as const;\nconst EMPTY_RANGES: TimeRanges = {\n length: 0,\n start: () => {\n throw new DOMException('Index out of range', 'IndexSizeError');\n },\n end: () => {\n throw new DOMException('Index out of range', 'IndexSizeError');\n },\n};\n/** Seek bar sürüklenirken her harekette TV'ye istek gitmesin. */\nconst SEEK_DEBOUNCE_MS = 150;\n\n/** <video>'nun gerçek (prototip) değeri — vekil kuruluyken de. */\nexport function nativeGet<K extends 'currentTime' | 'duration' | 'paused' | 'ended'>(video: HTMLVideoElement, key: K): HTMLMediaElement[K] {\n const d = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, key);\n return d!.get!.call(video) as HTMLMediaElement[K];\n}\n\n/**\n * Cast sırasında `<video>` örneğinin oynatma yüzeyini (paused, currentTime, play(), volume…) TV'ye bağlar ve TV'den\n * gelen durumu olay olarak (play / pause / timeupdate / volumechange…) yayar. Böylece kontrol çubuğu, seek bar,\n * klavye kısayolları ve eklentiler hiç değişmeden TV'yi yönetir. Kaldırılınca örnek özellikleri silinir, prototip\n * (gerçek video) geri gelir.\n */\nexport class RemoteMediaProxy {\n private state: RemoteState;\n private pendingSeek: number | null = null;\n private seekTimer: ReturnType<typeof setTimeout> | null = null;\n private installed = false;\n\n constructor(\n private readonly video: HTMLVideoElement,\n private readonly commands: RemoteCommands,\n initial: RemoteState\n ) {\n this.state = { ...initial };\n }\n\n get current(): Readonly<RemoteState> {\n return this.state;\n }\n\n install(): void {\n if (this.installed) return;\n this.installed = true;\n const v = this.video;\n const s = (): RemoteState => this.state;\n const define = (key: string, desc: PropertyDescriptor): void => {\n Object.defineProperty(v, key, { configurable: true, enumerable: false, ...desc });\n };\n define('paused', { get: () => s().paused });\n define('ended', { get: () => s().ended });\n define('duration', { get: () => s().duration });\n define('readyState', { get: () => 4 });\n define('seeking', { get: () => this.pendingSeek !== null });\n define('buffered', { get: () => EMPTY_RANGES });\n define('currentTime', {\n get: () => this.pendingSeek ?? s().currentTime,\n set: (t: number) => this.seek(t),\n });\n define('volume', {\n get: () => s().volume,\n set: (vol: number) => {\n const clamped = Math.min(1, Math.max(0, Number(vol) || 0));\n this.state.volume = clamped;\n this.commands.setVolume(clamped);\n this.fire('volumechange');\n },\n });\n define('muted', {\n get: () => s().muted,\n set: (m: boolean) => {\n this.state.muted = !!m;\n this.commands.setMuted(!!m);\n this.fire('volumechange');\n },\n });\n define('play', {\n value: () => {\n if (this.state.ended) this.seek(0);\n this.commands.play();\n return Promise.resolve();\n },\n });\n define('pause', { value: () => this.commands.pause() });\n }\n\n uninstall(): void {\n if (!this.installed) return;\n this.installed = false;\n if (this.seekTimer) clearTimeout(this.seekTimer);\n this.seekTimer = null;\n this.pendingSeek = null;\n for (const key of PROXIED) delete (this.video as unknown as Record<string, unknown>)[key];\n }\n\n /** TV'den gelen durum — değişen alanlar için olay yayar. */\n update(patch: Partial<RemoteState>): void {\n const prev = this.state;\n this.state = { ...prev, ...patch };\n const next = this.state;\n if (patch.duration !== undefined && patch.duration !== prev.duration) this.fire('durationchange');\n if (patch.currentTime !== undefined && patch.currentTime !== prev.currentTime && this.pendingSeek === null) this.fire('timeupdate');\n if (patch.volume !== undefined || patch.muted !== undefined) {\n if (next.volume !== prev.volume || next.muted !== prev.muted) this.fire('volumechange');\n }\n if (patch.paused !== undefined && patch.paused !== prev.paused) {\n if (next.paused) this.fire('pause');\n else {\n this.fire('play');\n this.fire('playing');\n }\n }\n if (patch.ended && !prev.ended) this.fire('ended');\n }\n\n private seek(t: number): void {\n const target = Math.max(0, Number(t) || 0);\n const first = this.pendingSeek === null;\n this.pendingSeek = target;\n if (first) this.fire('seeking');\n this.fire('timeupdate');\n if (this.seekTimer) clearTimeout(this.seekTimer);\n this.seekTimer = setTimeout(() => {\n this.seekTimer = null;\n const to = this.pendingSeek ?? target;\n this.commands.seek(to);\n this.state = { ...this.state, currentTime: to, ended: false };\n this.pendingSeek = null;\n this.fire('seeked');\n this.fire('timeupdate');\n }, SEEK_DEBOUNCE_MS);\n }\n\n private fire(type: string): void {\n this.video.dispatchEvent(new Event(type));\n }\n}\n","import type { CastOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { setIconName } from '../../icons/Icon';\nimport { loadCastSdk, type CastApi, type CastContextLike, type CastMediaInfo, type CastSessionLike, type RemotePlayerControllerLike, type RemotePlayerLike } from './castSdk';\nimport { RemoteMediaProxy, nativeGet } from './RemoteMediaProxy';\n\n/** TV'ye gönderilecek içerik — player o anki duruma göre hazırlar. */\nexport interface CastMedia {\n src: string;\n contentType: string;\n live: boolean;\n title?: string;\n subtitle?: string;\n image?: string;\n /** Ses modu: TV'de müzik parçası olarak (kapak, sanatçı). */\n music: boolean;\n subtitles: Array<{ src: string; label: string; lang: string; default?: boolean }>;\n /** TV'de oynatılacak reklamlar (makroları doldurulmuş tag'ler); null = reklamsız. */\n ads: { vmap?: string; preroll?: string; midroll?: string; midrollIntervalSeconds?: number; postroll?: string } | null;\n}\n\nexport interface CastPlayerContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n overlayEl: HTMLElement;\n i18n: HopeLocaleStrings;\n log(entry: { message: string; fatal?: boolean; details?: Record<string, string | number | boolean | undefined> }): void;\n addButton(label: string, icon: string, onClick: () => void): { btn: HTMLButtonElement; icon: HTMLElement };\n getMedia(): CastMedia | null;\n /** Yerelde video reklamı oynuyor — bu sırada yayın başlatılmaz. */\n isAdPlaying(): boolean;\n /** hls.js (MSE) ile oynatılıyor — AirPlay / Remote Playback bu kaynağı TV'ye veremez. */\n isMse(): boolean;\n /** İçerik kimliği — kalite / yedek kaynak değişimi aynı içerik sayılır (TV'de konum korunur). */\n contentKey(): string;\n /** İçerik TV'de mi (Chromecast) — player yerel reklamları askıya alır, otomatik oynatmayı keser. */\n onRemoteChange(remote: boolean): void;\n}\n\ntype Via = 'chromecast' | 'airplay' | 'remote';\ntype CastState = 'available' | 'unavailable' | 'connecting' | 'connected' | 'disconnected';\n\n/** Aynı sayfada birden çok player: Cast oturumu, butonuna basılan player'ındır. */\nlet requester: CastController | null = null;\nlet owner: CastController | null = null;\n/** Midroll aralığından üretilecek en fazla ara. */\nconst MAX_INTERVAL_BREAKS = 20;\nconst MIDROLL_END_MARGIN_S = 5;\n\n/**\n * TV'ye yayın: Google Cast (Chromecast / Google TV), AirPlay ve Remote Playback API. Her biri ayrı ayrı açılır;\n * butonlar yalnızca uygun cihaz varken görünür. Chromecast'te içerik TV'de oynar, player kumandaya dönüşür\n * (RemoteMediaProxy); bağlantı bitince yerelde TV'deki saniyeden devam eder.\n */\nexport class CastController {\n private options: CastOptions;\n private api: CastApi | null = null;\n private context: CastContextLike | null = null;\n private session: CastSessionLike | null = null;\n private player: RemotePlayerLike | null = null;\n private controller: RemotePlayerControllerLike | null = null;\n private proxy: RemoteMediaProxy | null = null;\n private castBtn: HTMLButtonElement | null = null;\n private castIcon: HTMLElement | null = null;\n private airplayBtn: HTMLButtonElement | null = null;\n private remoteBtn: HTMLButtonElement | null = null;\n private overlay: HTMLDivElement | null = null;\n private loadedSrc = '';\n private loadedContent = '';\n private savedAutoplay = false;\n private airplayActive = false;\n private destroyed = false;\n private remoteWatchId: number | null = null;\n\n constructor(\n private readonly ctx: CastPlayerContext,\n options: CastOptions\n ) {\n this.options = options;\n if (options.chromecast) void this.initChromecast();\n if (options.airplay) this.initAirPlay();\n if (options.remotePlayback) this.initRemotePlayback();\n }\n\n update(options: CastOptions): void {\n const prev = this.options;\n this.options = options;\n if (options.chromecast && !prev.chromecast) void this.initChromecast();\n if (options.airplay && !prev.airplay) this.initAirPlay();\n if (options.remotePlayback && !prev.remotePlayback) this.initRemotePlayback();\n if (this.castBtn) this.castBtn.hidden = !options.chromecast || this.castBtn.hidden;\n if (this.airplayBtn && !options.airplay) this.airplayBtn.hidden = true;\n if (this.remoteBtn && !options.remotePlayback) this.remoteBtn.hidden = true;\n }\n\n /** İçerik şu an TV'de mi (herhangi bir yoldan). */\n get casting(): boolean {\n return !!this.proxy || this.airplayActive || this.ctx.videoEl.remote?.state === 'connected';\n }\n\n private emit(state: CastState, via: Via, device?: string): void {\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:cast', { detail: { state, via, device } }));\n }\n\n private button(label: string, icon: string, onClick: () => void): { btn: HTMLButtonElement; icon: HTMLElement } {\n const b = this.ctx.addButton(label, icon, onClick);\n b.btn.hidden = true;\n return b;\n }\n\n // ── Google Cast ─────────────────────────────────────────────────────────\n\n private async initChromecast(): Promise<void> {\n if (this.castBtn) return;\n const { btn, icon } = this.button(this.ctx.i18n.castButton, 'cast', () => this.requestCast());\n btn.setAttribute('part', 'cast-button');\n this.castBtn = btn;\n this.castIcon = icon;\n const api = await loadCastSdk();\n if (!api || this.destroyed) {\n if (!api) this.ctx.log({ message: 'Google Cast is not available in this browser (Chrome / Edge over HTTPS needed)' });\n return;\n }\n this.api = api;\n const context = api.framework.CastContext.getInstance();\n this.context = context;\n context.setOptions({\n receiverApplicationId: this.options.receiverAppId || api.chrome.media.DEFAULT_MEDIA_RECEIVER_APP_ID,\n autoJoinPolicy: api.chrome.AutoJoinPolicy.ORIGIN_SCOPED,\n });\n const types = api.framework.CastContextEventType;\n context.addEventListener(types.CAST_STATE_CHANGED, this.onCastState);\n context.addEventListener(types.SESSION_STATE_CHANGED, this.onSessionState);\n this.onCastState({ castState: context.getCastState() });\n // Sayfa yenilendi ve oturum sürüyor (TV aynı içeriği oynatıyor) → kumandayı yeniden bağla.\n const existing = context.getCurrentSession();\n if (existing && !owner) this.tryResume(existing);\n }\n\n private readonly onCastState = (e: { castState?: string }): void => {\n const state = e.castState ?? 'NO_DEVICES_AVAILABLE';\n if (this.castBtn) this.castBtn.hidden = state === 'NO_DEVICES_AVAILABLE';\n this.castBtn?.toggleAttribute('data-connecting', state === 'CONNECTING');\n if (!this.proxy) this.emit(state === 'NO_DEVICES_AVAILABLE' ? 'unavailable' : state === 'CONNECTING' ? 'connecting' : 'available', 'chromecast');\n };\n\n private readonly onSessionState = (e: { sessionState?: string; session?: CastSessionLike }): void => {\n const s = e.sessionState;\n if ((s === 'SESSION_STARTED' || s === 'SESSION_RESUMED') && e.session) {\n if (requester === this) {\n requester = null;\n void this.attach(e.session, true);\n } else if (s === 'SESSION_RESUMED' && !owner) {\n this.tryResume(e.session);\n }\n } else if (s === 'SESSION_ENDED' || s === 'SESSION_START_FAILED') {\n if (requester === this) requester = null;\n if (owner === this) this.detach();\n }\n };\n\n private requestCast(): void {\n if (!this.context) return;\n if (this.ctx.isAdPlaying()) {\n this.ctx.log({ message: 'Cast: wait for the ad to finish' });\n return;\n }\n requester = this;\n // Bağlıyken Chrome'un seçicisi \"yayını durdur\"u da sunar.\n this.context.requestSession().catch((err: unknown) => {\n if (requester === this) requester = null;\n // Kullanıcı seçiciyi kapattı ('cancel') — hata değil.\n if (String(err) !== 'cancel') this.ctx.log({ message: `Cast session failed: ${String(err)}` });\n });\n }\n\n private tryResume(session: CastSessionLike): void {\n const media = this.ctx.getMedia();\n const remoteId = session.getMediaSession()?.media?.contentId;\n if (media && remoteId && remoteId === media.src) void this.attach(session, false);\n }\n\n private async attach(session: CastSessionLike, load: boolean): Promise<void> {\n const api = this.api;\n if (!api || this.destroyed) return;\n if (owner && owner !== this) owner.detach();\n owner = this;\n this.session = session;\n const v = this.ctx.videoEl;\n const startAt = nativeGet(v, 'currentTime');\n const duration = nativeGet(v, 'duration');\n HTMLMediaElement.prototype.pause.call(v);\n // Cast sırasında kaynak değişirse (playlist / kalite) yerel video kendiliğinden çalmasın.\n this.savedAutoplay = v.autoplay;\n v.autoplay = false;\n\n const player = new api.framework.RemotePlayer();\n const controller = new api.framework.RemotePlayerController(player);\n this.player = player;\n this.controller = controller;\n this.proxy = new RemoteMediaProxy(\n v,\n {\n play: () => player.isPaused && controller.playOrPause(),\n pause: () => !player.isPaused && controller.playOrPause(),\n seek: (t) => {\n player.currentTime = t;\n controller.seek();\n },\n setVolume: (vol) => {\n player.volumeLevel = vol;\n controller.setVolumeLevel();\n },\n setMuted: (m) => player.isMuted !== m && controller.muteOrUnmute(),\n },\n { paused: false, currentTime: startAt, duration, volume: v.volume, muted: v.muted, ended: false }\n );\n this.proxy.install();\n controller.addEventListener(api.framework.RemotePlayerEventType.ANY_CHANGE, this.onRemoteChange);\n v.addEventListener('loadstart', this.onLocalSourceChange);\n this.ctx.onRemoteChange(true);\n const device = session.getCastDevice()?.friendlyName || this.ctx.i18n.castDeviceFallback;\n this.showOverlay(this.ctx.i18n.castPlayingOn.replace('{device}', device));\n this.castBtn?.setAttribute('aria-pressed', 'true');\n if (this.castIcon) setIconName(this.castIcon, 'cast-connected');\n this.emit('connected', 'chromecast', device);\n if (load) await this.loadMedia(startAt, true);\n else {\n this.loadedSrc = session.getMediaSession()?.media?.contentId ?? '';\n this.loadedContent = this.ctx.contentKey();\n }\n }\n\n /** O an çalan içeriği TV'ye yükler (reklam araları ve altyazılarla). */\n private async loadMedia(currentTime: number, autoplay: boolean): Promise<void> {\n const api = this.api;\n const session = this.session;\n const media = this.ctx.getMedia();\n if (!api || !session || !media) {\n this.ctx.log({ message: 'Cast: nothing to send (no playable source)' });\n return;\n }\n const m = api.chrome.media;\n const info: CastMediaInfo = new m.MediaInfo(media.src, media.contentType);\n info.streamType = media.live ? m.StreamType.LIVE : m.StreamType.BUFFERED;\n const md = media.music ? new m.MusicTrackMediaMetadata() : new m.GenericMediaMetadata();\n md.title = media.title;\n if (media.music) md.artist = media.subtitle;\n else md.subtitle = media.subtitle;\n if (media.image) md.images = [new api.chrome.Image(media.image)];\n info.metadata = md;\n if (/mpegurl/i.test(media.contentType) && this.options.hlsSegmentFormat === 'fmp4') {\n if (m.HlsSegmentFormat) info.hlsSegmentFormat = m.HlsSegmentFormat.FMP4;\n if (m.HlsVideoSegmentFormat) info.hlsVideoSegmentFormat = m.HlsVideoSegmentFormat.FMP4;\n }\n const activeTrackIds: number[] = [];\n info.tracks = media.subtitles.map((s, i) => {\n const t = new m.Track(i + 1, m.TrackType.TEXT);\n t.trackContentId = s.src;\n t.trackContentType = 'text/vtt';\n t.subtype = m.TextTrackType.SUBTITLES;\n t.name = s.label;\n t.language = s.lang;\n if (s.default) activeTrackIds.push(i + 1);\n return t;\n });\n this.applyAds(info, media);\n const req = new m.LoadRequest(info);\n req.currentTime = media.live ? undefined : currentTime;\n req.autoplay = autoplay;\n if (activeTrackIds.length) req.activeTrackIds = activeTrackIds;\n this.loadedSrc = media.src;\n this.loadedContent = this.ctx.contentKey();\n try {\n await session.loadMedia(req);\n this.ctx.log({ message: 'Cast: media loaded on the TV', details: { src: media.src, ads: media.ads ? (media.ads.vmap ? 'vmap' : 'vast') : 'none' } });\n } catch (err) {\n this.ctx.log({ message: `Cast: the TV could not load the media: ${String(err)}`, fatal: true, details: { src: media.src } });\n }\n }\n\n /**\n * Reklamlar TV'de: VMAP verilmişse receiver tüm araları kendisi planlar (vmapAdsRequest); yoksa VAST tag'leri\n * ara olarak eklenir — preroll (0), aralıklı midroll'lar, postroll (-1). Reklamları receiver oynatır ve sayar.\n */\n private applyAds(info: CastMediaInfo, media: CastMedia): void {\n const ads = media.ads;\n const m = this.api!.chrome.media;\n if (!ads) return;\n if (ads.vmap) {\n const req = new m.VastAdsRequest();\n req.adTagUrl = ads.vmap;\n info.vmapAdsRequest = req;\n return;\n }\n const clips: unknown[] = [];\n const breaks: unknown[] = [];\n const add = (id: string, tag: string, position: number): void => {\n const clip = new m.BreakClip(`clip-${id}`);\n const req = new m.VastAdsRequest();\n req.adTagUrl = tag;\n clip.vastAdsRequest = req;\n clips.push(clip);\n breaks.push(new m.Break(`break-${id}`, [`clip-${id}`], position));\n };\n if (ads.preroll) add('pre', ads.preroll, 0);\n const every = ads.midrollIntervalSeconds ?? 0;\n const duration = this.proxy?.current.duration ?? NaN;\n if (ads.midroll && every > 0 && !media.live && Number.isFinite(duration)) {\n // Bitişe çok yakın midroll olmasın (orada postroll var).\n for (let t = every, i = 1; t < duration - MIDROLL_END_MARGIN_S && i <= MAX_INTERVAL_BREAKS; t += every, i++) add(`mid-${i}`, ads.midroll, t);\n }\n if (ads.postroll && !media.live) add('post', ads.postroll, -1);\n if (clips.length) {\n info.breakClips = clips as CastMediaInfo['breakClips'];\n info.breaks = breaks;\n }\n }\n\n private readonly onRemoteChange = (e: { field: string; value: unknown }): void => {\n const p = this.player;\n const proxy = this.proxy;\n if (!p || !proxy) return;\n switch (e.field) {\n case 'isPaused':\n proxy.update({ paused: !!e.value });\n break;\n case 'currentTime':\n proxy.update({ currentTime: Number(e.value) || 0 });\n break;\n case 'duration':\n proxy.update({ duration: Number(e.value) > 0 ? Number(e.value) : proxy.current.duration });\n break;\n case 'volumeLevel':\n proxy.update({ volume: Number(e.value) });\n break;\n case 'isMuted':\n proxy.update({ muted: !!e.value });\n break;\n case 'playerState':\n // İçerik TV'de bitti (IDLE + daha önce oynuyordu) → ended.\n if (e.value === 'IDLE' && p.isMediaLoaded === false && proxy.current.currentTime > 0) proxy.update({ ended: true, paused: true });\n else if (e.value === 'PLAYING') proxy.update({ ended: false, paused: false });\n break;\n case 'isPlayingBreak':\n this.overlay?.toggleAttribute('data-break', !!e.value);\n break;\n case 'isConnected':\n if (!e.value && owner === this) this.detach();\n break;\n }\n };\n\n /** Cast sırasında player başka bir kaynağa geçti (playlist sonraki öğe, kalite, yedek kaynak) → TV'ye de gönder. */\n private readonly onLocalSourceChange = (): void => {\n if (!this.proxy) return;\n HTMLMediaElement.prototype.pause.call(this.ctx.videoEl);\n const media = this.ctx.getMedia();\n if (!media || media.src === this.loadedSrc) return;\n // Aynı içeriğin başka kalitesi / yedeği ise kaldığı yerden, yeni bir içerikse (playlist) baştan.\n const same = this.ctx.contentKey() === this.loadedContent;\n void this.loadMedia(same ? this.proxy.current.currentTime : 0, true);\n };\n\n private detach(): void {\n const proxy = this.proxy;\n if (!proxy) return;\n if (owner === this) owner = null;\n const { currentTime, paused, ended } = proxy.current;\n const v = this.ctx.videoEl;\n this.controller?.removeEventListener(this.api!.framework.RemotePlayerEventType.ANY_CHANGE, this.onRemoteChange);\n v.removeEventListener('loadstart', this.onLocalSourceChange);\n proxy.uninstall();\n this.proxy = null;\n this.player = null;\n this.controller = null;\n this.session = null;\n this.loadedSrc = '';\n v.autoplay = this.savedAutoplay;\n this.ctx.onRemoteChange(false);\n this.hideOverlay();\n this.castBtn?.setAttribute('aria-pressed', 'false');\n if (this.castIcon) setIconName(this.castIcon, 'cast');\n // TV'deki saniyeden yerelde devam (bittiyse olduğu yerde kalır).\n if (Number.isFinite(currentTime) && currentTime > 0 && !ended) v.currentTime = currentTime;\n if (!paused && !ended) void v.play().catch(() => {});\n this.emit('disconnected', 'chromecast');\n }\n\n // ── AirPlay (Safari) ────────────────────────────────────────────────────\n\n private initAirPlay(): void {\n if (this.airplayBtn || !('WebKitPlaybackTargetAvailabilityEvent' in window)) return;\n const v = this.ctx.videoEl as HTMLVideoElement & { webkitShowPlaybackTargetPicker?: () => void; webkitCurrentPlaybackTargetIsWireless?: boolean };\n v.setAttribute('x-webkit-airplay', 'allow');\n const { btn } = this.button(this.ctx.i18n.airplayButton, 'airplay', () => {\n if (this.ctx.isMse()) {\n this.ctx.log({ message: 'AirPlay: this source plays through hls.js (MSE) — use hls.engine: \"auto\" / \"native\" on Safari for AirPlay' });\n return;\n }\n v.webkitShowPlaybackTargetPicker?.();\n });\n btn.setAttribute('part', 'airplay-button');\n this.airplayBtn = btn;\n v.addEventListener('webkitplaybacktargetavailabilitychanged', ((e: Event & { availability?: string }) => {\n const available = e.availability === 'available';\n btn.hidden = !available || !this.options.airplay;\n if (!this.airplayActive) this.emit(available ? 'available' : 'unavailable', 'airplay');\n }) as EventListener);\n v.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', () => {\n const on = !!v.webkitCurrentPlaybackTargetIsWireless;\n if (on === this.airplayActive) return;\n this.airplayActive = on;\n btn.setAttribute('aria-pressed', String(on));\n if (on) this.showOverlay(this.ctx.i18n.airplayPlaying);\n else this.hideOverlay();\n this.emit(on ? 'connected' : 'disconnected', 'airplay');\n });\n }\n\n // ── Remote Playback API ─────────────────────────────────────────────────\n\n private initRemotePlayback(): void {\n const v = this.ctx.videoEl;\n const remote = v.remote;\n if (this.remoteBtn || !remote) return;\n v.disableRemotePlayback = false;\n const { btn } = this.button(this.ctx.i18n.castButton, 'cast', () => {\n if (this.ctx.isMse()) {\n this.ctx.log({ message: 'Remote playback: hls.js (MSE) sources cannot be sent to the device' });\n return;\n }\n remote.prompt().catch((err: unknown) => this.ctx.log({ message: `Remote playback: ${String(err)}` }));\n });\n btn.setAttribute('part', 'remote-playback-button');\n this.remoteBtn = btn;\n remote\n .watchAvailability((available) => {\n // Google Cast butonu görünüyorsa aynı işi yapan ikinci butonu gösterme.\n btn.hidden = !available || this.ctx.isMse() || !!(this.castBtn && !this.castBtn.hidden);\n if (remote.state === 'disconnected') this.emit(available ? 'available' : 'unavailable', 'remote');\n })\n .then((id) => (this.remoteWatchId = id))\n .catch(() => (btn.hidden = true));\n remote.addEventListener('connecting', () => this.emit('connecting', 'remote'));\n remote.addEventListener('connect', () => {\n btn.setAttribute('aria-pressed', 'true');\n this.showOverlay(this.ctx.i18n.castPlayingOn.replace('{device}', this.ctx.i18n.castDeviceFallback));\n this.emit('connected', 'remote');\n });\n remote.addEventListener('disconnect', () => {\n btn.setAttribute('aria-pressed', 'false');\n this.hideOverlay();\n this.emit('disconnected', 'remote');\n });\n }\n\n // ── \"TV'de oynatılıyor\" katmanı ─────────────────────────────────────────\n\n private showOverlay(text: string): void {\n if (!this.overlay) {\n const el = document.createElement('div');\n el.className = 'hp-cast-overlay';\n el.setAttribute('part', 'cast-overlay');\n el.setAttribute('role', 'status');\n const icon = document.createElement('i');\n icon.className = 'hp-icon hp-icon-cast-connected';\n icon.setAttribute('aria-hidden', 'true');\n const label = document.createElement('span');\n label.className = 'hp-cast-overlay-text';\n const ad = document.createElement('span');\n ad.className = 'hp-cast-overlay-ad';\n el.append(icon, label, ad);\n this.ctx.overlayEl.appendChild(el);\n this.overlay = el;\n }\n this.overlay.querySelector('.hp-cast-overlay-text')!.textContent = text;\n this.overlay.querySelector('.hp-cast-overlay-ad')!.textContent = this.ctx.i18n.castAdOnTv;\n this.overlay.removeAttribute('data-break');\n this.overlay.setAttribute('data-open', '');\n this.ctx.overlayEl.setAttribute('data-casting', '');\n }\n\n private hideOverlay(): void {\n this.overlay?.removeAttribute('data-open');\n this.ctx.overlayEl.removeAttribute('data-casting');\n }\n\n refreshLabels(): void {\n this.castBtn?.setAttribute('aria-label', this.ctx.i18n.castButton);\n this.airplayBtn?.setAttribute('aria-label', this.ctx.i18n.airplayButton);\n this.remoteBtn?.setAttribute('aria-label', this.ctx.i18n.castButton);\n }\n\n destroy(): void {\n this.destroyed = true;\n if (owner === this) {\n // Player sayfadan kalkıyor: TV'deki yayın sürsün (Cast'in olağan davranışı), kumanda bağı kopsun.\n this.detach();\n }\n if (requester === this) requester = null;\n if (this.context && this.api) {\n const types = this.api.framework.CastContextEventType;\n this.context.removeEventListener(types.CAST_STATE_CHANGED, this.onCastState);\n this.context.removeEventListener(types.SESSION_STATE_CHANGED, this.onSessionState);\n }\n if (this.remoteWatchId !== null) void this.ctx.videoEl.remote?.cancelWatchAvailability(this.remoteWatchId).catch(() => {});\n this.castBtn?.remove();\n this.airplayBtn?.remove();\n this.remoteBtn?.remove();\n this.overlay?.remove();\n }\n}\n","import { CastController, type CastMedia, type CastPlayerContext } from './CastController';\nimport type { CastOptions } from '../../types';\n\n/** TV'ye yayını kurar (Google Cast / AirPlay / Remote Playback — her biri seçenekle açılır). */\nexport function installCast(ctx: CastPlayerContext, options: CastOptions): CastController {\n return new CastController(ctx, options);\n}\n\nexport { CastController };\nexport type { CastMedia, CastPlayerContext };\n"],"names":["CAST_SDK_SRC","LOAD_TIMEOUT_MS","loading","current","w","_a","_b","loadCastSdk","resolve","previous","timer","available","reason","s","PROXIED","EMPTY_RANGES","SEEK_DEBOUNCE_MS","nativeGet","video","key","RemoteMediaProxy","commands","initial","__publicField","v","define","desc","t","vol","clamped","m","patch","prev","next","target","first","to","type","requester","owner","MAX_INTERVAL_BREAKS","MIDROLL_END_MARGIN_S","CastController","ctx","options","e","state","p","proxy","media","same","via","device","label","icon","onClick","b","btn","api","context","types","existing","err","session","remoteId","load","startAt","duration","player","controller","setIconName","_d","_c","currentTime","autoplay","info","md","activeTrackIds","i","req","ads","clips","breaks","add","id","tag","position","clip","every","paused","ended","on","remote","text","el","ad","_e","installCast"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countdownScreen-CI-u6jjA.js","sources":["../../src/plugins/countdown-screen/CountdownScreen.ts","../../src/plugins/countdown-screen/index.ts"],"sourcesContent":["import type { CountdownScreenOptions } from '../../types';\nimport type { GatePlayerContext } from '../shared/GatePlayerContext';\n\n/** Hedef tarihe kadar içeriği engelleyen geri sayım ekranı (blockChrome ile). */\nexport class CountdownScreen {\n private readonly wrapper: HTMLElement;\n private readonly timerLabel: HTMLElement;\n private readonly timerEl: HTMLElement;\n private interval: ReturnType<typeof setInterval> | null = null;\n private bgInterval: ReturnType<typeof setInterval> | null = null;\n private imageIndex = 0;\n private readonly targetTime: number;\n private resolved = false;\n private readonly completeCallbacks: Array<() => void> = [];\n\n constructor(\n private readonly ctx: GatePlayerContext,\n private readonly options: CountdownScreenOptions\n ) {\n this.targetTime = new Date(options.time).getTime();\n\n this.wrapper = document.createElement('div');\n this.wrapper.setAttribute('part', 'countdown-screen');\n this.wrapper.className =\n 'hp:absolute hp:inset-0 hp:z-40 hp:flex hp:items-end hp:bg-cover hp:bg-center hp:bg-surface hp:text-on-surface';\n\n const info = document.createElement('div');\n info.className = 'hp:p-4 hp:w-full hp:bg-gradient-to-t hp:from-black/80 hp:to-transparent';\n\n if (options.title) {\n const title = document.createElement('h3');\n title.className = 'hp:text-lg hp:font-semibold hp:m-0';\n title.textContent = options.title;\n info.appendChild(title);\n }\n if (options.spot) {\n const spot = document.createElement('p');\n spot.className = 'hp:text-sm hp:opacity-80 hp:m-0 hp:mt-1';\n spot.textContent = options.spot;\n info.appendChild(spot);\n }\n if (options.description) {\n const desc = document.createElement('p');\n desc.className = 'hp:text-xs hp:opacity-70 hp:m-0 hp:mt-1';\n desc.textContent = options.description;\n info.appendChild(desc);\n }\n\n this.timerLabel = document.createElement('span');\n this.timerLabel.className = 'hp:text-xs hp:opacity-70 hp:block hp:mt-2';\n this.timerLabel.textContent = ctx.i18n.countdownRemaining;\n info.appendChild(this.timerLabel);\n\n this.timerEl = document.createElement('div');\n this.timerEl.className = 'hp:text-2xl hp:font-mono hp:tabular-nums';\n info.appendChild(this.timerEl);\n\n this.wrapper.appendChild(info);\n this.updateBackground();\n ctx.overlayContainerEl.appendChild(this.wrapper);\n\n ctx.blockChrome();\n ctx.videoEl.addEventListener('play', this.onPlayWhileBlocked);\n\n if (Array.isArray(options.coverImage) && options.coverImage.length > 0) {\n this.bgInterval = setInterval(() => {\n this.imageIndex = (this.imageIndex + 1) % (options.coverImage as string[]).length;\n this.updateBackground();\n }, options.imageChangeInterval ?? 5000);\n }\n\n this.start();\n }\n\n refreshLabels(): void {\n this.timerLabel.textContent = this.ctx.i18n.countdownRemaining;\n }\n\n isComplete(): boolean {\n return this.resolved;\n }\n\n /** Geri sayım bitince çağrılır (zaten bittiyse anında). */\n onComplete(cb: () => void): void {\n if (this.resolved) cb();\n else this.completeCallbacks.push(cb);\n }\n\n destroy(): void {\n if (this.interval) clearInterval(this.interval);\n if (this.bgInterval) clearInterval(this.bgInterval);\n this.ctx.videoEl.removeEventListener('play', this.onPlayWhileBlocked);\n if (!this.resolved) this.ctx.unblockChrome();\n this.wrapper.remove();\n this.completeCallbacks.length = 0;\n }\n\n private readonly onPlayWhileBlocked = (): void => {\n if (!this.resolved) this.ctx.videoEl.pause();\n };\n\n private updateBackground(): void {\n const img = Array.isArray(this.options.coverImage) ? this.options.coverImage[this.imageIndex] : this.options.coverImage;\n this.wrapper.style.backgroundImage = img ? `url(\"${img}\")` : 'none';\n }\n\n private start(): void {\n const tick = () => {\n const diff = Math.max(this.targetTime - Date.now(), 0);\n const h = Math.floor(diff / 3600000);\n const m = Math.floor((diff / 60000) % 60);\n const s = Math.floor((diff / 1000) % 60);\n this.timerEl.textContent = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;\n\n if (diff <= 0) this.complete();\n };\n\n tick();\n if (this.targetTime - Date.now() > 0) {\n this.interval = setInterval(tick, 1000);\n } else {\n this.complete();\n }\n }\n\n private complete(): void {\n if (this.resolved) return;\n this.resolved = true;\n if (this.interval) clearInterval(this.interval);\n if (this.bgInterval) clearInterval(this.bgInterval);\n this.ctx.videoEl.removeEventListener('play', this.onPlayWhileBlocked);\n this.wrapper.remove();\n this.ctx.unblockChrome();\n const callbacks = this.completeCallbacks.splice(0);\n for (const cb of callbacks) cb();\n }\n}\n","import { CountdownScreen } from './CountdownScreen';\nimport type { GatePlayerContext } from '../shared/GatePlayerContext';\nimport type { CountdownScreenOptions } from '../../types';\n\nexport function installCountdownScreen(ctx: GatePlayerContext, options: CountdownScreenOptions): CountdownScreen {\n return new CountdownScreen(ctx, options);\n}\n\nexport { CountdownScreen };\nexport type { GatePlayerContext };\n"],"names":["CountdownScreen","ctx","options","__publicField","info","title","spot","desc","cb","img","tick","diff","h","m","callbacks","installCountdownScreen"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dai-B9Tth1Iv.js","sources":["../../src/plugins/dai/loadDaiSdk.ts","../../src/plugins/dai/DaiController.ts","../../src/plugins/dai/index.ts"],"sourcesContent":["const DAI_SDK_URL = 'https://imasdk.googleapis.com/js/sdkloader/ima3_dai.js';\n\n// Window.google loadImaSdk.ts'de zaten augment edildi — burada tekrar tanımlanmıyor.\nfunction getLoadedDai(): typeof google.ima.dai | undefined {\n return (window as unknown as { google?: { ima?: { dai?: typeof google.ima.dai } } }).google?.ima?.dai;\n}\n\nlet loadPromise: Promise<typeof google.ima.dai> | null = null;\n\n/** DAI SDK, normal IMA SDK'dan (loadImaSdk.ts) AYRI bir script — ima3_dai.js. */\nexport function loadDaiSdk(): Promise<typeof google.ima.dai> {\n const existing = getLoadedDai();\n if (existing) return Promise.resolve(existing);\n if (loadPromise) return loadPromise;\n\n loadPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = DAI_SDK_URL;\n script.async = true;\n script.onload = () => {\n const dai = getLoadedDai();\n if (dai) resolve(dai);\n else reject(new Error('DAI SDK yüklendi ama window.google.ima.dai yok'));\n };\n script.onerror = () => reject(new Error('DAI SDK yüklenemedi (reklam engelleyici olabilir)'));\n document.head.appendChild(script);\n });\n return loadPromise;\n}\n","import { loadDaiSdk } from './loadDaiSdk';\nimport type { DaiOptions } from '../../types';\n\nexport interface DaiPlayerContext {\n videoEl: HTMLVideoElement;\n hostEl: HTMLElement;\n /** IMA DAI'nin kendi ad UI'ını (skip/countdown/clickthrough) çizdiği katman — plugins/ads'teki adLayerEl ile aynı fikir. */\n adUiEl: HTMLElement;\n loadStreamUrl(url: string): Promise<void>;\n /** Reklam arası boyunca kullanıcı canlı reklamın İÇİNE seek edemesin diye. */\n disableSeeking(): void;\n enableSeeking(): void;\n}\n\n/** Google IMA DAI: stream StreamManager üzerinden istenir; reklam araları sırasında seek kilitlenir. */\nexport class DaiController {\n private dai: typeof google.ima.dai | null = null;\n private streamManager: google.ima.dai.api.StreamManager | null = null;\n private readonly metadataTrackListeners = new Map<TextTrack, () => void>();\n\n constructor(\n private readonly ctx: DaiPlayerContext,\n private readonly options: DaiOptions\n ) {}\n\n async install(): Promise<void> {\n let dai: typeof google.ima.dai;\n try {\n dai = await loadDaiSdk();\n } catch (err) {\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:aderror', { detail: { message: String(err) } }));\n if (this.options.fallbackStreamUrl) void this.ctx.loadStreamUrl(this.options.fallbackStreamUrl);\n return;\n }\n this.dai = dai;\n\n this.streamManager = new dai.api.StreamManager(this.ctx.videoEl, this.ctx.adUiEl);\n this.streamManager.addEventListener(\n [\n dai.api.StreamEvent.Type.LOADED,\n dai.api.StreamEvent.Type.ERROR,\n dai.api.StreamEvent.Type.AD_BREAK_STARTED,\n dai.api.StreamEvent.Type.AD_BREAK_ENDED,\n ],\n this.onStreamEvent\n );\n\n const request = new dai.api.LiveStreamRequest();\n request.assetKey = this.options.assetKey;\n if (this.options.apiKey) request.apiKey = this.options.apiKey;\n if (this.options.adTagParameters) request.adTagParameters = this.options.adTagParameters;\n\n this.attachMetadataForwarding();\n this.streamManager.requestStream(request);\n }\n\n destroy(): void {\n this.ctx.videoEl.textTracks.removeEventListener('addtrack', this.onAddTrack);\n for (const [track, listener] of this.metadataTrackListeners) track.removeEventListener('cuechange', listener);\n this.metadataTrackListeners.clear();\n this.streamManager?.reset();\n }\n\n private readonly onStreamEvent = (event: google.ima.dai.api.StreamEvent): void => {\n if (!this.dai) return;\n const Type = this.dai.api.StreamEvent.Type;\n\n switch (event.type) {\n case Type.LOADED: {\n const { url } = event.getStreamData();\n void this.ctx.loadStreamUrl(url).then(() => void this.ctx.videoEl.play().catch(() => {}));\n break;\n }\n case Type.ERROR: {\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:aderror', { detail: { message: 'DAI stream error' } }));\n if (this.options.fallbackStreamUrl) void this.ctx.loadStreamUrl(this.options.fallbackStreamUrl);\n break;\n }\n case Type.AD_BREAK_STARTED:\n this.ctx.disableSeeking();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:adstart', { detail: { type: 'midroll' } }));\n break;\n case Type.AD_BREAK_ENDED:\n this.ctx.enableSeeking();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:adend', { detail: { type: 'midroll' } }));\n break;\n default:\n break;\n }\n };\n\n /** HLS live DAI reklam zamanlaması ID3/timed-metadata ile gelir — StreamManager.processMetadata()'ya iletilir. */\n private attachMetadataForwarding(): void {\n for (let i = 0; i < this.ctx.videoEl.textTracks.length; i++) {\n this.listenMetadataTrack(this.ctx.videoEl.textTracks[i]!);\n }\n this.ctx.videoEl.textTracks.addEventListener('addtrack', this.onAddTrack);\n }\n\n private readonly onAddTrack = (e: TrackEvent): void => {\n if (e.track instanceof TextTrack) this.listenMetadataTrack(e.track);\n };\n\n private listenMetadataTrack(track: TextTrack): void {\n if (track.kind !== 'metadata' || this.metadataTrackListeners.has(track)) return;\n track.mode = 'hidden';\n\n const listener = () => {\n const cues = track.activeCues;\n if (!cues || !this.streamManager) return;\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i] as unknown as { value?: unknown; startTime?: number };\n if (cue.value === undefined) continue;\n try {\n this.streamManager.processMetadata('ID3', cue.value as Uint8Array | string, cue.startTime);\n } catch {\n /* DAI akışla ilgisiz bir metadata cue'su olabilir — yoksay */\n }\n }\n };\n track.addEventListener('cuechange', listener);\n this.metadataTrackListeners.set(track, listener);\n }\n}\n","import { DaiController, type DaiPlayerContext } from './DaiController';\nimport type { DaiOptions } from '../../types';\n\nexport async function installDai(ctx: DaiPlayerContext, options: DaiOptions): Promise<DaiController> {\n const controller = new DaiController(ctx, options);\n await controller.install();\n return controller;\n}\n\nexport { DaiController };\nexport type { DaiPlayerContext };\n"],"names":["DAI_SDK_URL","getLoadedDai","_a","_b","loadPromise","loadDaiSdk","existing","resolve","reject","script","dai","DaiController","ctx","options","__publicField","event","Type","url","e","err","request","track","listener","i","cues","cue","installDai","controller"],"mappings":"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"}
|