43 KiB
43 KiB
Provider And Proxy Catalog
This is the current implementation inventory as of this snapshot of the repo. Use it to find the nearest existing pattern before adding a new channel.
Providers
| Provider | Group | /api/uploaders |
Uses local /proxy |
Notes |
|---|---|---|---|---|
all |
meta-search |
no | no | Aggregates all compiled providers. |
allpornstream |
mainstream-tube |
no | yes | Next.js App Router scraper; extracts cards via data-thumb-id/href/title/images attributes; redirect proxy lazy-resolves VOE/DoodStream/StreamTape/FileMoon embeds. |
animeidhentai |
hentai-animation |
no | yes | Next.js hentai site (animeidhentai.com) backed by a clean JSON API: latest feed GET /api/browse?page=N ({videos:[28],total,pages}, real pagination, ignores sort/genre params) and search GET /api/search?q=Q&page=N ({videos:[8]}, matches titles AND tags). Each episode JSON carries slug/titleSlug/ep, title, tags[], views, rating (0-10 → ×10 for the 0-100 scale), duration ("MM:SS"), brand (studio → uploader), releasedAt (RFC3339 → uploadedAt), relative thumb/backdrop images (served from animeidhentai.com/uploads/..., no referer), and an embedUrl of the form https://nhplayer.com/v/{embedId}/. video.url is the reachable series page https://animeidhentai.com/series/{titleSlug} (the per-episode watch route 307-redirects to /; episodes are watched on the series page). genre:/tag:/cat:/category: query prefixes and the categories filter (curated genre list, sanitized out of /api/status but honored in /api/videos) route to /api/search since browse can't filter by genre. Playback: yt-dlp cannot resolve nhplayer, whose real MP4 sits on a Cloudflare-fronted R2 bucket (r2.1hanime.com) behind a signed ?verify=<ts>-<sig> token minted by an obfuscated JS challenge (player.php → player-core-v2.php → get-video-url-v2.php): a SHA-256 proof-of-work over five DOM-embedded parts + a fixed fingerprint + a ≥700ms server-enforced dwell time, all replicated in src/proxies/animeidhentai.rs. The signed URL further needs a browser TLS JA3 to clear Cloudflare — curl_cffi/AVFoundation pass but our wreq stack is JA3-blocked on every emulation profile — so the proxy cannot stream server-side. /proxy/animeidhentai/{embedId}.mp4 is therefore a redirect proxy (like jable): HEAD→200 (so health checks/yt-dlp media detection pass on the .mp4 extension), GET→302 to the freshly-resolved CDN URL, which the client fetches directly (yt-dlp resolves it with --impersonate chrome). Resolved URLs are cached 150s. No /api/uploaders (no stable uploader identity; brand is studio-only). |
archivebate |
live-cams |
no | no | Livewire-backed cam archive listings with platform/gender/profile shortcuts. |
beeg |
mainstream-tube |
no | no | Basic mainstream tube pattern. |
blowjobspro |
mainstream-tube |
no | no | KVS-style HTML provider with async search pagination and category shortcut routing. |
chaturbate |
live-cams |
no | no | Live cam channel. |
clapdat |
amateur-homemade |
no | yes | Svelte/JSON-hydrated provider using home/recent/trending routes, Meilisearch keyword search, and /proxy/clapdat/... redirect playback resolution. |
erome |
amateur-homemade |
no | no | HTML album scraper with hot/new feeds, keyword search, and uploader-slug shortcuts (uploader:<name>). |
fikfap |
tiktok |
yes | yes (thumbs only) | JSON-API provider for fikfap.com (TikTok-style swipe short clips); anonymous auth via a client-generated Authorization-Anonymous UUID header (no real login needed); listing via GET api.fikfap.com/posts?sort=new|trending|random&amount=N&afterId=<lastPostId> (cursor pagination — page N costs N sequential requests); search via GET search?q= (single fixed-size batch, no pagination — page 2+ returns empty); hashtag feeds via GET hashtags/label/{label}/posts and creator feeds via GET profile/username/{user}/posts, both also cursor-paginated; tag:/hashtag:/# and user:/uploader: query prefixes route directly; categories option exposes a small curated static hashtag list (no full catalog endpoint exists anonymously); video.url is the fikfap.com/post/{id} page (a client-rendered SPA, not yt-dlp-resolvable on its own); videoStreamUrl from the JSON response is sent directly as formats[0].url (signed Bunny CDN HLS .m3u8, ~24h token expiry) with httpHeaders: {Referer: https://fikfap.com/} — Hot Tub clients apply a format's http_headers across the whole HLS playback session (manifest, sub-playlists, and segments), so no proxying of the media itself is needed; thumbnails have no per-field header mechanism, so they're proxied via /proxy/fikfap-thumb/... to inject the same Referer; get_uploader implemented (fikfap:<username> IDs) using GET profile/username/{user}. |
freepornvideosxxx |
studio-network |
no | no | Studio-style scraper. |
fyptt |
tiktok |
no | no | HTML scraper for fyptt.to (Beaver Builder/WordPress short-form TikTok-style vertical porn); card selector .fl-post-grid-post[class*="post-ID"] with category-{slug} CSS class doubling as both listing tag and category-archive route; latest feed / (page N: /page/N/), search /?s=query (page N: /page/N/?s=query), category archives at bare top-level slugs like /tiktok-ass/ (12 hardcoded categories exposed via the categories filter option, or via an explicit cat:/category: query prefix — bare keyword queries always go to WordPress search, never a category archive, because the category names ("sexy", "ass", "tiktok", "live", ...) are also the most common search terms); per-item enrichment fetches the detail page for the JSON-LD embedURL (one of three on-site player endpoints: fypttstr.php, fypttjwstr.php, or fypttjwstrhls.php) and datePublished, then fetches that embed URL to extract the actual signed stream.fyptt.to mp4 or /hls/*.m3u8 URL (token expires ~2h, no Referer required) for formats; thumbnails (fyptt.to/wp-content/uploads/...webp) need no proxy; no duration metadata available on listing or detail pages (set to 0); no real uploader/model identity (the girl-{slug} CSS class is cosmetic only, not a linkable archive) so /api/uploaders is not implemented; video.url is the detail page URL (not yt-dlp resolvable directly — the player is sandboxed-iframe-only) so formats are populated instead; no proxy needed. |
freeuseporn |
fetish-kink |
no | no | Fetish archive pattern. |
hanime |
hentai-animation |
no | yes | Uses proxied CDN/thumb handling. |
heavyfetish |
fetish-kink |
no | no | Direct media handling. |
hentaihaven |
hentai-animation |
no | no | HTML scraper for hentaihaven.xxx (WordPress/Madara theme), Cloudflare-protected so the provider is gated behind FLARE_URL in skip_reason_for_provider (mod.rs); the shared requester clears CF directly (wreq Firefox136 emulation currently passes for the listing/search/watch/episode/player.php GETs) and falls back to Jina/FlareSolverr. Latest feed /hentai/page/{N}/, search /?s={query} (search is single-page — page>1 returns empty); listing/search cards link to series watch pages https://hentaihaven.xxx/watch/{slug}/. Per-series media resolution (the UUID exists nowhere in page HTML, so enrichment is unavoidable): watch page → episode links …/watch/{slug}/episode-K (in manga-chapters-holder) → episode page → <iframe src="…/wp-content/plugins/player-logic/player.php?data=…"> → player.php → <meta name="x-secure-token" content="sha512-…"> → decode token (strip sha512-, then 3× of rot13→base64-decode, then JSON.parse) → {en, iv, uri, hot_domains, …} → POST …/wp-content/plugins/player-logic/api.php with action=zarat_get_data_player_ajax&a={en}&b={iv} (urlencoded; this one POST uses a dedicated wreq Chrome137 client, not the shared requester) → {"status":true,"data":{"sources":[{"src":"…m3u8"}],"isOctopus":bool}}. A multi-episode series collapses into one VideoItem titled "… (N Episodes)" with one m3u8 VideoFormat per episode (format_note/format_id = "Episode K"); each format carries Referer/Origin: https://hentaihaven.xxx + a Firefox User-Agent. video.url is the watch/{slug}/ page (no yt-dlp extractor exists for the site, so formats are populated rather than relying on video.url). Two CDN shapes are returned: newer content-addressed octopusmanifest.org/{uuid}/playlist.m3u8 (no token, portable across IPs) and older signed master-lengs.org/api/v3/hh/{slug}/master.m3u8?hash=… (~2.5h). Gotcha: both CDNs (same IP) aggressively per-IP rate-limit/ban with a TCP RST on 80/443 once tripped — looks like "host down" but is an IP ban; browsers play fine over HTTP/3 (QUIC) while TCP clients (curl/yt-dlp/wreq) get refused, so segment fetches can fail from a tripped IP even though the manifest URL is valid. Tags from the series "Genre(s)" block; views from the "Viewed … Total" counter; thumbnails (img.hentaihaven.xxx) load directly (no proxy/referer). Resolution is slow (each listing page = ~25 series × multi-episode player-API calls), so the provider is DB-first: it fetches the listing once for the ordered watch URLs, serves already-resolved VideoItems from the videos SQLite table instantly (db::upsert_video to avoid duplicate-row staleness), and spawn_refreshes the whole page in the background (in-memory VideoCache soft-TTL 1h / hard-TTL 24h, per-listing in-flight guard). No /api/uploaders (no uploader identity), no proxy. |
hentaitv |
hentai-animation |
no | yes | Next.js hentai site (hentai.tv) backed by a clean JSON API: GET /api/browse?page=N&sort=<Label>&genres=<ExactName> ({videos:[28],total,pages}, real pagination) and GET /api/search?q=Q ({videos:[...]}, single-page — page is ignored, so page>1 returns empty). Unlike animeidhentai, browse honors both sort (labels Most Recent/Most Viewed/Trending, mapped from option ids new/views/trending) and genres (the exact case-sensitive stored genre name, e.g. Big Boobs, incest), so genre archives go through /api/browse?genres= and paginate. The 68-genre catalogue (exact names) is background-loaded from the /browse page HTML ("genres":[{"name","count"}], not exposed by the JSON API) and powers the categories filter plus keyword→genre routing. Each episode JSON has slug, title/ep, tags[], views, rating (0-10 → ×10), duration ("MM:SS"), brand (studio → uploader), thumb/backdrop/cover (relative, served from hentai.tv/uploads/..., no referer), and embedUrl=https://nhplayer.com/v/{embedId}/. video.url is the reachable watch page https://hentai.tv/hentai/{slug}; genre:/cat:/category: prefixes and bare keywords that exactly match a genre route to the genre archive, everything else to search. Playback shares the same nhplayer→r2.1hanime.com signed-CDN backend as animeidhentai: /proxy/hentaitv/{embedId}.mp4 is a redirect proxy that replicates nhplayer's PoW+DOM challenge (player.php→player-core-v2.php→get-video-url-v2.php, SHA-256-first-byte-zero PoW, ≥700ms dwell, fixed fingerprint) to mint a signed ?verify=<ts>-<sig> URL — HEAD→200, GET→302 to the CDN URL (cached 150s). The CF wall is JA3-based not IP-based, so the signed URL is verifiable from anywhere with yt-dlp --impersonate chrome even though plain curl/wreq get 403. src/proxies/hentaitv.rs is a near-copy of src/proxies/animeidhentai.rs (only SITE_REFERER differs). No /api/uploaders (brand is studio-only). |
homoxxx |
gay-male |
no | no | Gay category grouping example. |
hotbunny |
ai |
no | yes (thumbs only) | JSON-API provider for hotbunny.ai (AI-generated hentai community). Feeds: GET /api/post/feed?limit=N (hot), /api/post/feed/popular, /api/post/feed/recents, /api/post/category/{cuid}?limit=N, /api/post/search?query=Q&limit=N, /api/post/author/{name}/all?limit=N. Pagination: fetch page × per_page items in one call and slice (cursor-based API, but limit works up to 200 total). Key fields: id, imageUrl (relative thumbnail path on CDN), authorName, likes (→ views), sharedVideos[].videoUrl (first video path, relative to CDN), width/height, galleries[].label (used as title prefix). 15 hardcoded categories from /api/categories (stable CUIDs). video.url is the post page https://hotbunny.ai/post/{id} (React SPA, not yt-dlp-resolvable); formats[0].url = https://assets.hotbunny.ai/{sharedVideos[0].videoUrl} with Referer: https://hotbunny.ai/ header. assets.hotbunny.ai is Cloudflare bot-management protected (returns 404 to plain curl/yt-dlp; iOS AVFoundation passes with real Apple TLS — no proxy wrapping needed for video). Thumbnails proxied via /proxy/hotbunny-thumb/... to inject the required Referer. Supports uploader:/author:, cat:/category:/#tag query shortcuts, categories filter option, and sort option (feed/popular/recent). |
hqporner |
studio-network |
no | yes | Uses thumb and redirect proxy helpers. |
hsex |
chinese |
yes | no | Strong template for tags, uploaders, and direct HLS formats. |
hypnotube |
fetish-kink |
no | no | Fetish/tube hybrid. |
javtiful |
jav |
no | no | JAV channel family. |
melonstube |
mainstream-tube |
no | yes | Meta-search aggregator for melonstube.com — every card is an /out/?l=<base64>&c=<hash>&v=3 redirect link whose destination (a third-party host) is embedded, zero-network, in a MessagePack blob under the l param (mixed binary/string fields: view/click counts, a JSON date-range blob, an array of related-video ids, and the destination URL itself as one msgpack string). Decoding is local: base64-decode l, then regex-extract the https?://... destination directly out of the raw (lossy-UTF8-converted) msgpack bytes — the regex must be a positive allowlist of legal URI characters ([A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+), not a denylist of a few excluded characters: the byte immediately following the msgpack string (a length-prefix marker for the next field, e.g. \xcd) lossy-converts to U+FFFD (code point 0xFFFD), which a denylist limited to ASCII control chars ([^\x00-\x1f\\"']) fails to exclude, silently appending a corrupt trailing character to the URL. Feeds: /new (latest), /popular, /rating (all three are static curated lists, ~120 items, true pagination via ?page=N); search is NOT the vestigial /search?q= GET endpoint (returns generic filler content behind a fake static result counter regardless of query) — the real mechanism mirrors the site's own search form: POST search_query[query]=<term> to /searching/by-form, which 303-redirects (cookies + redirect auto-followed by the shared Requester) to a resolved, genuinely query-relevant destination depending on entity match — /pornstar/<slug>, /category/<slug>, /search/a/<term> (studio), or /search/<term> (generic free text) — all of which support ?page=N pagination; a non-matching query resolves to a page with zero result cards, which parse_listing naturally returns as empty. Destination hosts fall into three buckets: (1) the common case — yt-dlp (--impersonate chrome-120) resolves the destination directly, so video.url is just the decoded destination URL, no proxy; (2) JUNK_HOSTS (currently fhgte.com) — observed dead-end paywall/signup funnels with no free playable video, so cards pointing there are dropped entirely rather than surfaced as false-positive results; (3) HARD_HOSTS (manysex.com, videomanysex.com) — yt-dlp cannot resolve these, so video.url is routed through /proxy/melonstube/{host}/{path}. The proxy (src/proxies/melonstube.rs) ports vjav.rs's Cyrillic-homoglyph-obfuscated base64 decode chain to pull the real get_file path/query out of videofile.php's video_url field, then makes two manual (non-auto-redirect) hops to the final CDN URL: hop 1 needs the manysex.com/videomanysex.com page as Referer; hop 2 (to the signed ahcdn.com URL) must be sent with no Referer at all, because the CDN's signed URL embeds a literal referer=none,.manysex.com,.gstatic.com allow-list that rejects the videomanysex.com Referer used on hop 1 — auto-redirect clients that forward the same Referer to every hop get a 403 at hop 2. Before returning the 302, an anti-false-positive check confirms the resolved URL string contains the requested numeric video id and that a ranged GET (Range: bytes=0-65535) returns 200/206 with a video/*/octet-stream content-type, so a paywall/ad/error page can't masquerade as the real stream. Thumbnails (ttcache.com) load directly, no proxy. No /api/uploaders (aggregator has no stable uploader identity). |
missav |
jav |
no | no | HLS format pattern. |
noodlemagazine |
mainstream-tube |
no | yes | Best template for media and thumbnail proxying. |
okporn |
mainstream-tube |
no | no | Simple mainstream archive. |
okxxx |
mainstream-tube |
no | no | Mainstream search/archive pattern. |
omgxxx |
studio-network |
yes | no | Best template for sites/networks/stars filter catalogs. |
paradisehill |
mainstream-tube |
no | no | Simple page scraper. |
perfectgirls |
studio-network |
no | no | Studio archive. |
perverzija |
studio-network |
no | no | WordPress (Generatepress/quick-view) HTML scraper for tube.perverzija.com (mirrors top-tier studio releases: MommysGirl, PureTaboo, VXN, AdultTime, etc). Default feed / (page N: /page/N/), featured=featured option swaps in featured-scenes/ prefix before the page segment. Search is native WordPress /?s=query (page N: /page/N/?s=query), but tag:/stars:/studio:/genre: query prefixes and a background-learned title→slug map (populated from studio/stars/tag/genre links seen on every listing/detail page, normalized lowercase) route a bare keyword straight to the matching /{kind}/{slug}/page/N/ archive when it matches — e.g. milf resolves via the learned stars-milf class to /stars/milf/ rather than falling back to ?s=milf. Listing cards (class="video-item post...") carry everything needed (data-url = canonical WP detail page, data-embed-encoded <iframe src="…xtremestream.xyz/player/index.php?data=ID">, tag-*/stars-* CSS classes, class="time_dur" duration, studio link) so the default/tag/page feeds need no per-item enrichment; only the generic ?s= search path is card-light (no embed/tags inline) and fetches each detail page concurrently (futures::join_all) for the iframe src plus Studio:/Stars:/Tags:/Genres: <strong> blocks — resolved detail data is cached in the videos SQLite table (db::insert_video/get_video) keyed by the WP page URL to skip re-fetching on repeat searches. video.url is the WordPress detail page (data-url/card href) — confirmed NOT yt-dlp-resolvable (the player loads via the quick-view AJAX iframe, not static HTML) — so formats carries the real media: the embed index.php path is rewritten to xs1.php (returns an HLS .m3u8 master) and requires Referer: https://xtremestream.xyz/ on every request (segments and master alike) or the host CDN returns 403; regression note: an earlier revision set video.url to this same xs1.php media link, which then 403'd in check.py/any plain GET because the bare url field carries no header contract — fixed by separating video.url (page) from formats[0].url (media+Referer). Thumbnails (tube.perverzija.com/wp-content/uploads/...jpg) load directly, no proxy/referer. No /api/uploaders (studio/stars are folded into tags, no dedicated profile page schema confirmed). No proxy needed. |
pimpbunny |
onlyfans |
no | yes | Proxy-backed playback and thumbnail handling. |
pmvhaven |
pmv-compilation |
no | no | PMV grouping example. |
porn00 |
mainstream-tube |
no | no | Lightweight scraper. |
porn4fans |
onlyfans |
no | no | KVS (Kernel Video Sharing) scraper for porn4fans.com (OnlyFans creator clips); Cloudflare-fronted but serves direct requests (no JS challenge), so the shared requester works without Jina/FlareSolverr and detail-page enrichment is safe; all feeds are fetched as KVS ?mode=async&function=get_block HTML fragments (cleaner + properly paginated vs the JS-filled full pages), parsed with scraper over div.item cards (a.img-wrap.video href→id/title, img.thumb data-webp/src, div.duration, li.video-item.views span, li.video-item.model a for uploader, div.preview-video[data-src] preview clip); latest feed is /onlyfans-videos/ block custom_list_videos_latest_videos_list paginated by from=N (12/page — note: NOT /latest-updates/, which 404s); search is /search/{dashed-query}/ block custom_list_videos_videos_list_search_result with q={query}&category_ids=&from_videos=N (24/page); category /categories/{slug}/ and tag /tags/{slug}/ share block custom_list_videos_common_videos_list (from=N, 12/page); model /models/{slug}/ uses block custom_list_videos_models_videos_list; sort maps new→post_date, popular→video_viewed, rated→rating, longest→duration; cat:/category:, tag:, and model:/uploader:/pornstar:/star: query prefixes route to the matching archive, and a bare query that exactly matches a background-loaded category title goes to that archive instead of keyword search; background-loads the 55-entry category title→slug map from /categories/ (#list_categories_categories_list_items a.item) for the categories filter option (sanitized out of /api/status like stars/networks, but honored in /api/videos); video.url is the /video/{id}/{slug}/ page URL (NOT yt-dlp-resolvable — yt-dlp's generic KVS extractor fails on this site's flashvars), so per-card enrichment fetches the detail page and pulls the direct video_url/video_alt_url flashvars (480p/720p) into formats (bounded buffered(8) concurrency); KVS get_file MP4 URLs come as …/ID.mp4/?v-acctoken=… with a trailing slash before the query — the provider strips it to …/ID.mp4?v-acctoken=… so the path ends in .mp4 (health-check/yt-dlp media detection keys off the extension); formats carry a Referer header (works with or without it); thumbnails (/contents/videos_screenshots/…) need no proxy or referer; uploader name on a card is the OnlyFans handle while the /models/{slug}/ URL slug is the canonical model name (they legitimately differ — e.g. handle "Blasianflexcouple" at slug nina-lee), so uploader uses the display handle and uploaderUrl/uploaderId (porn4fans:<slug>) use the slug; no /api/uploaders profile, no proxy; note "teen" and similar are compliance-blocked keywords that the site itself returns empty for. |
porndish |
studio-network |
no | yes | Redirect proxy plus thumb proxy usage. |
pornhat |
mainstream-tube |
no | no | Basic tube provider. |
pornhd3x |
studio-network |
no | yes | Best template for complex catalogs and redirect proxy generation. |
pornhub |
mainstream-tube |
no | no | Rich metadata and format examples. |
pornhub-shorties |
tiktok |
no | no | Pornhub Shorties vertical short-form clips; parses JSON_SHORTIES JS variable embedded in HTML; fields: vkey, title, linkUrl, imageUrl, likeNumber, dislikeNumber, name/profileUrl (uploader), pillsData (tags), trackingTimeWatched.video_duration; pagination via ?page=N; search via ?search=query; sort via ?sort=trending|mostviewed|top_rated|hottest; phncdn thumbnails require Referer: https://www.pornhub.com/ (served via cdnReferrers in /api/status); yt-dlp resolves video.url natively (PornHub extractor); no proxy needed. |
pornmz |
mainstream-tube |
no | no | Mainstream archive. |
pornzog |
mainstream-tube |
no | no | Basic list/detail scraper. |
porntrex |
mainstream-tube |
no | no | KVS-style HTML archive with direct MP4 formats and tag-aware search shortcuts. |
redgifs |
amateur-homemade |
yes | no | Direct integration against the public RedGifs v2 API (same backend xxxtik proxies through, but consumed natively here). Auth: anonymous bearer token from GET api.redgifs.com/v2/auth/temporary, cached in an Arc<RwLock<Option<String>>> with double-checked locking, refreshed once on a 401 via a centralized authed_get helper. Default feed: GET /v2/feeds/trending/{popular,established}?page=&count= (honors count exactly). Free-text query and tag:/category:/cat: shortcuts hit `GET /v2/gifs/search?query= |
redtube |
mainstream-tube |
no | no | Mainstream archive. |
rule34gen |
ai |
no | no | AI group example. |
rule34video |
hentai-animation |
no | no | Hentai group example. |
sextb |
jav |
no | no | JAV family provider. |
shooshtime |
onlyfans |
no | yes | Redirect proxy plus dedicated media route. |
spankbang |
mainstream-tube |
no | yes | Best template for redirect proxy plus anti-bot fetches. |
thaiporntv |
mainstream-tube |
no | yes | Decodes data-enc attribute for proxied HLS playback. |
supjav |
jav |
no | yes | JAV/HLS provider; detail page URLs for video.url, proxied HLS format URLs via /proxy/supjav/.... |
sxyprn |
mainstream-tube |
no | yes | Redirect proxy helper usage. |
tnaflix |
mainstream-tube |
no | no | Mainstream tube provider. |
tokyomotion |
jav |
no | no | JAV/tube hybrid. |
viralxxxporn |
mainstream-tube |
no | no | Basic parser with format extraction. |
vjav |
jav |
yes | no | Best API-style template with uploaders and tag-id lookup maps. |
vrporn |
studio-network |
no | no | Multi-format direct playback. |
xfree |
tiktok |
no | no | Short-form grouping example. |
xxdbx |
onlyfans |
no | no | OnlyFans-like grouping example. |
xxthots |
onlyfans |
no | no | OnlyFans-like metadata example. |
yesporn |
mainstream-tube |
no | no | Preview format examples. |
youjizz |
mainstream-tube |
no | no | Mainstream tube provider. |
youporn |
mainstream-tube |
no | no | Pornhub-network HTML provider with watch-page playback URLs and tag/channel/pornstar shortcuts. |
tube8 |
mainstream-tube |
no | yes | Aylo/MindGeek platform scraper; redirect proxy fetches signed /media/hls/?s=TOKEN endpoint and returns highest-quality CDN HLS URL; supports tag/category/channel/pornstar shortcut queries. |
jable |
jav |
no | yes | HTML JAV archive scraper; extracts var hlsUrl from detail pages; m3u8 format requires Referer + browser User-Agent; proxy route handles HEAD (200 OK) and GET (redirect to watch page) since yt-dlp blocks jable.tv; tag/category/model shortcut queries. |
kwiky |
tiktok |
no | no | Short-form cam clip provider for kwiky.com (ICF/StreamMate platform). Two-step fetch: ID list then metadata batch. Auth: XSRF token extracted from meta.content = '<TOKEN>' injected by /api/state/v1/preload, cached in an Arc<RwLock<Option<String>>> with double-checked locking (same pattern as xxxtik bearer token); all API calls also require x-gateway: 76d59e04-97fa-4ced-aa99-b86ffaf756a2 (platform-identifying fixed UUID observed in browser JS, not stored in cookies or localStorage). Default feed: GET /api/v1/gateway/v1/quickies/recommended?source=<base64-hotlist> (cursor-paged, walks up to 5 cursors for higher page numbers). All tag/keyword queries go through keywordSearch?keyword=... (offset-paged: pageToken=(page-1)*perPage) — the recommended endpoint's &tag= param does not reliably filter, so even curated-tag requests use keywordSearch. Media: media.url = direct media.icfcdn.com/*.mp4 (publicly accessible, no Referer/auth), media.thumbUrl thumbnail (same CDN, direct), media.previewUrl preview clip; both kwiky page URLs (kwiky.com/quickies/{id}) and the media CDN URLs pass direct curl -I health checks but the page URL is NOT yt-dlp-resolvable (React SPA, generic extractor fails), so formats are populated with the direct MP4 URL and video.url is the page. Aspect ratio set from media.width/media.height; uploadedAt from RFC3339 created field; uploader name/URL/ID from creator.name and creator.id. 48 curated tags from /api/v1/gateway/v1/keywords/populartags?gender=f exposed via categories filter option. No proxy needed. |
fullporner |
mainstream-tube |
no | no | HTML scraper for fullporner.com; thumbnail IDs derived from /thumb/{id}.jpg URLs and used to build direct xiaoshenke.net/vid/{id}/720 media redirect URLs (Referer + User-Agent headers required); supports cat:/category:/pornstar:/star: shortcut queries; no proxy needed. |
thepornbunny |
mainstream-tube |
no | yes | KVS-style HTML scraper for thepornbunny.com; 24 items per site page; thumbnails at https://www.thepornbunny.com/images/thumb/{id}.webp from data-original attribute (no proxy needed); studio exposed as uploader; pornstar names in tags; /proxy/thepornbunny/{slug} fetches the video page, extracts generate_mp4(enc_data, key, rnd, video_id) args, decrypts enc_data via PBKDF2-HMAC-SHA512+AES-256-CBC to get an OK.ru session key, calls api.ok.ru/fb.do?method=video.get&session_key=KEY&vids=RND to get signed CDN URLs, and returns 302 to the best-quality okcdn.ru/vkuser.net MP4 URL (no special client headers needed); supports sort: new/popular/rated, 20 hardcoded categories via categories option, and tag:/category:/studio:/pornstar: query shortcuts. |
eporner |
mainstream-tube |
no | no | HTML scraper for eporner.com (5M+ videos); card selector div.mb[data-id] with inline duration/rating/views/uploader; thumbnails at static-eu-cdn.eporner.com (no proxy needed); pagination uses /{N}/ suffix (page 1 = no suffix, page 2 = /2/); search queries map to /tag/{slug}/ (eporner redirects all keyword searches to tag pages — 404 tag pages still return related content); supports sort: new/popular/rated/best; 65 hardcoded categories via cat:, tag:, pornstar:, uploader: query shortcuts; background-loads pornstar name→URL map from /pornstar-list/; yt-dlp resolves video.url natively (Eporner extractor); no proxy needed. |
xnxx |
mainstream-tube |
no | no | HTML scraper for xnxx.com (10M+ videos); unified card parser handles two formats: div.thumb-block[data-eid] (search) and div.thumb-block.video[data-video='{"id":...}'] (hits); eid extracted from /video-{eid}/{slug} URL path; thumbnails at thumb-cdn77.xnxx-cdn.com and thumbs-gcore.xnxx-cdn.com (no proxy, no Referer needed); 0-indexed pagination (page 1 = /hits, page N = /hits/{N-1}); default feed is /hits (most-viewed — xnxx has no chronological listing); search via /search/{slug} (works for keywords and tags); supports tag:, cat:, category: query shortcuts; yt-dlp resolves video.url natively (XNXX extractor, returns 4-7 HLS formats); no proxy needed. |
xgroovy |
mainstream-tube |
no | no | KVS (Kernel Video Sharing)-style HTML scraper for xgroovy.com; card selector div.item[data-video-id] with data-views/data-rating as clean numeric attributes directly on the card (no text-parsing needed, unlike xhamster); title/url from a.popito[href] > strong.title; thumbnails at i.xgroovy.com (no proxy, no Referer needed) from `img.thumb[data-jpg |
xhamster |
mainstream-tube |
no | no | HTML scraper for xhamster.com; card selector div[data-video-type="video"] with data-video-id; thumbnails via img[data-role="thumb-preview-img"] at ic-vt-nss.xhcdn.com (no proxy, no Referer needed); pagination via ?page=N query param (browse feeds use infinite-scroll so only search reliably returns different content per page); feeds: /newest (default), /most-viewed, /best; categories via /categories/{slug}; channels via /channels/{slug}; 43 hardcoded categories as categories option; uploader type inferred from URL path (/channels/ → channel, /creators/ → creator, /pornstars/ → pornstar); supports cat:/category: and channel: query shortcuts, plus static category name matching; preview mp4 clips from data-previewvideo attribute; yt-dlp resolves video.url natively (xHamster extractor, 28 formats); no proxy needed. |
camsoda |
live-cams |
no | no | Live-cam provider for camsoda.com (chaturbate-style — live performers streaming now, video.url = the room page, is_live=true, no formats). camsoda.com is hard Cloudflare-protected: direct requests and yt-dlp both get HTTP 403, and FlareSolverr was unreliable during development, so the live-browse API is reached through the shared requester's Jina mirror fallback (r.jina.ai/http://..., X-Return-Format: html); Jina rate-limits per IP, so the provider caches each fetched feed URL for 60s (and serves stale items on a 429 rather than emptying the feed), and a single-provider build (HOT_TUB_PROVIDER=camsoda) validates most cleanly (one fetch at a time). Endpoint (found in the non-CF static main.js bundle): GET https://www.camsoda.com/api/v1/browse/react{route}?p=N returning a body with a top-level userList array (Jina wraps it in <pre>, so the provider slices out the {...} and parses it with serde_json::Value, like the chaturbate provider). Per-cam fields: username→id + room URL (/{username}), subjectText→title (html-decoded, falls back to displayName), displayName→uploader, connectionCount→views (string or number tolerated), thumbUrl→thumb (direct media.livemediahost.com CDN, no proxy/referer), status (skip offline), vr/private surfaced as tags. Category option category uses verified browse/react routes — all(featured)/girls/trans/couples/voyeur-cams/new (/male is NOT a path route, camsoda gates male via gender-hide); cat:/category: prefixes and a bare keyword matching a category id route there too. Search: GET browse/react/search/{dashed-query}?sortByConnection=1 (single connection-sorted result set, no real paging). Playback: video.url is the live room page; the room and the token-gated edge HLS (*.livemediahost.com) are both Cloudflare-protected, so HLS can't be resolved server-side and no formats are populated — yt-dlp has a Camsoda live extractor that resolves the room on a non-CF-blocked client, and check.py reports the sandbox's CF 403s as expected warnings (www.camsoda.com is in its CF allowlist), not errors. The earlier recorded-/media JSON scrape was replaced because clips were token-gated/non-playable; live cams are the site's actual product. No proxy needed. |
xvideos |
mainstream-tube |
no | no | HTML scraper for xvideos.com; handles two card formats: homepage (div.thumb-block[data-id][data-eid]) uses p.title a[title] + data-pvv on img, best-of-month page uses div.thumb-block.video[data-video=JSON] with div.title a text + previewVideo JSON key; thumbnails at thumb-cdn77.xvideos-cdn.com / thumbs-gcore.xvideos-cdn.com (no proxy needed); latest: / (page 1) / /new/{N-1} (page N≥2); best-of-month: /best/{YYYY-MM} (previous calendar month), page N: /best/{YYYY-MM}/{N-1}; search: /?k={query} / /?k={query}&p={N-1} (0-indexed); tag shortcuts: /tags/{slug}/{N-1}; category shortcuts: /c/{Name}-{ID}/{N-1} (38 hardcoded categories); cat:, tag:, uploader: query prefix routing; yt-dlp resolves video.url natively (XVideos extractor → HLS formats); CDN preview mp4 in preview field; no proxy needed. |
wowxxx |
studio-network |
no | no | HTML scraper for wow.xxx premium aggregator; default feed /latest-updates/, page 2 /{N}/ suffix (for example /latest-updates/2/), search /search/{query}/relevance/ with the same page suffix; supports site:/studio:/network:/model:/pornstar:/tag:/cat: query shortcuts to direct archive routes; list cards expose preview clips (cast.wow.xxx/preview/*.mp4), thumbnails (img.wow.xxx/.../medium@2x/1.jpg), duration, rating, views, site (as uploader), and model tags; video.url is the detail page URL and yt-dlp resolves HTML5 MP4 formats dynamically; no proxy needed. |
xlecx |
hentai-animation |
no | no | DLE (DataLife Engine)-style HTML scraper for xlecx.one, following the thaiporntv template. Latest feed /f/cat={id}/sort={mode}/order=desc/ (page N≥2 appends page/{N}/); sort options new/popular/commented/rated map to DLE's date/news_read/comm_num/rating sort params; category option is the 2 hardcoded top-level archives (videos, hentai-video). Search via /index.php?do=search&subaction=search&story={query} (page N adds search_start={N}). Tag shortcut (#slug query) routes to /tags/{slug}/ (paginated via /tags/{slug}/page/{N}/); the ~1,044-entry tag catalog is background-loaded once at startup from /tags/ (.tags-list1 a[href*='/tags/'], absolute-URL anchors) into an Arc<RwLock<Vec<FilterOption>>> and exposed as the filter/"Tags" ChannelOption — note this option (and any categories) is deliberately stripped from the live /api/status response by should_hide_status_option/decorate_channel in providers/mod.rs (any id=="filter" option titled "Tags" is hidden site-wide), so its absence there is expected, not a bug; it is still honored by /api/videos. Cards parsed from h3.thumb__title + img inside standard DLE thumb blocks; id extracted from the /{id}-{slug}.html URL suffix. Thumbnails are direct xlecx.one/uploads/posts/... webp (no proxy/Referer needed). video.url is the detail page URL, which yt-dlp resolves natively via the generic HTML5 embed extractor; no formats/proxy needed. No /api/uploaders (no stable uploader identity on the site). |
xxxtik |
tiktok |
yes | no | JSON-API short-form aggregator for xxxtik.com — every post is a moderated repost of a RedGifs clip, so the real media backend is the public RedGifs v2 API, not xxxtik itself (new pattern; no other provider currently resolves through a third-party media API). Listing API (xxxtik-api-iw98m.ondigitalocean.app, found by grepping the Angular main-es2015.js bundle): GET /post/new, /post/top/{week,month,year,all}, /post/tag/{name}, /post/creator/{username} — all cursor-paginated (?cursor={lastItemId}&limit=N; the cursor is the numeric id of the last item from the previous batch, not an offset/count — reaching page N walks N sequential requests, mirroring fikfap's fetch_cursor_page). GET /search?query=Q returns tag/profile autocomplete suggestions only (no posts), so free-text search is routed through it to resolve a Tag/Creator target before a second listing call; tag:/category:/cat: and user:/uploader:/creator: query prefixes skip that lookup. Each post's source field is a redgifs.com/watch/{id} URL; the provider fetches a short-lived anonymous bearer token from POST api.redgifs.com/v2/auth/temporary (cached, refreshed once on a 401) and resolves GET api.redgifs.com/v2/gifs/{id} (bounded to 8-way concurrency via buffer_unordered) for the real media.redgifs.com/*.mp4 + poster, both fetchable with zero auth/Referer. video.url is the xxxtik page (https://xxxtik.com/feed/{uuid}, not yt-dlp-resolvable — Angular SPA, generic extractor fails), with formats populated from the resolved redgifs mp4; tags merge xxxtik's own tags with RedGifs' tags. 20 curated tags exposed via categories (xxxtik has ~62k tags total, too many to background-load). /api/uploaders works via GET /user/by-username/{name} + /post/creator/{name}, but xxxtik's "creator" accounts are inconsistent: some (e.g. dlhoodninja, besttits) return real posts matching their profile _count.posts; others with a nonzero _count.posts (e.g. bigboobsgw, count 472) return an empty /post/creator/ list — likely synthetic curation accounts (name@default emails) rather than real uploaders. The provider degrades gracefully (returns the profile with videos: [], no error) rather than guessing which accounts are "real". No proxy needed — all media/thumb URLs are publicly fetchable with no Referer or auth. |
Proxy Routes
Redirect proxies
These resolve a provider-specific input into a 302 Location.
/proxy/doodstream/{endpoint}*/proxy/sxyprn/{endpoint}*/proxy/javtiful/{endpoint}*/proxy/spankbang/{endpoint}*/proxy/porndish/{endpoint}*/proxy/hqporner/{endpoint}*/proxy/heavyfetish/{endpoint}*/proxy/vjav/{endpoint}*/proxy/pornhd3x/{endpoint}*/proxy/shooshtime/{endpoint}*/proxy/pimpbunny/{endpoint}*/proxy/allpornstream/{endpoint}*/proxy/tube8/{endpoint}*/proxy/supjav/{endpoint}*/proxy/jable/{slug}*/proxy/thepornbunny/{slug}*/proxy/animeidhentai/{embedId}.mp4(HEAD→200, GET→302 to the signedr2.1hanime.comCDN URL)/proxy/hentaitv/{embedId}.mp4(HEAD→200, GET→302 to the signedr2.1hanime.comCDN URL; same nhplayer challenge asanimeidhentai)
Media/image proxies
These return binary media or images, sometimes rewriting manifests or forwarding cookies/referers.
/proxy/shooshtime-media/{endpoint}*/proxy/noodlemagazine/{endpoint}*/proxy/noodlemagazine-thumb/{endpoint}*/proxy/hanime-cdn/{endpoint}*/proxy/fikfap-thumb/{endpoint}*/proxy/hqporner-thumb/{endpoint}*/proxy/porndish-thumb/{endpoint}*/proxy/hotbunny-thumb/{endpoint}*/proxy/pornhub-thumb/{endpoint}*
Best Copy Sources By Problem
- Need uploader support: copy
hsex,omgxxx, orvjav. - Need proxied media: copy
noodlemagazine. - Need proxied redirect-only playback: copy
spankbangorpornhd3x. - Need big background-loaded filter catalogs: copy
pornhd3xoromgxxx. - Need tag title to site-ID lookup maps: copy
vjavorhsex.