kv-anki-connect/README.md
2025-06-06 16:07:58 +08:00

4484 lines
94 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Anki-Connect
Anki-Connect 使外部应用程序(如 Yomichan能够通过简单的 HTTP API 与[Anki](https://apps.ankiweb.net/)进行通信。它的功能包括对用户卡片组执行查询、自动创建新卡片等。Anki-Connect 与最新的稳定版(2.1.x)Anki 兼容;旧版本(2.0.x 及以下)不再受支持。
## 安装
安装过程与其他 Anki 插件类似,可以通过以下三个步骤完成:
1. 在 Anki 中选择`工具` | `插件` | `获取插件...`,打开`安装插件`对话框。
2. 在标有`代码`的文本框中输入[2055492159](https://ankiweb.net/shared/info/2055492159),然后按`确定`按钮继续。
3. 当提示重启 Anki 时,请按照要求进行操作,以完成 Anki-Connect 的安装。
Anki 必须在后台保持运行,以便其他应用程序能够使用 Anki-Connect。您可以随时通过在浏览器中访问`localhost:8765`来验证 Anki-Connect 是否在运行。如果服务器正在运行,您将在浏览器窗口中看到`Anki-Connect`的消息。
### Windows 用户注意事项
Windows 用户可能会在 Anki 启动时看到防火墙提示对话框。这是因为 Anki-Connect 运行了本地 HTTP 服务器,以便其他应用程序能够连接到它。主应用程序 Anki 必须被允许通过防火墙,此插件才能正常运行。
### MacOS 用户注意事项
从[Mac OS X Mavericks](https://en.wikipedia.org/wiki/OS_X_Mavericks)开始,操作系统引入了名为*App Nap*的功能。此功能会使某些已打开但不可见的应用程序进入挂起状态。由于此行为会导致 Anki-Connect 在前台显示其他窗口时停止工作,因此应为 Anki 禁用 App Nap
1. 启动终端应用程序。
2. 在终端窗口中执行以下命令:
```bash
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
```
3. 重启 Anki。
## 开发者应用程序接口
Anki-Connect 通过易于使用的 API 向外部应用程序公开 Anki 的内部功能。安装后,只要启动 Anki该插件就会在 8765 端口启动 HTTP 服务器。其他应用程序(包括浏览器扩展)可以通过 HTTP 请求与其通信。
默认情况下Anki-Connect 只会将 HTTP 服务器绑定到`127.0.0.1`IP 地址,因此您只能从运行它的同一主机访问它。如果您需要通过网络访问,可以在配置中更改绑定地址。进入工具->插件->AnkiConnect->配置,更改"webBindAddress"值。例如,您可以将其设置为`0.0.0.0`,以将其绑定到主机上的所有网络接口。这也需要重启 Anki。
### 调用示例
每个请求都由一个包含`action`、`version`、上下文`params`和用于认证的`key`值(可选,默认可以省略)的 JSON 编码对象组成。Anki-Connect 将返回一个包含两个字段的对象:`result`和`error`。`result`字段包含执行的 API 的返回值,而`error`字段是在 API 执行期间抛出的任何异常的描述(如果执行成功,则使用值`null`)。
_成功响应示例_
```json
{ "result": ["Default", "Filtered Deck 1"], "error": null }
```
_失败响应示例_
```json
{ "result": null, "error": "unsupported action" }
```
```json
{ "result": null, "error": "guiBrowse() got an unexpected keyword argument 'foobar'" }
```
为了与旧版本 Anki-Connect 设计的客户端兼容,如果请求中未提供`version`字段,版本将默认为 4。此外当提供的版本为 4 级或以下时API 响应将只包含`result`的值;没有`error`字段可用于错误处理。
您可以使用任何语言或工具向 Anki-Connect 发出请求,但下面包含了几个简单的示例作为参考。
#### Curl
```bash
curl localhost:8765 -X POST -d '{"action": "deckNames", "version": 6}'
```
#### Powershell
```powershell
(Invoke-RestMethod -Uri http://localhost:8765 -Method Post -Body '{"action": "deckNames", "version": 6}').result
```
#### Python
```python
import json
import urllib.request
def request(action, **params):
return {'action': action, 'params': params, 'version': 6}
def invoke(action, **params):
requestJson = json.dumps(request(action, **params)).encode('utf-8')
response = json.load(urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:8765', requestJson)))
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))
```
#### JavaScript
```javascript
function invoke(action, version, params = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener('error', () => reject('failed to issue request'));
xhr.addEventListener('load', () => {
try {
const response = JSON.parse(xhr.responseText);
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';
}
if (response.error) {
throw response.error;
}
resolve(response.result);
} catch (e) {
reject(e);
}
});
xhr.open('POST', 'http://127.0.0.1:8765');
xhr.send(JSON.stringify({ action, version, params }));
});
}
await invoke('createDeck', 6, { deck: 'test1' });
const result = await invoke('deckNames', 6);
console.log(`got list of decks: ${result}`);
```
### 认证
Anki-Connect 支持要求认证以便进行 API 请求。
默认情况下,此支持是*禁用*的,但可以通过在 Anki-Config 的设置(工具->插件->AnkiConnect->配置)中设置`apiKey`字段为所需的字符串来启用。
如果您已经这样做,您应该会看到[`requestPermission`](#requestpermission) API 请求返回`true`作为`requireApiKey`。
然后您必须在任何进一步的 API 请求体中包含一个名为`key`的附加参数,其值必须与配置的 API 密钥匹配。
### 嘿,你能添加一个新的 action 来支持$FEATURE 吗?
Anki-Connect 的主要目标是支持来自 Yomichan 浏览器扩展的实时闪卡创建。当前的 API 提供了所有必要的动作来实现这一点。我认识到 Anki-Connect 的角色已经从这一最初愿景演变,而且我很乐意审查新的功能请求。
话虽如此_本项目采用自助服务模式_。如果你想要一个新功能请创建一个 PR。我会审查它如果看起来不错就会合并。_没有附带拉取请求的添加新功能的请求将不会得到处理_。确保你的拉取请求满足以下标准
- 尝试匹配周围代码的风格。
- 有附带的文档和示例。
- 有验证操作的附带测试。
- 实现在其他应用中有用的功能。
## 支持的动作
当前支持的动作的文档按类别分类并在下面引用。请注意,已弃用的 API 将继续运行,尽管未在此页面上列出,只要您的请求标有对应 API 可用时的版本号。搜索参数传递给 Anki更多信息请查看文档https://docs.ankiweb.net/searching.html
- [卡片操作](#card-actions)
- [卡组操作](#deck-actions)
- [图形界面操作](#graphical-actions)
- [媒体操作](#media-actions)
- [杂项操作](#miscellaneous-actions)
- [模型操作](#model-actions)
- [笔记操作](#note-actions)
- [统计操作](#statistic-actions)
---
### 卡片操作
#### `getEaseFactors`
- 返回一个数组,包含给定卡片的简易度因子(按相同顺序)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getEaseFactors",
"version": 6,
"params": {
"cards": [1483959291685, 1483959293217]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [4100, 3900],
"error": null
}
```
</details>
#### `setEaseFactors`
- 通过卡片 ID 设置卡片的简易度因子;如果成功(所有卡片都存在)则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "setEaseFactors",
"version": 6,
"params": {
"cards": [1483959291685, 1483959293217],
"easeFactors": [4100, 3900]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [true, true],
"error": null
}
```
</details>
#### `setSpecificValueOfCard`
- 设置单个卡片的特定值。由于更改卡片的某些值可能会在数据库中造成混乱,一些键需要将参数"warning_check"设置为 True。
这可用于设置卡片的标志、更改其简易度因子、更改筛选卡组中的复习顺序以及更改列"data"(目前显然未被 anki 使用),以及许多其他值。
可以在[AnkiDroid 的 wiki](https://github.com/ankidroid/Anki-Android/wiki/Database-Structure)上找到值的列表及其各自的用途解释。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "setSpecificValueOfCard",
"version": 6,
"params": {
"card": 1483959291685,
"keys": ["flags", "odue"],
"newValues": ["1", "-100"]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [true, true],
"error": null
}
```
</details>
#### `suspend`
- 通过卡片 ID 暂停卡片;如果成功(至少有一张卡片之前没有被暂停)则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "suspend",
"version": 6,
"params": {
"cards": [1483959291685, 1483959293217]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `unsuspend`
- 通过卡片 ID 取消暂停卡片;如果成功(至少有一张卡片之前被暂停)则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "unsuspend",
"version": 6,
"params": {
"cards": [1483959291685, 1483959293217]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `suspended`
- 通过 ID 检查卡片是否被暂停。如果被暂停则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "suspended",
"version": 6,
"params": {
"card": 1483959293217
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `areSuspended`
- 返回一个数组,表示每张给定卡片是否被暂停(按相同顺序)。如果卡片不存在,则返回`null`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "areSuspended",
"version": 6,
"params": {
"cards": [1483959291685, 1483959293217, 1234567891234]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [false, true, null],
"error": null
}
```
</details>
#### `areDue`
- 返回一个数组表示每张给定卡片是否到期按相同顺序。_注意_学习队列中有大间隔超过 20 分钟)的卡片被视为未到期,直到其间隔时间过去为止,这与 Anki 在复习时对待它们的方式相匹配。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "areDue",
"version": 6,
"params": {
"cards": [1483959291685, 1483959293217]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [false, true],
"error": null
}
```
</details>
#### `getIntervals`
- 返回一个数组,包含每个给定卡片 ID 的最近间隔,或者当`complete`为`true`时,返回每个给定卡片 ID 的所有间隔的二维数组。负间隔以秒为单位,正间隔以天为单位。
<details>
<summary><i>示例请求1</i></summary>
```json
{
"action": "getIntervals",
"version": 6,
"params": {
"cards": [1502298033753, 1502298036657]
}
}
```
</details>
<details>
<summary><i>示例结果1</i></summary>
```json
{
"result": [-14400, 3],
"error": null
}
```
</details>
<details>
<summary><i>示例请求2</i></summary>
```json
{
"action": "getIntervals",
"version": 6,
"params": {
"cards": [1502298033753, 1502298036657],
"complete": true
}
}
```
</details>
<details>
<summary><i>示例结果2</i></summary>
```json
{
"result": [
[-120, -180, -240, -300, -360, -14400],
[-120, -180, -240, -300, -360, -14400, 1, 3]
],
"error": null
}
```
</details>
#### `findCards`
- 返回给定查询的卡片 ID 数组。功能上与`guiBrowse`相同,但不使用 GUI 以获得更好的性能。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "findCards",
"version": 6,
"params": {
"query": "deck:current"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [1494723142483, 1494703460437, 1494703479525],
"error": null
}
```
</details>
#### `cardsToNotes`
- 返回给定卡片 ID 的笔记 ID 的无序数组。对于具有相同笔记的卡片ID 在数组中只给出一次。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "cardsToNotes",
"version": 6,
"params": {
"cards": [1502098034045, 1502098034048, 1502298033753]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [1502098029797, 1502298025183],
"error": null
}
```
</details>
#### `cardsModTime`
- 返回一个对象列表,包含每个卡片 ID 的修改时间。
此功能比执行`cardsInfo`快约 15 倍。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "cardsModTime",
"version": 6,
"params": {
"cards": [1498938915662, 1502098034048]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"cardId": 1498938915662,
"mod": 1629454092
}
],
"error": null
}
```
</details>
#### `cardsInfo`
- 返回一个对象列表,包含每个卡片 ID 的卡片字段、正反面(包括 CSS、笔记类型、卡片所属的笔记、卡组名称、最后修改时间戳以及简易度和间隔。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "cardsInfo",
"version": 6,
"params": {
"cards": [1498938915662, 1502098034048]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"answer": "back content",
"question": "front content",
"deckName": "Default",
"modelName": "Basic",
"fieldOrder": 1,
"fields": {
"Front": { "value": "front content", "order": 0 },
"Back": { "value": "back content", "order": 1 }
},
"css": "p {font-family:Arial;}",
"cardId": 1498938915662,
"interval": 16,
"note": 1502298033753,
"ord": 1,
"type": 0,
"queue": 0,
"due": 1,
"reps": 1,
"lapses": 0,
"left": 6,
"mod": 1629454092
},
{
"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 }
},
"css": "p {font-family:Arial;}",
"cardId": 1502098034048,
"interval": 23,
"note": 1502298033753,
"ord": 1,
"type": 0,
"queue": 0,
"due": 1,
"reps": 1,
"lapses": 0,
"left": 6
}
],
"error": null
}
```
</details>
#### `forgetCards`
- 忘记卡片,使卡片再次成为新卡片。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "forgetCards",
"version": 6,
"params": {
"cards": [1498938915662, 1502098034048]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `relearnCards`
- 使卡片成为"重新学习"状态。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "relearnCards",
"version": 6,
"params": {
"cards": [1498938915662, 1502098034048]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `answerCards`
- 回答卡片。简易度在 1重来到 4简单之间。将在回答前立即开始计时器。如果卡片存在则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "answerCards",
"version": 6,
"params": {
"answers": [
{
"cardId": 1498938915662,
"ease": 2
},
{
"cardId": 1502098034048,
"ease": 4
}
]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [true, true],
"error": null
}
```
</details>
#### `setDueDate`
- 设置到期日期。如果是新卡片,则将其转为复习卡片,并使其在特定日期到期。
- 0 = 今天
- 1! = 明天 + 将间隔更改为 1
- 3-7 = 随机选择 3-7 天
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "setDueDate",
"version": 6,
"params": {
"cards": [1498938915662, 1502098034048],
"days": "3-7"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
---
### 卡组操作
#### `deckNames`
- 获取当前用户的完整卡组名称列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "deckNames",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["Default"],
"error": null
}
```
</details>
#### `deckNamesAndIds`
- 获取当前用户的完整卡组名称及其对应 ID 的列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "deckNamesAndIds",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": { "Default": 1 },
"error": null
}
```
</details>
#### `getDecks`
- 接受一个卡片 ID 数组,并返回一个对象,其中每个卡组名称作为键,其值是属于该卡组的给定卡片数组。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getDecks",
"version": 6,
"params": {
"cards": [1502298036657, 1502298033753, 1502032366472]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"Default": [1502032366472],
"Japanese::JLPT N3": [1502298036657, 1502298033753]
},
"error": null
}
```
</details>
#### `createDeck`
- 创建一个新的空卡组。不会覆盖同名的已存在卡组。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "createDeck",
"version": 6,
"params": {
"deck": "Japanese::Tokyo"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 1519323742721,
"error": null
}
```
</details>
#### `changeDeck`
- 将具有给定 ID 的卡片移动到不同的卡组,如果卡组尚不存在则创建它。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "changeDeck",
"version": 6,
"params": {
"cards": [1502098034045, 1502098034048, 1502298033753],
"deck": "Japanese::JLPT N3"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `deleteDecks`
- 删除具有给定名称的卡组。
参数`cardsToo` *必须*被指定并设置为`true`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "deleteDecks",
"version": 6,
"params": {
"decks": ["Japanese::JLPT N5", "Easy Spanish"],
"cardsToo": true
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `getDeckConfig`
- 获取给定卡组的配置组对象。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getDeckConfig",
"version": 6,
"params": {
"deck": "Default"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"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
},
"error": null
}
```
</details>
#### `saveDeckConfig`
- 保存给定的配置组,成功时返回`true`,如果配置组的 ID 无效(例如不存在)则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "saveDeckConfig",
"version": 6,
"params": {
"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
}
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `setDeckConfigId`
- 将给定卡组的配置组更改为具有给定 ID 的配置组。成功时返回`true`,如果给定的配置组或任何给定的卡组不存在则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "setDeckConfigId",
"version": 6,
"params": {
"decks": ["Default"],
"configId": 1
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `cloneDeckConfigId`
- 使用给定的名称创建一个新的配置组,从具有给定 ID 的组克隆,或者如果未指定,则从默认组克隆。返回新配置组的 ID或者如果指定的要克隆的组不存在则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "cloneDeckConfigId",
"version": 6,
"params": {
"name": "Copy of Default",
"cloneFrom": 1
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 1502972374573,
"error": null
}
```
</details>
#### `removeDeckConfigId`
- 移除具有给定 ID 的配置组,如果成功则返回`true`如果尝试移除默认配置组ID = 1或不存在的配置组则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "removeDeckConfigId",
"version": 6,
"params": {
"configId": 1502972374573
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `getDeckStats`
- 获取给定卡组的统计信息,如总卡片数和到期卡片数。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getDeckStats",
"version": 6,
"params": {
"decks": ["Japanese::JLPT N5", "Easy Spanish"]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"1651445861967": {
"deck_id": 1651445861967,
"name": "Japanese::JLPT N5",
"new_count": 20,
"learn_count": 0,
"review_count": 0,
"total_in_deck": 1506
},
"1651445861960": {
"deck_id": 1651445861960,
"name": "Easy Spanish",
"new_count": 26,
"learn_count": 10,
"review_count": 5,
"total_in_deck": 852
}
},
"error": null
}
```
</details>
---
### 图形界面操作
#### `guiBrowse`
- 调用*卡片浏览器*对话框并搜索给定查询。返回找到的卡片标识符数组。查询语法[在此处有文档](https://docs.ankiweb.net/searching.html)。
可选地,可以提供`reorderCards`属性来重新排序*卡片浏览器*中显示的卡片。
这是一个包含`order`和`columnId`对象的数组。`order`可以是`ascending`或`descending`,而`columnId`可以是几个列标识符之一(如在[Anki 源代码](https://github.com/ankitects/anki/blob/main/rslib/src/browser_table.rs)中记录的)。
指定的列需要在*卡片浏览器*中可见。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiBrowse",
"version": 6,
"params": {
"query": "deck:current",
"reorderCards": {
"order": "descending",
"columnId": "noteCrt"
}
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [1494723142483, 1494703460437, 1494703479525],
"error": null
}
```
</details>
#### `guiSelectCard`
- 找到*卡片浏览器*对话框的打开实例,并根据卡片标识符选择一张卡片。
如果*卡片浏览器*是打开的,返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiSelectCard",
"version": 6,
"params": {
"card": 1494723142483
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiSelectedNotes`
- 找到*卡片浏览器*对话框的打开实例,并返回选中笔记的标识符数组。如果浏览器未打开,则返回空列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiSelectedNotes",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [1494723142483, 1494703460437, 1494703479525],
"error": null
}
```
</details>
#### `guiAddCards`
- 调用*添加卡片*对话框,使用给定的卡组和模型预设笔记,带有提供的字段值和标签。
多次调用会关闭旧窗口并*重新打开窗口*,使用新提供的值。
可以通过`audio`、`video`和`picture`键将音频、视频和图片文件嵌入到字段中。
请参考`addNote`和`storeMediaFile`的文档,了解这些字段的说明。
结果是如果用户选择确认*添加卡片*对话框,将添加的笔记的 ID。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiAddCards",
"version": 6,
"params": {
"note": {
"deckName": "Default",
"modelName": "Cloze",
"fields": {
"Text": "The capital of Romania is {{c1::Bucharest}}",
"Extra": "Romania is a country in Europe"
},
"tags": ["countries"],
"picture": [
{
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/13/EU-Romania.svg/285px-EU-Romania.svg.png",
"filename": "romania.png",
"fields": ["Extra"]
}
]
}
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 1496198395707,
"error": null
}
```
</details>
#### `guiEditNote`
- 打开*编辑*对话框,显示对应于给定笔记 ID 的笔记。
该对话框类似于*编辑当前*对话框,但:
- 有一个预览按钮,用于预览笔记的卡片
- 有一个浏览按钮,用于打开浏览器并显示这些卡片
- 有上一个/后退按钮,用于导航对话框的历史
- 没有带有关闭按钮的栏
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiEditNote",
"version": 6,
"params": {
"note": 1649198355435
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `guiCurrentCard`
- 返回有关当前卡片的信息,如果不在复习模式,则返回`null`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiCurrentCard",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"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 }
},
"template": "Forward",
"cardId": 1498938915662,
"buttons": [1, 2, 3],
"nextReviews": ["<1m", "<10m", "4d"]
},
"error": null
}
```
</details>
#### `guiStartCardTimer`
- 启动或重置当前卡片的`timerStarted`值。这对于将开始时间推迟到通过 API 显示卡片时很有用,从而在调用`guiAnswerCard`时使记录的回答卡片所花费的时间更准确。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiStartCardTimer",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiShowQuestion`
- 显示当前卡片的问题文本;如果处于复习模式则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiShowQuestion",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiShowAnswer`
- 显示当前卡片的答案文本;如果处于复习模式则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiShowAnswer",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiAnswerCard`
- 回答当前卡片;如果成功则返回`true`,否则返回`false`。注意,在 Anki 接受任何答案之前,必须先显示当前卡片的答案。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiAnswerCard",
"version": 6,
"params": {
"ease": 1
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiUndo`
- 撤销最后一个动作/卡片;如果成功则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiUndo",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiDeckOverview`
- 为具有给定名称的卡组打开*卡组概览*对话框;如果成功则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiDeckOverview",
"version": 6,
"params": {
"name": "Default"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiDeckBrowser`
- 打开*卡组浏览器*对话框。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiDeckBrowser",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `guiDeckReview`
- 开始复习具有给定名称的卡组;如果成功则返回`true`,否则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiDeckReview",
"version": 6,
"params": {
"name": "Default"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `guiImportFile`
- 调用*导入...(Ctrl+Shift+I)*对话框,并可选择提供文件路径。弹出对话框供用户审核导入。支持 Anki 支持的所有文件类型。如果未提供路径,则显示打开文件对话框。在 Windows 上的路径中必须使用正斜杠。仅支持 Anki 2.1.52+。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiImportFile",
"version": 6,
"params": {
"path": "C:/Users/Desktop/cards.txt"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `guiExitAnki`
- 安排一个请求来优雅地关闭 Anki。此操作是异步的因此它会立即返回而不会等待 Anki 进程实际终止。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiExitAnki",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `guiCheckDatabase`
- 请求进行数据库检查,但立即返回而不等待检查完成。因此,即使在数据库检查过程中检测到错误,此操作也将始终返回`true`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "guiCheckDatabase",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
---
### 媒体操作
#### `storeMediaFile`
- 将具有指定 base64 编码内容的文件存储在媒体文件夹中。或者,您可以指定绝对文件路径,或者从中下载文件的 URL。如果提供了`data`、`path`和`url`中的多个,将首先使用`data`字段,然后是`path`,最后是`url`。为了防止 Anki 删除不被任何卡片使用的文件(例如配置文件),请在文件名前加下划线。这些文件仍然会同步到 AnkiWeb。
默认情况下,将删除任何同名的现有文件。设置`deleteExisting`为 false 可以通过[让 Anki 为新文件提供非冲突的名称](https://github.com/ankitects/anki/blob/aeba725d3ea9628c73300648f748140db3fdd5ed/rslib/src/media/files.rs#L194)来防止这种情况。
<details>
<summary><i>示例请求(相对路径):</i></summary>
```json
{
"action": "storeMediaFile",
"version": 6,
"params": {
"filename": "_hello.txt",
"data": "SGVsbG8sIHdvcmxkIQ=="
}
}
```
_`_hello.txt`的内容_:
```
Hello world!
```
</details>
<details>
<summary><i>示例结果(相对路径):</i></summary>
```json
{
"result": "_hello.txt",
"error": null
}
```
</details>
<details>
<summary><i>示例请求(绝对路径):</i></summary>
```json
{
"action": "storeMediaFile",
"version": 6,
"params": {
"filename": "_hello.txt",
"path": "/path/to/file"
}
}
```
</details>
<details>
<summary><i>示例结果(绝对路径):</i></summary>
```json
{
"result": "_hello.txt",
"error": null
}
```
</details>
<details>
<summary><i>示例请求url</i></summary>
```json
{
"action": "storeMediaFile",
"version": 6,
"params": {
"filename": "_hello.txt",
"url": "https://url.to.file"
}
}
```
</details>
<details>
<summary><i>示例结果url</i></summary>
```json
{
"result": "_hello.txt",
"error": null
}
```
</details>
#### `retrieveMediaFile`
- 检索指定文件的 base64 编码内容,如果文件不存在则返回`false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "retrieveMediaFile",
"version": 6,
"params": {
"filename": "_hello.txt"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": "SGVsbG8sIHdvcmxkIQ==",
"error": null
}
```
</details>
#### `getMediaFilesNames`
- 获取与模式匹配的媒体文件名。默认返回所有名称。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getMediaFilesNames",
"version": 6,
"params": {
"pattern": "_hell*.txt"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["_hello.txt"],
"error": null
}
```
</details>
#### `getMediaDirPath`
- 获取当前打开的配置文件的`collection.media`文件夹的完整路径。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getMediaDirPath",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": "/home/user/.local/share/Anki2/Main/collection.media",
"error": null
}
```
</details>
#### `deleteMediaFile`
- 删除媒体文件夹中的指定文件。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "deleteMediaFile",
"version": 6,
"params": {
"filename": "_hello.txt"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
---
### 杂项操作
#### `requestPermission`
- 请求使用此插件公开的 API 的权限。此方法不需要 API 密钥,是唯一接受来自任何来源的请求的方法;其他方法只接受来自受信任来源的请求,这些来源列在插件配置的`webCorsOriginList`下。默认情况下,`localhost`是受信任的。
从不受信任的来源调用此方法将在 Anki 中显示一个弹出窗口,询问用户是否允许您的来源使用 API来自受信任来源的调用将返回结果而不显示弹出窗口。
在拒绝许可时,用户还可以选择忽略来自该来源的进一步许可请求。这些来源最终会出现在`ignoreOriginList`中,可通过插件配置进行编辑。
结果始终包含`permission`字段,该字段反过来包含字符串`granted`或`denied`,对应于您的来源是否受信任。如果您的来源受信任,还将返回字段`requireApiKey`(如果需要则为`true`)和`version`。
这应该是您进行的第一个调用,以确保您的应用程序和 Anki-Connect 能够相互正确通信。新版本的 Anki-Connect 向后兼容;只要您使用在报告的 Anki-Connect 版本或更早版本中可用的操作,一切都应该正常工作。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "requestPermission",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"permission": "granted",
"requireApiKey": false,
"version": 6
},
"error": null
}
```
```json
{
"result": {
"permission": "denied"
},
"error": null
}
```
</details>
#### `version`
- 获取此插件公开的 API 的版本。目前定义了版本`1`到`6`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "version",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 6,
"error": null
}
```
</details>
#### `apiReflect`
- 获取有关 AnkiConnect API 的信息。该请求支持以下参数:
- `scopes` - 一个包含要获取反射信息的范围的数组。
当前唯一支持的值是 `"actions"`。
- `actions` - 为 `null` 或一个包含 API 方法名称的数组。
如果值为 `null`,结果将列出所有可用的 API 动作。
如果值是一个字符串数组,结果仅包含在该数组中的动作。
结果将包含使用的作用域列表以及每个作用域的值。
例如,`"actions"` 范围将包含一个 `"actions"` 属性,其中包含受支持的动作名称列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "apiReflect",
"version": 6,
"params": {
"scopes": ["actions", "invalidType"],
"actions": ["apiReflect", "invalidMethod"]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"scopes": ["actions"],
"actions": ["apiReflect"]
},
"error": null
}
```
</details>
#### `sync`
- 将本地 Anki 集合与 AnkiWeb 同步。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "sync",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `getProfiles`
- 检索配置文件列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getProfiles",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["User 1"],
"error": null
}
```
</details>
#### `getActiveProfile`
- 检索活动的配置文件。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getActiveProfile",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": "User 1",
"error": null
}
```
</details>
#### `loadProfile`
- 选择请求中指定的配置文件。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "loadProfile",
"version": 6,
"params": {
"name": "user1"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `multi`
- 在一个请求中执行多个操作,返回一个包含每个操作响应的数组(按给定顺序)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "multi",
"version": 6,
"params": {
"actions": [
{
"action": "deckNames"
},
{
"action": "deckNames",
"version": 6
},
{
"action": "invalidAction",
"params": {"useless": "param"}
},
{
"action": "invalidAction",
"params": {"useless": "param"},
"version": 6
}
]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
["Default"],
{"result": ["Default"], "error": null},
{"result": null, "error": "unsupported action"},
{"result": null, "error": "unsupported action"}
],
"error": null
}
```
</details>
#### `exportPackage`
- 将给定牌组导出为 `.apkg` 格式。如果成功则返回 `true`,否则返回 `false`。可选属性
`includeSched`(默认为 `false`)可以指定是否包含卡片的调度数据。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "exportPackage",
"version": 6,
"params": {
"deck": "Default",
"path": "/data/Deck.apkg",
"includeSched": true
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `importPackage`
- 将以 `.apkg` 格式的文件导入到集合中。如果成功则返回 `true`,否则返回 `false`。
注意,文件路径相对于 Anki 的 collection.media 文件夹,而不是客户端。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "importPackage",
"version": 6,
"params": {
"path": "/data/Deck.apkg"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
#### `reloadCollection`
- 告诉 Anki 从数据库重新加载所有数据。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "reloadCollection",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
---
### 模型操作
#### `modelNames`
- 获取当前用户的所有模型名称的完整列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelNames",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["Basic", "Basic (and reversed card)"],
"error": null
}
```
</details>
#### `modelNamesAndIds`
- 获取当前用户的所有模型名称及其对应 ID 的完整列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelNamesAndIds",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"Basic": 1483883011648,
"Basic (and reversed card)": 1483883011644,
"Basic (optional reversed card)": 1483883011631,
"Cloze": 1483883011630
},
"error": null
}
```
</details>
#### `findModelsById`
- 从当前用户提供的模型 ID 中获取模型列表。
<details>
<summary><i>示例请求:</i></summary>
`json
{
"action": "findModelsById",
"version": 6,
"params": {
"modelIds": [1704387367119, 1704387398570]
}
}
`
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"id": 1704387367119,
"name": "Basic",
"type": 0,
"mod": 1704387367,
"usn": -1,
"sortf": 0,
"did": null,
"tmpls": [
{
"name": "Card 1",
"ord": 0,
"qfmt": "{{Front}}",
"afmt": "{{FrontSide}}
<hr id=answer>
{{Back}}",
"bqfmt": "",
"bafmt": "",
"did": null,
"bfont": "",
"bsize": 0,
"id": 9176047152973362695
}
],
"flds": [
{
"name": "Front",
"ord": 0,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": 2453723143453745216,
"tag": null,
"preventDeletion": false
},
{
"name": "Back",
"ord": 1,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": -4853200230425436781,
"tag": null,
"preventDeletion": false
}
],
"css": ".card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
",
"latexPre": "\\documentclass[12pt]{article}
\\special{papersize=3in,5in}
\\usepackage[utf8]{inputenc}
\\usepackage{amssymb,amsmath}
\\pagestyle{empty}
\\setlength{\\parindent}{0in}
\\begin{document}
",
"latexPost": "\\end{document}",
"latexsvg": false,
"req": [
[
0,
"any",
[
0
]
]
],
"originalStockKind": 1
},
{
"id": 1704387398570,
"name": "Basic (and reversed card)",
"type": 0,
"mod": 1704387398,
"usn": -1,
"sortf": 0,
"did": null,
"tmpls": [
{
"name": "Card 1",
"ord": 0,
"qfmt": "{{Front}}",
"afmt": "{{FrontSide}}
<hr id=answer>
{{Back}}",
"bqfmt": "",
"bafmt": "",
"did": null,
"bfont": "",
"bsize": 0,
"id": 1689886528158874152
},
{
"name": "Card 2",
"ord": 1,
"qfmt": "{{Back}}",
"afmt": "{{FrontSide}}
<hr id=answer>
{{Front}}",
"bqfmt": "",
"bafmt": "",
"did": null,
"bfont": "",
"bsize": 0,
"id": -7839609225644824587
}
],
"flds": [
{
"name": "Front",
"ord": 0,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": -7787837672455357996,
"tag": null,
"preventDeletion": false
},
{
"name": "Back",
"ord": 1,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": 6364828289839985081,
"tag": null,
"preventDeletion": false
}
],
"css": ".card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
",
"latexPre": "\\documentclass[12pt]{article}
\\special{papersize=3in,5in}
\\usepackage[utf8]{inputenc}
\\usepackage{amssymb,amsmath}
\\pagestyle{empty}
\\setlength{\\parindent}{0in}
\\begin{document}
",
"latexPost": "\\end{document}",
"latexsvg": false,
"req": [
[
0,
"any",
[
0
]
],
[
1,
"any",
[
1
]
]
],
"originalStockKind": 1
}
],
"error": null
}
```
</details>
#### `findModelsByName`
- 从当前用户提供的模型名称中获取模型列表。
<details>
<summary><i>示例请求:</i></summary>
`json
{
"action": "findModelsByName",
"version": 6,
"params": {
"modelNames": ["Basic", "Basic (and reversed card)"]
}
}
`
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"id": 1704387367119,
"name": "Basic",
"type": 0,
"mod": 1704387367,
"usn": -1,
"sortf": 0,
"did": null,
"tmpls": [
{
"name": "Card 1",
"ord": 0,
"qfmt": "{{Front}}",
"afmt": "{{FrontSide}}
<hr id=answer>
{{Back}}",
"bqfmt": "",
"bafmt": "",
"did": null,
"bfont": "",
"bsize": 0,
"id": 9176047152973362695
}
],
"flds": [
{
"name": "Front",
"ord": 0,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": 2453723143453745216,
"tag": null,
"preventDeletion": false
},
{
"name": "Back",
"ord": 1,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": -4853200230425436781,
"tag": null,
"preventDeletion": false
}
],
"css": ".card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
",
"latexPre": "\\documentclass[12pt]{article}
\\special{papersize=3in,5in}
\\usepackage[utf8]{inputenc}
\\usepackage{amssymb,amsmath}
\\pagestyle{empty}
\\setlength{\\parindent}{0in}
\\begin{document}
",
"latexPost": "\\end{document}",
"latexsvg": false,
"req": [
[
0,
"any",
[
0
]
]
],
"originalStockKind": 1
},
{
"id": 1704387398570,
"name": "Basic (and reversed card)",
"type": 0,
"mod": 1704387398,
"usn": -1,
"sortf": 0,
"did": null,
"tmpls": [
{
"name": "Card 1",
"ord": 0,
"qfmt": "{{Front}}",
"afmt": "{{FrontSide}}
<hr id=answer>
{{Back}}",
"bqfmt": "",
"bafmt": "",
"did": null,
"bfont": "",
"bsize": 0,
"id": 1689886528158874152
},
{
"name": "Card 2",
"ord": 1,
"qfmt": "{{Back}}",
"afmt": "{{FrontSide}}
<hr id=answer>
{{Front}}",
"bqfmt": "",
"bafmt": "",
"did": null,
"bfont": "",
"bsize": 0,
"id": -7839609225644824587
}
],
"flds": [
{
"name": "Front",
"ord": 0,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": -7787837672455357996,
"tag": null,
"preventDeletion": false
},
{
"name": "Back",
"ord": 1,
"sticky": false,
"rtl": false,
"font": "Arial",
"size": 20,
"description": "",
"plainText": false,
"collapsed": false,
"excludeFromSearch": false,
"id": 6364828289839985081,
"tag": null,
"preventDeletion": false
}
],
"css": ".card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
",
"latexPre": "\\documentclass[12pt]{article}
\\special{papersize=3in,5in}
\\usepackage[utf8]{inputenc}
\\usepackage{amssymb,amsmath}
\\pagestyle{empty}
\\setlength{\\parindent}{0in}
\\begin{document}
",
"latexPost": "\\end{document}",
"latexsvg": false,
"req": [
[
0,
"any",
[
0
]
],
[
1,
"any",
[
1
]
]
],
"originalStockKind": 1
}
],
"error": null
}
```
</details>
#### `modelFieldNames`
- 获取提供模型名称的字段名称的完整列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldNames",
"version": 6,
"params": {
"modelName": "Basic"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["Front", "Back"],
"error": null
}
```
</details>
#### `modelFieldDescriptions`
- 获取提供模型名称的字段描述(在 GUI 编辑器中字段为空时看到的文本)的完整列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldDescriptions",
"version": 6,
"params": {
"modelName": "Basic"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["", ""],
"error": null
}
```
</details>
#### `modelFieldFonts`
- 获取字体及其字体大小的完整列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldFonts",
"version": 6,
"params": {
"modelName": "Basic"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"Front": {
"font": "Arial",
"size": 20
},
"Back": {
"font": "Arial",
"size": 20
}
},
"error": null
}
```
</details>
#### `modelFieldsOnTemplates`
- 返回一个对象,指示给定模型名称的每个卡模板的问题和答案侧的字段。问题侧在每个数组中首先给出。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldsOnTemplates",
"version": 6,
"params": {
"modelName": "Basic (and reversed card)"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"Card 1": [["Front"], ["Back"]],
"Card 2": [["Back"], ["Front"]]
},
"error": null
}
```
</details>
#### `createModel`
- 创建一个用于 Anki 的新模型。用户必须提供 `modelName`, `inOrderFields` 和 `cardTemplates`。
可选字段有 `css` 和 `isCloze`。如果未指定,`css` 将使用默认的 Anki css`isCloze` 将等于 `false`。如果 `isCloze` 为 `true`,则模型将作为 Cloze 创建。
可以为 `cardTemplates` 中的每个条目提供可选的 `Name` 字段。默认情况下,卡名称将是 `Card 1`、`Card 2` 等等。
<details>
<summary><i>示例请求:</i></summary>
`json
{
"action": "createModel",
"version": 6,
"params": {
"modelName": "newModelName",
"inOrderFields": ["Field1", "Field2", "Field3"],
"css": "Optional CSS with default to builtin css",
"isCloze": false,
"cardTemplates": [
{
"Name": "My Card 1",
"Front": "Front html {{Field1}}",
"Back": "Back html {{Field2}}"
}
]
}
}
`
</details>
<details>
<summary><i>示例结果:</i></summary>
`json
{
"result":{
"sortf":0,
"did":1,
"latexPre":"\\documentclass[12pt]{article}
\\special{papersize=3in,5in}
\\usepackage[utf8]{inputenc}
\\usepackage{amssymb,amsmath}
\\pagestyle{empty}
\\setlength{\\parindent}{0in}
\\begin{document}
",
"latexPost":"\\end{document}",
"mod":1551462107,
"usn":-1,
"vers":[
],
"type":0,
"css":".card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
",
"name":"TestApiModel",
"flds":[
{
"name":"Field1",
"ord":0,
"sticky":false,
"rtl":false,
"font":"Arial",
"size":20,
"media":[
]
},
{
"name":"Field2",
"ord":1,
"sticky":false,
"rtl":false,
"font":"Arial",
"size":20,
"media":[
]
}
],
"tmpls":[
{
"name":"My Card 1",
"ord":0,
"qfmt":"",
"afmt":"This is the back of the card {{Field2}}",
"did":null,
"bqfmt":"",
"bafmt":""
}
],
"tags":[
],
"id":1551462107104,
"req":[
[
0,
"none",
[
]
]
]
},
"error":null
}
`
</details>
#### `modelTemplates`
- 返回一个对象,表示通过提供的模型名称连接的每张卡的模板内容。
<details>
<summary><i>示例请求:</i></summary>
`json
{
"action": "modelTemplates",
"version": 6,
"params": {
"modelName": "Basic (and reversed card)"
}
}
`
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"Card 1": {
"Front": "{{Front}}",
"Back": "{{FrontSide}}
<hr id=answer>
{{Back}}"
},
"Card 2": {
"Front": "{{Back}}",
"Back": "{{FrontSide}}
<hr id=answer>
{{Front}}"
}
},
"error": null
}
```
</details>
#### `modelStyling`
- 获取通过提供的模型名称的模型的 CSS 样式。
<details>
<summary><i>示例请求:</i></summary>
`json
{
"action": "modelStyling",
"version": 6,
"params": {
"modelName": "Basic (and reversed card)"
}
}
`
</details>
<details>
<summary><i>示例结果:</i></summary>
`json
{
"result": {
"css": ".card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
"
},
"error": null
}
`
</details>
#### `updateModelTemplates`
- 通过名称修改现有模型的模板。仅修改请求中指定的卡和指定的侧面。
如果请求中未包含现有的卡或侧面,则不会进行任何更改。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "updateModelTemplates",
"version": 6,
"params": {
"model": {
"name": "Custom",
"templates": {
"Card 1": {
"Front": "{{Question}}?",
"Back": "{{Answer}}!"
}
}
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `updateModelStyling`
- 修改现有模型的 CSS 样式。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "updateModelStyling",
"version": 6,
"params": {
"model": {
"name": "Custom",
"css": "p { color: blue; }"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `findAndReplaceInModels`
- 在现有模型中查找并替换字符串。可以通过设置为 true/false 来自定义在 front、back 或 css 中替换。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "findAndReplaceInModels",
"version": 6,
"params": {
"model": {
"modelName": "",
"findText": "text_to_replace",
"replaceText": "replace_with_text",
"front": true,
"back": true,
"css": true
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 1,
"error": null
}
```
</details>
#### `modelTemplateRename`
- 重命名现有模型中的模板。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelTemplateRename",
"version": 6,
"params": {
"modelName": "Basic",
"oldTemplateName": "Card 1",
"newTemplateName": "Card 1 renamed"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelTemplateReposition`
- 重新定位现有模型中的模板。
`index` 的值从 0 开始。例如,索引为 `0` 时将模板放在第一个位置,索引为 `2` 时将模板放在第三个位置。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelTemplateReposition",
"version": 6,
"params": {
"modelName": "Basic",
"templateName": "Card 1",
"index": 1
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelTemplateAdd`
- 通过名称向现有模型添加模板。如果您想更新现有模板,请使用 `updateModelTemplates`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelTemplateAdd",
"version": 6,
"params": {
"modelName": "Basic",
"template": {
"Name": "Card 3",
"Front": "Front html {{Field1}}",
"Back": "Back html {{Field2}}"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelTemplateRemove`
- 从现有模型中删除模板。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelTemplateRemove",
"version": 6,
"params": {
"modelName": "Basic",
"templateName": "Card 1"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldRename`
- 重命名给定模型的字段名称。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldRename",
"version": 6,
"params": {
"modelName": "Basic",
"oldFieldName": "Front",
"newFieldName": "FrontRenamed"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldReposition`
- 在给定模型的字段列表中重新定位字段。
`index` 的值从 0 开始。例如,索引为 `0` 时将字段放在第一个位置,索引为 `2` 时将字段放在第三个位置。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldReposition",
"version": 6,
"params": {
"modelName": "Basic",
"fieldName": "Back",
"index": 0
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldAdd`
- 在给定模型中创建一个新字段。
可以选择性地提供 `index` 值,其工作方式与 `modelFieldReposition` 中的索引完全相同。默认情况下,字段会被添加到字段列表的末尾。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldAdd",
"version": 6,
"params": {
"modelName": "Basic",
"fieldName": "NewField",
"index": 0
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldRemove`
- 删除给定模型内的字段。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldRemove",
"version": 6,
"params": {
"modelName": "Basic",
"fieldName": "Front"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldSetFont`
- 设置给定模型内字段的字体。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldSetFont",
"version": 6,
"params": {
"modelName": "Basic",
"fieldName": "Front",
"font": "Courier"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldSetFontSize`
- 设置给定模型内字段的字体大小。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldSetFontSize",
"version": 6,
"params": {
"modelName": "Basic",
"fieldName": "Front",
"fontSize": 10
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `modelFieldSetDescription`
- 设置给定模型内字段的描述(在字段为空时在 GUI 编辑器中看到的文本)。
较旧版本的 Anki2.1.49 及以下)没有字段描述。在这种情况下,这将返回 `false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "modelFieldSetDescription",
"version": 6,
"params": {
"modelName": "Basic",
"fieldName": "Front",
"description": "example field description"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": true,
"error": null
}
```
</details>
---
### 笔记操作
#### `addNote`
- 使用给定的牌组和模型,以及提供的字段值和标签创建笔记。在成功创建时返回创建的笔记标识符,在失败时返回 `null`。
Anki-Connect 可以下载音频、视频和图片文件并将它们嵌入到新创建的笔记中。相应的 `audio`、`video` 和 `picture` 笔记成员是可选的,可以省略。如果您选择包含其中任何一个,它们应该包含一个单个对象或一组具有必填 `filename` 字段和 `data`、`path` 或 `url` 其中之一的对象。请参阅 `storeMediaFile` 文档以了解这些字段的解释。
可以选择性地提供 `skipHash` 字段以跳过包含与提供的 MD5 哈希匹配的文件。这对于避免保存错误页面和存根文件很有用。
`fields` 成员是一个应播放音频或视频或在 Anki 中显示卡片时显示图片的字段列表。`options` 组内的 `allowDuplicate` 成员可以设置为 true 以启用添加重复卡片。通常重复卡片不能被添加,并会触发异常。
`duplicateScope` 成员可以在 `options` 内用于指定检查重复项的范围。值为 `"deck"` 将只在目标牌组中检查重复项;其他任何值将在整个集合中检查。
`duplicateScopeOptions` 对象可用于指定一些额外的设置:
- `duplicateScopeOptions.deckName` 将指定在检查重复项时使用的牌组。如果未定义或为 `null`,将使用目标牌组。
- `duplicateScopeOptions.checkChildren` 将改变是否在子牌组中检查重复卡片。默认值为 `false`。
- `duplicateScopeOptions.checkAllModels` 指定是否在所有笔记类型之间执行重复检查。默认值为 `false`。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "addNote",
"version": 6,
"params": {
"note": {
"deckName": "Default",
"modelName": "Basic",
"fields": {
"Front": "front content",
"Back": "back content"
},
"options": {
"allowDuplicate": false,
"duplicateScope": "deck",
"duplicateScopeOptions": {
"deckName": "Default",
"checkChildren": false,
"checkAllModels": false
}
},
"tags": [
"yomichan"
],
"audio": [{
"url": "https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?kanji=猫&kana=ねこ",
"filename": "yomichan_ねこ_猫.mp3",
"skipHash": "7e2c2f954ef6051373ba916f000168dc",
"fields": [
"Front"
]
}],
"video": [{
"url": "https://cdn.videvo.net/videvo_files/video/free/2015-06/small_watermarked/Contador_Glam_preview.mp4",
"filename": "countdown.mp4",
"skipHash": "4117e8aab0d37534d9c8eac362388bbe",
"fields": [
"Back"
]
}],
"picture": [{
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/A_black_cat_named_Tilly.jpg/220px-A_black_cat_named_Tilly.jpg",
"filename": "black_cat.jpg",
"skipHash": "8d6e4646dfae812bf39651b59d7429ce",
"fields": [
"Back"
]
}]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 1496198395707,
"error": null
}
```
</details>
#### `addNotes`
- 使用给定的牌组和模型,以及提供的字段值和标签创建多个笔记。返回创建的笔记标识符的数组。在发生任何错误的情况下,将收集所有错误并返回。
- 请参阅 `addNote` 的文档以了解 `notes` 数组中的对象的解释。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action":"addNotes",
"version":6,
"params":{
"notes":[
{
"deckName":"College::PluginDev",
"modelName":"non_existent_model",
"fields":{
"Front":"front",
"Back":"bak"
}
},
{
"deckName":"College::PluginDev",
"modelName":"Basic",
"fields":{
"Front":"front",
"Back":"bak"
}
}
]
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result":null,
"error":"['model was not found: non_existent_model']"
}
```
</details>
#### `canAddNotes`
- 接收一个定义候选笔记参数的对象数组(参见 `addNote`),并返回一个布尔数组,指示相应索引处的参数是否可以用于创建新笔记。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "canAddNotes",
"version": 6,
"params": {
"notes": [
{
"deckName": "Default",
"modelName": "Basic",
"fields": {
"Front": "front content",
"Back": "back content"
},
"tags": [
"yomichan"
]
}
]
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [true],
"error": null
}
```
</details>
#### `canAddNotesWithErrorDetail`
- 接收一个定义候选笔记参数的对象数组(参见 `addNote`),并返回一个包含 `canAdd` 和 `error` 字段的对象数组。
- `canAdd` 表示相应索引处的参数是否可以用于创建新笔记。
- `error` 包含无法添加笔记的原因说明。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "canAddNotesWithErrorDetail",
"version": 6,
"params": {
"notes": [
{
"deckName": "Default",
"modelName": "Basic",
"fields": {
"Front": "front content",
"Back": "back content"
},
"tags": [
"yomichan"
]
},
{
"deckName": "Default",
"modelName": "Basic",
"fields": {
"Front": "front content 2",
"Back": "back content 2"
},
"tags": [
"yomichan"
]
}
]
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"canAdd": false,
"error": "cannot create note because it is a duplicate"
},
{
"canAdd": true
}
],
"error": null
}
```
</details>
#### `updateNoteFields`
- 修改现有笔记的字段。您还可以包括音频、视频或图片文件,这些文件将使用可选的 `audio`、`video` 或 `picture` 属性添加到笔记中。请参阅 `addNote` 的文档以了解 `audio`、`video` 或 `picture` 数组中的对象的解释。
> **警告**
> 您不能在 Anki 浏览器中查看正在更新的笔记,否则字段不会更新。详情请参见 [此问题](https://github.com/FooSoft/anki-connect/issues/82)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "updateNoteFields",
"version": 6,
"params": {
"note": {
"id": 1514547547030,
"fields": {
"Front": "new front content",
"Back": "new back content"
},
"audio": [{
"url": "https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?kanji=猫&kana=ねこ",
"filename": "yomichan_ねこ_猫.mp3",
"skipHash": "7e2c2f954ef6051373ba916f000168dc",
"fields": [
"Front"
]
}]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `updateNote`
- 修改现有笔记的字段和/或标签。
换句话说,结合了 `updateNoteFields` 和 `updateNoteTags`。
请参阅它们的文档以了解所有属性的解释。
可以省略 `fields` 或 `tags` 属性而不影响另一个。
因此,对 `updateNoteFields` 的有效请求也适用于 `updateNote`。
如果既不提供 `fields` 也不提供 `tags`,该方法将失败。
首先更新字段,如果更新标签失败,字段不会回滚。
如果更新字段失败,则不会更新标签。
> **警告**
> 您不能在 Anki 浏览器中查看正在更新的笔记,否则字段不会更新。详情请参见 [此问题](https://github.com/FooSoft/anki-connect/issues/82)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "updateNote",
"version": 6,
"params": {
"note": {
"id": 1514547547030,
"fields": {
"Front": "new front content",
"Back": "new back content"
},
"tags": ["new", "tags"]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `updateNoteModel`
- 更新现有笔记的模型、字段和标签。
这允许您更改笔记的模型,使用新内容更新其字段,并设置新的标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "updateNoteModel",
"version": 6,
"params": {
"note": {
"id": 1514547547030,
"modelName": "NewModel",
"fields": {
"NewField1": "new field 1",
"NewField2": "new field 2",
"NewField3": "new field 3"
},
"tags": ["new", "updated", "tags"]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `updateNoteTags`
- 通过笔记 ID 设置笔记的标签。旧标签将被移除。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "updateNoteTags",
"version": 6,
"params": {
"note": 1483959289817,
"tags": ["european-languages"]
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `getNoteTags`
- 通过笔记 ID 获取笔记的标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getNoteTags",
"version": 6,
"params": {
"note": 1483959289817
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["european-languages"],
"error": null
}
```
</details>
#### `addTags`
- 通过笔记 ID 向笔记添加标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "addTags",
"version": 6,
"params": {
"notes": [1483959289817, 1483959291695],
"tags": "european-languages"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `removeTags`
- 通过笔记 ID 从笔记中移除标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "removeTags",
"version": 6,
"params": {
"notes": [1483959289817, 1483959291695],
"tags": "european-languages"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `getTags`
- 获取当前用户的完整标签列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getTags",
"version": 6
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": ["european-languages", "idioms"],
"error": null
}
```
</details>
#### `clearUnusedTags`
- 清除当前用户笔记中所有未使用的标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "clearUnusedTags",
"version": 6
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `replaceTags`
- 替换笔记中的标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "replaceTags",
"version": 6,
"params": {
"notes": [1483959289817, 1483959291695],
"tag_to_replace": "european-languages",
"replace_with_tag": "french-languages"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `replaceTagsInAllNotes`
- 替换当前用户所有笔记中的标签。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "replaceTagsInAllNotes",
"version": 6,
"params": {
"tag_to_replace": "european-languages",
"replace_with_tag": "french-languages"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `findNotes`
- 返回给定查询的笔记 ID 数组。查询语法记录在 [此处](https://docs.ankiweb.net/searching.html)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "findNotes",
"version": 6,
"params": {
"query": "deck:current"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [1483959289817, 1483959291695],
"error": null
}
```
</details>
#### `notesInfo`
- 返回一个对象列表,包含每个笔记 ID 的笔记字段、标签、笔记类型、修改时间、属于该笔记的卡片以及创建该笔记的配置文件。
<details>
<summary><i>示例请求笔记ID</i></summary>
```json
{
"action": "notesInfo",
"version": 6,
"params": {
"notes": [1502298033753]
}
```
</details>
<details>
<summary><i>示例请求(查询):</i></summary>
```json
{
"action": "notesInfo",
"version": 6,
"params": {
"query": "deck:current"
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"noteId":1502298033753,
"profile": "User_1",
"modelName": "Basic",
"tags":["tag","another_tag"],
"fields": {
"Front": {"value": "front content", "order": 0},
"Back": {"value": "back content", "order": 1}
},
"mod": 1718377864,
"cards": [1498938915662]
}
],
"error": null
}
```
</details>
#### `notesModTime`
- 返回一个对象列表,每个对象包含对应笔记 ID 的修改时间。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "notesModTime",
"version": 6,
"params": {
"notes": [1502298033753]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
{
"noteId": 1498938915662,
"mod": 1629454092
}
],
"error": null
}
```
</details>
#### `deleteNotes`
- 删除指定 ID 的笔记。如果某个笔记关联了多张卡片,则所有关联的卡片也会被删除。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "deleteNotes",
"version": 6,
"params": {
"notes": [1502298033753]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
#### `removeEmptyNotes`
- 移除当前用户所有空的笔记。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "removeEmptyNotes",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>
---
### 统计操作
#### `getNumCardsReviewedToday`
- 获取当天已复习卡片的数量(以 Anki 用户配置的起始时间为准)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getNumCardsReviewedToday",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 0,
"error": null
}
```
</details>
#### `getNumCardsReviewedByDay`
- 获取每天复习卡片的数量,返回一个包含 `(日期字符串, 数量)` 对的列表。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getNumCardsReviewedByDay",
"version": 6
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
["2021-02-28", 124],
["2021-02-27", 261]
],
"error": null
}
```
</details>
#### `getCollectionStatsHTML`
- 获取整套卡组的统计报告HTML 格式)。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getCollectionStatsHTML",
"version": 6,
"params": {
"wholeCollection": true
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": "<center> lots of HTML here </center>",
"error": null
}
```
</details>
#### `cardReviews`
- 请求指定牌组在某一时间之后的所有卡片复习记录。
`startID` 是不会包含在结果中的最新 unix 时间。
返回值为一个包含 9 个元素的元组列表,格式为 `(复习时间, 卡片ID, usn, 按下的按钮, 新间隔, 上次间隔, 新因子, 复习时长, 复习类型)`
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "cardReviews",
"version": 6,
"params": {
"deck": "default",
"startID": 1594194095740
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": [
[1594194095746, 1485369733217, -1, 3, 4, -60, 2500, 6157, 0],
[1594201393292, 1485369902086, -1, 1, -60, -60, 0, 4846, 0]
],
"error": null
}
```
</details>
#### `getReviewsOfCards`
- 请求每个卡片 ID 的所有复习记录。
返回一个字典,将每个卡片 ID 映射到一个由下述格式字典组成的列表:
```
{
"id": reviewTime,
"usn": usn,
"ease": buttonPressed,
"ivl": newInterval,
"lastIvl": previousInterval,
"factor": newFactor,
"time": reviewDuration,
"type": reviewType,
}
```
之所以使用这些键名而不是更具描述性的名称,是因为这些是 Anki 数据库中使用的实际键名。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getReviewsOfCards",
"version": 6,
"params": {
"cards": ["1653613948202"]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": {
"1653613948202": [
{
"id": 1653772912146,
"usn": 1750,
"ease": 1,
"ivl": -20,
"lastIvl": -20,
"factor": 0,
"time": 38192,
"type": 0
},
{
"id": 1653772965429,
"usn": 1750,
"ease": 3,
"ivl": -45,
"lastIvl": -20,
"factor": 0,
"time": 15337,
"type": 0
}
]
},
"error": null
}
```
</details>
#### `getLatestReviewID`
- 返回指定牌组最近一次复习的 unix 时间。如果该牌组从未被复习过,则返回 0。
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "getLatestReviewID",
"version": 6,
"params": {
"deck": "default"
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": 1594194095746,
"error": null
}
```
</details>
#### `insertReviews`
- 将给定的复习记录插入数据库。所需格式为 9 元素元组列表:`(复习时间, 卡片ID, usn, 按下的按钮, 新间隔, 上次间隔, 新因子, 复习时长, 复习类型)`
<details>
<summary><i>示例请求:</i></summary>
```json
{
"action": "insertReviews",
"version": 6,
"params": {
"reviews": [
[1594194095746, 1485369733217, -1, 3, 4, -60, 2500, 6157, 0],
[1594201393292, 1485369902086, -1, 1, -60, -60, 0, 4846, 0]
]
}
}
```
</details>
<details>
<summary><i>示例结果:</i></summary>
```json
{
"result": null,
"error": null
}
```
</details>