Home

Awesome

Markdown2Anki

Markdown2Anki is a Python script that allows you to easily format your cards using Markdown syntax, and then import them into Anki while retaining the structure you gave them.
This tool supports code highlighting, clozes, and images, making it a versatile and convenient option for anyone looking to streamline their flashcard creation process. Additionally, it offers support for Obsidian notes, allowing you to create links inside your cards that point to your vault's notes! 🌸


Demo image

Unleash the power of spaced repetition: Convert your Markdown notes into Anki flashcards for optimal learning.
ChatGPT, when asked for a captivating description of this project.


Table of contents (for GitHub)


This is an open-source free software, you can find it on:
Github - https://github.com/Mochitto/Markdown2Anki
PyPi - https://pypi.org/project/markdown2anki


Features

Technical features

Images

CLI

Demo image of the CLI
Video demo of the CLI

Split-screen

Demo image

Code highlighting

Demo code highlighting

Clozes support

Demo image Demo image

Supports the addon "fill the blanks"

Demo image

Mobile (with light mode)

Mobile versionClozes in mobile
Demo image of mobileDemo image of mobile

Installation

This project is distributed using pip via Pypi. This means you need Python installed on your machine, you can get it here: https://www.python.org/downloads/
IMPORTANT!: When installing, make sure to check the Add python to PATH if on Windows/Mac.

Once you have installed Python, you can write in the command line:

python -m pip install Markdown2Anki

And then you should be able to run:

md2anki

There is a guided setup on your first time running the app, which will help you get up and running :)

Notice: This app uses emoji to give instant feedback to the user, depending on your terminal you might not be able to see them correctly.
On windows you can use the Windows terminal. On iOS and Linux they should be supported by default.

You can also get all of the possible arguments for the script with:

md2anki -h

The script will also let you know when there is a new update and point you to the CHANGELOG.md file, where you can read what has changed and decide if to update or not.
Update demo You can update the package with:

python -m pip install --upgrade Markdown2Anki

After doing this, the app will ask you again the location of your program folder and update (or heal) your configuration if it is present; if not, it will create a new one.

Initial setup

During the initial setup process, you will be prompted to select a folder where the program will put its files.
Once you will have confirmed the path to said folder, a configuration file named md2anki.config.ini will be added to it.
The configuration file holds all the information on each option, what it does and if it's required or not.

Suggested: Among the options, you might want to set as images out-folder your Anki media folder; this option sets the folder where images are copied to when they are found in your notes; by setting it to your anki's media folder, images are automatically added to you Anki's database.
You can learn more about Anki's folders here: https://docs.ankiweb.net/files.html#file-locations

There will also be a markdown2anki.apkg file which contains the anki note types you will need when importing the cards.
If you have Anki installed on your system, you should be able to just double-click the file to import it, and it will create a new deck with some template cards and the note types.
You can learn more on .apkg files here: https://docs.ankiweb.net/exporting.html#deck-apkg

Using fill the blanks

If you would like to have "type-in" clozes, you can use this addon: fill the blanks addon.
For it to work, you will need to duplicate the Markdown2Anki - Cloze Note type and modify it by changing the Front side field to: {{type:cloze:Front}}.

This is a video with how you can achieve this: Video Tutorial on how to modify a note type

Demo of fill the blanks

Usage

Markdown input formatting

To ensure that your notes are properly recognized by the program, there are a few formatting requirements:

Cards separator

Cards must be separated by a horizontal rule using three dashes or more ---.
Notice: *** do not work as cards separators, this is so that you can use * to define horizontal rules inside of your cards :)

Tabs

A unique feature of this program is the ability to create tabs within your cards.
Tabs are divided depending on the card side (front, back) and the tabs side (left window, right window).

Front side tabs, unless removed with the - flag (more on this later), are retained when moving to the back side (aka. "flipping the card").
Back side tabs are added after the front tabs, unless they replace one that has been removed.

Tab Labels and flags

Tab labels define the beginning of a tab and its content, and should be formatted as follows:

## <flags> [<tab label>]

Flags define where your tab goes (left or right side of the card, front or back side of the card).

The possible flags are:

FlagsMeaning
FFront side of the card
BBack side of the card
LLeft tabs side
RRight tabs side
-Only applied to Front tabs: removes the tab when switching to the back side
+Only applied to Back tabs: replaces a removed front tab
## BR [This is my tab]
And this is its body

Notice: Tab labels do not support Markdown formatting, such as bold text etc.

Default values:
Front and Left flags are applied automatically, so you can leave them out.

## [My tab]
is the same as
## FL [My tab]

## B [My tab]
is the same as 
## BL [My tab]

## R [My tab]
is the same as
## FR [My tab]

Example

Here are two example cards to illustrate the formatting requirements:

## - [Question]
# A great addition to humanity
What is the **name** of this funny cat?
## Make sure you get it right.

## R [Funny cat]
![[bingus.png]]

## +B [Answer]
This is the magnificent Bingus.

---

## [Complete the code]
This is the code needed to reverse sort a list.
```python
my_list = [3,5,2]
# New list
sorted_list = {{C1::sorted}}(my_list, {{C1::True}})
# In place
my_list.{{C1::sort}}(True)
    ```

The result: Usage demo image 2 Usage demo image 3 (This is using the fill the blanks addon) Usage demo image 1

Importing your cards

Once you have processed your cards, they will be divided in cards with clozes and cards without clozes.
Those will become two .csv files: basic_anki_cards.csv and clozed_anki_cards.csv.
To import these, you have to open up Anki and press the "Import File" in the lower side of the main menu, or, if you prefer, you can use "File>Import" from the menu in the top-left of the Anki app.
After selecting the .csv file, you have to let anki know that the separator used is Comma, select the right note type and the deck you wish the cards to be imported in. Also make sure to allow HTML in the cards, as they need it to work correctly.

