osu-mapper-indexer is a worker that scans osu! beatmapsets in discovery mode, extracts mapper users, and stores results in PostgreSQL.
No local app runtime is required. Run everything through Docker.
- Default worker throttle is 50 requests per minute.
- This project is designed to stay below the common safe ceiling of 60 requests per minute for ppy API usage.
- If you plan to go above 60 RPM, contact ppy first.
- Recommended policy: do not change the default 50 RPM unless you have a clear and justified reason.
Please respect API limits.
Quick Start With just
- Create env file:
cp .env.example .env- Fill required variables in
.env:
OSU_CLIENT_IDOSU_CLIENT_SECRETPOSTGRES_PASSWORD
- Start stack (DB + migrations + worker):
just up- View logs:
just logs- Stop stack:
just downUse plain Docker Compose commands:
- Start PostgreSQL:
docker compose up -d --build postgres- Run migrations:
docker compose run --rm migrator- Start worker:
docker compose up -d --build indexer- View logs:
docker compose logs -f --tail=727- Stop all:
docker compose downRebuild without cache:
docker compose down
docker compose build --no-cache
docker compose up -dVia just:
just up- start postgres, run migrations, start indexerjust migrate- run migrations onlyjust down- stop stackjust wipe- full cleanup of project Docker state (asks confirmation; onlyyesproceeds)just rebuild- down + no-cache build + upjust logs- follow service logsjust dump [dir]- create backup bundle (defaultbackups)just health- check Rust and Docker tooling availabilityjust check- runcargo checkandcargo clippy
Direct Docker equivalents:
docker compose up -d --build postgresdocker compose run --rm migratordocker compose up -d --build indexerdocker compose downdocker compose logs -f --tail=727./scripts/dump.sh backups
Full cleanup equivalent:
docker compose down -v --remove-orphans --rmi localThe app builds DB URL internally from POSTGRES_* values.
| Variable | Required | Default | Description |
|---|---|---|---|
OSU_CLIENT_ID |
Yes | - | osu! OAuth client ID |
OSU_CLIENT_SECRET |
Yes | - | osu! OAuth client secret |
POSTGRES_PASSWORD |
Yes | - | PostgreSQL password |
POSTGRES_HOST |
No | localhost (postgres in container runtime) |
PostgreSQL host |
POSTGRES_PORT |
No | 5432 |
PostgreSQL port |
POSTGRES_USER |
No | postgres |
PostgreSQL user |
POSTGRES_DB |
No | osu_mapper_indexer |
PostgreSQL database name |
SCAN_COUNTRY_CODES |
No | UA |
One or many ISO-3166 alpha-2 country codes (comma-separated for multiple) |
SCAN_MODES |
No | all |
Comma-separated scan modes: all, osu, taiko, catch, mania |
SCAN_OLDEST_FIRST |
No | false |
If true, scans from oldest pages first |
SCAN_RANKED_ONLY |
No | false |
If true, scan only ranked beatmapsets |
SCAN_PAGE_DELAY_MS |
No | 500 |
Delay between page requests (ms) |
SCAN_MAX_PAGES |
No | empty | Limit pages per run (empty = no limit) |
SCAN_BATCH_SIZE |
No | 50 |
Users batch size for profile lookup |
SCAN_FORCE_RESCAN |
No | false |
Ignore cutoff and rescan fully |
SCAN_RESUME_FROM_CHECKPOINT |
No | true |
Resume from stored checkpoint |
WORKER_PROGRESS_EVERY |
No | 25 |
Progress log interval in pages |
RUST_LOG |
No | info |
Log level |
SCAN_MODES examples:
SCAN_MODES=allSCAN_MODES=osu,taikoSCAN_MODES=std,tko,ctb
SCAN_COUNTRY_CODES examples:
SCAN_COUNTRY_CODES=UA(single country)SCAN_COUNTRY_CODES=UA,PL,DE(multiple countries)
The worker emits three main log groups:
- Start log:
start discovery=on countries=... modes=... ranked_only=...countries: country filter fromSCAN_COUNTRY_CODESmodes: mode filter fromSCAN_MODES(allor explicit list)ranked_only: ranked filter fromSCAN_RANKED_ONLY
- Progress log:
discovery page=<n> new=<n> existing=<n> skip=<n> <seconds>spage: number of scanned pages in current runnew: users inserted/updated as mapper rows in this runexisting: creators already present in DB, skipped from user profile fetchskip: users skipped because their country is not inSCAN_COUNTRY_CODES<seconds>s: elapsed time from run start
- Finish logs:
discovery done page=<n> new=<n> existing=<n> skip=<n> <seconds>sdone duration=... requests=... throttle_sleep_ms=... retries=...requests: number of throttled osu API acquiresthrottle_sleep_ms: total sleep time added by rate limiterretries: total osu API retry attempts
Main tables:
mapper_discovery_mappersmapper_discovery_scan_state
Service table:
seaql_migrations
Create backup bundle:
just dump
# also works as alias
just backupor
./scripts/dump.sh backupsEach run creates a folder like backups/omi-YYYYMMDD-HHMMSS/ with:
- plain SQL dump (
.sql) - compressed SQL dump (
.sql.gz) - custom PostgreSQL dump (
.dump) - CSV exports for
mapper_discovery_*tables (csv/*.csv)
This project is licensed under MIT. See LICENSE.