updated documentation
This commit is contained in:
@@ -128,7 +128,7 @@ DATA_FILE=/path/to/events.json ARCHIVE_DATA_FILE=/path/to/archive.json uvicorn m
|
|||||||
| `GET` | `/events/{index}` | A single event by its 0-based position in the merged list; `404` if out of range |
|
| `GET` | `/events/{index}` | A single event by its 0-based position in the merged list; `404` if out of range |
|
||||||
| `GET` | `/artists` | Deduplicated, case-insensitively sorted list of all artist names |
|
| `GET` | `/artists` | Deduplicated, case-insensitively sorted list of all artist names |
|
||||||
| `GET` | `/calendar.ics` | iCalendar/webcal feed of all events — subscribe from any calendar app |
|
| `GET` | `/calendar.ics` | iCalendar/webcal feed of all events — subscribe from any calendar app |
|
||||||
| `POST` | `/reload` | Re-read the data file(s) from disk (call after re-running the scraper); `500` if the main file is missing |
|
| `POST` | `/reload` | Re-read the data file(s) from disk (call after re-running the scraper); rate-limited (below); `500` if the main file is missing |
|
||||||
|
|
||||||
### `/events` query parameters
|
### `/events` query parameters
|
||||||
|
|
||||||
@@ -165,16 +165,26 @@ API. `GET /health` reports, for both the regular and archive scrape:
|
|||||||
- `last_scrape_at` / `seconds_since_last_scrape` — from the output file's
|
- `last_scrape_at` / `seconds_since_last_scrape` — from the output file's
|
||||||
mtime, so this works no matter how the scrape was triggered.
|
mtime, so this works no matter how the scrape was triggered.
|
||||||
- `next_scrape_at` / `seconds_until_next_scrape` — computed from a cron
|
- `next_scrape_at` / `seconds_until_next_scrape` — computed from a cron
|
||||||
expression *you provide*, since the API can't reliably read another
|
expression, sourced in order:
|
||||||
process's crontab. Set it to match what's actually in cron:
|
1. `SCRAPE_CRON` / `ARCHIVE_SCRAPE_CRON` env vars, if set — always wins,
|
||||||
|
and the only option that works when the API doesn't run as the same
|
||||||
|
user/host as the cron job.
|
||||||
|
2. Otherwise, the API's own OS user's crontab (`crontab -l`), looked up
|
||||||
|
for a line invoking `scraper.py` (with vs. without `--archive` picks
|
||||||
|
archive vs. plain; an `@reboot` line for the same script is skipped
|
||||||
|
since it isn't a recurring schedule). Only works when the API process
|
||||||
|
runs as the same user whose personal crontab holds the scrape job —
|
||||||
|
not a system crontab/cron.d entry, not a job under a different user
|
||||||
|
or host.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
SCRAPE_CRON="0 * * * *" ARCHIVE_SCRAPE_CRON="0 4 * * *" uvicorn main:app
|
SCRAPE_CRON="0 * * * *" ARCHIVE_SCRAPE_CRON="0 4 * * *" uvicorn main:app
|
||||||
```
|
```
|
||||||
|
|
||||||
`ARCHIVE_SCRAPE_CRON` falls back to `SCRAPE_CRON` if unset (handy if both
|
`ARCHIVE_SCRAPE_CRON` falls back to `SCRAPE_CRON` (env or crontab-discovered)
|
||||||
scrapes run off the same cron line). Leaving both unset just omits the
|
if unset (handy if both scrapes run off the same cron line). If neither an
|
||||||
`next_scrape_at` fields (`null`) — `last_scrape_at` still works.
|
env var nor a matching crontab line is found, you just get the last-scrape
|
||||||
|
info with `next_scrape_at` / `seconds_until_next_scrape` as `null`.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"scrape": {
|
"scrape": {
|
||||||
@@ -186,6 +196,17 @@ scrapes run off the same cron line). Leaving both unset just omits the
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `/reload` rate limiting
|
||||||
|
|
||||||
|
`POST /reload` is limited to one call per `RELOAD_MIN_INTERVAL_SECONDS`
|
||||||
|
(default 10) — a call within that window returns `429` with a `Retry-After`
|
||||||
|
header instead of re-reading the file(s). It's a single shared cooldown, not
|
||||||
|
per-caller, so it also protects the server if several callers hit it at once.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RELOAD_MIN_INTERVAL_SECONDS=30 uvicorn main:app
|
||||||
|
```
|
||||||
|
|
||||||
### Calendar / webcal feed
|
### Calendar / webcal feed
|
||||||
|
|
||||||
`GET /calendar.ics` renders every loaded event (upcoming + archived) as an
|
`GET /calendar.ics` renders every loaded event (upcoming + archived) as an
|
||||||
@@ -259,6 +280,8 @@ curl -X POST http://127.0.0.1:8000/reload
|
|||||||
│ ├── main.py # FastAPI app + routes
|
│ ├── main.py # FastAPI app + routes
|
||||||
│ ├── datasource.py # loads/merges/reloads the JSON files, date & artist helpers
|
│ ├── datasource.py # loads/merges/reloads the JSON files, date & artist helpers
|
||||||
│ ├── calendar_feed.py # builds the /calendar.ics webcal feed
|
│ ├── calendar_feed.py # builds the /calendar.ics webcal feed
|
||||||
|
│ ├── scrape_schedule.py # last/next-scrape info for /health (env var or crontab)
|
||||||
|
│ ├── rate_limit.py # shared cooldown gate used by /reload
|
||||||
│ ├── models.py # Pydantic models for the event schema
|
│ ├── models.py # Pydantic models for the event schema
|
||||||
│ ├── requirements.txt
|
│ ├── requirements.txt
|
||||||
│ └── README.md
|
│ └── README.md
|
||||||
|
|||||||
Reference in New Issue
Block a user