# 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=-` 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:`). | | `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=` (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:` 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 → `