|
|
@ -1,30 +1,28 @@ |
|
|
|
import fs from 'fs' |
|
|
|
import fs from 'fs'; |
|
|
|
|
|
|
|
import yaml from 'js-yaml' |
|
|
|
import { toKatakana } from 'wanakana' |
|
|
|
|
|
|
|
import { subjects } from './dump-subjects' |
|
|
|
import { IKanji, IRadical } from './shared' |
|
|
|
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 |
|
|
|
document_url: string; |
|
|
|
level: number; |
|
|
|
meaning: string; |
|
|
|
reading?: string; |
|
|
|
components: { |
|
|
|
[source: string]: string[] |
|
|
|
} |
|
|
|
similar: string[] |
|
|
|
[source: string]: string[]; |
|
|
|
}; |
|
|
|
similar: string[]; |
|
|
|
image?: { |
|
|
|
src: string |
|
|
|
content_type: string |
|
|
|
width: string | undefined |
|
|
|
height: string | undefined |
|
|
|
} |
|
|
|
src: string; |
|
|
|
content_type: string; |
|
|
|
width: string | undefined; |
|
|
|
height: string | undefined; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
interface IBeautifiedRadicals { |
|
|
|
[id: string]: IItem |
|
|
|
[id: string]: IItem; |
|
|
|
} |
|
|
|
|
|
|
|
export const radicals = { |
|
|
@ -32,59 +30,59 @@ export const radicals = { |
|
|
|
filename: 'radicals.yaml', |
|
|
|
load() { |
|
|
|
this.data = yaml.load( |
|
|
|
fs.readFileSync(this.filename, 'utf-8') |
|
|
|
) as IBeautifiedRadicals |
|
|
|
return this.data |
|
|
|
fs.readFileSync(this.filename, 'utf-8'), |
|
|
|
) as IBeautifiedRadicals; |
|
|
|
return this.data; |
|
|
|
}, |
|
|
|
dump(d: IBeautifiedRadicals) { |
|
|
|
this.data = d |
|
|
|
this.finalize() |
|
|
|
this.data = d; |
|
|
|
this.finalize(); |
|
|
|
}, |
|
|
|
finalize() { |
|
|
|
fs.writeFileSync( |
|
|
|
this.filename, |
|
|
|
yaml.dump(this.data, { |
|
|
|
skipInvalid: true |
|
|
|
}) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
skipInvalid: true, |
|
|
|
}), |
|
|
|
); |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
async function main() { |
|
|
|
const rs = subjects.load() |
|
|
|
const rs = await new WaniKani().subjects(); |
|
|
|
|
|
|
|
const idMap = new Map<number, string>() |
|
|
|
radicals.data = {} |
|
|
|
const idMap = new Map<number, string>(); |
|
|
|
radicals.data = {}; |
|
|
|
|
|
|
|
rs.filter((r) => r.object === 'radical').map((r0) => { |
|
|
|
const r = r0 as IRadical |
|
|
|
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: [] |
|
|
|
} |
|
|
|
similar: [], |
|
|
|
}; |
|
|
|
|
|
|
|
let id = r.data.characters |
|
|
|
let id = r.data.characters; |
|
|
|
|
|
|
|
if (id) { |
|
|
|
radicals.data[id] = d |
|
|
|
radicals.data[id] = d; |
|
|
|
} else { |
|
|
|
id = d.meaning |
|
|
|
id = d.meaning; |
|
|
|
|
|
|
|
const st = (im: { |
|
|
|
content_type: string |
|
|
|
metadata: { dimensions?: string } |
|
|
|
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') || [] |
|
|
|
: 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, |
|
|
@ -92,17 +90,17 @@ async function main() { |
|
|
|
src: im.url, |
|
|
|
content_type: im.content_type, |
|
|
|
width: dim[0], |
|
|
|
height: dim[1] |
|
|
|
} |
|
|
|
} |
|
|
|
height: dim[1], |
|
|
|
}, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
idMap.set(r.id, id) |
|
|
|
}) |
|
|
|
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 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, |
|
|
@ -112,13 +110,13 @@ async function main() { |
|
|
|
? toKatakana(reading.reading) |
|
|
|
: reading.reading, |
|
|
|
components: { |
|
|
|
wanikani: r.data.component_subject_ids.map((it) => it.toString()) |
|
|
|
wanikani: r.data.component_subject_ids.map((it) => it.toString()), |
|
|
|
}, |
|
|
|
similar: r.data.visually_similar_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 id = r.data.characters; |
|
|
|
idMap.set(r.id, id); |
|
|
|
// const prev = radicals.data[id]
|
|
|
|
|
|
|
|
// if (prev) {
|
|
|
@ -133,22 +131,22 @@ async function main() { |
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
radicals.data[id] = d |
|
|
|
}) |
|
|
|
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) |
|
|
|
.filter((s) => s !== k); |
|
|
|
} |
|
|
|
v.similar = v.similar.map((s) => idMap.get(Number(s)) || s) |
|
|
|
v.similar = v.similar.map((s) => idMap.get(Number(s)) || s); |
|
|
|
// v.sup = v.sup.map((s) => idMap.get(Number(s)) || s)
|
|
|
|
} |
|
|
|
|
|
|
|
radicals.finalize() |
|
|
|
radicals.finalize(); |
|
|
|
} |
|
|
|
|
|
|
|
if (require.main === module) { |
|
|
|
main() |
|
|
|
main(); |
|
|
|
} |