Split the API logic

This commit is contained in:
Taevas 2025-04-03 15:16:59 +02:00
parent 150b861bd3
commit 3728614109
31 changed files with 137 additions and 103 deletions

40
api/index.ts Normal file
View file

@ -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<string, Handler[]> = {
coding: [github, gitlab, kitsudev],
fediverse: [kitsuclub],
gaming: [osu, speedruncom],
hacking: [hackthebox],
japanese: [wanikani],
media: [anilist, lastfm],
website: [umami],
};
export type Handler = (req: URLSearchParams) => Promise<Response>;
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});
}

View file

@ -1,10 +1,12 @@
import {Octokit} from "@octokit/rest"; import {Octokit} from "@octokit/rest";
import {type GithubInfo} from "#Infos/Coding/GitHub.tsx"; 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 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 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); const privatePush = github.data.find((e) => (e.type === "PushEvent" || e.type === "PullRequestEvent") && !e.public);

View file

@ -1,8 +1,8 @@
import { Gitlab } from "@gitbeaker/rest"; import { Gitlab } from "@gitbeaker/rest";
import {type GitlabInfo} from "#Infos/Coding/GitLab.tsx"; 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 api = new Gitlab({token: process.env["API_GITLAB"]!});
const gitlab = await api.Events.all({action: "pushed"}); const gitlab = await api.Events.all({action: "pushed"});

View file

