#osu #osynic #wasm #score #osuapi

bin+lib osynic_osuapi

High performance, well-structured, extensible Rust osu! API client. Supports both WASM and native environments.

1 unstable release

Uses new Rust 2024

new 0.1.0 May 15, 2025

#30 in Games

MIT license

360KB
8K SLoC

Logo逃走啦~

OsynicOsuapi

高性能, 结构优良, 拓展性好的 Rust osu! API 客户端 支持 WASM 和 native 环境.


中文版本 | English Version

📄 OSU!API 官方文档

🧻 API体验网站

OsynicOsuapiCN.png

LeptosOsuapiPlayground是基于leptos框架快速搭建了一个osynic_osuapi体验网站,主要使用了的V1的WASM客户端支持(基于gloo-net),不过很显然,由于CORS的问题,不代理直接在浏览器中使用V1的API会遇到跨域问题(毕竟WASM部分是浏览器前端发的请求嘛),所以用Deno来搭建了一个中转服务器osynic-cors.deno.dev,配合WASM客户端的proxy_url来实现代理请求;

目前网站通过Deno部署在osynic-osuapi.deno.dev,支持中日韩德法俄英等多种语言;

📜 特性

  • 新旧 API 支持: 支持 V1 的所有端点 以及 V2 的大部分端点(除了文档未归类的接口)
  • WASM 兼容性: 为 V1 接口 提供了 WebAssembly 支持,支持直接从网页应用访问 OSU API(但是会遇到CORS)
  • 项目结构良好: 基于clientinterfacemodel三重模块划分;client部分聚合interface接口并支持多种HTTP客户端,便于拓展
  • 非常完整的示例支持: 在examples目录下,我们提供了非常完整的示例代码与返回数据,详见下方的API检查表部分
  • 在示例中学习使用: 学习使用本库的最佳方式就是直接查看examples中丰富的示例代码,或者直接运行cargo run --example 示例名来查看对应的返回数据,只要习惯示例的代码风格,很快就能上手使用

🚀 快速开始

1. 申请OSU!API的开放授权(V2)或者旧版本API(V1)

申请网址就在你的osu设置页,在开放授权(V2)或者旧版本API(V1)中申请即可

2. 设置环境变量

在你的项目根目录下创建一个.env文件,内容如下

# V2 API
CLIENT_ID="你的client_id"
CLIENT_SECRET="你的client_secret"
REDIRECT_URI="你的redirect_uri"
CODE="你的code" # Authorization Code Grant认证时需要

# V1 API
API_KEY="你的api_key"

然后我们就可以通过dotenvy依赖来读取.env中的环境变量了

3. 添加依赖并使用

首先在Cargo.toml中添加依赖

[dependencies]
osynic_osuapi = "0.1.0"
# 默认features是 ["v1", "v2", "not-wasm"],如果需要在WASM环境中使用,需要关闭`not-wasm`特性,然后添加`wasm`特性,例如:
# osynic_osuapi = { version = "0.1.0", default-features = false, features = ["v1", "v2", "wasm"] }

然后在代码中使用即可~

示例一:用V2完成CCG认证并获取peppy的用户信息

下面的代码来自examples/peppy.rs,可以直接运行cargo run --example peppy来查看效果

// Client Credentials Grant and Get Peppy's User Info
use osynic_osuapi::error::Result;
use osynic_osuapi::v2::client::request::client::OsynicOsuApiV2Client;
use osynic_osuapi::v2::interface::oauth::IOauth;
use osynic_osuapi::v2::interface::users::IUsers;

// You can also import all the client and interface modules by prelude
// use osynic_osuapi::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    dotenvy::dotenv().ok();
    let client_id = std::env::var("CLIENT_ID").expect("CLIENT_ID not set");
    let client_secret = std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set");
    let client = OsynicOsuApiV2Client::default();
    let token = client
        .oauth
        .get_token_without_code(client_id.parse()?, &client_secret)
        .await?;
    println!("{:?}", token);

    let peppy = client
        .users
        .get_user_by_username("peppy", None, None)
        .await?;
    println!("{:?}", peppy);

    Ok(())
}

示例二:用V1查阅谱面信息

下面的代码来自examples/gb.rs,可以直接运行cargo run --example gb来查看效果

// Get beatmap by hash
use osynic_osuapi::error::Result;
use osynic_osuapi::v1::client::request::client::OsynicOsuApiV1Client;
use osynic_osuapi::v1::interface::beatmap::IBeatmap;
use osynic_osuapi::v1::model::beatmap::GetBeatmapsParams;

// You can also import all the client and interface modules by prelude
// use osynic_osuapi::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("API_KEY").expect("API_KEY is not set.");
    let client = OsynicOsuApiV1Client::new(api_key.clone());
    let params = GetBeatmapsParams::default().hash("69f77b0dfe67d288c1bf748f91ceb133".to_string());

    let beatmaps = client.beatmap.get_beatmaps(params).await?;
    println!("{:?}", beatmaps);

    Ok(())
}

