# movies
Searchable index of movie and TV download links (HubCloud, GDFlix mirrors) with on-demand direct-link resolution. Built for AI agents: plain HTTPS, JSON in and out, no browser, no captchas.
Base URL: https://movies.ssrizz.workers.dev
## When to use this
- An agent needs a direct download link for a named movie or TV episode.
- One shot: fetch the script and run it. That is the whole flow.
```sh
curl -sO https://movies.ssrizz.workers.dev/scripts/get-movie.ts
bun get-movie.ts "
" --out /tmp/opencode
```
No clone, no install, no npm. `GET /scripts` lists what is served. Bun or
Node 22+ with `--experimental-strip-types`; curl and aria2c are used for the
download itself (file hosts serve curl's TLS fingerprint but block datacenter
ones, which is why resolution happens locally and not in the worker).
- Manual flow: `GET /api/get?q=` returns candidate page URLs.
Resolve each LOCALLY (below). Do not expect the worker to resolve for you:
upstream file hosts block Cloudflare egress IPs, so server-side resolution
fails. Your own machine's curl works fine.
## Endpoints
- `GET /api/get?q=&n=10` — search the index. Returns page URLs
(up to `n`, default 10, max 50) as `{query, results, hasMore,
nextCursor, truncated, searchWindow, resolve}`. Results are newest first, not
ranked: the search is a LIKE scan, so sort client-side if order matters.
`hasMore` means another page exists and `nextCursor` is the opaque token
that fetches it: pass it back as `&cursor=`. A cursor is bound to its `q`
and `host`, so reusing one with a different query answers 400 rather than
returning rows that do not match. `truncated` means paging stopped at the
2000-row offset ceiling; a cursor walks past that ceiling, because it seeks on
the last id instead of counting rows. `searchWindow` is how far back the
search looked, in rows, and
is now always **0**, meaning the whole active index is scanned rather than only
the newest N links. That is why an old title resolves: there is no window to
fall out of. A query with no searchable token (all non-ASCII, or every word
under 2 characters) returns zero rows rather than the whole index.
The script tries gdflix mirrors first, since those direct links live longest.
- `GET /api/resolve?url=` — best-effort server-side resolve.
Works only for hosts that accept Cloudflare egress; usually 502s.
- `GET /api/links?q=&host=&page=&limit=` — raw index search.
Same body as `/api/get` minus `query` and `resolve`. `&cursor=` works here
too and is the only way past the offset ceiling.
- `GET /api/hosts` — mirror host counts, top 50.
- `GET /api/domains` — upstream provider domain map.
- `GET /api/stats` — index coverage: link totals, posts per provider,
backfill pages, watchdog queue (in-flight plus stuck claims), and today's
ingest write and read row counts. The read count is the ingest fire's own
reads, not all traffic: it exists to show what running the index costs, and
it stays under the free-plan caps by design. Search traffic is budgeted
per isolate instead, and a spent isolate answers 503 on search while this
endpoint keeps working so you can still see the state.
- `GET /scripts` — agent scripts served as source, runnable anywhere.
- `GET /health` — liveness probe.
- `GET /llms.txt` — this file.
- `GET /sitemap.xml` — endpoint list.
- `GET /openapi.json` — machine-readable API description.
## Local resolve how-to (what the script does)
For each page URL, repeat (max 6 hops), preferring in order. This list is the
ACTUAL priority in `nextResolveStep` in src/resolve.ts, in order:
1. pixeldrain (prefer the JS-assigned `var pxl` over the static anchor: the
static one is the DMCA decoy) → DIRECT as `https://pixeldrain.dev/api/file/`.
Stable, resumable, no expiry.
2. `workers.dev` href → DIRECT, download it (lives minutes).
3. `googleusercontent.com` href → DIRECT (lives 3h, stated on provider page).
4. FSL server href (`cdn.fsl-buckets.*`, or any `id="fsl"` anchor) → DIRECT (short TTL).
5. Labeled CDN button ("FSL Server", "FSLv2", "S3 Server") whose href is a
known terminal host → DIRECT.
6. pages.dev watch links → base64-decode the `u` param → DIRECT.
7. `var url = '...gamerxyt...'` → fetch it next.
8. hubcloud `/drive/` href → fetch it next.
9. hubcloud `/re/` href → fetch it next.
10. `hubcloud.php` generator href → fetch it next.
11. `#download` anchor → fetch it next.
12. greenmotors → unpack `s('o','',...)` (base64, base64, rot13,
base64, JSON, base64 of the `o` field) to the hubcloud URL underneath →
fetch it next.
13. foxcloud `quick.` href → fetch it next.
14. BuzzServer anchor → fetch it plus `/download`.
15. "Instant DL" button → fetch it next.
16. JS `window.location.href` → fetch the absolute URL next.
17. `` → fetch its URL next.
Two rules that are not in that list because they are checked before it, on every
hop: an embedded `url=` param pointing at googleusercontent, and an
`hx-redirect` response header. HTTP 3xx → follow Location. Anything else → dead
end, try the next mirror.
Hubcloud search-session pages (`search-recover.php` carrying `Q_INITIAL` and
`FROM_AC_TOKEN`) are a separate branch, not a priority: call its `?api=search`
with a SHORT query (the first 3 distinctive words, never the full locked phrase),
pool pages 1-3 across 2-3 query windows, and fuzzy-pick the best filename.
Every DIRECT above has its host checked against a known-CDN allowlist, so a
terminal host in a page's PATH does not become a download link. The one exception
is rule 6: a pages.dev watch link decodes to an arbitrary https URL by design, so
treat that direct as unverified and check the bytes before trusting it.
Download with single-connection curl plus the file-host headers (follow
redirects: signed URLs 302 to the CDN):
```sh
curl -L -A "Mozilla/5.0" -H "Referer: https://gamerxyt.com/" -H "Cookie: xyt=1" -o movie.mkv ""
```
Verify the first bytes are Matroska (`1a 45 df a3`), not JSON (an error page means the signed URL expired: resolve again).
Docs: https://movies.ssrizz.workers.dev/llms.txt · Spec: https://movies.ssrizz.workers.dev/openapi.json