Documentation
¶
Overview ¶
Package ganki provides a Go library for generating Anki .apkg files.
ganki is functionally identical to the Python library genanki (v0.13.1), producing .apkg files that can be imported by Anki.
Quick Start ¶
Create a model, notes, deck, and package:
model := &ganki.Model{
ID: 1559383000,
Name: "Basic (genanki)",
Fields: []ganki.Field{
{Name: "Front", Font: "Arial"},
{Name: "Back", Font: "Arial"},
},
Templates: []ganki.Template{
{Name: "Card 1", QFmt: "{{Front}}", AFmt: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"},
},
CSS: ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n",
}
note := ganki.NewNote(model, []string{"What is 2+2?", "4"})
deck := ganki.NewDeck(123456, "My Deck")
deck.AddNote(note)
pkg := ganki.NewPackage([]*ganki.Deck{deck})
if err := pkg.WriteToFile("output.apkg"); err != nil {
log.Fatal(err)
}
Built-in Models ¶
ganki provides the same built-in models as genanki:
ganki.BasicModel // Basic (genanki) ganki.BasicAndReversedCardModel // Basic (and reversed card) (genanki) ganki.BasicOptionalReversedCardModel // Basic (optional reversed card) (genanki) ganki.BasicTypeInTheAnswerModel // Basic (type in the answer) (genanki) ganki.ClozeModel // Cloze (genanki)
GUID Generation ¶
Use GUIDFor to generate deterministic GUIDs from field values:
guid := ganki.GUIDFor("field1", "field2")
Index ¶
Constants ¶
This section is empty.
Variables ¶
var BasicAndReversedCardModel = &Model{ ID: 1485830179, Name: "Basic (and reversed card) (genanki)", Fields: []Field{ {Name: "Front", Font: "Arial"}, {Name: "Back", Font: "Arial"}, }, Templates: []Template{ {Name: "Card 1", QFmt: "{{Front}}", AFmt: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"}, {Name: "Card 2", QFmt: "{{Back}}", AFmt: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}"}, }, CSS: ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n", }
var BasicModel = &Model{ ID: 1559383000, Name: "Basic (genanki)", Fields: []Field{ {Name: "Front", Font: "Arial"}, {Name: "Back", Font: "Arial"}, }, Templates: []Template{ {Name: "Card 1", QFmt: "{{Front}}", AFmt: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"}, }, CSS: ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n", }
var BasicOptionalReversedCardModel = &Model{ ID: 1382232460, Name: "Basic (optional reversed card) (genanki)", Fields: []Field{ {Name: "Front", Font: "Arial"}, {Name: "Back", Font: "Arial"}, {Name: "Add Reverse", Font: "Arial"}, }, Templates: []Template{ {Name: "Card 1", QFmt: "{{Front}}", AFmt: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"}, {Name: "Card 2", QFmt: "{{#Add Reverse}}{{Back}}{{/Add Reverse}}", AFmt: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}"}, }, CSS: ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n", }
var BasicTypeInTheAnswerModel = &Model{ ID: 1305534440, Name: "Basic (type in the answer) (genanki)", Fields: []Field{ {Name: "Front", Font: "Arial"}, {Name: "Back", Font: "Arial"}, }, Templates: []Template{ {Name: "Card 1", QFmt: "{{Front}}\n\n{{type:Back}}", AFmt: "{{Front}}\n\n<hr id=answer>\n\n{{type:Back}}"}, }, CSS: ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n", }
var ClozeModel = &Model{ ID: 1550428389, Name: "Cloze (genanki)", ModelType: ModelCloze, Fields: []Field{ {Name: "Text", Font: "Arial"}, {Name: "Back Extra", Font: "Arial"}, }, Templates: []Template{ {Name: "Cloze", QFmt: "{{cloze:Text}}", AFmt: "{{cloze:Text}}<br>\n{{Back Extra}}"}, }, CSS: ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n\n.cloze {\n font-weight: bold;\n color: blue;\n}\n.nightMode .cloze {\n color: lightblue;\n}", }
var DefaultLatexPost = "\\end{document}"
DefaultLatexPost is the default LaTeX postamble used by Anki models.
var DefaultLatexPre = "\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n" +
"\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n" +
"\\begin{document}\n"
DefaultLatexPre is the default LaTeX preamble used by Anki models.
Functions ¶
func GUIDFor ¶
GUIDFor generates a globally unique identifier from the given values. The algorithm matches genanki's guid_for exactly:
- Join values with "__"
- SHA256 hash
- Take first 8 bytes
- Convert to big integer (big-endian)
- Encode in Anki's custom base91
If no values are provided, returns the GUID for an empty string.
func MustacheRender ¶
MustacheRender renders a Mustache template with the given context. This is a minimal implementation supporting only the features needed for computing required fields (_req) in Anki models:
- {{name}} — variable interpolation (unknown keys render as empty string)
- {{#name}}...{{/name}} — section (renders content if value is truthy/non-empty)
- {{^name}}...{{/name}} — inverted section (renders content if value is falsy/empty)
This matches the behavior of Python's chevron library for the subset we use.
Types ¶
type Card ¶
type Card struct {
// Ord is the card ordinal (0-based), corresponding to the template index.
Ord int
// Suspend indicates whether the card should be suspended when imported.
// Suspended cards have queue=-1 instead of queue=0.
Suspend bool
}
Card represents a single card within an Anki note. Each card corresponds to a template in the note's model.
type DeckOption ¶
type DeckOption func(*deckConfig)
func WithDescription ¶
func WithDescription(description string) DeckOption
type IDGenerator ¶
type IDGenerator struct {
// contains filtered or unexported fields
}
IDGenerator generates sequential integer IDs, replacing Python's itertools.count(). IDs start from the given initial value and increment by 1 for each call to Next. This is used to generate unique note and card IDs within an .apkg file.
func NewIDGenerator ¶
func NewIDGenerator(start int64) *IDGenerator
NewIDGenerator creates a new IDGenerator that starts producing IDs from start.
type Model ¶
type Note ¶
type Note struct {
Model *Model
Fields []string
SortField string
Tags []string
GUID_ string
Due int
// contains filtered or unexported fields
}
func (*Note) GetSortField ¶
type NoteOption ¶
type NoteOption func(*Note)
func WithDue ¶
func WithDue(d int) NoteOption
func WithGUID ¶
func WithGUID(g string) NoteOption
func WithSortField ¶
func WithSortField(sf string) NoteOption
func WithTags ¶
func WithTags(tags []string) NoteOption
type Package ¶
func NewPackage ¶
func NewPackage(decks []*Deck, opts ...PackageOption) *Package
func (*Package) WriteToFile ¶
func (p *Package) WriteToFile(path string, opts ...PackageOption) error
type PackageOption ¶
type PackageOption func(*packageConfig)
func WithMediaFiles ¶
func WithMediaFiles(files []string) PackageOption
func WithTimestamp ¶
func WithTimestamp(t time.Time) PackageOption