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:
parent
0f128d2e17
commit
ba53f872d2
4 changed files with 64 additions and 4 deletions
|
|
@ -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:
|
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.
|
"""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).
|
Cookies persist w session, użytkowane potem do mp4 GET (same-session bind).
|
||||||
|
|
@ -870,6 +904,23 @@ async def proxy_stream(
|
||||||
stream=True,
|
stream=True,
|
||||||
follow_redirects=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:
|
if upstream.status_code >= 400:
|
||||||
status = upstream.status_code
|
status = upstream.status_code
|
||||||
ups_headers = dict(upstream.headers)
|
ups_headers = dict(upstream.headers)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,9 @@ _SOURCE_RE = re.compile(
|
||||||
_SKIP_QUALITY_RE = re.compile(r"2160|1440|4k", re.IGNORECASE)
|
_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:
|
if not _HAS_CURL_CFFI:
|
||||||
log.info("source_getfile: curl_cffi unavailable — %s", page_url)
|
log.info("source_getfile: curl_cffi unavailable — %s", page_url)
|
||||||
return None
|
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):
|
if _SKIP_QUALITY_RE.search(quality):
|
||||||
log.info("source_getfile: skip broken-CDN quality %r on %s", quality, page_url)
|
log.info("source_getfile: skip broken-CDN quality %r on %s", quality, page_url)
|
||||||
continue
|
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(
|
out.append(StreamSource(
|
||||||
link=url, type="mp4", quality=quality or None,
|
link=url, type="mp4", quality=quality or None,
|
||||||
referer=base_url + "/", raw={"mobile_direct_ok": True},
|
referer=base_url + "/", raw=raw,
|
||||||
))
|
))
|
||||||
|
|
||||||
if not out:
|
if not out:
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ _BASE = "https://www.fullmovies.xxx"
|
||||||
|
|
||||||
|
|
||||||
def extract(page_url: str, *, timeout: float = 30.0) -> list[StreamSource] | None:
|
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")
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,4 @@ _BASE = "https://www.hdporn.gg"
|
||||||
|
|
||||||
|
|
||||||
def extract(page_url: str, *, timeout: float = 30.0) -> list[StreamSource] | None:
|
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")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue