GithubHelp home page GithubHelp logo

kerrickstaley / genanki Goto Github PK

View Code? Open in Web Editor NEW
1.9K 1.9K 147.0 134 KB

A Python 3 library for generating Anki decks

License: MIT License

Python 97.58% Shell 1.97% Makefile 0.45%
anki anki-flashcards

genanki's People

Contributors

black-puppydog avatar bollwyvl avatar chambln avatar dvklopfenstein avatar gzzo avatar hiandrewquinn avatar holocronweaver avatar kerrickstaley avatar pbanuru avatar remiberthoz avatar sciencemanx avatar z1lc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

genanki's Issues

Is it possible to change the LaTex premable on a Model?

Hi there, thank you for this great package.
When I was looking into the code for Model.to_json in model.py I noticed that the LaTex preamble for the Note type is constant.

return {
      "css": self.css,
      "did": deck_id,
      "flds": self.fields,
      "id": str(self.model_id),
      "latexPost": "\\end{document}",
      "latexPre": "\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage{amssymb,amsmath}\n"
                  "\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n",
      "mod": now_ts,
      "name": self.name,
      "req": self._req,
      "sortf": 0,
      "tags": [],
      "tmpls": self.templates,
      "type": self.model_type,
      "usn": -1,
      "vers": []
    }

Is there some way to change the LaTex preamble for a Model object to use more LaTex packages & define environments?

Is there a way to UPDATE a Model object's attributes? (fields & templates)

hello! Thank you so much for this library! It has been really helpful!

I just got a question cause once you create an object of type Model you're going to pass in fields and template right... So in my program I'll be needing to somehow UPDATE those fields and templates depending on the Question and Answer data that I have so my question is... Is there a function or setter method that would update the fields and templates attribute in the class?

I know I can make a new instance of a model over and over again but I think that's not programmatically efficient so I am asking the devs about this if they have included it... I know I can also call dir() to see the methods and review the code but I would like to ask it here and probably learn more about it when I talk to one of the developers.

Example here:
So when I create that my_model is there a way to update the attributes? Can I just simply do a .fields = #something same with templates? I was wondering if there could be a function for it.,

my_model = genanki.Model(1607392319,'Simple Model',
  fields=[
    {'name': 'Question'},
    {'name': 'Answer'}
  ],
  templates=[
    {
      'name': 'Card 1',
      'qfmt': '{{Question}}',
      'afmt': '{{FrontSide}}<hr id="answer">{{Answer}}',
    },

  ])

Again THANK YOU FOR THIS! SUCH A HELPFUL LIBRARY!

Says field is missing when field is missing with {{Type:}}

image
but VerseText is clearly present

image

Here's the template, as this is likely the problem:

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

<script>
  //Found here: https://gist.github.com/hinekidori/4085a1222af572057f1058d43cfce773
  //Script for modifying 'Show Answer' behavior for Input types.
  var htmlTextNodes = [];
  var innerHTMLText = [];
  var htmlNodeLength =document.getElementById('typeans').childNodes.length;
  var typedAnswer;
  var correctAnswer;
  var firstBr = null;
  var secondBr;
  
  //capture each node to array
  for (i = 0; i < htmlNodeLength; i++) {
   
   htmlTextNodes[i] = document.getElementById('typeans').childNodes[i];
   innerHTMLText[i] = document.getElementById('typeans').childNodes[i].innerHTML;
   
   //locate <br> tags for output change markers
   if (document.getElementById('typeans').childNodes[i].nodeName == "BR") {
    console.log("Runs if BR");
    if (firstBr != null) {
     secondBr = i;
    } else {
     firstBr = i;
    };
   };
  };
  
  //If answer is correct, firstBr will still be null, so must set to length of typeans.childNode
  if (firstBr == null) {
   firstBr = htmlNodeLength;
  };
  //assemble typed and correct answer strings
  typedAnswer = innerHTMLText.slice(0,firstBr).join("");
  var corr = document.getElementById('correctAnswer');
  correctAnswer = corr.innerHTML;
  
  //Modify answer output
  if (typedAnswer === correctAnswer) {
   var c = "<div id='correct'>"+typedAnswer+"</div>";
   var d = document.getElementById('typeans');
   d.innerHTML =  c;
  } else {
   var e = "<div id='incorrect'>"+typedAnswer+"</div>";
   var f = document.getElementById('typeans');
   f.innerHTML =  e;
  };
  </script><div class="front rote even container">
  <div class="row">
    <div class="field hint verse id col-12">
      {{BookName}} {{ChapterNumber}}:{{VerseNumber}}
    </div>
  </div>
  <div class="row">
    <div class="field hint even-words col-12">
      {{EvenWords}}
    </div>
  </div>
  <div class="row">
    <div class="type answer col-12">
      {{type: VerseText}}
    </div>
  </div>
</div>

No way to load/modify existing packages

I have grown dissatisfied with a shared deck I am using, and want to make some changes to it programatically.
I want to do this while maintaining the reviews/data/progress etc

I assume I could make a new deck and overwrite the cards if I keep the GUIDs the same, but there are over 2000 cards in this deck so it would be impractical to read these GUIDs manually.

