fix(player): scrape real CDN url for KVS hosts, not session-bound get_file

yespornvip (and other KVS / kt_player tubes) play via the WebView fallback:
INJECTED_JS scrapes <video>.src and hands it to ExoPlayer. For KVS, <video>.src
is a get_file/N/<hash>/... intermediate that 302-redirects to the CDN, but that
redirect is bound to the WebView's cookies/session (and is effectively one-shot).
ExoPlayer's separate request gets "Source error: response code 410" (user bug
2026-05-31, scenes Delicious Dulce / Alexis Fawx).

The actual playable CDN url (e.g. tsvideo.sacdnssedge.com/video/ol_<hash>.mp4) is
portable (206 with no cookies/referer) but never appears in <video>.src or
XHR/fetch — only in Performance resource timing (the native media loader fetches
it after the 302). Verified live in Chromium on the exact broken scene.

INJECTED_JS now:
- skips get_file intermediates (INTERMEDIATE_RE) so they're never sent to ExoPlayer
- skips scrubber preview/heatmap/sprite mp4s (PREVIEW_RE)
- scans performance.getEntriesByType('resource') each tick and reports the real
  CDN media url — cross-origin entries expose .name even without Timing-Allow-Origin

Pure JS → shipped via OTA runtime 1.1 (update d4708fed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-05-31 20:07:53 +02:00
parent 5ae5dbb201
commit a3be78373f

View file

@ -898,10 +898,23 @@ const INJECTED_JS = `
// -- 2. Auto-extract m3u8/mp4 -----------------------------------------------
const VIDEO_RE = /https?:\\/\\/[^"'\\s<>]+\\.(?:m3u8|mp4|mpd)(?:\\?[^"'\\s<>]*)?/i;
// Intermediate / session-bound URL-e: KVS \`get_file/...\` to NIE jest grywalny
// strumień — to redirect (302) zależny od cookies/sesji WebView. \`<video>.src\`
// pokazuje właśnie ten intermediate, ale ExoPlayer robi osobny request (bez cookies
// WebView) → CDN zwraca 410 (bug yespornvip 2026-05-31). Prawdziwy CDN URL (po 302)
// NIE pojawia się w video.src ani XHR/fetch (native media loader go ładuje), ale JEST
// w Performance resource timing — skanujemy je niżej. Skip get_file tutaj, żeby nie
// wysłać niegrywalnego URL-a do ExoPlayera.
const INTERMEDIATE_RE = /\\/get_file\\//i;
// Scrubber preview / heatmap / sprite / storyboard mp4 (np. \`..._preview_v6_a-352x220.mp4\`)
// — NIE jest właściwym video. Wymiary NxN albo preview/heatmap markery.
const PREVIEW_RE = /(preview|heatmap|sprite|storyboard|thumb|[?&/]\\d{2,3}x\\d{2,3}[/._])/i;
const seen = new Set();
function report(url) {
if (!url || seen.has(url)) return;
if (!VIDEO_RE.test(url)) return;
if (INTERMEDIATE_RE.test(url)) return; // KVS get_file — niegrywalny standalone
if (PREVIEW_RE.test(url)) return; // scrubber preview / heatmap clip
seen.add(url);
try {
window.ReactNativeWebView.postMessage(JSON.stringify({type: 'video_url', url: url}));
@ -937,6 +950,15 @@ const INJECTED_JS = `
} catch (e) {}
}
});
// Performance resource scan — łapie REALNY CDN media URL (po 302 z get_file), który
// <video> faktycznie pobiera, a którego nie widać w video.src/XHR/fetch. Cross-origin
// entries mają .name (URL) czytelne mimo braku Timing-Allow-Origin. To kluczowy fix
// dla KVS (yespornvip/freshporno/...): ExoPlayer dostaje portable CDN URL zamiast
// session-bound get_file → koniec 410.
try {
const res = performance.getEntriesByType('resource');
for (let i = 0; i < res.length; i++) report(res[i].name);
} catch (e) {}
// Jeśli mamy video URL i video się odpaliło, możemy zatrzymać polling.
// Próg podniesiony 5→15: po auto-dismiss cookie consent kt_player (hqporner)
// potrzebuje kilku sekund na init — zbyt wczesny stop łapał tylko preroll-ad