perf(mobile): rule34video rozwiazywany od razu na telefonie
Some checks are pending
Backend tests / test (push) Waiting to run
Some checks are pending
Backend tests / test (push) Waiting to run
Wczesniej resolve na serwerze, a potem telefon i tak pobieral cala strone jeszcze raz (token zwiazany z IP) i robil przeskok przez get_file. Teraz jedno pobranie strony na telefonie i wszystkie jakosci z flashvars, przekierowanie get_file robi ExoPlayer. Limity czasu na pobrania. Emulator: wybor jakosci -> odtwarzacz 3,1 s -> 0,1 s, -> dzwiek 7,2 s -> 2,9 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
97bca096e6
commit
b19d041f09
4 changed files with 83 additions and 5 deletions
|
|
@ -35,6 +35,13 @@ export type ChangelogEntry = {
|
|||
};
|
||||
|
||||
export const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
id: '2026-10-15c',
|
||||
date: 'October 2026',
|
||||
items: [
|
||||
'rule34video starts playing more than twice as fast: the app reads the video straight from the page instead of loading it twice.',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2026-10-15b',
|
||||
date: 'October 2026',
|
||||
|
|
|
|||
|
|
@ -12,9 +12,22 @@
|
|||
* bez proxy. Ten sam wzorzec co doodstream.ts (`redirect: 'manual'` + Location header,
|
||||
* potwierdzone że działa na Android RN).
|
||||
*/
|
||||
import type { StreamLink } from '../types';
|
||||
|
||||
const UA =
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36';
|
||||
|
||||
/** fetch z limitem czasu: bez niego wiszaca strona trzymala ekran "resolving" bez konca. */
|
||||
async function fetchWithTimeout(url: string, init: RequestInit, ms: number): Promise<Response> {
|
||||
const ctrl = new AbortController();
|
||||
const t = setTimeout(() => ctrl.abort(), ms);
|
||||
try {
|
||||
return await fetch(url, { ...init, signal: ctrl.signal });
|
||||
} finally {
|
||||
clearTimeout(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** get_file URL który wymaga in-session resolve (nie nasz proxy URL). */
|
||||
export function isGetFileUrl(url: string): boolean {
|
||||
return /\/get_file\//.test(url) && !/\/proxy\//.test(url);
|
||||
|
|
@ -49,7 +62,7 @@ export async function resolveGetFilePage(
|
|||
): Promise<string | null> {
|
||||
let html: string;
|
||||
try {
|
||||
const r = await fetch(pageUrl, { headers: { 'User-Agent': UA, Accept: 'text/html' } });
|
||||
const r = await fetchWithTimeout(pageUrl, { headers: { 'User-Agent': UA, Accept: 'text/html' } }, 10000);
|
||||
if (!r.ok) return null;
|
||||
html = await r.text();
|
||||
} catch {
|
||||
|
|
@ -118,7 +131,7 @@ export async function resolveGetFile(url: string, referer?: string): Promise<str
|
|||
for (let hop = 0; hop < 4; hop++) {
|
||||
let r: Response;
|
||||
try {
|
||||
r = await fetch(cur, {
|
||||
r = await fetchWithTimeout(cur, {
|
||||
method: 'GET',
|
||||
redirect: 'manual',
|
||||
headers: {
|
||||
|
|
@ -126,7 +139,7 @@ export async function resolveGetFile(url: string, referer?: string): Promise<str
|
|||
Range: 'bytes=0-1',
|
||||
...(referer ? { Referer: referer } : {}),
|
||||
},
|
||||
});
|
||||
}, 6000);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -150,3 +163,54 @@ export async function resolveGetFile(url: string, referer?: string): Promise<str
|
|||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
/**
|
||||
* rule34video od razu na telefonie (zgloszenie 008e261d, 2026-10-12: "dziala, ale strasznie
|
||||
* wolno"). Wczesniej: resolve na serwerze, potem telefon i tak pobieral cala strone jeszcze
|
||||
* raz (242 KB, token v-acctoken jest zwiazany z IP pobierajacego) i robil przeskok przez
|
||||
* get_file, w sumie ok. 3,5 s po odpowiedzi serwera. Tu jedno pobranie strony na telefonie
|
||||
* i wszystkie jakosci z flashvars. Przekierowanie get_file -> boomio-cdn robi sam ExoPlayer
|
||||
* (302, potem 206 bez Referera, sprawdzone z IP domowego).
|
||||
*/
|
||||
export async function resolveRule34Page(pageUrl: string): Promise<StreamLink[]> {
|
||||
let html: string;
|
||||
try {
|
||||
const r = await fetchWithTimeout(pageUrl, { headers: { 'User-Agent': UA, Accept: 'text/html' } }, 10000);
|
||||
if (!r.ok) return [];
|
||||
html = await r.text();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
const labels = new Map<string, string>();
|
||||
let lm: RegExpExecArray | null;
|
||||
_FLASHVAR_LABEL_RE.lastIndex = 0;
|
||||
while ((lm = _FLASHVAR_LABEL_RE.exec(html)) !== null) labels.set(lm[1], lm[2].trim());
|
||||
let origin = '';
|
||||
try {
|
||||
origin = new URL(pageUrl).origin;
|
||||
} catch {
|
||||
// zostaje pusty
|
||||
}
|
||||
const rank = (q: string) => ({ '1080p': 0, '720p': 1, '480p': 2, '360p': 3 }[q.toLowerCase()] ?? 99);
|
||||
const out: StreamLink[] = [];
|
||||
const seen = new Set<string>();
|
||||
let fm: RegExpExecArray | null;
|
||||
_FLASHVAR_URL_RE.lastIndex = 0;
|
||||
while ((fm = _FLASHVAR_URL_RE.exec(html)) !== null) {
|
||||
const q = labels.get(fm[1]) || '';
|
||||
if (_SKIP_Q.test(q)) continue;
|
||||
let u = fm[2];
|
||||
if (u.startsWith('//')) u = 'https:' + u;
|
||||
if (seen.has(u)) continue;
|
||||
seen.add(u);
|
||||
out.push({
|
||||
stream_url: u,
|
||||
direct_url: u,
|
||||
headers: { 'User-Agent': UA, ...(origin ? { Referer: origin + '/' } : {}) },
|
||||
quality: q || null,
|
||||
type: 'mp4',
|
||||
} as StreamLink);
|
||||
}
|
||||
out.sort((a, b) => rank(a.quality || '') - rank(b.quality || ''));
|
||||
return out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -525,6 +525,8 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
|
|||
links = await (await import('../lib/fpoxxxResolver')).resolveFpoxxxPage(resolvePageUrl);
|
||||
} else if (resolvePageUrl && playOrigin === 'tube:porndoecom') {
|
||||
links = await (await import('../lib/porndoeResolver')).resolvePorndoePage(resolvePageUrl);
|
||||
} else if (resolvePageUrl && playOrigin === 'tube:rule34video') {
|
||||
links = await (await import('../lib/getfileResolver')).resolveRule34Page(resolvePageUrl);
|
||||
} else if (canBackendReresolve && sceneId && params.playbackId) {
|
||||
// Świeży resolve przez backend (VPS re-runuje extractor KVS → nowy nod + token).
|
||||
const res = await client.resolvePlayback(sceneId, params.playbackId);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { resolveSxyprnPage } from '../lib/sxyprnResolver';
|
|||
import { resolveEpornerPage } from '../lib/epornerResolver';
|
||||
import { resolveFpoxxxPage } from '../lib/fpoxxxResolver';
|
||||
import { resolvePorndoePage } from '../lib/porndoeResolver';
|
||||
import { resolveRule34Page } from '../lib/getfileResolver';
|
||||
import { prefersPageMode } from '../lib/pageMode';
|
||||
import type { RootStackParamList } from '../navigation';
|
||||
import { fonts, theme } from '../theme';
|
||||
|
|
@ -640,7 +641,9 @@ function PlaybackButton({
|
|||
// hdporn.gg/fullmovies.xxx: backendowy get_file jest zbindowany do IP VPS (page-loader)
|
||||
// → telefon dostaje 410 → fallback proxy (mignięcie). Re-fetchujemy STRONĘ na telefonie
|
||||
// (phone-bound get_file) → fpvcdn z IP telefonu → ExoPlayer gra direct (bez proxy/migotania).
|
||||
if (isDirect && isGetFileUrl(initialUrl)) {
|
||||
// Link z resolvera na telefonie jest juz zwiazany z IP telefonu, drugie pobranie strony
|
||||
// tylko opoznialo start (rule34video, 008e261d).
|
||||
if (isDirect && via !== 'phone' && isGetFileUrl(initialUrl)) {
|
||||
const ref = link.headers?.Referer || (refererHost ? `https://${refererHost}/` : undefined);
|
||||
const resolved = await resolveGetFilePage(source.page_url, link.quality, ref);
|
||||
if (resolved) initialUrl = resolved;
|
||||
|
|
@ -648,7 +651,7 @@ function PlaybackButton({
|
|||
|
||||
// IP-bound tuby resolwowane phone-side: przekaż page_url, by Player mógł
|
||||
// re-resolve'ować świeży token gdy native padnie na initial-load (zmiana IP / TTL).
|
||||
const PHONE_RESOLVE_ORIGINS = ['tube:sxyprncom', 'tube:epornercom', 'tube:fpoxxx', 'tube:porndoecom'];
|
||||
const PHONE_RESOLVE_ORIGINS = ['tube:sxyprncom', 'tube:epornercom', 'tube:fpoxxx', 'tube:porndoecom', 'tube:rule34video'];
|
||||
nav.navigate('Player', {
|
||||
url: initialUrl,
|
||||
sceneId,
|
||||
|
|
@ -729,6 +732,8 @@ function PlaybackButton({
|
|||
? resolvePornxpPage
|
||||
: source.origin === 'tube:porndoecom'
|
||||
? resolvePorndoePage
|
||||
: source.origin === 'tube:rule34video'
|
||||
? resolveRule34Page
|
||||
: // hqfap zdjęty 2026-07-28: strona wdrożyła Cloudflare z JS-challenge na
|
||||
// /watch/ (403 dla każdego zwykłego fetcha, także z pełnym kompletem
|
||||
// nagłówków przeglądarki), więc phone-resolve tylko padał i zrzucał usera
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue