diff --git a/app/connectors/dooplay.py b/app/connectors/dooplay.py index 8e39a9a..ab86c96 100644 --- a/app/connectors/dooplay.py +++ b/app/connectors/dooplay.py @@ -56,10 +56,13 @@ USER_AGENT = ( # 2. streamporn/pandamovies: # (slug bez /movies/ prefix, np. /watch-xxx-...-adult-movie-online-free/) # Łapiemy oba przez alternatywę. +# 2026-10-02 mangoporn przeszedl na `` (klasa PRZED href) i +# wzorzec z href na poczatku nie lapal juz nic: 0 filmow od 2026-09-23. Teraz href moze +# stac w dowolnym miejscu znacznika; linki menu do /movies/category/ odpadaja. _LIST_ITEM_RE = re.compile( r'https?://[^"]+)"[^>]*\bclass="ml-mask\b[^"]*"' r"|" - r'https?://[^"]+/movies/[a-z0-9-]+/)"', + r']*?\s)?href="(?Phttps?://[^"]+/movies/(?!category/)[a-z0-9-]+/)"', re.IGNORECASE, ) # Tolerantny title, mangoporn (dooplay) używa

w class="data", streamporn/pandamovies @@ -69,6 +72,9 @@ _TITLE_RE = re.compile( r'|class="data"[^>]*>\s*]*>([^<]+)', re.IGNORECASE | re.DOTALL, ) +# Zapas: mangoporn od 2026-10 ma tytul w golym

, bez itemprop i bez class="data". +# Tylko gdy dwa wzorce wyzej nic nie znajda, zeby inne motywy nie braly logo z

. +_H1_TITLE_RE = re.compile(r"]*>\s*([^<]{2,300}?)\s*

", re.IGNORECASE) # dooplay uses /year/, raw PsyPlay uses /release-year/. Same dla pozostałych slugów, # różne thema dziedziczą podstawowy markup ale customizują URL słowniki. _YEAR_RE = re.compile( @@ -272,11 +278,11 @@ class DooplayConnector(BaseMovieConnector): def _parse_dooplay_detail( *, slug: str, html: str, source_name: str, base_url: str, page_url: str | None = None ) -> RawMovie | None: - m_title = _TITLE_RE.search(html) + m_title = _TITLE_RE.search(html) or _H1_TITLE_RE.search(html) if not m_title: log.warning("%s: no title in %s", source_name, slug) return None - title = _decode_html((m_title.group(1) or m_title.group(2)).strip()) + title = _decode_html(next(g for g in m_title.groups() if g).strip()) m_year = _YEAR_RE.search(html) release_year = int(m_year.group(1)) if m_year else None @@ -452,7 +458,10 @@ class StreampornVipConnector(DooplayConnector): # samym PsyPlay theme i świeższym katalogiem (ocena 2026-07-02). Osobny source_name # → nowe origins `streampornvip:`, nie miesza z martwym .nl. name = "streampornvip" - base_url = "https://streamporn.vip" + # 2026-10-02 streamporn.vip -> 302 streamporn.li. Konektor odrzuca linki spoza swojej + # domeny, wiec po przekierowaniu lista byla pusta (0 filmow od 2026-09-23). Id filmu to + # slug, bez domeny, wiec przeprowadzka nie robi duplikatow. + base_url = "https://streamporn.li" def _listing_path(self, page: int) -> str: """Strona główna, NIE `/movies/`. Diagnoza 2026-08-03: źródło stało od @@ -480,6 +489,15 @@ class MangopornConnector(DooplayConnector): name = "mangoporn" base_url = "https://mangoporn.net" + def __init__(self, *, timeout: float = 75.0): + # Strona odpowiada z VPS po 30-60 s (2026-10-02), przy 30 s ingest konczyl sie + # na timeoutcie listy. + super().__init__(timeout=timeout) + + def _listing_path(self, page: int) -> str: + """Od 2026-10 `/movies/` daje 404, najnowsze sa na stronie glownej (`/page/N/`).""" + return "/" if page == 1 else f"/page/{page}/" + # --------------------------------------------------------------------------- # Helpers (zduplikowane z paradisehill.py, celowo, żeby connectory były niezależne) diff --git a/app/connectors/yourdailypornmovies.py b/app/connectors/yourdailypornmovies.py index 364ac71..803a856 100644 --- a/app/connectors/yourdailypornmovies.py +++ b/app/connectors/yourdailypornmovies.py @@ -55,11 +55,13 @@ _BASE = "https://yourdailypornmovies.ws" # formacie: od ~2026-09-15 nowe filmy mają `imgs4cdn.adultempire.com/movie/?w=...` # zamiast `.../products/NN/h.jpg`, część ma okładkę z i.ibb.co. Regex wymagający # starego formatu po cichu gubił 33 z 40 filmów strony 1 (ingest: 0 nowych przez tydzień). +# 2026-10 strona wstawila nowe linie miedzy znacznikami karty i wzorzec bez \s* nie +# lapal juz nic (0 filmow od 2026-09-29, przy dzialajacej stronie). _CARD_RE = re.compile( - r'
\s*' + r'
\s*

(?P[^<]+)</h2>\s*<span class="year">(?P<year>\d{4})</span>', + r'</div>\s*<h2>(?P<title>[^<]+)</h2>\s*<span class="year">(?P<year>\d{4})</span>', re.DOTALL, ) # Id produktu Adult Empire z adresu okładki, w obu formatach (to ta sama numeracja). diff --git a/tests/test_dooplay_listing.py b/tests/test_dooplay_listing.py new file mode 100644 index 0000000..be8d5c8 --- /dev/null +++ b/tests/test_dooplay_listing.py @@ -0,0 +1,23 @@ +from app.connectors.dooplay import _LIST_ITEM_RE + + +def _urls(html): + return [m.group("url") or m.group("url2") for m in _LIST_ITEM_RE.finditer(html)] + + +def test_mangoporn_class_before_href(): + # mangoporn od 2026-10: klasa przed href, wczesniej wzorzec nie lapal nic. + html = ( + '<a class="thumb" href="https://mangoporn.net/movies/major-creampie/"><div></div></a>' + '<a class="infos" href="https://mangoporn.net/movies/major-creampie/" title="Major Creampie">' + '<a title="Porn Movies" href="https://mangoporn.net/movies/category/porn-movies-xxx/" class="nav-link">' + ) + assert _urls(html) == [ + "https://mangoporn.net/movies/major-creampie/", + "https://mangoporn.net/movies/major-creampie/", + ] + + +def test_old_layouts_still_match(): + assert _urls('<a href="https://mangoporn.net/movies/old-one/">x</a>') == ["https://mangoporn.net/movies/old-one/"] + assert _urls('<a href="https://streamporn.li/watch-xxx-a/" class="ml-mask jt">') == ["https://streamporn.li/watch-xxx-a/"] diff --git a/tests/test_yourdailypornmovies_cards.py b/tests/test_yourdailypornmovies_cards.py index 9434ce4..85127fd 100644 --- a/tests/test_yourdailypornmovies_cards.py +++ b/tests/test_yourdailypornmovies_cards.py @@ -36,3 +36,18 @@ def test_adultempire_id_from_both_poster_formats(): assert (old.group(1) or old.group(2)) == "5128705" assert (new.group(1) or new.group(2)) == "5136742" assert _AE_ID_RE.search("https://i.ibb.co/DHDd9pm9/Private-POV.jpg") is None + + +_MULTILINE = ( + '<div class="movie">\n<div class="imagen">\n' + '<img src="https://imgs4cdn.adultempire.com/movie/2755934?w=500&h=700&fit=cover" alt="Busty Treats Vol. 2" ' + 'width="100%" height="100%" />\n<a href="https://yourdailypornmovies.ws/busty-treats-vol-2/"><span class="player"></span></a>\n' + '</div>\n<h2>Busty Treats Vol. 2</h2>\n<span class="year">2026</span></div>' +) + + +def test_card_with_newlines_between_tags(): + # Uklad strony od 2026-10: nowe linie miedzy znacznikami (0 filmow do poprawki). + cards = list(_CARD_RE.finditer(_MULTILINE + _MULTILINE.replace("busty-treats-vol-2", "b2"))) + assert [c.group("title") for c in cards] == ["Busty Treats Vol. 2", "Busty Treats Vol. 2"] + assert cards[0].group("url").endswith("/busty-treats-vol-2/")