diff --git a/scripts/sort-anki.ts b/scripts/sort-anki.ts index 73bcdea..863a649 100644 --- a/scripts/sort-anki.ts +++ b/scripts/sort-anki.ts @@ -1,24 +1,69 @@ import { AnkiConnect } from '@/ankiconnect'; +const DECK = 'Takoboto'; + async function main() { const anki = new AnkiConnect(); + console.log( - await anki.multi<['findNotes', 'getTags']>({ - actions: [ - { - action: 'findNotes', - params: { - query: 'added:1', - }, - }, - { action: 'getTags' }, - ], - }), - ); - console.log( - await anki.api('findNotes', { - query: 'deck:Takoboto', - }), + await anki + .api('findCards', { + query: `deck:${DECK}`, + }) + .then((cards) => anki.api('cardsInfo', { cards })) + .then((rs) => { + const modelToSubdecks = new Map< + string, + { + [subdeck: string]: number[]; + } + >(); + rs.map((r) => { + const vs = modelToSubdecks.get(r.modelName) || {}; + // Get the subdeck names from Kanji + const subdeck = '???'; + vs[subdeck] = vs[subdeck] || []; + vs[subdeck]!.push(r.cardId); + modelToSubdecks.set(r.modelName, vs); + }); + + return Promise.all( + Array.from(modelToSubdecks).map(([modelName, subdecks]) => + anki.api('modelTemplates', { modelName }).then((templates) => + Object.entries(subdecks).map(([subdeck, cardIds]) => ({ + modelName, + templateNames: Object.keys(templates), + subdeck, + cardIdsSet: new Set(cardIds), + })), + ), + ), + ); + }) + .then((rs) => { + return Promise.all( + rs + .flat() + .flatMap((r) => + r.templateNames.map((templateName) => ({ + ...r, + templateName, + })), + ) + .map(({ templateName, subdeck, cardIdsSet }) => + anki + .api('findCards', { + query: `deck:${DECK} card:${templateName}`, + }) + .then((cards) => + anki.api('changeDeck', { + cards: cards.filter((c) => cardIdsSet.has(c)), + deck: `${DECK}::${subdeck}::${templateName}`, + }), + ), + ), + ); + }), ); } diff --git a/src/ankiconnect.ts b/src/ankiconnect.ts index 3aa7435..d2891cb 100644 --- a/src/ankiconnect.ts +++ b/src/ankiconnect.ts @@ -10,6 +10,44 @@ export interface IAnkiConnectActions result: unknown; } > { + // Card Actions + cardsInfo: { + params: { + cards: number[]; + }; + result: { + answer: string; + question: string; + deckName: string; + modelName: string; + fieldOrder: number; + fields: { + [fieldName: string]: { + value: string; + order: number; + }; + }; + css: string; + cardId: number; + interval: number; + note: number; + ord: number; + type: number; + queue: number; + due: number; + reps: number; + lapses: number; + left: number; + mod: number; + }[]; + }; + findCards: { + params: { + query: IAnkiQuery; + }; + result: number[]; + }; + // Deck Actions deckNames: { result: string[]; @@ -427,7 +465,7 @@ export class AnkiConnect { } /** - * Strongly-typed usage is via `[string, tuple]`: + * Strongly-typed usage is via `<[action1, action2, ...]>`: * * ```typescript * await new AnkiConnect().multi<['findNotes', 'getTags']>({