diff --git a/app/api/playback.py b/app/api/playback.py index 4f416c6..cb3ad01 100644 --- a/app/api/playback.py +++ b/app/api/playback.py @@ -65,6 +65,38 @@ _TIME_BOUND_CDN_RE = re.compile( re.IGNORECASE, ) +# Hostery znane z przekierowywania całej domeny na następcę (rodzina DoodStream +# zmienia szyld co kilka miesięcy). TYLKO dla nich rozwiązujemy przekierowanie przed +# oddaniem embedu, bo to kosztuje jeden fetch; zwykłe embedy idą bez dotykania sieci. +_REDIRECTING_EMBED_RE = re.compile( + r"//(?:[a-z0-9-]+\.)?(?:myvidplay|doply|doodstream|dood|d0+d|dooood|do0od|do7go" + r"|ds2play)\.[a-z]{2,6}/", + re.IGNORECASE, +) + + +def _resolve_embed_redirect(url: str) -> str: + """Zwraca końcowy adres po przekierowaniach albo oryginał, gdy nic się nie zmienia. + + Wynik trafia do `embed_url` w bazie, więc każdy adres jest rozwiązywany najwyżej + raz; po utrwaleniu regex przestaje pasować i ta funkcja robi się darmowa. + """ + if not _REDIRECTING_EMBED_RE.search(url): + return url + from app.extractors import browser_get + + try: + res = browser_get(url, timeout=15.0, follow_redirects=True) + final = str(getattr(res, "url", "") or "") + # Utrwalamy tylko realny skok na inny adres http(s); błąd hostera (5xx itp.) + # zostawia oryginał, żeby nie zabetonować chwilowej awarii jako "nowego" adresu. + if final.startswith("http") and final != url and res.status_code < 400: + return final + except Exception as e: + log.info("embed redirect resolve padl dla %s: %s", url, e) + return url + + # IP-BOUND CDN signature, token bind do requester IP, cross-IP fetch = 403. # Wymaga mobile WebView fallback (mobile extract z phone session, nie VPS). # Shared KVS infrastructure across multiple hosters (luluvid movies, mypornerleak, @@ -248,6 +280,21 @@ def resolve_movie_playback( ) # Zawsze dorzucamy embed jako fallback, mobile WebView może wyłapać URL z JS-a if pb.embed_url: + # Hoster potrafi zostać atrapą przekierowującą na następcę (myvidplay i + # doply odpowiadają 30x na playmogo). WebView w apce blokuje top-frame + # skok na inną domenę (ochrona przed popunderami), więc surowy adres + # kończy się czarnym ekranem: zgłoszenia 3b75cb54/11d7b17b/d3af0813, + # wcześniej identyczny mechanizm w galaxyporn (vikingfile → vik1ngfile). + # Rozwiązujemy przekierowanie TUTAJ i utrwalamy wynik, żeby telefon + # dostał adres, na którym wolno mu zostać. + final_embed = _resolve_embed_redirect(pb.embed_url) + if final_embed != pb.embed_url: + log.info( + "movie playback %s: embed %s przekierowuje na %s, utrwalam", + pb.id, pb.embed_url, final_embed, + ) + pb.embed_url = final_embed[:2048] + session.commit() links.append( StreamLink( stream_url=None,