Sur cette page

← Toute la documentation

API de l'index de maps

L'API JSON publique, en lecture seule, de l'index de maps : identité d'un chart, sources, sets, fichier .rox, scores en ligne, limites.

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 est 429 avec Retry-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.