Don't duplicate code for each osu! ruleset/gamemode

This commit is contained in:
Taevas 2025-02-17 16:10:05 +01:00
parent 41d33ab964
commit 3424924762
10 changed files with 24 additions and 274 deletions

View file

@ -13,6 +13,6 @@ jobs:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- name: Install modules
run: bun
run: bun install
- name: Run ESLint
run: bun lint

View file

@ -4,7 +4,7 @@ import {type OsuInfo} from "../../src/components/Info/RhythmGames/Osu.js";
import {MongoClient} from "mongodb";
import {type Token} from "./osu_token.js";
const handler: Handler = async () => {
const handler: Handler = async (req) => {
const client = new MongoClient(process.env.URL_MONGODB!);
await client.connect();
@ -13,8 +13,9 @@ const handler: Handler = async () => {
const token = await collection.findOne();
void client.close();
const ruleset = Number(req.queryStringParameters?.ruleset);
const api = new osu.API({access_token: token?.access_token});
const profile = await api.getUser(7276846, osu.Ruleset.osu);
const profile = await api.getUser(7276846, !isNaN(ruleset) ? ruleset : undefined);
const info: OsuInfo = {
country: profile.country.name,

View file

@ -1,33 +0,0 @@
import {type Handler} from "@netlify/functions";
import * as osu from "osu-api-v2-js";
import {type FruitsInfo} from "../../src/components/Info/RhythmGames/OsuFruits.js";
import {MongoClient} from "mongodb";
import {type Token} from "./osu_token.js";
const handler: Handler = async () => {
const client = new MongoClient(process.env.URL_MONGODB!);
await client.connect();
const db = client.db("tokens");
const collection = db.collection<Token>("osu");
const token = await collection.findOne();
void client.close();
const api = new osu.API({access_token: token?.access_token});
const profile = await api.getUser(7276846, osu.Ruleset.fruits);
const info: FruitsInfo = {
country: profile.country.name,
ranks: {
global: profile.statistics.global_rank ?? 0,
country: profile.statistics.country_rank ?? 0,
},
};
return {
statusCode: 200,
body: JSON.stringify(info),
};
};
export {handler};

View file

@ -1,33 +0,0 @@
import {type Handler} from "@netlify/functions";
import * as osu from "osu-api-v2-js";
import {type ManiaInfo} from "../../src/components/Info/RhythmGames/OsuMania.js";
import {MongoClient} from "mongodb";
import {type Token} from "./osu_token.js";
const handler: Handler = async () => {
const client = new MongoClient(process.env.URL_MONGODB!);
await client.connect();
const db = client.db("tokens");
const collection = db.collection<Token>("osu");
const token = await collection.findOne();
void client.close();
const api = new osu.API({access_token: token?.access_token});
const profile = await api.getUser(7276846, osu.Ruleset.mania);
const info: ManiaInfo = {
country: profile.country.name,
ranks: {
global: profile.statistics.global_rank ?? 0,
country: profile.statistics.country_rank ?? 0,
},
};
return {
statusCode: 200,
body: JSON.stringify(info),
};
};
export {handler};

View file

@ -1,33 +0,0 @@
import {type Handler} from "@netlify/functions";
import * as osu from "osu-api-v2-js";
import {type TaikoInfo} from "../../src/components/Info/RhythmGames/OsuTaiko.js";
import {MongoClient} from "mongodb";
import {type Token} from "./osu_token.js";
const handler: Handler = async () => {
const client = new MongoClient(process.env.URL_MONGODB!);
await client.connect();
const db = client.db("tokens");
const collection = db.collection<Token>("osu");
const token = await collection.findOne();
void client.close();
const api = new osu.API({access_token: token?.access_token});
const profile = await api.getUser(7276846, osu.Ruleset.taiko);
const info: TaikoInfo = {
country: profile.country.name,
ranks: {
global: profile.statistics.global_rank ?? 0,
country: profile.statistics.country_rank ?? 0,
},
};
return {
statusCode: 200,
body: JSON.stringify(info),
};
};
export {handler};

View file

@ -2,9 +2,7 @@ import React, {useEffect, useState} from "react";
import Info from "../Info.js";
import Osu from "./RhythmGames/Osu.js";
import Taiko from "./RhythmGames/OsuTaiko.js";
import Fruits from "./RhythmGames/OsuFruits.js";
import Mania from "./RhythmGames/OsuMania.js";
import { Ruleset } from "osu-api-v2-js";
export default function RhythmGames() {
const [token, setToken] = useState(false);
@ -29,10 +27,10 @@ export default function RhythmGames() {
useEffect(() => {
if (token) {
const osu = <Osu key={"osu"}/>;
const taiko = <Taiko key={"taiko"}/>;
const fruits = <Fruits key={"fruits"}/>;
const mania = <Mania key={"mania"}/>;
const osu = <Osu ruleset={Ruleset.osu} key={"osu"}/>;
const taiko = <Osu ruleset={Ruleset.taiko} key={"taiko"}/>;
const fruits = <Osu ruleset={Ruleset.fruits} key={"fruits"}/>;
const mania = <Osu ruleset={Ruleset.mania} key={"mania"}/>;
setWebsites([osu, taiko, fruits, mania]);
}
}, [token]);

View file

@ -1,5 +1,6 @@
import React, {useState, useEffect} from "react";
import Website from "../../Website.js";
import { Ruleset } from "osu-api-v2-js";
export type OsuInfo = {
country: string;
@ -9,13 +10,21 @@ export type OsuInfo = {
};
} | undefined;
export default function Osu() {
export default function Osu(args: {ruleset: Ruleset}) {
const [osu, setOsu]: [OsuInfo, React.Dispatch<React.SetStateAction<OsuInfo>>] = useState();
const [elements, setElements] = useState([] as React.JSX.Element[]);
const [error, setError] = useState(false);
const ruleset = Ruleset[args.ruleset];
let name = ruleset;
if (name === "osu") {
name = "";
} else if (name === "fruits") {
name = "catch";
}
const getOsu = async () => {
setOsu(await fetch("/.netlify/functions/osu_osu").then(async r => r.json()));
setOsu(await fetch(`/.netlify/functions/osu?ruleset=${args.ruleset}`).then(async r => r.json()));
};
useEffect(() => {
@ -28,8 +37,8 @@ export default function Osu() {
if (osu) {
try {
setElements([
<div key={"osu"} className="flex">
<img className="m-auto w-16 h-16" alt="osu mode logo" src="/mode-osu.png"/>
<div key={`osu-${ruleset}`} className="flex">
<img className="m-auto w-16 h-16" alt={`${ruleset} mode logo`} src={`/mode-${ruleset}.png`}/>
<div className="m-auto">
<p>Global: <strong>#{osu.ranks.global}</strong></p>
<p>{osu.country}: <strong>#{osu.ranks.country}</strong></p>
@ -44,8 +53,8 @@ export default function Osu() {
return (
<Website
name="osu!"
link="https://osu.ppy.sh/users/7276846/osu"
name={`osu!${name}`}
link={`https://osu.ppy.sh/users/7276846/${ruleset}`}
elements={elements}
error={error}
/>

View file

@ -1,53 +0,0 @@
import React, {useState, useEffect} from "react";
import Website from "../../Website.js";
export type FruitsInfo = {
country: string;
ranks: {
global: number;
country: number;
};
} | undefined;
export default function Fruits() {
const [fruits, setFruits]: [FruitsInfo, React.Dispatch<React.SetStateAction<FruitsInfo>>] = useState();
const [elements, setElements] = useState([] as React.JSX.Element[]);
const [error, setError] = useState(false);
const getFruits = async () => {
setFruits(await fetch("/.netlify/functions/osu_fruits").then(async r => r.json()));
};
useEffect(() => {
getFruits().catch(() => {
setError(true);
});
}, []);
useEffect(() => {
if (fruits) {
try {
setElements([
<div key={"fruits"} className="flex">
<img className="m-auto w-16 h-16" alt="fruits mode logo" src="/mode-fruits.png"/>
<div className="m-auto">
<p>Global: <strong>#{fruits.ranks.global}</strong></p>
<p>{fruits.country}: <strong>#{fruits.ranks.country}</strong></p>
</div>
</div>,
]);
} catch {
setError(true);
}
}
}, [fruits]);
return (
<Website
name="osu!catch"
link="https://osu.ppy.sh/users/7276846/fruits"
elements={elements}
error={error}
/>
);
}

View file

@ -1,53 +0,0 @@
import React, {useState, useEffect} from "react";
import Website from "../../Website.js";
export type ManiaInfo = {
country: string;
ranks: {
global: number;
country: number;
};
} | undefined;
export default function Mania() {
const [mania, setMania]: [ManiaInfo, React.Dispatch<React.SetStateAction<ManiaInfo>>] = useState();
const [elements, setElements] = useState([] as React.JSX.Element[]);
const [error, setError] = useState(false);
const getMania = async () => {
setMania(await fetch("/.netlify/functions/osu_mania").then(async r => r.json()));
};
useEffect(() => {
getMania().catch(() => {
setError(true);
});
}, []);
useEffect(() => {
if (mania) {
try {
setElements([
<div key={"mania"} className="flex">
<img className="m-auto w-16 h-16" alt="mania mode logo" src="/mode-mania.png"/>
<div className="m-auto">
<p>Global: <strong>#{mania.ranks.global}</strong></p>
<p>{mania.country}: <strong>#{mania.ranks.country}</strong></p>
</div>
</div>,
]);
} catch {
setError(true);
}
}
}, [mania]);
return (
<Website
name="osu!mania"
link="https://osu.ppy.sh/users/7276846/mania"
elements={elements}
error={error}
/>
);
}

View file

@ -1,53 +0,0 @@
import React, {useState, useEffect} from "react";
import Website from "../../Website.js";
export type TaikoInfo = {
country: string;
ranks: {
global: number;
country: number;
};
} | undefined;
export default function Taiko() {
const [taiko, setTaiko]: [TaikoInfo, React.Dispatch<React.SetStateAction<TaikoInfo>>] = useState();
const [elements, setElements] = useState([] as React.JSX.Element[]);
const [error, setError] = useState(false);
const getTaiko = async () => {
setTaiko(await fetch("/.netlify/functions/osu_taiko").then(async r => r.json()));
};
useEffect(() => {
getTaiko().catch(() => {
setError(true);
});
}, []);
useEffect(() => {
if (taiko) {
try {
setElements([
<div key={"taiko"} className="flex">
<img className="m-auto w-16 h-16" alt="taiko mode logo" src="/mode-taiko.png"/>
<div className="m-auto">
<p>Global: <strong>#{taiko.ranks.global}</strong></p>
<p>{taiko.country}: <strong>#{taiko.ranks.country}</strong></p>
</div>
</div>,
]);
} catch {
setError(true);
}
}
}, [taiko]);
return (
<Website
name="osu!taiko"
link="https://osu.ppy.sh/users/7276846/taiko"
elements={elements}
error={error}
/>
);
}