|
|
@ -1,4 +1,4 @@ |
|
|
|
import fs from 'fs'; |
|
|
|
import { existsSync, readFileSync, writeFileSync } from 'fs'; |
|
|
|
|
|
|
|
import axios, { AxiosInstance } from 'axios'; |
|
|
|
|
|
|
@ -20,18 +20,20 @@ export class WaniKani { |
|
|
|
force?: boolean; |
|
|
|
} = {}) { |
|
|
|
const subjects = { |
|
|
|
data: [] as (IKanji | IRadical)[], |
|
|
|
data: [] as ISubject[], |
|
|
|
filename: 'cache/wanikani.json', |
|
|
|
load() { |
|
|
|
this.data = JSON.parse(fs.readFileSync(this.filename, 'utf-8')); |
|
|
|
this.data = existsSync(this.filename) |
|
|
|
? JSON.parse(readFileSync(this.filename, 'utf-8')) |
|
|
|
: []; |
|
|
|
return this.data; |
|
|
|
}, |
|
|
|
dump(d: (IKanji | IRadical)[]) { |
|
|
|
dump(d: ISubject[]) { |
|
|
|
this.data = d; |
|
|
|
this.finalize(); |
|
|
|
}, |
|
|
|
finalize() { |
|
|
|
fs.writeFileSync(this.filename, JSON.stringify(this.data)); |
|
|
|
writeFileSync(this.filename, JSON.stringify(this.data)); |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
@ -41,14 +43,14 @@ export class WaniKani { |
|
|
|
} |
|
|
|
data = []; |
|
|
|
|
|
|
|
let nextURL = '/subjects?types=radical,kanji'; |
|
|
|
let nextURL = '/subjects'; |
|
|
|
while (nextURL) { |
|
|
|
const r = await this.$axios |
|
|
|
.get<{ |
|
|
|
pages: { |
|
|
|
next_url?: string; |
|
|
|
}; |
|
|
|
data: (IKanji | IRadical)[]; |
|
|
|
data: ISubject[]; |
|
|
|
}>(nextURL) |
|
|
|
.then((r) => r.data); |
|
|
|
data.push(...r.data); |
|
|
@ -61,52 +63,95 @@ export class WaniKani { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
export interface IKanji { |
|
|
|
id: number; |
|
|
|
/** Actual type */ |
|
|
|
object: 'kanji'; |
|
|
|
type WaniKaniDate = string; |
|
|
|
type Integer = number; |
|
|
|
type Level = Integer; |
|
|
|
type SubjectID = Integer; |
|
|
|
|
|
|
|
interface IMeaning { |
|
|
|
meaning: string; |
|
|
|
primary: boolean; |
|
|
|
} |
|
|
|
|
|
|
|
interface ISubjectBase< |
|
|
|
T extends 'radical' | 'kanji' | 'vocabulary', |
|
|
|
Data extends {}, |
|
|
|
> { |
|
|
|
id: SubjectID; |
|
|
|
object: T; |
|
|
|
url: string; |
|
|
|
data_updated_at: string; |
|
|
|
data_updated_at: WaniKaniDate; |
|
|
|
data: { |
|
|
|
level: number; |
|
|
|
document_url: string; |
|
|
|
auxillary_meanings: IMeaning[]; |
|
|
|
characters: string; |
|
|
|
meanings: { |
|
|
|
meaning: string; |
|
|
|
primary: boolean; |
|
|
|
created_at: WaniKaniDate; |
|
|
|
document_url: string; |
|
|
|
hidden_at: WaniKaniDate | null; |
|
|
|
lesson_position: Integer; |
|
|
|
level: Level; |
|
|
|
meaning_mnemonic: string; |
|
|
|
meanings: IMeaning[]; |
|
|
|
slug: string; |
|
|
|
spaced_repetition_system_id: Integer; |
|
|
|
} & Data; |
|
|
|
} |
|
|
|
|
|
|
|
export type IRadical = ISubjectBase< |
|
|
|
'radical', |
|
|
|
{ |
|
|
|
character_images: { |
|
|
|
url: string; |
|
|
|
metadata: { |
|
|
|
inline_styles?: boolean; |
|
|
|
dimensions?: string; |
|
|
|
}; |
|
|
|
content_type: string; |
|
|
|
}[]; |
|
|
|
amalgamation_subject_ids: SubjectID[]; |
|
|
|
} |
|
|
|
>; |
|
|
|
|
|
|
|
export type IKanji = ISubjectBase< |
|
|
|
'kanji', |
|
|
|
{ |
|
|
|
readings: { |
|
|
|
reading: string; |
|
|
|
primary: boolean; |
|
|
|
type: 'kunyomi' | 'onyomi'; |
|
|
|
}[]; |
|
|
|
component_subject_ids: number[]; |
|
|
|
visually_similar_subject_ids: number[]; |
|
|
|
}; |
|
|
|
} |
|
|
|
component_subject_ids: SubjectID[]; |
|
|
|
visually_similar_subject_ids: SubjectID[]; |
|
|
|
} |
|
|
|
>; |
|
|
|
|
|
|
|
export interface IRadical { |
|
|
|
id: number; |
|
|
|
/** Actual type */ |
|
|
|
object: 'radical'; |
|
|
|
url: string; |
|
|
|
data_updated_at: string; |
|
|
|
data: { |
|
|
|
level: number; |
|
|
|
document_url: string; |
|
|
|
characters: string | null; |
|
|
|
character_images: { |
|
|
|
export type IVocabulary = ISubjectBase< |
|
|
|
'vocabulary', |
|
|
|
{ |
|
|
|
component_subject_ids: SubjectID[]; |
|
|
|
context_sentences: { |
|
|
|
en: string; |
|
|
|
ja: string; |
|
|
|
}[]; |
|
|
|
part_of_speech: string[]; |
|
|
|
pronunciation_audios: { |
|
|
|
url: string; |
|
|
|
metadata: { |
|
|
|
inline_styles?: boolean; |
|
|
|
dimensions?: string; |
|
|
|
gender: 'male' | 'female'; |
|
|
|
source_id: Integer; |
|
|
|
pronunciation: string; |
|
|
|
voice_actor_id: Integer; |
|
|
|
voice_actor_name: string; |
|
|
|
voice_description: string; |
|
|
|
}; |
|
|
|
content_type: string; |
|
|
|
content_type: 'audio/mpeg' | 'audio/ogg'; |
|
|
|
}[]; |
|
|
|
meanings: { |
|
|
|
meaning: string; |
|
|
|
readings: { |
|
|
|
accepted_answer: boolean; |
|
|
|
primary: boolean; |
|
|
|
reading: string; |
|
|
|
}[]; |
|
|
|
amalgamation_subject_ids: number[]; |
|
|
|
}; |
|
|
|
} |
|
|
|
reading_mnemonic: string; |
|
|
|
} |
|
|
|
>; |
|
|
|
|
|
|
|
export type ISubject = IRadical | IKanji | IVocabulary; |