def get_anki_model(): with open(conf.get("Anki", "front"), 'r') as f: front_template = f.read() with open(conf.get("Anki", 'back'), 'r') as f: back_template = f.read() with open(conf.get("Anki", 'css'), 'r') as f: css = f.read() anki_model = Model( model_id=1048217874, name="LeetCode", fields=[ {"name": "ID"}, {"name": "Title"}, {"name": "TitleSlug"}, {"name": "Difficulty"}, {"name": "Description"}, {"name": "Tags"}, {"name": "TagSlugs"}, {"name": "Solution"}, {"name": "Submission"} ], templates=[ { "name": "LeetCode", "qfmt": front_template, "afmt": back_template } ], css=css ) return anki_model
def hanzi_english_model(deck_name): zh_front = open('assets/zh_front.html', 'r').read() zh_back = open('assets/zh_back.html', 'r').read() en_front = open('assets/en_front.html', 'r').read() en_back = open('assets/en_back.html', 'r').read() css = open('assets/styles.css', 'r').read() return Model( 1607392319, 'Hanzi <-> English', fields=[ {'name': 'Hanzi'}, {'name': 'Pinyin'}, {'name': 'English'}, {'name': 'Audio'}, ], css=css, templates=[ { 'name': 'Hanzi -> English', 'qfmt': zh_front, 'afmt': zh_back, }, { 'name': 'English -> Hanzi', 'qfmt': en_front, 'afmt': en_back, }, ])
def basic_model(id, name, css): return Model( id, name, fields=[ { "name": "Front" }, { "name": "Back" }, { "name": "MyMedia" }, ], templates=[{ "name": "card1", "qfmt": '<span class="front-text-pre">{{Front}}</span>', "afmt": '<span class="front-text-post">{{Front}}</span>' '<hr id="answer">' '<span class="back-text">{{Back}}</span>', }], css=css, )
def input_model(id, name, css, qfmt, afmt): if qfmt is None: qfmt = DEFAULT_INPUT_FRONT if afmt is None: afmt = DEFAULT_INPUT_BACK return Model( id, name, fields=[ { "name": "Front" }, { "name": "Back" }, { "name": "Input" }, { "name": "MyMedia" }, ], templates=[{ "name": name, "qfmt": qfmt, "afmt": afmt, }], css=css, )
def cloze_model(id, name, css): return Model( id, name, fields=[ { "name": "Text" }, { "name": "Extra" }, { "name": "MyMedia" }, ], templates=[ { "name": "notion2Anki Cloze Card", "qfmt": '<span class="front-text-pre">{{cloze:Text}}</span>', "afmt": '<span class="front-text-pre">{{cloze:Text}}</span><br><span class="extra">{{Extra}}</span>', }, ], css=css, model_type=Model.CLOZE, )
def input_model(id, name, css): return Model( id, name, fields=[ { "name": "Front" }, { "name": "Back" }, { "name": "Input" }, { "name": "MyMedia" }, ], templates=[{ "name": "notion2anki-input-card", "qfmt": "{{Front}}" "<br>" "{{type:Input}}", "afmt": "{{FrontSide}}" '<hr id="answer">' "{{Back}}", }], css=css, )
def get_anki_model(config): cfg_path = Path(config) if not cfg_path.exists(): raise Exception( "Anki model configuration does not exist: {cfg_path}".format( cfg_path=cfg_path)) with cfg_path.open(mode="r", encoding="utf-8") as f: cfg = json.load(f) model_id = cfg['id'] name = cfg['name'] fields = [{'name': f} for f in cfg['fields']] model_type = Model.CLOZE if cfg['type'] == 'cloze' else Model.FRONT_BACK stylesheet = Path(PurePath.joinpath(cfg_path.parent, cfg['styles'])) if not stylesheet.exists(): raise Exception( "Anki model stylesheet does not exist: {stylesheet}".format( stylesheet=stylesheet)) with stylesheet.open(mode="r", encoding="utf-8") as f: css = f.read() templates = [] for t in cfg['templates']: n = t['name'] q = Path(PurePath.joinpath(cfg_path.parent, t['qfmt'])) if not q.exists(): raise Exception( "Missing qfmt template in Anki model '{name}', card '{card}': {qfmt}" .format(name=name, card=n, qfmt=q)) with q.open(mode="r", encoding="utf-8") as f: qfmt = f.read() a = Path(PurePath.joinpath(cfg_path.parent, t['afmt'])) if not a.exists(): raise Exception( "Missing afmt template in Anki model '{name}', card '{card}': {afmt}" .format(name=name, card=n, afmt=a)) with a.open(mode="r", encoding="utf-8") as f: afmt = f.read() templates.append({'name': n, 'qfmt': qfmt, 'afmt': afmt}) return Model(model_id=model_id, name=name, fields=fields, templates=templates, css=css, model_type=model_type)
def input_model(id, name, css, qfmt, afmt): if qfmt is None: qfmt = DEFAULT_INPUT.get("front") if afmt is None: afmt = DEFAULT_INPUT.get("back") return Model( id, name, fields=DEFAULT_INPUT.get("fields"), templates=[{ "name": name, "qfmt": qfmt, "afmt": afmt, }], css=css, )
def basic_model(id, name, css, qfmt, afmt): if qfmt is None: qfmt = DEFAULT_BASIC.get('front') if afmt is None: afmt = DEFAULT_BASIC.get('back') return Model( id, name, fields=DEFAULT_BASIC.get("fields"), templates=[{ "name": name, "qfmt": qfmt, "afmt": afmt, }], css=css, )
def cloze_model(id, name, css, qfmt, afmt): if qfmt is None: qfmt = DEFAULT_CLOZE.get('front') if afmt is None: afmt = DEFAULT_CLOZE.get('back') return Model( id, name, fields=DEFAULT_CLOZE.get("fields"), templates=[ { "name": name, "qfmt": qfmt, "afmt": afmt, }, ], css=css, model_type=Model.CLOZE, )
def get_model() -> Model: return Model( KOREAN_NOTE_MODEL_ID, model_name, fields=[ { "name": "Korean" }, { "name": "English" }, { "name": "Hanja" }, { "name": "Sound" }, { "name": "Silhouette" }, { "name": "Comment" }, ], templates=[ { "name": "Recognition", "qfmt": recognition_front, "afmt": recognition_back, }, { "name": "Recall", "qfmt": recall_front, "afmt": recall_back }, ], css=style, )
def cloze_model(id, name, css, qfmt, afmt): if qfmt is None: qfmt = DEFAULT_CLOZE_FRONT if afmt is None: afmt = DEFAULT_CLOZE_BACK return Model( id, name, fields=[ {"name": "Text"}, {"name": "Extra"}, {"name": "MyMedia"}, ], templates=[ { "name": name, "qfmt": qfmt, "afmt": afmt, }, ], css=css, model_type=Model.CLOZE, )
color: blue; } .nightMode .cloze { color: lightblue; } """ MY_CLOZE_MODEL = Model(998877661, 'My Cloze Model', fields=[ { 'name': 'Text' }, { 'name': 'Extra' }, ], templates=[ { 'name': 'My Cloze Card', 'qfmt': '{{cloze:Text}}', 'afmt': '{{cloze:Text}}<br>{{Extra}}', }, ], css=CSS, model_type=Model.CLOZE) notes = [] #begin webdriver driver = webdriver.Chrome(executable_path="./chromedriver.exe") #??
MY_CLOZE_MODEL = Model( 998877661, "notion2Anki Cloze Model", fields=[ { "name": "Context" }, { "name": "Text" }, { "name": "Extra" }, { "name": "MyMedia" }, ], templates=[ { "name": "notion2Anki Cloze Card", "qfmt": '<span class="context-title">{{Context}}</span><br><span class="front-text-pre">{{cloze:Text}}</span>', "afmt": '<span class="front-text-pre">{{cloze:Text}}</span><br><span class="extra">{{Extra}}</span>', }, ], css=CLOZE_STYLE + "\n" + CSS, model_type=Model.CLOZE, )
""" with open(deck_style, 'r', encoding='utf-8') as file: CSS += file.read() MY_CLOZE_MODEL = Model(998877661, 'notion2Anki Cloze Model', fields=[ { 'name': 'Text' }, { 'name': 'Extra' }, { 'name': 'MyMedia' }, ], templates=[ { 'name': 'notion2Anki Cloze Card', 'qfmt': '{{cloze:Text}}', 'afmt': '{{cloze:Text}}<br>{{Extra}}', }, ], css=CLOZE_STYLE + '\n' + CSS, model_type=Model.CLOZE) BASIC_MODEL = Model(2020, 'notion2anki', fields=[ {
} .nightMode .cloze { color: lightblue; } """ MY_CLOZE_MODEL = Model(998877661, 'My Cloze Model', fields=[ { 'name': 'Text' }, { 'name': 'Extra' }, ], templates=[ { 'name': 'My Cloze Card', 'qfmt': '{{cloze:Text}}', 'afmt': '{{cloze:Text}}<br>{{Extra}}', }, ], css=CSS, model_type=Model.CLOZE) # This doesn't seem to be very useful but Anki supports it and so do we *shrug* MULTI_FIELD_CLOZE_MODEL = Model( 1047194615, 'Multi Field Cloze Model', fields=[
def create_anki_deck(text, deckname=None, filename=None): from genanki import Model, Note, Deck, Package # This is mostly hobbled together from the tests for genanki CSS = """.card { font-family: arial; font-size: 20px; text-align: center; color: black; background-color: white; } .cloze { font-weight: bold; color: blue; } .nightMode .cloze { color: lightblue; } """ MY_CLOZE_MODEL = Model( 998877661, "Nlaco Cloze Model", fields=[{"name": "Text"}, {"name": "Extra"},], templates=[ { "name": "Nlaco Cloze Card", "qfmt": "{{cloze:Text}}", "afmt": "{{cloze:Text}}<br>{{Extra}}", }, ], css=CSS, model_type=Model.CLOZE, ) name_uuid = uuid4() for overlap in range(1, 4): notes = [ Note(model=MY_CLOZE_MODEL, fields=(p, "")) for p in get_card_contents(text, phrases_per_cloze=overlap) ] for n in notes: assert ( n.cards ), f"No cards in note {n}, this will cause your Anki DB to break!" if deckname is None: _deckname = f"nlaco-overlap-{overlap}--" + str(name_uuid) else: raise NotImplementedError("Custom decknames are not supported yet :(") # % 500000 to make sure the int can fit into an SQL database. TODO see # whether this is random enough to make sure there are no collisions. deck = Deck(deck_id=name_uuid.int % 500000, name=_deckname) for note in notes: deck.add_note(note) if filename is None: Package(deck).write_to_file(f"{_deckname}.apkg") else: raise NotImplementedError("Custom filenames are not supported yet :(")