Created
September 26, 2022 20:53
-
-
Save dylan-sessler/1722cd17689ae57b6da9b41c952b881f to your computer and use it in GitHub Desktop.
anki stuff
This file contains hidden or 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 axios = require('axios') | |
const childProcess = require('child_process') | |
const path = require('path') | |
module.exports = {openReviewGui, getDeckStats} | |
async function anki(method, url, dataObject){ | |
// implemented using the ankiConnect plugin | |
// https://foosoft.net/projects/anki-connect/ | |
// https://ankiweb.net/shared/info/2055492159 | |
if(!isAnkiRunning()){ | |
startAnkiDetached() | |
waitForAnkiToBootUp() | |
} | |
const result = ankiRequest(method, url, dataObject) | |
.then(parseAnkiResponse) | |
.catch((error) => { | |
if(error.code === 'ECONNREFUSED'){ | |
throw Error('Unable to connect to the anki connect server. Do you have the Anki Connect add-on enabled?') | |
} | |
else {throw error} | |
}) | |
return result | |
} | |
function ankiRequest(method, url, dataObject){ | |
return axios({ | |
method: method, | |
url: url, | |
data: dataObject, | |
validateStatus: () => true, // every status code is a success, handle status codes differently in the parser. Default is 200-299 is success, rest is error | |
}) | |
} | |
function parseAnkiResponse(response) { | |
switch(response.status) { | |
case 200: | |
if(response.data){ | |
return response.data | |
} else { | |
const responseDataFormatError = Error('response.data was empty') | |
throw responseDataFormatError | |
} | |
break | |
default: | |
const unhandledStatusCodeError = Error(`Unhandled status code ${response.status}`) | |
unhandledStatusCodeError.responseData = response.data | |
throw unhandledStatusCodeError | |
} | |
} | |
async function openReviewGui(deckName) { | |
const dataObj = { | |
action: "guiDeckReview", | |
version: 6, | |
params: {name: deckName} | |
} | |
const result = await anki('post', 'http://localhost:8765', dataObj) | |
if(result.result === null){ | |
throw Error('Anki deck was not found when trying to open review. Have you entered it yet?') | |
} | |
raiseAnki() | |
} | |
async function getDeckStats(deckName) { | |
// If the deckName does not exist in anki, it will be created. This is some | |
// ankiConnect weirdness. | |
// TODO determine if a new deck was created (will have a key on the result | |
// that is not `1`, and is the deck Id (eg. 165468746)) and when it is throw | |
// an error and delete the new deck. | |
const dataObj = { | |
action: "getDeckStats", | |
version: 6, | |
params: {decks: [deckName]} | |
} | |
const result = await anki('post', 'http://localhost:8765', dataObj) | |
const deckStats = result.result[1] | |
return deckStats | |
} | |
// Fxns that do bash stuff to do a variety of things | |
function isAnkiRunning() { | |
const pathToFile = path.join(__dirname, 'bash-scripts', 'is-anki-running.sh') | |
const isAnkiRunningExitCode = childProcess.execFileSync(pathToFile).toString() | |
if(Number(isAnkiRunningExitCode) === 0){return true} | |
else {return false} | |
} | |
function startAnkiDetached() { | |
// const out = fs.openSync('./out.log', 'a') // only needed if you want to see the logs | |
// const err = fs.openSync('./out.log', 'a') // only needed if you want to see the logs | |
childProcess.spawn('anki', [], { | |
// https://stackoverflow.com/questions/25323703/nodejs-execute-command-in-background-and-forget | |
// By default parent process will wait for the detached child to exit, and | |
// it'll also listen for its stdio. To completely detach child process from the | |
// parent you should: | |
stdio: 'ignore', // detaches child's stdio from parent by piping all stdio to /dev/null | |
// stdio: ['ignore', out, err], // detaches stdio from parent by piping all stdio to a log file so you can check in on it | |
detached: true // makes the child the leader of a new process group so it will keep running after the parent exits | |
}).unref() // remove child process from the parent event loop reference count using unref() method | |
} | |
function waitForAnkiToBootUp() { | |
const pathToFile = path.join(__dirname, 'bash-scripts', 'wait-for-anki.sh') | |
const waitForAnki = childProcess.execFileSync(pathToFile,[],{timeout: 10000}) | |
} | |
function raiseAnki() { | |
const pathToFile = path.join(__dirname, 'bash-scripts', 'raise-anki.sh') | |
const stdout = childProcess.execFileSync(pathToFile).toString() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment