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

feat: add AnkiConnect plugin support #29

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ PyPi - https://pypi.org/project/markdown2anki
- **Support for clozes** including those in code blocks.
- **Support for images** with automatic importing: the program can find the images you mention in your obsidian notes and copy them to your Anki's media folder.
- **Support for Obsidian links and images**: using `[[Note.md|my Note]]` and `[[my_image.jpg]]`-like markdown.
- **Automatic upload of cards to Anki**: the program uses the [AnkiConnect plugin] to upload the cards to Anki automatically.
- **Accessible config file** that can self-heal (using [Type-Config](https://pypi.org/project/type-config/)): retaining as many custom configurations as possible even if the file is corrupted. This also ensures that if options are added with updates, your custom configuration will be retained.
- **Helpful error messages and feedback**.
- **Backup files of your inputs**, to help you retry in case something goes wrong.
Expand All @@ -65,6 +66,8 @@ PyPi - https://pypi.org/project/markdown2anki
- **Mobile first responsive CSS**: to ensure it's fully responsive on all devices.
- **High-level dev documentation** to make it easier for contributions and maintenance.

[AnkiConnect plugin]: https://foosoft.net/projects/anki-connect/

## Images

### CLI
Expand Down Expand Up @@ -130,6 +133,13 @@ There will also be a `markdown2anki.apkg` file which contains the anki note type
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

### Installing the AnkiConnect plugin

If you want the `md2anki` to automatically uploaded the generated cards to Anki, you will need to install the [AnkiConnect plugin](https://ankiweb.net/shared/info/2055492159).
As when installing any other Anki plugin, navigate to the `Tools>Add-ons` menu, click on the `Get Add-ons` button, and paste the code `2055492159` in the `Code` field and click `OK`.

If you don't want to install the AnkiConnect plugin, you can use the [legacy CSV file] output, which you can then import manually.

### Using fill the blanks

If you would like to have "type-in" clozes, you can use this addon: [fill the blanks addon](https://ankiweb.net/shared/info/1933645497).
Expand Down Expand Up @@ -259,25 +269,15 @@ Optional fields:

[Frontmatter]: https://dev.to/dailydevtips1/what-exactly-is-frontmatter-123g

### 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.
### Importing your card via the AnkiConnect pluging

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](https://raw.githubusercontent.com/Mochitto/Markdown2Anki/master/docs/Anki_import_example.webp)
After the cards are generated they are automatically imported into Anki via the AnkiConnect plugin.
Besides having the plugin installed in you Anki and having Anki open in the background, you don't need to do anything else.

You can find more information on importing to Anki here: https://docs.ankiweb.net/importing.html
If you don't want to use AnkiConnect plugin you can use the [legacy CSV file] output, which you can then import manually.

### Importing your images
You can import images automatically if you add the path to your [Anki media folder](https://docs.ankiweb.net/files.html#file-locations) 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.
[legacy CSV file]: ./docs/legacy_importing_cards_with_csv.md
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can turn this into a markdown link [Legacy CSV imports]( ./docs/legacy_importing_cards_with_csv.md) and put them in-line instead of as a foot-note


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.
Expand Down
38 changes: 38 additions & 0 deletions docs/legacy_importing_cards_with_csv.md
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just great :)

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Importing your cards via CSV - Legacy feature

<!-- prettier-ignore -->
> ![NOTE]
> This feature is considered legacy. Currently, the recommended way to import
> cards is via AnkiConnect plugin. To use this feature, you need to set `"use legacy CVS output?"`
> option in .ini config file to `True`.

### 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](https://raw.githubusercontent.com/Mochitto/Markdown2Anki/master/docs/Anki_import_example.webp)

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](https://docs.ankiweb.net/files.html#file-locations) 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.
80 changes: 51 additions & 29 deletions src/markdown2anki/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import os
import logging
import os
import sys
from pathlib import Path

from markdown2anki.md_2_anki.utils.card_error import CardError
from markdown2anki.md_2_anki import markdown_to_anki

import markdown2anki
import markdown2anki.config.configs_handle as config_handle
import markdown2anki.logger as log
import markdown2anki.output_handler as out
import markdown2anki.version_check as ver
import markdown2anki.config.configs_handle as config_handle
from markdown2anki.ankiconnect import AnkiConnect
from markdown2anki.markdown_handler import MarkdownHandler

from markdown2anki.md_2_anki import markdown_to_anki
from markdown2anki.md_2_anki.utils.card_error import CardError
from markdown2anki.utils.debug_tools import expressive_debug

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -41,13 +40,27 @@ def main():
)
expressive_debug(logger, "Processed config from main", config, "json")

logger.info("⏳ Starting cards extraction")

markdown_handle = MarkdownHandler(config["input md file path"])
try:
markdown_handle = MarkdownHandler(config["input md file path"])
except Exception as error:
logger.info("😯 An error occured when trying to open the input md file:")
logger.error(error)
sys.exit(1)
expressive_debug(
logger, "Markdown input file frontmatter", markdown_handle.metadata, "json"
logger,
"Markdown input file frontmatter",
markdown_handle.metadata,
"json",
)

try:
anki_conn = AnkiConnect(url=config["AnkiConnect URL"])
except Exception as error:
logger.error(error)
sys.exit(1)

logger.info("⏳ Starting cards extraction")

try:
cards_with_info = markdown_to_anki(
markdown_handle.content,
Expand Down Expand Up @@ -81,8 +94,13 @@ def main():
if images_to_copy:
out.copy_images_to_folder(images_to_copy, config["images out-folder"])

if success_cards:
logger.info(f"🔥 Successfully created a total of {success_cards} card/s!")
if not success_cards:
logger.info("❓ No cards created... Please check input the file.")
sys.exit(0)

logger.info(f"🔥 Successfully created a total of {success_cards} card/s!")

if config["use legacy CVS output?"]:
out.write_cards_to_csv(
cards_to_write,
os.path.join(config["config directory"], "basic_anki_cards.csv"),
Expand All @@ -91,27 +109,31 @@ def main():
cards_to_write_with_clozes,
os.path.join(config["config directory"], "clozed_anki_cards.csv"),
)

# Handle backups
out.backup_file(
config["input md file path"],
os.path.join(config["config directory"], "backups"),
else:
anki_conn.upload_cards(
cards_with_info,
markdown_handle.metadata["deck_name"],
markdown_handle.metadata["note_type_basic"],
markdown_handle.metadata["note_type_cloze"],
markdown_handle.metadata["tags"],
)

out.clear_backups(
os.path.join(config["config directory"], "backups"),
config["Number of backups"],
)
# Handle backups
out.backup_file(
config["input md file path"],
os.path.join(config["config directory"], "backups"),
)

if config["clear file?"]:
frontmatter_text = markdown_handle.get_frontmatter_text()
out.clear_file(config["input md file path"], frontmatter_text)
out.clear_backups(
os.path.join(config["config directory"], "backups"),
config["Number of backups"],
)

logger.info(
"🎆 File/s created! 🎆\nYou can now go import your file/s to Anki :)"
)
else:
logger.info("❓ No cards created... Please check input the file.")
if config["clear file?"]:
frontmatter_text = markdown_handle.get_frontmatter_text()
out.clear_file(config["input md file path"], frontmatter_text)

logger.info("🎆 File/s created! 🎆\nYou can now go import your file/s to Anki :)")

sys.exit(0)

Expand Down
Loading
Loading