Also apply basic linting to Netlify functions
This commit is contained in:
parent
3d38ba1768
commit
eb85319f73
11 changed files with 272 additions and 258 deletions
|
@ -15,6 +15,10 @@ export default [
|
||||||
...compat.extends("xo-typescript"),
|
...compat.extends("xo-typescript"),
|
||||||
pluginReactConfig,
|
pluginReactConfig,
|
||||||
{
|
{
|
||||||
|
files: [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx"
|
||||||
|
],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
globals: globals.node
|
globals: globals.node
|
||||||
},
|
},
|
||||||
|
@ -33,13 +37,10 @@ export default [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ignores: [
|
ignores: [
|
||||||
"**/.netlify/*",
|
".netlify/*",
|
||||||
"**/dist/*",
|
"dist/*",
|
||||||
"eslint.config.js",
|
"*.js",
|
||||||
"eslintrc.js",
|
"*.cjs"
|
||||||
"postcss.config.cjs",
|
],
|
||||||
"tailwind.config.js",
|
|
||||||
"vite.config.js"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:react/recommended"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import fetch from "node-fetch"
|
import fetch from "node-fetch";
|
||||||
import { AnilistInfo } from '../../src/components/infos/Anilist'
|
import {type AnilistInfo} from "../../src/components/Info/Anilist.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const anilist = await fetch("https://graphql.anilist.co", {
|
const anilist = await fetch("https://graphql.anilist.co", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json"
|
"Accept": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
query: `
|
query: `
|
||||||
|
@ -40,21 +40,21 @@ const handler: Handler = async () => {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
variables: {
|
variables: {
|
||||||
userName: "Taevas"
|
userName: "Taevas",
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
})
|
});
|
||||||
if (anilist.status !== 200) {
|
if (anilist.status !== 200) {
|
||||||
// log the issue in netlify, return 404 to the user anyway
|
// log the issue in netlify, return 404 to the user anyway
|
||||||
console.log(await anilist.json())
|
console.log(await anilist.json());
|
||||||
return {
|
return {
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
body: ""
|
body: "",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const p_json = await anilist.json() as {[key: string]: any}
|
const p_json = await anilist.json() as Record<string, any>;
|
||||||
const json = p_json.data.MediaList
|
const json = p_json.data.MediaList;
|
||||||
const anime: AnilistInfo = {
|
const anime: AnilistInfo = {
|
||||||
title: json.media.title.romaji,
|
title: json.media.title.romaji,
|
||||||
episodes: {
|
episodes: {
|
||||||
|
@ -66,17 +66,17 @@ const handler: Handler = async () => {
|
||||||
updateDate: new Date(json.updatedAt * 1000).toISOString(),
|
updateDate: new Date(json.updatedAt * 1000).toISOString(),
|
||||||
endDate: json.completedAt.year ? new Date(`${json.completedAt.year}-${json.completedAt.month}-${json.completedAt.day}`).toISOString() : new Date().toISOString(),
|
endDate: json.completedAt.year ? new Date(`${json.completedAt.year}-${json.completedAt.month}-${json.completedAt.day}`).toISOString() : new Date().toISOString(),
|
||||||
cover: json.media.coverImage.medium,
|
cover: json.media.coverImage.medium,
|
||||||
url: json.media.siteUrl
|
url: json.media.siteUrl,
|
||||||
}
|
};
|
||||||
|
|
||||||
anime.startDate = anime.startDate.substring(0, anime.startDate.indexOf("T"))
|
anime.startDate = anime.startDate.substring(0, anime.startDate.indexOf("T"));
|
||||||
anime.updateDate = anime.updateDate.substring(0, anime.updateDate.indexOf("T"))
|
anime.updateDate = anime.updateDate.substring(0, anime.updateDate.indexOf("T"));
|
||||||
anime.endDate = anime.endDate.substring(0, anime.endDate.indexOf("T"))
|
anime.endDate = anime.endDate.substring(0, anime.endDate.indexOf("T"));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(anime)
|
body: JSON.stringify(anime),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import { Octokit } from '@octokit/core'
|
import {Octokit} from "@octokit/core";
|
||||||
import { GithubInfo } from '../../src/components/infos/Git'
|
import {type GithubInfo} from "../../src/components/Info/Git.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const octokit = new Octokit({auth: process.env.API_GITHUB})
|
const octokit = new Octokit({auth: process.env.API_GITHUB});
|
||||||
const github = await octokit.request("GET /users/TTTaevas/events", {per_page: 100})
|
const github = await octokit.request("GET /users/TTTaevas/events", {per_page: 100});
|
||||||
if (github.status !== 200) {
|
if (github.status !== 200) {
|
||||||
return {
|
return {
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
body: ""
|
body: "",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const public_push = github.data.find((e: {type: string, public: boolean}) => e.type === "PushEvent" && e.public === true)
|
const public_push = github.data.find((e: {type: string; public: boolean}) => e.type === "PushEvent" && e.public);
|
||||||
const private_push = github.data.find((e: {type: string, public: boolean}) => e.type === "PushEvent" && e.public === false)
|
const private_push = github.data.find((e: {type: string; public: boolean}) => e.type === "PushEvent" && !e.public);
|
||||||
if (!public_push || !private_push) {
|
if (!public_push || !private_push) {
|
||||||
return {
|
return {
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
body: ""
|
body: "",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const info: GithubInfo = {
|
const info: GithubInfo = {
|
||||||
public: {
|
public: {
|
||||||
repo: public_push.repo.name,
|
repo: public_push.repo.name,
|
||||||
date: public_push.created_at.substring(0, public_push.created_at.indexOf("T"))
|
date: public_push.created_at.substring(0, public_push.created_at.indexOf("T")),
|
||||||
},
|
},
|
||||||
private: {
|
private: {
|
||||||
date: private_push.created_at.substring(0, private_push.created_at.indexOf("T"))
|
date: private_push.created_at.substring(0, private_push.created_at.indexOf("T")),
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(info)
|
body: JSON.stringify(info),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import fetch from "node-fetch"
|
import fetch from "node-fetch";
|
||||||
import { GitlabInfo } from '../../src/components/infos/Git'
|
import {type GitlabInfo} from "../../src/components/Info/Git.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const gitlab = await fetch("https://gitlab.com/api/v4/events?action=pushed", {
|
const gitlab = await fetch("https://gitlab.com/api/v4/events?action=pushed", {
|
||||||
|
@ -8,26 +8,26 @@ const handler: Handler = async () => {
|
||||||
headers: {
|
headers: {
|
||||||
"PRIVATE-TOKEN": process.env.API_GITLAB!,
|
"PRIVATE-TOKEN": process.env.API_GITLAB!,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json"
|
"Accept": "application/json",
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
if (gitlab.status !== 200) {
|
if (gitlab.status !== 200) {
|
||||||
return {
|
return {
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
body: ""
|
body: "",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = await gitlab.json() as {[key: string]: any}
|
const json = await gitlab.json() as Record<string, any>;
|
||||||
const activity: GitlabInfo = {
|
const activity: GitlabInfo = {
|
||||||
date: json[0].created_at.substring(0, json[0].created_at.indexOf("T"))
|
date: json[0].created_at.substring(0, json[0].created_at.indexOf("T")),
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(activity)
|
body: JSON.stringify(activity),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import { api } from "./shared/api"
|
import {api} from "./shared/api.js";
|
||||||
import { HacktheboxInfo } from '../../src/components/infos/Hackthebox'
|
import {type HacktheboxInfo} from "../../src/components/Info/Hackthebox.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const hackthebox: {profile: {activity: HacktheboxInfo[]}} = await api<{
|
const hackthebox: {profile: {activity: HacktheboxInfo[]}} = await api<{
|
||||||
profile: {
|
profile: {
|
||||||
activity: HacktheboxInfo[]
|
activity: HacktheboxInfo[];
|
||||||
}
|
};
|
||||||
}>
|
}>
|
||||||
(`https://www.hackthebox.com/api/v4/profile/activity/1063999`)
|
("https://www.hackthebox.com/api/v4/profile/activity/1063999");
|
||||||
|
|
||||||
const pwn = hackthebox.profile.activity.find((a: HacktheboxInfo) => a!.object_type === "machine")
|
const pwn = hackthebox.profile.activity.find((a: HacktheboxInfo) => a!.object_type === "machine");
|
||||||
if (!pwn) {
|
if (!pwn) {
|
||||||
return {
|
return {
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
body: ""
|
body: "",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pwn.machine_avatar = `https://www.hackthebox.com${pwn.machine_avatar}`
|
pwn.machine_avatar = `https://www.hackthebox.com${pwn.machine_avatar}`;
|
||||||
pwn.date = pwn.date.substring(0, pwn.date.indexOf("T"))
|
pwn.date = pwn.date.substring(0, pwn.date.indexOf("T"));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(pwn)
|
body: JSON.stringify(pwn),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,45 +1,45 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import { api } from "./shared/api"
|
import {api} from "./shared/api.js";
|
||||||
import { LastfmInfo } from '../../src/components/infos/Lastfm'
|
import {type LastfmInfo} from "../../src/components/Info/Lastfm.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const lastfm = await api<{
|
const lastfm = await api<{
|
||||||
recenttracks: {
|
recenttracks: {
|
||||||
track: {
|
track: Array<{
|
||||||
artist: {
|
artist: {
|
||||||
"#text": string
|
"#text": string;
|
||||||
},
|
};
|
||||||
image: {
|
image: Array<{
|
||||||
size: string,
|
size: string;
|
||||||
"#text": string
|
"#text": string;
|
||||||
}[]
|
}>;
|
||||||
album: {
|
album: {
|
||||||
"#text": string
|
"#text": string;
|
||||||
},
|
};
|
||||||
name: string,
|
name: string;
|
||||||
"@attr"?: {
|
"@attr"?: {
|
||||||
nowplaying?: string
|
nowplaying?: string;
|
||||||
}
|
};
|
||||||
url: string
|
url: string;
|
||||||
}[]
|
}>;
|
||||||
}
|
};
|
||||||
}>
|
}>
|
||||||
(`http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=TTTaevas&api_key=${process.env["API_LASTFM"]}&format=json&limit=1`)
|
(`http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=TTTaevas&api_key=${process.env.API_LASTFM}&format=json&limit=1`);
|
||||||
|
|
||||||
const image = lastfm.recenttracks.track[0].image.find((i) => i.size == "large")
|
const image = lastfm.recenttracks.track[0].image.find((i) => i.size == "large");
|
||||||
const track: LastfmInfo = {
|
const track: LastfmInfo = {
|
||||||
artist: lastfm.recenttracks.track[0].artist['#text'],
|
artist: lastfm.recenttracks.track[0].artist["#text"],
|
||||||
name: lastfm.recenttracks.track[0].name,
|
name: lastfm.recenttracks.track[0].name,
|
||||||
album: lastfm.recenttracks.track[0].album['#text'],
|
album: lastfm.recenttracks.track[0].album["#text"],
|
||||||
image: image ? image['#text'] : "",
|
image: image ? image["#text"] : "",
|
||||||
listening: Boolean(lastfm.recenttracks.track[0]['@attr']?.nowplaying),
|
listening: Boolean(lastfm.recenttracks.track[0]["@attr"]?.nowplaying),
|
||||||
url: lastfm.recenttracks.track[0].url
|
url: lastfm.recenttracks.track[0].url,
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(track)
|
body: JSON.stringify(track),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,40 +1,48 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import * as osu from 'osu-api-v2-js'
|
import * as osu from "osu-api-v2-js";
|
||||||
import { OsuInfo } from '../../src/components/infos/Osu'
|
import {type OsuInfo} from "../../src/components/Info/Osu.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const api = await osu.API.createAsync({id: 11451, secret: process.env.API_OSU!})
|
const api = await osu.API.createAsync({id: 11451, secret: process.env.API_OSU!});
|
||||||
|
|
||||||
const profile = await Promise.all([
|
const profile = await Promise.all([
|
||||||
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.osu))),
|
new Promise((resolve) => {
|
||||||
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.taiko))),
|
resolve(api.getUser(7276846, osu.Ruleset.osu));
|
||||||
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.fruits))),
|
}),
|
||||||
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.mania)))
|
new Promise((resolve) => {
|
||||||
]) as osu.User.Extended[]
|
resolve(api.getUser(7276846, osu.Ruleset.taiko));
|
||||||
|
}),
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolve(api.getUser(7276846, osu.Ruleset.fruits));
|
||||||
|
}),
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolve(api.getUser(7276846, osu.Ruleset.mania));
|
||||||
|
}),
|
||||||
|
]) as osu.User.Extended[];
|
||||||
|
|
||||||
const info: OsuInfo = {
|
const info: OsuInfo = {
|
||||||
country: (profile[0]).country.name || "Unknown",
|
country: (profile[0]).country.name || "Unknown",
|
||||||
osu: {global: 0, country: 0},
|
osu: {global: 0, country: 0},
|
||||||
taiko: {global: 0, country: 0},
|
taiko: {global: 0, country: 0},
|
||||||
fruits: {global: 0, country: 0},
|
fruits: {global: 0, country: 0},
|
||||||
mania: {global: 0, country: 0}
|
mania: {global: 0, country: 0},
|
||||||
}
|
};
|
||||||
|
|
||||||
for (let i = 0; i < profile.length; i++) {
|
for (let i = 0; i < profile.length; i++) {
|
||||||
const ruleset = profile[i]
|
const ruleset = profile[i];
|
||||||
if (ruleset.rank_history) {
|
if (ruleset.rank_history) {
|
||||||
const stats = ruleset.statistics
|
const stats = ruleset.statistics;
|
||||||
info[ruleset.rank_history.mode].global = stats.global_rank || 0
|
info[ruleset.rank_history.mode].global = stats.global_rank || 0;
|
||||||
info[ruleset.rank_history.mode].country = stats.country_rank || 0
|
info[ruleset.rank_history.mode].country = stats.country_rank || 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.revokeToken()
|
api.revokeToken();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(info)
|
body: JSON.stringify(info),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import fetch from "node-fetch"
|
import fetch from "node-fetch";
|
||||||
|
|
||||||
export async function api<T>(url: string, restful_token?: string): Promise<T> {
|
export async function api<T>(url: string, restful_token?: string): Promise<T> {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
return (restful_token ? fetch(url, {headers: {"Authorization": `Bearer ${restful_token}`}}) : fetch(url))
|
return (restful_token ? fetch(url, {headers: {"Authorization": `Bearer ${restful_token}`}}) : fetch(url))
|
||||||
.then(response => {
|
.then(async response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
console.error(response.status, response.statusText)
|
console.error(response.status, response.statusText);
|
||||||
throw new Error("Request failed :(")
|
throw new Error("Request failed :(");
|
||||||
}
|
}
|
||||||
return response.json() as Promise<T>
|
|
||||||
})
|
return response.json() as Promise<T>;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +1,62 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import { api } from "./shared/api"
|
import {api} from "./shared/api.js";
|
||||||
import { SpeedruncomInfo } from '../../src/components/infos/Speedruncom'
|
import {type SpeedruncomInfo} from "../../src/components/Info/Speedruncom.js";
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: 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 api<{
|
const speedruncom = await api<{
|
||||||
data: {
|
data: Array<{
|
||||||
place: number,
|
place: number;
|
||||||
run: {
|
run: {
|
||||||
weblink: string
|
weblink: string;
|
||||||
game: string
|
game: string;
|
||||||
level: string | null
|
level: string | undefined;
|
||||||
category: string | null
|
category: string | undefined;
|
||||||
date: string
|
date: string;
|
||||||
}
|
};
|
||||||
}[]
|
}>;
|
||||||
}>
|
}>
|
||||||
(`https://www.speedrun.com/api/v1/users/j03v45mj/personal-bests`)
|
("https://www.speedrun.com/api/v1/users/j03v45mj/personal-bests");
|
||||||
|
|
||||||
const details_to_request = [new Promise((resolve) => {
|
const details_to_request = [new Promise((resolve) => {
|
||||||
resolve(api<{
|
resolve(api<{
|
||||||
data: {
|
data: {
|
||||||
names: {
|
names: {
|
||||||
international: string
|
international: string;
|
||||||
}
|
};
|
||||||
assets: {
|
assets: {
|
||||||
"cover-tiny": {
|
"cover-tiny": {
|
||||||
uri: string
|
uri: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}>
|
}>
|
||||||
(`https://www.speedrun.com/api/v1/games/${speedruncom.data[0].run.game}`))
|
(`https://www.speedrun.com/api/v1/games/${speedruncom.data[0].run.game}`));
|
||||||
})]
|
})];
|
||||||
|
|
||||||
if (speedruncom.data[0].run.level) {
|
if (speedruncom.data[0].run.level) {
|
||||||
details_to_request.push(new Promise((resolve) => {
|
details_to_request.push(new Promise((resolve) => {
|
||||||
resolve(api<{
|
resolve(api<{
|
||||||
data: {
|
data: {
|
||||||
name: string
|
name: string;
|
||||||
}
|
};
|
||||||
}>
|
}>
|
||||||
(`https://www.speedrun.com/api/v1/levels/${speedruncom.data[0].run.level}`))
|
(`https://www.speedrun.com/api/v1/levels/${speedruncom.data[0].run.level}`));
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (speedruncom.data[0].run.category) {
|
if (speedruncom.data[0].run.category) {
|
||||||
details_to_request.push(new Promise((resolve) => {
|
details_to_request.push(new Promise((resolve) => {
|
||||||
resolve(api<{
|
resolve(api<{
|
||||||
data: {
|
data: {
|
||||||
name: string
|
name: string;
|
||||||
}
|
};
|
||||||
}>
|
}>
|
||||||
(`https://www.speedrun.com/api/v1/categories/${speedruncom.data[0].run.category}`))
|
(`https://www.speedrun.com/api/v1/categories/${speedruncom.data[0].run.category}`));
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const details = await Promise.all(details_to_request) as [{[key: string]: any}]
|
const details = await Promise.all(details_to_request) as [Record<string, any>];
|
||||||
|
|
||||||
const run: SpeedruncomInfo = {
|
const run: SpeedruncomInfo = {
|
||||||
place: speedruncom.data[0].place,
|
place: speedruncom.data[0].place,
|
||||||
|
@ -64,13 +64,13 @@ const handler: Handler = async () => {
|
||||||
date: speedruncom.data[0].run.date,
|
date: speedruncom.data[0].run.date,
|
||||||
thumbnail: details[0].data.assets["cover-tiny"].uri,
|
thumbnail: details[0].data.assets["cover-tiny"].uri,
|
||||||
game: details[0].data.names.international,
|
game: details[0].data.names.international,
|
||||||
details: details.slice(1).map((d) => d.data.name) || []
|
details: details.slice(1).map((d) => d.data.name) || [],
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(run)
|
body: JSON.stringify(run),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
import { Handler } from '@netlify/functions'
|
import {type Handler} from "@netlify/functions";
|
||||||
import { api } from "./shared/api"
|
import {api} from "./shared/api.js";
|
||||||
import { WanikaniInfo } from '../../src/components/infos/Wanikani'
|
import {type WanikaniInfo} from "../../src/components/Info/Wanikani.js";
|
||||||
|
|
||||||
type Subject = {
|
type Subject = {
|
||||||
id: number
|
id: number;
|
||||||
object: string
|
object: string;
|
||||||
data: {
|
data: {
|
||||||
characters: string
|
characters: string;
|
||||||
slug: string
|
slug: string;
|
||||||
document_url: string
|
document_url: string;
|
||||||
meanings: {
|
meanings: Array<{
|
||||||
meaning: string
|
meaning: string;
|
||||||
}[]
|
}>;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
function addStuffToLearn(ids: number[], data: {available_at: string, subject_ids: number[]}[], subjects: Subject[]): {
|
function addStuffToLearn(ids: number[], data: Array<{available_at: string; subject_ids: number[]}>, subjects: Subject[]): Array<{
|
||||||
available_at: string
|
available_at: string;
|
||||||
type: string
|
type: string;
|
||||||
writing: string
|
writing: string;
|
||||||
meanings: [{
|
meanings: [{
|
||||||
meaning: string
|
meaning: string;
|
||||||
}]
|
}];
|
||||||
url: string
|
url: string;
|
||||||
}[] {
|
}> {
|
||||||
const arr: any[] = []
|
const arr: any[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < ids.length; i++) {
|
for (let i = 0; i < ids.length; i++) {
|
||||||
const summary_data = data.find(lesson => lesson.subject_ids.includes(ids[i]))
|
const summary_data = data.find(lesson => lesson.subject_ids.includes(ids[i]));
|
||||||
const subject = subjects.find(subject => subject.id === ids[i])
|
const subject = subjects.find(subject => subject.id === ids[i]);
|
||||||
if (!summary_data || !subject) {
|
if (!summary_data || !subject) {
|
||||||
console.error("Failed: ", summary_data, subject)
|
console.error("Failed: ", summary_data, subject);
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
arr.push({
|
arr.push({
|
||||||
|
@ -39,95 +39,104 @@ function addStuffToLearn(ids: number[], data: {available_at: string, subject_ids
|
||||||
type: subject.object,
|
type: subject.object,
|
||||||
writing: subject.data.characters || subject.data.slug || subject.data.meanings[0].meaning,
|
writing: subject.data.characters || subject.data.slug || subject.data.meanings[0].meaning,
|
||||||
meanings: subject.data.meanings,
|
meanings: subject.data.meanings,
|
||||||
url: subject.data.document_url
|
url: subject.data.document_url,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handler: Handler = async () => {
|
const handler: Handler = async () => {
|
||||||
const data: any[] = await Promise.all([
|
const data: any[] = await Promise.all([
|
||||||
new Promise((resolve) => resolve(api("https://api.wanikani.com/v2/level_progressions", process.env["API_WANIKANI"]))),
|
new Promise((resolve) => {
|
||||||
new Promise((resolve) => resolve(api("https://api.wanikani.com/v2/resets", process.env["API_WANIKANI"]))),
|
resolve(api("https://api.wanikani.com/v2/level_progressions", process.env.API_WANIKANI));
|
||||||
new Promise((resolve) => resolve(api("https://api.wanikani.com/v2/summary", process.env["API_WANIKANI"])))
|
}),
|
||||||
])
|
new Promise((resolve) => {
|
||||||
|
resolve(api("https://api.wanikani.com/v2/resets", process.env.API_WANIKANI));
|
||||||
|
}),
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolve(api("https://api.wanikani.com/v2/summary", process.env.API_WANIKANI));
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
const progression: {
|
const progression: {
|
||||||
total_count: number
|
total_count: number;
|
||||||
|
data: Array<{
|
||||||
data: {
|
data: {
|
||||||
data: {
|
level: number;
|
||||||
level: number
|
unlocked_at: undefined | string;
|
||||||
unlocked_at: null | string
|
completed_at: undefined | string;
|
||||||
completed_at: null | string
|
abandoned_at: undefined | string;
|
||||||
abandoned_at: null| string
|
};
|
||||||
}
|
}>;
|
||||||
}[]
|
} = data[0];
|
||||||
} = data[0]
|
|
||||||
|
|
||||||
const resets: {
|
const resets: {
|
||||||
data: [{
|
data: [{
|
||||||
data: {
|
data: {
|
||||||
created_at: string
|
created_at: string;
|
||||||
original_level: number
|
original_level: number;
|
||||||
target_level: number
|
target_level: number;
|
||||||
}
|
};
|
||||||
}]
|
}];
|
||||||
} = data[1]
|
} = data[1];
|
||||||
|
|
||||||
const summary: {
|
const summary: {
|
||||||
data: {
|
data: {
|
||||||
lessons: {
|
lessons: Array<{
|
||||||
available_at: string
|
available_at: string;
|
||||||
subject_ids: number[]
|
subject_ids: number[];
|
||||||
}[],
|
}>;
|
||||||
reviews: {
|
reviews: Array<{
|
||||||
available_at: string
|
available_at: string;
|
||||||
subject_ids: number[]
|
subject_ids: number[];
|
||||||
}[],
|
}>;
|
||||||
next_reviews_at: null | string
|
next_reviews_at: undefined | string;
|
||||||
}
|
};
|
||||||
} = data[2]
|
} = data[2];
|
||||||
|
|
||||||
const subject_ids_lessons: number[] = []
|
const subject_ids_lessons: number[] = [];
|
||||||
const subject_ids_reviews: number[] = []
|
const subject_ids_reviews: number[] = [];
|
||||||
for (let i = 0; i < summary.data.lessons.length; i++) {
|
for (let i = 0; i < summary.data.lessons.length; i++) {
|
||||||
for (let e = 0; e < summary.data.lessons[i].subject_ids.length; e++) {
|
for (let e = 0; e < summary.data.lessons[i].subject_ids.length; e++) {
|
||||||
subject_ids_lessons.push(summary.data.lessons[i].subject_ids[e])
|
subject_ids_lessons.push(summary.data.lessons[i].subject_ids[e]);
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = 0; i < summary.data.reviews.length; i++) {
|
|
||||||
for (let e = 0; e < summary.data.reviews[i].subject_ids.length; e++) {
|
|
||||||
subject_ids_reviews.push(summary.data.reviews[i].subject_ids[e])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Date()
|
for (let i = 0; i < summary.data.reviews.length; i++) {
|
||||||
|
for (let e = 0; e < summary.data.reviews[i].subject_ids.length; e++) {
|
||||||
|
subject_ids_reviews.push(summary.data.reviews[i].subject_ids[e]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
// next_reviews checks what reviews will be available in the next 23 hours
|
// next_reviews checks what reviews will be available in the next 23 hours
|
||||||
// summary.data.next_reviews_at checks beyond that, but will be the current time if a review is already available
|
// summary.data.next_reviews_at checks beyond that, but will be the current time if a review is already available
|
||||||
const next_reviews = summary.data.reviews
|
const next_reviews = summary.data.reviews
|
||||||
.map((r: {subject_ids: number[], available_at: Date | string}) => {r.available_at = new Date(r.available_at); return r})
|
.map((r: {subject_ids: number[]; available_at: Date | string}) => {
|
||||||
.filter((r) => r.available_at > now && r.subject_ids.length) as {subject_ids: number[], available_at: Date}[]
|
r.available_at = new Date(r.available_at); return r;
|
||||||
const more_things_to_review_at = next_reviews[0] ? next_reviews[0].available_at.toISOString() : summary.data.next_reviews_at ? summary.data.next_reviews_at : null
|
})
|
||||||
|
.filter((r) => r.available_at > now && r.subject_ids.length) as Array<{subject_ids: number[]; available_at: Date}>;
|
||||||
|
const more_things_to_review_at = next_reviews[0] ? next_reviews[0].available_at.toISOString() : summary.data.next_reviews_at ? summary.data.next_reviews_at : null;
|
||||||
|
|
||||||
const subject_ids_all = subject_ids_lessons.concat(subject_ids_reviews)
|
const subject_ids_all = subject_ids_lessons.concat(subject_ids_reviews);
|
||||||
const subjects = await api<{data: Subject[]}>(`https://api.wanikani.com/v2/subjects?ids=${subject_ids_all.toString()}`, process.env["API_WANIKANI"])
|
const subjects = await api<{data: Subject[]}>(`https://api.wanikani.com/v2/subjects?ids=${subject_ids_all.toString()}`, process.env.API_WANIKANI);
|
||||||
|
|
||||||
const lessons = addStuffToLearn(subject_ids_lessons, summary.data.lessons, subjects.data)
|
const lessons = addStuffToLearn(subject_ids_lessons, summary.data.lessons, subjects.data);
|
||||||
const reviews = addStuffToLearn(subject_ids_reviews, summary.data.reviews, subjects.data)
|
const reviews = addStuffToLearn(subject_ids_reviews, summary.data.reviews, subjects.data);
|
||||||
|
|
||||||
const info: WanikaniInfo = {
|
const info: WanikaniInfo = {
|
||||||
progression,
|
progression,
|
||||||
resets: resets.data,
|
resets: resets.data,
|
||||||
lessons,
|
lessons,
|
||||||
reviews,
|
reviews,
|
||||||
more_things_to_review_at
|
more_things_to_review_at,
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: JSON.stringify(info)
|
body: JSON.stringify(info),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export { handler }
|
export {handler};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue