def convert_subdecks_to_tags(): """Main function to convert currently selected deck.""" parent_deck_id = mw.col.decks.selected() children_decks = mw.col.decks.children(parent_deck_id) mw.checkpoint(_("convert subdeck to tags")) for child_deck_name, child_deck_id in children_decks: # Reformat deck title into an appropriate tag tag = reformat_title(child_deck_name, SEPARATOR) # Get old card properties child_cids = mw.col.decks.cids(child_deck_id) mod = intTime() usn = mw.col.usn() str_cids = ids2str(child_cids) # Move cards to new deck if config option set if get_user_option("Merge decks", False): mw.col.db.execute( "update cards set usn=?, mod=?, did=? where id in " + str_cids, usn, mod, parent_deck_id) mw.col.decks.rem(child_deck_id) # New tag based on child deck name child_cards = (mw.col.getCard(cid) for cid in child_cids) child_nids = set(c.nid for c in child_cards) mw.col.tags.bulkAdd(list(child_nids), tag) mw.requireReset()
def open_or_switch_to_editor(function): aqt.dialogs.open("AddCards", mw) try: win = mw.app.activeWindow() if isinstance(win, aqt.addcards.AddCards): if isMac: win.raise_() else: win.showMaximized() else: win = aqt.dialogs._dialogs["AddCards"] if win: if isMac: win[1].raise_() else: win[1].showMaximized() except Exception as e: print("Failed to open.") print(e) if state.editor_is_ready: function() else: add_tmp_hook("editor-with-siac-initialised", lambda: function()) mw.requireReset()
def _onTreeTag2Deck(self, item): def tag2Deck(tag): did = mw.col.decks.id(tag) cids = self.findCards('"tag:%s"' % tag) if not cids: return mw.col.sched.remFromDyn(cids) mw.col.db.execute( "update cards set usn=?, mod=?, did=? where id in %s" % ids2str(cids), mw.col.usn(), intTime(), did) nids = self.findNotes('"tag:%s"' % tag) mw.col.tags.bulkRem(nids, tag) msg = _("Convert all tags to deck structure?") if not askUser(msg, parent=self, defaultno=True): return mw.progress.start(label=_("Converting tags to decks")) try: self.browser._lastSearchTxt = "" parent = unicodedata.normalize("NFC", item.fullname) tag2Deck(parent) for tag in mw.col.tags.all(): mw.progress.update(label=tag) if tag.startswith(parent + "::"): tag2Deck(tag) finally: mw.progress.finish() self._saveDecks() self._saveTags() # self.highlight('deck',item.fullname) mw.col.tags.registerNotes() mw.requireReset()
def check_card_for_extract(card): note = card.note() if note.model()["name"] == EXTRACT_MODEL and card.ord == 0: extract_widget.change_note(card.note(), set_original = True) extract_widget.enable() mw.requireReset()
def onResetCards(browser, isFullReset=False): cids = browser.selectedCards() if not cids: showInfo("No cards selected.") return if not askUser("Are you sure you wish to reset the selected cards?"): return mw.col.modSchema(check=True) mw.progress.start(immediate=True) if isFullReset: mw.col.db.execute("delete from revlog where cid in " + ids2str(cids)) # Reschedule cards for today and, when `isFullReset' is True, # reset `reps' and `lapses' counters. reschedCards(mw.col.sched, cids, isFullReset) mw.col.setMod() mw.col.save() mw.progress.finish() browser.model.reset() mw.requireReset() showInfo("Reset %d cards" % len(cids))
def start(self, delay=0): mw.requireReset(True) if ANKI21: mw.web.resetHandlers() mw.web.onBridgeCmd = lambda url: self._linkHandler(url) cmd = 'pycmd' else: mw.web.setLinkHandler(lambda url: self._linkHandler(url)) cmd = 'py.link' self.setUniqueMedia() img, au = self.get() Loots.start(self, delay) msg = '<br><i>( Click Image To Replay )</i>' if au else '' html = """<div id="intermission" style="display:none;"> <center><table><tr><td><h1>Intermission </h1></td> <td valign="bottom"><button id="resume" class="but " onclick="%s('refresh');return false;" autofocus> Resume Now</button></td></tr></table><br><br> <img src="%s" style="max-width:100%%" onclick="%s('replay');return false;" /> %s</center></div>""" % (cmd, img, cmd, msg) mw.web.stdHtml(html, css='' if ANKI21 else mw.sharedCSS) # mw.bottomWeb.hide() mw.web.setFocus()
def rename(editor, fname, type, field): mediafolder, fileabspath, base, ext = process_path(fname) if os.path.isfile(fileabspath): # verify newfilename = get_unused_new_name(mediafolder, base, ext) if newfilename: # reuse from "Image Editor" (307397307 from 2020-07-06) # that's more or less its replace_all_img_src ep = editor.parentWindow br = browser_parents() if ep in br: ep.model.beginReset() if type == "image": cnt = _replace_all_img_src(ep, fname, newfilename) elif type == "sound": cnt = _replace_all_sound_src(fname, newfilename) if anki_point_version <= 44: mw.requireReset() if ep in br: ep.model.endReset() notify_user(cnt, fname, newfilename) if not os.path.isfile(newfilename): os.rename(fname, newfilename) backup_changed_filenames(fname, newfilename) # update editor if type == "sound": searchstring = '[sound:' + fname + ']' replacestring = '[sound:' + newfilename + ']' replace_sound_in_editor_and_reload(editor, searchstring, replacestring, field) elif type == "image": replace_img_in_editor_and_reload(editor, fname, newfilename, "rename", field)
def onKDSG(ed, t): """ Initiate actions on notes for selected cards in browser. """ n = '%s' % t ed.editor.saveNow() runKDSG(ed, ed.selectedNotes(), t) mw.requireReset()
def update_utils_gui(self, nid, reading, pitch, target_reading, target_pitch, pitch_number): note = mw.col.getNote(nid) if self.ui.radioButton_Overwrite.isChecked(): note[target_reading] = reading note[target_pitch] = f"{pitch} ({pitch_number})" note.flush() mw.requireReset(reason=ResetReason.EditCurrentInit, context=self) mw.delayedMaybeReset()
def _onTreeTag(self, item, add=True): sel = self.browser.selectedNotes() tag = item.fullname self.browser.model.beginReset() if add: mw.col.tags.bulkAdd(sel, tag) else: mw.col.tags.bulkRem(sel, tag) self.browser.model.endReset() mw.requireReset()
def showMsg(): clearAudioQueue() m=random.choice(MELODY_LIST) m=os.path.join(SND_DIR,m) play(m) mw.requireReset(True) mw.bottomWeb.hide() mw.web.stdHtml(ASCII_ART, css=CSS) reset()
def update_all_enhanced_clozes_in_main_window(): mw.checkpoint("Update Enhanced Clozes") mw.progress.start() update_all_enhanced_clozes() mw.requireReset() mw.progress.finish() mw.reset() tooltip('Enhanced Clozed Updated!')
def replace_all_img_src(self, orig_name: str, new_name: str): # Only run if mw.col.backend.find_and_replace exist (2.1.27+) browser = aqt.dialogs._dialogs["Browser"][1] if browser: browser.model.beginReset() cnt = self._replace_all_img_src(orig_name, new_name) mw.requireReset() if browser: browser.model.endReset() tooltip(f"Images across {cnt} note(s) modified", parent=self.editor.widget)
def update_all_enhanced_clozes_in_browser(browser): mw.checkpoint("Update Enhanced Clozes") mw.progress.start() browser.model.beginReset() update_all_enhanced_clozes() browser.model.endReset() mw.requireReset() mw.progress.finish() mw.reset() tooltip('Enhanced Clozed Updated!')
def applyClozeFormat(browser, nids): mw = browser.mw mw.checkpoint("Note type change to cloze (reveal one)") mw.progress.start() browser.model.beginReset() for nid in nids: note = mw.col.getNote(nid) updateNote(note) note.flush() browser.model.endReset() mw.requireReset() mw.progress.finish() mw.reset()
def onLocalize(browser): nids = browser.selected_notes() if not nids: showInfo("Please select some notes.") return success = _localizeNids(browser, nids) browser.model.reset() mw.requireReset() if success: showInfo("Checked %d notes" % len(nids), parent=browser)
def saveNote(self, note): # self.layout.update() ret = note.dupeOrEmpty() if ret == 1: print "error" return elif ret == 2: print "duble" return cards = mw.col.addNote(note) if not cards: print "error" return mw.requireReset()
def update_all_enhanced_clozes_in_browser(self, evt=None): browser = self mw = browser.mw mw.checkpoint("Update Enhanced Clozes") mw.progress.start() browser.model.beginReset() update_all_enhanced_cloze(self) browser.model.endReset() mw.requireReset() mw.progress.finish() mw.reset()
def pomodoroTimer(): global pomodoros pomodoros += 1 if pomodoros == 4: pomodoros = 0 time = TEA_TIME msg = "You've Got Ketchup!" else: time = BREAK_TIME msg = random.choice(MESSAGES) mw.requireReset(True) mw.bottomWeb.hide() mw.web.stdHtml(TOMATO_ASCII % (msg, time), css=CSS) runHook('LifeDrain.recover', True, 9999)
def forgetCards(self, ids, _old): browConf=remem.conf.get("browser",{}) if not browConf.get("replace_brower_reschedule",False): return _old(self, ids) for i in range (2,5): #only wrap for browser calls try: f=sys._getframe(i) except ValueError: break if f.f_code.co_name==BROWSER_TAG: mw.requireReset() log=remem.conf.get("revlog_rescheduled",True) runHook('ReMemorize.forgetAll',ids,log) return return _old(self, ids) #called by bury card in reviewer
def _onTreeDeck2Tag(self, item): msg = _("Convert all notes in deck/subdecks to tags?") if not askUser(msg, parent=self, defaultno=True): return mw.progress.start(label=_("Converting decks to tags")) try: f = anki.find.Finder(mw.col) self.browser._lastSearchTxt = "" parentDid = mw.col.decks.byName(item.fullname)["id"] actv = mw.col.decks.children(parentDid) actv = sorted(actv, key=lambda t: t[0]) actv.insert(0, (item.fullname, parentDid)) found = False for name, did in actv: mw.progress.update(label=name) #add subdeck tree structure as tags nids = f.findNotes('''"deck:%s" -"deck:%s::*"''' % (name, name)) if nids: found = True tagName = re.sub(r"\s*(::)\s*", "\g<1>", name) tagName = re.sub(r"\s+", "_", tagName) tagName = unicodedata.normalize("NFC", tagName) mw.col.tags.bulkAdd(nids, tagName) #skip parent or dyn decks if did == parentDid or mw.col.decks.get(did)['dyn']: continue #collapse subdecks into one mw.col.sched.emptyDyn(None, "odid=%d" % did) mw.col.db.execute( "update cards set usn=?, mod=?, did=? where did=?", mw.col.usn(), intTime(), parentDid, did) mw.col.decks.rem(did, childrenToo=False) finally: mw.progress.finish() if not found: showInfo("No Cards in deck") return mw.col.decks.save() mw.col.decks.flush() mw.col.tags.save() mw.col.tags.flush() # self.highlight('tag',item.fullname) mw.col.tags.registerNotes() mw.requireReset()
def on_run_ocr(browser: Browser): selected_nids = browser.selectedNotes() num_notes = len(selected_nids) config = mw.addonManager.getConfig(__name__) if num_notes == 0: showInfo("No cards selected.") return elif askUser( f"Are you sure you wish to run OCR processing on {num_notes} notes?" ) is False: return if config.get("tesseract_install_valid") is not True and config.get( "text_output_location") == "new_field": showInfo( f"Note that because this addon changes the note template, you will see a warning about changing the database and uploading to AnkiWeb. \n" f"This is normal, and will be shown each time you modify a note template.\n" f"This message will be only be shown once.") mw.addonManager.writeConfig(__name__, config) config[ "tesseract_install_valid"] = True # Stop the above msg appearing multiple times progress = mw.progress ocr = OCR(col=mw.col, progress=progress, languages=config["languages"]) progress.start(immediate=True, min=0, max=num_notes) try: ocr.run_ocr_on_notes(note_ids=selected_nids, overwrite_existing=config["overwrite_existing"]) progress.finish() showInfo(f"Processed OCR for {num_notes} cards") except pytesseract.TesseractNotFoundError: progress.finish() showCritical( text=f"Could not find a valid Tesseract-OCR installation! \n" f"Please visit the addon page in at https://ankiweb.net/shared/info/450181164 for" f" install instructions") except Exception as errmsg: progress.finish() showCritical( f"Error encountered during processing, attempting to stop AnkiOCR gracefully. Error below:\n" f"{errmsg}") finally: browser.model.reset() mw.requireReset()
def reschedCards(self, ids, imin, imax, _old): browConf=remem.conf.get("browser",{}) if not browConf.get("replace_brower_reschedule",False): return _old(self, ids, imin, imax) for i in range (2,5): #only wrap for browser calls try: f=sys._getframe(i) except ValueError: break if f.f_code.co_name==BROWSER_TAG: mw.requireReset() log=remem.conf.get("revlog_rescheduled",True) fuzz=remem.conf.get("fuzz_days",True) #for load balance runHook('ReMemorize.rescheduleAll',ids,imin,imax,log,fuzz) return return _old(self, ids, imin, imax) #called by other addons in reviewer.
def on_CMdialog_finished(self, status): if status: content = maybe_minify(mw.col.cmhelper_field_content) else: # restore old content = self.original_cm_text try: note = mw.col.getNote(self.nid) except: # new note self.note.fields[self.original_current_field] = content.replace(unique_string, "") # self.note.flush() # doesn't work in 2.1.28 else: note.fields[self.original_current_field] = content note.flush() mw.requireReset() mw.reset() self.loadNote(focusTo=self.original_current_field)
def onFixHTML(browser): nids = browser.selectedNotes() if not nids: showInfo("Please select some notes.") return mw.checkpoint("Fix Invalid HTML") mw.progress.start(immediate=True) try: changed = _onFixHTML(browser, nids) finally: mw.progress.finish() browser.model.reset() mw.requireReset() showInfo("Updated %d/%d notes." % (changed, len(nids)), parent=browser)
def onLocalize(browser): nids = browser.selectedNotes() if not nids: showInfo("Please select some notes.") return mw.progress.start(immediate=True) success = False try: success = _localizeNids(browser, nids) finally: mw.progress.finish() browser.model.reset() mw.requireReset() if success: showInfo("Checked %d notes" % len(nids), parent=browser)
def add_ipa_transcription(self, result_dict: Dict[int, str]) -> None: """ Add IPA transcriptions to the target fields of all selected notes. :param result_dict: dictionary of Anki notes and their IPA transcriptions """ mw = self.browser.mw mw.checkpoint("add ipa transcription") mw.progress.start() self.browser.model.beginReset() for note_id, ipa_transcription in result_dict.items(): note = mw.col.getNote(note_id) target_field = self.field_combobox.currentText() note[target_field] = ipa_transcription note.flush() self.browser.model.endReset() mw.requireReset() mw.progress.finish() mw.reset()
def rtk_keywords(self): rev = mw.reviewer.card try: noteid = rev.nid except: showInfo("You must open the reviewer") return try: note = mw.col.getNote(noteid) except: showInfo("Couldn't find Note Info") return if note[self.focus_field]: keywords_res = self.query_rtk_list(note[self.focus_field]) note[self.target_rtk_field] = keywords_res note.flush() mw.requireReset(reason=ResetReason.EditCurrentInit, context=self) mw.delayedMaybeReset() else: showInfo(f"Nothing in the {self.focus_field} field")
def onRemoveHistory(browser): cids = browser.selectedCards() if not cids: showInfo("No cards selected.") return if not askUser("Are you sure you wish to remove the review history of the selected cards?"): return mw.col.modSchema(check=True) mw.progress.start(immediate=True) mw.col.db.execute("delete from revlog where cid in " + ids2str(cids)) mw.col.setMod() mw.col.save() mw.progress.finish() browser.model.reset() mw.requireReset() showInfo("Removed history of %d cards" % len(cids))
def on_rm_ocr_fields(browser: Browser): config = mw.addonManager.getConfig(__name__) selected_nids = browser.selectedNotes() num_notes = len(selected_nids) if num_notes == 0: showInfo("No cards selected.") return elif askUser(f"Are you sure you wish to remove the OCR field from {num_notes} notes?") is False: return progress = mw.progress progress.start(immediate=True) ocr = OCR(col=mw.col, progress=progress, languages=config["languages"]) ocr.remove_ocr_on_notes(note_ids=selected_nids) mw.progress.finish() browser.model.reset() mw.requireReset() log_messages = logger.handlers[0].flush() showInfo(f"Removed the OCR field from {num_notes} cards\n" f"{log_messages}")
def onRegenGlosses( ed ): n = "Regenerate Glosses" ed.editor.saveNow() regenGlosses(ed, ed.selectedNotes() ) mw.requireReset()