diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..09e279e --- /dev/null +++ b/SKILL.md @@ -0,0 +1,323 @@ +--- +name: hottub +description: Work on the Hottub Rust server. Use this skill when you need the real build/run commands, compile-time single-provider builds, runtime env vars, API and proxy endpoint trigger examples, or yt-dlp verification steps for returned media URLs. +--- + +# Hottub + +Hottub is a Rust `ntex` server. The main entrypoints are: + +- `src/main.rs`: server startup, env loading, root redirect, `/api`, `/proxy`, static files +- `src/api.rs`: `/api/status`, `/api/videos`, `/api/test`, `/api/proxies` +- `src/proxy.rs`: `/proxy/...` redirect and media/image proxy routes +- `src/providers/mod.rs`: provider registry, compile-time provider selection, channel metadata +- `src/util/requester.rs`: outbound HTTP, Burp proxy support, FlareSolverr fallback + +## Build and run + +Default local run: + +```bash +cargo run +``` + +Run with compiled-in debug logs: + +```bash +cargo run --features debug +``` + +Compile a single-provider binary: + +```bash +HOT_TUB_PROVIDER=hsex cargo build +``` + +Single-provider binary with debug logs: + +```bash +HOT_TUB_PROVIDER=hsex cargo run --features debug +``` + +Notes: + +- `HOT_TUB_PROVIDER` is the preferred compile-time selector. +- `HOTTUB_PROVIDER` is also supported as a fallback alias. +- Single-provider builds register only that provider at compile time, so other providers are not constructed and their init paths do not run. +- In a single-provider build, `/api/videos` requests with `"channel": "all"` are remapped to the compiled provider. +- The server binds to `0.0.0.0:18080`. + +Useful checks: + +```bash +cargo check -q +HOT_TUB_PROVIDER=hsex cargo check -q +HOT_TUB_PROVIDER=hsex cargo check -q --features debug +``` + +## Environment + +Runtime env vars: + +- `DATABASE_URL` required. SQLite path, for example `hottub.db`. +- `RUST_LOG` optional. Defaults to `warn` if unset. +- `PROXY` optional. Any value other than `"0"` enables proxy mode in the shared requester. +- `BURP_URL` optional. Outbound HTTP proxy used when `PROXY` is enabled. +- `FLARE_URL` optional but strongly recommended for provider work. Used for FlareSolverr fallback and some providers that call it directly. +- `DOMAIN` optional. Used for the `/` redirect target. +- `DISCORD_WEBHOOK` optional. Enables `/api/test` and provider error reporting to Discord. + +Build-time env vars: + +- `HOT_TUB_PROVIDER` optional. Compile only one provider into the binary. +- `HOTTUB_PROVIDER` optional fallback alias for the same purpose. + +Practical `.env` baseline: + +```dotenv +DATABASE_URL=hottub.db +RUST_LOG=info +PROXY=0 +BURP_URL=http://127.0.0.1:8081 +FLARE_URL=http://127.0.0.1:8191/v1 +DOMAIN=127.0.0.1:18080 +DISCORD_WEBHOOK= +``` + +## Endpoint surface + +Root: + +- `GET /` + - Returns `302 Found` + - Redirects to `hottub://source?url=` + +Status API: + +- `GET /api/status` +- `POST /api/status` + - Returns the server status and channel list + - The `User-Agent` matters because channel visibility can depend on parsed client version + +Videos API: + +- `POST /api/videos` + - Main provider execution endpoint + - Body is JSON matching `VideosRequest` in `src/videos.rs` + +Diagnostics: + +- `GET /api/test` + - Sends a Discord test error if `DISCORD_WEBHOOK` is configured +- `GET /api/proxies` + - Returns the current outbound proxy snapshot + +Proxy endpoints: + +- Redirect proxies: + - `GET|POST /proxy/sxyprn/{endpoint}*` + - `GET|POST /proxy/javtiful/{endpoint}*` + - `GET|POST /proxy/spankbang/{endpoint}*` + - `GET|POST /proxy/porndish/{endpoint}*` + - `GET|POST /proxy/pimpbunny/{endpoint}*` +- Media/image proxies: + - `GET|POST /proxy/noodlemagazine/{endpoint}*` + - `GET|POST /proxy/noodlemagazine-thumb/{endpoint}*` + - `GET|POST /proxy/hanime-cdn/{endpoint}*` + - `GET|POST /proxy/hqporner-thumb/{endpoint}*` + - `GET|POST /proxy/porndish-thumb/{endpoint}*` + - `GET|POST /proxy/pimpbunny-thumb/{endpoint}*` + +Everything else under `/` is served from `static/`. + +## How to trigger endpoints + +Verify the root redirect: + +```bash +curl -i http://127.0.0.1:18080/ +``` + +Fetch status with a Hot Tub-like user agent: + +```bash +curl -s \ + -H 'User-Agent: Hot%20Tub/22c CFNetwork/1494.0.7 Darwin/23.4.0' \ + http://127.0.0.1:18080/api/status | jq +``` + +Equivalent `POST /api/status`: + +```bash +curl -s -X POST http://127.0.0.1:18080/api/status | jq +``` + +Minimal videos request: + +```bash +curl -s http://127.0.0.1:18080/api/videos \ + -H 'Content-Type: application/json' \ + -H 'User-Agent: Hot%20Tub/22c CFNetwork/1494.0.7 Darwin/23.4.0' \ + -d '{"channel":"hsex","sort":"date","page":1,"perPage":10}' | jq +``` + +Use `"all"` against a normal multi-provider build: + +```bash +curl -s http://127.0.0.1:18080/api/videos \ + -H 'Content-Type: application/json' \ + -d '{"channel":"all","sort":"date","page":1,"perPage":10}' | jq +``` + +Use `"all"` against a single-provider build: + +```bash +HOT_TUB_PROVIDER=hsex cargo run --features debug +curl -s http://127.0.0.1:18080/api/videos \ + -H 'Content-Type: application/json' \ + -d '{"channel":"all","sort":"date","page":1,"perPage":10}' | jq +``` + +Literal query behavior: + +- Quoted queries are treated as literal substring filters after provider fetch. +- Leading `#` is stripped before matching. + +Example: + +```bash +curl -s http://127.0.0.1:18080/api/videos \ + -H 'Content-Type: application/json' \ + -d '{"channel":"hsex","query":"\"teacher\"","page":1,"perPage":10}' | jq +``` + +Trigger the Discord test route: + +```bash +curl -i http://127.0.0.1:18080/api/test +``` + +Inspect proxy state: + +```bash +curl -s http://127.0.0.1:18080/api/proxies | jq +``` + +Trigger a redirect proxy and inspect the `Location` header: + +```bash +curl -I 'http://127.0.0.1:18080/proxy/spankbang/some/provider/path' +``` + +Trigger a media proxy directly: + +```bash +curl -I 'http://127.0.0.1:18080/proxy/noodlemagazine/some/media/path' +``` + +## Videos request fields + +Commonly useful request keys: + +- `channel` +- `sort` +- `query` +- `page` +- `perPage` +- `featured` +- `category` +- `sites` +- `all_provider_sites` +- `filter` +- `language` +- `networks` +- `stars` +- `categories` +- `duration` +- `sexuality` + +Most provider debugging only needs: + +```json +{ + "channel": "hsex", + "sort": "date", + "query": null, + "page": 1, + "perPage": 10 +} +``` + +## Recommended provider-debug workflow + +1. Build only the provider you care about. +2. Run with `--features debug`. +3. Hit `/api/status` to confirm only the expected channel is present. +4. Hit `/api/videos` with either the provider id or `"all"`. +5. Inspect `.items[0].url`, `.items[0].formats`, `.items[0].thumb`, and any local `/proxy/...` URLs. +6. Verify the media URL with `yt-dlp`. + +Example: + +```bash +HOT_TUB_PROVIDER=hsex cargo run --features debug +curl -s http://127.0.0.1:18080/api/status | jq '.channels[].id' +curl -s http://127.0.0.1:18080/api/videos \ + -H 'Content-Type: application/json' \ + -d '{"channel":"all","page":1,"perPage":1}' | tee /tmp/hottub-video.json | jq +``` + +## yt-dlp verification + +Use `yt-dlp` to prove that a returned video URL or format is actually consumable. + +Check the primary item URL: + +```bash +URL="$(jq -r '.items[0].url' /tmp/hottub-video.json)" +yt-dlp -v --simulate "$URL" +``` + +Prefer the first explicit format when present: + +```bash +FORMAT_URL="$(jq -r '.items[0].formats[0].url' /tmp/hottub-video.json)" +yt-dlp -v -F "$FORMAT_URL" +yt-dlp -v --simulate "$FORMAT_URL" +``` + +If the format contains required HTTP headers, pass them through: + +```bash +yt-dlp -v --simulate \ + --add-header 'Referer: https://example.com/' \ + --add-header 'User-Agent: Mozilla/5.0 ...' \ + "$FORMAT_URL" +``` + +If you want to build the command from JSON: + +```bash +FORMAT_URL="$(jq -r '.items[0].formats[0].url' /tmp/hottub-video.json)" +mapfile -t HDRS < <( + jq -r '.items[0].formats[0].http_headers // {} | to_entries[] | "--add-header=\(.key): \(.value)"' \ + /tmp/hottub-video.json +) +yt-dlp -v --simulate "${HDRS[@]}" "$FORMAT_URL" +``` + +For local proxy URLs returned by Hottub, verify the server endpoint directly: + +```bash +LOCAL_URL="$(jq -r '.items[0].formats[0].url // .items[0].url' /tmp/hottub-video.json)" +yt-dlp -v --simulate "$LOCAL_URL" +``` + +## Interaction rules + +- Prefer compile-time single-provider builds for provider work. +- Prefer `/api/status` before `/api/videos` so you know what channels the current binary exposes. +- When reproducing client-specific issues, send a realistic `User-Agent`. +- When debugging fetch failures, enable `debug` and set `FLARE_URL`. +- When debugging outbound request behavior, set `PROXY=1` and `BURP_URL=...`. +- Use `/api/test` only when you intentionally want a Discord notification.