aboutsummaryrefslogtreecommitdiffstats
path: root/AGENTS.md
blob: 4c44b8dc5062df40308931c76b9d460c0b254d28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# AGENTS.md

Guidance for AI coding agents working in this repository.

## What this is

`coomer_dl`: single-file Python script that downloads Coomer creators, single
posts and single files. Runtime dependency: `requests` only. Keep it a single
file and do not add dependencies. Sibling project: `../bunkr_dl`, same
structure and `download_file`.

## Download chain

The site sits behind DDoS-Guard. When the script finds nothing, re-inspect the
API with `curl --compressed -H 'Accept: text/css'` before changing code.

1. `GET /api/v1/<service>/user/<id>/posts?o=N` returns a JSON list of up to 50
   posts. Pagination stops on a short or empty page.
2. `GET /api/v1/<service>/user/<id>/post/<post id>` returns
   `{"post": {...}, ...}`.
3. `GET /api/v1/<service>/user/<id>/profile` gives the creator `name`, used as
   the folder name.
4. Each post has `file` (may be `{}`) and `attachments`, each `{name, path}`.
   The main file often repeats as an attachment, `post_files` dedupes by path.
5. `GET /data<path>` 302-redirects to `nN.<domain>/data<path>`.

All API calls need `Accept: text/css`, otherwise 403.

## Conventions

- New options go in the `argparse` setup in `main()` and in the README usage
  table.
- `download_file` resumes with a per-request `Range` header. Never mutate the
  global `headers` dict. 206 appends, 200 overwrites, 416 means already complete.
- Creator folders are reused across runs (not suffixed like bunkr_dl) so a
  re-run resumes and only fetches new posts.
- Use placeholder URLs (`https://coomer.st/onlyfans/user/NAME`) in docs,
  comments and commit messages, never real creator names or post ids.

## Testing

No test suite. Verify the API side without downloading by stubbing
`download_file`:

    python - <<'PY'
    import importlib.util, importlib.machinery
    l = importlib.machinery.SourceFileLoader('c', 'coomer_dl')
    c = importlib.util.module_from_spec(importlib.util.spec_from_loader('c', l)); l.exec_module(c)
    got = []; c.download_file = lambda *a: got.append(a)
    c.process_creator('https://coomer.st', 'onlyfans', 'NAME', '/tmp/x')
    print(len(got), got[0])
    PY

The "Found N posts" total should match `post_count` from the profile endpoint.
For a full run use `-o` pointing at a temp dir.

## Repo facts

- License: GPLv2 only (`LICENSE`, header in `coomer_dl`).