@hopeplayer/core 1.5.0 → 1.6.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/dist/HopePlayerElement.d.ts +24 -0
- package/dist/HopePlayerElement.d.ts.map +1 -1
- package/dist/chunks/adTriggers-BIAWe8o4.js +419 -0
- package/dist/chunks/adTriggers-BIAWe8o4.js.map +1 -0
- package/dist/chunks/{ads-C4tDPsUs.js → ads-DlpHPpR9.js} +2 -2
- package/dist/chunks/{ads-C4tDPsUs.js.map → ads-DlpHPpR9.js.map} +1 -1
- package/dist/chunks/{cast-Baxvu76A.js → cast-vHyi7oV_.js} +2 -2
- package/dist/chunks/{cast-Baxvu76A.js.map → cast-vHyi7oV_.js.map} +1 -1
- package/dist/chunks/docPip-wybMVP1H.js +82 -0
- package/dist/chunks/docPip-wybMVP1H.js.map +1 -0
- package/dist/chunks/heatmap-Bb7neaYU.js +92 -0
- package/dist/chunks/heatmap-Bb7neaYU.js.map +1 -0
- package/dist/chunks/{history-CvydU0aN.js → history-CwqLXiZi.js} +2 -2
- package/dist/chunks/{history-CvydU0aN.js.map → history-CwqLXiZi.js.map} +1 -1
- package/dist/chunks/interactive-CgltIneu.js +189 -0
- package/dist/chunks/interactive-CgltIneu.js.map +1 -0
- package/dist/chunks/{loopSection-CvF4l5uf.js → loopSection-Bwk4W8vz.js} +16 -16
- package/dist/chunks/loopSection-Bwk4W8vz.js.map +1 -0
- package/dist/chunks/{markers-Dr4-CCxE.js → markers-L69W3kj6.js} +53 -51
- package/dist/chunks/markers-L69W3kj6.js.map +1 -0
- package/dist/chunks/{player-DV4Hf5Cw.js → player-D2_HRzot.js} +1382 -1158
- package/dist/chunks/player-D2_HRzot.js.map +1 -0
- package/dist/chunks/{playlist-DJsdK6xm.js → playlist-CHfStNbQ.js} +2 -2
- package/dist/chunks/{playlist-DJsdK6xm.js.map → playlist-CHfStNbQ.js.map} +1 -1
- package/dist/chunks/plugin-style-CPJELe-i.js +17 -0
- package/dist/chunks/plugin-style-CPJELe-i.js.map +1 -0
- package/dist/chunks/{pluginHost-GxNfyP5E.js → pluginHost-cN2uGFeG.js} +2 -2
- package/dist/chunks/{pluginHost-GxNfyP5E.js.map → pluginHost-cN2uGFeG.js.map} +1 -1
- package/dist/chunks/redirectScreen-TIqLdvBY.js +239 -0
- package/dist/chunks/redirectScreen-TIqLdvBY.js.map +1 -0
- package/dist/chunks/{rewardedUnlock-jFOdzfSq.js → rewardedUnlock-DUqYwXTr.js} +2 -2
- package/dist/chunks/{rewardedUnlock-jFOdzfSq.js.map → rewardedUnlock-DUqYwXTr.js.map} +1 -1
- package/dist/chunks/segments-Ds-c1b5e.js +66 -0
- package/dist/chunks/segments-Ds-c1b5e.js.map +1 -0
- package/dist/chunks/{skipSegments-vJMhdiJn.js → skipSegments-ByNoF1qZ.js} +2 -2
- package/dist/chunks/{skipSegments-vJMhdiJn.js.map → skipSegments-ByNoF1qZ.js.map} +1 -1
- package/dist/chunks/{spriteThumbnails-BoxVY--_.js → spriteThumbnails-Cr9UmkM9.js} +28 -28
- package/dist/chunks/spriteThumbnails-Cr9UmkM9.js.map +1 -0
- package/dist/chunks/{sticky-D_eLCNFk.js → sticky-BDStzjBM.js} +27 -26
- package/dist/chunks/sticky-BDStzjBM.js.map +1 -0
- package/dist/chunks/{story-BRkhSDhR.js → story-CodA2dfn.js} +2 -2
- package/dist/chunks/{story-BRkhSDhR.js.map → story-CodA2dfn.js.map} +1 -1
- package/dist/chunks/transcript-LG7E9UYE.js +186 -0
- package/dist/chunks/transcript-LG7E9UYE.js.map +1 -0
- package/dist/controls/ContextMenu.d.ts +1 -0
- package/dist/controls/ContextMenu.d.ts.map +1 -1
- package/dist/controls/ControlBar.d.ts +6 -0
- package/dist/controls/ControlBar.d.ts.map +1 -1
- package/dist/controls/SeekBar.d.ts +5 -2
- package/dist/controls/SeekBar.d.ts.map +1 -1
- package/dist/controls/SettingsMenu.d.ts +2 -1
- package/dist/controls/SettingsMenu.d.ts.map +1 -1
- package/dist/hope-player.js +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/types.d.ts +25 -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 +5 -0
- package/dist/plugins/ad-triggers/AdTriggers.d.ts.map +1 -1
- package/dist/plugins/doc-pip/DocumentPip.d.ts +44 -0
- package/dist/plugins/doc-pip/DocumentPip.d.ts.map +1 -0
- package/dist/plugins/doc-pip/index.d.ts +5 -0
- package/dist/plugins/doc-pip/index.d.ts.map +1 -0
- package/dist/plugins/heatmap/Heatmap.d.ts +36 -0
- package/dist/plugins/heatmap/Heatmap.d.ts.map +1 -0
- package/dist/plugins/heatmap/index.d.ts +6 -0
- package/dist/plugins/heatmap/index.d.ts.map +1 -0
- package/dist/plugins/interactive/Interactive.d.ts +45 -0
- package/dist/plugins/interactive/Interactive.d.ts.map +1 -0
- package/dist/plugins/interactive/index.d.ts +6 -0
- package/dist/plugins/interactive/index.d.ts.map +1 -0
- package/dist/plugins/markers/MarkProgress.d.ts +3 -1
- package/dist/plugins/markers/MarkProgress.d.ts.map +1 -1
- package/dist/plugins/redirect-screen/RedirectScreen.d.ts +3 -1
- package/dist/plugins/redirect-screen/RedirectScreen.d.ts.map +1 -1
- package/dist/plugins/segments/Segments.d.ts +1 -0
- package/dist/plugins/segments/Segments.d.ts.map +1 -1
- package/dist/plugins/sprite-thumbnails/SpriteThumbnails.d.ts +1 -0
- package/dist/plugins/sprite-thumbnails/SpriteThumbnails.d.ts.map +1 -1
- package/dist/plugins/sticky/StickyManager.d.ts +2 -0
- package/dist/plugins/sticky/StickyManager.d.ts.map +1 -1
- package/dist/plugins/transcript/Transcript.d.ts +65 -0
- package/dist/plugins/transcript/Transcript.d.ts.map +1 -0
- package/dist/plugins/transcript/index.d.ts +6 -0
- package/dist/plugins/transcript/index.d.ts.map +1 -0
- package/dist/subtitles/attachTracks.d.ts +6 -0
- package/dist/subtitles/attachTracks.d.ts.map +1 -1
- package/dist/types/index.d.ts +164 -12
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/plugin-style.d.ts +5 -0
- package/dist/utils/plugin-style.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/chunks/adTriggers-DXmtF4t2.js +0 -410
- package/dist/chunks/adTriggers-DXmtF4t2.js.map +0 -1
- package/dist/chunks/loopSection-CvF4l5uf.js.map +0 -1
- package/dist/chunks/markers-Dr4-CCxE.js.map +0 -1
- package/dist/chunks/player-DV4Hf5Cw.js.map +0 -1
- package/dist/chunks/redirectScreen-BT_26-5g.js +0 -208
- package/dist/chunks/redirectScreen-BT_26-5g.js.map +0 -1
- package/dist/chunks/segments--hl_QVrI.js +0 -63
- package/dist/chunks/segments--hl_QVrI.js.map +0 -1
- package/dist/chunks/spriteThumbnails-BoxVY--_.js.map +0 -1
- package/dist/chunks/sticky-D_eLCNFk.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cast-Baxvu76A.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';\nimport { seekWhenReady } from '../shared/seekWhenReady';\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 // Sıra önemli: önce oynat, SONRA sar. WebKitGTK / WPE (GStreamer) duraklatılmışken yapılan sarmayı play()'de\n // kaybediyor (sona fırlıyor ya da takılıyor); oynarken yapılan sarma her motorda tutuyor.\n const seekTo = Number.isFinite(currentTime) && currentTime > 0 && !ended ? currentTime : null;\n const seek = () => {\n if (seekTo !== null) seekWhenReady(v, seekTo, { guardMs: 2000 });\n };\n if (!paused && !ended) void v.play().then(seek, seek);\n else seek();\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","seekTo","seek","seekWhenReady","on","remote","text","el","ad","_e","installCast"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cast-vHyi7oV_.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';\nimport { seekWhenReady } from '../shared/seekWhenReady';\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 // Sıra önemli: önce oynat, SONRA sar. WebKitGTK / WPE (GStreamer) duraklatılmışken yapılan sarmayı play()'de\n // kaybediyor (sona fırlıyor ya da takılıyor); oynarken yapılan sarma her motorda tutuyor.\n const seekTo = Number.isFinite(currentTime) && currentTime > 0 && !ended ? currentTime : null;\n const seek = () => {\n if (seekTo !== null) seekWhenReady(v, seekTo, { guardMs: 2000 });\n };\n if (!paused && !ended) void v.play().then(seek, seek);\n else seek();\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","seekTo","seek","seekWhenReady","on","remote","text","el","ad","_e","installCast"],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var w = Object.defineProperty;
|
|
2
|
+
var v = (s, t, e) => t in s ? w(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
|
|
3
|
+
var d = (s, t, e) => v(s, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { c as E } from "./player-D2_HRzot.js";
|
|
5
|
+
import { a as k, c as b } from "./plugin-style-CPJELe-i.js";
|
|
6
|
+
const C = ":host(.hp-docpip){display:block;width:100%;height:100%}:host(.hp-docpip) .hp-root{height:100%}:host(.hp-docpip) .video-area{width:100%;height:100%;aspect-ratio:auto;border-radius:0;background:#000}.hp-docpip-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;width:100%;box-sizing:border-box;padding:16px;border-radius:var(--hp-radius);background:#0b0b0f;color:#fff;font:500 14px/1.4 system-ui,-apple-system,sans-serif;text-align:center}.hp-docpip-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border:0;border-radius:999px;background:#ffffff24;color:#fff;font:600 13px/1 system-ui,-apple-system,sans-serif;cursor:pointer}.hp-docpip-btn:hover{background:#ffffff3d}.hp-docpip-btn:focus-visible{outline:2px solid var(--hp-color-accent, #fff);outline-offset:2px}";
|
|
7
|
+
function A() {
|
|
8
|
+
return window.documentPictureInPicture ?? null;
|
|
9
|
+
}
|
|
10
|
+
class P {
|
|
11
|
+
constructor(t) {
|
|
12
|
+
d(this, "win", null);
|
|
13
|
+
d(this, "placeholder", null);
|
|
14
|
+
d(this, "pipRoot", null);
|
|
15
|
+
d(this, "restore", () => {
|
|
16
|
+
const t = this.placeholder;
|
|
17
|
+
if (!t) return;
|
|
18
|
+
const { videoArea: e } = this.ctx;
|
|
19
|
+
e.removeAttribute("data-docpip"), this.pipRoot && b(this.pipRoot, this.ctx.hostEl.shadowRoot), this.pipRoot = null, t.replaceWith(e), this.placeholder = null, this.win = null, this.ctx.onChange(!1, null);
|
|
20
|
+
});
|
|
21
|
+
this.ctx = t, k(t.rootEl, "doc-pip", C);
|
|
22
|
+
}
|
|
23
|
+
get active() {
|
|
24
|
+
return this.win !== null;
|
|
25
|
+
}
|
|
26
|
+
async open(t) {
|
|
27
|
+
const e = A();
|
|
28
|
+
if (!e || this.win) return !1;
|
|
29
|
+
const n = this.ctx.videoArea.getBoundingClientRect(), c = n.width > 0 && n.height > 0 ? n.height / n.width : 9 / 16, l = Math.round(t.width ?? Math.min(Math.max(n.width, 320), 640)), h = Math.round(t.height ?? l * c), u = await e.requestWindow({ width: l, height: h });
|
|
30
|
+
return this.mount(u), !0;
|
|
31
|
+
}
|
|
32
|
+
close() {
|
|
33
|
+
var t;
|
|
34
|
+
(t = this.win) == null || t.close();
|
|
35
|
+
}
|
|
36
|
+
destroy() {
|
|
37
|
+
if (this.win) {
|
|
38
|
+
const t = this.win;
|
|
39
|
+
this.restore(), t.close();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
mount(t) {
|
|
43
|
+
const e = t.document, { hostEl: n, videoArea: c, rootEl: l } = this.ctx;
|
|
44
|
+
e.title = document.title;
|
|
45
|
+
const h = e.createElement("style");
|
|
46
|
+
h.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}", e.head.appendChild(h);
|
|
47
|
+
const u = document.getElementById("hope-player-icon-font");
|
|
48
|
+
u && e.head.appendChild(u.cloneNode(!0));
|
|
49
|
+
const a = e.createElement("div");
|
|
50
|
+
a.className = "hp-docpip";
|
|
51
|
+
for (const { name: o, value: i } of Array.from(n.attributes)) o.startsWith("data-") && a.setAttribute(o, i);
|
|
52
|
+
const f = getComputedStyle(n);
|
|
53
|
+
for (let o = 0; o < f.length; o++) {
|
|
54
|
+
const i = f[o];
|
|
55
|
+
i.startsWith("--hp-") && a.style.setProperty(i, f.getPropertyValue(i));
|
|
56
|
+
}
|
|
57
|
+
a.style.fontFamily = f.fontFamily;
|
|
58
|
+
const m = a.attachShadow({ mode: "open" }), y = e.createElement("style");
|
|
59
|
+
y.textContent = this.ctx.css;
|
|
60
|
+
const x = e.createElement("div");
|
|
61
|
+
x.className = "hp-root", m.append(y, x), b(n.shadowRoot, m), this.pipRoot = m, e.body.appendChild(a);
|
|
62
|
+
const r = document.createElement("div");
|
|
63
|
+
r.className = "hp-docpip-placeholder", r.setAttribute("part", "pip-placeholder");
|
|
64
|
+
const g = document.createElement("span");
|
|
65
|
+
g.textContent = this.ctx.i18n.pipPlaying;
|
|
66
|
+
const p = document.createElement("button");
|
|
67
|
+
p.type = "button", p.className = "hp-docpip-btn", p.append(E("pip"), document.createTextNode(this.ctx.i18n.pipBack)), p.addEventListener("click", () => this.close()), r.append(g, p), r.style.aspectRatio = `${Math.max(1, c.offsetWidth)} / ${Math.max(1, c.offsetHeight)}`, l.insertBefore(r, c), x.appendChild(c), c.setAttribute("data-docpip", ""), this.placeholder = r, this.win = t, e.addEventListener("keydown", (o) => {
|
|
68
|
+
if (o.defaultPrevented) return;
|
|
69
|
+
const i = o.composedPath()[0];
|
|
70
|
+
i instanceof Element && i.closest("input, textarea, select") || (o.key === " " || o.key === "Enter") && i instanceof Element && i.closest("button") || this.ctx.forwardKey(o) && o.preventDefault();
|
|
71
|
+
}), t.addEventListener("pagehide", this.restore, { once: !0 }), this.ctx.onChange(!0, t);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function W(s) {
|
|
75
|
+
return new P(s);
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
P as DocumentPip,
|
|
79
|
+
A as documentPipApi,
|
|
80
|
+
W as installDocumentPip
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=docPip-wybMVP1H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docPip-wybMVP1H.js","sources":["../../src/plugins/doc-pip/DocumentPip.ts","../../src/plugins/doc-pip/index.ts"],"sourcesContent":["import type { DocumentPipOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { createIcon } from '../../icons/Icon';\nimport { adoptStyle, copyAdoptedStyles } from '../../utils/plugin-style';\nimport css from './doc-pip.css?inline';\n\nexport interface DocumentPipContext {\n hostEl: HTMLElement;\n /** Taşınan katman: video + kontroller + reklam + eklentiler. */\n videoArea: HTMLElement;\n /** videoArea'nın shadow içindeki kabı (.hp-root) — yer tutucu buraya girer. */\n rootEl: HTMLElement;\n css: string;\n i18n: HopeLocaleStrings;\n /** Pencere açıldı / kapandı. */\n onChange(active: boolean, win: Window | null): void;\n /** PiP penceresindeki tuşu player'a ilet; işlendiyse true. */\n forwardKey(e: KeyboardEvent): boolean;\n}\n\ninterface DocPipApi {\n requestWindow(options?: { width?: number; height?: number; disallowReturnToOpener?: boolean }): Promise<Window>;\n window: Window | null;\n}\n\nexport function documentPipApi(): DocPipApi | null {\n return (window as unknown as { documentPictureInPicture?: DocPipApi }).documentPictureInPicture ?? null;\n}\n\n/**\n * Document Picture-in-Picture (Chrome / Edge 116+): oynatıcının video alanı — kontroller, altyazı, menüler, reklam\n * katmanı ve eklentiler — her zaman üstte duran ayrı bir pencereye taşınır. Pencere kapanınca (X, \"geri al\",\n * sayfadan ayrılma) yerine döner. Video elementi aynı kalır: oynatma, tampon ve reklam durumu kesilmez.\n */\nexport class DocumentPip {\n private win: Window | null = null;\n private placeholder: HTMLElement | null = null;\n\n private pipRoot: ShadowRoot | null = null;\n\n constructor(private readonly ctx: DocumentPipContext) {\n adoptStyle(ctx.rootEl, 'doc-pip', css);\n }\n\n get active(): boolean {\n return this.win !== null;\n }\n\n async open(options: DocumentPipOptions): Promise<boolean> {\n const api = documentPipApi();\n if (!api || this.win) return false;\n const rect = this.ctx.videoArea.getBoundingClientRect();\n const ratio = rect.width > 0 && rect.height > 0 ? rect.height / rect.width : 9 / 16;\n const width = Math.round(options.width ?? Math.min(Math.max(rect.width, 320), 640));\n const height = Math.round(options.height ?? width * ratio);\n const win = await api.requestWindow({ width, height });\n this.mount(win);\n return true;\n }\n\n close(): void {\n this.win?.close();\n }\n\n destroy(): void {\n if (this.win) {\n const win = this.win;\n this.restore();\n win.close();\n }\n }\n\n private mount(win: Window): void {\n const doc = win.document;\n const { hostEl, videoArea, rootEl } = this.ctx;\n doc.title = document.title;\n const base = doc.createElement('style');\n base.textContent = 'html,body{margin:0;height:100%;background:#000;overflow:hidden}';\n doc.head.appendChild(base);\n // İkon fontu belge başına enjekte edilir (Shadow DOM'da @font-face çalışmıyor).\n const iconFont = document.getElementById('hope-player-icon-font');\n if (iconFont) doc.head.appendChild(iconFont.cloneNode(true));\n\n const host = doc.createElement('div');\n host.className = 'hp-docpip';\n // Tema ve sayfadan gelen token'lar (`hope-player { --hp-color-accent: … }`) pencereye de geçsin.\n for (const { name, value } of Array.from(hostEl.attributes)) if (name.startsWith('data-')) host.setAttribute(name, value);\n const computed = getComputedStyle(hostEl);\n for (let i = 0; i < computed.length; i++) {\n const prop = computed[i]!;\n if (prop.startsWith('--hp-')) host.style.setProperty(prop, computed.getPropertyValue(prop));\n }\n host.style.fontFamily = computed.fontFamily;\n const shadow = host.attachShadow({ mode: 'open' });\n const style = doc.createElement('style');\n style.textContent = this.ctx.css;\n const wrap = doc.createElement('div');\n wrap.className = 'hp-root';\n shadow.append(style, wrap);\n // Eklentilerin sonradan eklenen stilleri (transkript, etkileşimli…) pencereye de.\n copyAdoptedStyles(hostEl.shadowRoot!, shadow);\n this.pipRoot = shadow;\n doc.body.appendChild(host);\n\n const placeholder = document.createElement('div');\n placeholder.className = 'hp-docpip-placeholder';\n placeholder.setAttribute('part', 'pip-placeholder');\n const text = document.createElement('span');\n text.textContent = this.ctx.i18n.pipPlaying;\n const back = document.createElement('button');\n back.type = 'button';\n back.className = 'hp-docpip-btn';\n back.append(createIcon('pip'), document.createTextNode(this.ctx.i18n.pipBack));\n back.addEventListener('click', () => this.close());\n placeholder.append(text, back);\n // Yer tutucu oynatıcının boyutunu korur — sayfa düzeni kaymasın.\n placeholder.style.aspectRatio = `${Math.max(1, videoArea.offsetWidth)} / ${Math.max(1, videoArea.offsetHeight)}`;\n\n // Taşıma tek adımda (appendChild) — video oynamaya devam eder.\n rootEl.insertBefore(placeholder, videoArea);\n wrap.appendChild(videoArea);\n videoArea.setAttribute('data-docpip', '');\n this.placeholder = placeholder;\n this.win = win;\n\n doc.addEventListener('keydown', (e) => {\n if (e.defaultPrevented) return;\n const t = e.composedPath()[0];\n // Odaktaki buton / alan tuşu kendisi işlesin.\n if (t instanceof Element && t.closest('input, textarea, select')) return;\n if ((e.key === ' ' || e.key === 'Enter') && t instanceof Element && t.closest('button')) return;\n if (this.ctx.forwardKey(e)) e.preventDefault();\n });\n win.addEventListener('pagehide', this.restore, { once: true });\n this.ctx.onChange(true, win);\n }\n\n private readonly restore = (): void => {\n const placeholder = this.placeholder;\n if (!placeholder) return;\n const { videoArea } = this.ctx;\n videoArea.removeAttribute('data-docpip');\n // Pencere açıkken kurulan eklentilerin stilleri sayfaya dönsün.\n if (this.pipRoot) copyAdoptedStyles(this.pipRoot, this.ctx.hostEl.shadowRoot!);\n this.pipRoot = null;\n placeholder.replaceWith(videoArea);\n this.placeholder = null;\n this.win = null;\n this.ctx.onChange(false, null);\n };\n}\n","import { DocumentPip, documentPipApi, type DocumentPipContext } from './DocumentPip';\n\nexport function installDocumentPip(ctx: DocumentPipContext): DocumentPip {\n return new DocumentPip(ctx);\n}\n\nexport { DocumentPip, documentPipApi };\nexport type { DocumentPipContext };\n"],"names":["documentPipApi","DocumentPip","ctx","__publicField","placeholder","videoArea","copyAdoptedStyles","adoptStyle","css","options","api","rect","ratio","width","height","win","_a","doc","hostEl","rootEl","base","iconFont","host","name","value","computed","i","prop","shadow","style","wrap","text","back","createIcon","e","t","installDocumentPip"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var E = (s, t, e) => t in s ? b(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
|
|
3
|
+
var r = (s, t, e) => E(s, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { a as g } from "./plugin-style-CPJELe-i.js";
|
|
5
|
+
const L = ".hp-heatmap{position:absolute;left:0;right:0;bottom:50%;height:var(--hp-heatmap-h, 36px);pointer-events:none;opacity:0;transition:opacity .2s ease}.hp-heatmap[hidden]{display:none}.hp-heatmap[data-show=always],.hp-seekbar:hover .hp-heatmap,.hp-seekbar:focus-visible .hp-heatmap{opacity:1}.hp-heatmap-base,.hp-heatmap-played{position:absolute;top:0;right:0;bottom:0;left:0}.hp-heatmap svg{display:block;filter:drop-shadow(0 0 1.5px rgba(0,0,0,.25));width:100%;height:100%}.hp-heatmap-base path{fill:color-mix(in srgb,var(--hp-color-on-surface) 28%,transparent)}.hp-heatmap-played{clip-path:inset(0 calc(100% - var(--hp-heatmap-p, 0%)) 0 0)}.hp-heatmap-played path{fill:color-mix(in srgb,var(--hp-color-accent, #fff) 60%,transparent)}", m = "http://www.w3.org/2000/svg", d = 1e3, p = 100;
|
|
6
|
+
function w(s) {
|
|
7
|
+
const t = s.map((a) => Number.isFinite(a) && a > 0 ? a : 0), e = Math.max(0, ...t);
|
|
8
|
+
return e > 0 ? t.map((a) => a / e) : t;
|
|
9
|
+
}
|
|
10
|
+
function A(s) {
|
|
11
|
+
const t = s.length;
|
|
12
|
+
if (!t) return "";
|
|
13
|
+
const e = s.map((i, o) => [(o + 0.5) / t * d, p - i * p * 0.92]);
|
|
14
|
+
e.unshift([0, e[0][1]]), e.push([d, e[e.length - 1][1]]);
|
|
15
|
+
let a = `M0 ${p}L${e[0][0]} ${e[0][1].toFixed(1)}`;
|
|
16
|
+
for (let i = 0; i < e.length - 1; i++) {
|
|
17
|
+
const o = e[i - 1] ?? e[i], n = e[i], h = e[i + 1], l = e[i + 2] ?? h, u = Math.min(p, Math.max(0, n[1] + (h[1] - o[1]) / 6)), v = Math.min(p, Math.max(0, h[1] - (l[1] - n[1]) / 6)), f = n[0] + (h[0] - o[0]) / 6, y = h[0] - (l[0] - n[0]) / 6;
|
|
18
|
+
a += `C${f.toFixed(1)} ${u.toFixed(1)} ${y.toFixed(1)} ${v.toFixed(1)} ${h[0].toFixed(1)} ${h[1].toFixed(1)}`;
|
|
19
|
+
}
|
|
20
|
+
return `${a}L${d} ${p}Z`;
|
|
21
|
+
}
|
|
22
|
+
function c(s) {
|
|
23
|
+
const t = document.createElement("div");
|
|
24
|
+
t.className = s;
|
|
25
|
+
const e = document.createElementNS(m, "svg");
|
|
26
|
+
e.setAttribute("viewBox", `0 0 ${d} ${p}`), e.setAttribute("preserveAspectRatio", "none"), e.setAttribute("aria-hidden", "true");
|
|
27
|
+
const a = document.createElementNS(m, "path");
|
|
28
|
+
return e.appendChild(a), t.appendChild(e), { el: t, path: a };
|
|
29
|
+
}
|
|
30
|
+
class x {
|
|
31
|
+
constructor(t, e) {
|
|
32
|
+
r(this, "el");
|
|
33
|
+
r(this, "base");
|
|
34
|
+
r(this, "played");
|
|
35
|
+
r(this, "destroyed", !1);
|
|
36
|
+
r(this, "rafId", null);
|
|
37
|
+
r(this, "startLoop", () => {
|
|
38
|
+
if (this.rafId !== null) return;
|
|
39
|
+
const t = () => {
|
|
40
|
+
this.onTime(), this.rafId = requestAnimationFrame(t);
|
|
41
|
+
};
|
|
42
|
+
this.rafId = requestAnimationFrame(t);
|
|
43
|
+
});
|
|
44
|
+
r(this, "stopLoop", () => {
|
|
45
|
+
this.rafId !== null && cancelAnimationFrame(this.rafId), this.rafId = null, this.onTime();
|
|
46
|
+
});
|
|
47
|
+
r(this, "onDuration", () => {
|
|
48
|
+
const t = this.ctx.videoEl.duration;
|
|
49
|
+
this.el.hidden = !Number.isFinite(t) || t <= 0 || this.el.hasAttribute("data-empty") || !this.base.getAttribute("d"), this.onTime();
|
|
50
|
+
});
|
|
51
|
+
r(this, "onTime", () => {
|
|
52
|
+
const t = this.ctx.videoEl, e = Number.isFinite(t.duration) && t.duration > 0 ? Math.min(1, Math.max(0, t.currentTime / t.duration)) : 0;
|
|
53
|
+
this.el.hidden || this.el.style.setProperty("--hp-heatmap-p", `${(e * 100).toFixed(3)}%`);
|
|
54
|
+
});
|
|
55
|
+
var n;
|
|
56
|
+
this.ctx = t, this.options = e, g(t.seekBar.el, "heatmap", L);
|
|
57
|
+
const a = document.createElement("div");
|
|
58
|
+
a.className = "hp-heatmap", a.setAttribute("part", "heatmap"), a.setAttribute("aria-hidden", "true"), a.setAttribute("data-show", e.show === "always" ? "always" : "hover"), e.height && a.style.setProperty("--hp-heatmap-h", `${Math.max(8, e.height)}px`);
|
|
59
|
+
const i = c("hp-heatmap-base"), o = c("hp-heatmap-played");
|
|
60
|
+
a.append(i.el, o.el), this.el = a, this.base = i.path, this.played = o.path, a.hidden = !0, t.seekBar.el.prepend(a), t.videoEl.addEventListener("timeupdate", this.onTime), t.videoEl.addEventListener("seeking", this.onTime), t.videoEl.addEventListener("play", this.startLoop), t.videoEl.addEventListener("pause", this.stopLoop), t.videoEl.addEventListener("ended", this.stopLoop), t.videoEl.paused || this.startLoop(), t.videoEl.addEventListener("durationchange", this.onDuration), t.videoEl.addEventListener("loadedmetadata", this.onDuration), (n = e.data) != null && n.length ? this.setData(e.data) : e.src && this.fetchData(e.src);
|
|
61
|
+
}
|
|
62
|
+
/** Yeni değerler (ör. sunucudan güncel istatistik). */
|
|
63
|
+
setData(t) {
|
|
64
|
+
const e = A(w(t));
|
|
65
|
+
this.base.setAttribute("d", e), this.played.setAttribute("d", e), this.el.toggleAttribute("data-empty", !e), this.onDuration();
|
|
66
|
+
}
|
|
67
|
+
destroy() {
|
|
68
|
+
this.destroyed = !0;
|
|
69
|
+
const t = this.ctx.videoEl;
|
|
70
|
+
t.removeEventListener("timeupdate", this.onTime), t.removeEventListener("seeking", this.onTime), t.removeEventListener("durationchange", this.onDuration), t.removeEventListener("loadedmetadata", this.onDuration), t.removeEventListener("play", this.startLoop), t.removeEventListener("pause", this.stopLoop), t.removeEventListener("ended", this.stopLoop), this.stopLoop(), this.el.remove();
|
|
71
|
+
}
|
|
72
|
+
async fetchData(t) {
|
|
73
|
+
var e, a;
|
|
74
|
+
try {
|
|
75
|
+
const i = await fetch(t);
|
|
76
|
+
if (!i.ok) throw new Error(`HTTP ${i.status}`);
|
|
77
|
+
const o = await i.json(), n = Array.isArray(o) ? o : o == null ? void 0 : o.data;
|
|
78
|
+
if (!Array.isArray(n)) throw new Error("number[] bekleniyordu");
|
|
79
|
+
this.destroyed || this.setData(n.map(Number));
|
|
80
|
+
} catch (i) {
|
|
81
|
+
(a = (e = this.ctx).log) == null || a.call(e, { message: `Heatmap data could not be loaded: ${String(i)}`, details: { src: t } });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function D(s, t) {
|
|
86
|
+
return new x(s, t);
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
x as Heatmap,
|
|
90
|
+
D as installHeatmap
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=heatmap-Bb7neaYU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heatmap-Bb7neaYU.js","sources":["../../src/plugins/heatmap/Heatmap.ts","../../src/plugins/heatmap/index.ts"],"sourcesContent":["import type { HeatmapOptions } from '../../types';\nimport { adoptStyle } from '../../utils/plugin-style';\nimport css from './heatmap.css?inline';\n\nexport interface HeatmapPlayerContext {\n videoEl: HTMLVideoElement;\n seekBar: { readonly el: HTMLElement };\n log?: (entry: { message: string; details?: Record<string, string> }) => void;\n}\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst W = 1000;\nconst H = 100;\n\n/** Değerleri 0–1'e indirger (en yüksek = 1); geçersizler 0. */\nfunction normalize(values: number[]): number[] {\n const clean = values.map((v) => (Number.isFinite(v) && v > 0 ? v : 0));\n const max = Math.max(0, ...clean);\n return max > 0 ? clean.map((v) => v / max) : clean;\n}\n\n/** Noktalardan yumuşak (Catmull-Rom → Bezier) kapalı alan yolu; tabanı seek bar çizgisi. */\nexport function heatmapPath(values: number[]): string {\n const n = values.length;\n if (!n) return '';\n const pts: [number, number][] = values.map((v, i) => [((i + 0.5) / n) * W, H - v * H * 0.92]);\n pts.unshift([0, pts[0]![1]]);\n pts.push([W, pts[pts.length - 1]![1]]);\n let d = `M0 ${H}L${pts[0]![0]} ${pts[0]![1].toFixed(1)}`;\n for (let i = 0; i < pts.length - 1; i++) {\n const p0 = pts[i - 1] ?? pts[i]!;\n const p1 = pts[i]!;\n const p2 = pts[i + 1]!;\n const p3 = pts[i + 2] ?? p2;\n // Kontrol noktaları tabanın altına / tepenin üstüne taşmasın.\n const c1y = Math.min(H, Math.max(0, p1[1] + (p2[1] - p0[1]) / 6));\n const c2y = Math.min(H, Math.max(0, p2[1] - (p3[1] - p1[1]) / 6));\n const c1x = p1[0] + (p2[0] - p0[0]) / 6;\n const c2x = p2[0] - (p3[0] - p1[0]) / 6;\n d += `C${c1x.toFixed(1)} ${c1y.toFixed(1)} ${c2x.toFixed(1)} ${c2y.toFixed(1)} ${p2[0].toFixed(1)} ${p2[1].toFixed(1)}`;\n }\n return `${d}L${W} ${H}Z`;\n}\n\nfunction layer(className: string): { el: HTMLDivElement; path: SVGPathElement } {\n const el = document.createElement('div');\n el.className = className;\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('viewBox', `0 0 ${W} ${H}`);\n svg.setAttribute('preserveAspectRatio', 'none');\n svg.setAttribute('aria-hidden', 'true');\n const path = document.createElementNS(SVG_NS, 'path');\n svg.appendChild(path);\n el.appendChild(svg);\n return { el, path };\n}\n\n/**\n * \"En çok izlenen\" ısı haritası: seek bar'ın hemen üstünde yoğunluk eğrisi. Değerler videoya eşit aralıklarla\n * yayılır; izlenen kısım vurgu rengiyle dolar. Canlı yayında (süre bilinmiyorsa) gizlenir.\n */\nexport class Heatmap {\n private readonly el: HTMLDivElement;\n private readonly base: SVGPathElement;\n private readonly played: SVGPathElement;\n private destroyed = false;\n\n constructor(\n private readonly ctx: HeatmapPlayerContext,\n private readonly options: HeatmapOptions\n ) {\n adoptStyle(ctx.seekBar.el, 'heatmap', css);\n const el = document.createElement('div');\n el.className = 'hp-heatmap';\n el.setAttribute('part', 'heatmap');\n el.setAttribute('aria-hidden', 'true');\n el.setAttribute('data-show', options.show === 'always' ? 'always' : 'hover');\n if (options.height) el.style.setProperty('--hp-heatmap-h', `${Math.max(8, options.height)}px`);\n const base = layer('hp-heatmap-base');\n const played = layer('hp-heatmap-played');\n el.append(base.el, played.el);\n this.el = el;\n this.base = base.path;\n this.played = played.path;\n el.hidden = true;\n ctx.seekBar.el.prepend(el);\n\n ctx.videoEl.addEventListener('timeupdate', this.onTime);\n ctx.videoEl.addEventListener('seeking', this.onTime);\n // Oynarken her karede güncellenir — seek bar'daki ilerleme gibi akıcı.\n ctx.videoEl.addEventListener('play', this.startLoop);\n ctx.videoEl.addEventListener('pause', this.stopLoop);\n ctx.videoEl.addEventListener('ended', this.stopLoop);\n if (!ctx.videoEl.paused) this.startLoop();\n ctx.videoEl.addEventListener('durationchange', this.onDuration);\n ctx.videoEl.addEventListener('loadedmetadata', this.onDuration);\n\n if (options.data?.length) this.setData(options.data);\n else if (options.src) void this.fetchData(options.src);\n }\n\n /** Yeni değerler (ör. sunucudan güncel istatistik). */\n setData(values: number[]): void {\n const d = heatmapPath(normalize(values));\n this.base.setAttribute('d', d);\n this.played.setAttribute('d', d);\n this.el.toggleAttribute('data-empty', !d);\n this.onDuration();\n }\n\n destroy(): void {\n this.destroyed = true;\n const v = this.ctx.videoEl;\n v.removeEventListener('timeupdate', this.onTime);\n v.removeEventListener('seeking', this.onTime);\n v.removeEventListener('durationchange', this.onDuration);\n v.removeEventListener('loadedmetadata', this.onDuration);\n v.removeEventListener('play', this.startLoop);\n v.removeEventListener('pause', this.stopLoop);\n v.removeEventListener('ended', this.stopLoop);\n this.stopLoop();\n this.el.remove();\n }\n\n private rafId: number | null = null;\n\n private readonly startLoop = (): void => {\n if (this.rafId !== null) return;\n const tick = (): void => {\n this.onTime();\n this.rafId = requestAnimationFrame(tick);\n };\n this.rafId = requestAnimationFrame(tick);\n };\n\n private readonly stopLoop = (): void => {\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.rafId = null;\n this.onTime();\n };\n\n private async fetchData(src: string): Promise<void> {\n try {\n const res = await fetch(src);\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const json: unknown = await res.json();\n const values = Array.isArray(json) ? json : (json as { data?: unknown })?.data;\n if (!Array.isArray(values)) throw new Error('number[] bekleniyordu');\n if (!this.destroyed) this.setData(values.map(Number));\n } catch (err) {\n this.ctx.log?.({ message: `Heatmap data could not be loaded: ${String(err)}`, details: { src } });\n }\n }\n\n private readonly onDuration = (): void => {\n const d = this.ctx.videoEl.duration;\n this.el.hidden = !Number.isFinite(d) || d <= 0 || this.el.hasAttribute('data-empty') || !this.base.getAttribute('d');\n this.onTime();\n };\n\n private readonly onTime = (): void => {\n const v = this.ctx.videoEl;\n const ratio = Number.isFinite(v.duration) && v.duration > 0 ? Math.min(1, Math.max(0, v.currentTime / v.duration)) : 0;\n // Gizliyken (canlı yayın / veri yok) stil yazma.\n if (this.el.hidden) return;\n this.el.style.setProperty('--hp-heatmap-p', `${(ratio * 100).toFixed(3)}%`);\n };\n}\n","import { Heatmap, type HeatmapPlayerContext } from './Heatmap';\nimport type { HeatmapOptions } from '../../types';\n\nexport function installHeatmap(ctx: HeatmapPlayerContext, options: HeatmapOptions): Heatmap {\n return new Heatmap(ctx, options);\n}\n\nexport { Heatmap };\nexport type { HeatmapPlayerContext };\n"],"names":["SVG_NS","W","H","normalize","values","clean","v","max","heatmapPath","n","pts","i","d","p0","p1","p2","p3","c1y","c2y","c1x","c2x","layer","className","el","svg","path","Heatmap","ctx","options","__publicField","tick","ratio","adoptStyle","css","base","played","_a","src","res","json","err","_b","installHeatmap"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var m = Object.defineProperty;
|
|
2
2
|
var v = (n, t, e) => t in n ? m(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
|
|
3
3
|
var s = (n, t, e) => v(n, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
-
import { f as E } from "./player-
|
|
4
|
+
import { f as E } from "./player-D2_HRzot.js";
|
|
5
5
|
import { s as p } from "./seekWhenReady-Clzne3-S.js";
|
|
6
6
|
const d = "hp-history-positions", c = "hp-history-volume", y = 10, f = 15, L = 50, k = 30, T = 5e3, N = 6e3;
|
|
7
7
|
class x {
|
|
@@ -141,4 +141,4 @@ export {
|
|
|
141
141
|
x as PlaybackHistory,
|
|
142
142
|
w as installHistory
|
|
143
143
|
};
|
|
144
|
-
//# sourceMappingURL=history-
|
|
144
|
+
//# sourceMappingURL=history-CwqLXiZi.js.map
|