fix(movies): streamporn.li, nowy uklad mangoporn i yourdailypornmovies
Trzy zrodla filmow od tygodnia nie dawaly nic, a watchdog widzial tylko "brak nowych": - streamporn.vip -> 302 streamporn.li; konektor odrzuca linki spoza swojej domeny, wiec lista byla pusta. Id filmu to slug, domena nie robi duplikatow. - mangoporn: /movies/ daje 404, lista z /page/N/; link ma class przed href, tytul w golym <h1> (zapas po itemprop i class="data"); limit 75 s, strona odpowiada z VPS po 30-60 s. - yourdailypornmovies: nowe linie miedzy znacznikami karty, wzorzec bez \s* nie lapal nic przy dzialajacej stronie. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
251032a13b
commit
b0645f625a
4 changed files with 64 additions and 6 deletions
|
|
@ -56,10 +56,13 @@ USER_AGENT = (
|
||||||
# 2. streamporn/pandamovies: <a class="ml-mask jt" href="<base>/<slug>/">
|
# 2. streamporn/pandamovies: <a class="ml-mask jt" href="<base>/<slug>/">
|
||||||
# (slug bez /movies/ prefix, np. /watch-xxx-...-adult-movie-online-free/)
|
# (slug bez /movies/ prefix, np. /watch-xxx-...-adult-movie-online-free/)
|
||||||
# Łapiemy oba przez alternatywę.
|
# Łapiemy oba przez alternatywę.
|
||||||
|
# 2026-10-02 mangoporn przeszedl na `<a class="thumb" href=...>` (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(
|
_LIST_ITEM_RE = re.compile(
|
||||||
r'<a\s+href="(?P<url>https?://[^"]+)"[^>]*\bclass="ml-mask\b[^"]*"'
|
r'<a\s+href="(?P<url>https?://[^"]+)"[^>]*\bclass="ml-mask\b[^"]*"'
|
||||||
r"|"
|
r"|"
|
||||||
r'<a\s+href="(?P<url2>https?://[^"]+/movies/[a-z0-9-]+/)"',
|
r'<a\s+(?:[^>]*?\s)?href="(?P<url2>https?://[^"]+/movies/(?!category/)[a-z0-9-]+/)"',
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
# Tolerantny title, mangoporn (dooplay) używa <h1> w class="data", streamporn/pandamovies
|
# Tolerantny title, mangoporn (dooplay) używa <h1> w class="data", streamporn/pandamovies
|
||||||
|
|
@ -69,6 +72,9 @@ _TITLE_RE = re.compile(
|
||||||
r'|class="data"[^>]*>\s*<h[1-6][^>]*>([^<]+)</h[1-6]>',
|
r'|class="data"[^>]*>\s*<h[1-6][^>]*>([^<]+)</h[1-6]>',
|
||||||
re.IGNORECASE | re.DOTALL,
|
re.IGNORECASE | re.DOTALL,
|
||||||
)
|
)
|
||||||
|
# Zapas: mangoporn od 2026-10 ma tytul w golym <h1>, bez itemprop i bez class="data".
|
||||||
|
# Tylko gdy dwa wzorce wyzej nic nie znajda, zeby inne motywy nie braly logo z <h1>.
|
||||||
|
_H1_TITLE_RE = re.compile(r"<h1[^>]*>\s*([^<]{2,300}?)\s*</h1>", re.IGNORECASE)
|
||||||
# dooplay uses /year/, raw PsyPlay uses /release-year/. Same dla pozostałych slugów,
|
# 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.
|
# różne thema dziedziczą podstawowy markup ale customizują URL słowniki.
|
||||||
_YEAR_RE = re.compile(
|
_YEAR_RE = re.compile(
|
||||||
|
|
@ -272,11 +278,11 @@ class DooplayConnector(BaseMovieConnector):
|
||||||
def _parse_dooplay_detail(
|
def _parse_dooplay_detail(
|
||||||
*, slug: str, html: str, source_name: str, base_url: str, page_url: str | None = None
|
*, slug: str, html: str, source_name: str, base_url: str, page_url: str | None = None
|
||||||
) -> RawMovie | 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:
|
if not m_title:
|
||||||
log.warning("%s: no title in %s", source_name, slug)
|
log.warning("%s: no title in %s", source_name, slug)
|
||||||
return None
|
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)
|
m_year = _YEAR_RE.search(html)
|
||||||
release_year = int(m_year.group(1)) if m_year else None
|
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
|
# samym PsyPlay theme i świeższym katalogiem (ocena 2026-07-02). Osobny source_name
|
||||||
# → nowe origins `streampornvip:<host>`, nie miesza z martwym .nl.
|
# → nowe origins `streampornvip:<host>`, nie miesza z martwym .nl.
|
||||||
name = "streampornvip"
|
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:
|
def _listing_path(self, page: int) -> str:
|
||||||
"""Strona główna, NIE `/movies/`. Diagnoza 2026-08-03: źródło stało od
|
"""Strona główna, NIE `/movies/`. Diagnoza 2026-08-03: źródło stało od
|
||||||
|
|
@ -480,6 +489,15 @@ class MangopornConnector(DooplayConnector):
|
||||||
name = "mangoporn"
|
name = "mangoporn"
|
||||||
base_url = "https://mangoporn.net"
|
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)
|
# Helpers (zduplikowane z paradisehill.py, celowo, żeby connectory były niezależne)
|
||||||
|
|
|
||||||
|
|
@ -55,11 +55,13 @@ _BASE = "https://yourdailypornmovies.ws"
|
||||||
# formacie: od ~2026-09-15 nowe filmy mają `imgs4cdn.adultempire.com/movie/<id>?w=...`
|
# formacie: od ~2026-09-15 nowe filmy mają `imgs4cdn.adultempire.com/movie/<id>?w=...`
|
||||||
# zamiast `.../products/NN/<id>h.jpg`, część ma okładkę z i.ibb.co. Regex wymagający
|
# zamiast `.../products/NN/<id>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ń).
|
# 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(
|
_CARD_RE = re.compile(
|
||||||
r'<div class="movie"><div class="imagen">\s*'
|
r'<div class="movie">\s*<div class="imagen">\s*'
|
||||||
r'(?:<img src="(?P<poster>[^"]*)"[^>]*>\s*)?'
|
r'(?:<img src="(?P<poster>[^"]*)"[^>]*>\s*)?'
|
||||||
r'<a href="(?P<url>https://yourdailypornmovies\.ws/[^"]+)">.*?'
|
r'<a href="(?P<url>https://yourdailypornmovies\.ws/[^"]+)">.*?'
|
||||||
r'</div><h2>(?P<title>[^<]+)</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,
|
re.DOTALL,
|
||||||
)
|
)
|
||||||
# Id produktu Adult Empire z adresu okładki, w obu formatach (to ta sama numeracja).
|
# Id produktu Adult Empire z adresu okładki, w obu formatach (to ta sama numeracja).
|
||||||
|
|
|
||||||
23
tests/test_dooplay_listing.py
Normal file
23
tests/test_dooplay_listing.py
Normal file
|
|
@ -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/"]
|
||||||
|
|
@ -36,3 +36,18 @@ def test_adultempire_id_from_both_poster_formats():
|
||||||
assert (old.group(1) or old.group(2)) == "5128705"
|
assert (old.group(1) or old.group(2)) == "5128705"
|
||||||
assert (new.group(1) or new.group(2)) == "5136742"
|
assert (new.group(1) or new.group(2)) == "5136742"
|
||||||
assert _AE_ID_RE.search("https://i.ibb.co/DHDd9pm9/Private-POV.jpg") is None
|
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/")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue