Browse Source

add vocabulary to subjects

main
parent
commit
92c1de3d1f
2 changed files with 89 additions and 42 deletions
  1. +4
    -2
      scripts/get-kanji-level.ts
  2. +85
    -40
      src/wanikani.ts

+ 4
- 2
scripts/get-kanji-level.ts View File

@ -9,14 +9,16 @@ interface ILevelMap {
}; };
} }
async function makeWaniKaniKanjiLevels(opts: { cache?: boolean } = {}) {
async function makeWaniKaniKanjiLevels(
opts: { cache?: boolean; force?: boolean } = {},
) {
const FILENAME = 'cache/wanikani-kanji.yaml'; const FILENAME = 'cache/wanikani-kanji.yaml';
if (opts.cache && existsSync(FILENAME)) { if (opts.cache && existsSync(FILENAME)) {
return yaml.load(readFileSync(FILENAME, 'utf-8')) as ILevelMap; return yaml.load(readFileSync(FILENAME, 'utf-8')) as ILevelMap;
} }
const wkKanji = await new WaniKani() const wkKanji = await new WaniKani()
.subjects()
.subjects({ force: !!opts.force })
.then((vs) => vs.filter((v) => v.object === 'kanji') as IKanji[]); .then((vs) => vs.filter((v) => v.object === 'kanji') as IKanji[]);
const levelMap: ILevelMap = {}; const levelMap: ILevelMap = {};

+ 85
- 40
src/wanikani.ts View File

@ -1,4 +1,4 @@
import fs from 'fs';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import axios, { AxiosInstance } from 'axios'; import axios, { AxiosInstance } from 'axios';
@ -20,18 +20,20 @@ export class WaniKani {
force?: boolean; force?: boolean;
} = {}) { } = {}) {
const subjects = { const subjects = {
data: [] as (IKanji | IRadical)[],
data: [] as ISubject[],
filename: 'cache/wanikani.json', filename: 'cache/wanikani.json',
load() { 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; return this.data;
}, },
dump(d: (IKanji | IRadical)[]) {
dump(d: ISubject[]) {
this.data = d; this.data = d;
this.finalize(); this.finalize();
}, },
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 = []; data = [];
let nextURL = '/subjects?types=radical,kanji';
let nextURL = '/subjects';
while (nextURL) { while (nextURL) {
const r = await this.$axios const r = await this.$axios
.get<{ .get<{
pages: { pages: {
next_url?: string; next_url?: string;
}; };
data: (IKanji | IRadical)[];
data: ISubject[];
}>(nextURL) }>(nextURL)
.then((r) => r.data); .then((r) => r.data);
data.push(...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; url: string;
data_updated_at: string;
data_updated_at: WaniKaniDate;
data: { data: {
level: number;
document_url: string;
auxillary_meanings: IMeaning[];
characters: string; 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: { readings: {
reading: string; reading: string;
primary: boolean; primary: boolean;
type: 'kunyomi' | 'onyomi'; 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; url: string;
metadata: { 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; primary: boolean;
reading: string;
}[]; }[];
amalgamation_subject_ids: number[];
};
}
reading_mnemonic: string;
}
>;
export type ISubject = IRadical | IKanji | IVocabulary;

Loading…
Cancel
Save