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.
 
 
 
 

140 lines
3.2 KiB

import { existsSync, readFileSync, writeFileSync } from 'fs';
import { IKanji, WaniKani } from '@/wanikani';
import yaml from 'js-yaml';
interface ILevelMap {
[category: string]: {
[levelString: string]: string[];
};
}
async function makeWaniKaniKanjiLevels(opts: { cache?: boolean } = {}) {
const FILENAME = 'cache/wanikani-kanji.yaml';
if (opts.cache && existsSync(FILENAME)) {
return yaml.load(readFileSync(FILENAME, 'utf-8')) as ILevelMap;
}
const wkKanji = await new WaniKani()
.subjects()
.then((vs) => vs.filter((v) => v.object === 'kanji') as IKanji[]);
const levelMap: ILevelMap = {};
for (const k of wkKanji) {
const { level, characters } = k.data;
let category: string;
if (level < 11) {
category = '01-10: 快 PLEASANT';
} else if (level < 21) {
category = '11-21: 苦 PAINFUL';
} else if (level < 31) {
category = '21-30: 死 DEATH';
} else if (level < 41) {
category = '31-40: 地獄 HELL';
} else if (level < 51) {
category = '41-50: 天国 PARADISE';
} else {
category = '51-60: 現実 REALITY';
}
const catMap = levelMap[category] || {};
const levelString = level.toString().padStart(2, '0');
const ks = catMap[levelString] || [];
ks.push(characters);
catMap[levelString] = ks;
levelMap[category] = catMap;
}
writeFileSync(
FILENAME,
yaml.dump(levelMap, {
sortKeys: true,
flowLevel: 2,
}),
);
return levelMap;
}
export async function makeKanjiLevels(opts: { useBeyond: boolean }) {
const wk = await makeWaniKaniKanjiLevels({ cache: true });
const beyond = opts.useBeyond
? (yaml.load(readFileSync('assets/beyond.yaml', 'utf-8')) as ILevelMap)
: {};
const kanjiToLevel = new Map<
string,
{
level: number;
deckName: string;
}
>();
const setKanjiToLevel = (lvMap: ILevelMap) => {
Object.entries(lvMap).map(([cat, map]) => {
Object.entries(map).map(([levelString, ks]) => {
const level = Number(levelString);
ks.map((k) => {
let prev = kanjiToLevel.get(k);
if (!prev || prev.level > level) {
prev = {
level,
deckName: cat + '::' + levelString,
};
kanjiToLevel.set(k, prev);
}
});
});
});
};
setKanjiToLevel(wk);
setKanjiToLevel(beyond);
return kanjiToLevel;
}
export async function repairBeyond() {
const beyond = yaml.load(
readFileSync('cache/beyond.yaml', 'utf-8'),
) as Record<string, string>;
const levelMap: ILevelMap = {};
for (const [levelString, vs] of Object.entries(beyond)) {
const level = Number(levelString);
let category: string;
if (level < 71) {
category = '61-70: 無限 INFINITY';
} else if (level < 76) {
category = '71-75: 極度 BEYOND';
} else {
category = '76+: 名人 MASTERY';
}
const catMap = levelMap[category] || {};
const ks = catMap[levelString] || [];
ks.push(...vs);
catMap[levelString] = ks;
levelMap[category] = catMap;
}
writeFileSync(
'assets/beyond.yaml',
yaml.dump(levelMap, {
sortKeys: true,
flowLevel: 2,
}),
);
}
if (require.main === module) {
repairBeyond();
}