Last active
May 3, 2022 05:05
-
-
Save adelin-b/362a04fb29dd7ee618952fe2fe5e2417 to your computer and use it in GitHub Desktop.
A script to convert anki file to org file using anki-connect anki plugin and anki-editor for emacs `deno run --allow-net anki.ts "*"` or `deno run --allow-net anki.ts "Deckname"` or inside emacs evil mode `:read !deno run --allow-net anki.ts "*"` WARNING, currently anki-editor break html by escaping it automaticaly when you push the imported decks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const notesInfo = (results: any[]) => ({ | |
action: "notesInfo", | |
version: 6, | |
params: { | |
notes: results, | |
}, | |
}); | |
const deckname = Deno.args[0] ?? "*"; | |
const findNotes = { | |
action: "findNotes", | |
version: 6, | |
params: { | |
query: "deck:" + deckname, | |
}, | |
}; | |
const notesResponse = await fetch("http://localhost:8765", { | |
method: "POST", | |
body: JSON.stringify(findNotes), | |
}); | |
const notesJson = await notesResponse.json(); | |
const notesInfoResponse = await fetch("http://localhost:8765", { | |
method: "POST", | |
body: JSON.stringify(notesInfo(notesJson.result)), | |
}); | |
interface Note { | |
noteId: number; | |
tags: string[]; | |
deck: string; | |
fields: { | |
[key: string]: { | |
value: string; | |
order: number; | |
}; | |
}; | |
modelName: string; | |
cards: number[]; | |
} | |
const getDeck = async (card: number) => { | |
return deckLookup[card]; | |
}; | |
const getDeckLookup = async (card: number[]) => { | |
let lookupDeck: { [key: number]: string } = {}; | |
let i, | |
j, | |
chunkedCards, | |
chunk = 100000000; | |
for (i = 0, j = card.length; i < j; i += chunk) { | |
chunkedCards = card.slice(i, i + chunk); | |
// do whatever | |
const getDeckQuery = { | |
action: "getDecks", | |
version: 6, | |
params: { | |
cards: [...chunkedCards], | |
}, | |
}; | |
const decksResponse = await fetch("http://localhost:8765", { | |
method: "GET", | |
body: JSON.stringify(getDeckQuery), | |
}); | |
const deckJson = await decksResponse.json(); | |
Object.keys(deckJson.result).forEach((deckname) => { | |
deckJson.result[deckname].forEach( | |
(card: number) => (lookupDeck[card] = deckname) | |
); | |
}); | |
} | |
return lookupDeck; | |
}; | |
const notesInfoJson = await notesInfoResponse.json(); | |
const allCards: number[] = []; | |
const unused = (notesInfoJson.result as Note[]).forEach((note) => | |
note.cards.forEach((card) => allCards.push(card)) | |
); | |
const deckLookup = await getDeckLookup(allCards); | |
const tagsToOrg = (tags: Note["tags"]) => { | |
if (tags.length) return `:${tags.join(":")}:`; | |
}; | |
const tagsToOrgProperty = (tags: Note["tags"]) => { | |
if (tags.length) return tags.join(" "); | |
}; | |
const fieldsToOrg = (fields: Note["fields"]) => { | |
const keys = Object.keys(fields); | |
const listField = new Array(keys.length); | |
keys.forEach((key) => { | |
listField[fields[key].order] = `** ${key}\n${fields[key].value}`; | |
}); | |
return listField.join("\n"); | |
}; | |
const noteToOrg = async (note: Note) => { | |
const tags = tagsToOrg(note.tags) ?? ""; | |
const fields = fieldsToOrg(note.fields) ?? ""; | |
const properties = `:PROPERTIES: | |
:ANKI_DECK: ${await getDeck(note.cards[0])} | |
:ANKI_NOTE_TYPE: ${note.modelName} | |
${tags && `:ANKI_TAGS: ${tagsToOrgProperty(note.tags)}`} | |
:ANKI_NOTE_ID: ${note.noteId} | |
:END: | |
`; | |
return ` | |
* Item ${tags} | |
${properties} | |
${fields} | |
`; | |
}; | |
for (const note of notesInfoJson.result) { | |
console.log(await noteToOrg(note)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks for posting this. it just worked for me on node/typescript.
i created a tsconfig.json for async issues, added a package.json (with type: module) and imported node-fetch. it's been awhile since i've used JS/TS