If it's too much work to add read functionality to this library, I would appreciate some advice on how to extract an ordered list of GUIDs from within Anki, so I can use genanki without reading the old set of cards.

Thanks

genanki.Note should have a field for the paths to its media files

Instead of having a .media_files attribute on Package, it may be more ergonomic to have a .media_files attribute on each genanki.Note instance. The .media_files for the overall package will then be computed by combining the lists for each individual Note (removing duplicates).

Need to think a little more about whether this design will handle all use-cases and whether it will be genuinely easier to use. One consideration is "static" media files; those still need to be specified at the package level.

All cards added to the first deck name when multiple decks are added to a package.

Dear KerrickStaley,

Thank you for sharing your library.
I think I might have found an issue.

Example code:

data = {
    'deck1':
    [{
    'a': 'content deck 1 a1',
    'b': 'content deck 1 b1'
    },
    {
    'a': 'content deck 1 a2',
    'b': 'content deck 1 b2'
    }],
    'deck2':
     [{
    'a': 'content deck 2 a1',
    'b': 'content deck 2 b1'
    },
    {
    'a': 'content deck 2 a2',
    'b': 'content deck 2 b2'
    }],
    'deck3':
     [{
    'a': 'content deck 3 a1',
    'b': 'content deck 3 b1'
    },
    {
    'a': 'content deck 3 a2',
    'b': 'content deck 3 b2'
    }]  
}

# Create the model
a_to_b = genanki.Model(
    2043134337, # unique identifier
    'a-to-b', # human readable name
    fields = [ 
    {'name': 'a'},
    {'name': 'b'},
    ],
    templates=[
    {
      'name': 'Card 1',
      'qfmt': '{{a}}',
      'afmt': '{{FrontSide}}<hr id="answer">{{b}}',
    },
    ]
)

decks = []
for deck_name in data:
    deck = genanki.Deck(
      2043134340,
      deck_name
    )

    # Add the notes
    for note in data[deck_name]:
      note = genanki.Note(
        model=a_to_b,
        fields=[note.get('a',''),
                note.get('b',''),
               ])
      deck.add_note(note)
    decks.append(deck)

# Create the file
genanki.Package(decks).write_to_file('output.apkg')

When I then load this apkg file into Anki, Anki adds all 6 cards that should be in deck1, deck2 and deck3 into only deck1.

Set SRS mastery data

I am using genanki to convert data from an SRS app to Anki. I want to translate the SRS mastery data so the Anki items are due roughly when they would have been in the original SRS app.

How can I accomplish this using genanki?

Near as I can tell the fields in Card.write_to_db control this, but I am not sure what the SRS-related fields mean. I guess I will have to look at the Anki source to figure it out. AnkiDroid has some convenient documentation.

I would prefer to set SRS data at the Note level.

I plan to implement this feature, but thought I would ask for some guidance first.

Warning related to yaml.load call

Getting this YAMLLoadWarning on newer versions of the yaml lib:

/home/kerrick/.local/lib/python3.7/site-packages/genanki-0.6.5-py3.7.egg/genanki/model.py:18: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  self.fields = yaml.load(fields)
/home/kerrick/.local/lib/python3.7/site-packages/genanki-0.6.5-py3.7.egg/genanki/model.py:24: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  self.templates = yaml.load(templates)

How can I create with many Fields?

Hello first of all thank you with this python library. It is so cool! really helps me a lot in creating anki decks!

I have a question thoooo can you please help me and I think my question is just very very simple so here it is

my_note = genanki.Note(
  model=my_model,
  fields=['Capital of Argentina', 'Buenos Aires'])

On this code is you create a card right with the question "Capital of Argentina" and as the answer "Buenos Aires"... and it looks like this
image
image

I was thinking of can you provide an example on how can I make a field like this?
image

Thank you so much!

How can I apply cloze?

Hello! Thank you for this library :) really been helpful!

May I ask on how can I apply cloze. I am trying to read this data from google doc but when I generate a deck, it doesn't work

image

Instead I get this

image

Here is the code where I generate the deck. Thank you

model = genanki.Model(1607392319,'USC1 Sample Model',
		fields=[
			{'name': 'Question'},
			{'name': 'Answer'}
		],
		templates=[
			{
				'name': 'Card 1',
				'qfmt': '{{Question}}',
				'afmt': '{{FrontSide}}<hr id="answer">{{Answer}}',
			},

		])


	deck = genanki.Deck(2059400110,'USC1 Beta Deck')

	for key,value in output_dict.items():
		if isinstance(value,Mapping) == True:
			for subkey,subvalue in value.items():
				answer = subkey
				if subvalue:
					answer = f"{subkey} <ul>"+ ''.join([f"<li>{sa}</li>" for sa in subvalue]) + "<ul>"


				note = genanki.Note(
					model=model,
					fields=[key,answer])


				deck.add_note(note)

empty fields aren't supported?

Hi,

You're package si great but this doesn't work :
note = genanki.Note(
model=model,
fields=[citation, title, author, "", ""]
)
When a Package containing such card is uploaded, I can't get the deck to be generated correctly by athenki.

