# genanki-rs: A Rust Crate for Generating Anki Decks With `genanki-rs` you can easily generate decks for the popular open source flashcard platform Anki. *The code of this library is based on the code of [`genanki`](https://github.com/kerrickstaley/genanki), a python library to generate Anki decks.* *This library and its author(s) are not affiliated/associated with the main Anki project in any way.* ![example workflow](https://github.com/yannickfunk/genanki-rs/actions/workflows/rust.yml/badge.svg) ## Contribution Contributions in any form are welcome! Feel free to just create an Issue or a PR. ## How to use (Use the [`documentation`](https://docs.rs/genanki-rs/0.4.0/genanki_rs/index.html) for further information) Add ```toml [dependencies] genanki-rs = "0.4" ``` to your `Cargo.toml` or find another version on [*crates.io*](https://crates.io/crates/genanki-rs) ## Notes The basic unit in Anki is the `Note`, which contains a fact to memorize. `Note`s correspond to one or more `Card`s. Here's how you create a `Note`: ```rust use genanki_rs::{Note, Error}; fn main() -> Result<(), Error> { // let my_model = ... let my_note = Note::new(my_model, vec!["Capital of Argentina", "Buenos Aires"])?; Ok(()) } ``` You pass in a `Model`, discussed below, and a set of `fields` (encoded as HTML). ## Models A `Model` defines the fields and cards for a type of `Note`. For example: ```rust use genanki_rs::{Field, Model, Template, Error}; fn main() -> Result<(), Error> { let my_model = Model::new( 1607392319, "Simple Model", vec![Field::new("Question"), Field::new("Answer")], vec![Template::new("Card 1") .qfmt("{{Question}}") .afmt(r#"{{FrontSide}}
{{Answer}}"#)], ); // let my_note = ... Ok(()) } ``` This note-type has two fields and one card. The card displays the `Question` field on the front and the `Question` and `Answer` fields on the back, separated by a `
`. You can also pass custom `css` by calling `Model::css()` to supply custom CSS. ```rust let custom_css = ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n}\n"; let my_model_with_css = Model::new( 1607392319, "Simple Model", vec![Field::new("Question"), Field::new("Answer")], vec![Template::new("Card 1") .qfmt("{{Question}}") .afmt(r#"{{FrontSide}}
{{Answer}}"#)]) .css(custom_css); ``` You need to pass a model `id` and a model `name` so that Anki can keep track of your model. It's important that you use a unique model `id` for each `Model` you define. ## Generating a Deck/Package To import your notes into Anki, you need to add them to a `Deck`: ```rust use genanki_rs::{Deck, Error}; fn main() -> Result<(), Error> { // let my_note = ... let mut my_deck = Deck::new( 2059400110, "Country Capitals", "Deck for studying country capitals", ); my_deck.add_note(my_note); Ok(()) } ``` Once again, you need a unique deck `id`, a deck `name` and a deck `description`. Then, create a `Package` for your `Deck` and write it to a file: ```rust my_deck.write_to_file("output.apkg")?; ``` You can then load `output.apkg` into Anki using File -> Import... ## Media Files To add sounds or images, create a `Package` and pass the `decks` and `media_files` you want to include: ```rust use genanki_rs::{Deck, Error, Package}; fn main() -> Result<(), Error> { // ... // my_deck.add(my_note) let mut my_package = Package::new(vec![my_deck], vec!["sound.mp3", "images/image.jpg"])?; my_package.write_to_file("output.apkg")?; Ok(()) } ``` `media_files` should have the path (relative or absolute) to each file. To use them in notes, first add a field to your model, and reference that field in your template: ```rust let my_model = Model::new( 1607392319, "Simple Model", vec![ Field::new("Question"), Field::new("Answer"), Field::new("MyMedia"), // ADD THIS ], vec![Template::new("Card 1") .qfmt("{{Question}}{{Question}}
{{MyMedia}}") // AND THIS .afmt(r#"{{FrontSide}}
{{Answer}}"#)], ); ``` Then, set the `MyMedia` field on your `Note` to `[sound:sound.mp3]` for audio and `` for images (e.g): ```rust let my_note = Note::new(my_model, vec!["Capital of Argentina", "Buenos Aires", "[sound:sound.mp3]"])?; // or let my_note = Note::new(my_model, vec!["Capital of Argentina", "Buenos Aires", r#""#])?; ``` You *cannot* put `` in the template and `image.jpg` in the field. See these sections in the Anki manual for more information: [Importing Media](https://docs.ankiweb.net/#/importing?id=importing-media) and [Media & LaTeX](https://docs.ankiweb.net/#/templates/fields?id=media-amp-latex). You should only put the filename (aka basename) and not the full path in the field; `` will *not* work. Media files should have unique filenames. ## sort_field Anki has a value for each `Note` called the `sort_field`. Anki uses this value to sort the cards in the Browse interface. Anki also is happier if you avoid having two notes with the same `sort_field`, although this isn't strictly necessary. By default, the `sort_field` is the first field, but you can change it by calling `Note::sort_field()`. You can also call `Model::sort_field_index()`, passing the `sort_field_index` to change the sort field. `0` means the first field in the Note, `1` means the second, etc. ## FAQ ### My field data is getting garbled If fields in your notes contain literal `<`, `>`, or `&` characters, you need to HTML-encode them: field data is HTML, not plain text. For example, you should write ```rust let fields = vec!["AT&T was originally called", "Bell Telephone Company"] ``` This applies even if the content is LaTeX; for example, you should write ```rust let fields = vec!["Piketty calls this the \"central contradiction of capitalism\".", "[latex]r > g[/latex]"] ```