AnkiIO 1.0.2
Build, validate, import, and export Anki-compatible decks from .NET
Loading...
Searching...
No Matches
Getting started

Install

Reference the AnkiIO package from a .NET 10 or newer application:

dotnet add package AnkiIO

Conventional cards

The convenience methods reuse the appropriate conventional note type throughout a deck hierarchy and create safe, unscheduled cards:

using AnkiIO;
var deck = new AnkiDeck("German");
deck.AddBasicNote("der Apfel", "the apple", tags: ["german", "noun"]);
deck.AddBasicAndReversedNote("gehen", "to go", tags: ["german", "verb"]);
var answer = AnkiCloze.Wrap("Berlin", hint: "city");
deck.AddClozeNote($"Germany's capital is {answer}.", tags: ["german", "geography"]);
Builds conservative Anki cloze-deletion markup for a Cloze note's Text field.
Definition AnkiCloze.cs:27
static string Wrap(string text, int index=1, string? hint=null)
Wraps answer text in Anki cloze-deletion markup.
Definition AnkiCloze.cs:55
Builds one named deck hierarchy and acts as the root for validation and export.
Definition AnkiDeck.cs:31

Use AnkiDeck.AddBasicNote(), AnkiDeck.AddBasicAndReversedNote(), and AnkiDeck.AddClozeNote() unless you need a custom model. Each method returns the created AnkiNote so fields and tags remain easy to adjust.

Custom note type, templates, CSS, and tags

var vocabulary = new AnkiNoteType("Illustrated Vocabulary")
.AddConfiguredField(new AnkiField("German", Font: "Arial", FontSize: 24))
.AddConfiguredField(new AnkiField("English"))
"German -> English",
"<div class='word'>{{German}}</div>{{Image}}",
"{{FrontSide}}<hr id='answer'>{{English}}")
"English -> German",
"<div class='word'>{{English}}</div>",
"{{FrontSide}}<hr id='answer'>{{German}}<br>{{Image}}");
vocabulary.Css = ".card{text-align:center;font-family:Arial}.word{font-size:2rem}";
deck.AddNote(vocabulary, new Dictionary<string, string>
{
["German"] = "die Katze",
["English"] = "the cat",
["Image"] = "<img src='cat.png'>"
}, tags: ["german", "animals"]);
Configures one named input field in an AnkiNoteType.
Definition AnkiField.cs:45
Defines the reusable schema and rendering rules shared by a family of Anki notes.
AnkiNoteType AddTemplate(string name, string questionFormat, string answerFormat)
Adds a card template at the next ordinal.
AnkiNoteType AddConfiguredField(AnkiField field)
Adds a configured field at the end of the field order.

Register media once and refer to its filename from field HTML:

await deck.Media.AddFileAsync("cat.png", "assets/cat.png");

Media registration records a SHA-256 digest. A path-backed file that changes before export is rejected rather than silently packaging different bytes.

Validate and export

var result = AnkiValidator.Validate(deck);
foreach (var diagnostic in result.Diagnostics)
{
Console.WriteLine($"{diagnostic.Severity} {diagnostic.Code}: {diagnostic.Message}");
}
if (!result.IsValid)
{
throw new InvalidOperationException("The deck is not safe to export.");
}
await AnkiPackageWriter.WriteAsync(deck, "German.apkg");
Writes validated deck data as a legacy-compatible .apkg archive accepted by Anki 26....
static async Task WriteAsync(AnkiDeck deck, string path, CancellationToken cancellationToken=default)
Writes one deck hierarchy to a package file without opening or modifying an Anki profile.
Checks a complete deck hierarchy before native JSON, CrowdAnki-style JSON, or APKG output.
static AnkiValidationResult Validate(AnkiDeck root)
Validates a root deck and every reachable descendant without modifying them.

The writer validates again, so callers cannot accidentally bypass release-blocking diagnostics. Native JSON is useful for lossless library-to-library interchange; the CrowdAnki-inspired adapter is intentionally a smaller, lossy subset.