fix(galaxyporn): czarny ekran to zablokowane przekierowanie na druga domene

Trzecia proba i tym razem z dowodem z emulatora, a nie ze zgadywania. vikingfile.com
oddaje 302 na INNA domene (dzis vik1ngfile.site). WebView w aplikacji celowo blokuje
przejscie top-frame na inny eTLD+1, zeby popundery nie przejmowaly ekranu, wiec to
przekierowanie bylo odrzucane i zostawal czarny ekran. Z serwera tego nie widac, bo
httpx sledzi przekierowanie po cichu; widac dopiero w przegladarce na urzadzeniu,
gdzie w pasku adresu stoi vik1ngfile.site.

Poprawki:
- ekstraktor oddaje adres DOCELOWY (rozwiazuje 302 przy kazdym resolve, bo domena
  zapasowa rotuje), wiec aplikacja od razu otwiera wlasciwa domene i zadna zmiana
  domeny w ogole nie zachodzi
- wzorzec hosta we wstrzykiwanym skrypcie obejmuje obie pisownie (vik[i1]ngfile.),
  wczesniej dopasowywal tylko vikingfile.com, wiec po przekierowaniu w ogole sie nie
  uruchamial

Przy okazji z emulatora widac, ze zabezpieczenie to CHECKBOX "Verify you are human",
czyli wymaga kliniecia. Dlatego strona musi byc widoczna i uzywalna, a nie schowana.

Opublikowane OTA na 1.2 i 1.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
goon-foss 2026-08-22 20:03:54 +02:00
parent a1717e4b5e
commit 46e7839fb2
3 changed files with 32 additions and 9 deletions

View file