issue - multiline cloze detection (with solution)

Issue:

Multiline cloze deletions aren't detected. When exporting deck to Anki, cards with multiline clozes (probably only the ones with multiline clozes, but I didn't test that) don't show. Only when database check is preformed they are detected and put into deck named "Default".

Solution:

Edit3: I tested my solution and seems that there is also some other problem
Edit4: it seems to be working (I forgot to change model to cloze in my test)
Change in line 101 of file genanki/note.py:

      card_ords.update(int(m)-1 for m in re.findall(r"{{c(\d+)::.+?}}", field_value) if int(m) > 0)

to:

      card_ords.update(int(m)-1 for m in re.findall(r"{{c(\d+)::.+?}}", field_value, re.DOTALL) if int(m) > 0)

or:

      card_ords.update(int(m)-1 for m in re.findall(r"{{c(\d+)::[\s\S]+?}}", field_value) if int(m) > 0)

Explanation:

. matches anything except a newline character (relevant python3 doc).

Example:

test_str_part = \
"""
{{c1:: test 
}}
"""
clozes = re.findall(r"{{c(\d+)::.+?}}", test_str_part)
for e in clozes:
    print(e)
#cloze isn't detected

Other:

I'm new to git and currently I don't have much time, but if I find any I will try to send commit with fixed code (if that's possible).

With regards
mat383

Edit1: expanded issue description
Edit2: grammar

Support Python 2

Python 2 is never going to die. Support Python 2 for those poor unenlightened souls who can't or won't use Python 3.

A problem in media

I use a Python module genanki to generate cards.But the image is always broken in the card.
My code are as follow
.
‘’’
import genanki

my_model = genanki.Model(
1091735104,
‘Simple Model with Media’,
fields=[
{‘name’: ‘Question’},
{‘name’: ‘Answer’},
{‘name’: ‘MyMedia’},
{‘name’: ‘MyAnswerMedia’} # ADD THIS
],
templates=[
{
‘name’: ‘Card 1’,
‘qfmt’: ‘{{Question}}
{{MyAnswerMedia}}’, # AND THIS
‘afmt’: ‘{{FrontSide}}

{{MyMedia}}
{{Answer}}’,
},
])
deckname = “newDeck”
decknumber = 987655
my_deck = genanki.Deck(
decknumber,
deckname)

my_note=genanki.Note(
model=my_model,
fields=[“test”,“test”, ‘’,“test”])
my_deck.add_note(my_note)

my_package = genanki.Package(my_deck)
my_package.media_files = [ “img_2991.jpg”]
genanki.Package(my_deck).write_to_file(deckname + r".apkg")
‘’’

By the way when I check the media file within apkg file and open it with notebook,it simply contain a {}.Can someone help me?

Remove write_to_* from Deck class

This creates a dependency cycle and it pretty unneeded. Additionally, you can't use media files to the deck this way.

I think these methods should be removed... thoughts?

HOWTO: insert script into template model?

I'm trying to add mathjax support to one of my model templates using this guide

I have to insert it to the front and the back of the card, so far I tried to load it in

mathjax="<script type=\"text/x-mathjax-config\">\n"
mathjax+="MathJax.Hub.processSectionDelay = 0;\n"
mathjax+="MathJax.Hub.Config({\n"
mathjax+="  messageStyle: 'none',\n"
mathjax+="  showProcessingMessages: false,\n"
mathjax+="  tex2jax: {\n"
mathjax+="    inlineMath: [['$', '$']],\n"
mathjax+="    displayMath: [['$$', '$$']],\n"
mathjax+="    processEscapes: true\n"
mathjax+="  }\n"
mathjax+="});\n"
mathjax+="</script>\n"
mathjax+="<script type=\"text/javascript\">\n"
mathjax+="(function() {\n"
mathjax+="  if (window.MathJax != null) {\n"
mathjax+="    var card = document.querySelector('.card');\n"
mathjax+="    MathJax.Hub.Queue(['Typeset', MathJax.Hub, card]);\n"
mathjax+="    return;\n"
mathjax+="  }\n"
mathjax+="  var script = document.createElement('script');\n"
mathjax+="  script.type = 'text/javascript';\n"
mathjax+="  script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML';\n"
mathjax+="  document.body.appendChild(script);\n"
mathjax+="})();\n"
mathjax+="</script>\n"
reversible_mathjax = genanki.Model(
1179517143,
'Reversible Model with mathjax',
fields=[
  {'name': 'Question'},
  {'name': 'Answer'},
],
templates=[
  {
    'name': 'Card 1',
    'qfmt': ('{{Question}}\n{}').format(mathjax),
    'afmt': ('{{FrontSide}}<hr id="answer">\n{}').format(mathjax),
  },
  {
    'name': 'Card 2',
    'qfmt': ('{{Answer}}\n{}').format(mathjax),
    'afmt': ('{{FrontSide}}<hr id="answer">{{Question}}\n{}').format(mathjax),
  }
])

Turns out this worked, but I still want to leave this here for other people to use.

[FEATURE REQUEST] Generate subdecks from filenames

In Anki when you use the :: symbol when naming a deck and you get a little dropdown to help organise a large set of flashcards into multiple subdecks so for example Root name::Subdeck name would have Root name as the main deck name and Subdeck name as the name of the subdeck within the main deck.

Is it possible to do this with genanki?

We would love to be able to make subdecks as this would help us to autogenerate flashcards for various projects such as https://github.com/darigovresearch/Universal-Foreign-Language-Flashcards

Would be happy to do a pull request if given guidance on where to insert what in the relevant sections of the codebase.

Writing deck to file raises an exception.

I get an error whenever I try to write a deck to file. It happens also with the example in the documentation, so it shouldn't be caused by the deck I am trying to create.

This is the output I get:

>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/carles/Desktop/kindletoanki/test.py", line 30, in <module>
    genanki.Package(my_deck).write_to_file('output.apkg')
  File "/home/carles/.local/lib/python2.7/site-packages/genanki-0.2.1-py2.7.egg/genanki/__init__.py", line 289, in write_to_file
    self.write_to_db(cursor, now_ts)
  File "/home/carles/.local/lib/python2.7/site-packages/genanki-0.2.1-py2.7.egg/genanki/__init__.py", line 302, in write_to_db
    deck.write_to_db(cursor, now_ts)
  File "/home/carles/.local/lib/python2.7/site-packages/genanki-0.2.1-py2.7.egg/genanki/__init__.py", line 271, in write_to_db
    note.write_to_db(cursor, now_ts, self.deck_id)
  File "/home/carles/.local/lib/python2.7/site-packages/genanki-0.2.1-py2.7.egg/genanki/__init__.py", line 232, in write_to_db
    '',                           # data
sqlite3.IntegrityError: NOT NULL constraint failed: notes.guid

Same fields, different note ID lead to problems in Anki. Should GUID take note or deck ID into account?

I created two decks with genanki:

  • Deck A has its own deck ID, is own note type with its own ID. Let’s say fields A and B. I create one note with some values.
  • Deck B is identical but has its down deck ID and note type ID. But same fields and test note with same value as test note for deck A.

Importing deck A works, but importing deck B fails after I import A: "Notes skipped, as they’re already in your collection"

So Anki thinks the notes are identical because they have the same GUID. The mid of course is different.

I raised this topic on the Anki forum and it seems they don't consider this worth fixing. Anki author Damien Elmes said:

I think the original intention was to combine notetype ID + guid to get a standard UUID size, but I don't think the current code is
doing that. I'd be surprised if conflicts were common in practice however, outside of usage of third-party tools that are not
generating them randomly.

So I'm wondering if genanki should also use the note ID or deck ID to generate the GUID. This would avoid the problem I encountered.

One question is how to handle such a change without breaking existing deks (GUIDs).

Add media / sound support

I had like to use genanki to create cards having a sound as front side.

My understanding is that it is not yet possible because genanki does not support media. Do you plan to add media support?

Default Models

Creating Models is hard, let's add some default models based on Anki's built-in ones.

Anki Deck cannot import

When creating the deck, upon import, Anki says the notes have been added yet I cannot find them anywhere. Here's the code:

from openpyxl import load_workbook
import genanki
import random

"""
1. be able to generate a random number that's really big without repitions
2. setup note type
3. setup the model
4. make a deck to fill
5. figure out note types

"""
beg = 1000000000
end = 9999999999
id_list = []
for i in range(0, 5000):
    randomNum = random.randint(beg,end)
    while randomNum in id_list:
        randomNum = random.randint(beg, end)
    id_list.append(randomNum)


model = genanki.Model(
  id_list[-1],
  'Simple Model',
  fields=[
    {'name': 'Meaning'},
    {'name': 'Arabic Spelling'},
    {'name': 'Phonetic Spelling'},
    {'name': 'Audio'},
  ],
  templates=[
      {
        'name': 'Only Card',
          'qfmt': 'How do you say:<div style="font-family: Arial; font-size: 40px; padding: 20px;">{{Arabic Spelling}}</div>',
          'afmt': '{{FrontSide}}<hr id=answer><div style="font-family: Arial; font-size: 20px; padding: 20px;">{{Meaning}}</div><div style="font-family: Arial; font-size: 20px; padding: 20px;"><em>{{Phonetic Spelling}}</em></div><div style="font-family: Arial; font-size: 20px; padding: 20px;">{{Audio}}</div>',
      },
  ])
del id_list[-1]



my_deck = genanki.Deck(
  id_list[-1],
  'test')
del id_list[-1]

wb = load_workbook("all_words.xlsx")
sheet = wb.get_sheet_by_name('ALL WORDS')
englishWordList = []

for col_cells in sheet.iter_cols(min_row=2, min_col=1, max_col=1):
    for cell in col_cells:
        englishWordList.append(cell.value)

i = 0
for word in englishWordList:
    note = genanki.Note(
        sort_field=id_list[i],
        model=model,
        fields=[word, "", "", ""]
    )
    my_deck.add_note(note)
    i = i + 1
i = 0

genanki.Package(my_deck).write_to_file("testOutput.apkg")

Anki adds all the notes (which have no cards made) yet I can't find them inside Anki. I thought maybe it's because of my add-ons, yet from the readme file it's unclear how to use the .write_to_collection_from_addon() method. I don't know how to use the method.

When I close and reopen Anki, it says there is a problem with the database and tells me to "Check Database". Once I do this, it deletes all the notes that were added from my script. What's the best way to use the method, and/or what is the solution to this issue? I've tried looking everywhere.
Screen Shot 2019-09-03 at 5 13 39 PM
Screen Shot 2019-09-03 at 5 14 20 PM

<style> tags

Please could you tell me how to stop gen anki putting <style> tags in? I would like it just to be plain text.

Very best,
S

Add more information to note fields != note model fields valueError

raise ValueError('Number of fields in Model does not match number of fields in Note')

I ran into this error recently when installing genanki on a new user account (and incidentally updating it), and it was very hard to debug.

I generate thousands of cards each time across two note types, and I still don't know which note type or card generated the problem – instead, I ended up downgrading to 0.8.0.

I suggest adding model name or similar to the valueError, but am not sufficiently competent to add a new commit :-)

ModuleNotFoundError: No module named 'setuptools'

Hi Kerrick,

I have found this repository and very much like it. Thank your for investing your time into that code.
As I have not too much experience with python and some with Linux, I struggle to get it to run.

I have managed to download and install these 3 packages:

  • cached-property
  • frozendict
  • pystache

but "pyyaml" I am not sure if it was installed, as I downloaded that manually and not with the Software Manager of Linux.
When I do a "make install" in the "genanki-master"-directory, I receive this output:

python3 setup.py install --user
Traceback (most recent call last):
  File "setup.py", line 1, in <module>
    from setuptools import setup
ModuleNotFoundError: No module named 'setuptools'
Makefile:3: recipe for target 'install' failed
make: *** [install] Error 1

It seems like it point to this line here:

from setuptools import setup

I have not been able to find that directory or file "setuptools". Where is that?

Thank you very much for your help :)

Best regards
Joel

[DOCS] Generate an initial documentation page

Following the discussion on issue #74 thought it would be good to open a specific issue on generating documentation in case the community had any thoughts on what the best docs format would be and to see if anyone would like to contribute in making one.

Seeking clarification as to which is the 'real' master branch

I'm confused as to the connection between this branch and the one here:
https://github.com/dvklopfenstein/genanki

Though the dvklopfenstein fork has the same version number it appears to have received more recent contributions from kerrickstaley than this branch has. For that reason, I'm using the dvklopfenstein fork.

