def _sync_anki(col_path, anki_hkey): try: col = Collection(col_path) server = RemoteServer(anki_hkey) client = FullSyncer(col, anki_hkey, server.client) client.download() col = Collection(col_path) # reload collection media_server = RemoteMediaServer(col, anki_hkey, server.client) media_client = MediaSyncer(col, media_server) media_client.sync() col.close(save=True) except: return traceback.format_exc()
def viadb(front,back): # Define the path to the Anki SQLite collection PROFILE_HOME = os.path.expanduser("~/Documents/Anki/User 1/") cpath = os.path.join(PROFILE_HOME, "collection.anki2") thispath= os.path.dirname(os.path.abspath(__file__)) # Load Anki library sys.path.append(thispath + "/anki") from anki.storage import Collection # Load the Collection col = Collection(cpath, log=True) # Entry point to the API # get the deck we add all cards to deck = col.decks.byName("Default") # make a new note note = col.newNote() note.model()['did'] = deck['id'] # add values to the note note.fields[0] = front note.fields[1] = back # import anki.models # [ x['name'] for x in note.model()['flds'] ] # 'Front', 'Back' # save the note res=col.addNote(note) #print(res) col.save() # maybe autosave?
def update_anki_deck(deck_name, new_cards): # Load Anki library # Define the path to the Anki SQLite collection PROFILE_HOME = os.path.expanduser( "~/Library/Application Support/Anki2/User 1") cpath = os.path.join(PROFILE_HOME, "collection.anki2") col = Collection(cpath, log=True) # Load existing cards existing_cards = {} for card_id in col.findCards("deck:'" + deck_name + "'"): card = col.getCard(card_id) note = card.note() existing_cards[note['Front']] = dict( Id=card_id, Front=note['Front'], Back=note['Back'], Tags=" ".join(sorted(note.stringTags().strip().split(' ')))) # Set the model modelBasic = col.models.byName('Basic') col.decks.current()['mid'] = modelBasic['id'] # Get the deck deck = col.decks.byName(deck_name) for card in new_cards: if card['Front'] in existing_cards: existing_card = existing_cards[card['Front']] if existing_card['Back'] != card['Back'] or existing_card[ 'Tags'] != card['Tags']: print("Replacing the card", card['Front']) col.remCards([]) else: continue print("Adding a new card:", card['Front'], "-", card['Back']) # Instantiate the new note note = col.newNote() note.model()['did'] = deck['id'] # Set the content note.fields[0] = card['Front'] note.fields[1] = card['Back'] # Set the tags (and add the new ones to the deck configuration note.tags = col.tags.canonify(col.tags.split(card['Tags'])) m = note.model() m['tags'] = note.tags col.models.save(m) # Add the note col.addNote(note) # Save the changes to DB col.save()
def CreateSingleCard(image, sentence): # def CreateSingleCard(noteList): # Find the Anki directory anki_home = r'C:\Users\Linus\AppData\Roaming\Anki2\User 1' anki_collection_path = os.path.join(anki_home, "collection.anki2") # 1. Load the anki collection col = Collection(anki_collection_path, log=True) # 2. Select the deck # Find the model to use (Basic, Basic with reversed, ...) #trying this ###trying this modelBasic = col.models.byName('2. Picture Words') # Set the deck deck = col.decks.byName('Espanol') col.decks.select(deck['id']) col.decks.current()['mid'] = modelBasic['id'] # 3. Create a new card note = col.newNote() note.fields[0] = sentence # The Front input field in the U ###has to be in collection.models (AppData/Roaming) # note.fields[1] = '<img src="{0}.jpg">'.format(image) # The Back input field in the UI note.fields[1] = image col.addNote(note) # 4. Save changes col.close() print('Card created: ', sentence)
def _loadCollection(self) -> bool: cpath = self.pm.collectionPath() self.col = Collection(cpath, backend=self.backend) self.setEnabled(True) self.maybeEnableUndo() self.moveToState("deckBrowser") return True
def __init__(self, collectionfile, deckname=None, modelname=None): """Connects to an anki collection stored in a file. """ self.collection = Collection(collectionfile, log=True) if not deckname is None: deckid = self.createOrReturnDeckId(deckname) self.selectDeckById(deckid) if not modelname is None: self.selectModelByName(modelname)
def _loadCollection(self) -> bool: cpath = self.pm.collectionPath() self.col = Collection(cpath, log=True) self.setEnabled(True) self.progress.setupDB(self.col.db) self.maybeEnableUndo() self.moveToState("deckBrowser") return True
def _prepareFiles(self) -> None: importingV2 = self.file.endswith(".anki21") self.mustResetLearning = False self.dst = self.col self.src = Collection(self.file) if not importingV2 and self.col.schedVer() != 1: # any scheduling included? if self.src.db.scalar("select 1 from cards where queue != 0 limit 1"): self.mustResetLearning = True
def _addDummyCollection(self, zip) -> None: path = namedtmp("dummy.anki2") c = Collection(path) n = c.newNote() n[_("Front")] = "This file requires a newer version of Anki." c.addNote(n) c.save() c.close() zip.write(path, "collection.anki2") os.unlink(path)
def run(self): # init this first so an early crash doesn't cause an error # in the main thread self.syncMsg = "" self.uname = "" try: self.col = Collection(self.path, log=True) except: self.fireEvent("corrupt") return self.server = RemoteServer(self.hkey, hostNum=self.hostNum) self.client = Syncer(self.col, self.server) self.sentTotal = 0 self.recvTotal = 0 def syncEvent(type): self.fireEvent("sync", type) def syncMsg(msg): self.fireEvent("syncMsg", msg) def sendEvent(bytes): if not self._abort: self.sentTotal += bytes self.fireEvent("send", str(self.sentTotal)) elif self._abort == 1: self._abort = 2 raise Exception("sync cancelled") def recvEvent(bytes): if not self._abort: self.recvTotal += bytes self.fireEvent("recv", str(self.recvTotal)) elif self._abort == 1: self._abort = 2 raise Exception("sync cancelled") hooks.sync_stage_did_change.append(syncEvent) hooks.sync_progress_did_change.append(syncMsg) hooks.http_data_did_send.append(sendEvent) hooks.http_data_did_receive.append(recvEvent) # run sync and catch any errors try: self._sync() except: err = traceback.format_exc() self.fireEvent("error", err) finally: # don't bump mod time unless we explicitly save self.col.close(save=False) hooks.sync_stage_did_change.remove(syncEvent) hooks.sync_progress_did_change.remove(syncMsg) hooks.http_data_did_send.remove(sendEvent) hooks.http_data_did_receive.remove(recvEvent)
async def get_anki_col(username): ipfs_ctx = ipfs.MutableFileContext( ext='anki2', mfs_path=anki_col_path(username)) await ipfs_ctx.__aenter__() col = Collection(ipfs_ctx.fs_path) # Set a sync hook that exits the ipfs file context when the storage is # synced async def sync_hook(): logging.info('running sync_hook') await ipfs_ctx.__aexit__() col.__sync_hook__ = sync_hook return col
def run(self): # init this first so an early crash doesn't cause an error # in the main thread self.syncMsg = "" self.uname = "" try: self.col = Collection(self.path) except: self.fireEvent("corrupt") return self.server = RemoteServer(self.hkey, hostNum=self.hostNum) self.client = Syncer(self.col, self.server) self.sentTotal = 0 self.recvTotal = 0 def syncEvent(type): self.fireEvent("sync", type) def syncMsg(msg): self.fireEvent("syncMsg", msg) def http_progress(upload: int, download: int) -> None: if not self._abort: self.sentTotal += upload self.recvTotal += download self.progress_event.emit(self.sentTotal, self.recvTotal) # type: ignore elif self._abort == 1: self._abort = 2 raise Exception("sync cancelled") self.server.client.progress_hook = http_progress hooks.sync_stage_did_change.append(syncEvent) hooks.sync_progress_did_change.append(syncMsg) # run sync and catch any errors try: self._sync() except: err = traceback.format_exc() self.fireEvent("error", err) finally: # don't bump mod time unless we explicitly save self.col.close(save=False, downgrade=False) hooks.sync_stage_did_change.remove(syncEvent) hooks.sync_progress_did_change.remove(syncMsg)
def CreateBatchCards(noteList): ##notes is a list of dicts # notes = [ # { # "Front": "Bonjour", # "Back": "Hello", # }, # { # "Front": "Merci", # "Back": "Thank you", # }, # # Thousands of additional notes... # ] notez = CreateNotes(noteList) # Find the Anki directory anki_home = r'C:\Users\Linus\AppData\Roaming\Anki2\User 1' anki_collection_path = os.path.join(anki_home, "collection.anki2") # 1. Load the anki collection col = Collection(anki_collection_path, log=True) # 2. Select the deck # Find the model to use (Basic, Basic with reversed, ...) modelBasic = col.models.byName('2. Picture Words') # Set the deck deck = col.decks.byName('Espanol') col.decks.select(deck['id']) col.decks.current()['mid'] = modelBasic['id'] # 3. Create the cards for current_note in notez: note = col.newNote() note.fields[0] = current_note["Front"] note.fields[1] = current_note["Image"] col.addNote(note) print('Card created: ', note.fields[0]) # 4. Save changes col.close()
def bulk_loading_anki(deck, note_type, data_list, field_indices=[0, 1], tags=""): # Load the anki collection cpath = os.path.join(PROFILE_HOME, "collection.anki2") col = Collection(cpath, log=True) # Set the model modelBasic = col.models.byName(note_type) col.decks.current()['mid'] = modelBasic['id'] # Get the deck deck = col.decks.byName(deck) # Iterate over idioms for data in data_list: # Instantiate the new note note = col.newNote() note.model()['did'] = deck['id'] # Set the content for i, idx in enumerate(field_indices): note.fields[idx] = data[i] m = note.model() # Set the tags (and add the new ones to the deck configuration if len(tags) > 0: note.tags = col.tags.canonify(col.tags.split(tags)) m['tags'] = note.tags col.models.save(m) # Add the note col.addNote(note) # Save the changes to DB col.save()
def testWrap(): from anki.schedv2 import Scheduler path = namedtmp("humpty_dumpty_tmp.anki2") dummy_col = Collection(path) v2_sched = Scheduler(dummy_col) try: run_test.reset() v2_sched.moveToV1() assert run_test.state == 1, "The addon HumptyDumpty was not patched correctly. Error code 1" run_test.reset() v2_sched.moveToV2() assert run_test.state == 2, "The addon HumptyDumpty was not patched correctly. Error code 2" run_test.setTestState(run_test.STATE_FINISHED) #for pref menu # print("HumptyDumpty was patched correctly.") finally: dummy_col.close() del dummy_col
def main(): data = read_in() #data = {"accented": "соба'ка","exampleSentence":"Де́вочка бои́тся соба́к","extraInfo":"feminine"} anki_collection_path = os.path.join(anki_home, "collection.anki2") try: col = Collection(anki_collection_path, log=True) except Exception as e: print(e) exit() try: modelPictureWord = col.models.byName('2. Picture Words') col.models.save(modelPictureWord) deck = col.decks.byName("Russian") note = col.newNote(deck['id']) note.fields[0] = data["accented"] #Word note.fields[ 1] = "<img src=" + data["accented"] + ".jpg" + "/>" #Picture note.fields[2] = data["extraInfo"] #ExtraInfo note.fields[ 3] = "[sound:" + data["accented"] + ".mp3" + "]" #Pronounciation note.fields[4] = data["exampleSentence"] #ExampleSentence except Exception as e: print("An error occured trying to add data to note") print(e) try: download_file('audio', data["pronounciationURL"], data["accented"]) download_file('image', data["imageURL"], data["accented"]) col.add_note(note, deck["id"]) col.save() except Exception as e: print("An error occured trying to add a note") print(e) exit()
def get_anki2(self): return Collection(os.path.join(self.anki2, "collection.anki2"))
default="English") parser.add_argument("-v", "--verbose", help="Enable verbose mode", action='store_true') parser.set_defaults(verbose=False) args = parser.parse_args() print("----------------------------------") print("Phrasal Verbs Loader -------------") print("----------------------------------") print("Anki home: %s\n" % args.anki_home) # Load the anki collection cpath = os.path.join(args.anki_home, "collection.anki2") col = Collection(cpath, log=True) # Set the model modelBasic = col.models.byName('Basic') deck = col.decks.byName(args.deck) col.decks.select(deck['id']) col.decks.current()['mid'] = modelBasic['id'] # Iterate over false friends current_word = None # Parse input file load_phrasal_verbs(args.input_file, col, deck) # Save the changes to DB col.save()
parser = argparse.ArgumentParser() parser.add_argument("output", help="Location of output: desktop or file") args = parser.parse_args() if args.output not in ["desktop", "file"]: usage() sys.exit() if args.output == "file": collection_fn = os.path.join(directory, "..", "..", "output", "leetcode", "leetcode.anki2") collection_fn = os.path.abspath(collection_fn) elif args.output == "desktop": collection_fn = util_anki.get_default_collection() col = Collection(collection_fn, log=True) my_sol_folder = os.path.join(directory, "..", "..", "output", "raw", "leetcode", "my_solution") modelBasic = col.models.byName('Basic') if modelBasic is None: # 新安装的 Anki 桌面端会存在为空的情况 modelBasic = addBasicModel(col) modelBasic["css"] = conf.DEFAULT_CSS_N_ALIGN + "\n" + conf.HIGHLIGHT_CSS modelBasic["tmpls"][0]["qfmt"] = "{{Front}}" + conf.JS_TEMPLATE modelBasic["tmpls"][0][ "afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}" + conf.JS_TEMPLATE col.models.save(modelBasic) # 建立新 deck deck_name = "leetcode"
def callLoad(): col = Collection(cpath, log=True) json_pattern = "word_data.json" main_script_path = module_locator.module_path() file_pattern = os.path.join(main_script_path, json_pattern) load(col, file_pattern)
def bulk_loading_anki(idioms): # Load the anki collection cpath = os.path.join(PROFILE_HOME, "collection.anki2") col = Collection(cpath, log=True) # Set the model modelBasic = col.models.byName('Idiom') col.decks.current()['mid'] = modelBasic['id'] # Get the deck deck = col.decks.byName("English") # Iterate over idioms for idiom in idioms: # Instantiate the new note note = col.newNote() note.model()['did'] = deck['id'] # Set the content english_field = highlight_qualifier(idiom.en) french_field = highlight_qualifier(idiom.fr) examples_field = "" # fill below note_field = "" # fill below if not idiom.en: # Should not happen continue if not idiom.fr and idiom.examples: # Sometimes, there is not translation in french, we used the first example phrase instead english_field = idiom.examples[0]['en'] french_field = idiom.examples[0]['fr'] if "(familier)" in idiom.en: french_field += " " + highlight_qualifier('(familier)') for example in idiom.examples: examples_field += '<p class="example"><span class="english">%s</span> <span class="french">%s</span></p>' \ % (example['en'], example['fr']) for warning in idiom.warnings: note_field += '<p class="warning">%s<p>' % warning note.fields[0] = english_field note.fields[1] = french_field note.fields[2] = examples_field note.fields[3] = note_field print("{\nEnglish: %s,\nFrench: %s,\nExamples: %s,\nNotes: %s}" % (note.fields[0], note.fields[1], note.fields[2], note.fields[3])) # Set the tags (and add the new ones to the deck configuration tags = "idiom" note.tags = col.tags.canonify(col.tags.split(tags)) m = note.model() m['tags'] = note.tags col.models.save(m) # Add the note col.addNote(note) # Save the changes to DB col.save()
from anki.exporting import AnkiPackageExporter from anki.importing import AnkiPackageImporter from pymongo import MongoClient from config import DB, MONGO_DB_URI, DROPBOX_AUTH_TOKEN IMPORT_PATH = '/Users/admin/Dropbox/KevNI/Japanese Decks/Public Decks/' BASE_DECK = 'Gamegogakuen JP' OUTPUT_FILE_NAME = 'Gamegogakuen_JP.apkg' OUTPUT_PATH = '/Users/admin/Desktop/' + OUTPUT_FILE_NAME # Define the path to the Anki SQLite collection COLLECTION_PATH = '/Users/admin/Library/Application Support/Anki2/User 1/collection.anki2' # Load the Collection col = Collection(COLLECTION_PATH, log=False) # Entry point to the API # Clear collection for did in col.decks.allIds(): col.decks.rem(did, True) col.save() # Import game decks for filename in os.listdir(IMPORT_PATH): apkg = IMPORT_PATH + filename AnkiPackageImporter(col, apkg).run() col.save() # Create a base dynamic deck base_deck_id = col.decks.newDyn(BASE_DECK)
def _open_collection(self): anki_collection_path = os.path.join(self.anki_dir, "collection.anki2") print("📂 Opening Anki collection...") self.col = Collection(anki_collection_path, log=True)
import sys, os, decorator # Load Anki library sys.path.append("anki") from anki.storage import Collection # Define the path to the Anki SQLite collection PROFILE_HOME = os.path.expanduser("/Users/Jesus/Documents/anki/Usuario 1") cpath = os.path.join(PROFILE_HOME, "collection.anki2") # Load the Collection col = Collection(cpath, log=True) # Entry point to the API # Use the available methods to list the notes for cid in col.findNotes("tag:Vocabulary"): note = col.getNote(cid) front = note.fields[0] # "Front" is the first field of these cards print(front)
help="JSON file containing data with which to create cards") parser.add_argument( "-m", "--model-name", help="Name of the note type (model) to be used for new cards") parser.add_argument( "-p", "--anki-profile", default="User 1", help="Name of the profile for which the collection should be created") args = parser.parse_args() # Load the anki collection collection_path = os.path.join(args.anki_home, args.anki_profile, "collection.anki2") json_file = os.path.abspath(args.json_file) collection = Collection(collection_path, log=True) # Set the model model = collection.models.byName(args.model_name) deck = collection.decks.byName(args.deck_name) collection.decks.select(deck['id']) collection.decks.current()['mid'] = model['id'] # Load JSON into collection fill(collection, deck, json_file) # Save the changes to DB collection.save() collection.close()
def exportInto(self, path: str) -> None: # sched info+v2 scheduler not compatible w/ older clients self._v2sched = self.col.schedVer() != 1 and self.includeSched # create a new collection at the target try: os.unlink(path) except (IOError, OSError): pass self.dst = Collection(path) self.src = self.col # find cards cids = self.cardIds() # copy cards, noting used nids nids = {} data = [] for row in self.src.db.execute( "select * from cards where id in " + ids2str(cids) ): nids[row[1]] = True data.append(row) # clear flags row = list(row) row[-2] = 0 self.dst.db.executemany( "insert into cards values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", data ) # notes strnids = ids2str(list(nids.keys())) notedata = [] for row in self.src.db.all("select * from notes where id in " + strnids): # remove system tags if not exporting scheduling info if not self.includeSched: row = list(row) row[5] = self.removeSystemTags(row[5]) notedata.append(row) self.dst.db.executemany( "insert into notes values (?,?,?,?,?,?,?,?,?,?,?)", notedata ) # models used by the notes mids = self.dst.db.list("select distinct mid from notes where id in " + strnids) # card history and revlog if self.includeSched: data = self.src.db.all("select * from revlog where cid in " + ids2str(cids)) self.dst.db.executemany( "insert into revlog values (?,?,?,?,?,?,?,?,?)", data ) else: # need to reset card state self.dst.sched.resetCards(cids) # models - start with zero self.dst.models.models = {} for m in self.src.models.all(): if int(m["id"]) in mids: self.dst.models.update(m) # decks dids = self.deckIds() dconfs = {} for d in self.src.decks.all(): if str(d["id"]) == "1": continue if dids and d["id"] not in dids: continue if not d["dyn"] and d["conf"] != 1: if self.includeSched: dconfs[d["conf"]] = True if not self.includeSched: # scheduling not included, so reset deck settings to default d = dict(d) d["conf"] = 1 self.dst.decks.update(d) # copy used deck confs for dc in self.src.decks.allConf(): if dc["id"] in dconfs: self.dst.decks.updateConf(dc) # find used media media = {} self.mediaDir = self.src.media.dir() if self.includeMedia: for row in notedata: flds = row[6] mid = row[2] for file in self.src.media.filesInStr(mid, flds): # skip files in subdirs if file != os.path.basename(file): continue media[file] = True if self.mediaDir: for fname in os.listdir(self.mediaDir): path = os.path.join(self.mediaDir, fname) if os.path.isdir(path): continue if fname.startswith("_"): # Scan all models in mids for reference to fname for m in self.src.models.all(): if int(m["id"]) in mids: if self._modelHasMedia(m, fname): media[fname] = True break self.mediaFiles = list(media.keys()) self.dst.crt = self.src.crt # todo: tags? self.count = self.dst.cardCount() self.dst.setMod() self.postExport() self.dst.close()
def reopen(self): cpath = self.pm.collectionPath() self.col = Collection(cpath, backend=self.backend)
#!/usr/bin/env python3 # imports a text file (question and answer separated by '=') adding notes for each line from anki.storage import Collection model_name = '<model>' deck_name = '<deck>' collection_path = '<path>' data_source = '<source>' collection = Collection(collection_path) try: # gets the desired model and sets the desired deck id on it, then sets it as the current model # this strange API is the way it all works: the current model is used when a new Note is created # and when cards are generated their target deck is taken from the model (unless overriding is used) model = collection.models.byName(model_name) if not model: raise ValueError('model \'{}\' not found'.format(model_name)) deck = collection.decks.byName(deck_name) if not deck: raise ValueError('deck \'{}\' not found'.format(deck_name)) model['did'] = deck['id'] collection.models.setCurrent(model) with open(data_source, encoding='utf-8') as lines: total_cards = 0 for i, line in enumerate(lines): if '=' not in line: print('Ignoring line {}: \'{}\''.format(i + 1, line.strip())) continue
def load_collection(db_dir, db_file): db_dir = os.path.expanduser(db_dir) coll_path = os.path.join(db_dir, db_file) return Collection(coll_path, log=True)