Switched to new models for notes in order to use Anki feature of preventing
authorOleksandr Gavenko <gavenkoa@gmail.com>
Sat, 12 Nov 2016 13:55:08 +0200
changeset 677 e330e7f195b7
parent 676 e3266e096360
child 678 28e04408c0c0
Switched to new models for notes in order to use Anki feature of preventing showing related card on same day. But I decided to separate plural and irregular verb forms from main articles...
py/gadict_srs_anki.py
--- a/py/gadict_srs_anki.py	Sat Nov 12 12:39:02 2016 +0200
+++ b/py/gadict_srs_anki.py	Sat Nov 12 13:55:08 2016 +0200
@@ -125,20 +125,7 @@
 from anki.exporting import AnkiPackageExporter
 
 
-class AnkiDbBuilder:
-
-    def __init__(self, tmpdir, name):
-        self.tmpdir = tmpdir
-        self.name = name
-
-        self.collection = collection = anki.Collection(os.path.join(self.tmpdir, 'collection.anki2'))
-
-        deck_id = collection.decks.id(self.name + "_deck")
-        deck = collection.decks.get(deck_id)
-
-        model = collection.models.new(self.name + "_model")
-        model['did'] = deck_id
-        model['css'] = """
+MODEL_CSS = """
 .card {
   font-family: arial;
   font-size: 20px;
@@ -205,41 +192,172 @@
 }
 """
 
-        collection.models.addField(model, collection.models.newField('From'))
-        collection.models.addField(model, collection.models.newField('To'))
+def note_add_tags(note, tags):
+    if isinstance(tags, str):       note.tags = [tags]
+    elif isinstance(tags, list):    note.tags = tags
+    elif tags is None:              pass
+    else:                           raise Exception('Expecting string or list of tags...')
+
+
+class AnkiDbBuilder:
+
+    def __init__(self, tmpdir, name):
+        self.tmpdir = tmpdir
+        self.name = name
+
+        self.collection = collection = anki.Collection(os.path.join(self.tmpdir, 'collection.anki2'))
+
+        deck_id = collection.decks.id(self.name)
+        deck = collection.decks.get(deck_id)
+
+        # It is essential to keep model['id'] unchanged between upgrades!!
+        MODEL_ID = int(hashlib.sha1(self.name).hexdigest(), 16) % (2**63)
+
+        ################################################################
+        # Regular card model. SafeBack doesn't include examples to not spoil
+        # word spelling.
+        model = collection.models.new(self.name + "_frontback")
+        model['did'] = deck_id
+        model['css'] = MODEL_CSS
+
+        collection.models.addField(model, collection.models.newField('Front'))
+        collection.models.addField(model, collection.models.newField('Back'))
+        collection.models.addField(model, collection.models.newField('SafeBack'))
+
+        tmpl = collection.models.newTemplate('Front -> Back')
+        tmpl['qfmt'] = '<div class="front">{{Front}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
 
-        tmpl = collection.models.newTemplate('From -> To')
-        tmpl['qfmt'] = '<div class="from">{{From}}</div>'
-        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="to">{{To}}</div>'
+        tmpl = collection.models.newTemplate('SafeBack -> Front')
+        tmpl['qfmt'] = '<div class="safe-back">{{SafeBack}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="front">{{Front}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        # Equivalent of ``collection.models.add(model)`` without setting
+        # auto-generated ID.
+        # Increment +1 is for keeping model['id'] unique from previous v0.9 release.
+        model['id'] = MODEL_ID + 1
+        collection.models.update(model)
+        collection.models.save(model)
+        self.model = model
+        # collection.models.setCurrent(model)
+
+        if not RICH_MODE:
+            return
+
+        ################################################################
+        # Model for irregular verbs.
+        model = collection.models.new(self.name + "_irrverb")
+        model['did'] = deck_id
+        model['css'] = MODEL_CSS
+
+        collection.models.addField(model, collection.models.newField('V1'))
+        collection.models.addField(model, collection.models.newField('V2'))
+        collection.models.addField(model, collection.models.newField('V3'))
+        collection.models.addField(model, collection.models.newField('V2alt'))
+        collection.models.addField(model, collection.models.newField('V3alt'))
+        collection.models.addField(model, collection.models.newField('Front'))
+        collection.models.addField(model, collection.models.newField('Back'))
+
+        question = u"<div class='ask'>Find irregular verb:</div>"
+
+        tmpl = collection.models.newTemplate('V1 -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{V1}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        tmpl = collection.models.newTemplate('V2 -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{V2}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
         collection.models.addTemplate(model, tmpl)
 
-        # Equivalent of:
-        #   collection.models.add(model)
-        # without setting auto-generated ID. It is essential to keep model['id']
-        # unchanged between upgrades or notes will be skipped!!
-        model['id'] = int(hashlib.sha1(self.name).hexdigest(), 16) % (2**63)
+        tmpl = collection.models.newTemplate('V3 -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{V3}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        tmpl = collection.models.newTemplate('V2alt -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{V2alt}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        tmpl = collection.models.newTemplate('V3alt -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{V3alt}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        model['id'] = MODEL_ID + 2          # Keep model['id'] unique.
         collection.models.update(model)
-        collection.models.setCurrent(model)
         collection.models.save(model)
+        self.model_irr = model
+
+        ################################################################
+        # Model for irregular plurals.
+        model = collection.models.new(self.name + "_plural")
+        model['did'] = deck_id
+        model['css'] = MODEL_CSS
+
+        collection.models.addField(model, collection.models.newField('Singular'))
+        collection.models.addField(model, collection.models.newField('Plural'))
+        collection.models.addField(model, collection.models.newField('Front'))
+        collection.models.addField(model, collection.models.newField('Back'))
+
+        question = u"<div class='ask'>Find singular/plural form:</div>"
 
-    def guid(self, type_, headword):
+        tmpl = collection.models.newTemplate('Singular -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{Singular}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        tmpl = collection.models.newTemplate('Plural -> Back')
+        tmpl['qfmt'] = question + '<div class="front">{{Plural}}</div>'
+        tmpl['afmt'] = '{{FrontSide}}<hr id=answer><div class="back">{{Front}}</div><div class="back">{{Back}}</div>'
+        collection.models.addTemplate(model, tmpl)
+
+        model['id'] = MODEL_ID + 3          # Keep model['id'] unique.
+        collection.models.update(model)
+        collection.models.save(model)
+        self.model_pl = model
+
+
+    def guid(self, nodetype, headword):
         """
