L'index de maps derrière la page Parcourir a une petite API publique. Elle est en lecture seule, ne demande aucun compte et répond en JSON (sauf le fichier de chart). Soyez raisonnable : les réponses sont mises en cache et les requêtes limitées par adresse.
Identité d'un chart : le hash des notes
Un chart est identifié par le hash de ses notes : 64 caractères hexadécimaux minuscules, un condensé BLAKE3 du nombre
de touches et de chaque note (début, colonne, type, fin d'une note longue) en millisecondes entières, relatives à la
première note. Les mêmes notes donnent le même hash, qu'elles viennent d'un fichier .osu, .sm, .ssc ou .qua et
quel que soit le nom du fichier ; les mines et les rafales sont ignorées ; la musique et les métadonnées ne comptent pas.
La version du hash est renvoyée dans noteHashVersion. L'index ne contient que des charts osu!mania et Etterna de 4 à
7 touches.
GET /api/charts/{hash}
Où peut-on télécharger ce chart ? Un hash mal formé répond 400 ; un hash bien formé que l'index ne connaît pas répond
200 avec status: "unknown" (un client peut donc demander sans traiter d'erreur).
{
"chartHash": "9f2c…64 hex…",
"status": "known",
"sources": [
{ "kind": "osuSet", "ref": "4001", "confidence": "verified", "checkedAtMs": 1791600000000 }
],
"ttlMs": 300000,
"chart": {
"hash": "9f2c…", "noteHashVersion": 1, "keys": 7,
"bpmMin": 120.0, "bpmMax": 180.0, "bpmMain": 180.0,
"lengthMs": 144000, "notes": 1200, "lns": 40,
"densityAvg": 8.3, "densityPeak": 14.0, "roxBytes": 5120,
"title": "Song", "artist": "Artist", "creator": "Mapper", "difficulty": "7K Hard"
}
}
kind est un ensemble ouvert (osuSet, etternaPack, ...) : ignorez les valeurs inconnues. ref est un
identifiant, jamais une URL : un id de set osu!, un id de pack EtternaOnline. La page de la source est
https://osu.ppy.sh/beatmapsets/<ref> ou https://etternaonline.com/packs/<ref>. La réponse porte un ETag et
Cache-Control: public, max-age=300.
GET /api/charts/{hash}/rox
Le chart au format compact ROX (le format d'échange ouvert du jeu), servi à la demande comme pièce jointe
(application/octet-stream, ETag: "<hash>", immutable). 404 si le chart est inconnu ou retiré. Jamais de
musique, jamais d'image.
GET /api/charts/{hash}/scores
Le classement en ligne d'un chart : chaque joueur une fois, avec sa meilleure partie. Le serveur de jeu a vérifié chaque partie et l'a rejouée sur sa propre copie du chart avant de l'écrire dans la base du site, et il lit toute partie sous le jugement Prism (le jugement choisi par le joueur n'est que la trace de ce avec quoi il a joué : les classements n'ont pas de dimension « jugement »). La précision, le combo et les miss sont ceux de Prism, jamais ce que le joueur déclare. Meilleure note d'abord (la note MinaCalc 515 calculée par le serveur ; une partie sans note après), puis la précision Prism, puis le plus grand combo, puis la partie enregistrée la première. Les parties d'un compte banni, ou dont la suppression est programmée, ne sont pas listées.
| Paramètre | Sens |
|---|---|
rate |
absent ou all : LE classement du chart, chaque joueur une fois avec sa meilleure partie quelle que soit sa vitesse. Une vitesse de lecture exacte, 0,5 à 2,0 : le même classement sur les parties de cette vitesse, chaque joueur une fois aussi (total compte les joueurs) |
limit, offset |
limit de 1 à 100 (défaut 50), offset au plus 10000 |
Il n'y a plus de paramètre judgement ; un paramètre inconnu (le judgement= d'un ancien client) est ignoré, pas une erreur.
{
"chartHash": "9f2c…64 hex…", "rate": 1.0,
"total": 132, "offset": 0, "limit": 50,
"items": [
{ "id": 4821, "hasReplay": true, "rank": 1, "username": "Ada", "userId": "0190…uuid…", "accuracy": 99.12, "maxCombo": 842, "misses": 1,
"counts": [610, 120, 60, 30, 12, 6, 3, 1], "rating": 24.5, "playedAtMs": 1791600000000, "playbackRate": 1.0 }
]
}
Un chart que personne n'a joué donne total: 0 sans entrée, jamais une erreur ; un hash ou un paramètre mal formé
répond 400 en le nommant. rank compte sur tout le classement, pas sur la page. playedAtMs est la date que le jeu
du joueur déclare. userId est l'UUID du compte (en minuscules) : le jeu le compare à son propre compte pour repérer
« mon score ». counts (les huit paliers Prism, le Miss en dernier) et rating manquent pour une partie enregistrée avant que le serveur les garde.
GET /api/charts/{hash}/boards
Les vitesses d'un chart, pour qu'une page ne propose que des choix menant à un classement qui a des parties : une entrée par vitesse de lecture ayant au moins une partie visible, par vitesse croissante (200 au plus). Il n'y a aucun jugement dedans.
{
"chartHash": "9f2c…64 hex…",
"boards": [
{ "rate": 1.0, "plays": 132 }
]
}
plays compte les joueurs de cette vitesse (le total de GET /api/charts/{hash}/scores?rate=). Les parties des comptes bannis ou en suppression programmée ne sont pas
comptées. Un chart que personne n'a joué donne une liste vide, jamais une erreur ; un hash mal formé répond 400.
GET /api/chartsets
Les sets (un par dossier de chanson d'un set osu! ou d'un pack Etterna), les plus récents d'abord par défaut.
| Paramètre | Sens |
|---|---|
q |
texte trouvé dans le titre, l'artiste, le créateur ou les tags |
keys |
nombres de touches séparés par des virgules, par exemple 4,7 |
source |
osuSet ou etternaPack |
creator, artist, title |
une partie du nom (avec creatorMatch, artistMatch, titleMatch = exact pour une égalité exacte, sans casse) |
difficulty |
un nom de difficulté d'un chart du set (difficultyMatch comme ci-dessus) |
tags |
texte trouvé dans les tags |
bpmMin, bpmMax |
plage de BPM recouvrant les charts du set |
lengthMin, lengthMax |
durée en secondes |
densityMin, densityMax |
notes par seconde au plus fort |
ratingCalc, ratingMin, ratingMax |
plage de difficulté selon le calculateur : minacalc (par défaut), osu, quaver ou sunny, à 1,0× |
sort |
updated (par défaut), title, artist, bpm, length, density, rating (selon ratingCalc) |
page, perPage |
perPage vaut 60 au plus |
La réponse est { "items": [...], "total": n, "page": p, "perPage": n } ; chaque élément porte id, title, artist,
creator, sourceKind, keys, bpmMin, bpmMax, lengthMinMs, lengthMaxMs, densityMax, chartCount et
downloadUrl (/go/chartset/<id>, absent pour un set sans source publique).
GET /api/chartsets/{id}
Un set : les champs ci-dessus plus tags, sources et charts (chacun avec son objet chart, le nom de sa
difficulty dans ce set et, pour osu!, son osuBeatmapId).
GET /go/chartset/{id}
Une redirection 302 vers la page de la source d'origine, où l'on télécharge la map. 404 pour un set sans source
publique.
Limites et usages
- Les requêtes sont limitées par adresse (240 par minute par défaut pour chacun des quatre groupes : consultation de
charts, fichiers
.rox, classements, liste des sets) ; au-delà, la réponse est429avecRetry-After. - Utilisez
ETag/If-None-Match; n'interrogez pas en boucle. - Mettez un moyen de vous joindre dans votre
User-Agent. - Les créateurs sont crédités partout où un chart est montré. Pour faire retirer une entrée, utilisez la page Contact.