Files
hottub/docs/provider-catalog.md
2026-06-23 10:47:30 +00:00

30 KiB
Raw Blame History

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.phpplayer-core-v2.phpget-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.phpplayer-core-v2.phpget-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.
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.
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 Multi-format/HLS examples.
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.
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.
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.
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.
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 signed r2.1hanime.com CDN URL)
  • /proxy/hentaitv/{embedId}.mp4 (HEAD→200, GET→302 to the signed r2.1hanime.com CDN URL; same nhplayer challenge as animeidhentai)

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/pornhub-thumb/{endpoint}*

Best Copy Sources By Problem

  • Need uploader support: copy hsex, omgxxx, or vjav.
  • Need proxied media: copy noodlemagazine.
  • Need proxied redirect-only playback: copy spankbang or pornhd3x.
  • Need big background-loaded filter catalogs: copy pornhd3x or omgxxx.
  • Need tag title to site-ID lookup maps: copy vjav or hsex.