Should I be? And if I have questions to ask or issues to report, where should I post them? I guess here because the other fork's "Issues" button is missing, but please confirm.

Handle HTML in sort field

Anki allows HTML in field data, but for the sort field, it looks like it renders it down to plain ASCII. Currently genanki just copies the field data directly into the sort field, without stripping the HMTL tags. We should mimic Anki's behavior. (Needs more investigation / more detailed examples, just putting this here so I don't lose track of it.)

Packaging issues with media files

I've reviewed the prior issues and I don't think the problem is related to #46. Neither my sound files nor images appear when the .apkg file is loaded. I'm using genaki version 0.80.

ItalianModel = genanki.Model(
    1300703785,
    'Italian Model',
    fields=[
        {'name': 'Question'},
        {'name': 'Answer'},
        {'name': 'Image'},
        {'name': 'Audio'},
    ],
    templates=[
        {
            'name': 'Card 1',
            'qfmt': '{{Question}}<br><br>{{Image}}',
            'afmt': '{{FrontSide}}<hr id="answer">{{Answer}}<br>{{ Audio}}',
        },
    ],
)


ItalianDeck = genanki.Deck(
    1281791336,
    'My Italian Deck')


def build_anki_deck(*source):
    package = genanki.Package(ItalianDeck)
    for question, answer, image, mp3file in source:
        package.media_files.append(image)
        package.media_files.append(mp3file)
        note = genanki.Note(
            model=ItalianModel,
            fields=[
                question,
                answer,
                '<img src=\"{}\">'.format(image),
                "[sound:{}]".format(mp3file),
            ])
        ItalianDeck.add_note(note)
    genanki.Package(ItalianDeck).write_to_file('output.apkg')

The script is run from the same path where all the media files are located. I'm running Python 3.7.5 on Linux and the libraries are in a virtual environment.

note order after importation in anki and note creation date problem

hi , thank you for the amazing library you maid.
I remark that when i generate a deck with genanki and just after import it , the creation date displayed by anki is incorrect . check the picture below :
Capture d’écran du 2019-06-09 03-25-38

My main problem is that when i create decks by adding notes one by one , this order is not the same in anki .

Donations?

Hi guys!

You're doing great work, and this software has allowed me to do a bunch of things I couldn't do without it. Is there a place I can donate to, or do you have a preferred charity? :-)

Martin

BUG? Incorrect parsing of < > in generation of fields for card

