MCPcopy Index your code
hub / github.com/cyperdark/osu-api-extended

github.com/cyperdark/osu-api-extended @v3.0.10

Chat with this repo
repository ↗ · DeepWiki ↗ · release v3.0.10 ↗ · + Follow
741 symbols 927 edges 168 files 0 documented · 0% updated 8d ago3.0.0 · 2024-10-06★ 62
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

osu-api-extended

Quick Links: Features ​ / ​ Usage ​ / ​ Install ​ / ​ Quickstart ​ / ​ Tools

Features

  • [x] Api
  • [x] osu api v1:
  • [x] osu api v2 (82+ api routes):
  • [x] Auto session refresh
  • [x] Does not require you to login for each action
  • [x] Built-in Tools
  • tools.build_url - Create link for user, score, editor_timing and others
  • tools.calculate_accuracy - Calculate accuracy from play hits
  • tools.calculate_hits - Calculate hits if play was an FC
  • tools.calculate_mods - Calculate mods Number/Name from Number/Name
  • tools.calculate_net_pp - Calculate how much pp would you gain from a play
  • tools.calculate_pp - Create link for user, score, editor_timing and others
  • tools.calculate_rank - Calculate rank from play hits
  • tools.calculate_total_passed_objects - Calculate total passed objects
  • tools.country_details - Get country name and code by providing country name/code
  • tools.download_beatmaps - Downloads a beatmap or beatmap set by given ID. (Supports different hosts)
  • See documentation
  • [x] Setting to prevent throw, instead send .error

Installation

npm i osu-api-extended
yarn install osu-api-extended
pnpm install osu-api-extended
bun install osu-api-extended

Quickstart

Links: create your client here ​ / ​ get your api key here

Quick Links: v2 - client auth ​ / ​ v2 - lazer auth ​ / ​ v2 - cli auth ​ / ​ v2 - Discord Verify ​ / ​ v2 - Website login ​ / ​ v1 usage ​ / ​ v2 - prevent throw errors

Client Auth

import { auth } from 'osu-api-extended';


async function main() {
  try {
    await auth.login({
      type: 'v2',
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      cachedTokenPath: './client.json' // path to the file your auth token will be saved (to prevent osu!api spam)
    });

    const result = await v2.users.details({ user: 'mrekk', mode: 'osu', key: '@' });
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};

main();

Lazer Auth

Authorization though your account

import { auth } from 'osu-api-extended';


async function main() {
  try {
    await auth.login({
      type: 'v2',
      login: LOGIN,
      password: PASSWORD,
      cachedTokenPath: './lazer.json' // path to the file your auth token will be saved (to prevent osu!api spam)
    });

    const result = await v2.me.details();
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};

main();

CLI Auth

import { auth } from 'osu-api-extended';


async function main() {
  try {
    await auth.login({
      type: 'cli',
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      redirect_url: REDIRECT_URL,
      scopes: ['public'],
      cachedTokenPath: './cli.json' // path to the file your auth token will be saved (to prevent osu!api spam)
    });

    const result = await v2.me.details();
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};

main();

Discord Verify

import { Client } from 'discord.js';
import { auth } from 'osu-api-extended';

const discord_bot = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages] }); // no clue why i need those intents


// send this link to user
discord_bot.on('messageCreate', async message => {
  if (message.author.bot) return;
  if (!message.content.startsWith('!')) return;

  const [command, value1, value2] = message.content.split('!').join('').split(' ');
  logger('command', { _c: 'yellowBright', v: command }, value1, value2);

  if (command == 'verify') {
    const url = const url = auth.build_url({
      client_id: CLIENT_ID,
      redirect_url: REDIRECT_URL,
      scopes: ['identify'],
      state: message.author.id
    });


    message.reply(`Verify via this link: ${url}`);
    return;
  };
});



// somewhere else verify this
function verifyUser(code, state) {
  // it returns user object
  const verify = await auth.authorize({
    code: code,
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    redirect_url: REDIRECT_URL
  });


  console.log(verify);
};

Website login

Nitro framework example

import { auth } from 'osu-api-extended';


// /auth page
export default defineEventHandler(event => {
  const build_url = auth.build_url({
    client_id: CLIENT_ID,
    redirect_uri: REDIRECT_URL,
    scopes: ['identify'],
  });


  return sendRedirect(event, build_url);
});


// /callback page
export default defineEventHandler(async event => {
  const { code } = getQuery(event);
  const verify = await auth.authorize({
    code: code.toString(),

    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    redirect_url: REDIRECT_URL,
  });


  setCookie(event, 'user_id', verify.id.toString());
  setCookie(event, 'user_name', verify.username.toString());

  setCookie(event, 'access_token', verify.access_token);
  setCookie(event, 'refresh_token', verify.refresh_token);


  return sendRedirect(event, '/');
});

