"""Direct tube scrapers. Każdy scraper hit'uje tube bezpośrednio HTTPm — różne tube'y to różne rate limit budgets, więc mogą iść równolegle. Wszystkie feedują sceny do tej samej `Source(name=SCRAPER_SOURCE_NAME)` z external_id `f"{sitetag}:{url}"`. Resolver mergeuje idempotentnie po tym kluczu. Nazwa źródła: do 2026-06-07 brzmiała `"pornapp"` — myląca pozostałość po usuniętym zewnętrznym porn-app API (sugerowała zależność od obcego serwisu, której NIE MA — to nasze własne direct-scrapery tubów). Przemianowana na `"tube-scraper"`; wiersz `sources` zaktualizowany w DB (UPDATE name) więc cała historia ingest_runs została. Search-based ścieżka (per performer name); category browse'ng przez `categoriesUrl`. UWAGA — speculative scrapers: większość aggregator + special tubes (xmoviesforyou, watchporn, siska, porn4days, porndish, xxxfreewatch, latestleaks, mypornerleak, porndittcom, perverzija, fpoxxx, ...) ma URL templates + regex'y oparte na typowych WordPress conventions. Wymagają post-deploy verification — gdy któryś nie zwraca wyników, sprawdź real search HTML + popraw template/regex w odpowiednim pliku. """ # Umbrella Source.name dla wszystkich direct-scraperów (deep-crawl, browse-latest, # performer-driven). Rename z legacy "pornapp" 2026-06-07 (mylące — nie ma zależności # od zewnętrznego porn-app API). SCRAPER_SOURCE_NAME = "tube-scraper" from app.connectors.direct_scrapers._browse_base import BaseBrowseScraper from app.connectors.direct_scrapers.base import BaseDirectTubeScraper from app.connectors.direct_scrapers.eporner import EpornerScraper from app.connectors.direct_scrapers.fpoxxx import FpoxxxScraper from app.connectors.direct_scrapers.hdporn92 import HDPorn92Scraper # noqa: F401 — kept for backref; disabled from app.connectors.direct_scrapers.hqporner import HQPornerScraper from app.connectors.direct_scrapers.latestleaks import LatestLeaksScraper from app.connectors.direct_scrapers.latestpornvideo import LatestPornVideoScraper from app.connectors.direct_scrapers.mypornerleak import MyPornerLeakScraper from app.connectors.direct_scrapers.perverzija import PerverzijaScraper from app.connectors.direct_scrapers.porn4days import Porn4DaysScraper from app.connectors.direct_scrapers.pornditt import PornDittScraper from app.connectors.direct_scrapers.porndish import PornDishScraper from app.connectors.direct_scrapers.pornhat import PornHatScraper # noqa: F401 — kept for backref; ingest disabled from app.connectors.direct_scrapers.pornhub import PornHubScraper from app.connectors.direct_scrapers.porntrex import PornTrexScraper from app.connectors.direct_scrapers.redtube import RedTubeScraper from app.connectors.direct_scrapers.siska import SiskaScraper from app.connectors.direct_scrapers.sxyland import SxyLandScraper from app.connectors.direct_scrapers.sxyprn import SxyPrnScraper from app.connectors.direct_scrapers.watchporn import WatchPornScraper from app.connectors.direct_scrapers.xhamster import XHamsterScraper from app.connectors.direct_scrapers.xmoviesforyou import XMoviesForYouScraper from app.connectors.direct_scrapers.xnxx import XnxxScraper from app.connectors.direct_scrapers.xvideos import XVideosScraper from app.connectors.direct_scrapers.xxxfreewatch import XxxFreeWatchScraper # noqa: F401 — kept for backref; delisted from app.connectors.direct_scrapers.youporn import YouPornScraper from app.connectors.direct_scrapers.zerodayxx import ZeroDayXXScraper ALL_DIRECT_SCRAPERS: list[type[BaseDirectTubeScraper]] = [ # Existing 4 (verified, in production) HQPornerScraper, # HDPorn92Scraper — wyłączony 2026-05-18. Scene pages to SEO shell: ZERO player iframe # (tylko happyleafmotion ads), JS hijackuje wszystkie kliki → `go.rmishe.com/smartpop/...` # popunder redirect. Mobile WebView page-as-hoster pokazuje ad redirect zamiast video. # 33,598 playback_sources mass-marked dead, 27,374 solo-orphan scenes deleted. SxyLandScraper, # ZeroDayXXScraper — wyłączony 2026-05-12 (source quality report): 25,596 scen, 0.1% canonical # match. Slug-concat tytuły (`bella reese big butt ready to be filled with cum analized`) bez # `[Studio]` lub `Studio - Perf - Title` prefixu (parse rate 3%) → resolver nie ma żadnego # signalu do matchu. Wraps watchporn ale dziedziczy stripped metadata. Solo orphany usunięte # (~21k scen) — plik scrapera + extractor zostają (istniejące playback_sources nadal się # resolvują). # Mainstream (URL templates well-known) # PornHubScraper — wyłączony 2026-05-12 (analiza źródeł): 23,750 scen scrapnietych, # tylko 105 (0.4%) match z TPDB/StashDB. PH hostuje głównie własne shortened # clipy + amateur upload — nigdy nie zmatchują studio canonical content. Plik # zostaje (extractor `pornhubcom` używa go w playback resolve dla istniejących # playback_sources). # RedTubeScraper — wyłączony 2026-05-12 (analiza źródeł): 20,127 scen, 82 match # (0.4%). Same powody co PH (skrócone clipy + amateur upload). XVideosScraper, XnxxScraper, XHamsterScraper, YouPornScraper, PornTrexScraper, EpornerScraper, # Aggregators (WordPress-like ?s= search; speculative — verify post-deploy) # XMoviesForYouScraper — wyłączony 2026-05-12 (post audit fix). 100% scen serwuje # streamtape (DEAD_HOSTER_RE — malware drive-by .reg) + opcjonalnie playmogo/mixdrop. # Mixdrop zrebrandował na m1xdrop.bz, yt-dlp out-of-date, packer/JS extract = fail. # Playmogo = DoodStream CAPTCHA. Porn-app sam olewa xmoviesforyou (brak handlera w # jadx). 1,321 solo-orphan scen. # WatchPornScraper — wyłączony 2026-05-12 (user bug-report). Wszystkie iframes to # DoodStream variants (playmogo/d0000d/dooood/mivalyo) z CAPTCHA gate. WebView na # mobile = black screen (player JS nie inicjalizuje się przez Turnstile). 16% # scen solo (no backup tube), 84% multi-source — user może użyć innego tube. yt-dlp # nie wspiera DoodStream ("Piracy"), własny resolver TBD jeśli warto. # SiskaScraper — wyłączony 2026-05-16, pozostaje WYŁĄCZONY. Rewizja 2026-06-20 # (user fa4083a2): świeże filmy (videoID 227xxx) embedują playmogo + luluvid i # SĄ phone-resolwowalne (_embed_iframe oddaje type='hoster', extractor+regex # zaktualizowane do `video.php?videoID=` w siska.py). ALE search siski jest # ZEPSUTY site-side: `?s=` ignoruje zapytanie i zwraca zawsze latest # (angela white == riley reid == homepage). Jako BaseSearchScraper (performer- # driven) zawsze yielduje 0 → bezcelowy. Żeby ożywić, trzeba PRZEROBIĆ na # browse-scraper (latest chronologicznie) — zmiana charakteru ingestu, do decyzji. # Stare self-player filmy (player.siska.video → cfglobalcdn) z 2018 są martwe. # SiskaScraper, # Porn4DaysScraper — wyłączony 2026-05-12 (post audit fix). 100% scen na streamtape # only (DEAD_HOSTER_RE blacklist - malware drive-by .reg downloads). SERVER1_URL = # streamtape, brak SERVER2/SERVER3 backup. Porn-app sam olewa porn4days. 10,346 # solo-orphan scen. PornDishScraper, # XxxFreeWatchScraper — wyłączony 2026-05-18. 790 scen, 0% canonical match, 100% solo-orphan. # Cloudflare 403 z VPS IP, mobile WebView teoretycznie działa ale 0/790 scen miało jakikolwiek # match do TPDB/StashDB. Pure orphan factory. Solo scenes deleted, scraper disabled. LatestPornVideoScraper, # LatestLeaksScraper — wyłączony 2026-05-12 (source quality report): 16,438 scen, 0.0% # canonical match. Slug-concat tytuły, brak studio/duration/date signali. Solo orphany # usunięte (~15k scen). MyPornerLeakScraper, # Added 2026-05-12 (theporndude survey): jeden z 14 free tubes na liście który # zwraca consistent search results. KVS engine, slug-aware scene URLs. Mostly # orphan ingest (auto-screenshots, no canonical phash match — sprawdzone), ale # może łapać sceny popularnych performerów których jeszcze nie mamy w TPDB. # PornHatScraper — wyłączony 2026-05-18. 9,799 scen, 0.2% canonical match, 100% solo-orphan. # Pure orphan factory — auto-screenshot thumbs nie matchują phash do canonical, slug tytuły # nie matchują rapidfuzz, brak duration/date signals. KEEP `pornhatcom` extractor i istniejące # playback_sources żywe — mobile może je odtwarzać; disable tylko future ingest. # PornDittScraper — wyłączony 2026-05-12 (bug-report 64356e9b). Każdy link # produkował nową Scene row zamiast matchować do istniejącej kanonicznej # (TPDB/StashDB) bo pornditt ma weak signal: title + cz. performera, brak # fingerprintu/duration/date → composite_score zawsze poniżej auto_merge # threshold (0.92). Plik scrapera + extractor zostają (istniejące playback_sources # nadal się resolvują, _REGISTRY w app/extractors/__init__.py odpala # `porndittcom` → _embed_iframe.extract). Re-enable wymaga albo # "alternative-source mode" w resolverze (match-only, never create new), # albo bogatszej extracji metadanych (duration + fingerprint). # Special SxyPrnScraper, PerverzijaScraper, FpoxxxScraper, ] # Browse-mode scrapers — iterują `latest-vids` listing zamiast search-by-performer. # Phash thumbnail fingerprint (waga 0.40 w composite scoring) auto-mergeuje do # canonical (TPDB/StashDB) gdy tube hot-linkuje studio thumbnail. Schedulowane # raz dziennie, pages 1-5. Patrz `_browse_base.BaseBrowseScraper` + # `app/scheduler/browse_latest.py`. # # **Pilot results (2026-05-12):** # - ShyfapScraper: 0/23 match (0%) — robi własne thumbnails ≠ canonical # (phash Hamming 12-16). Plus rebranduje tytuły. **Wyłączony.** # - FreshpornoScraper: 39/59 match (66%) — hot-linkuje studio thumbnaile # (phash Hamming 0). Oryginalne tytuły + channels=studio 1:1. **Aktywny.** from app.connectors.direct_scrapers.freshporno import FreshpornoScraper # noqa: E402 from app.connectors.direct_scrapers.porn00 import Porn00Scraper # noqa: E402 from app.connectors.direct_scrapers.porndoe import PornDoeScraper # noqa: E402 from app.connectors.direct_scrapers.pornxp import PornXPScraper # noqa: E402 from app.connectors.direct_scrapers.shyfap import ShyfapScraper # noqa: E402, F401 from app.connectors.direct_scrapers.yesporn import YesPornVipScraper # noqa: E402 from app.connectors.direct_scrapers.fullmovies import FullmoviesScraper # noqa: E402 from app.connectors.direct_scrapers.hdporngg import HDPornGGScraper # noqa: E402 from app.connectors.direct_scrapers.fourk69 import FourK69Scraper # noqa: E402 from app.connectors.direct_scrapers.hqfap import HQFapScraper # noqa: E402 from app.connectors.direct_scrapers.neporn import NepornScraper # noqa: E402 from app.connectors.direct_scrapers.superporn import SuperpornScraper # noqa: E402 from app.connectors.direct_scrapers.eporner_api import EpornerApiScraper # noqa: E402 from app.connectors.direct_scrapers.xvideos_browse import XVideosBrowseScraper # noqa: E402 ALL_BROWSE_SCRAPERS: list[type[BaseBrowseScraper]] = [ FreshpornoScraper, # PornXPScraper — pilot 2026-05-17 (20 scen): studio 100%, performer 95%, # release_date 100%, duration 100%, stream_url 100%, phash 100%. Najlepsze # sygnały spośród browse-mode scraperów. Stream direct mp4 (sv.porn-xp.com) # 360/720 quality. Release year z `Released: ` na detail. PornXPScraper, # Porn00Scraper — pilot 2026-05-17 (16 scen): brak studio (0%) + brak release # date (0%) ALE performer 100%, duration 100%, stream_url 100% (KVS video_alt_url # 720p). Tytuł zachowuje studio prefix ("Studio Title - Scene Name") → title # fuzzy match (rapidfuzz token_set_ratio) może załapać canonical. Monitorować. Porn00Scraper, # PornDoeScraper — dołączony 2026-05-21 (theporndude audit). Każda scena ma # kompletny JSON-LD VideoObject: title + uploadDate + duration + named studio # (producer/publisher) + named performers (actor[]) + thumbnail. Najbogatsze # strukturalne metadane spośród browse scraperów — composite fuzzy match ma # komplet sygnałów. Phash hit-rate niski (własne crop-thumbnaile), studio + # performer + date + duration nadrabiają. PornDoeScraper, # YesPornVipScraper — dołączony 2026-05-27 (user audit). JSON-LD VideoObject # + `` per scena (Goon ma # duration w sekundach gotowe + ISO 8601 release_date z timezone). Studio + # performerzy z `btn gold` linków (`/channels//` + `/models//`). # 941k organic monthly (SE Ranking, comparable z porndoe 731k / porntrex 790k). # Scraper-of-paysites (DogFart / HardX / TeamSkeet / Vixen) — wysokie expected # canonical match dla studio scenes. Korekta: theporndude scorecard rank 26 # ('yespornvip.com', score -0.5, auth wall) dotyczył **innej domeny** — pdude.link # redirect do porndudecams affiliate. Prawdziwa kanoniczna domena to TLD `.vip`. YesPornVipScraper, # FullmoviesScraper + HDPornGGScraper — dołączone 2026-06-01. KVS engine (sponsor_groups # stack, `/videos//` + `/latest-updates/`). Studio teraz z PREFIKSU tytułu # ("Studio - Scene") — sidebar `/networks/` listował WSZYSTKIE sieci, więc pierwszy match # zawsze Brazzers (mis-attribution, dlatego nigdy nie były włączone). Niosą paysite studio # content (TeamSkeet/Dad Crush/Brazzers/...) z title+performer+duration → composite fuzzy. # Nawet bez canonical match: grywalny content z inferred tagami (mission: daily tagged ingest). FullmoviesScraper, HDPornGGScraper, # EpornerApiScraper — dołączony 2026-06-03 (Faza 2b alternatywa). eporner detail to # JS-heavy KVS bez SSR metadanych (jak porntrex/hqporner — odrzucone), ALE eporner ma # publiczne JSON API (api/v2/video/search): 1 call = 100 filmów z title+length_sec+ # keywords+added+thumb. ~100k filmów, deep-crawl przez crawl_page() (API, bez detail-fetch). EpornerApiScraper, # XVideosBrowseScraper — dołączony 2026-06-03. SSR JSON-LD (duration/title/uploadDate) # + page-parse /models/ (performerzy) + /tags/. Sample: median ~10.5min, 93% ≥3min. # Mega-katalog ~13M → deep_crawl._PAGE_CAP["xvideoscom"]=1800 (~50k najnowszych), nie # full-crawl. (youporn pominięty — JSON-LD bez actor/keywords, scene-perf/tagi = nav A-Z.) XVideosBrowseScraper, # HQFapScraper — dołączony 2026-06-10 (user request). PlayTube CMS, ~120k scen # (re-upload pornhd.pet). JSON-LD VideoObject (title+uploadDate+duration+thumb+ # contentUrl) + pille Pornstars/Categories na detail page. Listing nie paginuje # się GET-em → crawl_page po sitemap index (12 plików, lastmod desc). Direct mp4 # (cdnde.com / okcdn.ru), cross-IP portable → natywny extractor `hqfapcom`. HQFapScraper, # FourK69Scraper — dołączony 2026-06-10 (user request). Probe 2026-06-01 odrzucił # po homepage "JS-rendered" — błędnie: scene pages mają pełny SSR + JSON-LD. Ta sama # platforma PlayTube co hqfap (wspólna baza _playtube.py), ~65k scen, content głównie # studyjny (4K paysite re-upload). Studio z kategorii matchowanych do listy /studios. # Stream get_file (www.4kporno.xxx) jak fullmovies → mobile_direct, skip 2160p. FourK69Scraper, # NepornScraper — dołączony 2026-06-10 (user request). KVS engine (jak freshporno/ # porn00), /latest-updates/N/. JSON-LD (title+desc+uploadDate+thumb) + video:duration # meta + /models/ performerzy + /categories/ tagi. Brak studio (tytuł bywa # "- HardX Update - ..." — fuzzy match po tytule). Resolve server-side _kvs, # finalny remote_control.php portable cross-IP. NepornScraper, # SuperpornScraper — dołączony 2026-06-10 (user request). superporn blokuje VPS IP # twardym CF 403 (każda impersonacja TLS), więc ingest HTML idzie przez Bright Data # ISP proxy (BRIGHTDATA_PROXY_URL, ryczałt nie per-GB). Pierwszy scraper z proxy — `_proxy` w # _browse_base. JSON-LD (title+desc+uploadDate+thumb+duration) + chipy pornstar/ # kategorie. Playback IP-bound → WebView (extractor superporncom → _vps_blocked_fallback). # Bez proxy: scraper no-op (pusty iterator). SuperpornScraper, # porntrex/hqporner/youporn — NIE: KVS/JS bez SSR duration → niewidoczne orphany (2026-06-03). # ShyfapScraper — wyłączony 2026-05-12 (pilot fail, 0% match — orphan factory). ] __all__ = [ "BaseDirectTubeScraper", "BaseBrowseScraper", "ALL_DIRECT_SCRAPERS", "ALL_BROWSE_SCRAPERS", ]