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

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. import { existsSync, readFileSync, writeFileSync } from 'fs';
  2. import { IKanji, WaniKani } from '@/wanikani';
  3. import yaml from 'js-yaml';
  4. interface ILevelMap {
  5. [category: string]: {
  6. [levelString: string]: string[];
  7. };
  8. }
  9. async function makeWaniKaniKanjiLevels(opts: { cache?: boolean } = {}) {
  10. const FILENAME = 'cache/wanikani-kanji.yaml';
  11. if (opts.cache && existsSync(FILENAME)) {
  12. return yaml.load(readFileSync(FILENAME, 'utf-8')) as ILevelMap;
  13. }
  14. const wkKanji = await new WaniKani()
  15. .subjects()
  16. .then((vs) => vs.filter((v) => v.object === 'kanji') as IKanji[]);
  17. const levelMap: ILevelMap = {};
  18. for (const k of wkKanji) {
  19. const { level, characters } = k.data;
  20. let category: string;
  21. if (level < 11) {
  22. category = '01-10: 快 PLEASANT';
  23. } else if (level < 21) {
  24. category = '11-21: 苦 PAINFUL';
  25. } else if (level < 31) {
  26. category = '21-30: 死 DEATH';
  27. } else if (level < 41) {
  28. category = '31-40: 地獄 HELL';
  29. } else if (level < 51) {
  30. category = '41-50: 天国 PARADISE';
  31. } else {
  32. category = '51-60: 現実 REALITY';
  33. }
  34. const catMap = levelMap[category] || {};
  35. const levelString = level.toString().padStart(2, '0');
  36. const ks = catMap[levelString] || [];
  37. ks.push(characters);
  38. catMap[levelString] = ks;
  39. levelMap[category] = catMap;
  40. }
  41. writeFileSync(
  42. FILENAME,
  43. yaml.dump(levelMap, {
  44. sortKeys: true,
  45. flowLevel: 2,
  46. }),
  47. );
  48. return levelMap;
  49. }
  50. export async function makeKanjiLevels(opts: { useBeyond: boolean }) {
  51. const wk = await makeWaniKaniKanjiLevels({ cache: true });
  52. const beyond = opts.useBeyond
  53. ? (yaml.load(readFileSync('assets/beyond.yaml', 'utf-8')) as ILevelMap)
  54. : {};
  55. const kanjiToLevel = new Map<
  56. string,
  57. {
  58. level: number;
  59. deckName: string;
  60. }
  61. >();
  62. const setKanjiToLevel = (lvMap: ILevelMap) => {
  63. Object.entries(lvMap).map(([cat, map]) => {
  64. Object.entries(map).map(([levelString, ks]) => {
  65. const level = Number(levelString);
  66. ks.map((k) => {
  67. let prev = kanjiToLevel.get(k);
  68. if (!prev || prev.level > level) {
  69. prev = {
  70. level,
  71. deckName: cat + '::' + levelString,
  72. };
  73. kanjiToLevel.set(k, prev);
  74. }
  75. });
  76. });
  77. });
  78. };
  79. setKanjiToLevel(wk);
  80. setKanjiToLevel(beyond);
  81. return kanjiToLevel;
  82. }
  83. export async function repairBeyond() {
  84. const beyond = yaml.load(
  85. readFileSync('cache/beyond.yaml', 'utf-8'),
  86. ) as Record<string, string>;
  87. const levelMap: ILevelMap = {};
  88. for (const [levelString, vs] of Object.entries(beyond)) {
  89. const level = Number(levelString);
  90. let category: string;
  91. if (level < 71) {
  92. category = '61-70: 無限 INFINITY';
  93. } else if (level < 76) {
  94. category = '71-75: 極度 BEYOND';
  95. } else {
  96. category = '76+: 名人 MASTERY';
  97. }
  98. const catMap = levelMap[category] || {};
  99. const ks = catMap[levelString] || [];
  100. ks.push(...vs);
  101. catMap[levelString] = ks;
  102. levelMap[category] = catMap;
  103. }
  104. writeFileSync(
  105. 'assets/beyond.yaml',
  106. yaml.dump(levelMap, {
  107. sortKeys: true,
  108. flowLevel: 2,
  109. }),
  110. );
  111. }
  112. if (require.main === module) {
  113. repairBeyond();
  114. }