@hopeplayer/core 1.4.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 +42 -2
- package/dist/HopePlayerElement.d.ts.map +1 -1
- package/dist/chunks/NativeEme-CXosVcw8.js +80 -0
- package/dist/chunks/NativeEme-CXosVcw8.js.map +1 -0
- package/dist/chunks/{accessibility-DeUIoAda.js → accessibility-DFx4CE0H.js} +9 -8
- package/dist/chunks/{accessibility-DeUIoAda.js.map → accessibility-DFx4CE0H.js.map} +1 -1
- package/dist/chunks/adTriggers-BIAWe8o4.js +419 -0
- package/dist/chunks/adTriggers-BIAWe8o4.js.map +1 -0
- package/dist/chunks/{ads-CdWbE9aD.js → ads-DlpHPpR9.js} +3 -3
- package/dist/chunks/ads-DlpHPpR9.js.map +1 -0
- package/dist/chunks/analytics-DEjTAJO9.js +281 -0
- package/dist/chunks/analytics-DEjTAJO9.js.map +1 -0
- package/dist/chunks/{cast-BQ-suTcF.js → cast-vHyi7oV_.js} +2 -2
- package/dist/chunks/{cast-BQ-suTcF.js.map → cast-vHyi7oV_.js.map} +1 -1
- package/dist/chunks/dash-CWjy-y7B.js +22 -0
- package/dist/chunks/dash-CWjy-y7B.js.map +1 -0
- package/dist/chunks/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-DAbqEhNB.js → history-CwqLXiZi.js} +2 -2
- package/dist/chunks/{history-DAbqEhNB.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/keySystems-CNzjRq6e.js +70 -0
- package/dist/chunks/keySystems-CNzjRq6e.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-B04NMI79.js → markers-L69W3kj6.js} +53 -51
- package/dist/chunks/markers-L69W3kj6.js.map +1 -0
- package/dist/chunks/player-D2_HRzot.js +4351 -0
- package/dist/chunks/player-D2_HRzot.js.map +1 -0
- package/dist/chunks/{playlist-C6Mh9BE8.js → playlist-CHfStNbQ.js} +29 -21
- package/dist/chunks/playlist-CHfStNbQ.js.map +1 -0
- 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-cN2uGFeG.js +566 -0
- package/dist/chunks/pluginHost-cN2uGFeG.js.map +1 -0
- package/dist/chunks/redirectScreen-TIqLdvBY.js +239 -0
- package/dist/chunks/redirectScreen-TIqLdvBY.js.map +1 -0
- package/dist/chunks/{rewardedUnlock-CGhQyWOk.js → rewardedUnlock-DUqYwXTr.js} +2 -2
- package/dist/chunks/{rewardedUnlock-CGhQyWOk.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-BbWzPpXz.js → skipSegments-ByNoF1qZ.js} +2 -2
- package/dist/chunks/{skipSegments-BbWzPpXz.js.map → skipSegments-ByNoF1qZ.js.map} +1 -1
- package/dist/chunks/{spriteThumbnails-B7oDZFTo.js → spriteThumbnails-Cr9UmkM9.js} +74 -51
- package/dist/chunks/spriteThumbnails-Cr9UmkM9.js.map +1 -0
- package/dist/chunks/{statsPanel-DSClIwA3.js → statsPanel-D0DtoFgS.js} +2 -2
- package/dist/chunks/statsPanel-D0DtoFgS.js.map +1 -0
- package/dist/chunks/{sticky-D_eLCNFk.js → sticky-BDStzjBM.js} +27 -26
- package/dist/chunks/sticky-BDStzjBM.js.map +1 -0
- package/dist/chunks/{story-BLBij82f.js → story-CodA2dfn.js} +2 -2
- package/dist/chunks/{story-BLBij82f.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/drm/NativeEme.d.ts +23 -0
- package/dist/drm/NativeEme.d.ts.map +1 -0
- package/dist/drm/keySystems.d.ts +18 -0
- package/dist/drm/keySystems.d.ts.map +1 -0
- package/dist/hls/SourceManager.d.ts +31 -5
- package/dist/hls/SourceManager.d.ts.map +1 -1
- package/dist/hls/dashEngine.d.ts +85 -0
- package/dist/hls/dashEngine.d.ts.map +1 -0
- package/dist/hls/sourceGroups.d.ts.map +1 -1
- package/dist/hope-player.js +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 +28 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/keyboard/KeyboardController.d.ts +14 -0
- package/dist/keyboard/KeyboardController.d.ts.map +1 -1
- package/dist/plugin-api/PluginAds.d.ts +61 -0
- package/dist/plugin-api/PluginAds.d.ts.map +1 -0
- package/dist/plugin-api/PluginHost.d.ts +6 -0
- package/dist/plugin-api/PluginHost.d.ts.map +1 -1
- package/dist/plugin-api/types.d.ts +39 -0
- package/dist/plugin-api/types.d.ts.map +1 -1
- package/dist/plugins/accessibility/Accessibility.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/ads/AdsController.d.ts +2 -0
- package/dist/plugins/ads/AdsController.d.ts.map +1 -1
- package/dist/plugins/analytics/QoeTracker.d.ts +71 -0
- package/dist/plugins/analytics/QoeTracker.d.ts.map +1 -0
- package/dist/plugins/analytics/index.d.ts +6 -0
- package/dist/plugins/analytics/index.d.ts.map +1 -0
- package/dist/plugins/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/playlist/PlaylistRunner.d.ts +2 -0
- package/dist/plugins/playlist/PlaylistRunner.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 +9 -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/screens/ErrorScreen.d.ts +1 -1
- package/dist/screens/ErrorScreen.d.ts.map +1 -1
- package/dist/subtitles/attachTracks.d.ts +6 -0
- package/dist/subtitles/attachTracks.d.ts.map +1 -1
- package/dist/types/index.d.ts +320 -16
- 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 +2 -1
- package/dist/chunks/adTriggers-DXmtF4t2.js +0 -410
- package/dist/chunks/adTriggers-DXmtF4t2.js.map +0 -1
- package/dist/chunks/ads-CdWbE9aD.js.map +0 -1
- package/dist/chunks/loopSection-CvF4l5uf.js.map +0 -1
- package/dist/chunks/markers-B04NMI79.js.map +0 -1
- package/dist/chunks/player-D7WQxMzr.js +0 -3894
- package/dist/chunks/player-D7WQxMzr.js.map +0 -1
- package/dist/chunks/playlist-C6Mh9BE8.js.map +0 -1
- package/dist/chunks/pluginHost-DjvLmMYZ.js +0 -376
- package/dist/chunks/pluginHost-DjvLmMYZ.js.map +0 -1
- package/dist/chunks/redirectScreen-5HAVRtxe.js +0 -208
- package/dist/chunks/redirectScreen-5HAVRtxe.js.map +0 -1
- package/dist/chunks/segments-gCPrWRig.js +0 -63
- package/dist/chunks/segments-gCPrWRig.js.map +0 -1
- package/dist/chunks/spriteThumbnails-B7oDZFTo.js.map +0 -1
- package/dist/chunks/statsPanel-DSClIwA3.js.map +0 -1
- package/dist/chunks/sticky-D_eLCNFk.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rewardedUnlock-CGhQyWOk.js","sources":["../../src/plugins/rewarded/gpt.ts","../../src/plugins/rewarded/RewardedUnlock.ts","../../src/plugins/rewarded/index.ts"],"sourcesContent":["import type { RewardedResult } from '../../types';\n\n/** Google Publisher Tag'in kullanılan yüzeyi (minimal tipler). */\ninterface GptSlot {\n addService(service: unknown): GptSlot;\n}\ninterface GptEvent {\n slot: GptSlot;\n isEmpty?: boolean;\n makeRewardedVisible?: () => boolean | void;\n}\ninterface GptPubAds {\n addEventListener(type: string, listener: (e: GptEvent) => void): void;\n removeEventListener?(type: string, listener: (e: GptEvent) => void): void;\n}\ninterface GoogleTag {\n cmd: Array<() => void> | { push(fn: () => void): void };\n apiReady?: boolean;\n enums: { OutOfPageFormat: { REWARDED: unknown } };\n pubads(): GptPubAds;\n defineOutOfPageSlot(path: string, format: unknown): GptSlot | null;\n enableServices(): void;\n display(slot: GptSlot): void;\n destroySlots(slots: GptSlot[]): void;\n}\n\n/** Google'ın güncel örneklerindeki adres (eski securepagead2 adresi bazı ağlarda sertifika hatası veriyordu). */\nconst GPT_SRC = 'https://securepubads.g.doubleclick.net/tag/js/gpt.js';\nlet gptLoading: Promise<void> | null = null;\n\n/** GPT sayfada yoksa yükler; sayfa GPT'yi (hangi adresten olursa olsun) zaten yüklüyorsa onu paylaşır. */\nfunction loadGpt(): Promise<void> {\n const w = window as unknown as { googletag?: Partial<GoogleTag> };\n w.googletag ??= { cmd: [] } as Partial<GoogleTag>;\n w.googletag.cmd ??= [];\n if (w.googletag.apiReady || document.querySelector('script[src*=\"/tag/js/gpt.js\"]')) return Promise.resolve();\n gptLoading ??= new Promise<void>((resolve, reject) => {\n const s = document.createElement('script');\n s.async = true;\n s.src = GPT_SRC;\n s.onload = () => resolve();\n s.onerror = () => {\n gptLoading = null;\n s.remove();\n reject(new Error('gpt.js could not be loaded (ad blocker / network / certificate)'));\n };\n document.head.appendChild(s);\n });\n return gptLoading;\n}\n\n/**\n * GPT web rewarded akışı (Google'ın örneğiyle aynı): slot tanımla → display → `rewardedSlotReady` gelince göster →\n * `rewardedSlotGranted` ödül → `rewardedSlotClosed` kapandı → slotu yok et. Kullanıcı onayı bu fonksiyon çağrılmadan\n * ÖNCE alınmış olmalı (player'ın onay penceresi).\n *\n * `timeoutMs` betiğin yüklenmesi DAHİL en baştan sayar: GPT hiç yüklenemez ya da çalışmazsa (engelleyici, ağ,\n * sertifika) da 'nofill' döner — bekleme ekranı asla takılı kalmaz. `signal` iptal edilirse (kullanıcı \"Vazgeç\") slot\n * temizlenip 'closed' döner. Reklam görünür olduktan sonra zaman aşımı işlemez; kapanışı GPT bildirir.\n */\nexport function showGptRewarded(adUnitPath: string, timeoutMs: number, signal?: AbortSignal): Promise<RewardedResult> {\n return new Promise<RewardedResult>((resolve) => {\n let done = false;\n let granted = false;\n let videoCompleted = false;\n let slot: GptSlot | null = null;\n let googletag: GoogleTag | null = null;\n const listeners: Array<[string, (e: GptEvent) => void]> = [];\n\n const finish = (result: RewardedResult): void => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n if (googletag) {\n const pubads = googletag.pubads();\n for (const [type, fn] of listeners) pubads.removeEventListener?.(type, fn);\n if (slot) {\n try {\n googletag.destroySlots([slot]);\n } catch {\n /* zaten yok edildi */\n }\n }\n }\n resolve(result);\n };\n const onAbort = (): void => finish('closed');\n const timer = setTimeout(() => finish('nofill'), timeoutMs);\n if (signal?.aborted) {\n finish('closed');\n return;\n }\n signal?.addEventListener('abort', onAbort);\n\n loadGpt()\n .then(() => {\n if (done) return;\n const gt = (window as unknown as { googletag: GoogleTag }).googletag;\n gt.cmd.push(() => {\n if (done) return;\n googletag = gt;\n slot = gt.defineOutOfPageSlot(adUnitPath, gt.enums.OutOfPageFormat.REWARDED);\n // null: sayfa formatı desteklemiyor (ör. mobil uyumlu viewport yok) — reklam yok sayılır.\n if (!slot) {\n finish('nofill');\n return;\n }\n slot.addService(gt.pubads());\n const pubads = gt.pubads();\n const on = (type: string, fn: (e: GptEvent) => void): void => {\n listeners.push([type, fn]);\n pubads.addEventListener(type, fn);\n };\n on('rewardedSlotReady', (e) => {\n if (e.slot !== slot || done) return;\n // Reklam hazır: artık bekleme yok — kapanışı GPT bildirecek.\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n e.makeRewardedVisible?.();\n });\n // Google: \"You need to close out ads rather than relying on GPT to do so.\" — ödül verilip video reklam\n // sonuna kadar oynayınca reklam player tarafından kapatılır (slot yok edilir); kullanıcı X'e basmak\n // zorunda kalmaz. Ödülü video bitmeden veren reklamlarda kapanış video bitince olur.\n on('rewardedSlotGranted', (e) => {\n if (e.slot !== slot) return;\n granted = true;\n if (videoCompleted) finish('granted');\n });\n on('rewardedSlotVideoCompleted', (e) => {\n if (e.slot !== slot) return;\n videoCompleted = true;\n if (granted) finish('granted');\n });\n on('rewardedSlotClosed', (e) => {\n if (e.slot === slot) finish(granted ? 'granted' : 'closed');\n });\n on('slotRenderEnded', (e) => {\n if (e.slot === slot && e.isEmpty) finish('nofill');\n });\n gt.enableServices();\n gt.display(slot);\n });\n })\n .catch(() => finish('nofill'));\n });\n}\n","import type { RewardedResult, RewardedUnlockOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { LOCK_SVG } from '../../controls/SettingsMenu';\nimport { showGptRewarded } from './gpt';\n\nexport interface RewardedUnlockContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n /** Onay penceresinin ekleneceği alan (video alanı). */\n overlayEl: HTMLElement;\n /** Buton kontrollerle birlikte görünüp gizlensin diye kontrol katmanına eklenir. */\n chromeEl: HTMLElement;\n i18n: HopeLocaleStrings;\n log(entry: { message: string; details?: Record<string, string | number | boolean | undefined> }): void;\n play(): void;\n exitFullscreen(): void;\n /** Kilitli kalitelerin en yükseği (ör. \"1080p\") — yoksa null (buton gizlenir). */\n lockedQualityLabel(): string | null;\n /** İçeriğin kimliği (kaynak listesi) — kalite değişince değişmez, başka video yüklenince değişir. */\n contentKey(): string;\n /** Kilit açıldı / geri geldi: player menüleri yeniden kurar; `upgrade` → en iyi kaliteye geç. */\n onLockChange(upgrade: boolean): void;\n}\n\nconst DEFAULT_MAX_FREE_HEIGHT = 480;\nconst DEFAULT_STORAGE_KEY = 'hope-rewarded-unlock';\nconst DEFAULT_GPT_TIMEOUT_MS = 8000;\nconst TOAST_MS = 2600;\n\ntype Phase = 'idle' | 'prompt' | 'loading' | 'nofill';\n\n/**\n * Ödüllü reklamla kalite kilidi. Akış (Google'ın ödüllü reklam politikasına göre): kullanıcı kilitli bir kaliteye ya da\n * \"Yüksek kaliteyi aç\" butonuna dokunur → ödülü açıkça yazan onay penceresi → yalnızca \"Reklamı izle\" ile reklam istenir\n * → ödül verildiyse kilit açılır. Vazgeçmek videoyu izlemeyi engellemez (düşük kalitede devam eder).\n */\n/** Diyalog başlık id'leri — aynı sayfada birden çok player olabilir. */\nlet dialogSeq = 0;\n\nexport class RewardedUnlock {\n private options: RewardedUnlockOptions;\n private readonly button: HTMLButtonElement;\n private dialog: HTMLDivElement | null = null;\n private toast: HTMLDivElement | null = null;\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n private phase: Phase = 'idle';\n /** 'video' modunda kilidin açık olduğu içerik (kaynak listesi — kalite dosyası değil). */\n private videoUnlockedKey: string | null = null;\n private lastKey = '';\n\n constructor(\n private readonly ctx: RewardedUnlockContext,\n options: RewardedUnlockOptions\n ) {\n this.options = options;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hp-rw-button';\n btn.setAttribute('part', 'rewarded-button');\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.requestUnlock();\n });\n btn.addEventListener('pointerdown', (e) => e.stopPropagation());\n ctx.chromeEl.appendChild(btn);\n this.button = btn;\n ctx.videoEl.addEventListener('loadstart', this.onSourceChange);\n this.refreshLabels();\n this.onQualitiesChanged();\n }\n\n update(options: RewardedUnlockOptions): void {\n const before = this.unlocked;\n this.options = options;\n if (before !== this.unlocked) this.ctx.onLockChange(false);\n this.onQualitiesChanged();\n }\n\n // ── Kilit durumu ────────────────────────────────────────────────────\n\n private get maxFreeHeight(): number {\n const h = this.options.maxFreeHeight;\n return typeof h === 'number' && h > 0 ? h : DEFAULT_MAX_FREE_HEIGHT;\n }\n\n private get storageKey(): string {\n return this.options.storageKey || DEFAULT_STORAGE_KEY;\n }\n\n private get unlockFor(): 'video' | 'session' | number {\n const u = this.options.unlockFor;\n return typeof u === 'number' && u > 0 ? u : u === 'video' ? 'video' : 'session';\n }\n\n get unlocked(): boolean {\n const mode = this.unlockFor;\n if (mode === 'video') return !!this.videoUnlockedKey && this.videoUnlockedKey === this.ctx.contentKey();\n try {\n if (mode === 'session') return sessionStorage.getItem(this.storageKey) === '1';\n const until = Number(localStorage.getItem(this.storageKey));\n return Number.isFinite(until) && until > Date.now();\n } catch {\n return false; // depolama kapalı (gizli mod vb.)\n }\n }\n\n private grant(): void {\n const mode = this.unlockFor;\n if (mode === 'video') this.videoUnlockedKey = this.ctx.contentKey();\n try {\n if (mode === 'session') sessionStorage.setItem(this.storageKey, '1');\n else if (typeof mode === 'number') localStorage.setItem(this.storageKey, String(Date.now() + mode * 60_000));\n } catch {\n // Depolama yoksa yalnızca bu video için açık kalır.\n this.videoUnlockedKey = this.ctx.contentKey();\n }\n }\n\n /** Player için: bu yükseklikteki kalite kilitli mi? */\n isLocked(height: number | null): boolean {\n if (this.unlocked) return false;\n return height !== null && height > this.maxFreeHeight;\n }\n\n /** Kaynak değişti: 'video' modunda kilit yeniden kapanır; süreli kilit dolduysa menüler güncellenir. */\n private readonly onSourceChange = (): void => {\n const key = this.ctx.contentKey();\n if (key === this.lastKey) return;\n this.lastKey = key;\n this.onQualitiesChanged();\n };\n\n /** Player kalite listesi değişince çağırır: buton yalnızca kilitli kalite varken görünür. */\n onQualitiesChanged(): void {\n const label = this.ctx.lockedQualityLabel();\n const show = this.options.button !== false && !!label && !this.unlocked;\n this.button.hidden = !show;\n if (!show) return;\n const text = this.fill(this.ctx.i18n.rewardedButton, label!);\n this.button.innerHTML = `${LOCK_SVG}<span>${escapeHtml(text)}</span>`;\n // Erişilebilir ad görünen metinle aynı (sesli komutla \"720p kilidini aç\" dendiğinde bulunabilsin).\n this.button.setAttribute('aria-label', text);\n }\n\n // ── Akış ────────────────────────────────────────────────────────────\n\n /** Kilitli kaliteye ya da butona dokunuldu: onay penceresi. */\n requestUnlock(): void {\n if (this.unlocked || this.phase !== 'idle') return;\n const label = this.ctx.lockedQualityLabel() ?? 'HD';\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedprompt', { detail: { quality: label } }));\n this.showDialog('prompt', label);\n }\n\n private async watch(label: string): Promise<void> {\n const v = this.ctx.videoEl;\n const wasPlaying = !v.paused;\n v.pause();\n // GPT reklamı sayfanın kendi katmanında açılır — player tam ekrandaysa görünmez.\n this.ctx.exitFullscreen();\n this.abort = new AbortController();\n const signal = this.abort.signal;\n this.showDialog('loading', label);\n let result: RewardedResult;\n try {\n result = await this.runProvider(signal);\n } catch (err) {\n this.ctx.log({ message: `Rewarded ad failed: ${String(err)}` });\n result = 'nofill';\n }\n this.abort = null;\n // Kullanıcı hazırlanırken \"Vazgeç\" dedi — sonuç ne olursa olsun ödül yok, video devam eder.\n if (signal.aborted) {\n this.closeDialog();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedclosed', { detail: { granted: false, cancelled: true } }));\n if (wasPlaying) this.ctx.play();\n return;\n }\n // Reklam yok / boş / hata: kusur kullanıcıda değil — varsayılan olarak kilit yine de açılır (grantOnNoFill: false kapatır).\n let noAd = false;\n if (result === 'nofill' && this.options.grantOnNoFill !== false) {\n this.ctx.log({ message: 'Rewarded ad: no ad available (no fill / error / timeout) — unlocked anyway (grantOnNoFill)' });\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardednofill', { detail: { granted: true } }));\n result = 'granted';\n noAd = true;\n }\n if (result === 'granted') {\n this.grant();\n this.closeDialog();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedgranted', { detail: { quality: label, noAd } }));\n this.ctx.onLockChange(true);\n this.onQualitiesChanged();\n this.showToast(this.fill(noAd ? this.ctx.i18n.rewardedUnlockedNoAd : this.ctx.i18n.rewardedUnlocked, label));\n if (wasPlaying) this.ctx.play();\n return;\n }\n if (result === 'nofill') {\n this.ctx.log({ message: 'Rewarded ad: no ad available (no fill / unsupported page / timeout)' });\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardednofill', { detail: { granted: false } }));\n this.showDialog('nofill', label);\n this.resumeAfterDialog = wasPlaying;\n return;\n }\n // Kullanıcı reklamı ödül kazanmadan kapattı — video kaldığı kalitede devam eder.\n this.closeDialog();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedclosed', { detail: { granted: false } }));\n if (wasPlaying) this.ctx.play();\n }\n\n private resumeAfterDialog = false;\n /** Reklam hazırlanırken \"Vazgeç\" — sağlayıcıya iletilir (GPT slotu temizlenir). */\n private abort: AbortController | null = null;\n\n private async runProvider(signal: AbortSignal): Promise<RewardedResult> {\n const p = this.options.provider;\n if (p?.type === 'gpt') return showGptRewarded(p.adUnitPath, p.timeoutMs ?? DEFAULT_GPT_TIMEOUT_MS, signal);\n if (p?.type === 'custom') {\n // İptal edilirse kendi reklam sisteminizin sonucu beklenmez (sinyali kendi tarafınızda da dinleyebilirsiniz).\n const aborted = new Promise<RewardedResult>((resolve) => signal.addEventListener('abort', () => resolve('closed'), { once: true }));\n const r = await Promise.race([p.show({ signal }), aborted]);\n return r === true ? 'granted' : r === false ? 'closed' : r;\n }\n throw new Error('rewardedUnlock.provider is missing');\n }\n\n // ── Arayüz ─────────────────────────────────────────────────────────\n\n private fill(template: string, quality: string): string {\n const mode = this.unlockFor;\n const i = this.ctx.i18n;\n const duration =\n mode === 'video' ? i.rewardedForVideo : mode === 'session' ? i.rewardedForSession : i.rewardedForMinutes.replace('{n}', String(mode));\n return template.replace('{quality}', quality).replace('{duration}', duration);\n }\n\n private showDialog(phase: Exclude<Phase, 'idle'>, label: string): void {\n this.phase = phase;\n const i = this.ctx.i18n;\n if (!this.dialog) {\n const d = document.createElement('div');\n d.className = 'hp-rw-dialog';\n d.setAttribute('part', 'rewarded-dialog');\n d.setAttribute('role', 'dialog');\n d.setAttribute('aria-modal', 'true');\n for (const t of ['click', 'pointerdown', 'dblclick'] as const) d.addEventListener(t, (e) => e.stopPropagation());\n d.addEventListener('keydown', (e) => {\n e.stopPropagation();\n if (e.key !== 'Escape') return;\n if (this.phase === 'loading') this.abort?.abort();\n else this.dismiss();\n });\n this.ctx.overlayEl.appendChild(d);\n this.dialog = d;\n }\n const d = this.dialog;\n d.setAttribute('data-phase', phase);\n d.innerHTML = '';\n const card = document.createElement('div');\n card.className = 'hp-rw-card';\n const icon = document.createElement('div');\n icon.className = 'hp-rw-icon';\n icon.innerHTML = LOCK_SVG;\n const title = document.createElement('div');\n title.className = 'hp-rw-title';\n // Diyaloğun erişilebilir adı başlığı (ekran okuyucu \"720p kilidini aç\" diye okur).\n title.id = `hp-rw-title-${++dialogSeq}`;\n d.setAttribute('aria-labelledby', title.id);\n const text = document.createElement('div');\n text.className = 'hp-rw-text';\n const actions = document.createElement('div');\n actions.className = 'hp-rw-actions';\n card.append(icon, title, text, actions);\n d.appendChild(card);\n\n const button = (labelText: string, primary: boolean, onClick: () => void): HTMLButtonElement => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = primary ? 'hp-rw-btn hp-rw-btn-primary' : 'hp-rw-btn';\n b.textContent = labelText;\n b.addEventListener('click', onClick);\n actions.appendChild(b);\n return b;\n };\n\n if (phase === 'prompt') {\n title.textContent = this.fill(i.rewardedTitle, label);\n // Ödül, reklamdan ÖNCE açıkça yazılır (politika şartı).\n text.textContent = this.fill(i.rewardedBody, label);\n button(i.rewardedDecline, false, () => this.dismiss());\n button(i.rewardedWatch, true, () => void this.watch(label)).focus();\n } else if (phase === 'loading') {\n title.textContent = i.rewardedLoading;\n const spin = document.createElement('div');\n spin.className = 'hp-rw-spinner';\n text.appendChild(spin);\n // Hazırlanma ne kadar sürerse sürsün kullanıcı takılı kalmaz.\n button(i.rewardedDecline, false, () => this.abort?.abort());\n } else {\n title.textContent = this.fill(i.rewardedTitle, label);\n text.textContent = i.rewardedNoFill;\n button(i.rewardedOk, true, () => this.dismiss()).focus();\n }\n }\n\n private dismiss(): void {\n const wasNoFill = this.phase === 'nofill';\n this.closeDialog();\n if (!wasNoFill) this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedclosed', { detail: { granted: false, declined: true } }));\n if (this.resumeAfterDialog) this.ctx.play();\n this.resumeAfterDialog = false;\n }\n\n private closeDialog(): void {\n this.phase = 'idle';\n this.dialog?.remove();\n this.dialog = null;\n }\n\n private showToast(message: string): void {\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toast?.remove();\n const t = document.createElement('div');\n t.className = 'hp-rw-toast';\n t.setAttribute('part', 'rewarded-toast');\n t.setAttribute('role', 'status');\n t.textContent = message;\n this.ctx.overlayEl.appendChild(t);\n this.toast = t;\n this.toastTimer = setTimeout(() => {\n this.toast?.remove();\n this.toast = null;\n }, TOAST_MS);\n }\n\n refreshLabels(): void {\n this.onQualitiesChanged();\n }\n\n destroy(): void {\n this.abort?.abort();\n this.ctx.videoEl.removeEventListener('loadstart', this.onSourceChange);\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toast?.remove();\n this.closeDialog();\n this.button.remove();\n }\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[c]!);\n}\n","import { RewardedUnlock, type RewardedUnlockContext } from './RewardedUnlock';\nimport type { RewardedUnlockOptions } from '../../types';\n\n/** Ödüllü reklamla kalite kilidini kurar. */\nexport function installRewardedUnlock(ctx: RewardedUnlockContext, options: RewardedUnlockOptions): RewardedUnlock {\n return new RewardedUnlock(ctx, options);\n}\n\nexport { RewardedUnlock };\nexport type { RewardedUnlockContext };\n"],"names":["GPT_SRC","gptLoading","loadGpt","w","_a","resolve","reject","showGptRewarded","adUnitPath","timeoutMs","signal","done","granted","videoCompleted","slot","googletag","listeners","finish","result","timer","onAbort","pubads","type","fn","gt","on","e","DEFAULT_MAX_FREE_HEIGHT","DEFAULT_STORAGE_KEY","DEFAULT_GPT_TIMEOUT_MS","TOAST_MS","dialogSeq","RewardedUnlock","ctx","options","__publicField","key","btn","before","h","u","mode","until","height","label","show","text","LOCK_SVG","escapeHtml","v","wasPlaying","err","noAd","p","aborted","r","template","quality","i","duration","phase","d","t","card","icon","title","actions","button","labelText","primary","onClick","b","spin","wasNoFill","message","_b","s","c","installRewardedUnlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rewardedUnlock-DUqYwXTr.js","sources":["../../src/plugins/rewarded/gpt.ts","../../src/plugins/rewarded/RewardedUnlock.ts","../../src/plugins/rewarded/index.ts"],"sourcesContent":["import type { RewardedResult } from '../../types';\n\n/** Google Publisher Tag'in kullanılan yüzeyi (minimal tipler). */\ninterface GptSlot {\n addService(service: unknown): GptSlot;\n}\ninterface GptEvent {\n slot: GptSlot;\n isEmpty?: boolean;\n makeRewardedVisible?: () => boolean | void;\n}\ninterface GptPubAds {\n addEventListener(type: string, listener: (e: GptEvent) => void): void;\n removeEventListener?(type: string, listener: (e: GptEvent) => void): void;\n}\ninterface GoogleTag {\n cmd: Array<() => void> | { push(fn: () => void): void };\n apiReady?: boolean;\n enums: { OutOfPageFormat: { REWARDED: unknown } };\n pubads(): GptPubAds;\n defineOutOfPageSlot(path: string, format: unknown): GptSlot | null;\n enableServices(): void;\n display(slot: GptSlot): void;\n destroySlots(slots: GptSlot[]): void;\n}\n\n/** Google'ın güncel örneklerindeki adres (eski securepagead2 adresi bazı ağlarda sertifika hatası veriyordu). */\nconst GPT_SRC = 'https://securepubads.g.doubleclick.net/tag/js/gpt.js';\nlet gptLoading: Promise<void> | null = null;\n\n/** GPT sayfada yoksa yükler; sayfa GPT'yi (hangi adresten olursa olsun) zaten yüklüyorsa onu paylaşır. */\nfunction loadGpt(): Promise<void> {\n const w = window as unknown as { googletag?: Partial<GoogleTag> };\n w.googletag ??= { cmd: [] } as Partial<GoogleTag>;\n w.googletag.cmd ??= [];\n if (w.googletag.apiReady || document.querySelector('script[src*=\"/tag/js/gpt.js\"]')) return Promise.resolve();\n gptLoading ??= new Promise<void>((resolve, reject) => {\n const s = document.createElement('script');\n s.async = true;\n s.src = GPT_SRC;\n s.onload = () => resolve();\n s.onerror = () => {\n gptLoading = null;\n s.remove();\n reject(new Error('gpt.js could not be loaded (ad blocker / network / certificate)'));\n };\n document.head.appendChild(s);\n });\n return gptLoading;\n}\n\n/**\n * GPT web rewarded akışı (Google'ın örneğiyle aynı): slot tanımla → display → `rewardedSlotReady` gelince göster →\n * `rewardedSlotGranted` ödül → `rewardedSlotClosed` kapandı → slotu yok et. Kullanıcı onayı bu fonksiyon çağrılmadan\n * ÖNCE alınmış olmalı (player'ın onay penceresi).\n *\n * `timeoutMs` betiğin yüklenmesi DAHİL en baştan sayar: GPT hiç yüklenemez ya da çalışmazsa (engelleyici, ağ,\n * sertifika) da 'nofill' döner — bekleme ekranı asla takılı kalmaz. `signal` iptal edilirse (kullanıcı \"Vazgeç\") slot\n * temizlenip 'closed' döner. Reklam görünür olduktan sonra zaman aşımı işlemez; kapanışı GPT bildirir.\n */\nexport function showGptRewarded(adUnitPath: string, timeoutMs: number, signal?: AbortSignal): Promise<RewardedResult> {\n return new Promise<RewardedResult>((resolve) => {\n let done = false;\n let granted = false;\n let videoCompleted = false;\n let slot: GptSlot | null = null;\n let googletag: GoogleTag | null = null;\n const listeners: Array<[string, (e: GptEvent) => void]> = [];\n\n const finish = (result: RewardedResult): void => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n if (googletag) {\n const pubads = googletag.pubads();\n for (const [type, fn] of listeners) pubads.removeEventListener?.(type, fn);\n if (slot) {\n try {\n googletag.destroySlots([slot]);\n } catch {\n /* zaten yok edildi */\n }\n }\n }\n resolve(result);\n };\n const onAbort = (): void => finish('closed');\n const timer = setTimeout(() => finish('nofill'), timeoutMs);\n if (signal?.aborted) {\n finish('closed');\n return;\n }\n signal?.addEventListener('abort', onAbort);\n\n loadGpt()\n .then(() => {\n if (done) return;\n const gt = (window as unknown as { googletag: GoogleTag }).googletag;\n gt.cmd.push(() => {\n if (done) return;\n googletag = gt;\n slot = gt.defineOutOfPageSlot(adUnitPath, gt.enums.OutOfPageFormat.REWARDED);\n // null: sayfa formatı desteklemiyor (ör. mobil uyumlu viewport yok) — reklam yok sayılır.\n if (!slot) {\n finish('nofill');\n return;\n }\n slot.addService(gt.pubads());\n const pubads = gt.pubads();\n const on = (type: string, fn: (e: GptEvent) => void): void => {\n listeners.push([type, fn]);\n pubads.addEventListener(type, fn);\n };\n on('rewardedSlotReady', (e) => {\n if (e.slot !== slot || done) return;\n // Reklam hazır: artık bekleme yok — kapanışı GPT bildirecek.\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n e.makeRewardedVisible?.();\n });\n // Google: \"You need to close out ads rather than relying on GPT to do so.\" — ödül verilip video reklam\n // sonuna kadar oynayınca reklam player tarafından kapatılır (slot yok edilir); kullanıcı X'e basmak\n // zorunda kalmaz. Ödülü video bitmeden veren reklamlarda kapanış video bitince olur.\n on('rewardedSlotGranted', (e) => {\n if (e.slot !== slot) return;\n granted = true;\n if (videoCompleted) finish('granted');\n });\n on('rewardedSlotVideoCompleted', (e) => {\n if (e.slot !== slot) return;\n videoCompleted = true;\n if (granted) finish('granted');\n });\n on('rewardedSlotClosed', (e) => {\n if (e.slot === slot) finish(granted ? 'granted' : 'closed');\n });\n on('slotRenderEnded', (e) => {\n if (e.slot === slot && e.isEmpty) finish('nofill');\n });\n gt.enableServices();\n gt.display(slot);\n });\n })\n .catch(() => finish('nofill'));\n });\n}\n","import type { RewardedResult, RewardedUnlockOptions } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { LOCK_SVG } from '../../controls/SettingsMenu';\nimport { showGptRewarded } from './gpt';\n\nexport interface RewardedUnlockContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n /** Onay penceresinin ekleneceği alan (video alanı). */\n overlayEl: HTMLElement;\n /** Buton kontrollerle birlikte görünüp gizlensin diye kontrol katmanına eklenir. */\n chromeEl: HTMLElement;\n i18n: HopeLocaleStrings;\n log(entry: { message: string; details?: Record<string, string | number | boolean | undefined> }): void;\n play(): void;\n exitFullscreen(): void;\n /** Kilitli kalitelerin en yükseği (ör. \"1080p\") — yoksa null (buton gizlenir). */\n lockedQualityLabel(): string | null;\n /** İçeriğin kimliği (kaynak listesi) — kalite değişince değişmez, başka video yüklenince değişir. */\n contentKey(): string;\n /** Kilit açıldı / geri geldi: player menüleri yeniden kurar; `upgrade` → en iyi kaliteye geç. */\n onLockChange(upgrade: boolean): void;\n}\n\nconst DEFAULT_MAX_FREE_HEIGHT = 480;\nconst DEFAULT_STORAGE_KEY = 'hope-rewarded-unlock';\nconst DEFAULT_GPT_TIMEOUT_MS = 8000;\nconst TOAST_MS = 2600;\n\ntype Phase = 'idle' | 'prompt' | 'loading' | 'nofill';\n\n/**\n * Ödüllü reklamla kalite kilidi. Akış (Google'ın ödüllü reklam politikasına göre): kullanıcı kilitli bir kaliteye ya da\n * \"Yüksek kaliteyi aç\" butonuna dokunur → ödülü açıkça yazan onay penceresi → yalnızca \"Reklamı izle\" ile reklam istenir\n * → ödül verildiyse kilit açılır. Vazgeçmek videoyu izlemeyi engellemez (düşük kalitede devam eder).\n */\n/** Diyalog başlık id'leri — aynı sayfada birden çok player olabilir. */\nlet dialogSeq = 0;\n\nexport class RewardedUnlock {\n private options: RewardedUnlockOptions;\n private readonly button: HTMLButtonElement;\n private dialog: HTMLDivElement | null = null;\n private toast: HTMLDivElement | null = null;\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n private phase: Phase = 'idle';\n /** 'video' modunda kilidin açık olduğu içerik (kaynak listesi — kalite dosyası değil). */\n private videoUnlockedKey: string | null = null;\n private lastKey = '';\n\n constructor(\n private readonly ctx: RewardedUnlockContext,\n options: RewardedUnlockOptions\n ) {\n this.options = options;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hp-rw-button';\n btn.setAttribute('part', 'rewarded-button');\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.requestUnlock();\n });\n btn.addEventListener('pointerdown', (e) => e.stopPropagation());\n ctx.chromeEl.appendChild(btn);\n this.button = btn;\n ctx.videoEl.addEventListener('loadstart', this.onSourceChange);\n this.refreshLabels();\n this.onQualitiesChanged();\n }\n\n update(options: RewardedUnlockOptions): void {\n const before = this.unlocked;\n this.options = options;\n if (before !== this.unlocked) this.ctx.onLockChange(false);\n this.onQualitiesChanged();\n }\n\n // ── Kilit durumu ────────────────────────────────────────────────────\n\n private get maxFreeHeight(): number {\n const h = this.options.maxFreeHeight;\n return typeof h === 'number' && h > 0 ? h : DEFAULT_MAX_FREE_HEIGHT;\n }\n\n private get storageKey(): string {\n return this.options.storageKey || DEFAULT_STORAGE_KEY;\n }\n\n private get unlockFor(): 'video' | 'session' | number {\n const u = this.options.unlockFor;\n return typeof u === 'number' && u > 0 ? u : u === 'video' ? 'video' : 'session';\n }\n\n get unlocked(): boolean {\n const mode = this.unlockFor;\n if (mode === 'video') return !!this.videoUnlockedKey && this.videoUnlockedKey === this.ctx.contentKey();\n try {\n if (mode === 'session') return sessionStorage.getItem(this.storageKey) === '1';\n const until = Number(localStorage.getItem(this.storageKey));\n return Number.isFinite(until) && until > Date.now();\n } catch {\n return false; // depolama kapalı (gizli mod vb.)\n }\n }\n\n private grant(): void {\n const mode = this.unlockFor;\n if (mode === 'video') this.videoUnlockedKey = this.ctx.contentKey();\n try {\n if (mode === 'session') sessionStorage.setItem(this.storageKey, '1');\n else if (typeof mode === 'number') localStorage.setItem(this.storageKey, String(Date.now() + mode * 60_000));\n } catch {\n // Depolama yoksa yalnızca bu video için açık kalır.\n this.videoUnlockedKey = this.ctx.contentKey();\n }\n }\n\n /** Player için: bu yükseklikteki kalite kilitli mi? */\n isLocked(height: number | null): boolean {\n if (this.unlocked) return false;\n return height !== null && height > this.maxFreeHeight;\n }\n\n /** Kaynak değişti: 'video' modunda kilit yeniden kapanır; süreli kilit dolduysa menüler güncellenir. */\n private readonly onSourceChange = (): void => {\n const key = this.ctx.contentKey();\n if (key === this.lastKey) return;\n this.lastKey = key;\n this.onQualitiesChanged();\n };\n\n /** Player kalite listesi değişince çağırır: buton yalnızca kilitli kalite varken görünür. */\n onQualitiesChanged(): void {\n const label = this.ctx.lockedQualityLabel();\n const show = this.options.button !== false && !!label && !this.unlocked;\n this.button.hidden = !show;\n if (!show) return;\n const text = this.fill(this.ctx.i18n.rewardedButton, label!);\n this.button.innerHTML = `${LOCK_SVG}<span>${escapeHtml(text)}</span>`;\n // Erişilebilir ad görünen metinle aynı (sesli komutla \"720p kilidini aç\" dendiğinde bulunabilsin).\n this.button.setAttribute('aria-label', text);\n }\n\n // ── Akış ────────────────────────────────────────────────────────────\n\n /** Kilitli kaliteye ya da butona dokunuldu: onay penceresi. */\n requestUnlock(): void {\n if (this.unlocked || this.phase !== 'idle') return;\n const label = this.ctx.lockedQualityLabel() ?? 'HD';\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedprompt', { detail: { quality: label } }));\n this.showDialog('prompt', label);\n }\n\n private async watch(label: string): Promise<void> {\n const v = this.ctx.videoEl;\n const wasPlaying = !v.paused;\n v.pause();\n // GPT reklamı sayfanın kendi katmanında açılır — player tam ekrandaysa görünmez.\n this.ctx.exitFullscreen();\n this.abort = new AbortController();\n const signal = this.abort.signal;\n this.showDialog('loading', label);\n let result: RewardedResult;\n try {\n result = await this.runProvider(signal);\n } catch (err) {\n this.ctx.log({ message: `Rewarded ad failed: ${String(err)}` });\n result = 'nofill';\n }\n this.abort = null;\n // Kullanıcı hazırlanırken \"Vazgeç\" dedi — sonuç ne olursa olsun ödül yok, video devam eder.\n if (signal.aborted) {\n this.closeDialog();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedclosed', { detail: { granted: false, cancelled: true } }));\n if (wasPlaying) this.ctx.play();\n return;\n }\n // Reklam yok / boş / hata: kusur kullanıcıda değil — varsayılan olarak kilit yine de açılır (grantOnNoFill: false kapatır).\n let noAd = false;\n if (result === 'nofill' && this.options.grantOnNoFill !== false) {\n this.ctx.log({ message: 'Rewarded ad: no ad available (no fill / error / timeout) — unlocked anyway (grantOnNoFill)' });\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardednofill', { detail: { granted: true } }));\n result = 'granted';\n noAd = true;\n }\n if (result === 'granted') {\n this.grant();\n this.closeDialog();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedgranted', { detail: { quality: label, noAd } }));\n this.ctx.onLockChange(true);\n this.onQualitiesChanged();\n this.showToast(this.fill(noAd ? this.ctx.i18n.rewardedUnlockedNoAd : this.ctx.i18n.rewardedUnlocked, label));\n if (wasPlaying) this.ctx.play();\n return;\n }\n if (result === 'nofill') {\n this.ctx.log({ message: 'Rewarded ad: no ad available (no fill / unsupported page / timeout)' });\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardednofill', { detail: { granted: false } }));\n this.showDialog('nofill', label);\n this.resumeAfterDialog = wasPlaying;\n return;\n }\n // Kullanıcı reklamı ödül kazanmadan kapattı — video kaldığı kalitede devam eder.\n this.closeDialog();\n this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedclosed', { detail: { granted: false } }));\n if (wasPlaying) this.ctx.play();\n }\n\n private resumeAfterDialog = false;\n /** Reklam hazırlanırken \"Vazgeç\" — sağlayıcıya iletilir (GPT slotu temizlenir). */\n private abort: AbortController | null = null;\n\n private async runProvider(signal: AbortSignal): Promise<RewardedResult> {\n const p = this.options.provider;\n if (p?.type === 'gpt') return showGptRewarded(p.adUnitPath, p.timeoutMs ?? DEFAULT_GPT_TIMEOUT_MS, signal);\n if (p?.type === 'custom') {\n // İptal edilirse kendi reklam sisteminizin sonucu beklenmez (sinyali kendi tarafınızda da dinleyebilirsiniz).\n const aborted = new Promise<RewardedResult>((resolve) => signal.addEventListener('abort', () => resolve('closed'), { once: true }));\n const r = await Promise.race([p.show({ signal }), aborted]);\n return r === true ? 'granted' : r === false ? 'closed' : r;\n }\n throw new Error('rewardedUnlock.provider is missing');\n }\n\n // ── Arayüz ─────────────────────────────────────────────────────────\n\n private fill(template: string, quality: string): string {\n const mode = this.unlockFor;\n const i = this.ctx.i18n;\n const duration =\n mode === 'video' ? i.rewardedForVideo : mode === 'session' ? i.rewardedForSession : i.rewardedForMinutes.replace('{n}', String(mode));\n return template.replace('{quality}', quality).replace('{duration}', duration);\n }\n\n private showDialog(phase: Exclude<Phase, 'idle'>, label: string): void {\n this.phase = phase;\n const i = this.ctx.i18n;\n if (!this.dialog) {\n const d = document.createElement('div');\n d.className = 'hp-rw-dialog';\n d.setAttribute('part', 'rewarded-dialog');\n d.setAttribute('role', 'dialog');\n d.setAttribute('aria-modal', 'true');\n for (const t of ['click', 'pointerdown', 'dblclick'] as const) d.addEventListener(t, (e) => e.stopPropagation());\n d.addEventListener('keydown', (e) => {\n e.stopPropagation();\n if (e.key !== 'Escape') return;\n if (this.phase === 'loading') this.abort?.abort();\n else this.dismiss();\n });\n this.ctx.overlayEl.appendChild(d);\n this.dialog = d;\n }\n const d = this.dialog;\n d.setAttribute('data-phase', phase);\n d.innerHTML = '';\n const card = document.createElement('div');\n card.className = 'hp-rw-card';\n const icon = document.createElement('div');\n icon.className = 'hp-rw-icon';\n icon.innerHTML = LOCK_SVG;\n const title = document.createElement('div');\n title.className = 'hp-rw-title';\n // Diyaloğun erişilebilir adı başlığı (ekran okuyucu \"720p kilidini aç\" diye okur).\n title.id = `hp-rw-title-${++dialogSeq}`;\n d.setAttribute('aria-labelledby', title.id);\n const text = document.createElement('div');\n text.className = 'hp-rw-text';\n const actions = document.createElement('div');\n actions.className = 'hp-rw-actions';\n card.append(icon, title, text, actions);\n d.appendChild(card);\n\n const button = (labelText: string, primary: boolean, onClick: () => void): HTMLButtonElement => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = primary ? 'hp-rw-btn hp-rw-btn-primary' : 'hp-rw-btn';\n b.textContent = labelText;\n b.addEventListener('click', onClick);\n actions.appendChild(b);\n return b;\n };\n\n if (phase === 'prompt') {\n title.textContent = this.fill(i.rewardedTitle, label);\n // Ödül, reklamdan ÖNCE açıkça yazılır (politika şartı).\n text.textContent = this.fill(i.rewardedBody, label);\n button(i.rewardedDecline, false, () => this.dismiss());\n button(i.rewardedWatch, true, () => void this.watch(label)).focus();\n } else if (phase === 'loading') {\n title.textContent = i.rewardedLoading;\n const spin = document.createElement('div');\n spin.className = 'hp-rw-spinner';\n text.appendChild(spin);\n // Hazırlanma ne kadar sürerse sürsün kullanıcı takılı kalmaz.\n button(i.rewardedDecline, false, () => this.abort?.abort());\n } else {\n title.textContent = this.fill(i.rewardedTitle, label);\n text.textContent = i.rewardedNoFill;\n button(i.rewardedOk, true, () => this.dismiss()).focus();\n }\n }\n\n private dismiss(): void {\n const wasNoFill = this.phase === 'nofill';\n this.closeDialog();\n if (!wasNoFill) this.ctx.hostEl.dispatchEvent(new CustomEvent('hp:rewardedclosed', { detail: { granted: false, declined: true } }));\n if (this.resumeAfterDialog) this.ctx.play();\n this.resumeAfterDialog = false;\n }\n\n private closeDialog(): void {\n this.phase = 'idle';\n this.dialog?.remove();\n this.dialog = null;\n }\n\n private showToast(message: string): void {\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toast?.remove();\n const t = document.createElement('div');\n t.className = 'hp-rw-toast';\n t.setAttribute('part', 'rewarded-toast');\n t.setAttribute('role', 'status');\n t.textContent = message;\n this.ctx.overlayEl.appendChild(t);\n this.toast = t;\n this.toastTimer = setTimeout(() => {\n this.toast?.remove();\n this.toast = null;\n }, TOAST_MS);\n }\n\n refreshLabels(): void {\n this.onQualitiesChanged();\n }\n\n destroy(): void {\n this.abort?.abort();\n this.ctx.videoEl.removeEventListener('loadstart', this.onSourceChange);\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toast?.remove();\n this.closeDialog();\n this.button.remove();\n }\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[c]!);\n}\n","import { RewardedUnlock, type RewardedUnlockContext } from './RewardedUnlock';\nimport type { RewardedUnlockOptions } from '../../types';\n\n/** Ödüllü reklamla kalite kilidini kurar. */\nexport function installRewardedUnlock(ctx: RewardedUnlockContext, options: RewardedUnlockOptions): RewardedUnlock {\n return new RewardedUnlock(ctx, options);\n}\n\nexport { RewardedUnlock };\nexport type { RewardedUnlockContext };\n"],"names":["GPT_SRC","gptLoading","loadGpt","w","_a","resolve","reject","showGptRewarded","adUnitPath","timeoutMs","signal","done","granted","videoCompleted","slot","googletag","listeners","finish","result","timer","onAbort","pubads","type","fn","gt","on","e","DEFAULT_MAX_FREE_HEIGHT","DEFAULT_STORAGE_KEY","DEFAULT_GPT_TIMEOUT_MS","TOAST_MS","dialogSeq","RewardedUnlock","ctx","options","__publicField","key","btn","before","h","u","mode","until","height","label","show","text","LOCK_SVG","escapeHtml","v","wasPlaying","err","noAd","p","aborted","r","template","quality","i","duration","phase","d","t","card","icon","title","actions","button","labelText","primary","onClick","b","spin","wasNoFill","message","_b","s","c","installRewardedUnlock"],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
var f = Object.defineProperty;
|
|
2
|
+
var x = (o, t, e) => t in o ? f(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
|
|
3
|
+
var a = (o, t, e) => x(o, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { f as v } from "./player-D2_HRzot.js";
|
|
5
|
+
class b {
|
|
6
|
+
constructor(t, e) {
|
|
7
|
+
a(this, "chapters", []);
|
|
8
|
+
a(this, "chapterEls", []);
|
|
9
|
+
a(this, "hoverIndex", -1);
|
|
10
|
+
a(this, "tooltipEl");
|
|
11
|
+
a(this, "titleEl");
|
|
12
|
+
a(this, "timeEl");
|
|
13
|
+
a(this, "onLoadedMetadata", () => {
|
|
14
|
+
const t = this.ctx.videoEl.duration;
|
|
15
|
+
!Number.isFinite(t) || t <= 0 || (this.chapters = g(this.segments, t), this.chapterEls = this.ctx.seekBar.setChapters(
|
|
16
|
+
this.chapters.map((e) => ({ start: e.start / t, end: e.end / t, color: e.color }))
|
|
17
|
+
));
|
|
18
|
+
});
|
|
19
|
+
a(this, "onPointerMove", (t) => {
|
|
20
|
+
var d, m;
|
|
21
|
+
const e = this.ctx.videoEl.duration;
|
|
22
|
+
if (!this.chapters.length || !Number.isFinite(e) || e <= 0) return;
|
|
23
|
+
const s = this.ctx.seekBar.ratioAtClientX(t.clientX) * e;
|
|
24
|
+
let r = this.chapters.findIndex((u) => s < u.end);
|
|
25
|
+
r === -1 && (r = this.chapters.length - 1), this.setHover(r);
|
|
26
|
+
const i = this.chapters[r];
|
|
27
|
+
this.titleEl.textContent = i.text ?? "", this.titleEl.style.display = i.text ? "" : "none";
|
|
28
|
+
const n = (m = (d = this.ctx.seekBar).markerLabelAt) == null ? void 0 : m.call(d, t.clientX);
|
|
29
|
+
this.timeEl.textContent = n ? `${n} · ${v(s)}` : v(s);
|
|
30
|
+
const l = this.ctx.seekBar.el.querySelector('[part="sprite-tooltip"]'), h = l && l.hasAttribute("data-visible") && l.offsetHeight > 0 ? l.offsetHeight + 8 : 0;
|
|
31
|
+
this.tooltipEl.style.bottom = h ? `calc(100% + 6px + ${h}px)` : "", this.timeEl.style.display = h ? "none" : "";
|
|
32
|
+
const p = this.ctx.seekBar.el.getBoundingClientRect();
|
|
33
|
+
this.tooltipEl.setAttribute("data-visible", "");
|
|
34
|
+
const c = this.tooltipEl.offsetWidth, E = Math.min(Math.max(t.clientX - p.left - c / 2, 0), Math.max(p.width - c, 0));
|
|
35
|
+
this.tooltipEl.style.transform = `translateX(${E}px)`;
|
|
36
|
+
});
|
|
37
|
+
a(this, "onPointerLeave", () => {
|
|
38
|
+
this.setHover(-1), this.tooltipEl.removeAttribute("data-visible");
|
|
39
|
+
});
|
|
40
|
+
this.ctx = t, this.segments = e, this.tooltipEl = document.createElement("div"), this.tooltipEl.className = "hp-chapter-tooltip", this.tooltipEl.setAttribute("part", "segment-tooltip"), this.titleEl = document.createElement("div"), this.titleEl.className = "hp-chapter-tooltip-title", this.timeEl = document.createElement("div"), this.timeEl.className = "hp-chapter-tooltip-time", this.tooltipEl.append(this.titleEl, this.timeEl), t.seekBar.el.appendChild(this.tooltipEl), t.seekBar.suppressHoverTime("segments", !0), t.seekBar.el.addEventListener("pointermove", this.onPointerMove), t.seekBar.el.addEventListener("pointerleave", this.onPointerLeave), t.videoEl.addEventListener("loadedmetadata", this.onLoadedMetadata), t.videoEl.readyState >= 1 && this.onLoadedMetadata();
|
|
41
|
+
}
|
|
42
|
+
destroy() {
|
|
43
|
+
this.ctx.videoEl.removeEventListener("loadedmetadata", this.onLoadedMetadata), this.ctx.seekBar.el.removeEventListener("pointermove", this.onPointerMove), this.ctx.seekBar.el.removeEventListener("pointerleave", this.onPointerLeave), this.ctx.seekBar.clearChapters(), this.ctx.seekBar.suppressHoverTime("segments", !1), this.tooltipEl.remove(), this.chapterEls = [], this.chapters = [];
|
|
44
|
+
}
|
|
45
|
+
setHover(t) {
|
|
46
|
+
var e, s;
|
|
47
|
+
t !== this.hoverIndex && ((e = this.chapterEls[this.hoverIndex]) == null || e.removeAttribute("data-hover"), this.hoverIndex = t, (s = this.chapterEls[t]) == null || s.setAttribute("data-hover", ""));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function g(o, t) {
|
|
51
|
+
const e = o.filter((i) => Number.isFinite(i.start) && i.start < t).slice().sort((i, n) => i.start - n.start), s = [];
|
|
52
|
+
let r = 0;
|
|
53
|
+
for (const i of e) {
|
|
54
|
+
const n = Math.max(i.start, r), l = Math.min(Number.isFinite(i.end) ? i.end : t, t);
|
|
55
|
+
l <= n || (n > r && s.push({ start: r, end: n }), s.push({ start: n, end: l, text: i.text, color: i.color }), r = l);
|
|
56
|
+
}
|
|
57
|
+
return s.length ? (r < t && (s[s.length - 1].end = t), s) : [];
|
|
58
|
+
}
|
|
59
|
+
function L(o, t) {
|
|
60
|
+
return new b(o, t);
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
b as Segments,
|
|
64
|
+
L as installSegments
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=segments-Ds-c1b5e.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments-Ds-c1b5e.js","sources":["../../src/plugins/segments/Segments.ts","../../src/plugins/segments/index.ts"],"sourcesContent":["import type { SegmentItem } from '../../types';\nimport type { SeekBarChapterRange } from '../../controls/SeekBar';\nimport { formatTime } from '../../utils/format-time';\n\nexport interface SegmentsPlayerContext {\n videoEl: HTMLVideoElement;\n /** Chapter modunu destekleyen seek bar — parçalara bölme/zaman eşlemesi onda. */\n seekBar: {\n readonly el: HTMLElement;\n setChapters(ranges: SeekBarChapterRange[]): HTMLElement[];\n suppressHoverTime(key: string, suppressed: boolean): void;\n clearChapters(): void;\n ratioAtClientX(clientX: number): number;\n markerLabelAt?(clientX: number): string | null;\n };\n}\n\ninterface Chapter {\n start: number;\n end: number;\n text?: string;\n color?: string;\n}\n\n/**\n * YouTube tarzı bölümler: seek bar parçalara bölünür (SeekBar.setChapters), hover'da bölüm adı + zaman.\n * Zaman çizgisi her zaman tam kaplanır (boşluklar adsız bölüm, son bölüm sona uzar).\n */\nexport class Segments {\n private chapters: Chapter[] = [];\n private chapterEls: HTMLElement[] = [];\n private hoverIndex = -1;\n private readonly tooltipEl: HTMLDivElement;\n private readonly titleEl: HTMLDivElement;\n private readonly timeEl: HTMLDivElement;\n\n constructor(\n private readonly ctx: SegmentsPlayerContext,\n private readonly segments: SegmentItem[]\n ) {\n this.tooltipEl = document.createElement('div');\n this.tooltipEl.className = 'hp-chapter-tooltip';\n this.tooltipEl.setAttribute('part', 'segment-tooltip');\n this.titleEl = document.createElement('div');\n this.titleEl.className = 'hp-chapter-tooltip-title';\n this.timeEl = document.createElement('div');\n this.timeEl.className = 'hp-chapter-tooltip-time';\n this.tooltipEl.append(this.titleEl, this.timeEl);\n ctx.seekBar.el.appendChild(this.tooltipEl);\n // Popup zamanı zaten gösteriyor — seek bar'ın varsayılan hover zamanı ikinci kez yazmasın.\n ctx.seekBar.suppressHoverTime('segments', true);\n\n ctx.seekBar.el.addEventListener('pointermove', this.onPointerMove);\n ctx.seekBar.el.addEventListener('pointerleave', this.onPointerLeave);\n ctx.videoEl.addEventListener('loadedmetadata', this.onLoadedMetadata);\n if (ctx.videoEl.readyState >= 1) this.onLoadedMetadata();\n }\n\n destroy(): void {\n this.ctx.videoEl.removeEventListener('loadedmetadata', this.onLoadedMetadata);\n this.ctx.seekBar.el.removeEventListener('pointermove', this.onPointerMove);\n this.ctx.seekBar.el.removeEventListener('pointerleave', this.onPointerLeave);\n this.ctx.seekBar.clearChapters();\n this.ctx.seekBar.suppressHoverTime('segments', false);\n this.tooltipEl.remove();\n this.chapterEls = [];\n this.chapters = [];\n }\n\n private readonly onLoadedMetadata = (): void => {\n const duration = this.ctx.videoEl.duration;\n if (!Number.isFinite(duration) || duration <= 0) return;\n\n this.chapters = buildChapters(this.segments, duration);\n this.chapterEls = this.ctx.seekBar.setChapters(\n this.chapters.map((c) => ({ start: c.start / duration, end: c.end / duration, color: c.color }))\n );\n };\n\n private readonly onPointerMove = (e: PointerEvent): void => {\n const duration = this.ctx.videoEl.duration;\n if (!this.chapters.length || !Number.isFinite(duration) || duration <= 0) return;\n\n const time = this.ctx.seekBar.ratioAtClientX(e.clientX) * duration;\n let index = this.chapters.findIndex((c) => time < c.end);\n if (index === -1) index = this.chapters.length - 1;\n this.setHover(index);\n\n const chapter = this.chapters[index]!;\n this.titleEl.textContent = chapter.text ?? '';\n this.titleEl.style.display = chapter.text ? '' : 'none';\n const label = this.ctx.seekBar.markerLabelAt?.(e.clientX);\n this.timeEl.textContent = label ? `${label} · ${formatTime(time)}` : formatTime(time);\n\n // sprite-thumbnails önizlemesi de seek bar'ın hemen üstünde açılıyor —\n // görünürse popup onun ÜSTÜNE çıkıyor (üst üste binmesin).\n const sprite = this.ctx.seekBar.el.querySelector<HTMLElement>('[part=\"sprite-tooltip\"]');\n const spriteH = sprite && sprite.hasAttribute('data-visible') && sprite.offsetHeight > 0 ? sprite.offsetHeight + 8 : 0;\n this.tooltipEl.style.bottom = spriteH ? `calc(100% + 6px + ${spriteH}px)` : '';\n // Sprite önizlemesi zamanı zaten kendi altında gösteriyor — aynı zaman iki kez yazılmasın.\n this.timeEl.style.display = spriteH ? 'none' : '';\n\n // Popup imleci ortalar ama seek bar kenarlarından taşmaz.\n const barRect = this.ctx.seekBar.el.getBoundingClientRect();\n this.tooltipEl.setAttribute('data-visible', '');\n const tipWidth = this.tooltipEl.offsetWidth;\n const x = Math.min(Math.max(e.clientX - barRect.left - tipWidth / 2, 0), Math.max(barRect.width - tipWidth, 0));\n this.tooltipEl.style.transform = `translateX(${x}px)`;\n };\n\n private readonly onPointerLeave = (): void => {\n this.setHover(-1);\n this.tooltipEl.removeAttribute('data-visible');\n };\n\n private setHover(index: number): void {\n if (index === this.hoverIndex) return;\n this.chapterEls[this.hoverIndex]?.removeAttribute('data-hover');\n this.hoverIndex = index;\n this.chapterEls[index]?.setAttribute('data-hover', '');\n }\n}\n\n/** Segmentleri sıralar, boşlukları adsız bölümle doldurur, son bölümü video sonuna uzatır — sonuç 0→duration'ı kesintisiz kaplar. */\nfunction buildChapters(segments: SegmentItem[], duration: number): Chapter[] {\n const sorted = segments\n .filter((s) => Number.isFinite(s.start) && s.start < duration)\n .slice()\n .sort((a, b) => a.start - b.start);\n\n const chapters: Chapter[] = [];\n let cursor = 0;\n for (const seg of sorted) {\n const start = Math.max(seg.start, cursor);\n const end = Math.min(Number.isFinite(seg.end) ? seg.end : duration, duration);\n if (end <= start) continue;\n if (start > cursor) chapters.push({ start: cursor, end: start });\n chapters.push({ start, end, text: seg.text, color: seg.color });\n cursor = end;\n }\n if (!chapters.length) return [];\n if (cursor < duration) chapters[chapters.length - 1]!.end = duration;\n return chapters;\n}\n","import { Segments, type SegmentsPlayerContext } from './Segments';\nimport type { SegmentItem } from '../../types';\n\nexport function installSegments(ctx: SegmentsPlayerContext, items: SegmentItem[]): Segments {\n return new Segments(ctx, items);\n}\n\nexport { Segments };\nexport type { SegmentsPlayerContext };\n"],"names":["Segments","ctx","segments","__publicField","duration","buildChapters","c","e","time","index","chapter","label","_b","_a","formatTime","sprite","spriteH","barRect","tipWidth","x","sorted","s","a","b","chapters","cursor","seg","start","end","installSegments","items"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var c = Object.defineProperty;
|
|
2
2
|
var p = (i, e, t) => e in i ? c(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
|
|
3
3
|
var h = (i, e, t) => p(i, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
-
import { c as m, v, d as b } from "./player-
|
|
4
|
+
import { c as m, v, d as b } from "./player-D2_HRzot.js";
|
|
5
5
|
const k = 0.25;
|
|
6
6
|
class g {
|
|
7
7
|
constructor(e, t) {
|
|
@@ -132,4 +132,4 @@ export {
|
|
|
132
132
|
g as SkipSegments,
|
|
133
133
|
S as skipSegmentsPlugin
|
|
134
134
|
};
|
|
135
|
-
//# sourceMappingURL=skipSegments-
|
|
135
|
+
//# sourceMappingURL=skipSegments-ByNoF1qZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skipSegments-BbWzPpXz.js","sources":["../../src/plugins/skip-segments/SkipSegments.ts","../../src/plugins/skip-segments/index.ts"],"sourcesContent":["import type { SkipSegment, SkipSegmentType } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { createIcon } from '../../icons/Icon';\nimport { vodSeekTarget } from '../../utils/seek-by';\n\nexport interface SkipSegmentsPlayerContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n overlayContainerEl: HTMLElement;\n isAdActive(): boolean;\n i18n: HopeLocaleStrings;\n}\n\n/** Bölüm sonuna bu kadar kala buton kalkar — sona yaklaşırken bir an görünüp kaybolmasın. */\nconst END_MARGIN_SEC = 0.25;\n\ninterface Active {\n index: number;\n segment: SkipSegment;\n end: number;\n /** Butonun göründüğü video zamanı — `hideAfter` / `autoSkip` geri sayımı video zamanıyla işler (duraklatınca durur). */\n shownAt: number;\n /** Kullanıcı bölüme sararak girdi ya da bölüm içinde geri sardı → bu gösterimde otomatik atlama yok. */\n autoCancelled: boolean;\n}\n\n/**\n * \"İntroyu atla\" / \"Özeti atla\" / \"Jeneriği atla\": bölüm oynarken köşede bir buton, basınca bölümün sonuna atlar.\n * `autoSkip` ile basılmadan (isteğe bağlı geri sayımla) atlar; `hideAfter` ile bir süre sonra çekilir, kontroller\n * açılınca geri gelir. Reklam sırasında görünmez. `hp:skip` (`skip`) iptal edilebilir.\n */\nexport class SkipSegments {\n private active: Active | null = null;\n private button: HTMLButtonElement | null = null;\n private labelEl: HTMLSpanElement | null = null;\n /** Kullanıcının (bizim değil) yaptığı sarma — bir sonraki timeupdate'te işlenir. */\n private userSeeked = false;\n private ownSeek = false;\n\n constructor(\n private readonly ctx: SkipSegmentsPlayerContext,\n private readonly segments: SkipSegment[]\n ) {\n const v = ctx.videoEl;\n v.addEventListener('timeupdate', this.update);\n v.addEventListener('seeking', this.onSeeking);\n v.addEventListener('seeked', this.update);\n v.addEventListener('loadstart', this.onSourceChange);\n ctx.hostEl.addEventListener('hp:adstart', this.update);\n ctx.hostEl.addEventListener('hp:adend', this.update);\n this.update();\n }\n\n destroy(): void {\n const v = this.ctx.videoEl;\n v.removeEventListener('timeupdate', this.update);\n v.removeEventListener('seeking', this.onSeeking);\n v.removeEventListener('seeked', this.update);\n v.removeEventListener('loadstart', this.onSourceChange);\n this.ctx.hostEl.removeEventListener('hp:adstart', this.update);\n this.ctx.hostEl.removeEventListener('hp:adend', this.update);\n this.hide();\n }\n\n refreshLabels(): void {\n if (this.active && this.labelEl) this.labelEl.textContent = this.label(this.active.segment);\n }\n\n private label(s: SkipSegment): string {\n if (s.label) return s.label;\n const t = this.ctx.i18n;\n const byType: Record<SkipSegmentType, string> = { intro: t.skipIntro, recap: t.skipRecap, credits: t.skipCredits, custom: t.skipSegment };\n return byType[s.type ?? 'intro'] ?? t.skipSegment;\n }\n\n /** Bölümün sonu: `end` yoksa videonun sonu (süre bilinmiyorsa bölüm yok sayılır). */\n private endOf(s: SkipSegment): number | null {\n if (Number.isFinite(s.end)) return s.end!;\n const d = this.ctx.videoEl.duration;\n return Number.isFinite(d) && d > 0 ? d : null;\n }\n\n private readonly onSeeking = (): void => {\n if (this.ownSeek) this.ownSeek = false;\n else this.userSeeked = true;\n };\n\n private readonly onSourceChange = (): void => {\n this.hide();\n this.userSeeked = false;\n };\n\n private readonly update = (): void => {\n const v = this.ctx.videoEl;\n const t = v.currentTime;\n const seeked = this.userSeeked;\n this.userSeeked = false;\n\n let found: { index: number; segment: SkipSegment; end: number } | null = null;\n if (!this.ctx.isAdActive()) {\n for (let i = 0; i < this.segments.length; i++) {\n const s = this.segments[i]!;\n const end = this.endOf(s);\n if (end === null || !Number.isFinite(s.start)) continue;\n const from = Math.max(s.start, Number.isFinite(s.showFrom) ? s.showFrom! : s.start);\n const until = Number.isFinite(s.showUntil) ? Math.min(s.showUntil!, end) : end;\n if (t >= from && t < until - END_MARGIN_SEC) {\n found = { index: i, segment: s, end };\n break;\n }\n }\n }\n\n if (!found) {\n this.hide();\n return;\n }\n if (this.active?.index !== found.index) {\n this.hide();\n this.active = { ...found, shownAt: t, autoCancelled: seeked };\n this.show();\n this.emit('shown');\n } else if (seeked) {\n // Bölüm içinde sarma: geri sardıysa (kullanıcı bölümü izlemek istiyor) otomatik atlama bu gösterimde kapanır.\n this.active.autoCancelled = true;\n this.active.shownAt = Math.min(this.active.shownAt, t);\n }\n this.tick(t);\n };\n\n /** `hideAfter` (çekilme) ve `autoSkip` geri sayımı. */\n private tick(t: number): void {\n const a = this.active;\n if (!a || !this.button) return;\n const elapsed = Math.max(0, t - a.shownAt);\n const hideAfter = a.segment.hideAfter ?? 0;\n this.button.toggleAttribute('data-faded', hideAfter > 0 && elapsed >= hideAfter);\n\n const auto = a.segment.autoSkip;\n if (!auto || a.autoCancelled) {\n this.button.removeAttribute('data-auto');\n return;\n }\n const delay = auto === true ? 0 : Math.max(0, auto);\n if (elapsed >= delay) {\n this.skip('auto');\n return;\n }\n this.button.setAttribute('data-auto', '');\n this.button.style.setProperty('--hp-skip-progress', String(delay ? elapsed / delay : 1));\n }\n\n private show(): void {\n const a = this.active!;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hp-skip-segment';\n btn.setAttribute('part', 'skip-segment');\n btn.setAttribute('data-position', a.segment.position ?? 'bottom-right');\n btn.setAttribute('data-type', a.segment.type ?? 'intro');\n const label = document.createElement('span');\n label.className = 'hp-skip-segment-label';\n label.textContent = this.label(a.segment);\n btn.append(label, createIcon('skip-forward', 'hp-skip-segment-icon'));\n btn.addEventListener('click', () => this.skip('click'));\n // Oynat/duraklat ve çift tık tam ekran alttaki video alanına geçmesin.\n for (const ev of ['pointerdown', 'pointerup', 'click', 'dblclick'] as const) btn.addEventListener(ev, (e) => e.stopPropagation());\n this.ctx.overlayContainerEl.appendChild(btn);\n this.button = btn;\n this.labelEl = label;\n }\n\n private hide(): void {\n this.button?.remove();\n this.button = null;\n this.labelEl = null;\n this.active = null;\n }\n\n private emit(state: 'shown' | 'skip', reason?: 'click' | 'auto'): boolean {\n const a = this.active!;\n return this.ctx.hostEl.dispatchEvent(\n new CustomEvent('hp:skip', {\n detail: { state, type: a.segment.type ?? 'intro', start: a.segment.start, end: a.end, reason },\n cancelable: state === 'skip',\n })\n );\n }\n\n private skip(reason: 'click' | 'auto'): void {\n const a = this.active;\n if (!a) return;\n const focused = !!this.button?.matches(':focus');\n if (!this.emit('skip', reason)) {\n // Entegratör kendisi halletti — bu gösterim için otomatik atlama tekrar tetiklenmesin.\n a.autoCancelled = true;\n this.button?.removeAttribute('data-auto');\n return;\n }\n const v = this.ctx.videoEl;\n this.hide();\n this.ownSeek = true;\n v.currentTime = vodSeekTarget(v, a.end);\n // Klavyeyle basıldıysa odak kaybolmasın — player'a dön (kısayollar çalışmaya devam etsin).\n if (focused) this.ctx.hostEl.focus({ preventScroll: true });\n }\n}\n","import { SkipSegments, type SkipSegmentsPlayerContext } from './SkipSegments';\nimport type { SkipSegment } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { definePlugin } from '../../plugin-api/registry';\n\nexport function installSkipSegments(ctx: SkipSegmentsPlayerContext, segments: SkipSegment[]): SkipSegments {\n return new SkipSegments(ctx, segments);\n}\n\n/** \"İntroyu atla\", herkese açık eklenti API'si üzerinden. */\nexport const skipSegmentsPlugin = definePlugin<SkipSegment[]>({\n name: 'hope:skip-segments',\n setup(player, segments) {\n const layer = player.ui.addLayer({ position: 'fill' });\n const skip = new SkipSegments(\n {\n hostEl: player.element,\n videoEl: player.video,\n overlayContainerEl: layer.el,\n isAdActive: () => player.isAdPlaying,\n i18n: player.labels as unknown as HopeLocaleStrings,\n },\n segments\n );\n player.onLocaleChange(() => skip.refreshLabels());\n return () => skip.destroy();\n },\n});\n\nexport { SkipSegments };\nexport type { SkipSegmentsPlayerContext };\n"],"names":["END_MARGIN_SEC","SkipSegments","ctx","segments","__publicField","seeked","found","i","s","end","from","until","_a","v","d","t","a","elapsed","hideAfter","auto","delay","btn","label","createIcon","ev","e","state","reason","focused","_b","vodSeekTarget","skipSegmentsPlugin","definePlugin","player","layer","skip"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skipSegments-ByNoF1qZ.js","sources":["../../src/plugins/skip-segments/SkipSegments.ts","../../src/plugins/skip-segments/index.ts"],"sourcesContent":["import type { SkipSegment, SkipSegmentType } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { createIcon } from '../../icons/Icon';\nimport { vodSeekTarget } from '../../utils/seek-by';\n\nexport interface SkipSegmentsPlayerContext {\n hostEl: HTMLElement;\n videoEl: HTMLVideoElement;\n overlayContainerEl: HTMLElement;\n isAdActive(): boolean;\n i18n: HopeLocaleStrings;\n}\n\n/** Bölüm sonuna bu kadar kala buton kalkar — sona yaklaşırken bir an görünüp kaybolmasın. */\nconst END_MARGIN_SEC = 0.25;\n\ninterface Active {\n index: number;\n segment: SkipSegment;\n end: number;\n /** Butonun göründüğü video zamanı — `hideAfter` / `autoSkip` geri sayımı video zamanıyla işler (duraklatınca durur). */\n shownAt: number;\n /** Kullanıcı bölüme sararak girdi ya da bölüm içinde geri sardı → bu gösterimde otomatik atlama yok. */\n autoCancelled: boolean;\n}\n\n/**\n * \"İntroyu atla\" / \"Özeti atla\" / \"Jeneriği atla\": bölüm oynarken köşede bir buton, basınca bölümün sonuna atlar.\n * `autoSkip` ile basılmadan (isteğe bağlı geri sayımla) atlar; `hideAfter` ile bir süre sonra çekilir, kontroller\n * açılınca geri gelir. Reklam sırasında görünmez. `hp:skip` (`skip`) iptal edilebilir.\n */\nexport class SkipSegments {\n private active: Active | null = null;\n private button: HTMLButtonElement | null = null;\n private labelEl: HTMLSpanElement | null = null;\n /** Kullanıcının (bizim değil) yaptığı sarma — bir sonraki timeupdate'te işlenir. */\n private userSeeked = false;\n private ownSeek = false;\n\n constructor(\n private readonly ctx: SkipSegmentsPlayerContext,\n private readonly segments: SkipSegment[]\n ) {\n const v = ctx.videoEl;\n v.addEventListener('timeupdate', this.update);\n v.addEventListener('seeking', this.onSeeking);\n v.addEventListener('seeked', this.update);\n v.addEventListener('loadstart', this.onSourceChange);\n ctx.hostEl.addEventListener('hp:adstart', this.update);\n ctx.hostEl.addEventListener('hp:adend', this.update);\n this.update();\n }\n\n destroy(): void {\n const v = this.ctx.videoEl;\n v.removeEventListener('timeupdate', this.update);\n v.removeEventListener('seeking', this.onSeeking);\n v.removeEventListener('seeked', this.update);\n v.removeEventListener('loadstart', this.onSourceChange);\n this.ctx.hostEl.removeEventListener('hp:adstart', this.update);\n this.ctx.hostEl.removeEventListener('hp:adend', this.update);\n this.hide();\n }\n\n refreshLabels(): void {\n if (this.active && this.labelEl) this.labelEl.textContent = this.label(this.active.segment);\n }\n\n private label(s: SkipSegment): string {\n if (s.label) return s.label;\n const t = this.ctx.i18n;\n const byType: Record<SkipSegmentType, string> = { intro: t.skipIntro, recap: t.skipRecap, credits: t.skipCredits, custom: t.skipSegment };\n return byType[s.type ?? 'intro'] ?? t.skipSegment;\n }\n\n /** Bölümün sonu: `end` yoksa videonun sonu (süre bilinmiyorsa bölüm yok sayılır). */\n private endOf(s: SkipSegment): number | null {\n if (Number.isFinite(s.end)) return s.end!;\n const d = this.ctx.videoEl.duration;\n return Number.isFinite(d) && d > 0 ? d : null;\n }\n\n private readonly onSeeking = (): void => {\n if (this.ownSeek) this.ownSeek = false;\n else this.userSeeked = true;\n };\n\n private readonly onSourceChange = (): void => {\n this.hide();\n this.userSeeked = false;\n };\n\n private readonly update = (): void => {\n const v = this.ctx.videoEl;\n const t = v.currentTime;\n const seeked = this.userSeeked;\n this.userSeeked = false;\n\n let found: { index: number; segment: SkipSegment; end: number } | null = null;\n if (!this.ctx.isAdActive()) {\n for (let i = 0; i < this.segments.length; i++) {\n const s = this.segments[i]!;\n const end = this.endOf(s);\n if (end === null || !Number.isFinite(s.start)) continue;\n const from = Math.max(s.start, Number.isFinite(s.showFrom) ? s.showFrom! : s.start);\n const until = Number.isFinite(s.showUntil) ? Math.min(s.showUntil!, end) : end;\n if (t >= from && t < until - END_MARGIN_SEC) {\n found = { index: i, segment: s, end };\n break;\n }\n }\n }\n\n if (!found) {\n this.hide();\n return;\n }\n if (this.active?.index !== found.index) {\n this.hide();\n this.active = { ...found, shownAt: t, autoCancelled: seeked };\n this.show();\n this.emit('shown');\n } else if (seeked) {\n // Bölüm içinde sarma: geri sardıysa (kullanıcı bölümü izlemek istiyor) otomatik atlama bu gösterimde kapanır.\n this.active.autoCancelled = true;\n this.active.shownAt = Math.min(this.active.shownAt, t);\n }\n this.tick(t);\n };\n\n /** `hideAfter` (çekilme) ve `autoSkip` geri sayımı. */\n private tick(t: number): void {\n const a = this.active;\n if (!a || !this.button) return;\n const elapsed = Math.max(0, t - a.shownAt);\n const hideAfter = a.segment.hideAfter ?? 0;\n this.button.toggleAttribute('data-faded', hideAfter > 0 && elapsed >= hideAfter);\n\n const auto = a.segment.autoSkip;\n if (!auto || a.autoCancelled) {\n this.button.removeAttribute('data-auto');\n return;\n }\n const delay = auto === true ? 0 : Math.max(0, auto);\n if (elapsed >= delay) {\n this.skip('auto');\n return;\n }\n this.button.setAttribute('data-auto', '');\n this.button.style.setProperty('--hp-skip-progress', String(delay ? elapsed / delay : 1));\n }\n\n private show(): void {\n const a = this.active!;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hp-skip-segment';\n btn.setAttribute('part', 'skip-segment');\n btn.setAttribute('data-position', a.segment.position ?? 'bottom-right');\n btn.setAttribute('data-type', a.segment.type ?? 'intro');\n const label = document.createElement('span');\n label.className = 'hp-skip-segment-label';\n label.textContent = this.label(a.segment);\n btn.append(label, createIcon('skip-forward', 'hp-skip-segment-icon'));\n btn.addEventListener('click', () => this.skip('click'));\n // Oynat/duraklat ve çift tık tam ekran alttaki video alanına geçmesin.\n for (const ev of ['pointerdown', 'pointerup', 'click', 'dblclick'] as const) btn.addEventListener(ev, (e) => e.stopPropagation());\n this.ctx.overlayContainerEl.appendChild(btn);\n this.button = btn;\n this.labelEl = label;\n }\n\n private hide(): void {\n this.button?.remove();\n this.button = null;\n this.labelEl = null;\n this.active = null;\n }\n\n private emit(state: 'shown' | 'skip', reason?: 'click' | 'auto'): boolean {\n const a = this.active!;\n return this.ctx.hostEl.dispatchEvent(\n new CustomEvent('hp:skip', {\n detail: { state, type: a.segment.type ?? 'intro', start: a.segment.start, end: a.end, reason },\n cancelable: state === 'skip',\n })\n );\n }\n\n private skip(reason: 'click' | 'auto'): void {\n const a = this.active;\n if (!a) return;\n const focused = !!this.button?.matches(':focus');\n if (!this.emit('skip', reason)) {\n // Entegratör kendisi halletti — bu gösterim için otomatik atlama tekrar tetiklenmesin.\n a.autoCancelled = true;\n this.button?.removeAttribute('data-auto');\n return;\n }\n const v = this.ctx.videoEl;\n this.hide();\n this.ownSeek = true;\n v.currentTime = vodSeekTarget(v, a.end);\n // Klavyeyle basıldıysa odak kaybolmasın — player'a dön (kısayollar çalışmaya devam etsin).\n if (focused) this.ctx.hostEl.focus({ preventScroll: true });\n }\n}\n","import { SkipSegments, type SkipSegmentsPlayerContext } from './SkipSegments';\nimport type { SkipSegment } from '../../types';\nimport type { HopeLocaleStrings } from '../../i18n/types';\nimport { definePlugin } from '../../plugin-api/registry';\n\nexport function installSkipSegments(ctx: SkipSegmentsPlayerContext, segments: SkipSegment[]): SkipSegments {\n return new SkipSegments(ctx, segments);\n}\n\n/** \"İntroyu atla\", herkese açık eklenti API'si üzerinden. */\nexport const skipSegmentsPlugin = definePlugin<SkipSegment[]>({\n name: 'hope:skip-segments',\n setup(player, segments) {\n const layer = player.ui.addLayer({ position: 'fill' });\n const skip = new SkipSegments(\n {\n hostEl: player.element,\n videoEl: player.video,\n overlayContainerEl: layer.el,\n isAdActive: () => player.isAdPlaying,\n i18n: player.labels as unknown as HopeLocaleStrings,\n },\n segments\n );\n player.onLocaleChange(() => skip.refreshLabels());\n return () => skip.destroy();\n },\n});\n\nexport { SkipSegments };\nexport type { SkipSegmentsPlayerContext };\n"],"names":["END_MARGIN_SEC","SkipSegments","ctx","segments","__publicField","seeked","found","i","s","end","from","until","_a","v","d","t","a","elapsed","hideAfter","auto","delay","btn","label","createIcon","ev","e","state","reason","focused","_b","vodSeekTarget","skipSegmentsPlugin","definePlugin","player","layer","skip"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
var E = Object.defineProperty;
|
|
2
|
-
var y = (
|
|
3
|
-
var l = (
|
|
4
|
-
import { f as
|
|
5
|
-
const
|
|
6
|
-
class
|
|
2
|
+
var y = (u, t, e) => t in u ? E(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
|
|
3
|
+
var l = (u, t, e) => y(u, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { f as v } from "./player-D2_HRzot.js";
|
|
5
|
+
const x = 8, g = /%(0(\d+))?d/;
|
|
6
|
+
class S {
|
|
7
7
|
constructor(t, e) {
|
|
8
8
|
l(this, "tooltip");
|
|
9
9
|
l(this, "imageEl");
|
|
@@ -13,6 +13,10 @@ class M {
|
|
|
13
13
|
l(this, "vttLoading", null);
|
|
14
14
|
/** Çok parçalı modda otomatik hesaplanan sheet süresi (ilk sheet yüklenince). */
|
|
15
15
|
l(this, "derivedSheetDuration", null);
|
|
16
|
+
/** `lowRes` sheet'i — LRU dışında, hep bellekte. */
|
|
17
|
+
l(this, "lowSheet", null);
|
|
18
|
+
/** Son çizilen asıl karenin genişliği (VTT'de `width` yok). */
|
|
19
|
+
l(this, "lastFrameWidth", 0);
|
|
16
20
|
l(this, "warmed", !1);
|
|
17
21
|
l(this, "hovering", !1);
|
|
18
22
|
l(this, "lastClientX", 0);
|
|
@@ -30,8 +34,9 @@ class M {
|
|
|
30
34
|
});
|
|
31
35
|
/** İlk ihtiyaç anında (hover / oynatma) kaynağı hazırla — kurulumda hiçbir şey indirilmiyor. */
|
|
32
36
|
l(this, "warm", () => {
|
|
37
|
+
var i;
|
|
33
38
|
if (this.warmed || this.destroyed) return;
|
|
34
|
-
if (this.warmed = !0, this.options.vtt) {
|
|
39
|
+
if (this.warmed = !0, (i = this.options.lowRes) != null && i.url && (this.lowSheet = this.createSheet(this.options.lowRes.url, () => this.hovering && this.scheduleRender())), this.options.vtt) {
|
|
35
40
|
this.loadVtt();
|
|
36
41
|
return;
|
|
37
42
|
}
|
|
@@ -43,7 +48,7 @@ class M {
|
|
|
43
48
|
destroy() {
|
|
44
49
|
this.destroyed = !0, this.rafId !== null && cancelAnimationFrame(this.rafId), this.ctx.seekBar.el.removeEventListener("pointerenter", this.onPointerEnter), this.ctx.seekBar.el.removeEventListener("pointermove", this.onPointerMove), this.ctx.seekBar.el.removeEventListener("pointerleave", this.onPointerLeave), this.ctx.videoEl.removeEventListener("play", this.warm), this.tooltip.remove(), this.ctx.seekBar.suppressHoverTime("sprite", !1);
|
|
45
50
|
for (const t of this.sheets.values()) t.img.src = "";
|
|
46
|
-
this.sheets.clear();
|
|
51
|
+
this.lowSheet && (this.lowSheet.img.src = ""), this.sheets.clear();
|
|
47
52
|
}
|
|
48
53
|
scheduleRender() {
|
|
49
54
|
this.rafId === null && (this.rafId = requestAnimationFrame(() => {
|
|
@@ -52,18 +57,21 @@ class M {
|
|
|
52
57
|
}
|
|
53
58
|
// ── çizim ──
|
|
54
59
|
render() {
|
|
60
|
+
var d, p, f;
|
|
55
61
|
if (!this.hovering || this.destroyed) return;
|
|
56
62
|
const t = this.ctx.videoEl.duration;
|
|
57
63
|
if (!Number.isFinite(t) || t <= 0) return;
|
|
58
|
-
const e = this.ctx.seekBar.ratioAtClientX(this.lastClientX) * t;
|
|
59
|
-
this.timeEl.textContent =
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
const e = this.ctx.seekBar.ratioAtClientX(this.lastClientX) * t, i = (p = (d = this.ctx.seekBar).markerLabelAt) == null ? void 0 : p.call(d, this.lastClientX);
|
|
65
|
+
this.timeEl.textContent = i ? `${i} · ${v(e)}` : v(e);
|
|
66
|
+
const s = this.isNetworkEligible() ? this.frameAt(e, t) : null;
|
|
67
|
+
s && (this.lastFrameWidth = s.w);
|
|
68
|
+
const n = s ?? this.lowResFrameAt(e, t), r = s ? this.sheets.get(s.url).img : (f = this.lowSheet) == null ? void 0 : f.img;
|
|
69
|
+
if (n && r) {
|
|
70
|
+
const c = (this.options.displayWidth ?? (s ? s.w : this.options.width || this.lastFrameWidth || n.w)) * this.scale(), m = c / n.w;
|
|
71
|
+
this.imageEl.style.display = "", this.imageEl.toggleAttribute("data-lowres", !s), this.imageEl.style.width = `${c}px`, this.imageEl.style.height = `${n.h * m}px`, this.imageEl.style.backgroundImage = `url("${n.url}")`, this.imageEl.style.backgroundSize = `${r.naturalWidth * m}px ${r.naturalHeight * m}px`, this.imageEl.style.backgroundPosition = `${-n.x * m}px ${-n.y * m}px`;
|
|
64
72
|
} else this.imageEl.style.backgroundImage || (this.imageEl.style.display = "none");
|
|
65
73
|
this.tooltip.setAttribute("data-visible", "");
|
|
66
|
-
const
|
|
74
|
+
const o = this.ctx.seekBar.el.getBoundingClientRect(), a = this.tooltip.offsetWidth, h = Math.min(Math.max(this.lastClientX - o.left - a / 2, 0), Math.max(o.width - a, 0));
|
|
67
75
|
this.tooltip.style.transform = `translateX(${h}px)`;
|
|
68
76
|
}
|
|
69
77
|
scale() {
|
|
@@ -76,13 +84,21 @@ class M {
|
|
|
76
84
|
return e === void 0 || e >= (this.options.downlink ?? 2) || i;
|
|
77
85
|
}
|
|
78
86
|
// ── kare çözümleme ──
|
|
87
|
+
/** `lowRes` sheet'inden saniyedeki kare (hazır değilse null). */
|
|
88
|
+
lowResFrameAt(t, e) {
|
|
89
|
+
var h;
|
|
90
|
+
const i = this.options.lowRes, s = (h = this.lowSheet) != null && h.ready ? this.lowSheet.img : null;
|
|
91
|
+
if (!i || !s || !i.width || !i.height) return null;
|
|
92
|
+
const n = Math.max(1, Math.floor(s.naturalWidth / i.width)), r = n * Math.max(1, Math.floor(s.naturalHeight / i.height)), o = i.interval || e / r, a = Math.min(r - 1, Math.max(0, Math.floor(t / o)));
|
|
93
|
+
return { url: i.url, x: a % n * i.width, y: Math.floor(a / n) * i.height, w: i.width, h: i.height };
|
|
94
|
+
}
|
|
79
95
|
/** Saniyedeki kareyi döner; gereken sheet hazır değilse yüklemeyi başlatıp null döner (yüklenince render tekrar çağrılır). */
|
|
80
96
|
frameAt(t, e) {
|
|
81
97
|
return this.options.vtt ? this.vttFrameAt(t) : this.gridFrameAt(t, e);
|
|
82
98
|
}
|
|
83
99
|
isMultiSheet() {
|
|
84
100
|
var t;
|
|
85
|
-
return !!((t = this.options.sheets) != null && t.length) ||
|
|
101
|
+
return !!((t = this.options.sheets) != null && t.length) || g.test(this.options.url ?? "");
|
|
86
102
|
}
|
|
87
103
|
/** Tek sheet → Infinity (tüm video); çok parçalı → verilen ya da ilk sheet'ten hesaplanan süre; henüz bilinmiyorsa null. */
|
|
88
104
|
sheetDuration() {
|
|
@@ -100,7 +116,7 @@ class M {
|
|
|
100
116
|
var s;
|
|
101
117
|
if ((s = this.options.sheets) != null && s.length) return this.options.sheets[Math.min(t, this.options.sheets.length - 1)];
|
|
102
118
|
const e = this.options.url ?? "", i = t + (this.options.firstSheetIndex ?? 1);
|
|
103
|
-
return e.replace(
|
|
119
|
+
return e.replace(g, (n, r, o) => String(i).padStart(o ? Number(o) : 0, "0"));
|
|
104
120
|
}
|
|
105
121
|
gridFrameAt(t, e) {
|
|
106
122
|
const { width: i, height: s } = this.options;
|
|
@@ -108,14 +124,14 @@ class M {
|
|
|
108
124
|
const n = this.options.interval || 1, r = this.sheetDuration();
|
|
109
125
|
if (r === null)
|
|
110
126
|
return this.ensureSheet(this.sheetUrl(0)), null;
|
|
111
|
-
const
|
|
112
|
-
this.preloadAround(
|
|
113
|
-
const d = this.sheets.get(
|
|
127
|
+
const o = r === 1 / 0 ? 0 : this.sheetIndexAt(Math.max(0, e - 1e-3)), a = Math.min(this.sheetIndexAt(t), o), h = this.sheetUrl(a);
|
|
128
|
+
this.preloadAround(a, o);
|
|
129
|
+
const d = this.sheets.get(h);
|
|
114
130
|
if (!(d != null && d.ready))
|
|
115
|
-
return this.ensureSheet(
|
|
116
|
-
this.touch(
|
|
117
|
-
const
|
|
118
|
-
return { url:
|
|
131
|
+
return this.ensureSheet(h), null;
|
|
132
|
+
this.touch(h);
|
|
133
|
+
const p = Math.max(1, Math.floor(d.img.naturalWidth / i)), f = Math.max(1, Math.floor(d.img.naturalHeight / s)), c = r === 1 / 0 ? t : t - a * r, m = Math.min(Math.max(0, Math.floor(c / n)), p * f - 1);
|
|
134
|
+
return { url: h, x: m % p * i, y: Math.floor(m / p) * s, w: i, h: s };
|
|
119
135
|
}
|
|
120
136
|
preloadAround(t, e) {
|
|
121
137
|
const i = this.options.preloadSheets ?? 1;
|
|
@@ -129,23 +145,30 @@ class M {
|
|
|
129
145
|
if (!e.length) return null;
|
|
130
146
|
let i = 0, s = e.length - 1;
|
|
131
147
|
for (; i < s; ) {
|
|
132
|
-
const
|
|
133
|
-
e[
|
|
148
|
+
const h = i + s + 1 >> 1;
|
|
149
|
+
e[h].start <= t ? i = h : s = h - 1;
|
|
134
150
|
}
|
|
135
151
|
const n = e[i];
|
|
136
|
-
[e[i + 1], e[i - 1]].filter((
|
|
137
|
-
const
|
|
138
|
-
if (!(
|
|
152
|
+
[e[i + 1], e[i - 1]].filter((h) => !!h && h.url !== n.url).forEach((h) => void this.ensureSheet(h.url));
|
|
153
|
+
const o = this.sheets.get(n.url);
|
|
154
|
+
if (!(o != null && o.ready))
|
|
139
155
|
return this.ensureSheet(n.url), null;
|
|
140
156
|
this.touch(n.url);
|
|
141
|
-
const
|
|
142
|
-
return { url: n.url, ...
|
|
157
|
+
const a = n.rect ?? { x: 0, y: 0, w: o.img.naturalWidth, h: o.img.naturalHeight };
|
|
158
|
+
return { url: n.url, ...a };
|
|
143
159
|
}
|
|
144
160
|
// ── yükleme / cache ──
|
|
145
161
|
ensureSheet(t) {
|
|
146
162
|
if (!t) return Promise.resolve();
|
|
147
163
|
const e = this.sheets.get(t);
|
|
148
164
|
if (e) return e.promise;
|
|
165
|
+
const i = this.createSheet(t, (s) => {
|
|
166
|
+
this.learnSheetDuration(s), this.hovering && this.scheduleRender();
|
|
167
|
+
});
|
|
168
|
+
return this.sheets.set(t, i), this.evict(), i.promise;
|
|
169
|
+
}
|
|
170
|
+
/** Görseli yükler; decode bitmeden hazır sayılmaz (sheet geçişinde titreme olmasın). */
|
|
171
|
+
createSheet(t, e) {
|
|
149
172
|
const i = new Image();
|
|
150
173
|
i.decoding = "async";
|
|
151
174
|
const s = { img: i, ready: !1, failed: !1, promise: Promise.resolve() };
|
|
@@ -153,13 +176,13 @@ class M {
|
|
|
153
176
|
i.onload = () => {
|
|
154
177
|
const r = () => {
|
|
155
178
|
if (this.destroyed) return n();
|
|
156
|
-
s.ready = !0,
|
|
179
|
+
s.ready = !0, e(i), n();
|
|
157
180
|
};
|
|
158
181
|
i.decode ? i.decode().then(r, r) : r();
|
|
159
182
|
}, i.onerror = () => {
|
|
160
183
|
s.failed = !0, n();
|
|
161
184
|
};
|
|
162
|
-
}), i.src = t,
|
|
185
|
+
}), i.src = t, s;
|
|
163
186
|
}
|
|
164
187
|
/** Çok parçalı modda `sheetDuration` verilmediyse ilk yüklenen sheet'in ızgara kapasitesinden hesapla. */
|
|
165
188
|
learnSheetDuration(t) {
|
|
@@ -175,7 +198,7 @@ class M {
|
|
|
175
198
|
e && (this.sheets.delete(t), this.sheets.set(t, e));
|
|
176
199
|
}
|
|
177
200
|
evict() {
|
|
178
|
-
for (; this.sheets.size >
|
|
201
|
+
for (; this.sheets.size > x; ) {
|
|
179
202
|
const t = this.sheets.keys().next().value, e = this.sheets.get(t);
|
|
180
203
|
e.img.onload = null, e.img.onerror = null, this.sheets.delete(t);
|
|
181
204
|
}
|
|
@@ -187,39 +210,39 @@ class M {
|
|
|
187
210
|
if (!e.ok) throw new Error(`HTTP ${e.status}`);
|
|
188
211
|
return e.text();
|
|
189
212
|
}).then((e) => {
|
|
190
|
-
this.destroyed || (this.vttCues =
|
|
213
|
+
this.destroyed || (this.vttCues = M(e, new URL(t, document.baseURI).href), this.vttCues.length && this.ensureSheet(this.vttCues[0].url), this.hovering && this.scheduleRender());
|
|
191
214
|
}).catch((e) => {
|
|
192
215
|
console.warn("[HopePlayer sprite-thumbnails] VTT yüklenemedi:", e), this.vttCues = [];
|
|
193
216
|
}), this.vttLoading;
|
|
194
217
|
}
|
|
195
218
|
}
|
|
196
|
-
function
|
|
197
|
-
return
|
|
219
|
+
function w(u) {
|
|
220
|
+
return u.trim().split(":").map(Number).reduce((e, i) => e * 60 + i, 0);
|
|
198
221
|
}
|
|
199
|
-
function
|
|
222
|
+
function M(u, t) {
|
|
200
223
|
var s;
|
|
201
|
-
const e = [], i =
|
|
224
|
+
const e = [], i = u.replace(/\r/g, "").split(/\n\n+/);
|
|
202
225
|
for (const n of i) {
|
|
203
226
|
const r = n.split(`
|
|
204
|
-
`).filter(Boolean),
|
|
205
|
-
if (
|
|
206
|
-
const [
|
|
207
|
-
if (!
|
|
208
|
-
const [
|
|
227
|
+
`).filter(Boolean), o = r.findIndex((m) => m.includes("-->"));
|
|
228
|
+
if (o === -1) continue;
|
|
229
|
+
const [a, h] = r[o].split("-->"), d = (s = r[o + 1]) == null ? void 0 : s.trim();
|
|
230
|
+
if (!a || !h || !d) continue;
|
|
231
|
+
const [p, f] = d.split("#"), c = f == null ? void 0 : f.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
|
|
209
232
|
e.push({
|
|
210
|
-
start:
|
|
211
|
-
end:
|
|
212
|
-
url: new URL(
|
|
233
|
+
start: w(a),
|
|
234
|
+
end: w(h.trim().split(/\s+/)[0]),
|
|
235
|
+
url: new URL(p, t).href,
|
|
213
236
|
rect: c ? { x: +c[1], y: +c[2], w: +c[3], h: +c[4] } : null
|
|
214
237
|
});
|
|
215
238
|
}
|
|
216
239
|
return e.sort((n, r) => n.start - r.start);
|
|
217
240
|
}
|
|
218
|
-
function
|
|
219
|
-
return new
|
|
241
|
+
function A(u, t) {
|
|
242
|
+
return new S(u, t);
|
|
220
243
|
}
|
|
221
244
|
export {
|
|
222
|
-
|
|
223
|
-
|
|
245
|
+
S as SpriteThumbnails,
|
|
246
|
+
A as installSpriteThumbnails
|
|
224
247
|
};
|
|
225
|
-
//# sourceMappingURL=spriteThumbnails-
|
|
248
|
+
//# sourceMappingURL=spriteThumbnails-Cr9UmkM9.js.map
|