@ -15,7 +15,7 @@ import logging
import re
from urllib.parse import urlparse
from app.extractors._fetch import fetch_tube_html
from app.extractors._fetch import browser_get, fetch_tube_html
from app.extractors._models import StreamSource
from app.extractors.hosters import seekplayer_engine
@ -31,7 +31,20 @@ _NEEDS_WEBVIEW_RE = re.compile(r"vikingfile\.", re.IGNORECASE)
_VIKINGFILE_RE = re.compile(r"https?://vikingfile\.com/f/[A-Za-z0-9]+", re.IGNORECASE)
def _vikingfile_source(html_text: str, page_url: str) -> list[StreamSource] | None:
def _follow_redirect(url: str, *, timeout: float) -> str:
"""Adres po przekierowaniach; przy bledzie oddaje wejsciowy (lepszy niz nic)."""
try:
res = browser_get(url, timeout=min(timeout, 20.0), follow_redirects=True)
final = str(getattr(res, "url", "") or "")
return final or url
except Exception as e:
log.info("galaxyporn: nie rozwiazalem przekierowania %s: %s", url, e)
return url
def _vikingfile_source(
html_text: str, page_url: str, *, timeout: float = 30.0
) -> list[StreamSource] | None:
"""Link do vikingfile z DOWOLNEGO miejsca strony, nie tylko z iframe'a.
Na starszych stronach vikingfile siedzi w zwyklym `<a href>`, a iframe wskazuje
@ -40,9 +53,18 @@ def _vikingfile_source(html_text: str, page_url: str) -> list[StreamSource] | No
mv = _VIKINGFILE_RE.search(html_text)
if not mv:
return None
# WAZNE: vikingfile.com oddaje 302 na INNA domene (2026-08-22: vik1ngfile.site).
# WebView w aplikacji blokuje przejscie top-frame na inny eTLD+1, zeby popundery nie
# przejmowaly ekranu, wiec to przekierowanie bylo odrzucane i user dostawal CZARNY
# EKRAN (zgloszenie 21d6f5af). Widac to bylo dopiero na emulatorze, bo z serwera
# httpx sledzi przekierowanie po cichu. Oddajemy wiec adres DOCELOWY, zeby aplikacja
# od razu otwierala wlasciwa domene i zadna zmiana domeny w ogole nie zachodzila.
# Domena zapasowa potrafi rotowac, dlatego rozwiazujemy ja za kazdym razem, a nie
# wpisujemy na sztywno.
link = _follow_redirect(mv.group(0), timeout=timeout)
return [
StreamSource(
link=mv.group(0),
link=link,
quality="hoster",
type="hoster",
referer=page_url,
@ -56,7 +78,7 @@ def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | Non
m = _IFRAME_RE.search(html_text)
if not m:
log.info("galaxyporn: no iframe on %s", page_url)
return _vikingfile_source(html_text, page_url)
return _vikingfile_source(html_text, page_url, timeout=timeout)
iframe_src = m.group(1).strip()
if iframe_src.startswith("//"):
iframe_src = "https:" + iframe_src
@ -91,7 +113,7 @@ def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | Non
# oddac pustke. Bez tego wyjatek wychodzil na zewnatrz i ratunek z vikingfile
# nigdy sie nie wykonywal.
log.info("galaxyporn: seekplayer rzucil dla %s (%s), probuje vikingfile", iframe_src, e)
return _vikingfile_source(html_text, page_url)
return _vikingfile_source(html_text, page_url, timeout=timeout)
if not sources:
# Iframe bywa ZWIETRZALY. Serwis przeniosl pliki na vikingfile, ale w starszych
# wpisach zostawil stary iframe (news.upns.pro, sport.seekplays.com,
@ -103,7 +125,7 @@ def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | Non
# seekplayer PIERWSZY, bo resolwuje sie po naszej stronie i gra bez CAPTCHA,
# a vikingfile to ratunek, ktory kosztuje usera przejscie Turnstile w WebView.
log.info("galaxyporn: seekplayer padl dla %s, probuje vikingfile", iframe_src)
return _vikingfile_source(html_text, page_url)
return _vikingfile_source(html_text, page_url, timeout=timeout)
# Referer MUSI być hostem PLAYERA (np. https://galaxy.4meplayer.pro/), NIE
# galaxyporn.net, zweryfikowane: ten sam manifest z Refererem galaxyporn = 403,

View file

@ -20,7 +20,7 @@ export const CHANGELOG: ChangelogEntry[] = [
id: '2026-08-22c',
date: 'August 2026',
items: [
'Fixed the black screen on older galaxyporn scenes. The player was covering the host page for a fixed 15 seconds, so by the time anything appeared there was nothing left to see. Now the page shows the moment it needs you, and when the app can grab the video file itself it skips the page entirely and plays it in the normal player.',
'Fixed the black screen on older galaxyporn scenes. The file host bounces you to a second domain, and the player was blocking that jump as if it were a pop-up, so nothing ever loaded. The app now opens the right address straight away, shows the confirm-you-are-human box as soon as it appears, and where it can grab the video file itself it skips the page and plays it in the normal player.',
],
},
{

View file

@ -1156,7 +1156,8 @@ const INJECTED_JS = `
if (window.__goonPatched) return;
window.__goonPatched = true;
// -- 0. vikingfile: to STRONA PLIKU, nie goly odtwarzacz. Galaxyporn przeniosl tam
// -- 0. vikingfile: to STRONA PLIKU, nie goly odtwarzacz. UWAGA: serwis rotuje
// domena, vikingfile.com oddaje 302 na vik1ngfile.site, stad luzniejszy wzorzec. Galaxyporn przeniosl tam
// swoj katalog, a my podajemy ja do WebView, bo wideo odslania sie dopiero po
// recznym przejsciu zabezpieczenia Cloudflare. Bez tego bloku user widzi
// naglowek serwisu, nazwe pliku i stopke, a wlasciwy widget bywa pod zgieciem,
@ -1166,7 +1167,7 @@ const INJECTED_JS = `
// obraz w calosci; dalej dziala zwykly scrape <source>, wiec i tak przeskoczymy
// na natywny odtwarzacz, gdy tylko pojawi sie adres pliku.
try {
if (/(^|\\.)vikingfile\\.com$/i.test(location.hostname)) {
if (/vik[i1]ngfile\\./i.test(location.hostname)) {
// UWAGA: NIE chowamy tu reszty strony. Pierwsza wersja robila dokladnie to i user
// dostawal CZARNY EKRAN zamiast pustej strony, bo gdy widget zabezpieczenia sie nie
// wyrenderuje, na czarnym tle nie zostaje juz nic. Gorsze niz stan wyjsciowy. Teraz