import { AnkiConnect } from '@/ankiconnect'; export async function listTags( query = 'deck:Takoboto -Takoboto: tag:common -tag:reading-challenge -tag:favorites -tag:death-note -tag:ハピネス -tag:https://www.bunka.go.jp/seisaku/bunkashingikai/kokugo/hokoku/pdf/ijidokun_140221.pdf', ) { const anki = new AnkiConnect(); return anki .api('findNotes', { query, }) .then((notes) => anki.api('notesInfo', { notes })) .then((notes) => { return new Set(notes.flatMap((n) => n.tags)); }); } const soundTag = { pre: '[sound:', post: ']', is(src: string) { return src.startsWith(this.pre) && src.endsWith(this.post); }, add(src: string) { if (soundTag.is(src)) return src; return this.pre + src + this.post; }, remove(src: string) { if (!soundTag.is(src)) return src; if (this.isEmpty(src)) return src; return src.substring(this.pre.length, src.length - this.post.length); }, isEmpty(src: string) { return src === this.pre + this.post; }, }; export async function addSoundTag(query: string, fieldNames: string[]) { query += ' (' + fieldNames.map((f) => `-${f}:`).join(' OR ') + ')'; const anki = new AnkiConnect(); anki .api('findNotes', { query, }) .then((notes) => anki.api('notesInfo', { notes })) .then((notes) => { const notesToUpdate: { id: number; fields: Record; }[] = []; for (const n of notes) { let toUpdate: typeof notesToUpdate[0] | undefined; fieldNames.map((fieldName: string) => { const field = n.fields[fieldName]; if (field) { const { value } = field; if (!soundTag.is(value)) { toUpdate = toUpdate || { id: n.noteId, fields: {} }; toUpdate.fields[fieldName] = soundTag.add(value); } } }); if (toUpdate) { notesToUpdate.push(toUpdate); } } if (!notesToUpdate.length) return; return anki.multi<'updateNoteFields'[]>({ actions: notesToUpdate.map((note) => ({ action: 'updateNoteFields', params: { note, }, })), }); }); } if (require.main === module) { addSoundTag('jp.takoboto', ['SentenceAudio', 'JapaneseAudio']); }