# wanikani2anki, import unlocked Kanji and Vocab from WaniKani to a
# deck in desktop Anki 2.0.x. place this file in your desktop Anki 2
# addons folder.
# from https://github.com/nigelkerr/wanikani2anki and in the public
# domain, with no sort of warranty whatsoever.
from aqt import mw
from aqt.utils import showInfo
from aqt.qt import *
from anki.importing.noteimp import NoteImporter, ForeignNote
import wanikaniforms as forms
import re
import urllib2
import json
import sys
WANIKANI_API_KEY = '7cabb1e2050da36761ad124d447ad5e0'
KANJI_URL = 'https://www.wanikani.com/api/v1.1/user/{}/kanji'
VOCAB_URL = 'https://www.wanikani.com/api/v1.1/user/{}/vocabulary'
KANJI_DECK = "WaniKani Kanji"
VOCAB_DECK = "WaniKani Vocab"
KANJI_MODEL = "WaniKani Kanji Model"
VOCAB_MODEL = "WaniKani Vocab Model"
wkconf = { 'key': '', 'deck_separation': 'bothSeparately', 'card_direction': 'wanikaniDirection', 'include_tangorin_link': False }
class WaniKaniImporter(NoteImporter):
def __init__(self, *args):
NoteImporter.__init__(self, *args)
self.allowHTML = True # see NoteImporter
def foreignNotes(self):
notes = []
for item in self.correctPart(): # json structures different
if item[u'stats']:
note = self.noteFromJson(item)
notes.append(note)
return notes
def correctPart(self):
return self.file[u'requested_information']
def noteFromJson(self,jsonDict):
return None
class KanjiImporter(WaniKaniImporter):
def __init(self, *args):
WaniKaniImporter.__init(self, *args)
def fields(self):
return 5 # see NoteImporter
def noteFromJson(self,jsonDict):
note = ForeignNote()
note.fields.append(jsonDict[u'character'])
onyomi = jsonDict[u'onyomi'] if jsonDict[u'onyomi'] else u'none'
kunyomi = jsonDict[u'kunyomi'] if jsonDict[u'kunyomi'] else u'none'
if jsonDict[u'important_reading'] == u'onyomi':
note.fields.append(onyomi)
else:
note.fields.append(kunyomi)
note.fields.append(onyomi)
note.fields.append(kunyomi)
note.fields.append(jsonDict[u'meaning'])
note.tags.append("wk{0:s}".format(str(jsonDict[u'level'])))
return note
class VocabImporter(WaniKaniImporter):
def __init(self, *args):
WaniKaniImporter.__init(self, *args)
def fields(self):
return 3 # see NoteImporter
def correctPart(self):
return self.file[u'requested_information'][u'general']
def noteFromJson(self, jsonDict):
note = ForeignNote()
note.fields.append(jsonDict[u'character'])
note.fields.append(jsonDict[u'kana'])
note.fields.append(jsonDict[u'meaning'])
note.tags.append("wk{0:s}".format(str(jsonDict[u'level'])))
return note
def getjsonbolus(url):
parsed = None
try:
response = urllib2.urlopen(url)
data = response.read()
parsed = json.loads(data)
except Exception as e:
showInfo('Something unfortunate happened trying to contact WaniKani, as below, please try again later. {}'.format(e))
return parsed
def getvocab():
return getjsonbolus(VOCAB_URL.format(wkconf['key']))
def getkanji():
return getjsonbolus(KANJI_URL.format(wkconf['key']))
def showApiKey():
if WANIKANI_API_KEY and re.match('^[a-f0-9]{32}$', WANIKANI_API_KEY):
showInfo('WaniKani API Key: {}'.format(WANIKANI_API_KEY))
else:
showInfo('WaniKani API Key not defined!')
def updateWaniKaniDeck():
kanjiJson = None
vocabJson = None
if wkconf['deck_separation'] != 'vocabOnly':
kanjiJson = getkanji()
if wkconf['deck_separation'] != 'kanjiOnly':
vocabJson = getvocab()
if not kanjiJson and not vocabJson:
showInfo("WaniKani didn't respond to either request, not updating anything.")
return
mm = mw.col.models
tangorin = ""
if wkconf['include_tangorin_link']:
tangorin = "
Tangorin"
if kanjiJson:
wk_model = mm.byName(KANJI_MODEL)
if not wk_model:
wk_model = mm.new(KANJI_MODEL)
mm.addField(wk_model, mm.newField("Kanji"))
mm.addField(wk_model, mm.newField("Reading"))
mm.addField(wk_model, mm.newField("Onyomi"))
mm.addField(wk_model, mm.newField("Kunyomi"))
mm.addField(wk_model, mm.newField("Meaning"))
if wkconf['card_direction'] != 'reverseDirection':
tmpl = mm.newTemplate("WaniKani Kanji Meaning")
tmpl['qfmt'] = "{{Kanji}}
What is the meaning?"
tmpl['afmt'] = "{{FrontSide}}\n\n