Helps with eventually adding other pages Also makes it clear it's the backend that decides what data to send to the frontend
131 linhas
3,7 KiB
TypeScript
131 linhas
3,7 KiB
TypeScript
import type { WKLevelProgression, WKReset, WKResetCollection, WKSummary } from "@bachmacintosh/wanikani-api-types";
|
|
import { headers, parseJson, type Handler } from "../..";
|
|
|
|
export type Info = {
|
|
progression: {
|
|
total_count: number;
|
|
data: WKLevelProgression[];
|
|
};
|
|
resets: WKReset[];
|
|
lessons: Item[];
|
|
reviews: Item[];
|
|
moreThingsToReviewAt: string | null;
|
|
} | undefined;
|
|
|
|
export interface Item {
|
|
available_at: string;
|
|
type: string;
|
|
writing: string;
|
|
meanings: {
|
|
meaning: string;
|
|
}[];
|
|
url: string;
|
|
}
|
|
|
|
interface Subject {
|
|
id: number;
|
|
object: string;
|
|
data: {
|
|
characters: string;
|
|
slug: string;
|
|
document_url: string;
|
|
meanings: {
|
|
meaning: string;
|
|
}[];
|
|
};
|
|
}
|
|
|
|
interface StuffToLearn {
|
|
available_at: string;
|
|
type: string;
|
|
writing: string;
|
|
meanings: {
|
|
meaning: string;
|
|
}[];
|
|
url: string;
|
|
}
|
|
|
|
function addStuffToLearn(ids: number[], data: {available_at: string; subject_ids: number[]}[], subjects: Subject[]): StuffToLearn[] {
|
|
const arr: StuffToLearn[] = [];
|
|
|
|
for (const id of ids) {
|
|
const summaryData = data.find(lesson => lesson.subject_ids.includes(id));
|
|
const subject = subjects.find(subject => subject.id === id);
|
|
if (!summaryData || !subject) {
|
|
console.error("Failed: ", summaryData, subject);
|
|
continue;
|
|
}
|
|
|
|
arr.push({
|
|
available_at: summaryData.available_at,
|
|
type: subject.object,
|
|
writing: subject.data.characters || subject.data.slug || subject.data.meanings[0].meaning,
|
|
meanings: subject.data.meanings,
|
|
url: subject.data.document_url,
|
|
});
|
|
}
|
|
|
|
return arr;
|
|
}
|
|
|
|
export const wanikani: Handler = async () => {
|
|
const urlsToRequest = [
|
|
"https://api.wanikani.com/v2/level_progressions",
|
|
"https://api.wanikani.com/v2/resets",
|
|
"https://api.wanikani.com/v2/summary",
|
|
];
|
|
const toRequest = urlsToRequest.map((url) => new Promise(async (resolve) => {
|
|
const response = await fetch(url, {headers: {
|
|
...headers,
|
|
"Authorization": `Bearer ${process.env["API_WANIKANI"]}`,
|
|
}});
|
|
resolve(await parseJson(response));
|
|
}));
|
|
|
|
const data = await Promise.all(toRequest);
|
|
const progression = data[0] as {
|
|
total_count: number;
|
|
data: WKLevelProgression[];
|
|
};
|
|
const resets = data[1] as WKResetCollection;
|
|
const summary = data[2] as WKSummary;
|
|
|
|
const subjectIdsLessons: number[] = [];
|
|
for (const lesson of summary.data.lessons) {
|
|
for (const subjectId of lesson.subject_ids) {
|
|
subjectIdsLessons.push(subjectId);
|
|
}
|
|
}
|
|
|
|
const subjectIdsReviews: number[] = [];
|
|
for (const review of summary.data.reviews) {
|
|
for (const subjectId of review.subject_ids) {
|
|
subjectIdsReviews.push(subjectId);
|
|
}
|
|
}
|
|
|
|
// 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
|
|
const now = new Date();
|
|
const nextReviews = summary.data.reviews.filter((r) => new Date(r.available_at) > now && r.subject_ids.length);
|
|
const moreThingsToReviewAt = nextReviews.at(0)?.available_at ?? summary.data.next_reviews_at;
|
|
|
|
const subjectIdsAll = subjectIdsLessons.concat(subjectIdsReviews);
|
|
const subjects = await parseJson(await fetch(`https://api.wanikani.com/v2/subjects?ids=${subjectIdsAll.toString()}`, {headers: {
|
|
...headers,
|
|
"Authorization": `Bearer ${process.env["API_WANIKANI"]}`,
|
|
}})) as {data: Subject[]};
|
|
|
|
const lessons = addStuffToLearn(subjectIdsLessons, summary.data.lessons, subjects.data);
|
|
const reviews = addStuffToLearn(subjectIdsReviews, summary.data.reviews, subjects.data);
|
|
|
|
const info: Info = {
|
|
progression,
|
|
resets: resets.data,
|
|
lessons,
|
|
reviews,
|
|
moreThingsToReviewAt,
|
|
};
|
|
|
|
return Response.json(info, {status: 200});
|
|
};
|