From 00ea8c3fd494a1f9ee7673cabc4807dd19278b2e Mon Sep 17 00:00:00 2001 From: jtrzupek Date: Sun, 31 May 2026 21:47:35 +0200 Subject: [PATCH] fix(player): hide ad-heavy WebView behind opaque cover until stream scraped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User bug: opening a WebView-fallback scene (yespornvip etc.) shows the host's ad-heavy page while INJECTED_JS auto-plays + scrapes the stream url in the background. User sees ads instead of a loading state. Render an opaque cover (theme.bg + spinner "Loading video…") over the WebView while !extractedUrl. The WebView is still laid out and painted underneath, so media keeps playing (autoplay via mediaPlaybackRequiresUserAction=false) and the performance-scan picks up the CDN url — but the user only ever sees a loading screen, then the native player. Applies to every WebView-fallback host. Safety: if no stream is scraped within 15s (host needs a real tap to start), reveal the WebView so the user can interact manually — no worse than before. Co-Authored-By: Claude Opus 4.8 (1M context) --- mobile/src/screens/PlayerScreen.tsx | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/mobile/src/screens/PlayerScreen.tsx b/mobile/src/screens/PlayerScreen.tsx index 8bcaf4f..d87b251 100644 --- a/mobile/src/screens/PlayerScreen.tsx +++ b/mobile/src/screens/PlayerScreen.tsx @@ -988,6 +988,17 @@ function EmbedWebViewPlayer({ params }: { params: RouteParams }) { const [resolveError, setResolveError] = React.useState(null); const [skipResolve, setSkipResolve] = React.useState(false); const [resolveAttempted, setResolveAttempted] = React.useState(false); + // Anti-ads: trzymamy nieprzezroczysty cover NA WebView dopóki INJECTED_JS nie + // wyciągnie URL — user nie widzi ad-heavy strony hostera (bug yespornvip "otwiera + // reklamy" 2026-05-31). WebView gra pod spodem (jest malowany, media leci, scrape + // łapie CDN). Jeśli po REVEAL_AFTER_MS autoplay nie zaskoczył (host wymaga gestu) — + // odsłaniamy WebView żeby user mógł ręcznie tapnąć play (graceful fallback). + const [revealEmbed, setRevealEmbed] = React.useState(false); + React.useEffect(() => { + if (extractedUrl) return; + const t = setTimeout(() => setRevealEmbed(true), 15000); + return () => clearTimeout(t); + }, [extractedUrl]); // Stage 0.8: mobile-side hoster resolvery. Mobile IP usera unika Cloudflare // Turnstile / CAPTCHA gate który blokuje Hetzner VPS — embed page renderuje @@ -1206,6 +1217,12 @@ function EmbedWebViewPlayer({ params }: { params: RouteParams }) { )} /> + {!extractedUrl && !revealEmbed && ( + + + Loading video… + + )} {extractedUrl && (