From 5e203e7e9841efb883863355b959c88ef501a5ea Mon Sep 17 00:00:00 2001 From: goon-foss Date: Fri, 16 Oct 2026 09:23:52 +0200 Subject: [PATCH] fix(mobile): zapas hls4 dla sextapes, przycisk OK w klawiaturze PIN-u sextapes: hls2 na zewnetrznym CDN dawal 502 albo byl blokowany filtrem DNS (Failed to connect ... [::]); resolver sprawdza manifest i przechodzi na hls4 z domeny embedu (segmenty to TS z doklejonym PNG, ExoPlayer je gra; sprawdzone na emulatorze). PIN: na TV w poziomie Cancel/Next byly pod krawedzia ekranu, OK siedzi teraz w pustym polu klawiatury. Co-Authored-By: Claude Opus 5.5 --- mobile/src/changelog.ts | 8 ++++++ mobile/src/lib/packerHoster.ts | 51 +++++++++++++++++++++++++++------ mobile/src/screens/PinEntry.tsx | 18 +++++++++++- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/mobile/src/changelog.ts b/mobile/src/changelog.ts index 6bcc472..ad9a60d 100644 --- a/mobile/src/changelog.ts +++ b/mobile/src/changelog.ts @@ -35,6 +35,14 @@ export type ChangelogEntry = { }; export const CHANGELOG: ChangelogEntry[] = [ + { + id: '2026-10-16a', + date: 'October 2026', + items: [ + 'xtapes movies fall back to a second stream when the first one fails or is blocked on your network.', + 'TV: setting a PIN works with the remote. An OK key now sits in the keypad, the Next button was below the edge of the screen.', + ], + }, { id: '2026-10-15e', date: 'October 2026', diff --git a/mobile/src/lib/packerHoster.ts b/mobile/src/lib/packerHoster.ts index 4ca90bc..c24300e 100644 --- a/mobile/src/lib/packerHoster.ts +++ b/mobile/src/lib/packerHoster.ts @@ -102,24 +102,59 @@ const AD_RE = /\/(?:preroll|midroll|postroll|preplay|ads?|advert|promo)\d*\.(?:m // (hls4) doklejony do domeny embedu. const LINKS_ENTRY_RE = /["']?(hls\d+)["']?\s*:\s*["']([^"']+\.m3u8[^"']*)["']/gi; -function linksObjectUrl(js: string, embedUrl: string): string | null { - let relative: string | null = null; +/** Kandydaci z obiektu `links`: najpierw pelne adresy (hls2, CDN), potem wzgledne (hls4, + * sciezka na domenie embedu) zamienione na pelne. */ +function linksObjectCandidates(js: string, embedUrl: string): string[] { + const absolute: string[] = []; + const relative: string[] = []; let m: RegExpExecArray | null; LINKS_ENTRY_RE.lastIndex = 0; while ((m = LINKS_ENTRY_RE.exec(js)) !== null) { const u = m[2]; if (AD_RE.test(u)) continue; - if (/^https?:\/\//i.test(u)) return u; - if (!relative && u.startsWith('/')) relative = u; + if (/^https?:\/\//i.test(u)) absolute.push(u); + else if (u.startsWith('/')) { + try { + relative.push(new URL(u, embedUrl).toString()); + } catch { + // pomijamy + } + } } - if (!relative) return null; + return [...absolute, ...relative]; +} + +/** Czy manifest pod adresem odpowiada (krotki GET z limitem czasu). */ +async function manifestReachable(url: string, referer: string): Promise { + const ctrl = new AbortController(); + const t = setTimeout(() => ctrl.abort(), 4000); try { - return new URL(relative, embedUrl).toString(); + const r = await fetch(url, { headers: { 'User-Agent': UA, Referer: referer }, signal: ctrl.signal }); + if (!r.ok) return false; + return (await r.text()).trimStart().startsWith('#EXTM3U'); } catch { - return null; + return false; + } finally { + clearTimeout(t); } } +/** + * Adres z obiektu `links`, sprawdzony z telefonu. sextapes (2026-10-16): hls2 lezy na + * zewnetrznym CDN (premilkyway, cdn-centaurus), ktory potrafi dac 502 albo byc zablokowany + * przez filtr reklam w DNS (blad "Failed to connect to ...premilkyway.com/[::]"). Wtedy + * bierzemy hls4 z domeny embedu (tam strona sama zaczyna). Segmenty hls4 to TS z doklejonym + * na poczatku 70-bajtowym PNG, ExoPlayer i tak znajduje synchronizacje TS. + */ +async function linksObjectUrl(js: string, embedUrl: string, referer: string): Promise { + const candidates = linksObjectCandidates(js, embedUrl); + if (candidates.length <= 1) return candidates[0] || null; + for (const c of candidates) { + if (await manifestReachable(c, referer)) return c; + } + return candidates[0]; +} + export async function resolvePackerHoster( embedUrl: string, sourceUrl?: string, @@ -164,7 +199,7 @@ export async function resolvePackerHoster( } const um = unpacked.match(FILE_RE); if (um && !AD_RE.test(um[1])) videoUrl = um[1]; - if (!videoUrl) videoUrl = linksObjectUrl(unpacked, url); + if (!videoUrl) videoUrl = await linksObjectUrl(unpacked, url, referer); } if (!videoUrl) return { error: 'no_video_url' }; diff --git a/mobile/src/screens/PinEntry.tsx b/mobile/src/screens/PinEntry.tsx index 32b4c1a..2432999 100644 --- a/mobile/src/screens/PinEntry.tsx +++ b/mobile/src/screens/PinEntry.tsx @@ -44,7 +44,21 @@ export function PinEntry({ title, error, onSubmit, onCancel, footerAction }: Pro {KEYS.map((k, i) => k === null ? ( - + // Zatwierdzenie tez w samej klawiaturze: na telewizorze w poziomie przyciski + // Cancel/Next lezaly pod dolna krawedzia ekranu i nie dalo sie przejsc dalej + // (zgloszenie 94305101, Fire TV AFTMM: "where is ok"). + [ + styles.key, + pin.length < 4 ? styles.keyEmpty : styles.keyOk, + pressed && styles.keyPressed, + ]} + onPress={() => onSubmit(pin)} + > + {pin.length >= 4 ? OK : null} + ) : (