fix(siska): kafelki z apostrofem w tytule i kilka osob w jednym nazwisku
Some checks are pending
Backend tests / test (push) Waiting to run

Strona nie escapuje apostrofu w title/alt, wiec "Brenna's Mouths" urywal
dopasowanie i kafelek wypadal (3 z 18 na stronie). Pierwszy czlon alt z
kilkoma osobami ("A, B - Tytul") szedl jako jeden wykonawca.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
goon-foss 2026-09-27 19:14:47 +02:00
parent 9225ae95de
commit 494b15aedd
2 changed files with 53 additions and 9 deletions

View file

@ -45,14 +45,16 @@ _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.
# Strona nie escapuje apostrofu w atrybutach (title='Brenna's Mouths'), wiec wartosc
# konczy sie na apostrofie, po ktorym idzie nastepny atrybut, a nie na pierwszym.
_A_RE = re.compile(
r"<a\s+title='(?P<title>[^']*)'\s+"
r"<a\s+title='(?P<title>[^<>]*?)'\s+"
r"href='(?P<url>https://(?:www\.)?siska\.(?:tv|video)/video\.php\?videoID=\d+)'",
re.IGNORECASE,
)
_DUR_RE = re.compile(r"th_video_duration'>\s*([\d]{1,2}(?:\s*:\s*[\d]{2}){1,2})\s*<")
_THUMB_RE = re.compile(r"data-src='([^']+\.(?:jpg|jpeg|webp|png))'", re.IGNORECASE)
_ALT_RE = re.compile(r"alt='([^']*)'")
_ALT_RE = re.compile(r"alt='([^<>]*?)'(?=\s+[\w-]+=|\s*/?>)")
_CAT_RE = re.compile(r"/category/([^/]+)/", re.IGNORECASE)
@ -122,21 +124,22 @@ class SiskaScraper(BaseBrowseScraper):
thumbnail_url = _canonical(tm.group(1)) if tm else None
# alt='Performer - Tytuł - Studio' → performer (pierwszy), studio (ostatni).
# Kilka osob stoi w pierwszym czlonie po przecinku ("A, B - Tytul").
performers: list[RawPerformer] = []
studio: RawStudio | None = None
am = _ALT_RE.search(window)
if am and " - " in am.group(1):
parts = [p.strip() for p in am.group(1).split(" - ") if p.strip()]
if len(parts) >= 2:
pname = parts[0]
sname = parts[-1]
if pname:
performers.append(
RawPerformer(
external_id=f"{self.sitetag}:performer:{_slugify(pname)}",
name=pname,
for pname in (n.strip() for n in parts[0].split(",")):
if pname:
performers.append(
RawPerformer(
external_id=f"{self.sitetag}:performer:{_slugify(pname)}",
name=pname,
)
)
)
if sname and len(parts) >= 3:
studio = RawStudio(
external_id=f"{self.sitetag}:studio:{_slugify(sname)}",

View file

@ -0,0 +1,41 @@
from app.connectors.direct_scrapers import siska
from app.connectors.direct_scrapers.siska import SiskaScraper
# Dwa kafelki jak na siska.tv 2026-09-27; pierwszy z nieescapowanym apostrofem.
_LISTING = """
<li class='pure-u-1-3'><div class='back'><div class='thumb'><div class='rel'>
<a title=' Filling Chanel and Brenna's Mouths' href='https://siska.tv/video.php?videoID=226988' class='video-thumb'><span class='icon-hd'></span><span class='th_video_duration'>36 : 58</span><span class='th_photo_count'><span class='ico-photo'></span></span><img src='data:image/png;base64,R0lGOD' data-src='https://siska.tv/category/Deep-Throat/1049123346.jpg' width='640' height='360' alt='Chanel Camryn, Brenna McKenna - Filling Chanel and Brenna's Mouths' class='pure-img padding' /></a></div>
</div></div></li>
<li class='pure-u-1-3'><div class='back'><div class='thumb'><div class='rel'>
<a title='Plain Title' href='https://www.siska.video/video.php?videoID=226987' class='video-thumb'><span class='th_video_duration'>1 : 02 : 03</span><img data-src='https://siska.tv/category/Anal/1049123345.jpg' alt='Jane Doe - Plain Title - Some Studio' class='pure-img' /></a></div>
</div></div></li>
"""
class _Res:
text = _LISTING
def _crawl(monkeypatch):
monkeypatch.setattr(siska, "browser_get", lambda url, timeout=None: _Res())
monkeypatch.setattr(siska, "compute_thumbnail_phash", lambda *a, **k: None)
return SiskaScraper().crawl_page(1)
def test_apostrophe_in_title_keeps_tile(monkeypatch):
scenes = _crawl(monkeypatch)
assert [s.url for s in scenes] == [
"https://siska.tv/video.php?videoID=226988",
"https://siska.tv/video.php?videoID=226987",
]
assert scenes[0].title == "Filling Chanel and Brenna's Mouths"
assert scenes[0].duration_sec == 36 * 60 + 58
def test_comma_separated_performers_are_split(monkeypatch):
first, second = _crawl(monkeypatch)
assert [p.name for p in first.performers] == ["Chanel Camryn", "Brenna McKenna"]
# dwa czlony alt = osoby + tytul, studia brak
assert first.studio is None
assert [p.name for p in second.performers] == ["Jane Doe"]
assert second.studio.name == "Some Studio"