/** * Mobile-side porndoe.com resolver. * * Linki do pliku (mp4 `?ip=&token=` i HLS z tokenem w sciezce) sa podpisane pod * adres, z ktorego przyszlo zapytanie `/service/index.json`. Sprawdzone 2026-10-02: token * pobrany przez IPv4 gra tylko przez IPv4, przez IPv6 tylko przez IPv6, z VPS 403. * * Wczesniej porndoe szedl przez WebView: token pobieral Chromium, a plik ExoPlayer * (OkHttp). Na sieciach z IPv4 i IPv6 albo za CGNAT z pula adresow te dwa stosy potrafia * wyjsc innymi adresami i plik dostawal 403 (164 bledy na 278 udanych w tydzien). * Tu token pobiera zwykly `fetch` (tez OkHttp), wiec idzie ta sama droga co odtwarzacz. * * Jedno zapytanie wystarcza: serwis rozpoznaje film po Refererze, ciasteczka niepotrzebne. */ import type { StreamLink } from '../types'; const UA = 'Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Mobile Safari/537.36'; type PorndoeSource = { name?: string; height?: string | number; link?: string; type?: string; }; export async function resolvePorndoePage(pageUrl: string): Promise { let origin: string; try { origin = new URL(pageUrl).origin; } catch { return []; } let data: { payload?: { player?: { sources?: { mp4?: unknown; hls?: unknown } } } } | null; try { const r = await fetch(`${origin}/service/index.json?device=mobile`, { headers: { 'User-Agent': UA, Referer: pageUrl, Accept: 'application/json' }, }); if (!r.ok) return []; data = await r.json(); } catch { return []; } const sources = data?.payload?.player?.sources; // mp4 przed HLS: jeden plik z przewijaniem. 1080p ma `type: 'link'` (reklama konta // premium zamiast adresu), dlatego bierzemy tylko `type: 'video'`. const pick = (list: unknown, kind: 'mp4' | 'm3u8'): StreamLink[] => (Array.isArray(list) ? (list as PorndoeSource[]) : []) .filter((s) => s.type === 'video' && /^https?:\/\//.test(s.link || '')) .sort((a, b) => Number(b.height || 0) - Number(a.height || 0)) .map((s) => ({ stream_url: s.link!, direct_url: s.link!, headers: { Referer: `${origin}/`, 'User-Agent': UA }, quality: s.name || (s.height ? `${s.height}p` : null), type: kind, })); const mp4 = pick(sources?.mp4, 'mp4'); return mp4.length > 0 ? mp4 : pick(sources?.hls, 'm3u8'); }