This is a screenshot of how this could look in your Anki (Anki's UI can change depending on the OS it is running on):
Image of Anki's import screen

You can find more information on importing to Anki here: https://docs.ankiweb.net/importing.html

Importing your images

You can import images automatically if you add the path to your Anki media folder in the config file.
Images that are already present won't be added twice and will be skipped (based on filename).
If you prefer checking the images before importing them manually, you can point to another folder or leave the default one.
Notice: when images are copied, they lose their metadata: this is due to security, as others' could read your images metadata if you were to share your cards, and for how the python library that handles the copying process is implemented.

Hopefully, in the near future, the importing part will be made automatic by the addition of AnkiConnect support.

Errors and Bad cards

When there are errors in formatting, the app will let you know what went wrong and create a Bad_cards.md file in your program folder.
This will be a file of all of the "Bad cards" (cards that had a problem in them). The specific error for each card is added before the tabs, so that you can easily fix them.

These, as other text added at the beginning of a card, before all the tabs labels, are considered comments, so you can leave them in.
For example:

❌ ERROR ❌ - A card without front tabs has been found.
## B [My card]
That is very cool ⭐

---

❌ ERROR ❌ - A tab without body has been found.
## [Fast inverse square root]

Some common card errors are:

Some common general errors are:

Once you have fixed your bad cards, you can run the program with

md2anki -bf

This will automatically use the Bad_cards.md as input, if you prefer fixing the cards in that file instead of adding them to the main input file.

A debug_log.txt file is also present in your program folder, which is created every time you run the program. This file contains more information on what happens when the program is running, the result of various processes, your configuration and so on.
If you find a bug in the program, it would be of great help if you could add this file to your issues on GitHub.

Privacy Notice: the log file has your configuration in it, as it can contain crucial information for debugging.
If you don't want to share your paths or other information from it when making issues, you should search-and-replace that information with some fake one, while trying not to change their general structure.

Using clozes

You can specify clozes in your markdown and they will be carried over to your anki cards. Whenever there is a word or sentence you'd like to have as a cloze, you can use Anki's formatting {{c<number>::<word>::<hint?>}} (notice the two colons, not just one). Clozes will also work in code blocks.

The number tells Anki what cloze to add to what card. This means that if you have C1, C2 and C3, there will be three cards created (this is a feature of Anki, not of Markdown2Anki), each missing the respective words.
More on this here: https://docs.ankiweb.net/editing.html#cloze-deletion

For example:

my_list = [3,5,2]
# New list
sorted_list = {{C1::sorted}}(my_list, {{C1::True}}) 
# In place
my_list.{{C1::sort}}(True)

Changing Themes

The default theme is mochitto's Rosé Pine theme, but there is also a catpuccin theme.
You can find all the themes in the themes folder.
To use another theme, you can just copy the CSS from the file in the themes folder and paste it in your Note types' styling field.

This can be found by accessing Tools>Manage Note Types>(select your note type)>Cards(on the right)>Styling(on the left). The Tools menu is found in the top-left part of Anki's main menu.
You can reference this: Video Tutorial showing how to access a card's style

You can read more on how styling happens here: https://docs.ankiweb.net/templates/styling.html

Navigating the UI

The custom User Interface of the note-type that comes with this project is focused on the concept of tabs.
You can have side-by-side tabs and multiple tabs to toggle through.

Demo image

To navigate them, you can either click on the labels of non-active tabs to make them active (switch to them), and click an active tab to make it full-screen.
This works also in mobile.

There are also keyboard commands: you can select a tab with <alt>+<number of the tab> or ⌥ + <number of the tab> (the number is displayed next to the tab label) to switch to that tab or make it full-screen, or you can TAB between to navigate between them.

For example, Alt+1 will show the first tab if it's not-active, or make it full-screen if it's active.

Notice: at times the hotkeys don't seem to work completely (maybe one tab is not accessible with <alt>); I'm working on understanding better how Anki handles HTML and Javascript, as it's a problem on how it handles changing between cards... The <tab> and <click> methods seem to be stable, so you can use those if this bug happens.
I'm sorry about it...

Query error

Sometimes, you might come across a screen saying "ERROR: Couldn't find any element using the query [...]".
This happens because, for some reason, Anki is not loading correctly the card or the script. This shouldn't happen often and I'm still trying to understand better the underlying reasons behind it, as they have to do with Anki's way of handling HTML and Javascript...
It will likely be patched in the near future, until then, your best call is to go back to the main menu and try again, or restarting Anki; this often fixes the problem.
I'm sorry about it...

Creating a new theme

The theme was made with customizability in mind; you can learn more on how to make your own theme in the theme builder folder's README.
Once you've made your own theme, you can submit it as a contribution to make it "official" and share it with others.

Contributing and dev documentation

The project was built with contributions and future projects in mind, using expressive names, doc strings on functions/classes/modules and types.
You can read more on the project's inner workings in the CONTRIBUTING.md.
If you want to help with issues, you can head to this project's kanban.

If you have any questions or find something in the documentation that is not clear, let me know with an issue, I'll (mochitto) will get back to you asap!

The reasons behind the project

Anki uses formatted text and html, but makes users pick a very strict way of defining that, while using plain text. This "helps" some users by shielding them from the possible complexity of formatting the text, but a lot more could be achieved by giving them freedom with Markdown.

Markdown formatting also makes space for coding cards, which are pretty awful to make in Anki (even if, thanks to Ijgnd and Glutanimate, there was at least an ok possibility to make them work).
This means that users do not really need tens of note types, but can define the kind of note they actually need while writing them (or by using their own, flexible templates).
This also takes away some limitations, such as having to use clozes on only one field of the card.

I (mochitto) also really like the idea of Open Source/Free software communicating between different projects, so creating a "bridge" between Obsidian and Anki feels like a great way of pulling together applications that give society a huge value, making them even stronger.

Technologies used

Languages

Building

Core dependencies

Testing

Methodology

Hopes for the future

Some things that I hope will be implemented in the future, either by me (mochitto) or by the community are:

Versioning

The formatting of the changelog file is based on Keep a Changelog and this project adheres to Semantic Versioning. You can read the CHANGELOG file here.

License

This project uses the GPL3 LICENSE.
The project was made possible by lots of free software and is a bridge between free softwares; it couldn't have been made possible without Pygments, Mistune, Pytest, esbuild, sass and tons more of community efforts.

Closing note

I hope this project inspires others to create more open source software, fostering growth and collaboration within our community and society. - Mochitto, 2023