prototype subdeck from Kanji
This commit is contained in:
1 parent
f427a8e148
commit
13f2bb421c
4 files changed
+148
-84
No files matched your search
+120
-83
@@ -1,4 +1,4 @@
|
||||
import { AnkiConnect } from '@/ankiconnect';
|
||||
import { AnkiConnect, IAnkiConnectActions } from '@/ankiconnect';
|
||||
|
||||
import { makeKanjiLevels } from './get-kanji-level';
|
||||
|
||||
@@ -8,95 +8,132 @@ const KANJI_FIELD = 'Japanese';
|
||||
async function main() {
|
||||
const anki = new AnkiConnect();
|
||||
|
||||
console.log(
|
||||
await anki
|
||||
.api('findCards', {
|
||||
query: `deck:${DECK}`,
|
||||
})
|
||||
.then((cards) => anki.api('cardsInfo', { cards }))
|
||||
.then(async (rs) => {
|
||||
const kanjiLevels = await makeKanjiLevels();
|
||||
const deckConfig = await anki.api('getDeckConfig', {
|
||||
deck: DECK,
|
||||
});
|
||||
|
||||
const modelToSubdecks = new Map<
|
||||
string,
|
||||
{
|
||||
[subdeck: string]: number[];
|
||||
}
|
||||
>();
|
||||
rs.map((r) => {
|
||||
const vs = modelToSubdecks.get(r.modelName) || {};
|
||||
const { value } = r.fields[KANJI_FIELD] || {};
|
||||
if (value) {
|
||||
// Get the subdeck names from Kanji
|
||||
let subdeck = '';
|
||||
let level = 0;
|
||||
await anki
|
||||
.api('findCards', {
|
||||
query: `deck:${DECK}`,
|
||||
})
|
||||
.then((cards) => anki.api('cardsInfo', { cards }))
|
||||
.then(async (rs) => {
|
||||
const kanjiLevels = await makeKanjiLevels();
|
||||
|
||||
Array.from(value).map((k) => {
|
||||
const m = kanjiLevels.get(k);
|
||||
if (m && m.level > level) {
|
||||
level = m.level;
|
||||
subdeck = m.deckName;
|
||||
}
|
||||
});
|
||||
const modelToSubdecks = new Map<
|
||||
string,
|
||||
{
|
||||
[subdeck: string]: number[];
|
||||
}
|
||||
>();
|
||||
rs.map((r) => {
|
||||
const vs = modelToSubdecks.get(r.modelName) || {};
|
||||
const { value } = r.fields[KANJI_FIELD] || {};
|
||||
if (value) {
|
||||
// Get the subdeck names from Kanji
|
||||
let subdeck = '';
|
||||
let level = 0;
|
||||
|
||||
if (subdeck) {
|
||||
const cardIds = vs[subdeck] || [];
|
||||
cardIds.push(r.cardId);
|
||||
vs[subdeck] = cardIds;
|
||||
|
||||
modelToSubdecks.set(r.modelName, vs);
|
||||
Array.from(value).map((k) => {
|
||||
const m = kanjiLevels.get(k);
|
||||
if (m && m.level > level) {
|
||||
level = m.level;
|
||||
subdeck = m.deckName;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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),
|
||||
})),
|
||||
),
|
||||
if (subdeck) {
|
||||
const cardIds = vs[subdeck] || [];
|
||||
cardIds.push(r.cardId);
|
||||
vs[subdeck] = cardIds;
|
||||
|
||||
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) => {
|
||||
const cardsByTemplateName = {
|
||||
data: new Map<string, number[]>(),
|
||||
async get(templateName: string) {
|
||||
let v = this.data.get(templateName);
|
||||
if (!v) {
|
||||
v = await anki.api('findCards', {
|
||||
query: `deck:${DECK} card:${templateName}`,
|
||||
});
|
||||
}
|
||||
this.data.set(templateName, v);
|
||||
return v;
|
||||
},
|
||||
};
|
||||
),
|
||||
);
|
||||
})
|
||||
.then(async (rs) => {
|
||||
const remaining: {
|
||||
[templateName: string]: Set<number>;
|
||||
} = {};
|
||||
|
||||
return Promise.all(
|
||||
rs
|
||||
.flat()
|
||||
.flatMap((r) =>
|
||||
r.templateNames.map((templateName) => ({
|
||||
...r,
|
||||
templateName,
|
||||
})),
|
||||
)
|
||||
.map(({ templateName, subdeck, cardIdsSet }) =>
|
||||
cardsByTemplateName.get(templateName).then((cards) =>
|
||||
anki.api('changeDeck', {
|
||||
cards: cards.filter((c) => cardIdsSet.has(c)),
|
||||
deck: `${DECK}::${subdeck}::${templateName}`,
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
const cardsByTemplateName = {
|
||||
data: new Map<string, number[]>(),
|
||||
async get(templateName: string) {
|
||||
let v = this.data.get(templateName);
|
||||
if (!v) {
|
||||
v = await anki.api('findCards', {
|
||||
query: `deck:${DECK} card:${templateName}`,
|
||||
});
|
||||
remaining[templateName] = new Set(v);
|
||||
}
|
||||
this.data.set(templateName, v);
|
||||
return v;
|
||||
},
|
||||
};
|
||||
|
||||
const toChangeDeck: IAnkiConnectActions['changeDeck']['params'][] = [];
|
||||
|
||||
for (const { templateName, subdeck, cardIdsSet } of rs
|
||||
.flat()
|
||||
.flatMap((r) =>
|
||||
r.templateNames.map((templateName) => ({
|
||||
...r,
|
||||
templateName,
|
||||
})),
|
||||
)) {
|
||||
const cards = await cardsByTemplateName.get(templateName);
|
||||
|
||||
toChangeDeck.push({
|
||||
cards: cards.filter((c) => {
|
||||
const r = remaining[templateName];
|
||||
if (r) {
|
||||
r.delete(c);
|
||||
}
|
||||
return cardIdsSet.has(c);
|
||||
}),
|
||||
deck: `${DECK}::${subdeck}::${templateName}`,
|
||||
});
|
||||
}
|
||||
|
||||
Object.entries(remaining).map(([templateName, cards]) => {
|
||||
if (cards.size) {
|
||||
toChangeDeck.push({
|
||||
cards: [...cards],
|
||||
deck: `${DECK}::独習::${templateName}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (toChangeDeck.length) {
|
||||
const batchSize = 20;
|
||||
for (let i = 0; i < toChangeDeck.length; i += batchSize) {
|
||||
await Promise.all(
|
||||
toChangeDeck
|
||||
.slice(i, i + batchSize)
|
||||
.map((params) => anki.api('changeDeck', params)),
|
||||
);
|
||||
}
|
||||
|
||||
await anki.api('setDeckConfigId', {
|
||||
decks: toChangeDeck.map((r) => r.deck),
|
||||
configId: deckConfig.id,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
|
||||
Reference in new issue
Block a user