From 3728614109f704d45fe4bf0334d0db92aadbc8da Mon Sep 17 00:00:00 2001 From: Taevas Date: Thu, 3 Apr 2025 15:16:59 +0200 Subject: [PATCH] Split the API logic --- api/index.ts | 40 ++++++++++++++++++ .../coding/github.ts} | 8 ++-- .../coding/gitlab.ts} | 4 +- .../coding/kitsudev.ts} | 9 ++-- .../fediverse/kitsuclub.ts} | 9 ++-- api/{gaming_osu.ts => infos/gaming/osu.ts} | 14 +++--- .../gaming/speedruncom.ts} | 13 ++++-- .../hacking/hackthebox.ts} | 9 ++-- .../japanese/wanikani.ts} | 4 +- .../media/anilist.ts} | 9 ++-- .../media/lastfm.ts} | 9 ++-- api/{ => infos}/token.ts | 2 +- .../website/umami.ts} | 6 +-- bun.lockb | Bin 230370 -> 230015 bytes database.ts | 2 +- index.ts | 36 +--------------- package.json | 12 +++--- src/Infos/Coding/GitHub.tsx | 4 +- src/Infos/Coding/GitLab.tsx | 4 +- src/Infos/Coding/KitsuDev.tsx | 4 +- src/Infos/Fediverse/KitsuClub.tsx | 4 +- src/Infos/Gaming/Osu.tsx | 4 +- src/Infos/Gaming/Speedruncom.tsx | 4 +- src/Infos/Gaming/index.tsx | 4 +- src/Infos/Hacking/Hackthebox.tsx | 4 +- src/Infos/Japanese/Wanikani.tsx | 6 +-- src/Infos/Media/Anilist.tsx | 4 +- src/Infos/Media/Lastfm.tsx | 4 +- src/Infos/Website/Umami.tsx | 4 +- src/Infos/Website/index.tsx | 4 +- src/{Infos => parts}/DataHandler.tsx | 0 31 files changed, 137 insertions(+), 103 deletions(-) create mode 100644 api/index.ts rename api/{coding_github.ts => infos/coding/github.ts} (86%) rename api/{coding_gitlab.ts => infos/coding/gitlab.ts} (85%) rename api/{coding_kitsudev.ts => infos/coding/kitsudev.ts} (52%) rename api/{fediverse_kitsuclub.ts => infos/fediverse/kitsuclub.ts} (92%) rename api/{gaming_osu.ts => infos/gaming/osu.ts} (58%) rename api/{gaming_speedruncom.ts => infos/gaming/speedruncom.ts} (80%) rename api/{hacking_hackthebox.ts => infos/hacking/hackthebox.ts} (59%) rename api/{japanese_wanikani.ts => infos/japanese/wanikani.ts} (97%) rename api/{media_anilist.ts => infos/media/anilist.ts} (89%) rename api/{media_lastfm.ts => infos/media/lastfm.ts} (78%) rename api/{ => infos}/token.ts (97%) rename api/{website_umami.ts => infos/website/umami.ts} (89%) rename src/{Infos => parts}/DataHandler.tsx (100%) diff --git a/api/index.ts b/api/index.ts new file mode 100644 index 0000000..9d8e958 --- /dev/null +++ b/api/index.ts @@ -0,0 +1,40 @@ +import { token } from "./infos/token"; +import { github } from "./infos/coding/github"; +import { gitlab } from "./infos/coding/gitlab"; +import { kitsudev } from "./infos/coding/kitsudev"; +import { kitsuclub } from "./infos/fediverse/kitsuclub"; +import { osu } from "./infos/gaming/osu"; +import { speedruncom } from "./infos/gaming/speedruncom"; +import { hackthebox } from "./infos/hacking/hackthebox"; +import { wanikani } from "./infos/japanese/wanikani"; +import { anilist } from "./infos/media/anilist"; +import { lastfm } from "./infos/media/lastfm"; +import { umami } from "./infos/website/umami"; + +const info_routes: Record = { + coding: [github, gitlab, kitsudev], + fediverse: [kitsuclub], + gaming: [osu, speedruncom], + hacking: [hackthebox], + japanese: [wanikani], + media: [anilist, lastfm], + website: [umami], +}; + +export type Handler = (req: URLSearchParams) => Promise; + +export async function api(pathname: string, parameters: URLSearchParams) { + if (pathname === "/api/infos/token") { + return await token(parameters); + } + + for (const route of Object.keys(info_routes)) { + for (const endpoint of info_routes[route]) { + if (pathname === "/api/infos/" + route + "/" + endpoint.name) { + return await endpoint(parameters); + } + } + } + + return new Response("Not Found", {status: 404}); +} diff --git a/api/coding_github.ts b/api/infos/coding/github.ts similarity index 86% rename from api/coding_github.ts rename to api/infos/coding/github.ts index 2341da5..cd1c648 100644 --- a/api/coding_github.ts +++ b/api/infos/coding/github.ts @@ -1,10 +1,12 @@ import {Octokit} from "@octokit/rest"; import {type GithubInfo} from "#Infos/Coding/GitHub.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const coding_github: Handler = async () => { +const username = "TTTaevas"; + +export const github: Handler = async () => { const octokit = new Octokit({auth: process.env["API_GITHUB"]}); - const github = await octokit.rest.activity.listEventsForAuthenticatedUser({username: "TTTaevas"}); + const github = await octokit.rest.activity.listEventsForAuthenticatedUser({username}); const publicPush = github.data.find((e) => (e.type === "PushEvent" || e.type === "PullRequestEvent") && e.public); const privatePush = github.data.find((e) => (e.type === "PushEvent" || e.type === "PullRequestEvent") && !e.public); diff --git a/api/coding_gitlab.ts b/api/infos/coding/gitlab.ts similarity index 85% rename from api/coding_gitlab.ts rename to api/infos/coding/gitlab.ts index ebf00d3..58f9a14 100644 --- a/api/coding_gitlab.ts +++ b/api/infos/coding/gitlab.ts @@ -1,8 +1,8 @@ import { Gitlab } from "@gitbeaker/rest"; import {type GitlabInfo} from "#Infos/Coding/GitLab.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const coding_gitlab: Handler = async () => { +export const gitlab: Handler = async () => { const api = new Gitlab({token: process.env["API_GITLAB"]!}); const gitlab = await api.Events.all({action: "pushed"}); diff --git a/api/coding_kitsudev.ts b/api/infos/coding/kitsudev.ts similarity index 52% rename from api/coding_kitsudev.ts rename to api/infos/coding/kitsudev.ts index e67fe9c..2bcfd38 100644 --- a/api/coding_kitsudev.ts +++ b/api/infos/coding/kitsudev.ts @@ -1,8 +1,11 @@ import { type KitsudevInfo } from "#Infos/Coding/KitsuDev.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const coding_kitsudev: Handler = async () => { - const kitsudev = await (await fetch("https://kitsunes.dev/api/v1/users/Taevas/activities/feeds?limit=1")).json() as [{ +const username = "Taevas"; + +export const kitsudev: Handler = async () => { + /** https://kitsunes.dev/api/swagger#/user/userListActivityFeeds */ + const kitsudev = await (await fetch(`https://kitsunes.dev/api/v1/users/${username}/activities/feeds?limit=1`)).json() as [{ repo: { full_name: string html_url: string diff --git a/api/fediverse_kitsuclub.ts b/api/infos/fediverse/kitsuclub.ts similarity index 92% rename from api/fediverse_kitsuclub.ts rename to api/infos/fediverse/kitsuclub.ts index 8f0b066..a192aed 100644 --- a/api/fediverse_kitsuclub.ts +++ b/api/infos/fediverse/kitsuclub.ts @@ -1,7 +1,10 @@ import { type KitsuclubInfo } from "#Infos/Fediverse/KitsuClub.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const fediverse_kitsuclub: Handler = async () => { +const user_id = "a2hgd7delf"; + +export const kitsuclub: Handler = async () => { + /** https://kitsunes.club/api-doc#tag/users/POST/users/notes */ const kitsuclub = await (await fetch("https://kitsunes.club/api/users/notes", { method: "POST", headers: { @@ -9,7 +12,7 @@ export const fediverse_kitsuclub: Handler = async () => { "Content-Type": "application/json", }, body: JSON.stringify({ - "userId": "a2hgd7delf", + "userId": user_id, "limit": 1, "withReplies": false, "withRepliesToSelf": false, diff --git a/api/gaming_osu.ts b/api/infos/gaming/osu.ts similarity index 58% rename from api/gaming_osu.ts rename to api/infos/gaming/osu.ts index 1eb3b4b..c518a39 100644 --- a/api/gaming_osu.ts +++ b/api/infos/gaming/osu.ts @@ -1,15 +1,17 @@ -import * as osu from "osu-api-v2-js"; +import * as osuv2 from "osu-api-v2-js"; import {type OsuInfo} from "#Infos/Gaming/Osu.tsx"; -import type { Handler } from "../index.ts"; -import { db, getToken } from "../database.ts"; +import type { Handler } from "../../index.ts"; +import { db, getToken } from "../../../database.ts"; -export const gaming_osu: Handler = async (params) => { +const user_id = 7276846; + +export const osu: Handler = async (params) => { const token = await getToken(db, "osu"); let ruleset = params.has("ruleset") ? Number(params.get("ruleset")) : undefined; if (ruleset && isNaN(ruleset)) {ruleset = undefined;} - const api = new osu.API({access_token: token?.access_token}); - const profile = await api.getUser(7276846, ruleset); + const api = new osuv2.API({access_token: token?.access_token}); + const profile = await api.getUser(user_id, ruleset); const info: OsuInfo = { country: profile.country.name, diff --git a/api/gaming_speedruncom.ts b/api/infos/gaming/speedruncom.ts similarity index 80% rename from api/gaming_speedruncom.ts rename to api/infos/gaming/speedruncom.ts index 01be70d..558f53d 100644 --- a/api/gaming_speedruncom.ts +++ b/api/infos/gaming/speedruncom.ts @@ -1,5 +1,7 @@ import {type SpeedruncomInfo} from "#Infos/Gaming/Speedruncom.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; + +const user_id = "j03v45mj"; interface Runs { data: { @@ -41,17 +43,22 @@ interface Level { }; } -export const gaming_speedruncom: Handler = async () => { +export const speedruncom: Handler = async () => { // using the API's embedding would be stupid here, as that'd create lag due to irrelevant runs - const speedruncom = await (await fetch("https://www.speedrun.com/api/v1/users/j03v45mj/personal-bests")).json() as Runs; + + /** https://github.com/speedruncomorg/api/blob/master/version1/users.md#get-usersidpersonal-bests */ + const speedruncom = await (await fetch(`https://www.speedrun.com/api/v1/users/${user_id}/personal-bests`)).json() as Runs; const data = speedruncom.data.at(0); if (!data) { return new Response("Not Found", {status: 404}); } + /** https://github.com/speedruncomorg/api/blob/master/version1/games.md#get-gamesid */ const urlsToRequest = [`https://www.speedrun.com/api/v1/games/${data.run.game}`]; + /** https://github.com/speedruncomorg/api/blob/master/version1/levels.md#get-levelsid */ if (data.run.level) {urlsToRequest.push(`https://www.speedrun.com/api/v1/levels/${data.run.level}`);} + /** https://github.com/speedruncomorg/api/blob/master/version1/categories.md */ if (data.run.category) {urlsToRequest.push(`https://www.speedrun.com/api/v1/categories/${data.run.category}`);} const toRequest = urlsToRequest.map((url) => new Promise(async (resolve) => resolve(await (await fetch(url)).json()))); diff --git a/api/hacking_hackthebox.ts b/api/infos/hacking/hackthebox.ts similarity index 59% rename from api/hacking_hackthebox.ts rename to api/infos/hacking/hackthebox.ts index b995321..c9a8e85 100644 --- a/api/hacking_hackthebox.ts +++ b/api/infos/hacking/hackthebox.ts @@ -1,8 +1,11 @@ import {type HacktheboxInfo} from "#Infos/Hacking/Hackthebox.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const hacking_hackthebox: Handler = async () => { - const hackthebox = await (await fetch("https://www.hackthebox.com/api/v4/profile/activity/1063999")).json() as { +const user_id = 1063999; + +export const hackthebox: Handler = async () => { + /** https://documenter.getpostman.com/view/13129365/TVeqbmeq#1b0b22fc-2e45-456a-9a8f-42888375d1a9 */ + const hackthebox = await (await fetch(`https://www.hackthebox.com/api/v4/profile/activity/${user_id}`)).json() as { profile: { activity: HacktheboxInfo[]; }; diff --git a/api/japanese_wanikani.ts b/api/infos/japanese/wanikani.ts similarity index 97% rename from api/japanese_wanikani.ts rename to api/infos/japanese/wanikani.ts index 1ce1eb5..8897490 100644 --- a/api/japanese_wanikani.ts +++ b/api/infos/japanese/wanikani.ts @@ -1,6 +1,6 @@ import {type WanikaniInfo} from "#Infos/Japanese/Wanikani.tsx"; import type { WKLevelProgression, WKResetCollection, WKSummary } from "@bachmacintosh/wanikani-api-types"; -import type { Handler } from ".."; +import type { Handler } from "../.."; interface Subject { id: number; @@ -48,7 +48,7 @@ function addStuffToLearn(ids: number[], data: {available_at: string; subject_ids return arr; } -export const japanese_wanikani: Handler = async () => { +export const wanikani: Handler = async () => { const urlsToRequest = [ "https://api.wanikani.com/v2/level_progressions", "https://api.wanikani.com/v2/resets", diff --git a/api/media_anilist.ts b/api/infos/media/anilist.ts similarity index 89% rename from api/media_anilist.ts rename to api/infos/media/anilist.ts index 01bce26..9d561f7 100644 --- a/api/media_anilist.ts +++ b/api/infos/media/anilist.ts @@ -1,7 +1,10 @@ import {type AnilistInfo} from "#Infos/Media/Anilist.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const media_anilist: Handler = async () => { +const username = "Taevas"; + +export const anilist: Handler = async () => { + /** https://github.com/AniList/ApiV2-GraphQL-Docs/blob/master/docs/reference/query.md */ const anilist = await fetch("https://graphql.anilist.co", { method: "POST", headers: { @@ -39,7 +42,7 @@ export const media_anilist: Handler = async () => { } `, variables: { - userName: "Taevas", + userName: username, }, }), }); diff --git a/api/media_lastfm.ts b/api/infos/media/lastfm.ts similarity index 78% rename from api/media_lastfm.ts rename to api/infos/media/lastfm.ts index 2c6a826..d12e277 100644 --- a/api/media_lastfm.ts +++ b/api/infos/media/lastfm.ts @@ -1,8 +1,11 @@ import {type LastfmInfo} from "#Infos/Media/Lastfm.tsx"; -import type { Handler } from ".."; +import type { Handler } from "../.."; -export const media_lastfm: Handler = async () => { - const lastfm = await (await fetch(`https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=TTTaevas&api_key=${process.env["API_LASTFM"]}&format=json&limit=1`)).json() as { +const username = "TTTaevas"; + +export const lastfm: Handler = async () => { + /** https://www.last.fm/api/show/user.getRecentTracks */ + const lastfm = await (await fetch(`https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=${username}&api_key=${process.env["API_LASTFM"]}&format=json&limit=1`)).json() as { recenttracks: { track: { artist: { diff --git a/api/token.ts b/api/infos/token.ts similarity index 97% rename from api/token.ts rename to api/infos/token.ts index 8b61c2f..5709081 100644 --- a/api/token.ts +++ b/api/infos/token.ts @@ -1,4 +1,4 @@ -import { addToken, createTables, db, getToken, removeExpiredTokens } from "../database"; +import { addToken, createTables, db, getToken, removeExpiredTokens } from "../../database"; import {API} from "osu-api-v2-js"; import type { Handler } from ".."; diff --git a/api/website_umami.ts b/api/infos/website/umami.ts similarity index 89% rename from api/website_umami.ts rename to api/infos/website/umami.ts index 38595f4..8a1e26f 100644 --- a/api/website_umami.ts +++ b/api/infos/website/umami.ts @@ -1,8 +1,8 @@ -import type { Handler } from "../index.ts"; +import type { Handler } from "../.."; import type { UmamiInfo } from "#Infos/Website/Umami.tsx"; -import { db, getToken } from "../database.ts"; +import { db, getToken } from "../../../database.ts"; -export const website_umami: Handler = async () => { +export const umami: Handler = async () => { const token = await getToken(db, "umami"); const api_server = "https://visitors.taevas.xyz/api"; diff --git a/bun.lockb b/bun.lockb index 2eeb5ec54c6ec78fbfe091ae1d90a32a1245da5c..eab4dc4b84642f58b7a84fcdb1873fafbdba6635 100755 GIT binary patch delta 20441 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 Promise; - -const api_endpoints: Handler[] = [ - coding_github, - coding_gitlab, - coding_kitsudev, - fediverse_kitsuclub, - gaming_osu, - gaming_speedruncom, - hacking_hackthebox, - japanese_wanikani, - media_anilist, - media_lastfm, - token, - website_umami -]; - const servers: Server[] = ports.map((port) => Bun.serve({ idleTimeout: 30, tls: port !== 80 ? tls : undefined, @@ -92,11 +64,7 @@ const servers: Server[] = ports.map((port) => Bun.serve({ // API if (pathname.startsWith("/api")) { - for (const endpoint of api_endpoints) { - if (pathname === "/api/" + endpoint.name) { - return await endpoint(parameters); - } - } + return await api(pathname, parameters); } return new Response("Not Found", {status: 404}); diff --git a/package.json b/package.json index 1ffb6c0..cf94724 100644 --- a/package.json +++ b/package.json @@ -21,20 +21,20 @@ "@eslint/js": "^9.23.0", "@stylistic/eslint-plugin": "^3.1.0", "@tailwindcss/forms": "^0.5.10", - "@tailwindcss/postcss": "^4.0.17", + "@tailwindcss/postcss": "^4.1.1", "@types/bun": "^1.2.8", - "@types/react": "^19.0.12", - "@types/react-dom": "^19.0.4", + "@types/react": "^19.1.0", + "@types/react-dom": "^19.1.1", "dotenv": "^16.4.7", "eslint": "^9.23.0", "eslint-config-xo-typescript": "^7.0.0", "eslint-plugin-react": "^7.37.4", "postcss": "^8.5.3", "react-animate-height": "^3.2.3", - "tailwindcss": "^4.0.17", + "tailwindcss": "^4.1.1", "typescript": "^5.8.2", - "typescript-eslint": "^8.28.0", - "vite": "^6.2.3" + "typescript-eslint": "^8.29.0", + "vite": "^6.2.5" }, "imports": { "#Main/*": "./src/Main/*", diff --git a/src/Infos/Coding/GitHub.tsx b/src/Infos/Coding/GitHub.tsx index c09dcf1..4e9543b 100644 --- a/src/Infos/Coding/GitHub.tsx +++ b/src/Infos/Coding/GitHub.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; import Link from "#parts/Link.tsx"; export interface GithubInfo { @@ -14,7 +14,7 @@ export interface GithubInfo { } export default function GitHub() { - const {data, error, setError} = DataHandler("coding_github", 60 * 20); + const {data, error, setError} = DataHandler("infos/coding/github", 60 * 20); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Coding/GitLab.tsx b/src/Infos/Coding/GitLab.tsx index 08b641d..ac1e958 100644 --- a/src/Infos/Coding/GitLab.tsx +++ b/src/Infos/Coding/GitLab.tsx @@ -1,13 +1,13 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; export type GitlabInfo = { date: string; } | undefined; export default function GitLab() { - const {data, error, setError} = DataHandler("coding_gitlab", 60 * 20); + const {data, error, setError} = DataHandler("infos/coding/gitlab", 60 * 20); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Coding/KitsuDev.tsx b/src/Infos/Coding/KitsuDev.tsx index 8a9b68e..17390a9 100644 --- a/src/Infos/Coding/KitsuDev.tsx +++ b/src/Infos/Coding/KitsuDev.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; import Link from "#parts/Link.tsx"; export type KitsudevInfo = { @@ -10,7 +10,7 @@ export type KitsudevInfo = { } | undefined; export default function KitsuDev() { - const {data, error, setError} = DataHandler("coding_kitsudev", 60 * 20); + const {data, error, setError} = DataHandler("infos/coding/kitsudev", 60 * 20); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Fediverse/KitsuClub.tsx b/src/Infos/Fediverse/KitsuClub.tsx index 3f69c3e..f1ff996 100644 --- a/src/Infos/Fediverse/KitsuClub.tsx +++ b/src/Infos/Fediverse/KitsuClub.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; import Link from "#parts/Link.tsx"; export type KitsuclubInfo = { @@ -18,7 +18,7 @@ export type KitsuclubInfo = { } | undefined; export default function KitsuClub() { - const {data, error, setError} = DataHandler("fediverse_kitsuclub", 60 * 20); + const {data, error, setError} = DataHandler("infos/fediverse/kitsuclub", 60 * 20); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Gaming/Osu.tsx b/src/Infos/Gaming/Osu.tsx index ce1e897..d711386 100644 --- a/src/Infos/Gaming/Osu.tsx +++ b/src/Infos/Gaming/Osu.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; import { Ruleset } from "osu-api-v2-js"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; export type OsuInfo = { country: string; @@ -12,7 +12,7 @@ export type OsuInfo = { } | undefined; export default function Osu(args: {ruleset: Ruleset}) { - const {data, error, setError} = DataHandler(`gaming_osu?ruleset=${args.ruleset}`, 60 * 45); + const {data, error, setError} = DataHandler(`infos/gaming/osu?ruleset=${args.ruleset}`, 60 * 45); const [elements, setElements] = useState([] as React.JSX.Element[]); const ruleset = Ruleset[args.ruleset]; diff --git a/src/Infos/Gaming/Speedruncom.tsx b/src/Infos/Gaming/Speedruncom.tsx index 8e4c6c7..d4cf766 100644 --- a/src/Infos/Gaming/Speedruncom.tsx +++ b/src/Infos/Gaming/Speedruncom.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; import Link from "#parts/Link.tsx"; import ButtonLink from "#parts/ButtonLink.tsx"; @@ -16,7 +16,7 @@ export type SpeedruncomInfo = { } | undefined; export default function Speedruncom() { - const {data, error, setError} = DataHandler("gaming_speedruncom", 60 * 60); + const {data, error, setError} = DataHandler("infos/gaming/speedruncom", 60 * 60); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Gaming/index.tsx b/src/Infos/Gaming/index.tsx index 4b9c18f..348a2aa 100644 --- a/src/Infos/Gaming/index.tsx +++ b/src/Infos/Gaming/index.tsx @@ -4,10 +4,10 @@ import Info from "../Info.tsx"; import Speedruncom from "./Speedruncom.tsx"; // import Osu from "./Osu.tsx"; // import { Ruleset } from "osu-api-v2-js"; -// import DataHandler from "#Infos/DataHandler.tsx"; +// import DataHandler from "#parts/DataHandler.tsx"; export default function RhythmGames() { -// const {data, error} = DataHandler("token?service=osu", 60 * 60 * 8, false); +// const {data, error} = DataHandler("infos/token?service=osu", 60 * 60 * 8, false); const [websites, setWebsites] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Hacking/Hackthebox.tsx b/src/Infos/Hacking/Hackthebox.tsx index 7fac489..3375b2a 100644 --- a/src/Infos/Hacking/Hackthebox.tsx +++ b/src/Infos/Hacking/Hackthebox.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; import ButtonLink from "#parts/ButtonLink.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; export type HacktheboxInfo = { id: string; @@ -14,7 +14,7 @@ export type HacktheboxInfo = { } | undefined; export default function Hackthebox() { - const {data, error, setError} = DataHandler("hacking_hackthebox", 60 * 60); + const {data, error, setError} = DataHandler("infos/hacking/hackthebox", 60 * 60); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Japanese/Wanikani.tsx b/src/Infos/Japanese/Wanikani.tsx index ea9bf3c..7fc42f1 100644 --- a/src/Infos/Japanese/Wanikani.tsx +++ b/src/Infos/Japanese/Wanikani.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import { WKLevelProgression, WKReset } from "@bachmacintosh/wanikani-api-types"; -import DataHandler from "#Infos/DataHandler.tsx"; +import type { WKLevelProgression, WKReset } from "@bachmacintosh/wanikani-api-types"; +import DataHandler from "#parts/DataHandler.tsx"; export type WanikaniInfo = { progression: { @@ -37,7 +37,7 @@ function Button(item: Item) { } export default function Wanikani() { - const {data, error, setError} = DataHandler("japanese_wanikani", 60 * 60); + const {data, error, setError} = DataHandler("infos/japanese/wanikani", 60 * 60); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Media/Anilist.tsx b/src/Infos/Media/Anilist.tsx index 97c1dd7..a609100 100644 --- a/src/Infos/Media/Anilist.tsx +++ b/src/Infos/Media/Anilist.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; import Link from "#parts/Link.tsx"; export type AnilistInfo = { @@ -18,7 +18,7 @@ export type AnilistInfo = { } | undefined; export default function Anilist() { - const {data, error, setError} = DataHandler("media_anilist", 60 * 30); + const {data, error, setError} = DataHandler("infos/media/anilist", 60 * 30); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Media/Lastfm.tsx b/src/Infos/Media/Lastfm.tsx index 890c221..cf94c52 100644 --- a/src/Infos/Media/Lastfm.tsx +++ b/src/Infos/Media/Lastfm.tsx @@ -2,7 +2,7 @@ import React, {useState, useEffect} from "react"; import {format} from "timeago.js"; import Website from "../Website.tsx"; import Link from "#parts/Link.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; export type LastfmInfo = { artist: string; @@ -15,7 +15,7 @@ export type LastfmInfo = { } | undefined; export default function Lastfm() { - const {data, error, setError} = DataHandler("media_lastfm", 60 * 2); + const {data, error, setError} = DataHandler("infos/media/lastfm", 60 * 2); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Website/Umami.tsx b/src/Infos/Website/Umami.tsx index da744a0..66e7a4f 100644 --- a/src/Infos/Website/Umami.tsx +++ b/src/Infos/Website/Umami.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import Website from "../Website.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; export type UmamiInfo = { pageviews: number @@ -10,7 +10,7 @@ export type UmamiInfo = { } | undefined; export default function Umami() { - const {data, error, setError} = DataHandler("website_umami", 60 * 5); + const {data, error, setError} = DataHandler("infos/website/umami", 60 * 5); const [elements, setElements] = useState([] as React.JSX.Element[]); useEffect(() => { diff --git a/src/Infos/Website/index.tsx b/src/Infos/Website/index.tsx index bc61704..a937730 100644 --- a/src/Infos/Website/index.tsx +++ b/src/Infos/Website/index.tsx @@ -1,10 +1,10 @@ import React, {useEffect, useState} from "react"; import Info from "../Info.tsx"; import Umami from "./Umami.tsx"; -import DataHandler from "#Infos/DataHandler.tsx"; +import DataHandler from "#parts/DataHandler.tsx"; export default function Website() { - const {data} = DataHandler("token?service=umami", 60 * 60 * 8, false); + const {data} = DataHandler("infos/token?service=umami", 60 * 60 * 8, false); const [websites, setWebsites] = useState([] as React.JSX.Element[]); // useEffect(() => { diff --git a/src/Infos/DataHandler.tsx b/src/parts/DataHandler.tsx similarity index 100% rename from src/Infos/DataHandler.tsx rename to src/parts/DataHandler.tsx