API 目前处于 Early Preview 阶段, 可能存在诸多不完善与错误之处,欢迎加群交流反馈:加入官方交流群(1073434398)
落雪查分器
从落雪(LXNS)maimai / chunithm API 迁到 RankHub v1:三种鉴权、success/code 包络、端点、成绩字段、B50 结构与限流。
这一页写给已经接过落雪咖啡屋(LXNS)API 的开发者:认证、包络、端点、成绩字段、Best 50 结构 与写入语义逐项对照。逐游戏字段表不在这里重复:maimai 格式 / chunithm 格式。
你会的东西 vs RankHub
落雪(https://maimai.lxns.net/api/v0) | RankHub v1(https://api.rankhub.cc) |
|---|---|
三种头:Authorization: <API 密钥>(裸值)、X-User-Token: <token>、Authorization: Bearer <access_token>(OAuth) | 只有一种:Authorization: Bearer <access_token>,scope game:read / game:write |
玩家授权开关(allow_third_party_fetch_* / _write_data)关掉即 403 | 档案归属即授权:只能读写自己的 profileId,别人的档案 404 |
包络 {success,code,message,data};公共资源(曲库/别名)成功时直接返回数据 | 一律 {code,message,description,data,requestId}(没有「裸返回」分支) |
GET /maimai/player/{friend_code} 查玩家;.../bests 取 B50(含 standard_selections / dx_selections) | GET /v1/games/maimai/profiles/{profileId} 读档案;GET .../bests 直接给当期/往期两个桶 |
POST /maimai/player/{friend_code}/scores,body {"scores": Score[]} | POST /v1/games/maimai/profiles/{profileId}/scores,body {"scores":[…]}(同名形状,字段见下) |
GET /maimai/song/list 曲库(无需鉴权) | 不提供曲库;曲目信息由服务端按 id 解析 |
单曲 dx_rating 是 float,展示时自行 floor | maimai 的 rating 由服务端算并返回整数;不要回传 dx_rating |
chunithm:/chunithm/player/...、bests/selections/new_bests | GET /v1/games/chunithm/... 的 bests 按 best30 / selection10 / new20 分桶 |
三种鉴权 → 一种
落雪的三种密钥不能混用(文档原话):开发者密钥只能查别人、个人 token 只能查自己、OAuth 才能拿全量成绩。 RankHub 没有「开发者钥匙」概念:第三方应用走 OAuth(用户授权你的 app),拿到 access token 后 以用户身份读写。流程见授权码模式 与 scope。
迁移提示:落雪开发者密钥是
Authorization: <裸值>,没有Bearer前缀 —— 照抄成 RankHub 会401; RankHub 只认Bearer <token>。
包络与错误
| 落雪 | RankHub | |
|---|---|---|
| 成功 | {"success":true,"code":200,"message":null,"data":…} | {"code":"common.ok","message":"OK","description":null,"data":…,"requestId":"…"} |
| 失败 | {"success":false,"code":400,"message":"invalid friend code"} | HTTP 4xx/5xx + {"code":"common.invalidArgument","message":"…"} |
| 限流 | 按 IP:5 req/s,突发 20,超限 429,需退避 | 见批量与限流 |
| 时间 | UTC ISO(2026-01-01T00:00:00Z) | RFC3339(同 UTC ISO) |
成绩字段对照(maimai)
落雪 Score | RankHub scores[] | 注意 |
|---|---|---|
id(数字;无 10000 偏移,标准/DX 共用;宴会场 >100000) | songId(字符串) | 标准/DX 用 type 区分;不要套水鱼 DX 的 -10000 逻辑 |
type:standard / dx / utage | 同名枚举 | 宴会场不参与 Best 50 |
level_index 0~4 | levelIndex 0~4 | 同 |
achievements(float 百分比) | achievements | 同口径,直接透传;不是 ×10000 |
dx_score、dx_star | dxScore、dxStar | native 机台路径里对应 deluxscoreMax |
fc:app/ap/fcp/fc | fc | 同枚举;机台 comboStatus 1~4 映射 |
fs:fsdp/fsd/fsp/fs/sync | fs | 同枚举;机台 syncStatus 1~4 映射,0/5 表示无 |
dx_rating(float) | 不接收 | 服务端按 achievements + 定数重算,返回整数 rating |
play_time / upload_time / last_played_time | playTime | 只保留 playTime |
chunithm:score(≤1,010,000)、rating、full_combo(alljusticecritical/alljustice/fullcombo)、
full_chain(fullchain/fullchain2)、level_index(0~5,含 WORLD'S END)对应 RankHub 的同名字段,
差异见 chunithm 字段对照。
B50 / 分桶
- 落雪
bests直接返回standard/dx两组 +*_selections(旧版 B35 + 新曲 selection); - RankHub 的
GET .../bests把「当期 / 往期」分成两个桶,成员规则由服务端定, 与落雪的standard_total/dx_total不是一一对应 —— 别把落雪的 total 当 RankHub 的totals。
迁移四步
- 用 RankHub OAuth 换 token(
game:read/game:write); POST /v1/games/{game}/profiles建档(maimai:好友码或机台userId;chunithm:好友码);- 把落雪的
Score[]映射成 RankHubscores[](或直接给native:maimai 机台载荷 / chunithm 原始对象); - 读回用
/scores(cursor分页)与/bests。
最容易踩的五个坑
- 开发者密钥无
Bearer:落雪裸值、RankHubBearer。 dx_rating不要回传:RankHub 会忽略(maimai 服务端算),传了也没用,还可能造成困惑。- 宴会场(utage)不进 Best 50:落雪 B50 本来就不含;RankHub 同样不计入最佳桶,但
/scores能读到。 achievements量纲:两边都是百分比;机台 ×10000 的整数只在native里用。 (另:songId两家不同 —— 落雪id无偏移,水鱼 DXsong_id带 +10000,见 水鱼篇。)- 曲线不同:落雪按好友码查任意人;RankHub 只能读写自己名下档案,多用户要各自授权 + 建档。