Metadata-Version: 2.4
Name: markdown-to-anki
Version: 0.2.2
Summary: Convert Markdown files into Anki cards via AnkiConnect
Project-URL: Homepage, https://github.com/rayyh/markdown-to-anki
Project-URL: Repository, https://github.com/rayyh/markdown-to-anki
Project-URL: Issues, https://github.com/rayyh/markdown-to-anki/issues
Project-URL: Changelog, https://github.com/rayyh/markdown-to-anki/releases
License: MIT
License-File: LICENSE
Keywords: anki,ankiconnect,flashcards,markdown,spaced-repetition
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Education
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Education
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4
Requires-Dist: click
Requires-Dist: markdown
Requires-Dist: pymdown-extensions
Requires-Dist: python-dotenv
Requires-Dist: python-markdown-math
Requires-Dist: pyyaml
Description-Content-Type: text/markdown

# Markdown to Anki

[![PyPI version](https://img.shields.io/pypi/v/markdown-to-anki)](https://pypi.org/project/markdown-to-anki/)
[![Python versions](https://img.shields.io/pypi/pyversions/markdown-to-anki)](https://pypi.org/project/markdown-to-anki/)
[![Release](https://github.com/rayyh/markdown-to-anki/actions/workflows/release.yml/badge.svg)](https://github.com/rayyh/markdown-to-anki/actions/workflows/release.yml)

> [!CAUTION]
> This software is provided "as is", without warranty of any kind. The author is not responsible for any consequences of its use, including but not limited to data loss, corrupted Anki collections, or unintended modifications to your notes. **Back up your Anki collection before syncing. Use at your own risk.**

**markdown-to-anki** is a lightweight Python CLI that automatically converts **raw Markdown files into Anki cards** using [AnkiConnect](https://foosoft.net/projects/anki-connect/). It's designed for learners and note-takers who prefer writing in Markdown and want to seamlessly sync their content into Anki.

## Installation

```shell
pip install markdown-to-anki
```

Requires Python 3.10+ and [AnkiConnect](https://foosoft.net/projects/anki-connect/) running in your Anki app.

## Getting Started

Open Anki, then register note models once:

```shell
m2a --folder ~/notes/anki init
```

Then sync your notes anytime:

```shell
m2a --folder ~/notes/anki sync
```

## Commands

| Command        | Description                                                    |
| -------------- | -------------------------------------------------------------- |
| `m2a check`    | Verify the AnkiConnect server is reachable.                    |
| `m2a init`     | Register note models in Anki. Run once before your first sync. |
| `m2a sync`     | Import media and notes, then trigger an AnkiWeb sync.          |
| `m2a sync_web` | Trigger an AnkiWeb sync only (no re-import). Useful for cron.  |

Only files modified within the last `TIME_RANGE` seconds (default 2 hours) are processed.

> **Force a full sync** — to re-sync all notes regardless of modification time, touch every Markdown file first:
>
> ```shell
> find ~/notes/anki -name "*.md" -exec touch {} +
> m2a --folder ~/notes/anki sync
> ```

## Configuration

Settings are resolved in this order — highest priority wins:

```
CLI flag  >  environment variable / .env  >  config file  >  default
```

### CLI flags

```shell
m2a --folder ~/notes/anki --url http://localhost:8765 sync
m2a --resources ~/my-templates init
```

| Flag          | Description                                    | Default                 |
| ------------- | ---------------------------------------------- | ----------------------- |
| `--folder`    | Path to your Markdown notes dir                | see Config file         |
| `--url`       | AnkiConnect URL                                | `http://localhost:8765` |
| `--resources` | Path to custom card templates/styles directory | built-in resources      |

### Config file

Create `~/.config/markdown-to-anki/config.yaml` (respects `$XDG_CONFIG_HOME`):

```yaml
md_folder: ~/notes/anki
time_range: 7200
anki_url: http://localhost:8765
resources_dir: ~/notes/anki-templates
```

### Environment variables / `.env`

Place a `.env` file in the directory where you run `m2a`, or set the variables in your shell:

```dotenv
MD_FOLDER=~/notes/anki
TIME_RANGE=7200
ANKI_URL=http://localhost:8765
M2A_RESOURCES_DIR=~/notes/anki-templates
```

## Markdown Style

Each Markdown file may contain one or more cards. Use YAML frontmatter for per-file metadata and the comment separators below to split cards and fields:

```markdown
---
deck: M2A::Example::Math
tags: math, theorem
model: m2a-basic
# skip: 1   # uncomment to skip this file
---

<!--CARD-->

### Front of card 1

<!--FIELD-->

Back of card 1

<!--CARD-->
<!--TAGS: hard, exam-->

### Front of card 2

<!--FIELD-->

Back of card 2
```

Supported metadata keys: `deck`, `tags`, `model`, `skip`.

Per-card tags via `<!--TAGS: a, b-->` (anywhere inside a card section) are merged with the file-level `tags` from frontmatter.

### Built-in note types

| Model               | Fields               | Description                        |
| ------------------- | -------------------- | ---------------------------------- |
| `m2a-basic`         | Front, Back          | Simple front → back card           |
| `m2a-basic-reverse` | Front, Back          | Front → back and back → front      |
| `m2a-cloze`         | Text, Extra          | Cloze deletion card                |
| `m2a-english`       | Word, Audio, Meaning | Vocabulary card with audio support |

### Cloze cards

Use Anki's native `{{c1::...}}` syntax in the `Text` field. Multiple deletions (`c1`, `c2`, …) are supported in a single card.

```markdown
---
deck: M2A::Example::Cloze
model: m2a-cloze
---

<!--CARD-->

The capital of {{c1::France}} is {{c2::Paris}}.

<!--FIELD-->

European geography.

<!--CARD-->

{{c1::Water}} boils at {{c2::100}}°C at standard pressure.

<!--FIELD-->

Basic chemistry fact.
```

The `Text` field holds the cloze content; `Extra` is shown on the back and can hold supplementary notes.

## Custom Resources

Point `--resources` (or `resources_dir` / `M2A_RESOURCES_DIR`) at your own directory to override built-in templates/styles and define new note types. Only the files you provide are overridden — everything else falls back to the built-in defaults.

### Override built-in templates or styles

Mirror the built-in layout under your resources directory:

```
my-resources/
└── anki/
    ├── styles/
    │   └── basic.css          # overrides the built-in basic.css
    └── templates/
        └── basic/
            └── front.html     # overrides the built-in front template
```

### Define custom note types

Place a YAML file per model inside a `models/` subdirectory:

```
my-resources/
├── models/
│   └── my-vocab.yaml
├── styles/
│   └── my-vocab.css
└── templates/
    └── my-vocab/
        ├── front.html
        └── back.html
```

**`models/my-vocab.yaml`**:

```yaml
name: my-vocab
fields:
  - Word
  - Definition
  - Example
is_cloze: false
css_file: styles/my-vocab.css # relative to my-resources/
templates:
  - name: word-to-definition
    front_file: templates/my-vocab/front.html
    back_file: templates/my-vocab/back.html
```

Inline CSS and HTML are also supported instead of file references:

```yaml
name: my-simple
fields:
  - Question
  - Hint
  - Answer
css: ".card { font-family: sans-serif; }"
templates:
  - name: card
    front: "<div>{{Question}}</div><div class='hint'>{{Hint}}</div>"
    back: "<div>{{Answer}}</div>"
```

Fields map to `<!--FIELD-->` sections in order. A card with three fields uses two separators:

```markdown
---
model: my-vocab
deck: Languages::English
---

<!--CARD-->

hello

<!--FIELD-->

A common English greeting.

<!--FIELD-->

"Hello, how are you?" — used when meeting someone.
```

Run `m2a --resources my-resources/ init` once to register your custom models in Anki, then use `m2a --resources my-resources/ sync` as usual.

## Cronjob

Automatically sync your notes to AnkiWeb hourly:

```shell
crontab -e

# sync hourly (replace /usr/local/bin/m2a with the output of: which m2a)
5 * * * *  /usr/local/bin/m2a --folder ~/notes/anki sync_web &>/dev/null
```

## Examples

See the [example notes](https://github.com/rayyh/markdown-to-anki/tree/main/tests/fixtures) for working Markdown files covering basic cards, cloze deletions, math, code, and audio.

## License

This project is open-sourced and licensed under the [MIT license](https://github.com/rayyh/markdown-to-anki/blob/main/LICENSE).