@ -1,8 +1,11 @@
import { type KitsudevInfo } from "#Infos/Coding/KitsuDev.tsx"; import { type KitsudevInfo } from "#Infos/Coding/KitsuDev.tsx";
import type { Handler } from ".."; import type { Handler } from "../..";
export const coding_kitsudev: Handler = async () => { const username = "Taevas";
const kitsudev = await (await fetch("https://kitsunes.dev/api/v1/users/Taevas/activities/feeds?limit=1")).json() as [{
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: { repo: {
full_name: string full_name: string
html_url: string html_url: string

View file

@ -1,7 +1,10 @@
import { type KitsuclubInfo } from "#Infos/Fediverse/KitsuClub.tsx"; 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", { const kitsuclub = await (await fetch("https://kitsunes.club/api/users/notes", {
method: "POST", method: "POST",
headers: { headers: {
@ -9,7 +12,7 @@ export const fediverse_kitsuclub: Handler = async () => {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
"userId": "a2hgd7delf", "userId": user_id,
"limit": 1, "limit": 1,
"withReplies": false, "withReplies": false,
"withRepliesToSelf": false, "withRepliesToSelf": false,

View file

@ -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 OsuInfo} from "#Infos/Gaming/Osu.tsx";
import type { Handler } from "../index.ts"; import type { Handler } from "../../index.ts";
import { db, getToken } from "../database.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"); const token = await getToken(db, "osu");
let ruleset = params.has("ruleset") ? Number(params.get("ruleset")) : undefined; let ruleset = params.has("ruleset") ? Number(params.get("ruleset")) : undefined;
if (ruleset && isNaN(ruleset)) {ruleset = undefined;} if (ruleset && isNaN(ruleset)) {ruleset = undefined;}
const api = new osu.API({access_token: token?.access_token}); const api = new osuv2.API({access_token: token?.access_token});
const profile = await api.getUser(7276846, ruleset); const profile = await api.getUser(user_id, ruleset);
const info: OsuInfo = { const info: OsuInfo = {
country: profile.country.name, country: profile.country.name,

View file

@ -1,5 +1,7 @@
import {type SpeedruncomInfo} from "#Infos/Gaming/Speedruncom.tsx"; import {type SpeedruncomInfo} from "#Infos/Gaming/Speedruncom.tsx";
import type { Handler } from ".."; import type { Handler } from "../..";
const user_id = "j03v45mj";
interface Runs { interface Runs {
data: { 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 // 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); const data = speedruncom.data.at(0);
if (!data) { if (!data) {
return new Response("Not Found", {status: 404}); 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}`]; 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}`);} 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}`);} 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()))); const toRequest = urlsToRequest.map((url) => new Promise(async (resolve) => resolve(await (await fetch(url)).json())));

View file

@ -1,8 +1,11 @@
import {type HacktheboxInfo} from "#Infos/Hacking/Hackthebox.tsx"; import {type HacktheboxInfo} from "#Infos/Hacking/Hackthebox.tsx";
import type { Handler } from ".."; import type { Handler } from "../..";
export const hacking_hackthebox: Handler = async () => { const user_id = 1063999;
const hackthebox = await (await fetch("https://www.hackthebox.com/api/v4/profile/activity/1063999")).json() as {
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: { profile: {
activity: HacktheboxInfo[]; activity: HacktheboxInfo[];
}; };

View file

@ -1,6 +1,6 @@
import {type WanikaniInfo} from "#Infos/Japanese/Wanikani.tsx"; import {type WanikaniInfo} from "#Infos/Japanese/Wanikani.tsx";
import type { WKLevelProgression, WKResetCollection, WKSummary } from "@bachmacintosh/wanikani-api-types"; import type { WKLevelProgression, WKResetCollection, WKSummary } from "@bachmacintosh/wanikani-api-types";
import type { Handler } from ".."; import type { Handler } from "../..";
interface Subject { interface Subject {
id: number; id: number;
@ -48,7 +48,7 @@ function addStuffToLearn(ids: number[], data: {available_at: string; subject_ids
return arr; return arr;
} }
export const japanese_wanikani: Handler = async () => { export const wanikani: Handler = async () => {
const urlsToRequest = [ const urlsToRequest = [
"https://api.wanikani.com/v2/level_progressions", "https://api.wanikani.com/v2/level_progressions",
"https://api.wanikani.com/v2/resets", "https://api.wanikani.com/v2/resets",

View file

@ -1,7 +1,10 @@
import {type AnilistInfo} from "#Infos/Media/Anilist.tsx"; 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", { const anilist = await fetch("https://graphql.anilist.co", {
method: "POST", method: "POST",
headers: { headers: {
@ -39,7 +42,7 @@ export const media_anilist: Handler = async () => {
} }
`, `,
variables: { variables: {
userName: "Taevas", userName: username,
}, },
}), }),
}); });

View file

@ -1,8 +1,11 @@
import {type LastfmInfo} from "#Infos/Media/Lastfm.tsx"; import {type LastfmInfo} from "#Infos/Media/Lastfm.tsx";
import type { Handler } from ".."; import type { Handler } from "../..";
export const media_lastfm: Handler = async () => { const username = "TTTaevas";
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 {
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: { recenttracks: {
track: { track: {
artist: { artist: {

View file

@ -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 {API} from "osu-api-v2-js";
import type { Handler } from ".."; import type { Handler } from "..";

View file

@ -1,8 +1,8 @@
import type { Handler } from "../index.ts"; import type { Handler } from "../..";
import type { UmamiInfo } from "#Infos/Website/Umami.tsx"; 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 token = await getToken(db, "umami");
const api_server = "https://visitors.taevas.xyz/api"; const api_server = "https://visitors.taevas.xyz/api";

BIN
bun.lockb

Binary file not shown.

View file

@ -1,5 +1,5 @@
import { SQL } from "bun"; import { SQL } from "bun";
import type { Token } from "./api/token"; import type { Token } from "./api/infos/token";
export const db = new SQL({url: process.env["URL_POSTGRESQL"]}); export const db = new SQL({url: process.env["URL_POSTGRESQL"]});

View file

@ -1,17 +1,6 @@
import type { Server } from "bun"; import type { Server } from "bun";
import { parseArgs } from "util"; import { parseArgs } from "util";
import { coding_github } from "./api/coding_github"; import { api } from "./api";
import { coding_gitlab } from "./api/coding_gitlab";
import { coding_kitsudev } from "./api/coding_kitsudev";
import { fediverse_kitsuclub } from "./api/fediverse_kitsuclub";
import { gaming_osu } from "./api/gaming_osu";
import { gaming_speedruncom } from "./api/gaming_speedruncom";
import { hacking_hackthebox } from "./api/hacking_hackthebox";
import { japanese_wanikani } from "./api/japanese_wanikani";
import { media_anilist } from "./api/media_anilist";
import { media_lastfm } from "./api/media_lastfm";
import { token } from "./api/token";
import { website_umami } from "./api/website_umami";
// PORT AND SSL STUFF // PORT AND SSL STUFF
@ -32,23 +21,6 @@ console.log("Therefore, we are opening ports on:", ports);
// ACTUAL CODE // ACTUAL CODE
export type Handler = (req: URLSearchParams) => Promise<Response>;
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({ const servers: Server[] = ports.map((port) => Bun.serve({
idleTimeout: 30, idleTimeout: 30,
tls: port !== 80 ? tls : undefined, tls: port !== 80 ? tls : undefined,
@ -92,11 +64,7 @@ const servers: Server[] = ports.map((port) => Bun.serve({
// API // API
if (pathname.startsWith("/api")) { if (pathname.startsWith("/api")) {
for (const endpoint of api_endpoints) { return await api(pathname, parameters);
if (pathname === "/api/" + endpoint.name) {
return await endpoint(parameters);
}
}
} }
return new Response("Not Found", {status: 404}); return new Response("Not Found", {status: 404});

View file

@ -21,20 +21,20 @@
"@eslint/js": "^9.23.0", "@eslint/js": "^9.23.0",
"@stylistic/eslint-plugin": "^3.1.0", "@stylistic/eslint-plugin": "^3.1.0",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.0.17", "@tailwindcss/postcss": "^4.1.1",
"@types/bun": "^1.2.8", "@types/bun": "^1.2.8",
"@types/react": "^19.0.12", "@types/react": "^19.1.0",
"@types/react-dom": "^19.0.4", "@types/react-dom": "^19.1.1",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"eslint": "^9.23.0", "eslint": "^9.23.0",
"eslint-config-xo-typescript": "^7.0.0", "eslint-config-xo-typescript": "^7.0.0",
"eslint-plugin-react": "^7.37.4", "eslint-plugin-react": "^7.37.4",
"postcss": "^8.5.3", "postcss": "^8.5.3",
"react-animate-height": "^3.2.3", "react-animate-height": "^3.2.3",
"tailwindcss": "^4.0.17", "tailwindcss": "^4.1.1",
"typescript": "^5.8.2", "typescript": "^5.8.2",
"typescript-eslint": "^8.28.0", "typescript-eslint": "^8.29.0",
"vite": "^6.2.3" "vite": "^6.2.5"
}, },
"imports": { "imports": {
"#Main/*": "./src/Main/*", "#Main/*": "./src/Main/*",

View file

@ -1,6 +1,6 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
import Link from "#parts/Link.tsx"; import Link from "#parts/Link.tsx";
export interface GithubInfo { export interface GithubInfo {
@ -14,7 +14,7 @@ export interface GithubInfo {
} }
export default function GitHub() { export default function GitHub() {
const {data, error, setError} = DataHandler<GithubInfo>("coding_github", 60 * 20); const {data, error, setError} = DataHandler<GithubInfo>("infos/coding/github", 60 * 20);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,13 +1,13 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export type GitlabInfo = { export type GitlabInfo = {
date: string; date: string;
} | undefined; } | undefined;
export default function GitLab() { export default function GitLab() {
const {data, error, setError} = DataHandler<GitlabInfo>("coding_gitlab", 60 * 20); const {data, error, setError} = DataHandler<GitlabInfo>("infos/coding/gitlab", 60 * 20);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,6 +1,6 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
import Link from "#parts/Link.tsx"; import Link from "#parts/Link.tsx";
export type KitsudevInfo = { export type KitsudevInfo = {
@ -10,7 +10,7 @@ export type KitsudevInfo = {
} | undefined; } | undefined;
export default function KitsuDev() { export default function KitsuDev() {
const {data, error, setError} = DataHandler<KitsudevInfo>("coding_kitsudev", 60 * 20); const {data, error, setError} = DataHandler<KitsudevInfo>("infos/coding/kitsudev", 60 * 20);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,6 +1,6 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
import Link from "#parts/Link.tsx"; import Link from "#parts/Link.tsx";
export type KitsuclubInfo = { export type KitsuclubInfo = {
@ -18,7 +18,7 @@ export type KitsuclubInfo = {
} | undefined; } | undefined;
export default function KitsuClub() { export default function KitsuClub() {
const {data, error, setError} = DataHandler<KitsuclubInfo>("fediverse_kitsuclub", 60 * 20); const {data, error, setError} = DataHandler<KitsuclubInfo>("infos/fediverse/kitsuclub", 60 * 20);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,7 +1,7 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import { Ruleset } from "osu-api-v2-js"; import { Ruleset } from "osu-api-v2-js";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export type OsuInfo = { export type OsuInfo = {
country: string; country: string;
@ -12,7 +12,7 @@ export type OsuInfo = {
} | undefined; } | undefined;
export default function Osu(args: {ruleset: Ruleset}) { export default function Osu(args: {ruleset: Ruleset}) {
const {data, error, setError} = DataHandler<OsuInfo>(`gaming_osu?ruleset=${args.ruleset}`, 60 * 45); const {data, error, setError} = DataHandler<OsuInfo>(`infos/gaming/osu?ruleset=${args.ruleset}`, 60 * 45);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
const ruleset = Ruleset[args.ruleset]; const ruleset = Ruleset[args.ruleset];

View file

@ -1,6 +1,6 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
import Link from "#parts/Link.tsx"; import Link from "#parts/Link.tsx";
import ButtonLink from "#parts/ButtonLink.tsx"; import ButtonLink from "#parts/ButtonLink.tsx";
@ -16,7 +16,7 @@ export type SpeedruncomInfo = {
} | undefined; } | undefined;
export default function Speedruncom() { export default function Speedruncom() {
const {data, error, setError} = DataHandler<SpeedruncomInfo>("gaming_speedruncom", 60 * 60); const {data, error, setError} = DataHandler<SpeedruncomInfo>("infos/gaming/speedruncom", 60 * 60);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -4,10 +4,10 @@ import Info from "../Info.tsx";
import Speedruncom from "./Speedruncom.tsx"; import Speedruncom from "./Speedruncom.tsx";
// import Osu from "./Osu.tsx"; // import Osu from "./Osu.tsx";
// import { Ruleset } from "osu-api-v2-js"; // import { Ruleset } from "osu-api-v2-js";
// import DataHandler from "#Infos/DataHandler.tsx"; // import DataHandler from "#parts/DataHandler.tsx";
export default function RhythmGames() { export default function RhythmGames() {
// const {data, error} = DataHandler<boolean>("token?service=osu", 60 * 60 * 8, false); // const {data, error} = DataHandler<boolean>("infos/token?service=osu", 60 * 60 * 8, false);
const [websites, setWebsites] = useState([] as React.JSX.Element[]); const [websites, setWebsites] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,7 +1,7 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import ButtonLink from "#parts/ButtonLink.tsx"; import ButtonLink from "#parts/ButtonLink.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export type HacktheboxInfo = { export type HacktheboxInfo = {
id: string; id: string;
@ -14,7 +14,7 @@ export type HacktheboxInfo = {
} | undefined; } | undefined;
export default function Hackthebox() { export default function Hackthebox() {
const {data, error, setError} = DataHandler<HacktheboxInfo>("hacking_hackthebox", 60 * 60); const {data, error, setError} = DataHandler<HacktheboxInfo>("infos/hacking/hackthebox", 60 * 60);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,7 +1,7 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import { WKLevelProgression, WKReset } from "@bachmacintosh/wanikani-api-types"; import type { WKLevelProgression, WKReset } from "@bachmacintosh/wanikani-api-types";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export type WanikaniInfo = { export type WanikaniInfo = {
progression: { progression: {
@ -37,7 +37,7 @@ function Button(item: Item) {
} }
export default function Wanikani() { export default function Wanikani() {
const {data, error, setError} = DataHandler<WanikaniInfo>("japanese_wanikani", 60 * 60); const {data, error, setError} = DataHandler<WanikaniInfo>("infos/japanese/wanikani", 60 * 60);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,6 +1,6 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
import Link from "#parts/Link.tsx"; import Link from "#parts/Link.tsx";
export type AnilistInfo = { export type AnilistInfo = {
@ -18,7 +18,7 @@ export type AnilistInfo = {
} | undefined; } | undefined;
export default function Anilist() { export default function Anilist() {
const {data, error, setError} = DataHandler<AnilistInfo>("media_anilist", 60 * 30); const {data, error, setError} = DataHandler<AnilistInfo>("infos/media/anilist", 60 * 30);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -2,7 +2,7 @@ import React, {useState, useEffect} from "react";
import {format} from "timeago.js"; import {format} from "timeago.js";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import Link from "#parts/Link.tsx"; import Link from "#parts/Link.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export type LastfmInfo = { export type LastfmInfo = {
artist: string; artist: string;
@ -15,7 +15,7 @@ export type LastfmInfo = {
} | undefined; } | undefined;
export default function Lastfm() { export default function Lastfm() {
const {data, error, setError} = DataHandler<LastfmInfo>("media_lastfm", 60 * 2); const {data, error, setError} = DataHandler<LastfmInfo>("infos/media/lastfm", 60 * 2);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,6 +1,6 @@
import React, {useState, useEffect} from "react"; import React, {useState, useEffect} from "react";
import Website from "../Website.tsx"; import Website from "../Website.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export type UmamiInfo = { export type UmamiInfo = {
pageviews: number pageviews: number
@ -10,7 +10,7 @@ export type UmamiInfo = {
} | undefined; } | undefined;
export default function Umami() { export default function Umami() {
const {data, error, setError} = DataHandler<UmamiInfo>("website_umami", 60 * 5); const {data, error, setError} = DataHandler<UmamiInfo>("infos/website/umami", 60 * 5);
const [elements, setElements] = useState([] as React.JSX.Element[]); const [elements, setElements] = useState([] as React.JSX.Element[]);
useEffect(() => { useEffect(() => {

View file

@ -1,10 +1,10 @@
import React, {useEffect, useState} from "react"; import React, {useEffect, useState} from "react";
import Info from "../Info.tsx"; import Info from "../Info.tsx";
import Umami from "./Umami.tsx"; import Umami from "./Umami.tsx";
import DataHandler from "#Infos/DataHandler.tsx"; import DataHandler from "#parts/DataHandler.tsx";
export default function Website() { export default function Website() {
const {data} = DataHandler<boolean>("token?service=umami", 60 * 60 * 8, false); const {data} = DataHandler<boolean>("infos/token?service=umami", 60 * 60 * 8, false);
const [websites, setWebsites] = useState([] as React.JSX.Element[]); const [websites, setWebsites] = useState([] as React.JSX.Element[]);
// useEffect(() => { // useEffect(() => {