Split the API logic
This commit is contained in:
parent
150b861bd3
commit
3728614109
31 changed files with 137 additions and 103 deletions
40
api/index.ts
Normal file
40
api/index.ts
Normal 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});
|
||||||
|
}
|
|
@ -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);
|
|
@ -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"});
|
||||||
|
|
|
@ -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
|
|
@ -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,
|
|
@ -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,
|
|
@ -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())));
|
|
@ -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[];
|
||||||
};
|
};
|
|
@ -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",
|
|
@ -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,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
|
@ -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: {
|
|
@ -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 "..";
|
||||||
|
|
|
@ -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
BIN
bun.lockb
Binary file not shown.
|
@ -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"]});
|
||||||
|
|
||||||
|
|
36
index.ts
36
index.ts
|
@ -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});
|
||||||
|
|
12
package.json
12
package.json
|
@ -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/*",
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue