ripnsfw.com serves its entire catalogue as a published-Google-Sheet CSV with no native pagination/search API, so the provider fetches and parses that CSV once (cached 180s) and does feed/search/pagination/sort in memory. Each row's Doodstream/Lulustream embed links resolve to formats[] via the existing (previously unused) doodstream/lulustream redirect proxies. Also fixes check.py's follow_proxy_redirect, which used HEAD even though these redirect-proxy routes only accept GET/POST, so it never actually resolved the redirect; extends the CF-protected host list (suffix matching + ripnsfw.com's client-only-SPA 404 page, dood.video, tnmr.org) so known sandbox/CDN-IP-reputation failures are reported as warnings instead of errors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QTqf6orbHZ9rFFpVpcgzcR
58 KiB
58 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>). |
fapello |
onlyfans |
no | no | HTML + embedded-JSON provider for fapello.com (OnlyFans-style photo/video leak aggregator; the site is fundamentally a photo model archive — /, /new/, /hot/, /trending/, /tags/, /search_v2/ — and the much smaller /videos/ section is what this channel surfaces). Cloudflare-gated; the shared requester's Jina mirror fallback resolves every listing and detail page (r.jina.ai/http://fapello.com/..., X-Return-Format: html). Latest feed GET /videos/ (page 1, ~6-8 cards), GET /ajax/videos/page-{N}/ (page 2+, ~4 cards) — cards expose the numeric id, the fapello.com/content/.../{model}_{NNNN}_300px.jpg thumbnail, and the /{model_slug}/ uploader link. Each detail page GET /video/new/{id}/ embeds a complete var BOOT = { items: [...], next_page, page_size } JSON block (preserved by the Jina mirror) — every BOOT item carries the resolved video_url (https://cdn.fapello.com/content/.../{N}/{model}_{NNNN}.mp4), poster_url (the matching .jpg, no _300px suffix — provider swaps that in for the full-size thumb), duration ("HH:MM:SS" → seconds), width/height/aspect/orientation, count_likes (→ views), name/model_url (uploader), and tags[]. Per-card BOOT enrichment is bounded via buffer_unordered(4) with a 20s timeout — listing-only metadata (id, thumb, uploader) is preserved on timeout so a Jina-throttled page still produces usable cards. The Jina mirror does NOT trigger JS, so the /popular_videos/{twelve_hours,month,all_time}/ routes and /search_v2/?type=... are empty (search returns photo models, not videos; the site has no native "videos matching keyword" search) — those filters are deliberately not exposed; only sort:new is offered. video.url is the detail page (not yt-dlp-resolvable — no extractor exists), so formats[0] carries the direct cdn.fapello.com mp4 with Referer: https://fapello.com/ (the CDN serves direct without it, but the header matches the on-site context). Media and thumbnails (fapello.com/content/.../*.jpg, cdn.fapello.com/content/.../*.mp4) are range-served, no auth/cookies/JA3 emulation required, so no proxy route is needed. check.py's _CF_PROTECTED_HOSTS allowlist includes fapello.com and cdn.fapello.com so its plain-requests 403s for video.url and the format URL downgrade to warnings instead of errors. No /api/uploaders (fapello has stable model slugs but no dedicated "videos by this uploader" feed — only the mixed photo+video model page). |
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. |
hdporn92 |
mainstream-tube |
no | no | WordPress retrotube-theme aggregator for hdporn92.com (network studio releases — MyPervyFamily, MYLF, StepSiblings, …). Latest feed / (page 1) and /page/N/ (page N≥2); search /?s={query} (page 1) and /page/N/?s={query} (page N≥2) — the path with the s parameter must come after the page/N segment, not before. Pagination is by article.loop-video cards; the post id comes from the post-{N} CSS class. Two-step enrichment (page URL + Referer-locked m3u8 in formats): detail page → <IFRAME SRC="https://morencius.com/embed/{id}"> (case-insensitive; the page emits an uppercase <IFRAME SRC=...> tag) → morencius embed → embedded `eval(function(p,a,c,k,e,d){…}(p,a,c,k.split(' |
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. |
hentaimama |
hentai-animation |
no | no | WordPress/DooPlay-theme provider for hentaimama.io (series /tvshows/{slug}/ each holding numbered /episodes/{slug}-episode-N/ posts). Latest feed is the episodes post-type archive: /episodes/ (page N: /episodes/page/N/), 24 cards/page, each already carrying the numeric post id (id="post-{N}"/rel="{N}"), title (div.season_m span.b+span.c, joined with a space — the two spans are adjacent text nodes with no whitespace between them), thumb, and rating, so the latest feed needs only one more request per item (see media resolution below), no page-2 detail fetch. Search (/?s=query, page N: /page/N/?s=query), genre archives (/genre/{slug}/, 118+ curated genres background-loaded from a.genreitem on /genres-filter/ into the categories filter option, sanitized out of /api/status like other providers' catalogs but honored in /api/videos; bare keywords matching a loaded genre title route here, otherwise genre:/cat:/category: prefixes), and studio archives (/studio/{slug}/ via studio:/uploader: prefix, naive-slugified — no background catalog) all only expose series cards (article.series-card / a.sc-poster), not individual episodes, so each match is resolved to its single most-recent episode (fetch the series page's a.dt-se-item list, take the last href, then resolve that episode page) — richer results (tags, rating, exact title, uploadedAt) than the latest feed, at the cost of two extra requests instead of one. Media resolution (same for every path): POST /wp-admin/admin-ajax.php with action=get_player_contents&a={post_id}&i=1 returns a JSON array of iframe-HTML strings; the populated slot's src is hentaimama.io/?dt_embed=rtmp&p={base64}&ep={id} where the base64 p param decodes directly to the storage path (e.g. P/{file}.mp4) on a second, unrelated mirror host gdvid.info — so the direct, non-expiring, Referer-free https://gdvid.info/{path} format URL is built locally from the AJAX response with no extra fetch; a dt_embed=cu fallback mirror (na-01.javprovider.com, signed/expiring ?st=&e= token) exists but is only used as a last resort (fetch the iframe src page itself and pull the jwplayer file: value) if the primary parse fails, since it needs an extra request. video.url is the episode page (not yt-dlp-resolvable — the player loads via the AJAX handshake, not static HTML), so formats[0] carries the gdvid.info mp4. Thumbnails (wp-content/uploads/...webp) load directly, no proxy/Referer. No /api/uploaders (studio pages exist but have no per-provider profile schema confirmed; no background studio catalog for the same reason). No proxy needed. |
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). |
hornyleak |
amateur-homemade |
no | no | HTML scraper for hornyleak.tv (KVS / Kernel Video Sharing — leaked-amateur and OnlyFans-creator clips). Listing cards div.thumb.thumb_rel.item (24/page) with a.img[href*="/video/"] (href→/video/{id}/{slug}/, title attr→title), img.thumb (data-webp preferred, falls back to data-src/src), div.duration (text → seconds), div.thumb-item > span views text, a.avatar uploader (often empty — - placeholder on the listing), div.rating percent; /videos/{N}/ is the path-based pagination for Latest and the per-archive pages. The detail page is yt-dlp-resolvable (page URL → generic extractor → https://www.hornyleak.tv/video/{id}/{slug}/ → 1 format), so video.url is set to that detail page (NOT a proxy URL) and per-card enrichment is optional — but most clients want a stable HLS link, so the provider enriches each card to populate formats[]. Two-step media resolution chain: (1) GET /embed/{id}/ (Referer: detail page) → regex on hdplayer\.gives/embed/([A-Za-z0-9]+) to find the per-video hash; (2) GET https://hdplayer.gives/embed/{hash}/ (Referer: hornyleak.tv embed URL) → regex on file:"(https://hdplayer\.gives/list/enc[^"]+)" to extract the signed list/enc token URL. The enc URL is a real m3u8 with three variants (FULLHD 1920x1080 / HD 1280x720 / SD 842x480) pointing to https://hdplayer.gives/m3u/... sub-playlists and https://swa3.top/upload/videos/... segments. formats[0] is the m3u8 with Referer: https://hdplayer.gives/ and the hornyleak.tv user-agent. video.url is left as the page URL (yt-dlp's generic extractor resolves it to 1 format on a non-JA3-blocked client; the HLS in formats[] is the primary path for clients that honor http_headers). sort option: new/popular/rated/viewed/longest (path-based: /latest-updates/, /most-popular/, /top-rated/, /most-viewed/, /longest/). cat:/category:/tag:/model:/uploader:/pornstar:/star: query prefixes route to the matching archive (/categories/{slug}/, /tags/{slug}/, /models/{slug}/). Search is path-1 GET /search/?q={query} (returns search results HTML directly) and path-≥2 GET /search/?q={query}&mode=async&function=get_block&block_id=custom_list_videos_videos_list_search_result&from_videos={N}&from_albums={N} (XHR pagination — the search results page itself is paged via the custom_list_videos_videos_list_search_result block). Background-loaded category filter (≈ 100 entries scraped from /categories/) via the shared Arc<RwLock<Vec<FilterOption>>> pattern, with title→slug map for bare-query short-circuit to a category archive when the keyword exactly matches a category title. Tags from detail .tags-row a, .categories-row a; thumbnails https://www.hornyleak.tv/contents/videos_screenshots/{N}00/{id}/preview.jpg (direct, no proxy/referer); no proxy route needed. uploaderId is namespaced as hornyleak:<model-slug>. Known limitation: the hdplayer.gives/list/enc... token is request-bound to the player-page TLS context; yt-dlp's generic extractor gets HTTP 404 when probing the URL directly with curl_cffi, so the validator's _CF_PROTECTED_HOSTS allowlist includes hdplayer.gives to downgrade the 404 to a warning (the HLS body itself returns 200 with valid m3u8 to plain curl, and iOS AVFoundation + Hot Tub clients play it directly through the formats[] entry). No /api/uploaders profile (KVS uploader pages exist but have no public stats). |
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. |
notfans |
onlyfans |
no | no | HTML scraper for notfans.com (OnlyFans / Fansly / Patreon / Manyvids leak aggregator); site is behind Cloudflare but does NOT issue a JS challenge to direct requests (the shared Requester with Chrome 120 emulation gets a 200), so detail-page enrichment is safe and there's no FLARE_URL gate. Card parser splits the listing on the literal <div class="item "> delimiter (the two trailing spaces match the card class exactly and skip the sponsored class="item avd" variant — homoxxx uses the same convention); per card: <a href="…/videos/{id}/{slug}/" title="…"> for the id/url/title, plus <img class="thumb " src="…/contents/videos_screenshots/{id3}/{id}/320x180/N.jpg"> for the listing thumb. Feeds: latest /latest-updates/{N}/ (23/page, last page 30990), most-viewed /most-popular/{N}/ (24/page), top-rated /top-rated/{N}/ (24/page), and period tops /day/{N}/, /week/{N}/, /month/{N}/, /year/{N}/ (all 12-24/page); search /search/{query}/{N}/; tag /tags/{tag}/{N}/ reachable via the tag:/category:/tags: query prefix. Per-card enrichment (page 1 only, buffer_unordered(4), 8s timeout) fetches the detail page …/videos/{id}/{slug}/ and pulls: Duration: <em>HH:MM:SS</em> → parse_time_to_seconds, Views: <em>N</em> → u32, Tags: <a href="/tags/…">name</a>…</div> block (regex over /tags/…/>(name)</a>), `Submitted: N (minute |
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. |
ripnsfw |
onlyfans |
no | yes | Leaked-creator aggregator for ripnsfw.com — the entire catalogue (~2.5k rows) is a single client-side-rendered page whose data source is a published Google Sheet exported as CSV (GET /data.csv, no auth/CF gate); the provider fetches and parses that CSV directly instead of scraping any HTML, replicating the site's own JS parseCSV/csvSplit column layout (THUMB,NEW,NOME,DOODSTREAM,LULUSTREAM,<link3>,DOOD,<guests>,SITE(bunkr links),TITLE,ID,#(tags),POST,,DATE,SIZE). Feed/search/pagination/sort are all done in-memory over the fetched rows (no native site pagination exists — perPage-sized pages are sliced locally), with a 180s in-process cache to avoid re-fetching the CSV on every request. tag:/category:/cat: and model:/uploader: query prefixes filter by the parsed tag list / model name; bare keywords substring-match model name, guests, and tags. video.url is the site's client-rendered https://ripnsfw.com/model/{slug}/{id} route — the host has no server-side SPA fallback, so this 404s to any plain HTTP client (its custom 404 page stashes the path and JS-redirects to /, which restores the route — works in a real browser/webview only); check.py's _CF_PROTECTED_HOSTS allowlist includes ripnsfw.com for this reason. Media is never hosted on ripnsfw.com itself: each row carries a Doodstream and/or Lulustream embed link, resolved into formats[] (Lulustream first, matching the site's own default-player order) via the existing, previously-unused src/proxies/doodstream.rs / src/proxies/lulustream.rs redirect proxies (build_proxy_url(&options, "doodstream"/"lulustream", &strip_url_scheme(link))) — no new proxy code was written. Both proxies resolve correctly to real signed CDN URLs (verified against live data), but neither CDN's final edge is reachable from this repo's dev sandbox: Lulustream's *.tnmr.org edge 403s datacenter/proxy IPs regardless of UA or TLS impersonation, and Doodstream's final *.dood.video edge resolves to a loopback/refused address from non-residential egress — both are IP-reputation-style CDN blocks, not code defects (same class of sandbox limitation already documented for camsoda/hentaihaven/animeidhentai), so check.py allowlists both by suffix (_CF_PROTECTED_SUFFIXES). No thumbnail proxy needed (cdn.ripnsfw.com/thumbs/... is directly hotlinkable, no CF/referer gate). No /api/uploaders (model pages exist but have no dedicated profile/stats schema confirmed). |
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/lulustream/{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.