From 065c1991056a3e0a003b5edd4fbf6d91a751ccf8 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Fri, 15 Sep 2017 22:17:52 -0700 Subject: [PATCH 1/7] fix broken error handling for invalid json --- AnkiConnect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AnkiConnect.py b/AnkiConnect.py index 8306588..94ec384 100644 --- a/AnkiConnect.py +++ b/AnkiConnect.py @@ -268,7 +268,7 @@ class AjaxServer: params = json.loads(makeStr(req.body)) body = makeBytes(json.dumps(self.handler(params))) except ValueError: - body = json.dumps(None); + body = makeBytes(json.dumps(None)) resp = bytes() From bd071a3dfebc6573af776b98608c5ee1fd0125e0 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Fri, 29 Sep 2017 17:03:48 -0700 Subject: [PATCH 2/7] Updating README.md --- README.md | 196 +++++++++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index eb3fbaa..0725701 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ in order to bind it to all network interfaces on your host. Every request consists of a JSON-encoded object containing an `action`, a `version`, and a set of contextual `params`. A simple example of a modern JavaScript application communicating with the extension is illustrated below: -```JavaScript +```javascript function ankiConnectInvoke(action, version, params={}) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); @@ -92,7 +92,7 @@ try { Or using [`curl`](https://curl.haxx.se) from the command line: -``` +```bash curl localhost:8765 -X POST -d '{"action": "deckNames", "version": 5}' ``` @@ -101,15 +101,15 @@ return value of the executed API, and the `error` field is a description of any (the value `null` is used if execution completed successfully). *Sample successful response*: -``` +```json {"result": ["Default", "Filtered Deck 1"], "error": null} ``` *Samples of failed responses*: -``` +```json {"result": null, "error": "unsupported action"} ``` -``` +```json {"result": null, "error": "guiBrowse() got an unexpected keyword argument 'foobar'"} ``` @@ -137,14 +137,14 @@ guarantee that your application continues to function properly in the future. which are available in the reported AnkiConnect version or earlier, everything should work fine. *Sample request*: - ``` + ```json { "action": "version" } ``` *Sample result*: - ``` + ```json 5 ``` @@ -155,14 +155,14 @@ guarantee that your application continues to function properly in the future. GitHub. Returns a boolean value indicating if the plugin was upgraded or not. *Sample request*: - ``` + ```json { "action": "upgrade" } ``` *Sample result*: - ``` + ```json true ``` @@ -171,7 +171,7 @@ guarantee that your application continues to function properly in the future. Performs multiple actions in one request, returning an array with the response of each action (in the given order). *Sample request*: - ``` + ```json { "action": "multi", "params": { @@ -187,7 +187,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ ["Default"], [1494723142483, 1494703460437, 1494703479525] @@ -201,14 +201,14 @@ guarantee that your application continues to function properly in the future. Gets the complete list of deck names for the current user. *Sample request*: - ``` + ```json { "action": "deckNames" } ``` *Sample result*: - ``` + ```json [ "Default" ] @@ -219,14 +219,14 @@ guarantee that your application continues to function properly in the future. Gets the complete list of deck names and their respective IDs for the current user. *Sample request*: - ``` + ```json { "action": "deckNamesAndIds" } ``` *Sample result*: - ``` + ```json { "Default": 1 } @@ -238,7 +238,7 @@ guarantee that your application continues to function properly in the future. cards which belong to it. *Sample request*: - ``` + ```json { "action": "getDecks", "params": { @@ -248,7 +248,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json { "Default": [1502032366472], "Japanese::JLPT N3": [1502298036657, 1502298033753] @@ -260,7 +260,7 @@ guarantee that your application continues to function properly in the future. Moves cards with the given IDs to a different deck, creating the deck if it doesn't exist yet. *Sample request*: - ``` + ```json { "action": "changeDeck", "params": { @@ -271,7 +271,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json null ``` @@ -281,7 +281,7 @@ guarantee that your application continues to function properly in the future. the deleted decks will also be deleted; otherwise they will be moved to the default deck. *Sample request*: - ``` + ```json { "action": "deleteDecks", "params": { @@ -292,7 +292,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json null ``` @@ -303,7 +303,7 @@ guarantee that your application continues to function properly in the future. Gets the config group object for the given deck. *Sample request*: - ``` + ```json { "action": "getDeckConfig", "params": { @@ -313,7 +313,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json { "lapse": { "leechFails": 8, @@ -358,7 +358,7 @@ guarantee that your application continues to function properly in the future. it does not exist). *Sample request*: - ``` + ```json { "action": "saveDeckConfig", "params": { @@ -368,7 +368,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -378,7 +378,7 @@ guarantee that your application continues to function properly in the future. `false` if the given configuration group or any of the given decks do not exist. *Sample request*: - ``` + ```json { "action": "setDeckConfigId", "params": { @@ -389,7 +389,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -400,7 +400,7 @@ guarantee that your application continues to function properly in the future. not exist. *Sample request*: - ``` + ```json { "action": "cloneDeckConfigId", "params": { @@ -411,7 +411,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json 1502972374573 ``` @@ -421,7 +421,7 @@ guarantee that your application continues to function properly in the future. either the default config group (ID = 1) or a config group that does not exist. *Sample request*: - ``` + ```json { "action": "removeDeckConfigId", "params": { @@ -431,7 +431,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -442,14 +442,14 @@ guarantee that your application continues to function properly in the future. Gets the complete list of model names for the current user. *Sample request*: - ``` + ```json { "action": "modelNames" } ``` *Sample result*: - ``` + ```json [ "Basic", "Basic (and reversed card)" @@ -461,18 +461,18 @@ guarantee that your application continues to function properly in the future. Gets the complete list of model names and their corresponding IDs for the current user. *Sample request*: - ``` + ```json { "action": "modelNamesAndIds" } ``` *Sample result*: - ``` + ```json { - "Basic": 1483883011648 - "Basic (and reversed card)": 1483883011644 - "Basic (optional reversed card)": 1483883011631 + "Basic": 1483883011648, + "Basic (and reversed card)": 1483883011644, + "Basic (optional reversed card)": 1483883011631, "Cloze": 1483883011630 } ``` @@ -482,7 +482,7 @@ guarantee that your application continues to function properly in the future. Gets the complete list of field names for the provided model name. *Sample request*: - ``` + ```json { "action": "modelFieldNames", "params": { @@ -492,7 +492,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ "Front", "Back" @@ -505,7 +505,7 @@ guarantee that your application continues to function properly in the future. name. The question side is given first in each array. *Sample request*: - ``` + ```json { "action": "modelFieldsOnTemplates", "params": { @@ -515,7 +515,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json { "Card 1": [ ["Front"], @@ -542,7 +542,7 @@ guarantee that your application continues to function properly in the future. list of fields that should play audio when the card is displayed in Anki. *Sample request*: - ``` + ```json { "action": "addNote", "params": { @@ -568,7 +568,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json 1496198395707 ``` @@ -579,7 +579,7 @@ guarantee that your application continues to function properly in the future. documentation for `addNote` for an explanation of objects in the `notes` array. *Sample request*: - ``` + ```json { "action": "addNotes", "params": { @@ -607,7 +607,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ 1496198395707, null @@ -620,7 +620,7 @@ guarantee that your application continues to function properly in the future. booleans indicating whether or not the parameters at the corresponding index could be used to create a new note. *Sample request*: - ``` + ```json { "action": "canAddNotes", "params": { @@ -642,7 +642,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ true ] @@ -655,7 +655,7 @@ guarantee that your application continues to function properly in the future. Adds tags to notes by note ID. *Sample request*: - ``` + ```json { "action": "addTags", "params": { @@ -666,7 +666,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json null ``` @@ -675,7 +675,7 @@ guarantee that your application continues to function properly in the future. Remove tags from notes by note ID. *Sample request*: - ``` + ```json { "action": "removeTags", "params": { @@ -686,7 +686,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json null ``` @@ -698,7 +698,7 @@ guarantee that your application continues to function properly in the future. otherwise. *Sample request*: - ``` + ```json { "action": "suspend", "params": { @@ -708,7 +708,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -718,7 +718,7 @@ guarantee that your application continues to function properly in the future. otherwise. *Sample request*: - ``` + ```json { "action": "unsuspend", "params": { @@ -728,7 +728,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -737,7 +737,7 @@ guarantee that your application continues to function properly in the future. Returns an array indicating whether each of the given cards is suspended (in the same order). *Sample request*: - ``` + ```json { "action": "areSuspended", "params": { @@ -747,7 +747,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [false, true] ``` @@ -760,7 +760,7 @@ guarantee that your application continues to function properly in the future. match the way Anki treats them when reviewing. *Sample request*: - ``` + ```json { "action": "areDue", "params": { @@ -770,7 +770,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [false, true] ``` @@ -780,7 +780,7 @@ guarantee that your application continues to function properly in the future. for each given card ID when `complete` is `true`. (Negative intervals are in seconds and positive intervals in days.) *Sample request 1*: - ``` + ```json { "action": "getIntervals", "params": { @@ -790,12 +790,12 @@ guarantee that your application continues to function properly in the future. ``` *Sample result 1*: - ``` + ```json [-14400, 3] ``` *Sample request 2*: - ``` + ```json { "action": "getIntervals", "params": { @@ -806,7 +806,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result 2*: - ``` + ```json [ [-120, -180, -240, -300, -360, -14400], [-120, -180, -240, -300, -360, -14400, 1, 3] @@ -820,7 +820,7 @@ guarantee that your application continues to function properly in the future. Returns an array of note IDs for a given query (same query syntax as **guiBrowse**). *Sample request*: - ``` + ```json { "action": "findNotes", "params": { @@ -830,7 +830,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ 1483959289817, 1483959291695 @@ -843,7 +843,7 @@ guarantee that your application continues to function properly in the future. for better performance). *Sample request*: - ``` + ```json { "action": "findCards", "params": { @@ -853,7 +853,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ 1494723142483, 1494703460437, @@ -867,7 +867,7 @@ guarantee that your application continues to function properly in the future. given once in the array. *Sample request*: - ``` + ```json { "action": "cardsToNotes", "params": { @@ -877,7 +877,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ 1502098029797, 1502298025183 @@ -894,7 +894,7 @@ guarantee that your application continues to function properly in the future. with an underscore. These files are still synchronized to AnkiWeb. *Sample request*: - ``` + ```json { "action": "storeMediaFile", "params": { @@ -905,7 +905,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json null ``` @@ -919,7 +919,7 @@ guarantee that your application continues to function properly in the future. Retrieves the base64-encoded contents of the specified file, returning `false` if the file does not exist. *Sample request*: - ``` + ```json { "action": "retrieveMediaFile", "params": { @@ -929,7 +929,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json "SGVsbG8sIHdvcmxkIQ==" ``` @@ -938,7 +938,7 @@ guarantee that your application continues to function properly in the future. Deletes the specified file inside the media folder. *Sample request*: - ``` + ```json { "action": "deleteMediaFile", "params": { @@ -948,7 +948,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json null ``` @@ -959,7 +959,7 @@ guarantee that your application continues to function properly in the future. Invokes the card browser and searches for a given query. Returns an array of identifiers of the cards that were found. *Sample request*: - ``` + ```json { "action": "guiBrowse", "params": { @@ -969,7 +969,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json [ 1494723142483, 1494703460437, @@ -982,14 +982,14 @@ guarantee that your application continues to function properly in the future. Invokes the AddCards dialog. *Sample request*: - ``` + ```json { "action": "guiAddCards" } ``` *Sample result*: - ``` + ```json null ``` @@ -998,14 +998,14 @@ guarantee that your application continues to function properly in the future. Returns information about the current card or `null` if not in review mode. *Sample request*: - ``` + ```json { "action": "guiCurrentCard" } ``` *Sample result*: - ``` + ```json { "answer": "back content", "question": "front content", @@ -1032,14 +1032,14 @@ guarantee that your application continues to function properly in the future. Starts or resets the 'timerStarted' value for the current card. This is useful for deferring the start time to when it is displayed via the API, allowing the recorded time taken to answer the card to be more accurate when calling guiAnswerCard. *Sample request*: - ``` + ```json { "action": "guiStartCardTimer" } ``` *Sample result*: - ``` + ```json true ``` @@ -1048,14 +1048,14 @@ guarantee that your application continues to function properly in the future. Shows question text for the current card; returns `true` if in review mode or `false` otherwise. *Sample request*: - ``` + ```json { "action": "guiShowQuestion" } ``` *Sample result*: - ``` + ```json true ``` @@ -1064,14 +1064,14 @@ guarantee that your application continues to function properly in the future. Shows answer text for the current card; returns `true` if in review mode or `false` otherwise. *Sample request*: - ``` + ```json { "action": "guiShowAnswer" } ``` *Sample result*: - ``` + ```json true ``` @@ -1081,7 +1081,7 @@ guarantee that your application continues to function properly in the future. card must be displayed before before any answer can be accepted by Anki. *Sample request*: - ``` + ```json { "action": "guiAnswerCard", "params": { @@ -1091,7 +1091,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -1100,7 +1100,7 @@ guarantee that your application continues to function properly in the future. Opens the Deck Overview screen for the deck with the given name; returns `true` if succeeded or `false` otherwise. *Sample request*: - ``` + ```json { "action": "guiDeckOverview", "params": { @@ -1110,7 +1110,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -1119,14 +1119,14 @@ guarantee that your application continues to function properly in the future. Opens the Deck Browser screen. *Sample request*: - ``` + ```json { "action": "guiDeckBrowser" } ``` *Sample result*: - ``` + ```json null ``` @@ -1135,7 +1135,7 @@ guarantee that your application continues to function properly in the future. Starts review for the deck with the given name; returns `true` if succeeded or `false` otherwise. *Sample request*: - ``` + ```json { "action": "guiDeckReview", "params": { @@ -1145,7 +1145,7 @@ guarantee that your application continues to function properly in the future. ``` *Sample result*: - ``` + ```json true ``` @@ -1154,14 +1154,14 @@ guarantee that your application continues to function properly in the future. Schedules a request to close Anki after 1s. This operation is asynchronous, so it will return immediately and won't wait until Anki actually exits. *Sample request*: - ``` + ```json { "action": "guiExitAnki" } ``` *Sample result*: - ``` + ```json null ``` From 01676f7b2c6fbb355f8bde1513ecfb2d2b9560de Mon Sep 17 00:00:00 2001 From: tomasgodoi Date: Sun, 1 Oct 2017 12:22:04 -0300 Subject: [PATCH 3/7] Including the css field on the guiCurrentCard endpoint. --- AnkiConnect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AnkiConnect.py b/AnkiConnect.py index 94ec384..436c771 100644 --- a/AnkiConnect.py +++ b/AnkiConnect.py @@ -785,7 +785,8 @@ class AnkiBridge: 'answer': card._getQA()['a'], 'buttons': [b[0] for b in reviewer._answerButtonList()], 'modelName': model['name'], - 'deckName': self.deckNameFromId(card.did) + 'deckName': self.deckNameFromId(card.did), + 'css': model['css'] } From 1c1cf2ec613c32da3478160fd369d08a8c69e101 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 1 Oct 2017 18:17:39 -0700 Subject: [PATCH 4/7] Updating README.md --- README.md | 534 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 356 insertions(+), 178 deletions(-) diff --git a/README.md b/README.md index 0725701..ff46222 100644 --- a/README.md +++ b/README.md @@ -139,13 +139,17 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "version" + "action": "version", + "version": 5 } ``` *Sample result*: ```json - 5 + { + "result": 5, + "error": null + } ``` * **upgrade** @@ -157,13 +161,17 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "upgrade" + "action": "upgrade", + "version": 5 } ``` *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **multi** @@ -174,6 +182,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "multi", + "version": 5, "params": { "actions": [ {"action": "deckNames"}, @@ -188,10 +197,13 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - ["Default"], - [1494723142483, 1494703460437, 1494703479525] - ] + { + "result": [ + ["Default"], + [1494723142483, 1494703460437, 1494703479525] + ], + "error": null + } ``` #### Decks #### @@ -203,15 +215,17 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "deckNames" + "action": "deckNames", + "version": 5 } ``` *Sample result*: ```json - [ - "Default" - ] + { + "result": ["Default"], + "error": null + } ``` * **deckNamesAndIds** @@ -221,14 +235,16 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "deckNamesAndIds" + "action": "deckNamesAndIds", + "version": 5 } ``` *Sample result*: ```json { - "Default": 1 + "result": {"Default": 1}, + "error": null } ``` @@ -241,6 +257,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "getDecks", + "version": 5, "params": { "cards": [1502298036657, 1502298033753, 1502032366472] } @@ -250,8 +267,11 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json { - "Default": [1502032366472], - "Japanese::JLPT N3": [1502298036657, 1502298033753] + "result": { + "Default": [1502032366472], + "Japanese::JLPT N3": [1502298036657, 1502298033753] + }, + "error": null } ``` @@ -263,6 +283,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "changeDeck", + "version": 5, "params": { "cards": [1502098034045, 1502098034048, 1502298033753], "deck": "Japanese::JLPT N3" @@ -272,7 +293,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` * **deleteDecks** @@ -284,6 +308,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "deleteDecks", + "version": 5, "params": { "decks": ["Japanese::JLPT N5", "Easy Spanish"], "cardsToo": true @@ -293,19 +318,23 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` #### Deck Configurations #### * **getDeckConfig** - Gets the config group object for the given deck. + Gets the configuration group object for the given deck. *Sample request*: ```json { "action": "getDeckConfig", + "version": 5, "params": { "deck": "Default" } @@ -315,61 +344,103 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json { - "lapse": { - "leechFails": 8, - "delays": [10], - "minInt": 1, - "leechAction": 0, - "mult": 0 + "result": { + "lapse": { + "leechFails": 8, + "delays": [10], + "minInt": 1, + "leechAction": 0, + "mult": 0 + }, + "dyn": false, + "autoplay": true, + "mod": 1502970872, + "id": 1, + "maxTaken": 60, + "new": { + "bury": true, + "order": 1, + "initialFactor": 2500, + "perDay": 20, + "delays": [1, 10], + "separate": true, + "ints": [1, 4, 7] + }, + "name": "Default", + "rev": { + "bury": true, + "ivlFct": 1, + "ease4": 1.3, + "maxIvl": 36500, + "perDay": 100, + "minSpace": 1, + "fuzz": 0.05 + }, + "timer": 0, + "replayq": true, + "usn": -1 }, - "dyn": false, - "autoplay": true, - "mod": 1502970872, - "id": 1, - "maxTaken": 60, - "new": { - "bury": true, - "order": 1, - "initialFactor": 2500, - "perDay": 20, - "delays": [1, 10], - "separate": true, - "ints": [1, 4, 7] - }, - "name": "Default", - "rev": { - "bury": true, - "ivlFct": 1, - "ease4": 1.3, - "maxIvl": 36500, - "perDay": 100, - "minSpace": 1, - "fuzz": 0.05 - }, - "timer": 0, - "replayq": true, - "usn": -1 + "error": null } ``` * **saveDeckConfig** - Saves the given config group, returning `true` on success or `false` if the ID of the config group is invalid (i.e. - it does not exist). + Saves the given configuration group, returning `true` on success or `false` if the ID of the configuration group is + invalid (such as when it does not exist). *Sample request*: ```json { "action": "saveDeckConfig", + "version": 5, "params": { - "config": (config group object) + "config": { + "lapse": { + "leechFails": 8, + "delays": [10], + "minInt": 1, + "leechAction": 0, + "mult": 0 + }, + "dyn": false, + "autoplay": true, + "mod": 1502970872, + "id": 1, + "maxTaken": 60, + "new": { + "bury": true, + "order": 1, + "initialFactor": 2500, + "perDay": 20, + "delays": [1, 10], + "separate": true, + "ints": [1, 4, 7] + }, + "name": "Default", + "rev": { + "bury": true, + "ivlFct": 1, + "ease4": 1.3, + "maxIvl": 36500, + "perDay": 100, + "minSpace": 1, + "fuzz": 0.05 + }, + "timer": 0, + "replayq": true, + "usn": -1 + } } } ``` *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **setDeckConfigId** @@ -381,6 +452,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "setDeckConfigId", + "version": 5, "params": { "decks": ["Default"], "configId": 1 @@ -390,19 +462,23 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **cloneDeckConfigId** - Creates a new config group with the given name, cloning from the group with the given ID, or from the default group - if this is unspecified. Returns the ID of the new config group, or `false` if the specified group to clone from does - not exist. + Creates a new configuration group with the given name, cloning from the group with the given ID, or from the default + group if this is unspecified. Returns the ID of the new configuration group, or `false` if the specified group to + clone from does not exist. *Sample request*: ```json { "action": "cloneDeckConfigId", + "version": 5, "params": { "name": "Copy of Default", "cloneFrom": 1 @@ -412,18 +488,22 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - 1502972374573 + { + "result": 1502972374573, + "error": null + } ``` * **removeDeckConfigId** - Removes the config group with the given ID, returning `true` if successful, or `false` if attempting to remove - either the default config group (ID = 1) or a config group that does not exist. + Removes the configuration group with the given ID, returning `true` if successful, or `false` if attempting to + remove either the default configuration group (ID = 1) or a configuration group that does not exist. *Sample request*: ```json { "action": "removeDeckConfigId", + "version": 5, "params": { "configId": 1502972374573 } @@ -432,7 +512,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` #### Models #### @@ -444,16 +527,17 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "modelNames" + "action": "modelNames", + "version": 5 } ``` *Sample result*: ```json - [ - "Basic", - "Basic (and reversed card)" - ] + { + "result": ["Basic", "Basic (and reversed card)"], + "error": null + } ``` * **modelNamesAndIds** @@ -463,17 +547,21 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "modelNamesAndIds" + "action": "modelNamesAndIds", + "version": 5 } ``` *Sample result*: ```json { - "Basic": 1483883011648, - "Basic (and reversed card)": 1483883011644, - "Basic (optional reversed card)": 1483883011631, - "Cloze": 1483883011630 + "result": { + "Basic": 1483883011648, + "Basic (and reversed card)": 1483883011644, + "Basic (optional reversed card)": 1483883011631, + "Cloze": 1483883011630 + }, + "error": null } ``` @@ -485,6 +573,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "modelFieldNames", + "version": 5, "params": { "modelName": "Basic" } @@ -493,10 +582,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - "Front", - "Back" - ] + { + "result": ["Front", "Back"], + "error": null + } ``` * **modelFieldsOnTemplates** @@ -508,6 +597,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "modelFieldsOnTemplates", + "version": 5, "params": { "modelName": "Basic (and reversed card)" } @@ -517,14 +607,11 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json { - "Card 1": [ - ["Front"], - ["Back"] - ], - "Card 2": [ - ["Back"], - ["Front"] - ] + "result": { + "Card 1": [["Front"], ["Back"]], + "Card 2": [["Back"], ["Front"]] + }, + "error": null } ``` @@ -535,16 +622,17 @@ guarantee that your application continues to function properly in the future. Creates a note using the given deck and model, with the provided field values and tags. Returns the identifier of the created note created on success, and `null` on failure. - AnkiConnect can download audio files and embed them in newly created notes. The corresponding *audio* note member is - optional and can be omitted. If you choose to include it, the *url* and *filename* fields must be also defined. The - *skipHash* field can be optionally provided to skip the inclusion of downloaded files with an MD5 hash that matches - the provided value. This is useful for avoiding the saving of error pages and stub files. The *fields* member is a + AnkiConnect can download audio files and embed them in newly created notes. The corresponding `audio` note member is + optional and can be omitted. If you choose to include it, the `url` and `filename` fields must be also defined. The + `skipHash` field can be optionally provided to skip the inclusion of downloaded files with an MD5 hash that matches + the provided value. This is useful for avoiding the saving of error pages and stub files. The `fields` member is a list of fields that should play audio when the card is displayed in Anki. *Sample request*: ```json { "action": "addNote", + "version": 5, "params": { "note": { "deckName": "Default", @@ -569,7 +657,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - 1496198395707 + { + "result": 1496198395707, + "error": null + } ``` * **addNotes** @@ -582,6 +673,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "addNotes", + "version": 5, "params": { "notes": [ { @@ -608,10 +700,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - 1496198395707, - null - ] + { + "result": [1496198395707, null], + "error": null + } ``` * **canAddNotes** @@ -623,6 +715,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "canAddNotes", + "version": 5, "params": { "notes": [ { @@ -643,9 +736,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - true - ] + { + "result": [true], + "error": null + } ``` #### Note Tags #### @@ -658,6 +752,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "addTags", + "version": 5, "params": { "notes": [1483959289817, 1483959291695], "tags": "european-languages" @@ -667,7 +762,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` * **removeTags** @@ -678,6 +776,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "removeTags", + "version": 5, "params": { "notes": [1483959289817, 1483959291695], "tags": "european-languages" @@ -687,7 +786,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` #### Card Suspension #### @@ -701,6 +803,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "suspend", + "version": 5, "params": { "cards": [1483959291685, 1483959293217] } @@ -709,7 +812,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **unsuspend** @@ -721,6 +827,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "unsuspend", + "version": 5, "params": { "cards": [1483959291685, 1483959293217] } @@ -729,7 +836,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **areSuspended** @@ -740,6 +850,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "areSuspended", + "version": 5, "params": { "cards": [1483959291685, 1483959293217] } @@ -748,21 +859,25 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [false, true] + { + "result": [false, true], + "error": null + } ``` #### Card Intervals #### * **areDue** - Returns an array indicating whether each of the given cards is due (in the same order). Note: cards in the learning - queue with a large interval (over 20 minutes) are treated as not due until the time of their interval has passed, to - match the way Anki treats them when reviewing. + Returns an array indicating whether each of the given cards is due (in the same order). *Note*: cards in the + learning queue with a large interval (over 20 minutes) are treated as not due until the time of their interval has + passed, to match the way Anki treats them when reviewing. *Sample request*: ```json { "action": "areDue", + "version": 5, "params": { "cards": [1483959291685, 1483959293217] } @@ -771,18 +886,22 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [false, true] + { + "result": [false, true], + "error": null + } ``` * **getIntervals** Returns an array of the most recent intervals for each given card ID, or a 2-dimensional array of all the intervals - for each given card ID when `complete` is `true`. (Negative intervals are in seconds and positive intervals in days.) + for each given card ID when `complete` is `true`. Negative intervals are in seconds and positive intervals in days. *Sample request 1*: ```json { "action": "getIntervals", + "version": 5, "params": { "cards": [1502298033753, 1502298036657] } @@ -791,13 +910,17 @@ guarantee that your application continues to function properly in the future. *Sample result 1*: ```json - [-14400, 3] + { + "result": [-14400, 3], + "error": null + } ``` *Sample request 2*: ```json { "action": "getIntervals", + "version": 5, "params": { "cards": [1502298033753, 1502298036657], "complete": true @@ -807,22 +930,26 @@ guarantee that your application continues to function properly in the future. *Sample result 2*: ```json - [ - [-120, -180, -240, -300, -360, -14400], - [-120, -180, -240, -300, -360, -14400, 1, 3] - ] + { + "result": [ + [-120, -180, -240, -300, -360, -14400], + [-120, -180, -240, -300, -360, -14400, 1, 3] + ], + "error": null + } ``` #### Finding Notes and Cards #### * **findNotes** - Returns an array of note IDs for a given query (same query syntax as **guiBrowse**). + Returns an array of note IDs for a given query. Same query syntax as `guiBrowse`. *Sample request*: ```json { "action": "findNotes", + "version": 5, "params": { "query": "deck:current" } @@ -831,21 +958,22 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - 1483959289817, - 1483959291695 - ] + { + "result": [1483959289817, 1483959291695], + "error": null + } ``` * **findCards** - Returns an array of card IDs for a given query (functionally identical to **guiBrowse** but doesn't use the GUI - for better performance). + Returns an array of card IDs for a given query. Functionally identical to `guiBrowse` but doesn't use the GUI for + better performance. *Sample request*: ```json { "action": "findCards", + "version": 5, "params": { "query": "deck:current" } @@ -854,22 +982,22 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - 1494723142483, - 1494703460437, - 1494703479525 - ] + { + "result": [1494723142483, 1494703460437, 1494703479525], + "error": null + } ``` * **cardsToNotes** - Returns an (unordered) array of note IDs for the given card IDs. For cards with the same note, the ID is only - given once in the array. + Returns an unordered array of note IDs for the given card IDs. For cards with the same note, the ID is only given + once in the array. *Sample request*: ```json { "action": "cardsToNotes", + "version": 5, "params": { "cards": [1502098034045, 1502098034048, 1502298033753] } @@ -878,10 +1006,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - 1502098029797, - 1502298025183 - ] + { + "result": [1502098029797, 1502298025183], + "error": null + } ``` #### Media File Storage #### @@ -890,13 +1018,14 @@ guarantee that your application continues to function properly in the future. Stores a file with the specified base64-encoded contents inside the media folder. - Note: to prevent Anki from removing files not used by any cards (e.g. for configuration files), prefix the filename - with an underscore. These files are still synchronized to AnkiWeb. + *Note*: to prevent Anki from removing files not used by any cards (e.g. for configuration files), prefix the + filename with an underscore. These files are still synchronized to AnkiWeb. *Sample request*: ```json { "action": "storeMediaFile", + "version": 5, "params": { "filename": "_hello.txt", "data": "SGVsbG8sIHdvcmxkIQ==" @@ -906,7 +1035,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` *Content of `_hello.txt`*: @@ -922,6 +1054,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "retrieveMediaFile", + "version": 5, "params": { "filename": "_hello.txt" } @@ -930,7 +1063,10 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - "SGVsbG8sIHdvcmxkIQ==" + { + "result": "SGVsbG8sIHdvcmxkIQ==", + "error": null + } ``` * **deleteMediaFile** @@ -941,6 +1077,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "deleteMediaFile", + "version": 5, "params": { "filename": "_hello.txt" } @@ -949,19 +1086,24 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` #### Graphical #### * **guiBrowse** - Invokes the card browser and searches for a given query. Returns an array of identifiers of the cards that were found. + Invokes the *Card Browser* dialog and searches for a given query. Returns an array of identifiers of the cards that + were found. *Sample request*: ```json { "action": "guiBrowse", + "version": 5, "params": { "query": "deck:current" } @@ -970,27 +1112,30 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - [ - 1494723142483, - 1494703460437, - 1494703479525 - ] + { + "result": [1494723142483, 1494703460437, 1494703479525], + "error": null + } ``` * **guiAddCards** - Invokes the AddCards dialog. + Invokes the *Add Cards* dialog. *Sample request*: ```json { - "action": "guiAddCards" + "action": "guiAddCards", + "version": 5 } ``` *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` * **guiCurrentCard** @@ -1000,47 +1145,51 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "guiCurrentCard" + "action": "guiCurrentCard", + "version": 5 } ``` *Sample result*: ```json { - "answer": "back content", - "question": "front content", - "deckName": "Default", - "modelName": "Basic", - "fieldOrder": 0, - "fields": { - "Front": { - "value": "front content", - "order": 0 + "result": { + "answer": "back content", + "question": "front content", + "deckName": "Default", + "modelName": "Basic", + "fieldOrder": 0, + "fields": { + "Front": {"value": "front content", "order": 0}, + "Back": {"value": "back content", "order": 1} }, - "Back": { - "value": "back content", - "order": 1 - } + "cardId": 1498938915662, + "buttons": [1, 2, 3] }, - "cardId": 1498938915662, - "buttons": [1, 2, 3] + "error": null } ``` * **guiStartCardTimer** - Starts or resets the 'timerStarted' value for the current card. This is useful for deferring the start time to when it is displayed via the API, allowing the recorded time taken to answer the card to be more accurate when calling guiAnswerCard. + Starts or resets the `timerStarted` value for the current card. This is useful for deferring the start time to when + it is displayed via the API, allowing the recorded time taken to answer the card to be more accurate when calling + `guiAnswerCard`. *Sample request*: ```json { - "action": "guiStartCardTimer" + "action": "guiStartCardTimer", + "version": 5 } ``` *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **guiShowQuestion** @@ -1050,13 +1199,17 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "guiShowQuestion" + "action": "guiShowQuestion", + "version": 5 } ``` *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **guiShowAnswer** @@ -1066,13 +1219,17 @@ guarantee that your application continues to function properly in the future. *Sample request*: ```json { - "action": "guiShowAnswer" + "action": "guiShowAnswer", + "version": 5 } ``` *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **guiAnswerCard** @@ -1084,6 +1241,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "guiAnswerCard", + "version": 5, "params": { "ease": 1 } @@ -1092,17 +1250,21 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **guiDeckOverview** - Opens the Deck Overview screen for the deck with the given name; returns `true` if succeeded or `false` otherwise. + Opens the *Deck Overview* dialog for the deck with the given name; returns `true` if succeeded or `false` otherwise. *Sample request*: ```json { "action": "guiDeckOverview", + "version": 5, "params": { "name": "Default" } @@ -1111,23 +1273,30 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **guiDeckBrowser** - Opens the Deck Browser screen. + Opens the *Deck Browser* dialog. *Sample request*: ```json { - "action": "guiDeckBrowser" + "action": "guiDeckBrowser", + "version": 5 } ``` *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` * **guiDeckReview** @@ -1138,6 +1307,7 @@ guarantee that your application continues to function properly in the future. ```json { "action": "guiDeckReview", + "version": 5, "params": { "name": "Default" } @@ -1146,23 +1316,31 @@ guarantee that your application continues to function properly in the future. *Sample result*: ```json - true + { + "result": true, + "error": null + } ``` * **guiExitAnki** - Schedules a request to close Anki after 1s. This operation is asynchronous, so it will return immediately and won't wait until Anki actually exits. + Schedules a request to gracefully close Anki. This operation is asynchronous, so it will return immediately and + won't wait until the Anki process actually terminates. *Sample request*: ```json { - "action": "guiExitAnki" + "action": "guiExitAnki", + "version": 5 } ``` *Sample result*: ```json - null + { + "result": null, + "error": null + } ``` ## License ## From 6aa40a698f04367e522f12778e6f05cad1336fba Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Mon, 2 Oct 2017 09:31:31 -0700 Subject: [PATCH 5/7] Updating README.md --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index ff46222..ee65981 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,27 @@ The AnkiConnect plugin enables external applications such as [Yomichan](https:// the user's card deck, automatically create new vocabulary and Kanji flash cards, and more. AnkiConnect is compatible with the latest stable (2.0.x) and alpha (2.1.x) releases of Anki and works on Linux, Windows, and Mac OS X. +## Table of Contents ## + +* [Installation](https://foosoft.net/projects/anki-connect/#installation) + * [Notes for Windows Users](https://foosoft.net/projects/anki-connect/#notes-for-windows-users) + * [Notes for Mac OS X Users](https://foosoft.net/projects/anki-connect/#notes-for-mac-os-x-users) +* [Application Interface for Developers](https://foosoft.net/projects/anki-connect/#application-interface-for-developers) + * [Sample Invocation](https://foosoft.net/projects/anki-connect/#sample-invocation) + * [Supported Actions](https://foosoft.net/projects/anki-connect/#supported-actions) + * [Miscellaneous](https://foosoft.net/projects/anki-connect/#miscellaneous) + * [Decks](https://foosoft.net/projects/anki-connect/#decks) + * [Deck Configurations](https://foosoft.net/projects/anki-connect/#deck-configurations) + * [Models](https://foosoft.net/projects/anki-connect/#models) + * [Note Creation](https://foosoft.net/projects/anki-connect/#note-creation) + * [Note Tags](https://foosoft.net/projects/anki-connect/#note-tags) + * [Card Suspension](https://foosoft.net/projects/anki-connect/#card-suspension) + * [Card Intervals](https://foosoft.net/projects/anki-connect/#card-intervals) + * [Finding Notes and Cards](https://foosoft.net/projects/anki-connect/#finding-notes-and-cards) + * [Media File Storage](https://foosoft.net/projects/anki-connect/#media-file-storage) + * [Graphical](https://foosoft.net/projects/anki-connect/#graphical) +* [License](https://foosoft.net/projects/anki-connect/#license) + ## Installation ## The installation process is similar to that of other Anki plugins and can be accomplished in three steps: From 9ddb7eb19a559e50aceae319023bf82d177ba74d Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 8 Oct 2017 14:34:17 -0700 Subject: [PATCH 6/7] Updating README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ee65981..900b6b0 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ try { Or using [`curl`](https://curl.haxx.se) from the command line: ```bash -curl localhost:8765 -X POST -d '{"action": "deckNames", "version": 5}' +curl localhost:8765 -X POST -d "{\"action\": \"deckNames\", \"version\": 5}" ``` AnkiConnect will respond with an object containing two fields: `result` and `error`. The `result` field contains the From 20f1920e062247abfcf08b3c6d936132cfe78d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C5=BEe=20Bertoncelj?= Date: Fri, 22 Dec 2017 23:53:41 +0100 Subject: [PATCH 7/7] Add a header for CORS support --- AnkiConnect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AnkiConnect.py b/AnkiConnect.py index 436c771..ecee2fe 100644 --- a/AnkiConnect.py +++ b/AnkiConnect.py @@ -217,7 +217,8 @@ class AjaxServer: def resetHeaders(self): self.headers = [ ['HTTP/1.1 200 OK', None], - ['Content-Type', 'text/json'] + ['Content-Type', 'text/json'], + ['Access-Control-Allow-Origin', '*'] ] self.extraHeaders = {}