Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Anki's API to send cards to Anki #3

Open
Mochitto opened this issue Apr 21, 2023 · 2 comments
Open

Use Anki's API to send cards to Anki #3

Mochitto opened this issue Apr 21, 2023 · 2 comments
Labels
enhancement New feature or request

Comments

@Mochitto
Copy link
Owner

Using CSV/manual import is a bit annoying; it would be nice if you could use the Anki API (it would require you to add the path to the collection file to the config) to send the cards automatically to anki.
Maybe it can also send images automatically (would remove the need of manually adding the media folder).

@Mochitto Mochitto added the enhancement New feature or request label Apr 21, 2023
@Mochitto Mochitto moved this from Backlog to Todo in Markdown2Anki Sep 2, 2023
@MarkoSagadin
Copy link
Collaborator

I have looked a bit into the AnkiConnect and tried to make something. I documented the findings below.

Here are the things that learned:

The setup

Naturally, the user needs to install AnkiConnect plugin and have Anki running. AnkiConnect exposes a ton of functionality via HTTP API.

Structure of API

HTTP requests needs to contain a JSON-encoded object, with specific fields:

{
    "action": "forgetCards",
    "version": 6,
    "params": {
        "cards": [1498938915662, 1502098034048]
    }
}

Where:

  • "action" tells AnkiConnect what should be done, for example createDeck or guiAddCards
  • "params" contains contextual information related to the specific "action" and is specified in the docs
  • "version" tells which version of AnkiConnect Api should be used (I recommend that we keep this at latest, so 6).

HTTP responses look like this:

{
    "result": ["Default", "Filtered Deck 1"], 
    "error": null
}

Where:

  • "result" contains the result data relevant to the action, but only if error is null
  • "error" contains error string, if something bad happened.

What I tried to do

I played a bit with the provided Python snippet and tried a few of the API methods.

addNote

As the name says, this is the action for adding notes.

I could create a test note with the following JSON, I think that the most fields are self-explanatory. There are also possible audio and video fields with the same content as the picture key.

{
    "action": "addNote",
    "version": 6,
    "params": {
        "note": {
            "deckName": "Work Notes",
            "modelName": "Basic",
            "fields": {
                "Front": "front content",
                "Back": "back content"
            },
            "options": {
                "allowDuplicate": false,
                "duplicateScope": "deck",
                "duplicateScopeOptions": {
                    "deckName": "Work Notes",
                    "checkChildren": true,
                    "checkAllModels": true
                }
            },
			"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" 
				]
			}],
            "tags": [
                "testinput"
            ]
        }
    }
}

Some remarks:

  • You can specify where exactly should a image (or video or audio) be placed in the text, this is showed in this issue: Add Cards/Notes with Images FooSoft/anki-connect#158 (comment) We need this, so this is good.
  • There is some duplication prevention feature via "allowDuplicate": false field, however it is only using the Front field to determine if you are trying to add a duplicate. In other words if the existing note in the Anki and the note you are trying to add have the same Front field but maybe different Back field or tags or something else, then that's a duplicate.
  • Fields accept HTML in string representation, so there shouldn't be any need for extra processing of existing output.
  • When a note is successfully updated you get back it's id number.

updateNote

Same fields as above, with addition of id field. That's the way to tell Anki which note you want to update.

{
    "action": "updateNote",
    "version": 6,
    "params": {
        "note": {
            "id": 1514547547030,
            "fields": {
                "Front": "new front content",
                "Back": "new back content"
            },
            "tags": ["new", "tags"]
        }
    }
}

Some remarks:

  • You can get note ids by using findNotes API which takes Anki query parameter.

Topics to discuss and do.

  1. I want try to pass the examples that are in the project's readme (the example notes with code and the cat) via above API and see what happens. I want to see how this works with a more realistic note and if there are any drawback.
  2. If we want to support the "update note" usecase (user does not wish to delete the notes once they are imported, as he wants a way to update them via Markdown and run the md2anki again and again), then we need some way of storing and tracking the id number in the markdown. The logic could then such that you would write the id number in the markdown file, next to the note that created it, and whenever a note with id number would be encountered, then it would try to find that note via API and update it. That is not hard to implement.
  3. There is addNote and addNotes API methods. Latter one takes an array of addNote compatible objects and creates multiple notes them. The docs do not indicate that there is any other special behavior going on. If I have 100 notes, what difference does it matter if I create 100 addNote requests or 1 addNotes requests with all 100 notes in the body? Is there anything HTTP related that could affect this?

MarkoSagadin added a commit to MarkoSagadin/Markdown2Anki that referenced this issue Nov 19, 2023
This is a prototype implementation.

In the current state the md2anki will:
- Send processed cards to the Anki via 'addNote' API
- Send images to the Anki via 'storeMediaFile' API
- Display basic info when that is being done
- Display error messages if any step fails

This feature is far from done:
- deck name and note type are currently hardcoded, they should be
  provided by the caller for each card/note.
- error handling and validation are missing.
- code style will probably need to be adjusted.

There are several TODO comments that ask questions.

Related: Mochitto#3
@Mochitto Mochitto moved this from Todo to Backlog in Markdown2Anki Jan 22, 2024
Mochitto pushed a commit that referenced this issue Jan 22, 2024
This is a prototype implementation.

In the current state the md2anki will:
- Send processed cards to the Anki via 'addNote' API
- Send images to the Anki via 'storeMediaFile' API
- Display basic info when that is being done
- Display error messages if any step fails

This feature is far from done:
- deck name and note type are currently hardcoded, they should be
  provided by the caller for each card/note.
- error handling and validation are missing.
- code style will probably need to be adjusted.

There are several TODO comments that ask questions.

Related: #3
@MarkoSagadin
Copy link
Collaborator

MarkoSagadin commented Oct 17, 2024

Hello after quite some time!

I would like to get back to working on this, since I have some free time in the coming months :)

I looked again code that I wrote in the #16 and would like some input where to take this.

  • As mentioned there, deck name and model name are currently hardcoded. It probably makes sense that they are picked up from frontmatter of the markdown that is being processed right? So something like "deck_name" and "note_type" (this is model name) would become the part of the markdown "API". But they would probably need to be mandatory, otherwise you can't know to which deck are you supposed to send stuff. ... Well, I am just describing this issue: Adding metadata to markdown input files #11 😅
  • I would really like to support the previously described "update note" usecase (see my previous comment above). And it seems that you also though about this in Feat: Support for fixing cards #8.
  • What kind of integration tests would you like for this? I have experience writing tests/fixtures in pytest. I guess that if you just describe some common testing scenarios and maybe provide me some general direction, I can get going.
  • Anything else that I should think about?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Backlog
Development

No branches or pull requests

2 participants