fix(siska): przeniesienie na siska.tv po wygasnieciu siska.video
siska.video od 2026-09-22 nie istnieje (NXDOMAIN), ten sam serwis dziala pod siska.tv z tymi samymi videoID i sciezkami miniatur. Scraper bierze kafelki z obu domen i z www, zapisuje jeden kanoniczny adres. Lista najnowszych jest pod best_xvideos.php?page=N, bo /page/N/ na siska.tv zawsze oddaje strone 1. Na produkcji adresy stron, miniatur i external_id przepisane na siska.tv (16 007 zrodel, 16 265 powiazan scen); 103 duplikaty www.siska.video oznaczone jako martwe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ed7c1cd3ed
commit
cb9e4ab035
2 changed files with 22 additions and 9 deletions
|
|
@ -110,7 +110,7 @@ class SourceListOut(BaseModel):
|
||||||
# tubey mają nietypowe TLDs / brakujące kropki w sitetag.
|
# tubey mają nietypowe TLDs / brakujące kropki w sitetag.
|
||||||
_DISPLAY_OVERRIDES: dict[str, str] = {
|
_DISPLAY_OVERRIDES: dict[str, str] = {
|
||||||
"fpoxxx": "fpo.xxx",
|
"fpoxxx": "fpo.xxx",
|
||||||
"siskavideo": "siska.video",
|
"siskavideo": "siska.tv",
|
||||||
"porn4dayspw": "porn4days.pw",
|
"porn4dayspw": "porn4days.pw",
|
||||||
"porn00org": "porn00.org",
|
"porn00org": "porn00.org",
|
||||||
"freshpornoorg": "freshporno.org",
|
"freshpornoorg": "freshporno.org",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""siska.video, latest-vids browse scraper.
|
"""siska.tv (do 2026-09-22 siska.video), latest-vids browse scraper.
|
||||||
|
|
||||||
Historia: dawniej performer-driven search scraper (`?s=<q>`), ale siska zepsuła
|
Historia: dawniej performer-driven search scraper (`?s=<q>`), ale siska zepsuła
|
||||||
wyszukiwarkę (zwraca latest niezależnie od query). Przerobione na BROWSE (latest
|
wyszukiwarkę (zwraca latest niezależnie od query). Przerobione na BROWSE (latest
|
||||||
chronologicznie z `/page/<n>/`), re-enabled 2026-06-20 (user fa4083a2).
|
chronologicznie z listingu, patrz `_listing_url`), re-enabled 2026-06-20 (user fa4083a2).
|
||||||
|
|
||||||
Cały blok kafelka listingu ma komplet metadanych (zero detail-fetchy):
|
Cały blok kafelka listingu ma komplet metadanych (zero detail-fetchy):
|
||||||
<a title='<Tytuł>' href='https://siska.video/video.php?videoID=<n>'>
|
<a title='<Tytuł>' href='https://siska.video/video.php?videoID=<n>'>
|
||||||
|
|
@ -36,11 +36,18 @@ from app.extractors import browser_get
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
_BASE = "https://siska.video"
|
# Domena siska.video wygasla 2026-09-22 (NXDOMAIN), ten sam serwis dziala dalej pod
|
||||||
|
# siska.tv: te same numery videoID i sciezki miniatur. Adresy w bazie przepisane na
|
||||||
|
# siska.tv tego samego dnia. Kafelki przyjmujemy z obu domen i z www, ale zapisujemy
|
||||||
|
# zawsze jeden kanoniczny adres (_canonical), bo external_id sceny i unikalny klucz
|
||||||
|
# zrodla to sam adres; www.siska.video i siska.video dawaly 103 zdublowane zrodla.
|
||||||
|
_BASE = "https://siska.tv"
|
||||||
|
_HOST_RE = re.compile(r"^https://(?:www\.)?siska\.(?:tv|video)/", re.IGNORECASE)
|
||||||
|
|
||||||
# Kafelek: <a title='..' href='..videoID=N'>. Reszta pól w oknie po tym matchu.
|
# Kafelek: <a title='..' href='..videoID=N'>. Reszta pól w oknie po tym matchu.
|
||||||
_A_RE = re.compile(
|
_A_RE = re.compile(
|
||||||
r"<a\s+title='(?P<title>[^']*)'\s+href='(?P<url>https://siska\.video/video\.php\?videoID=\d+)'",
|
r"<a\s+title='(?P<title>[^']*)'\s+"
|
||||||
|
r"href='(?P<url>https://(?:www\.)?siska\.(?:tv|video)/video\.php\?videoID=\d+)'",
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
_DUR_RE = re.compile(r"th_video_duration'>\s*([\d]{1,2}(?:\s*:\s*[\d]{2}){1,2})\s*<")
|
_DUR_RE = re.compile(r"th_video_duration'>\s*([\d]{1,2}(?:\s*:\s*[\d]{2}){1,2})\s*<")
|
||||||
|
|
@ -49,6 +56,10 @@ _ALT_RE = re.compile(r"alt='([^']*)'")
|
||||||
_CAT_RE = re.compile(r"/category/([^/]+)/", re.IGNORECASE)
|
_CAT_RE = re.compile(r"/category/([^/]+)/", re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
|
def _canonical(url: str) -> str:
|
||||||
|
return _HOST_RE.sub(_BASE + "/", url)
|
||||||
|
|
||||||
|
|
||||||
def _parse_duration(text: str | None) -> int | None:
|
def _parse_duration(text: str | None) -> int | None:
|
||||||
"""`40 : 27` → 2427 (MM:SS); `1 : 05 : 30` → H:MM:SS. None gdy brak."""
|
"""`40 : 27` → 2427 (MM:SS); `1 : 05 : 30` → H:MM:SS. None gdy brak."""
|
||||||
if not text:
|
if not text:
|
||||||
|
|
@ -73,11 +84,13 @@ class SiskaScraper(BaseBrowseScraper):
|
||||||
sitetag = "siskavideo"
|
sitetag = "siskavideo"
|
||||||
|
|
||||||
def _listing_url(self, page: int) -> str:
|
def _listing_url(self, page: int) -> str:
|
||||||
return f"{_BASE}/page/{page}/"
|
# Na siska.tv `/page/<n>/` oddaje zawsze strone 1. Najnowsze po kolei (18 na
|
||||||
|
# strone, videoID malejaco) sa pod `best_xvideos.php`, mimo nazwy.
|
||||||
|
return f"{_BASE}/best_xvideos.php?page={page}"
|
||||||
|
|
||||||
# crawl_page nadpisany → poniższe abstrakcje nieużywane, ale wymagane do instancji.
|
# crawl_page nadpisany → poniższe abstrakcje nieużywane, ale wymagane do instancji.
|
||||||
def _extract_scene_urls(self, listing_html: str) -> list[str]:
|
def _extract_scene_urls(self, listing_html: str) -> list[str]:
|
||||||
return [m.group("url") for m in _A_RE.finditer(listing_html)]
|
return [_canonical(m.group("url")) for m in _A_RE.finditer(listing_html)]
|
||||||
|
|
||||||
def _parse_detail(self, scene_url: str, detail_html: str) -> RawScene | None:
|
def _parse_detail(self, scene_url: str, detail_html: str) -> RawScene | None:
|
||||||
return None
|
return None
|
||||||
|
|
@ -94,7 +107,7 @@ class SiskaScraper(BaseBrowseScraper):
|
||||||
out: list[RawScene] = []
|
out: list[RawScene] = []
|
||||||
seen: set[str] = set()
|
seen: set[str] = set()
|
||||||
for m in _A_RE.finditer(html):
|
for m in _A_RE.finditer(html):
|
||||||
scene_url = m.group("url")
|
scene_url = _canonical(m.group("url"))
|
||||||
if scene_url in seen:
|
if scene_url in seen:
|
||||||
continue
|
continue
|
||||||
seen.add(scene_url)
|
seen.add(scene_url)
|
||||||
|
|
@ -106,7 +119,7 @@ class SiskaScraper(BaseBrowseScraper):
|
||||||
dm = _DUR_RE.search(window)
|
dm = _DUR_RE.search(window)
|
||||||
duration_sec = _parse_duration(dm.group(1) if dm else None)
|
duration_sec = _parse_duration(dm.group(1) if dm else None)
|
||||||
tm = _THUMB_RE.search(window)
|
tm = _THUMB_RE.search(window)
|
||||||
thumbnail_url = tm.group(1) if tm else None
|
thumbnail_url = _canonical(tm.group(1)) if tm else None
|
||||||
|
|
||||||
# alt='Performer - Tytuł - Studio' → performer (pierwszy), studio (ostatni).
|
# alt='Performer - Tytuł - Studio' → performer (pierwszy), studio (ostatni).
|
||||||
performers: list[RawPerformer] = []
|
performers: list[RawPerformer] = []
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue