goon/app/connectors/direct_scrapers/hqfap.py
jtrzupek 80fd83cb4e feat(tubes): add 4k69 + neporn browse scrapers, shared PlayTube base
4k69.com (~65k scenes): same PlayTube CMS as hqfap - common logic moved
to _playtube.py (sitemap catalog, JSON-LD, pills). Studio classified by
matching category pills against the studios index page. Streams are
get_file (fullmovies family) returned unresolved with mobile_direct,
2160p skipped.

neporn.com: KVS engine, latest-updates listing, JSON-LD + video:duration
meta, performers from models links with flashvars video_tags fallback
for fresh uploads. Resolve via _kvs; final URL portable cross-IP.

superporn.com rejected: Cloudflare 403 from VPS on all TLS impersonations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 18:15:13 +02:00

26 lines
1 KiB
Python

"""hqfap.com — latest-vids browse scraper (PlayTube CMS, patrz _playtube.py).
Dołączony 2026-06-10 (user request). Re-uploader katalogu pornhd.pet (~120k scen,
thumbnaile to base64-encoded oryginalne URL-e w `/uploads/images/`).
Specyfika vs baza: studio siedzi w kategoriach z suffixem " Clips"
("Filthy Kings Clips" → studio "Filthy Kings"); reszta kategorii → tagi.
Playback: direct mp4 z JSON-LD contentUrl (cdnde.com nowsze / okcdn.ru starsze),
tokeny time-bound i portable cross-IP → natywny extractor `hqfapcom`.
"""
from __future__ import annotations
from app.connectors.direct_scrapers._playtube import BasePlayTubeScraper
class HQFapScraper(BasePlayTubeScraper):
sitetag = "hqfapcom"
base_url = "https://hqfap.com"
def _pick_studio(self, category_names: list[str]) -> str | None:
for name in category_names:
if name.lower().endswith(" clips"):
studio_name = name[: -len(" clips")].strip()
if studio_name:
return studio_name
return None