maistats is a monorepo for collecting and viewing maimai DX NET play data.
It separates shared song metadata from private play records: song data can be
hosted publicly, while each user's records stay in their own self-hosted
collector.
maistats-song-infobuilds the shared song database: titles, aliases, chart metadata, internal levels, and jacket assets.maistats-record-collectoris the per-user service. It logs in with one SEGA ID, stores records in local SQLite, and exposes APIs used by the web app and Discord bot.maistats-discord-botis a shared Discord bot. Users register their own collector URL with the bot, and the bot reads only from that collector.apps/maistatsis the web frontend. It reads the shared song database and connects to a collector URL configured by the user.crates/contains shared Rust crates for auth, parsing, clients, and common models.
The intended deployment model is:
- Shared infrastructure hosts the song database, Discord bot, and frontend.
- Each player hosts their own record collector with their own SEGA ID.
- The frontend and Discord bot connect to that user's collector URL.
.
|-- apps/maistats/ # Vite + React frontend
|-- maistats-record-collector/ # Self-hosted personal record API
|-- maistats-song-info/ # Shared song database generator
|-- maistats-discord-bot/ # Shared Discord bot
|-- crates/
| |-- maimai-auth/ # maimai DX NET auth helpers
| |-- maimai-client/ # API clients for maistats services
| |-- maimai-parsers/ # HTML parsers
| `-- models/ # Shared API/domain/storage models
`-- .github/workflows/ # CI and deployment workflows
- Rust stable
- Node.js 20+
- npm
- A SEGA ID account for collector or song database generation
- A Discord bot token if running the Discord bot
Root Rust services use .env:
cp .env.example .envImportant groups:
- Record collector:
SEGA_ID,SEGA_PASSWORD,RECORD_COLLECTOR_PORT,DATA_DIR,DATABASE_URL - Song database:
SONG_DATA_PATH - Song database authenticated source:
MAIMAI_INTL_SEGA_ID,MAIMAI_INTL_SEGA_PASSWORD,USER_AGENT - Discord bot:
DISCORD_BOT_TOKEN,DISCORD_DEV_USER_ID,SONG_DATABASE_URL,DISCORD_BOT_DATABASE_URL - Song database publishing: R2 credentials and public base URL
The frontend has its own template:
cp apps/maistats/.env.example apps/maistats/.envSONG_DATABASE_URLRECORD_COLLECTOR_SERVER_URL
RECORD_COLLECTOR_SERVER_URL is only the default connection target. In normal
use, each user can set their own collector URL in the web app.
Install frontend dependencies from the repository root:
npm ciGenerate shared song data:
cargo run -p maistats-song-infoRun a personal record collector:
cargo run -p maistats-record-collectorBy default it listens on http://localhost:3000. Useful endpoints include:
GET /healthGET /health/readyGET /api/versionGET /api/playerGET /api/scores/ratedGET /api/songs/scoresGET /api/recentGET /api/todayGET /api/rating/targetsPOST /api/poll
Run the Discord bot:
cargo run -p maistats-discord-botRun the frontend:
npm run dev:maistatsThe Vite dev server normally starts at http://localhost:5174 unless that port
is already in use.
Published images are available from GHCR:
ghcr.io/minty99/maistats-record-collector:latestghcr.io/minty99/maistats-discord-bot:latest
Example compose files are included:
docker compose -f compose.record_collector.yaml up -d
docker compose -f compose.discord_bot.yaml up -dThe record collector compose file stores SQLite data under ./data.
The frontend provides pages for setup, score browsing, rating breakdowns, user tier views, playlogs, achievement plots, and connection settings. It can use the public song database while reading personal records from any compatible self-hosted collector.
Users connect their collector with /register <url>. The bot can then show
score summaries, song metadata, recent plays, today's plays, up/down sessions,
user-tier up/down sessions, and rating plots through slash commands.
- Record collector SQLite: usually
data/maimai.sqlite3 - Discord bot SQLite: usually
data/maistats-discord-bot.sqlite3 - Song database output: usually
data/song_data/data.jsonanddata/song_data/cover/ - Runtime cookies: temporary process-local files outside committed source
Do not commit .env, data/, generated databases, cookies, or private crawl
artifacts.
Rust:
cargo fmt --all -- --check
cargo clippy --all -- -D warnings
cargo testFrontend:
npm run build:maistats
npm run test:maistatsmaistats-song-infois validated in CI and published by the scheduledSong Databaseworkflow when the required secrets are configured.maistats-record-collectorandmaistats-discord-botare built as Docker images by the GHCR workflow.apps/maistatsis validated separately by the frontend workflow and is configured for Cloudflare/Vite deployment.