V1 usage

import { auth, v1 } from 'osu-api-extended';


async function main() {
  try {
    auth.login({
      type: 'v1',
      api_key: API_KEY,
    });


    const beatmap = await v1.beatmap.diff(3798013);
    console.log(beatmap);

  } catch (error) {
    console.log(error);
  };
};

main();

Prevent throw errors

import { auth } from 'osu-api-extended';

auth.settings.throwErrors = false;


async function main() {
  try {
    await auth.login({
      type: 'v2',
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
    });

    const result = await v2.beatmaps.events.list({ types: ['approve'] });
    if (result.error instanceof Error) {
    // or
    if (result.error != null) {
      console.log(result.error);
      return;
    };

    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


main();

Tools

import { tools } from 'osu-api-extended';


function build_url() {
  try {
    const result = tools.build_url({ type: 'beatmap', value: 4397592 });
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function download_beatmaps() {
  try {
    const set_id = 320118;
    const progress_update = (...args) => {
      console.log(args);
    };


    const result = await tools.download_beatmaps({
      type: 'set',
      host: 'gatari',
      id: set_id,
      file_path: `./cache/${set_id}.osz`,
      progress_log_fn: progress_update
    });
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function calculate_accuracy() {
  try {
    const hits = { 300: 123, 100: 12, 50: 1, 0: 1 };
    const result = tools.calculate_accuracy(hits, 'osu');
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function calculate_mods() {
  try {
    const result = tools.calculate_mods('HDDT');
    // or
    const result = tools.calculate_mods(72);
    // or
    const result = tools.calculate_mods([{ acronym: "EZ" }]);
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function country_details() {
  try {
    const result = tools.country_details('US');
    // or
    const result = tools.country_details('United States');
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function calculate_rank() {
  try {
    const hits = { 300: 123, 100: 12, 50: 1, 0: 1 };
    const result = tools.calculate_rank(hits, 72, 'osu');
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function calculate_total_passed_objects() {
  try {
    const hits = { 300: 123, 100: 12, 50: 1, 0: 1 };
    const result = tools.calculate_total_passed_objects(hits, 'osu');
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function calculate_hits() {
  try {
    const hits = { 300: 123, 100: 12, 50: 1, 0: 1 };
    const result = tools.calculate_hits(hits, 'osu');
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};


function calculate_net_pp() {
  try {
    const plays = [1000, 900, 800, 700];
    const scores = [{ id: 123, pp: 1000 }, { id: 123, pp: 555 }, { id: 123, pp: 234 }, { id: 123, pp: 100 }];
    const result = tools.calculate_net_pp(plays, 400);
    // or 
    const result = tools.calculate_net_pp(scores, 400);
    if (result.error != null) {
      console.log(result.error);
      return;
    };


    console.log(result);
  } catch (error) {
    console.log(error);
  };
};

Dependencies

zero

Credits

Extension points exported contracts — how you extend this code

lazer_auth_response (Interface)
(no doc)
types/index.ts
ModsResponse (Interface)
(no doc)
types/tools.ts
EZ (Interface)
(no doc)
types/mods.ts
ForumsTopicsActionsEditPostResponse (Interface)
(no doc)
types/v2/forums_topics_actions_edit_post.ts
RequestType (Interface)
(no doc)
utility/request.ts
types (Interface)
(no doc)
api/v1/routes/match.ts
CountryResponse (Interface)
(no doc)
types/tools.ts
NF (Interface)
(no doc)
types/mods.ts

Core symbols most depended-on inside this repo

handleErrors
called by 215
utility/handleErrors.ts
request
called by 66
utility/request.ts
calculate_mods
called by 10
tools/mods.ts
parse
called by 7
api/v1/form/beatmap/creator.ts
parse
called by 7
api/v1/form/beatmap/category.ts
calculate_accuracy
called by 4
tools/accuracy.ts
download
called by 3
utility/request.ts
token_exists
called by 3
utility/auth.ts

Shape

Interface 633
Function 102
Enum 6

Languages

TypeScript100%

Modules by API surface

types/mods.ts57 symbols
types/v2/me_details.ts29 symbols
types/v2/users_details.ts20 symbols
types/v2/rooms_scores_user_highest.ts19 symbols
types/v2/rooms_scores_single.ts19 symbols
types/v2/users_list.ts18 symbols
types/v2/beatmaps_discussions_list.ts15 symbols
types/v2/matches_detaIls.ts14 symbols
types/v2/beatmaps_lookup_set.ts14 symbols
types/v2/beatmaps_events_list.ts14 symbols
types/v2/beatmaps_details_set.ts14 symbols
types/v2/search_all.ts13 symbols

For agents

$ claude mcp add osu-api-extended \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact