diff --git a/app/connectors/direct_scrapers/siska.py b/app/connectors/direct_scrapers/siska.py
index 9c06c04..1395642 100644
--- a/app/connectors/direct_scrapers/siska.py
+++ b/app/connectors/direct_scrapers/siska.py
@@ -45,14 +45,16 @@ _BASE = "https://siska.tv"
_HOST_RE = re.compile(r"^https://(?:www\.)?siska\.(?:tv|video)/", re.IGNORECASE)
# Kafelek: . 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"[^']*)'\s+"
+ r"[^<>]*?)'\s+"
r"href='(?Phttps://(?: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)}",
diff --git a/tests/test_siska_listing.py b/tests/test_siska_listing.py
new file mode 100644
index 0000000..80d4a7c
--- /dev/null
+++ b/tests/test_siska_listing.py
@@ -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 = """
+
+
+"""
+
+
+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"