anki-connect/README.md

180 lines
8.4 KiB
Markdown
Raw Normal View History

2020-04-22 01:22:10 +00:00
# AnkiConnect
2016-05-30 02:59:21 +00:00
2020-05-25 00:50:48 +00:00
AnkiConnect enables external applications such as [Yomichan](https://foosoft.net/projects/yomichan/) to communicate with
[Anki](https://apps.ankiweb.net/) over a simple HTTP API. Its capabilities include executing queries against the user's
card deck, automatically creating new cards, and more. AnkiConnect is compatible with the latest stable (2.1.x) releases
of Anki; older versions (2.0.x and below) are no longer supported.
2016-05-30 02:59:21 +00:00
2020-04-22 01:22:10 +00:00
## Installation
2016-05-30 02:59:21 +00:00
2020-05-25 00:50:48 +00:00
The installation process is similar to other Anki plugins and can be accomplished in three steps:
2017-03-15 04:10:45 +00:00
1. Open the `Install Add-on` dialog by selecting `Tools` | `Add-ons` | `Get Add-ons...` in Anki.
2019-04-28 23:02:02 +00:00
2. Input [2055492159](https://ankiweb.net/shared/info/2055492159) into the text box labeled `Code` and press the `OK` button to proceed.
2017-03-15 04:10:45 +00:00
3. Restart Anki when prompted to do so in order to complete the installation of AnkiConnect.
2017-04-01 20:21:04 +00:00
Anki must be kept running in the background in order for other applications to be able to use AnkiConnect. You can
2020-05-25 00:50:48 +00:00
verify that AnkiConnect is running at any time by accessing `localhost:8765` in your browser. If the server is running,
you will see the message `AnkiConnect` displayed in your browser window.
2016-07-03 02:46:01 +00:00
2020-04-22 01:22:10 +00:00
### Notes for Windows Users
2017-01-28 20:20:38 +00:00
2020-05-25 00:50:48 +00:00
Windows users may see a firewall nag dialog box appear on Anki startup. This occurs because AnkiConnect runs a local
HTTP server in order to enable other applications to connect to it. The host application, Anki, must be unblocked for
this plugin to function correctly.
2017-01-28 20:20:38 +00:00
2020-04-22 01:22:10 +00:00
### Notes for Mac OS X Users
2017-01-28 20:20:38 +00:00
2017-02-12 00:41:02 +00:00
Starting with [Mac OS X Mavericks](https://en.wikipedia.org/wiki/OS_X_Mavericks), a feature named *App Nap* has been
introduced to the operating system. This feature causes certain applications which are open (but not visible) to be
2017-02-12 03:26:22 +00:00
placed in a suspended state. As this behavior causes AnkiConnect to stop working while you have another window in the
2017-02-12 00:41:02 +00:00
foreground, App Nap should be disabled for Anki:
1. Start the Terminal application.
2018-09-16 03:21:03 +00:00
2. Execute the following commands in the terminal window:
2020-05-25 00:50:48 +00:00
* `defaults write net.ankiweb.dtop NSAppSleepDisabled -bool true`
* `defaults write net.ichi2.anki NSAppSleepDisabled -bool true`
* `defaults write org.qt-project.Qt.QtWebEngineCore NSAppSleepDisabled -bool true`
2017-02-12 00:41:02 +00:00
3. Restart Anki.
2020-04-22 01:22:10 +00:00
## Application Interface for Developers
2017-02-01 17:23:09 +00:00
2020-05-25 00:50:48 +00:00
AnkiConnect exposes internal Anki features to external applications via an easy to use API. After being installed, this
plugin will start an HTTP sever on port 8765 whenever Anki is launched. Other applications (including browser
extensions) can then communicate with it via HTTP requests.
2017-02-01 17:23:09 +00:00
2017-08-31 04:26:28 +00:00
By default, AnkiConnect will only bind the HTTP server to the `127.0.0.1` IP address, so that you will only be able to
access it from the same host on which it is running. If you need to access it over a network, you can set the
environment variable `ANKICONNECT_BIND_ADDRESS` to change the binding address. For example, you can set it to `0.0.0.0`
in order to bind it to all network interfaces on your host.
2020-04-22 01:22:10 +00:00
### Sample Invocation
2017-02-01 17:23:09 +00:00
2020-01-06 03:01:11 +00:00
Every request consists of a JSON-encoded object containing an `action`, a `version`, contextual `params`, and a `key`
value used for authentication (which is optional and can be omitted by default). AnkiConnect will respond with an object
containing two fields: `result` and `error`. The `result` field contains the return value of the executed API, and the
`error` field is a description of any exception thrown during API execution (the value `null` is used if execution
completed successfully).
2019-02-03 16:48:57 +00:00
*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'"}
```
For compatibility with clients designed to work with older versions of AnkiConnect, failing to provide a `version` field
in the request will make the version default to 4. Furthermore, when the provided version is level 4 or below, the API
response will only contain the value of the `result`; no `error` field is available for error handling.
You can use whatever language or tool you like to issue request to AnkiConnect, but a couple of simple examples are
included below as reference.
2020-04-22 01:22:10 +00:00
#### Curl
2019-02-03 16:48:57 +00:00
```bash
curl localhost:8765 -X POST -d "{\"action\": \"deckNames\", \"version\": 6}"
```
2020-04-22 01:22:10 +00:00
#### Python
2019-02-03 16:48:57 +00:00
```python
import json
2019-09-22 10:28:25 +00:00
import urllib.request
2019-02-03 16:48:57 +00:00
def request(action, **params):
return {'action': action, 'params': params, 'version': 6}
def invoke(action, **params):
2019-09-22 10:28:25 +00:00
requestJson = json.dumps(request(action, **params)).encode('utf-8')
response = json.load(urllib.request.urlopen(urllib.request.Request('http://localhost:8765', requestJson)))
2019-02-03 16:48:57 +00:00
if len(response) != 2:
raise Exception('response has an unexpected number of fields')
if 'error' not in response:
raise Exception('response is missing required error field')
if 'result' not in response:
raise Exception('response is missing required result field')
if response['error'] is not None:
raise Exception(response['error'])
return response['result']
invoke('createDeck', deck='test1')
result = invoke('deckNames')
print('got list of decks: {}'.format(result))
```
2020-04-22 01:22:10 +00:00
#### JavaScript
2017-02-01 17:23:09 +00:00
2017-09-30 00:03:48 +00:00
```javascript
2019-02-03 16:48:57 +00:00
function invoke(action, version, params={}) {
2017-02-03 04:14:24 +00:00
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
2019-02-03 16:48:57 +00:00
xhr.addEventListener('error', () => reject('failed to issue request'));
2017-09-10 05:28:09 +00:00
xhr.addEventListener('load', () => {
try {
const response = JSON.parse(xhr.responseText);
2019-02-03 16:48:57 +00:00
if (Object.getOwnPropertyNames(response).length != 2) {
throw 'response has an unexpected number of fields';
}
if (!response.hasOwnProperty('error')) {
throw 'response is missing required error field';
}
if (!response.hasOwnProperty('result')) {
throw 'response is missing required result field';
}
2017-09-10 05:28:09 +00:00
if (response.error) {
throw response.error;
}
2019-02-03 16:48:57 +00:00
resolve(response.result);
2017-09-10 05:28:09 +00:00
} catch (e) {
reject(e);
2017-02-03 04:14:24 +00:00
}
});
xhr.open('POST', 'http://127.0.0.1:8765');
2017-08-31 04:26:28 +00:00
xhr.send(JSON.stringify({action, version, params}));
2017-02-03 04:14:24 +00:00
});
}
2017-02-01 17:23:09 +00:00
2019-02-03 16:48:57 +00:00
await invoke('createDeck', {deck: 'test1'});
const result = await invoke('deckNames', 6);
console.log(`got list of decks: ${result}`);
2017-05-06 12:39:38 +00:00
```
2020-04-22 01:22:10 +00:00
### Supported Actions
2017-08-22 08:43:37 +00:00
2020-05-25 00:23:37 +00:00
Documentation for currently supported actions is split up by category and is referenced below. Note that deprecated APIs
will continue to function despite not being listed on this page as long as your request is labeled with a version number
2020-05-25 00:50:48 +00:00
corresponding to when the API was available for use.
2020-05-25 00:23:37 +00:00
2020-05-25 00:25:17 +00:00
* [Cards](https://github.com/FooSoft/anki-connect/blob/master/actions/cards.md)
* [Decks](https://github.com/FooSoft/anki-connect/blob/master/actions/decks.md)
* [Graphical](https://github.com/FooSoft/anki-connect/blob/master/actions/graphical.md)
* [Media](https://github.com/FooSoft/anki-connect/blob/master/actions/media.md)
* [Miscellaneous](https://github.com/FooSoft/anki-connect/blob/master/actions/miscellaneous.md)
* [Models](https://github.com/FooSoft/anki-connect/blob/master/actions/models.md)
* [Notes](https://github.com/FooSoft/anki-connect/blob/master/actions/notes.md)
* [Statistics](https://github.com/FooSoft/anki-connect/blob/master/actions/statistics.md)
2021-01-18 20:36:47 +00:00
### Hey, could you add a new action to support $FEATURE?
The primary goal for AnkiConnect was to support real-time flash card creation from the
[Yomichan](https://foosoft.net/projects/yomichan/) browser extension. The current API provides all the required actions
to make this happen. I recognise that the role of AnkiConnect has evolved from this original vision, and I am happy to
review new feature requests.
With that said, *this project operates on a self-serve model*. If you would like a new feature, create a PR. I'll review
it and if it looks good, it will be merged in. *Requests to add new features without accompanying PRs will not be
serviced*. Make sure that your PRs meet the following criteria:
* Attempt to match style of the surrounding code.
* Have accompanying documentation with examples.
2021-01-19 05:03:27 +00:00
* Have accompanying tests that verify operation.
* Implement features useful in other applications.