Linki porndoe (mp4 z ip= i HLS z tokenem w sciezce) sa podpisane pod adres, z ktorego przyszlo /service/index.json: token z IPv4 gra tylko przez IPv4, z IPv6 tylko przez IPv6, z VPS 403. Token pobieral WebView (Chromium), a plik ExoPlayer (OkHttp), wiec na sieciach dual-stack i za CGNAT wychodzily innymi adresami: 164 bledy 403 na 278 udanych w tydzien. Nowy resolver po stronie telefonu robi jedno zapytanie (film rozpoznawany po Refererze) zwyklym fetch, ta sama droga co odtwarzacz; mp4 przed HLS, ponowne rozwiazanie przy bledzie jak eporner/sxyprn. Pusto = dotychczasowy WebView. Emulator: gra bez WebView. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
/**
|
|
* Mobile-side porndoe.com resolver.
|
|
*
|
|
* Linki do pliku (mp4 `?ip=<adres>&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<StreamLink[]> {
|
|
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');
|
|
}
|