Extra contents beyond WaniKani
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

152 lines
3.5 KiB

import fs from 'fs';
import { IKanji, IRadical, WaniKani } from '@/wanikani';
import yaml from 'js-yaml';
import { toKatakana } from 'wanakana';
interface IItem {
document_url: string;
level: number;
meaning: string;
reading?: string;
components: {
[source: string]: string[];
};
similar: string[];
image?: {
src: string;
content_type: string;
width: string | undefined;
height: string | undefined;
};
}
interface IBeautifiedRadicals {
[id: string]: IItem;
}
export const radicals = {
data: {} as IBeautifiedRadicals,
filename: 'radicals.yaml',
load() {
this.data = yaml.load(
fs.readFileSync(this.filename, 'utf-8'),
) as IBeautifiedRadicals;
return this.data;
},
dump(d: IBeautifiedRadicals) {
this.data = d;
this.finalize();
},
finalize() {
fs.writeFileSync(
this.filename,
yaml.dump(this.data, {
skipInvalid: true,
}),
);
},
};
async function main() {
const rs = await new WaniKani().subjects();
const idMap = new Map<number, string>();
radicals.data = {};
rs.filter((r) => r.object === 'radical').map((r0) => {
const r = r0 as IRadical;
const d = {
document_url: r.data.document_url,
level: r.data.level,
meaning: r.data.meanings.filter((m) => m.primary)[0]!.meaning,
components: {},
sup: r.data.amalgamation_subject_ids.map((it) => it.toString()),
similar: [],
};
let id = r.data.characters;
if (id) {
radicals.data[id] = d;
} else {
id = d.meaning;
const st = (im: {
content_type: string;
metadata: { dimensions?: string };
}) =>
im.content_type === 'image/svg+xml'
? 5000
: im.metadata.dimensions
? Math.min(...im.metadata.dimensions.split('x').map(Number))
: 0;
const im = r.data.character_images.sort((a, b) => st(a) - st(b))[0]!;
const dim = im.metadata.dimensions?.split('x') || [];
radicals.data[id] = {
...d,
image: {
src: im.url,
content_type: im.content_type,
width: dim[0],
height: dim[1],
},
};
}
idMap.set(r.id, id);
});
rs.filter((r) => r.object === 'kanji').map((r0) => {
const r = r0 as IKanji;
const reading = r.data.readings.filter((m) => m.primary)[0]!;
const d = {
document_url: r.data.document_url,
level: r.data.level,
meaning: r.data.meanings.filter((m) => m.primary)[0]!.meaning,
reading:
reading.type === 'onyomi'
? toKatakana(reading.reading)
: reading.reading,
components: {
wanikani: r.data.component_subject_ids.map((it) => it.toString()),
},
similar: r.data.visually_similar_subject_ids.map((it) => it.toString()),
};
const id = r.data.characters;
idMap.set(r.id, id);
// const prev = radicals.data[id]
// if (prev) {
// radicals.data[id] = {
// ...d,
// sup: prev.sup
// }
// } else {
// radicals.data[id] = {
// ...d,
// sup: []
// }
// }
radicals.data[id] = d;
});
for (const [k, v] of Object.entries(radicals.data)) {
if (v.components?.['wanikani']) {
v.components['wanikani'] = v.components['wanikani']
.map((s) => idMap.get(Number(s)) || s)
.filter((s) => s !== k);
}
v.similar = v.similar.map((s) => idMap.get(Number(s)) || s);
// v.sup = v.sup.map((s) => idMap.get(Number(s)) || s)
}
radicals.finalize();
}
if (require.main === module) {
main();
}