My version Version ⁨2.1.36 (c505894b)⁩
Python 3.8.6 Qt 5.14.2 PyQt 5.14.2

Problem I am creating notes with genanki but I realised that for some notes which have the characters < /> in them they are partially parsed. So, I've checked the collections.anki2 file within the genanki-generate .apkg. (the following refers to the notes table of the Anki sqlite database) .E.g. for the flds value

2-Programming-Techniq...�0�code out the simplest c++ template for CP?��#include <bits/stdc++.h>

using namsepace std;

int main() {
}

where each field is correctly separated by the 0x1f character, I incorrectly get the output shown on the image. **The field is correctly set for other string values, so I was wondering if this is a bug relating to how it escapes < and > character? @kerrickstaley **

I've disabled all add-ons to make sure it wasn't an add-on that incorrectly modified the card.

Screenshot 2021-04-21 at 19 05 48

[decks_info.json] [ { "name": "Guide to Competitive Programming", "cards": [ { "name": "code out the simplest c++ template for CP?", "back": "", "tags": [ "Guide-to-Competitive-Programming::2-Programming-Techniq..." ], "media": [], "model": "code", "number": 0, "answer": "#include <bits/stdc++.h>\n\nusing namsepace std;\n\nint main() {\n}" },

[note model] based on fields=[ {"name": "CategoryTag"}, {"name": "OrderNumber"}, {"name": "Front"}, {"name": "Back"}, {"name": "Answer"}, {"name": "MyMedia"}, ],

Problem when attaching an image media file

This library is really a convenient way to create decks! I am trying to create decks programmatically to learn the names of my students (https://github.com/jlumbroso/tiger-anki). As such, I am trying to associate names to images and vice-versa.

This seems to be a perfect use of the media_files attribute. However, every attempt I have made, results in a deck in which Anki displays all images as "broken images."

I have attached a minimal reproducible example, test.py, on my system with Python 3.6, Anki 2.1.4 and genanki 0.6.0 (installed with pip). It generates an output.apkg deck, with a single card that produces one of these broken links.

When I unzip the deck, it seems like the media file is encoded appropriately following the format specs:

http://decks.wikia.com/wiki/Anki_APKG_format_documentation#Media_Formatting

I am not sure what is the wrong, or whether it is an issue with genanki or anki.

screen shot 2018-09-23 at 12 36 01 am

I created a minimal example in the following gist:
https://gist.github.com/jlumbroso/60971ec65324603c0ab2efd02fd8098b

which will generate the deck python3 genanki-media-test.py.

The file I have included as an example image format.jpg is:

format

But any JPG image would do.

Complicated LaTeX gets messed up when importing

On Arch Linux, Python 3.7.2

If I create a apkg file with this script:

import genanki

my_deck = genanki.Deck(1391554143, "my_deck")

my_model = genanki.Model(
    1836072805,
    "my_model",
    fields=[{"name": "Question"}, {"name": "Answer"}],
    templates=[{"name": "Card 1", "qfmt": "{{Question}}", "afmt": "{{Answer}}"}],
)

rxn0 = r"""[latex]
\schemestart
\chemfig{*6(--(<OH)-(<:Br)---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop[/latex]"""

reagents0 = r"""\(\ce{NaOH, H_2O_2}\)"""

rxn1 = r"""[latex]
\schemestart
\chemfig{*6(--=---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop[/latex]
"""

reagents1 = r"""\(\ce{mCPBA, CH_2Cl_2}\)"""

rxn2 = r"""[latex]
\schemestart
\chemfig{C(-[:0]
    C(-[:90]X)(-[:0])(-[:270])
)(-[:90])(-[:180])(-[:270]H)}
\arrow{->[?]}
\chemfig{C(-[:120])(-[:-120])=C(-[:60])(-[:-60])} \+ \ce{HX}
\schemestop[/latex]
"""

reagents2 = r"""\(\ce{Na^{+}{}^{-}OCH_2CH_3, EtOH, 70°C}\)"""

my_deck.add_note(genanki.Note(model=my_model, fields=[rxn0, reagents0]))
my_deck.add_note(genanki.Note(model=my_model, fields=[rxn1, reagents1]))
my_deck.add_note(genanki.Note(model=my_model, fields=[rxn2, reagents2]))

genanki.Package(my_deck).write_to_file("output.apkg")

results in an anki popup window that says:

Notes found in file: 3
Notes added from file: 3

[Added] [latex]
\schemestart
\chemfig{*6(--(<OH)-(<:Br)---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop[/latex], \(\ce{NaOH, H_2O_2}\)
[Added] [latex]
\schemestart
\chemfig{*6(--=---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop[/latex]
, \(\ce{mCPBA, CH_2Cl_2}\)
[Added] [latex]
\schemestart
\chemfig{C(-[:0]
    C(-[:90]X)(-[:0])(-[:270])
)(-[:90])(-[:180])(-[:270]H)}
\arrow{->[?]}
\chemfig{C(-[:120])(-[:-120])=C(-[:60])(-[:-60])} \+ \ce{HX}
\schemestop[/latex]
, \(\ce{Na^{+}{}^{-}OCH_2CH_3, EtOH, 70°C}\)

which looks fine.

And I set the appropriate latex header and enable dvisvgm:

\documentclass[varwidth=100cm]{standalone}
\usepackage[version=4]{mhchem}
\usepackage{chemfig}
\being{document}

However, when studying or browsing, for some reason the latex output of rxn0 and rxn1 gets messed up:

rxn0

[latex] \schemestart \chemfig{*6(--([?]} \chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)} \schemestop[/latex]

/tmp/anki_temp/tmp.tex:

\documentclass[varwidth=100cm]{standalone}
\usepackage[version=4]{mhchem}
\usepackage{chemfig}
\being{document}

\schemestart
\chemfig{*6(--([?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop
\end{document}

when it should be:

[latex]
{\Large Halohydrine $\to$ Epoxide}\\[12pt]
\schemestart
\chemfig{*6(--(<OH)-(<:Br)---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop[/latex]

/tmp/anki_temp/tmp.tex:

\documentclass[varwidth=100cm]{standalone}
\usepackage[version=4]{mhchem}
\usepackage{chemfig}
\being{document}

\schemestart
\chemfig{*6(--(<OH)-(<:Br)---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop
\end{document}

rxn1

[latex] \schemestart \chemfig{*6(--=---)} \arrow{->[?]} \chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)} \schemestop[/latex]

/tmp/anki_temp/tmp.tex:

\documentclass[varwidth=100cm]{standalone}
\usepackage[version=4]{mhchem}
\usepackage{chemfig}
\begin{document}

\schemestart
\chemfig{*6(--=---)}
\arrow{->[?]}
\chemfig{*6(--(},](<:H)---)}
\schemestop
\end{document}

instead of

[latex]
\schemestart
\chemfig{*6(--=---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop[/latex]

/tmp/anki_temp/tmp.tex:

\documentclass[varwidth=100cm]{standalone}
\usepackage[version=4]{mhchem}
\usepackage{chemfig}
\begin{document}

\schemestart
\chemfig{*6(--=---)}
\arrow{->[?]}
\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}
\schemestop
\end{document}

So basically,

\chemfig{*6(--(<OH)-(<:Br)---)}
\arrow{->[?]}

becomes

\chemfig{*6(--([?]}

and

\chemfig{*6(--(<[:30]{O}?)(<:H)-?[,{>},](<:H)---)}

becomes

\chemfig{*6(--(},](<:H)---)}

What's stranger is that I tested the python script several times and one time rxn1 did not have the issue. rxn2 has never been affected by this quirk. For some reason, chemfigs of epoxides get messed up by anki when importing a apkg generated by genanki.

[FEATURE REQUEST] Generate due date order

Currently when generating decks with genanki all the cards have the due date/order of 0. This can be seen when viewing the deck in the browser.

Would be great to auto-generate the due order within the code if possible or to be able to set the start so that it would start counting from the value given instead of zero.

This is particularly helpful when auto generating flashcards for a course where learning order makes it easier to learn.

Again, would be happy to do a pull request if given guidance on where to insert what in the relevant sections of the codebase.

Not packaging mp3 media

Firstly would like to thank you for making this @kerrickstaley ! My application is making Anki cards for children learning spellings, now that the schools are closing for COVID-19 in UK. I have audio files named after each word to be learned in the folder where my .py file is (using Pycharm).

When I package up and then import to Anki, I can't get the audio files to play unless I manually find the collection.media folder in the Anki2 appdata folder (on Win10). When I unzip the Anki package in 7Zip and open the media file, the only contents are {}, so I currently think this is a packaging issue.

My code is below. The whole thing works really well when I manually add the media files but from the readme.md section on adding media, it seems they should be packaged for import too. Thanks for any insight you can offer - this will help so many people if I can get it to work (making all the spelling lists automatically into Anki cards using Text to Speech and genanki)!


#read the file into a list of words
lines_list = open('file.txt').read().splitlines()

# declare the Deck and give it a name and unique ID number
my_deck = genanki.Deck(
  2759406110,
  'Test Deck')

# Declare the Model to be used (sets the format for the cards)
my_model = genanki.Model(
  1607792720,
  'Basic (type in the answer)',
  fields=[  # These fields need to match up with the field names used inside the `Template` section below
    {'name': 'Front'},
    {'name': 'Back'},
  ],
  templates=[  # {{type:Back}} is what prompts Anki to put the box in the card for text input for your answer. Anki compares and shows a "diff" against the real answer
    {
      'name': 'Card 1',
      'qfmt': '{{Front}} {{type:Back}}',  # Question Format?
      'afmt': '{{Front}}<hr id="answer">{{type:Back}}',  # Answer Format? `Frontside` can be used instead of 'Front' if you want to display the whole front as well as the back, but this can lead to repetition
    },
  ])

mediaList = []  # declare a list to hold the names of all our media files
for l in lines_list:
    mediaName = l + '.mp3'  # generate the file name for the audio file from the word in the list
    mediaList.append(l + '.mp3')  # append the name of each media file to the list
    soundName = '[sound:' + mediaName + ']'
    print(soundName)

    my_note = genanki.Note(
      model=my_model,
      fields=[soundName , l])

    my_deck.add_note(my_note)

print(mediaList)  # show the list for debug purposes

my_package = genanki.Package(my_deck)
my_package.media_files = mediaList # Contains the list of all our media files. May need to experiment with and without square braces here
#my_package.media_files = ['actual.mp3','bicycle.mp3','business.mp3']

genanki.Package(my_deck).write_to_file('test_output.apkg')

Can't load media in Anki 2.1.35

When creating a new deck with a set of new cards, running the line my_package.media_files = media_list, and importing the .apkg file to Anki the media names do appear in the cards fields, but neither the images are shown or the sound is being played, which seems to indicate that my_package.media_files is not doing its job (here is a sample code that supposedly should work that I also tried: https://gist.github.com/jlumbroso/e17abff02d89be04240072191af09ab2)

It took me a while to realize why my new Anki decks could not show the media files that I wanted to, until I ended up changing my_package.media_files = media_list with the following function, where media_path is the folder where Anki stores all the media (C:\Users\user\AppData\Roaming\Anki2\User 1\collection.media)

def move_media(media_list, media_path):
for file in media_list:
...destination = media_path + '\\' + os.path.basename(file)
...shutil.move(file, destination)

SQL injection attack vulnerability - please use prepared statements

I am making a toy example where I make the template for "afmt" be this string:

'afmt': {{FrontSide}}<hr id='answer'>{{Answer}}

However, using single quotes around answer notably gives me a syntax error, meaning this code does not use a prepared statement and hence is vulnerable to a SQL injection. Although I'm pretty sure the stakes here are low, it's an issue worth fixing, since any question or answer template that contains a single quote is rejected.

Thank you very much for making this repo! It's been really useful to me :)

How does this compare to the official anki library?

Since this project doesn't have the GitHub Discussions feature enabled, I thought I'd ask my question here.

The official Anki application is open-source and has classes for importing (https://github.com/ankitects/anki/tree/main/pylib/anki/importing) and exporting (https://github.com/ankitects/anki/blob/main/pylib/anki/exporting.py).

How does this compare? Are there any pros/cons for using one over the other?

From what I can see, genanki seems to have a more permissive licence and the API is documented. On the other hand, I would be concerned that since it's not an official library that the apkg files it generates could have compatibility issues with the official Anki applications.

Thanks!

Missing MyMedia as field

import genanki

my_model = genanki.Model(
  1091735104,
  'Simple Model with Media',
  fields=[
    {'name': 'Question'},
    {'name': 'Answer'},
  ],
  templates=[
    {
      'name': 'Card 1',
      'qfmt': '{{Question}}<br>{{MyMedia}}',
      'afmt': '{{FrontSide}}<hr id="answer">{{Answer}}',
    },
  ])

my_note = genanki.Note(
  model=my_model,
  fields=['Capital of Argentina', 'Buenos Aires'])

my_deck = genanki.Deck(
  2059400110,
  'Country Capitals')

my_deck.add_note(my_note)
genanki.Package(my_deck).write_to_file('output.apkg')

Produces a file, where the question on the card can not be displayed, because it needs {{MyMedia}}, but I didn't define {{MyMedia}} as a field.

Should there maybe be a check if all fields are present, or should all template items which have no corresponding field be replaced with an empty string?
As I'm currently working on a Rust port of genanki I am quite familiar with the codebase.
I would like to solve this issue, if you can tell me, whether this is intended or not, and if yes, where to insert a check in the codebase.

Why does genanki require both the model id and deck id to be hardcoded?

First of all, thank you for this awesome tool.

I have a few questions about the model id and deck id behavior. According the README, the model id must be randomly generated and then hardcoded into the source code:

You need to pass a model_id so that Anki can keep track of your model. It's important that you use a unique model_id for each Model you define. Use random.randrange(1 << 30, 1 << 31) to generate a suitable model_id, and hardcode it into your Model definition.

Same for the deck id:

Once again, you need a unique deck_id that you should generate once and then hardcode into your .py file.

After reading this, I have the following questions:

How do the model and deck ids work in Anki? Can the model id be unique per deck? What if my deck id collides with another deck already imported in my Anki profile?

Also, why does the id need to be hardcoded? Can the change the deck id change on future versions? What would happen in that case?

sort_field_index not released & what is sort_field doing?

Hi,

I wanted to use sort_field_index but it appears the feature has not been released yet. The latest release is from December 2020 but sort_field_index was implemented only 3 months ago. Can you release a new version or is there another (clean) way to make use of that feature?

Also, to me it is not clear what sort_field is expecting. Is it

  • n-th field to sort on, e.g. 1 for first field, 2 for second field
  • value to be sorted on, e.g. a card with sort_field=10 appears before a card with sort_field=11
  • the name of the field to be sorted on, e.g. when there is a field called Level, then sort_field="Level" will sort all cards according to the value of the Field Level
  • something else??

Thanks!

Best
René

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.