🍕 API检查表

可通过cargo run --exmaple 示例名来运行API对应示例

V1

本条目基于V1官方文档的API大类进行划分,分类如下

其中接口模块对应可以在src/v1/interface中找到,相应实现则在src/v1/client/request/api或者src/v1/client/gloo/api中可以找到

API 支持 备注 示例名 模块名
/get_beatmaps 获取谱面 gb beatmap
/get_user 获取用户 gu user
/get_user_best 获取用户最佳成绩 gub user
/get_user_recent 获取用户最近成绩 gur user
/get_match 获取比赛 gm multiplayer
/get_scores 获取谱面成绩 gss scores
/get_replay 获取回放 gr replay

V2

本条目基于V2官方文档的API大类进行划分,分类如下

其中接口模块对应可以在src/v2/interface中找到,相应实现则在src/v2/client/request/api中可以找到,示例代码和相应数据在src/v2/examples中可以找到

大类 API总数 API支持数 备注 模块名
Authentication 4 4 ✅ OAuth与认证 oauth
Beatmaps 10 10 ✅ 谱面API beatmaps
Beatmapsets 7 2 ⚠️403 Forbidden 谱面集API beatmapsets
Changelog 3 3 ✅ 变更日志API changelog
Chat 11 0 ❌403 Forbidden 聊天API chat
Comments 7 2 ⚠️403 Forbidden 评论API comments
Events 1 1 ✅ 事件API events
Forum 8 4 ⚠️403 Forbidden 论坛API forum
Home 1 1 ✅ 首页API search
Matches 1 2 ✅ 比赛API matches
Multiplayer 4 2 ⚠️403 Forbidden 多人API multiplayer
News 2 2 ✅ 新闻API news
Notifications 2 0 ❌403 Forbidden 通知API notifications
Rankings 3 3 ✅ 排行榜API rankings
Scores 1 1 ✅ 成绩API scores
Users 7 7 ✅ 用户API users
Wiki 1 1 ✅ Wiki API wiki

Authentication

API 支持 备注 示例名
/get_token_with_code 即Authorization Code Grant的缩写,需要用户在浏览器OAuth授权来拿到code,进而来请求token,不需要client_secret acg
/get_token_without_code 即Client Credentials Grant的缩写,直接请求token,不需要用户授权,client_secret需要在环境变量中设置 ccg
/refresh_token CCG认证下,通过拿到的refresh_token刷新token refresh
/revoke_current_token 撤销当前token revoke

Beatmaps

API 支持 备注 示例名
/get_beatmap_packs 获取多个谱面包 bpsg
/get_beatmap_pack 获取谱面包 bpg
/lookup_beatmap 查阅谱面 bl
/get_beatmap 获取谱面 bg
/get_beatmap_attributes 获取谱面属性 bga
/get_beatmaps 获取多个谱面 bgs
/get_scores 获取谱面成绩 bgss
/get_solo_scores 获取谱面成绩(Legacy) bgssn
/get_user_score 获取用户成绩 bgus
/get_user_scores 获取用户多个成绩 bguss

Beatmapsets

API 支持 备注 示例名
/get_beatmapsets_discussions_posts 🈳(不稳定接口) 获取铺面集讨论区发布 bsdpg
/get_beatmapsets_discussions_vote 🈳(不稳定接口) 获取铺面集讨论区投票 bsdvg
/get_beatmapsets_discussions 🈳(不稳定接口) 获取铺面集讨论区 bsdg
/search 搜索谱面集 bss
/lookup 🈳(文档不明) 查阅谱面集 bsl
/get_beatmapset 获取谱面集 bsg
/download 下载谱面集(lazer) bsd

Changelog

API 支持 备注 示例名
/get_changelog_build 获取变更日志 cbg
/get_changelog_listing 获取变更日志列表 clg
/lookup_changelog_build 查阅变更日志 cbl

Chat

API 支持 备注 示例名
/chat_keepalive ❌403 Forbidden 保持连接 chk
/create_new_pm ❌403 Forbidden 创建新私信 chpc
/get_updates ❌403 Forbidden 获取更新 chug
/get_channel_messages ❌403 Forbidden 获取频道消息 chmg
/send_message_to_channel ❌403 Forbidden 发送消息 chms
/join_channel ❌403 Forbidden 加入频道 chj
/leave_channel ❌403 Forbidden 离开频道 chl
/mark_channel_as_read ❌403 Forbidden 标记频道已读 chmr
/get_channel_list ❌403 Forbidden 获取频道列表 chlg
/create_channel ❌403 Forbidden 创建频道 chc
/get_channel ❌403 Forbidden 获取频道 chg

Comments

