fix(proxy): hdporn.gg i fullmovies, swiezy adres zamiast 410 w zapasowym proxy

get_file jest przypiety do IP i sesji ladujacej strone i bywa jednorazowy.
Gdy resolver na telefonie zawiodl, proxy dostawalo ten sam zuzyty adres i
oddawalo 410/503: 14 urzadzen w tydzien mialo na tych serwisach same porazki
(inne serwisy graly im bez problemu). Teraz po 403/404/410 albo trwalym 503
proxy pobiera strone na nowo (try_extract) i bierze adres w tej samej jakosci.
Test: adres pobrany z innego IP przez proxy 410 -> z odswiezaniem 206 video/mp4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
goon-foss 2026-10-02 14:16:14 +02:00
parent 0f128d2e17
commit ba53f872d2
4 changed files with 64 additions and 4 deletions

View file

@ -585,6 +585,40 @@ async def sxyprn_thumb(post_id: str) -> Response:
)
#: Po tych statusach proxy pobiera strone tube na nowo (gdy token ma rf + rh "tube:...").
#: 503 dopiero po nieudanym ponowieniu: nowy token bywa kierowany na inny wezel CDN.
_TUBE_REFRESH_STATUSES = frozenset({403, 404, 410, 503})
_QUALITY_IN_URL_RE = re.compile(r"_(\d{3,4})[a-z]?\.mp4", re.IGNORECASE)
async def _fresh_tube_link(sitetag: str, page_url: str, old_target: str) -> str | None:
"""Swiezy adres pliku z ekstraktora tube, w tej samej jakosci co `old_target`.
hdporn.gg / fullmovies.xxx: get_file jest przypiety do IP ladujacego strone i bywa
jednorazowy. Telefon, ktoremu nie wyszedl wlasny resolver, dostawal od proxy ten sam
zuzyty adres i konczyl na 410/503 (14 urzadzen w tydzien z samymi porazkami, 2026-10-02).
"""
import anyio
from app.extractors import try_extract
try:
sources = await anyio.to_thread.run_sync(lambda: try_extract(sitetag, page_url))
except Exception as e: # noqa: BLE001 (HosterDead/TubePageError: zostaje stary blad)
log.info("proxy: odswiezenie %s nie wyszlo: %s", page_url, e)
return None
links = [s.link for s in (sources or []) if s.link]
if not links:
return None
want = _QUALITY_IN_URL_RE.search(old_target)
if want:
for link in links:
m = _QUALITY_IN_URL_RE.search(link)
if m and m.group(1) == want.group(1):
return link
return links[0]
async def _refetch_mixdrop_url(session: "AsyncSession", embed_url: str) -> str | None:
"""Re-fetch mixdrop embed, decode P.A.C.K.E.R., extract fresh MDCore.wurl.
Cookies persist w session, użytkowane potem do mp4 GET (same-session bind).
@ -870,6 +904,23 @@ async def proxy_stream(
stream=True,
follow_redirects=True,
)
if (
upstream.status_code in _TUBE_REFRESH_STATUSES
and refetch_url
and (refetch_hoster or "").startswith("tube:")
and method.upper() in ("GET", "HEAD")
):
fresh = await _fresh_tube_link(refetch_hoster[5:], refetch_url, target)
if fresh:
log.info("proxy: upstream %d, swiezy adres z %s", upstream.status_code, refetch_url[:70])
await upstream.aclose()
target = fresh
cached_target = None # nowy cel: po sukcesie cache dostanie jego koncowy adres
upstream = await client.send(
client.build_request(method, target, headers=headers),
stream=True,
follow_redirects=True,
)
if upstream.status_code >= 400:
status = upstream.status_code
ups_headers = dict(upstream.headers)

View file

@ -31,7 +31,9 @@ _SOURCE_RE = re.compile(
_SKIP_QUALITY_RE = re.compile(r"2160|1440|4k", re.IGNORECASE)
def resolve(page_url: str, base_url: str, *, timeout: float = 30.0) -> list[StreamSource] | None:
def resolve(
page_url: str, base_url: str, *, timeout: float = 30.0, sitetag: str | None = None
) -> list[StreamSource] | None:
if not _HAS_CURL_CFFI:
log.info("source_getfile: curl_cffi unavailable — %s", page_url)
return None
@ -59,9 +61,16 @@ def resolve(page_url: str, base_url: str, *, timeout: float = 30.0) -> list[Stre
if _SKIP_QUALITY_RE.search(quality):
log.info("source_getfile: skip broken-CDN quality %r on %s", quality, page_url)
continue
raw: dict = {"mobile_direct_ok": True}
if sitetag:
# get_file jest przypiety do IP tego, kto zaladowal strone, i bywa jednorazowy,
# wiec proxy (zapas, gdy resolver na telefonie zawiedzie) po 403/410 pobiera
# strone na nowo zamiast oddac blad (stream_proxy._fresh_tube_link, 2026-10-02).
raw["refetch_url"] = page_url
raw["refetch_hoster"] = f"tube:{sitetag}"
out.append(StreamSource(
link=url, type="mp4", quality=quality or None,
referer=base_url + "/", raw={"mobile_direct_ok": True},
referer=base_url + "/", raw=raw,
))
if not out:

View file

@ -16,4 +16,4 @@ _BASE = "https://www.fullmovies.xxx"
def extract(page_url: str, *, timeout: float = 30.0) -> list[StreamSource] | None:
return _source_getfile.resolve(page_url, _BASE, timeout=timeout)
return _source_getfile.resolve(page_url, _BASE, timeout=timeout, sitetag="fullmoviesxxx")

View file

@ -14,4 +14,4 @@ _BASE = "https://www.hdporn.gg"
def extract(page_url: str, *, timeout: float = 30.0) -> list[StreamSource] | None:
return _source_getfile.resolve(page_url, _BASE, timeout=timeout)
return _source_getfile.resolve(page_url, _BASE, timeout=timeout, sitetag="hdporngg")