anki-cli-unofficial 1.0.3
A CLI to load flashcards in Anki2
Requires Python: >=3.6

# Anki CLI

CLI to automate Anki notes/flashcards creation.

**This project is not part of the official Anki project.**

Note: The code was tested using Python 3.8 and Anki 2.1.35.

## Installation

```shell
$ pip3 install aqt==2.1.44 # Must be compatible with your Anki desktop installation
$ pip3 install anki-cli-unofficial
```

## Usage

The CLI supports a single command `load`.

```shell
$ anki-cli-unofficial load -h
usage: anki-cli-unofficial load [-h] [--anki-dir ANKI_DIR] [--media-dir MEDIA_DIR] [--deck DECK] input_file output_file

positional arguments:
  input_file            YAML file containing the flashcards to create
  output_file           Anki generated archive filepath

optional arguments:
  -h, --help            show this help message and exit
  --anki-dir ANKI_DIR
                        Anki directory (Default to a temp directory)
  --media-dir MEDIA_DIR
                        local directory containing medias referenced in input_file
  --deck DECK
                        deck name in which to create flashcards
```

By default, the CLI will create a sandbox Anki environment. This temporary directory will be deleted by your OS after a few days. You can specify an existing Anki directory using the option `--anki-dir` but **I strongly recommend that you don't run this program on your main Anki directory**. This code may become outdated, and I don't want bugs to damage your precious flashcards.

The command `load` expects a YAML file as input. This file must use this format:

```yaml
# File cards.yaml

# An array of documents

- type: Basic # The type of the node to create ("Basic", "Basic (with reverse card)", etc.). Also known as the model.
  tags: [tag1, tag2] # An optional list of tags
  fields: # The ordered list of fields for the selected note type (ex: Basic notes require two fields: Front & Back)
    Front: Bonjour
    Back: Hello
```

The command `load` also expects the filename of the generated Anki package (usually ends with `.apkg`). The file doesn't have to exist. The CLI will create it in your current directory.

To generate the flashcards:

```shell
$ anki-cli-unofficial load cards.yaml archive.apkg

📂 Opening Anki collection...
🔍 Loading 'cards.yaml' into the deck 'Default'...
💾 Saving Anki collection...
👍 Done
👉 Anki collection can be opened using the following command:
        open /Applications/Anki.app --args -b /var/folders/5f/9sp_9nk17jjdtw7y9t9rydr80000gn/T/tmpn8rl4l2w
👉 Anki Archive is available here: ./archive.apkg
```

After the completion, you have the option to visualize the generated flashcard by opening Anki on the sandbox directory. The command differs depending on your OS and is therefore displayed by the CLI. If everything looks fine, you can close Anki and reopen it without any option like usual to import the packaged Anki deck generated by the CLI. That's it!

## Advanced Uses

### Multilingual Support

The CLI was tested using the English locale. You may still use it with a different locale but minor adjustement are required.

Ex: (French)

```
# Create a Anki home with the French locale
$ anki -l fr -b ./ankidir

# Make sure your input file follows the locale naming conventions
$ echo cards.yml
- type: Basique  # "Basic" translation in French
  tags: [idiom]
  fields:        # Field names must be translated:
    Recto: 'Avoir la banane! <small>idiom</small>'
    Verso: 'To feel great. (literally: <em>to have the banana<em>)'

# Use the option --deck to override the default deck name
$ anki-cli-unofficial load cards.yaml \
      --deck="Par défaut" \
      --anki-dir="./ankidir/Utilisateur 1/" \
      archive.apkg

# Open Anki to check generated cards
$ anki -b ankdir
```


### Medias

Medias are supported using the usual Anki syntax:

* Include `[sound:file.mp3]` inside a field to add sounds to your flashcard.
* Include `<img src="file.jpg">` inside a field to add images to your flashcard.

Ex:

```yaml
- type: Basic
  fields:
    Front: '<img src="car.jpg" />'
    Back: '[sound:voiture.mp3] Une voiture'
# This card will show the picture of a card and print the translation
# with the pronunciation when the back card is revealed.
```

You must specify the local directory containing the media files. The CLI will copy these files in the Anki medias database (missing files are ignored).

```shell
$ anki-cli-unofficial load --media-dir ~/anki-images cards.yaml
# Where ~/anki-images contains the files car.jpg and voiture.mp3
```

### Custom Note Types

The CLI creates a fresh Anki directory to generate the flashcards (for safety reasons). Therefore, only default card types are supported. If you have custom note types, you may decide to launch the CLI directly on your Anki directory using the option `--anki-dir`. That would be a bad idea. Bugs happen. I don't want to damage your flashcards. A better alternative is to create a copy of your current directory.

Note: The Anki directory differs according your OS ([check the official documentation](https://docs.ankiweb.net/#/files?id=file-locations)):

* Windows: `%APPDATA%\Anki2`
* MacOS: `~/Library/Application Support/Anki2`
* Linux: `~/.local/share/Anki2`

The CLI expects a user directory (`~/Library/Application Support/Anki2/User 1` is valid but `~/Library/Application Support/Anki2/` is not).

**Before running the CLI, make sure to back up this directory!** (Create a zip archive using the file explorer or using the terminal.) Anki Desktop creates automatic backups by default, but they don't include medias.

Then, run the CLI on the copy of your Anki directory. Example (on MacOS):

```
$ mkdir $TMPDIR/Anki2
$ cp -R ~/Library/Application Support/Anki2/User\ 1 $TMPDIR/Anki2
$ anki-cli-unofficial load --anki-dir $TMPDIR/Anki2/User\ 1 cards.yaml archive.apkg
```

When running on an existing Anki directory, the CLI doesn't create the package file (to avoid exporting all of your flashcards). Therefore, you have to create the archive yourself:

* Open Anki on the clone directory (the command is displayed in the output).
* Use the menu _Browser_ and select the newly created cards (using a special tag, for example).
* Right-click and select _Export_.

## Examples

You will find additional examples in the directory `examples/`.


## Development

### Test locally

```shell
$ cd anki-cli/
$ python3 setup.py install # The binary anki-cli-unofficial is now present in $PATH
$ anki-cli-unofficial load --media-dir ./examples ./examples/french.yaml archive.apkg
```

### Upload to PyPI

1. Create an API Token from the Web UI. (Edit your `~/.pypirc` with the generated token.)
2. Install Twine
```shell
$ python3 -m pip install --user --upgrade twine
```
3. Upload the bundle
```shell
$ python3 -m twine upload dist/*
```

Note: The upload to PyPI is currently assured by GitHub Actions.


### Release

1. Increase the version number in `setup.py`.
2. Commit and push.
3. Create a new tag in GitHub to trigger the CI pipeline.