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();
|
|
}
|