Compare commits
13 Commits
eef3be8599
...
1f7fc80b7e
Author | SHA1 | Date | |
---|---|---|---|
|
1f7fc80b7e | ||
|
820300cc5c | ||
|
4847fff790 | ||
|
82210ddf87 | ||
|
b896b66736 | ||
|
5a153691fd | ||
|
14a8a84150 | ||
|
9f7dccaca0 | ||
|
9e214e90e5 | ||
|
6693ab6b97 | ||
|
423d3e2aa2 | ||
|
cd66410ff3 | ||
|
e999a44a47 |
37
README.md
37
README.md
@ -156,6 +156,13 @@ const result = await invoke('deckNames', 6);
|
|||||||
console.log(`got list of decks: ${result}`);
|
console.log(`got list of decks: ${result}`);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
Anki-Connect supports requiring authentication in order to make API requests.
|
||||||
|
This support is *disabled* by default, but can be enabled by setting the `apiKey` field of Anki-Config's settings (Tools->Add-ons->AnkiConnect->Config) to a desired string.
|
||||||
|
If you have done so, you should see the [`requestPermission`](#requestpermission) API request return `true` for `requireApiKey`.
|
||||||
|
You then must include an additional parameter called `key` in any further API request bodies, whose value must match the configured API key.
|
||||||
|
|
||||||
### Hey, could you add a new action to support $FEATURE?
|
### Hey, could you add a new action to support $FEATURE?
|
||||||
|
|
||||||
The primary goal for Anki-Connect was to support real-time flash card creation from the
|
The primary goal for Anki-Connect was to support real-time flash card creation from the
|
||||||
@ -177,6 +184,7 @@ be serviced*. Make sure that your pull request meets the following criteria:
|
|||||||
Documentation for currently supported actions is split up by category and is referenced below. Note that deprecated APIs
|
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
|
will continue to function despite not being listed on this page as long as your request is labeled with a version number
|
||||||
corresponding to when the API was available for use.
|
corresponding to when the API was available for use.
|
||||||
|
Search parameters are passed to Anki, check the docs for more information: https://docs.ankiweb.net/searching.html
|
||||||
|
|
||||||
* [Card Actions](#card-actions)
|
* [Card Actions](#card-actions)
|
||||||
* [Deck Actions](#deck-actions)
|
* [Deck Actions](#deck-actions)
|
||||||
@ -1617,6 +1625,35 @@ corresponding to when the API was available for use.
|
|||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
#### `guiImportFile`
|
||||||
|
|
||||||
|
* Invokes the *Import... (Ctrl+Shift+I)* dialog with an optional file path. Brings up the dialog for user to review the import. Supports all file types that Anki supports. Brings open file dialog if no path is provided. Forward slashes must be used in the path on Windows. Only supported for Anki 2.1.52+.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><i>Sample request:</i></summary>
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"action": "guiImportFile",
|
||||||
|
"version": 6,
|
||||||
|
"params": {
|
||||||
|
"path": "C:/Users/Desktop/cards.txt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><i>Sample result:</i></summary>
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"result": null,
|
||||||
|
"error": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
#### `guiExitAnki`
|
#### `guiExitAnki`
|
||||||
|
|
||||||
* Schedules a request to gracefully close Anki. This operation is asynchronous, so it will return immediately and
|
* Schedules a request to gracefully close Anki. This operation is asynchronous, so it will return immediately and
|
||||||
|
@ -1852,6 +1852,48 @@ class AnkiConnect:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@util.api()
|
||||||
|
def guiImportFile(self, path=None):
|
||||||
|
"""
|
||||||
|
Open Import File (Ctrl+Shift+I) dialog with provided file path.
|
||||||
|
If no path is given, the user will be prompted to select a file.
|
||||||
|
Only supported from Anki version >=2.1.52
|
||||||
|
|
||||||
|
path: string
|
||||||
|
import file path, note on Windows you must use forward slashes.
|
||||||
|
"""
|
||||||
|
if anki_version >= (2, 1, 52):
|
||||||
|
from aqt.import_export.importing import import_file, prompt_for_file_then_import
|
||||||
|
else:
|
||||||
|
raise Exception('guiImportFile is only supported from Anki version >=2.1.52')
|
||||||
|
|
||||||
|
if hasattr(Qt, 'WindowStaysOnTopHint'):
|
||||||
|
# Qt5
|
||||||
|
WindowOnTopFlag = Qt.WindowStaysOnTopHint
|
||||||
|
elif hasattr(Qt, 'WindowType') and hasattr(Qt.WindowType, 'WindowStaysOnTopHint'):
|
||||||
|
# Qt6
|
||||||
|
WindowOnTopFlag = Qt.WindowType.WindowStaysOnTopHint
|
||||||
|
else:
|
||||||
|
# Unsupported, don't try to bring window to top
|
||||||
|
WindowOnTopFlag = None
|
||||||
|
|
||||||
|
# Bring window to top for user to review import settings.
|
||||||
|
if WindowOnTopFlag is not None:
|
||||||
|
try:
|
||||||
|
# [Step 1/2] set always on top flag, show window (it stays on top for now)
|
||||||
|
self.window().setWindowFlags(self.window().windowFlags() | WindowOnTopFlag)
|
||||||
|
self.window().show()
|
||||||
|
finally:
|
||||||
|
# [Step 2/2] clear always on top flag, show window (it doesn't stay on top anymore)
|
||||||
|
self.window().setWindowFlags(self.window().windowFlags() & ~WindowOnTopFlag)
|
||||||
|
self.window().show()
|
||||||
|
|
||||||
|
if path is None:
|
||||||
|
prompt_for_file_then_import(self.window())
|
||||||
|
else:
|
||||||
|
import_file(self.window(), path)
|
||||||
|
|
||||||
|
|
||||||
@util.api()
|
@util.api()
|
||||||
def guiExitAnki(self):
|
def guiExitAnki(self):
|
||||||
timer = QTimer()
|
timer = QTimer()
|
||||||
|
@ -248,7 +248,7 @@ class WebServer:
|
|||||||
def buildHeaders(self, corsOrigin, body):
|
def buildHeaders(self, corsOrigin, body):
|
||||||
return [
|
return [
|
||||||
['HTTP/1.1 200 OK', None],
|
['HTTP/1.1 200 OK', None],
|
||||||
['Content-Type', 'text/json'],
|
['Content-Type', 'application/json'],
|
||||||
['Access-Control-Allow-Origin', corsOrigin],
|
['Access-Control-Allow-Origin', corsOrigin],
|
||||||
['Access-Control-Allow-Headers', '*'],
|
['Access-Control-Allow-Headers', '*'],
|
||||||
['Content-Length', str(len(body))]
|
['Content-Length', str(len(body))]
|
||||||
@ -298,4 +298,4 @@ request_schema = {
|
|||||||
"params": {"type": "object"},
|
"params": {"type": "object"},
|
||||||
},
|
},
|
||||||
"required": ["action"],
|
"required": ["action"],
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from conftest import ac, wait_until, \
|
from conftest import ac, anki_version, wait_until, \
|
||||||
close_all_dialogs_and_wait_for_them_to_run_closing_callbacks, \
|
close_all_dialogs_and_wait_for_them_to_run_closing_callbacks, \
|
||||||
get_dialog_instance
|
get_dialog_instance
|
||||||
|
|
||||||
@ -28,6 +29,13 @@ def test_guiDeckOverview(setup):
|
|||||||
assert ac.guiDeckOverview(name="test_deck") is True
|
assert ac.guiDeckOverview(name="test_deck") is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_guiImportFile(setup):
|
||||||
|
if anki_version >= (2, 1, 52):
|
||||||
|
with mock.patch('aqt.import_export.importing.prompt_for_file_then_import') as mock_prompt_for_file_then_import:
|
||||||
|
mock_prompt_for_file_then_import.return_value = True
|
||||||
|
ac.guiImportFile()
|
||||||
|
|
||||||
|
|
||||||
class TestAddCards:
|
class TestAddCards:
|
||||||
note = {
|
note = {
|
||||||
"deckName": "test_deck",
|
"deckName": "test_deck",
|
||||||
|
Loading…
Reference in New Issue
Block a user