Browse Source

add tag adder

main
parent
commit
16d1307744
4 changed files with 148 additions and 26 deletions
  1. +4
    -16
      scripts/get-kanji-level.ts
  2. +3
    -10
      scripts/populate-from-wanikani.ts
  3. +5
    -0
      src/level.ts
  4. +136
    -0
      src/wanikani.ts

+ 4
- 16
scripts/get-kanji-level.ts View File

@ -25,24 +25,12 @@ async function makeWaniKaniKanjiLevels(
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 label = WaniKani.getLevelLabel(level);
const category = `${label.range}: ${
label.ja
} ${label.en.toLocaleUpperCase()}`;
const catMap = levelMap[category] || {};
const levelString = level.toString().padStart(2, '0');
const ks = catMap[levelString] || [];

+ 3
- 10
scripts/populate-from-wanikani.ts View File

@ -6,14 +6,7 @@ if (require.main === module) {
// { ja: 'Japanese', audio: 'JapaneseAudio' },
// { mode: { online: true } },
// );
new WaniKani().populateSentence(
'note:jp.takoboto',
{
vocabJa: 'Japanese',
sentenceJa: 'Sentence',
sentenceAudio: 'SentenceAudio',
sentenceEn: 'SentenceMeaning',
},
{ overwrite: true },
);
new WaniKani().addTags('note:jp.takoboto', {
ja: 'Japanese',
});
}

+ 5
- 0
src/level.ts View File

@ -0,0 +1,5 @@
export interface ILevelLabel {
range: string;
ja: string;
en: string;
}

+ 136
- 0
src/wanikani.ts View File

@ -4,6 +4,7 @@ import axios, { AxiosInstance } from 'axios';
import { soundTag } from './anki';
import { AnkiConnect, IAnkiConnectActions } from './ankiconnect';
import { ILevelLabel } from './level';
import { logger } from './logger';
export class WaniKani {
@ -18,6 +19,48 @@ export class WaniKani {
});
}
static getLevelLabel(level: number): ILevelLabel {
if (level < 11) {
return {
range: '01-10',
ja: '快',
en: 'PLEASANT',
};
} else if (level < 21) {
return {
range: '11-20',
ja: '苦',
en: 'PAINFUL',
};
} else if (level < 31) {
return {
range: '21-30',
ja: '死',
en: 'DEATH',
};
} else if (level < 41) {
return {
range: '31-40',
ja: '地獄',
en: 'HELL',
};
} else if (level < 51) {
return {
range: '41-50',
ja: '天国',
en: 'PARADISE',
};
} else if (level < 61) {
return {
range: '51-60',
ja: '現実',
en: 'REALITY',
};
}
throw new Error(`invalid level: ${level}`);
}
async subjects({
force,
}: {
@ -239,6 +282,99 @@ export class WaniKani {
});
});
}
async addTags(
query: string,
fields: {
ja: string;
},
) {
const subjects = await this.subjects();
const vocabularies = subjects.filter(
(s) => s.object === 'vocabulary',
) as IVocabulary[];
const vocabMap = new Map<
string,
{
level: number;
label: ILevelLabel;
}
>();
vocabularies.map((v) => {
if (vocabMap.has(v.data.characters)) return;
vocabMap.set(v.data.characters, {
level: v.data.level,
label: WaniKani.getLevelLabel(v.data.level),
});
});
if (!vocabMap.size) return;
query += ` -${fields.ja}:`;
const anki = new AnkiConnect();
anki
.api('findNotes', {
query,
})
.then((notes) => anki.api('notesInfo', { notes }))
.then(async (notes) => {
const notesToUpdate: {
id: SubjectID;
tags: string[];
}[] = [];
for (const n of notes) {
const { value: ja } = n.fields[fields.ja] || {};
if (ja) {
const vocab = vocabMap.get(
ja.replace(/\[.+?\]/g, '').replace(/ /g, ''),
);
if (vocab) {
notesToUpdate.push({
id: n.noteId,
tags: [
'wanikani',
`level-${vocab.level}`,
`wanikani-level-${vocab.level}`,
`wanikani-level-${vocab.label.range}-${vocab.label.ja}`,
`wanikani-level-${
vocab.label.range
}-${vocab.label.en.toLocaleLowerCase()}`,
],
});
}
}
}
if (!notesToUpdate.length) return;
const addTagsMap = new Map<
string,
{
notes: SubjectID[];
tags: string;
}
>();
notesToUpdate.map(({ id, tags }) => {
const identifier = JSON.stringify(tags);
const v = addTagsMap.get(identifier) || {
notes: [],
tags: tags.join(' '),
};
v.notes.push(id);
addTagsMap.set(identifier, v);
});
await anki.multi<'addTags'[]>({
actions: Array.from(addTagsMap.values()).map((params) => ({
action: 'addTags',
params,
})),
});
});
}
}
type WaniKaniDate = string;

Loading…
Cancel
Save