API 支持 备注 示例名
/get_comments 获取多条评论 csg
/post_comment ❌403 Forbidden 发送评论 cp
/get_comment 获取评论 cg
/edit_comment ❌403 Forbidden 编辑评论 ce
/delete_comment ❌403 Forbidden 删除评论 cd
/add_comment_vote ❌403 Forbidden 投票 cva
/remove_comment_vote ❌403 Forbidden 撤销投票 cvr

Events

API 支持 备注 示例名
/get_events 获取事件 events

Forum

API 支持 备注 示例名
/reply_topic ❌401 Unauthorized 回帖 ftr
/get_topics_listing 获取主题列表 ftlg
/create_topic ❌401 Unauthorized 创建主题 ftc
/get_topic_and_posts 获取主题及其帖子 ftpg
/edit_topic ❌403 Forbidden 编辑主题 fte
/edit_post ❌403 Forbidden 编辑帖子 fpe
/get_forum_listing 获取论坛列表 flg
/get_forum_and_topic 获取论坛及其主题 ftg

Home

API 支持 备注 示例名
/search 获取首页 search

Matches

API 支持 备注 示例名
/get_matches_listing 获取比赛列表 mlg
/get_match 获取比赛 mg

Multiplayer

API 支持 备注 示例名
/get_user_high_score ❌403 Forbidden 获取用户高分 muhsg
/get_scores 获取多个分数 mssg
/get_score ❌403 Forbidden 获取分数 msg
/get_multiplayer_rooms 获取房间 mrg

News

API 支持 备注 示例名
/get_news_listing 获取新闻列表 nlg
/get_news_post 获取新闻 npg

Notifications

API 支持 备注 示例名
/get_notifications ❌403 Forbidden 获取通知 ng
/mark_notifications_as_read ❌403 Forbidden 标为已读 nm

Rankings

API 支持 备注 示例名
/get_ranking 获取排行榜 rg
/get_kudosu_ranking 获取Kudosu排行榜 rkg
/get_spotlights 获取聚光灯 rsg

Scores

API 支持 备注 示例名
/get_scores 获取最多1000个成绩 scores

Users

API 支持 备注 示例名
/get_own_data 获取自己的用户信息(CCG) me
/get_user_kudosu 获取用户Kudosu ukg
/get_user_scores 获取用户分数 ussg
/get_user_beatmaps, /get_user_beatmaps_most_played 获取用户谱面信息 ubsg
/get_user_recent_activity 获取用户最近活动 urag
/get_user, /get_user_by_username 获取用户信息 ug
/get_users 获取多个用户信息 usg

Wiki

API 支持 备注 示例名
/get_wiki_page 获取Wiki页面 wiki

❤️ 鸣谢

最开始项目本来是打算直接用rosu-v2这个库的,但是由于当时看到rosu-v2已经就大几个月没更新了,并且项目组织和使用方式也不太习惯(可能是rosu-v2至今已经有四年历史的缘故,库里面有很多早期Rust代码,也不是很方便直接修改),所以就另起炉灶决定自己写一个了;

osynic_osuapi的开发过程中,还是参考了rosu-v2的接口设计(但并未沿用)和部分类型(比如u64和u32的选取),感谢rosu-v2的作者们!

rosu-v2项目基于MIT License,项目证书放置在licenses/LICENSE-rosu-v2

⚠️ 特别注意!!!

使用本库时,最常见的问题来源于osu!API官方实体结构的变动:

  • 实体结构变动:osu!API的结构可能会随时变化,但官方文档更新可能不及时
  • 返回字段变动:某些接口的返回字段可能会发生变化,尤其是较少使用的端点
  • 异常空值:某些字段可能在特定情况下返回null,但在文档中未标明为可选

这些问题的主要原因是osu!API官方文档对实体属性的描述不够全面。如果您在使用过程中遇到解析错误或类型不匹配等问题,请不要犹豫,直接提交Issue并附上:

  1. 使用的API端点
  2. 请求参数
  3. 错误信息或异常堆栈

我会尽快处理并更新库以适应API的变化。本库的大部分模型都是基于实际请求返回结果构建的,但仍可能存在遗漏或错误。您的反馈对完善本库至关重要!

🤝 贡献指南

这个库基本上只是为Osynic这个应用开发的一个模块,但是同时也是一个功能完整的osu!api的Rust封装;

目前,v1和v2的大部分(除了文档未归类的接口)已经实现,v2的WASM支持暂时还没有做。

这个库仍然在开发中,可能会有一些bug或者不完善的地方;

所以,如果代码有任何问题,或者你有任何建议,欢迎提交PR或者Issue,我会尽快处理~

如果你想贡献代码,请遵循以下规则:

  • 遵循Rust官方编码规范
  • 新增功能需附带测试用例
  • 提交前运行cargo fmtcargo clippy

📜 开源协议

本项目基于 MIT License 开源,请尊重原作者的著作权。

Dependencies

~2–14MB
~173K SLoC