@osynicite/osynic-osuapi
    Preparing search index...

    @osynicite/osynic-osuapi

    Logo逃走啦~

    OsynicOsuapi

    🚀 高性能 WebAssembly · 📦 开箱即用 · 🎯 浏览器原生支持
    功能完整的 osu! API 客户端库 WASM 绑定,为 Web 应用赋能

    🇨🇳 中文 · 🇺🇸 English


    📚 目录

    🧻 API体验网站

    OSUAPIV1CN.png

    ✨ 特性

    • 🌐 WASM 原生支持: 编译为 WebAssembly,在浏览器中以接近原生的速度运行
    • 📱 多框架支持: 支持 Vue、React、Svelte 等流行前端框架
    • 🔄 完整 API 支持: V1 和 V2 API 的所有主要端点(除文档未归类接口)
    • 🎨 TypeScript 友好: 完整的类型定义,提供最佳的开发体验
    • ⚡ 零配置: 通过 npm 安装即可使用,集成简单快速
    • 🌍 跨域处理: 内置 CORS 代理支持,处理浏览器跨域问题
    • 📊 轻量级: WASM 包体积优化,快速加载和初始化

    🚀 快速开始

    使用 npm、yarn 或 pnpm 安装:

    # npm
    npm install @osynicite/osynic-osuapi

    # yarn
    yarn add @osynicite/osynic-osuapi

    # pnpm
    pnpm add @osynicite/osynic-osuapi

    确保您的项目配置支持 WebAssembly:

    // vite.config.ts
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import wasm from 'vite-plugin-wasm'
    import topLevelAwait from 'vite-plugin-top-level-await'

    export default defineConfig({
    plugins: [
    wasm(),
    topLevelAwait(),
    vue(),
    ],
    })

    访问您的 osu! 设置页面,在以下位置申请相应的 API 授权:

    • V2 API: 在 "OAuth" 或 "开放授权" 部分申请
    • V1 API: 在 "Legacy API" 或 "旧版本 API" 部分申请

    📖 使用指南

    import { OsynicOsuApiV2GlooClient } from '@osynicite/osynic-osuapi'

    async function getUserInfo() {
    const client = new OsynicOsuApiV2GlooClient()
    client.set_proxy_url('YOUR_CORS_PROXY_URL') // You can see https://github.com/Islatri/deno_osynic_cors

    const token = await client.oauth.getTokenWithoutCode(
    'YOUR_CLIENT_ID_HERE',
    'YOUR_CLIENT_SECRET_HERE'
    )

    // 获取用户信息
    const user = await client.users.getUserByUsername('peppy')
    console.log(user)
    }

    getUserInfo().catch(console.error)

    这一部分应当在后端完成,以保护 client_secret 不被暴露在前端。服务端具体实现可以参考 osynic-oauth 项目,部署例程可见 OsynicOauth

    前端部分可以参照examples中的实现。

    import { OsynicOsuApiV1GlooClient } from '@osynicite/osynic-osuapi'

    async function getBeatmapInfo() {
    const client = new OsynicOsuApiV1GlooClient('YOUR_API_KEY_HERE')
    client.set_proxy_url('YOUR_CORS_PROXY_URL') // You can see https://github.com/Islatri/deno_osynic_cors

    // 通过哈希值查询谱面
    const beatmaps = await client.beatmap.getBeatmaps({
    hash: '69f77b0dfe67d288c1bf748f91ceb133'
    })

    console.log(beatmaps)
    }

    getBeatmapInfo().catch(console.error)
    <template>
    <div class="p-6 bg-gray-900 text-white min-h-screen">
    <div class="max-w-2xl mx-auto space-y-4">
    <div class="space-y-2">
    <input v-model="query.bid" type="text" placeholder="谱面ID"
    class="w-full px-3 py-2 bg-gray-800 rounded border border-gray-700" />
    <input v-model="query.sid" type="text" placeholder="谱面集ID"
    class="w-full px-3 py-2 bg-gray-800 rounded border border-gray-700" />
    <select v-model="query.mode" class="w-full px-3 py-2 bg-gray-800 rounded border border-gray-700">
    <option value="">所有模式</option>
    <option value="0">标准</option>
    <option value="1">太鼓</option>
    <option value="2">接水果</option>
    <option value="3">mania</option>
    </select>
    <button @click="search" :disabled="loading"
    class="w-full px-3 py-2 bg-blue-600 hover:bg-blue-700 rounded disabled:opacity-50">
    {{ loading ? '加载中...' : '搜索' }}
    </button>
    </div>
    <div v-if="error" class="text-red-400">{{ error }}</div>
    <div v-if="beatmaps.length" class="space-y-2">
    <div v-for="m in beatmaps" :key="m.beatmap_id" class="bg-gray-800 p-3 rounded text-sm">
    <div class="font-bold text-blue-300">{{ m.title }} [{{ m.version }}]</div>
    <div class="text-gray-400">★{{ parseFloat(m.difficultyrating).toFixed(2) }} | {{ m.artist }}</div>
    <div class="text-gray-500 text-xs mt-1">
    {{ formatTime(m.total_length) }} | BPM {{ parseInt(m.bpm) }} | {{ calcPassRate(m.playcount,
    m.passcount) }}% 通过率
    </div>
    </div>
    </div>
    </div>
    </div>
    </template>

    <script setup lang="ts">
    import { ref, reactive } from 'vue';
    import { OsynicOsuApiV1GlooClient } from '@osynicite/osynic-osuapi';

    const client = new OsynicOsuApiV1GlooClient("YOUR_API_KEY_HERE_AND_PLS_NOT_SHARE_IT_IN_YOUR_CONCRETE_PROJECT");
    client.setProxyUrl("YOUR_PROXY_URL_HERE_BECAUSE_CORS"); // You can see https://github.com/Islatri/deno_osynic_cors

    const query = reactive({ bid: '', sid: '', mode: '' });
    const beatmaps = ref([]);
    const loading = ref(false);
    const error = ref('');

    const search = async () => {
    loading.value = true;
    error.value = '';
    try {
    const params = Object.fromEntries(Object.entries(query).filter(([, v]) => v));
    beatmaps.value = await client.getBeatmaps(params).then(r => Array.isArray(r) ? r : [r]);
    } catch (err: any) {
    error.value = err?.message || '查询失败';
    } finally {
    loading.value = false;
    }
    };

    const formatTime = (s: string) => {
    const t = parseInt(s);
    return `${Math.floor(t / 60)}:${(t % 60).toString().padStart(2, '0')}`;
    };

    const calcPassRate = (p: string, pa: string) => ((parseInt(pa) / parseInt(p)) * 100).toFixed(1);
    </script>

    🎯 API 支持

    API 支持 说明
    /get_beatmaps 获取谱面
    /get_user 获取用户
    /get_user_best 获取用户最佳成绩
    /get_user_recent 获取用户最近成绩
    /get_match 获取比赛
    /get_scores 获取谱面成绩
    /get_replay 获取回放
    大类 支持情况 说明
    Authentication ✅ 4/4 OAuth 认证
    Beatmaps ✅ 10/10 谱面 API
    Beatmapsets ⚠️ 2/7(部分需授权) 谱面集 API
    Changelog ✅ 3/3 变更日志
    Comments ⚠️ 2/7(部分需授权) 评论 API
    Events ✅ 1/1 事件 API
    Forum ⚠️ 4/8(部分需授权) 论坛 API
    Matches ✅ 2/2 比赛 API
    News ✅ 2/2 新闻 API
    Rankings ✅ 3/3 排行榜 API
    Scores ✅ 1/1 成绩 API
    Users ✅ 7/7 用户 API
    Wiki ✅ 1/1 Wiki API
    Friends ✅ 2/2 好友 API

    更多详细信息请查看主项目的 API 检查表

    ⚡ 性能特性

    • 🚀 高性能: 相比 JavaScript 有显著的性能优势,特别是在处理复杂计算时
    • 💾 小包体积: 经过优化的 WASM 包比完整的 JavaScript 库更小
    • 🔄 无依赖: 不依赖其他 JavaScript 库,可以直接在任何项目中使用
    • 🌐 浏览器原生支持: 现代浏览器均支持 WebAssembly,无需额外配置

    🔧 集成示例

    本库提供完整的项目示例,位于 wasm/examples/ 目录下:

    • Vue 3 项目: 基于 Vue 3 + TypeScript + Vite 的完整示例
    • 功能演示:用户查询、谱面搜索、成绩查看等
    cd wasm/examples
    npm install
    npm run dev
    npm install @osynicite/osynic-osuapi
    

    然后在您的项目中:

    import { OsynicOsuApiV2Client } from '@osynicite/osynic-osuapi'

    const client = new OsynicOsuApiV2Client()
    client.set_proxy_url('YOUR_CORS_PROXY_URL') // You can see https://github.com/Islatri/deno_osynic_cors

    ⚠️ 特别注意

    由于浏览器的跨域政策限制,JavaScript 客户端无法直接访问 osu! API。本库暴露了set_proxy_url 方法,允许您设置一个 CORS 代理 URL 来绕过此限制。关于 CORS 代理服务器的搭建和使用,可以参考 deno_osynic_cors

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

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

    如果您在使用过程中遇到问题,请提交 Issue 并附上:

    1. 使用的 API 端点
    2. 请求参数
    3. 错误信息或网络响应
    4. 浏览器控制台输出

    A: 强烈建议在生产环境中使用后端代理或者V2的 Authorization Code Grant 方案,而不是直接在浏览器中暴露 client_secret

    A: 本库主要支持 ES 模块。如需使用 CommonJS,请确保您的构建工具支持 ESM to CJS 转换。

    A: 不建议在 Node.js 中使用 WASM 版本,因为 WASM 对 Node.js 的支持暂不完善,但可以通过 vite-plugin-wasmvite-plugin-top-level-await 等插件来在各大前端框架中使用。

    🤝 贡献指南

    我们欢迎贡献!如果您发现任何问题或有改进建议,请遵循以下规则:

    1. Fork 项目 - 在 GitHub 上 fork 该项目
    2. 创建分支 - git checkout -b feature/your-feature
    3. 提交更改 - git commit -am 'Add your feature'
    4. 推送到分支 - git push origin feature/your-feature
    5. 提交 Pull Request - 创建一个新的 Pull Request
    # 从项目根目录
    cd wasm

    # 构建 WASM 库
    wasm-pack build --release --target bundler --out-dir pkg --scope osynicite
    # 安装依赖
    npm install

    # 发布(维护者)
    npm publish
    • 遵循 Rust 官方编码规范
    • 新增功能需附带测试用例
    • 提交前运行 cargo fmtcargo clippy
    • 更新相关文档和示例

    📜 开源协议

    本项目基于 MIT License 开源。