-        :type_ used to generate different notes from same headword
+        :nodetype  used to generate different notes from same headword
         """
-        h = hashlib.md5(":".join((self.name, type_, headword)))
+        h = hashlib.md5(":".join((self.name, nodetype, headword)))
         return h.hexdigest()
 
-    def add_note(self, type_, id_, from_, to_, tags_ = None):
-        note = self.collection.newNote()
-        note['From'] = from_
-        # print(from_)
-        note['To'] = to_
-        # print(to_)
-        if isinstance(tags_, str):      note.tags = [tags_]
-        elif isinstance(tags_, list):   note.tags = tags_
-        elif tags_ is None:             pass
-        else:                           raise Exception('Expect string or list of tags...')
-        note.guid = self.guid(type_, id_)
+    def add_note(self, headword, front, back, safeback, tags = None):
+        note = anki.notes.Note(self.collection, self.model)
+        note['Front'] = front
+        note['Back'] = back
+        note['SafeBack'] = safeback
+        note_add_tags(note, tags)
+        note.guid = self.guid("front/back", headword)
+        self.collection.addNote(note)
+
+    def add_note_irr(self, headword, v1, v2, v2alt, v3, v3alt, front, back, tags = None):
+        note = anki.notes.Note(self.collection, self.model_irr)
+        note['V1'] = v1
+        note['V2'] = v2
+        note['V3'] = v3
+        note['V2alt'] = v2alt
+        note['V3alt'] = v3alt
+        note['Front'] = front
+        note['Back'] = back
+        note_add_tags(note, tags)
+        note.guid = self.guid("irregular verb", headword)
+        self.collection.addNote(note)
+
+    def add_note_pl(self, headword, singular, plural, front, back, tags = None):
+        note = anki.notes.Note(self.collection, self.model_pl)
+        note['Singular'] = singular
+        note['Plural'] = plural
+        note['Front'] = front
+        note['Back'] = back
+        note_add_tags(note, tags)
+        note.guid = self.guid("singular/plural noun", headword)
         self.collection.addNote(note)
 
     def export(self, fname):
@@ -317,13 +435,9 @@
     for identity in FDEL or []:
         identity = identity.strip()
         warnmsg = "<div class='del'>Please delete this note ({})</div>".format(identity)
-        builder.add_note("en->tr", identity, warnmsg, warnmsg+" en->tr", "del")
-        builder.add_note("tr->en", identity, warnmsg, warnmsg+" tr->en", "del")
-        builder.add_note("irregular1", identity, warnmsg, warnmsg+" irregular1", "del")
-        builder.add_note("irregular2", identity, warnmsg, warnmsg+" irregular2", "del")
-        builder.add_note("irregular3", identity, warnmsg, warnmsg+" irregular3", "del")
-        builder.add_note("singular", identity, warnmsg, warnmsg+" singular", "del")
-        builder.add_note("plural", identity, warnmsg, warnmsg+" plural", "del")
+        builder.add_note(identity, warnmsg, warnmsg, warnmsg, "del")
+        builder.add_note_irr(identity, warnmsg, warnmsg, warnmsg, warnmsg, warnmsg, warnmsg, warnmsg, "del")
+        builder.add_note_pl(identity, warnmsg, warnmsg, warnmsg, warnmsg, "del")
 
     for (headwords, translations) in DOM[1:]:
         identity = headwords[0].headword
@@ -338,7 +452,7 @@
             freqmsg = ",".join(freqtags)
             freqmsg = "<div class='freq'>{:s}</div>".format(freqmsg)
         buf = []
-        v1, v2, v3 = (None, None, None)
+        v1, v2, v3, v2alt, v3alt = (None, None, None, None, None)
         singular, plural = (None, None)
         for hw in headwords:
             buf.append("<div clsas='headword'>")
@@ -358,9 +472,15 @@
             if 'v1' in hw.attrs:
                 v1 = (hw.headword, hw.pron)
             if 'v2' in hw.attrs:
-                v2 = (hw.headword, hw.pron)
+                if v2:
+                    v2alt = (hw.headword, hw.pron)
+                else:
+                    v2 = (hw.headword, hw.pron)
             if 'v3' in hw.attrs:
-                v3 = (hw.headword, hw.pron)
+                if v3:
+                    v3alt = (hw.headword, hw.pron)
+                else:
+                    v3 = (hw.headword, hw.pron)
             if 's' in hw.attrs:
                 singular = (hw.headword, hw.pron)
             if 'pl' in hw.attrs:
@@ -375,24 +495,24 @@
         for sense in translations:
             write_sense(buf, sense, with_examples = False)
         reverse_from = "".join(buf)         # without examples!!
-        builder.add_note("en->tr", identity, direct_from + freqmsg, direct_to)
-        builder.add_note("tr->en", identity, reverse_from, direct_from + freqmsg)
+        builder.add_note(identity, direct_from, direct_to, reverse_from)
         if v1 and v2 and v3 and RICH_MODE:
-            question = u"<div class='ask'>Find irregular verb:</div>"
             riddle1 = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>v1</span>".format(v1[0], v1[1])
             riddle2 = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>v2</span>".format(v2[0], v2[1])
             riddle3 = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>v3</span>".format(v3[0], v3[1])
-            answer = direct_from + direct_to
-            builder.add_note("irregular1", identity, question + riddle1 + freqmsg, answer)
-            builder.add_note("irregular2", identity, question + riddle2 + freqmsg, answer)
-            builder.add_note("irregular3", identity, question + riddle3 + freqmsg, answer)
+            if v2alt:
+                riddle2alt = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>v2</span>".format(v2alt[0], v2alt[1])
+            else:
+                riddle2alt = ""
+            if v3alt:
+                riddle3alt = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>v2</span>".format(v3alt[0], v3alt[1])
+            else:
+                riddle3alt = ""
+            builder.add_note_irr(identity, riddle1 + freqmsg, riddle2 + freqmsg, riddle2alt, riddle3 + freqmsg, riddle3alt, direct_from, direct_to)
         if singular and plural and RICH_MODE:
-            question = u"<div class='ask'>Find plural:</div>"
             riddle_s = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>s</span>".format(singular[0], singular[1])
             riddle_pl = u"<span class='headword'>{}</span> <span class='pron'>[{}]</span> <span class='attrs'>pl</span>".format(plural[0], plural[1])
-            answer = direct_from + direct_to
-            builder.add_note("singular", identity, question + riddle_s + freqmsg, answer)
-            builder.add_note("plural", identity, question + riddle_pl + freqmsg, answer)
+            builder.add_note_pl(identity, riddle_s + freqmsg, riddle_pl + freqmsg, direct_from, direct_to)
 
     builder.export(FONAME)
 finally: