예제 #1
0
def import_apkg_model(path, delete=False):
    #If delete==True, our sole purpose is to import the note types and flashcard templates, not the data.

    imp = AnkiPackageImporter(mw.col, path)
    imp.run()
    mw.col.models.flush()
    mw.reset(
        True)  # refresh the screen so that the newly imported deck is visible

    if delete:
        # Delete ALL cards/notes in the LIFT deck. Ignore errors
        try:
            #            deck = mw.col.decks.byName(TARGET_DECK)  #hmm, this returns a Python dict(); how to get the deck object?
            #            assert deck.cardCount() > 0
            #            assert deck.noteCount() > 0
            ids = mw.col.findCards("deck:{}".format(TARGET_DECK))
            mw.col.remCards(ids, True)
#            assert deck.cardCount() == 0
#            assert deck.noteCount() == 0
        except:
            return "Failed to delete cards and notes after importing the APKG file."

    mw.col.models.flush()
    mw.reset(True)
    return ""
예제 #2
0
 def reset(self, path):
     self.log.info('removing previous Kanji Damage decks')
     util.remove_model_and_deck(self.col, KD_MODEL, KD_DECK_NAME, self.log)
     util.remove_model_and_deck(self.col, KD_MODEL, KDR_DECK_NAME, self.log)
     self.log.info('importing %s', path)
     importer = AnkiPackageImporter(self.col, path)
     importer.run()
     self.col.save()
예제 #3
0
def test_anki2_updates():
    # create a new empty deck
    dst = getEmptyCol()
    tmp = getUpgradeDeckPath("update1.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert imp.dupes == 0
    assert imp.added == 1
    assert imp.updated == 0
    # importing again should be idempotent
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert imp.dupes == 1
    assert imp.added == 0
    assert imp.updated == 0
    # importing a newer note should update
    assert dst.noteCount() == 1
    assert dst.db.scalar("select flds from notes").startswith("hello")
    tmp = getUpgradeDeckPath("update2.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert imp.dupes == 1
    assert imp.added == 0
    assert imp.updated == 1
    assert dst.noteCount() == 1
    assert dst.db.scalar("select flds from notes").startswith("goodbye")
예제 #4
0
    def importPackage(self, path):
        collection = self.collection()
        if collection is not None:
            try:
                self.startEditing()
                importer = AnkiPackageImporter(collection, path)
                importer.run()
            except:
                self.stopEditing()
                raise
            else:
                self.stopEditing()
                return True

        return False
예제 #5
0
def test_anki2_diffmodel_templates():
    # different from the above as this one tests only the template text being
    # changed, not the number of cards/fields
    dst = getEmptyCol()
    # import the first version of the model
    tmp = getUpgradeDeckPath("diffmodeltemplates-1.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.dupeOnSchemaChange = True
    imp.run()
    # then the version with updated template
    tmp = getUpgradeDeckPath("diffmodeltemplates-2.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.dupeOnSchemaChange = True
    imp.run()
    # collection should contain the note we imported
    assert dst.noteCount() == 1
    # the front template should contain the text added in the 2nd package
    tcid = dst.findCards("")[0]  # only 1 note in collection
    tnote = dst.getCard(tcid).note()
    assert "Changed Front Template" in tnote.cards()[0].template()["qfmt"]
예제 #6
0
def test_apkg():
    tmp = getEmptyDeck()
    apkg = unicode(os.path.join(testDir, "support/media.apkg"))
    imp = AnkiPackageImporter(tmp, apkg)
    assert os.listdir(tmp.media.dir()) == []
    imp.run()
    assert os.listdir(tmp.media.dir()) == ['foo.wav']
    # importing again should be idempotent in terms of media
    tmp.remCards(tmp.db.list("select id from cards"))
    imp = AnkiPackageImporter(tmp, apkg)
    imp.run()
    assert os.listdir(tmp.media.dir()) == ['foo.wav']
    # but if the local file has different data, it will rename
    tmp.remCards(tmp.db.list("select id from cards"))
    open(os.path.join(tmp.media.dir(), "foo.wav"), "w").write("xyz")
    imp = AnkiPackageImporter(tmp, apkg)
    imp.run()
    assert len(os.listdir(tmp.media.dir())) == 2
예제 #7
0
def import_apkg_model(path, delete=False):
    #If delete==True, our sole purpose is to import the note types and flashcard templates, not the data.
    
    imp = AnkiPackageImporter(mw.col, path)
    imp.run()
    mw.col.models.flush()
    mw.reset(True) # refresh the screen so that the newly imported deck is visible

    if delete:
        # Delete ALL cards/notes in the LIFT deck. Ignore errors
        try:
#            deck = mw.col.decks.byName(TARGET_DECK)  #hmm, this returns a Python dict(); how to get the deck object?
#            assert deck.cardCount() > 0
#            assert deck.noteCount() > 0
            ids = mw.col.findCards("deck:{}".format(TARGET_DECK))
            mw.col.remCards(ids, True)
#            assert deck.cardCount() == 0
#            assert deck.noteCount() == 0
        except:
            return "Failed to delete cards and notes after importing the APKG file."
    
    mw.col.models.flush()
    mw.reset(True)
    return ""
예제 #8
0
def test_anki2_diffmodel_templates():
    # different from the above as this one tests only the template text being
    # changed, not the number of cards/fields
    dst = getEmptyCol()
    # import the first version of the model
    tmp = getUpgradeDeckPath("diffmodeltemplates-1.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.dupeOnSchemaChange = True
    imp.run()
    # then the version with updated template
    tmp = getUpgradeDeckPath("diffmodeltemplates-2.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.dupeOnSchemaChange = True
    imp.run()
    # collection should contain the note we imported
    assert(dst.noteCount() == 1)
    # the front template should contain the text added in the 2nd package
    tcid = dst.findCards("")[0] # only 1 note in collection
    tnote = dst.getCard(tcid).note()
    assert("Changed Front Template" in dst.findTemplates(tnote)[0]['qfmt'])
예제 #9
0
APKG_PATH = DOCS_PATH + 'accelerated_spanish_empty.apkg'
CSV_PATH = DOCS_PATH + 'spanish5.csv'
TMP_COL_PATH = TMP_PATH
DECK_NAME = 'accelerated spanish'
DECK_ID = None  #1518389138178
MODEL_NAME = 'Basic'
QUESTION_FIELD = 'Front'
ANSWER_FIELD = 'Back'
MEDIA_PATH = '/home/cowley/.local/share/Anki2/User 1/collection.media/'

with open(CSV_PATH) as f:
    reader = csv.reader(f, delimiter='\t')

    collection = anki.Collection(TMP_COL_PATH +
                                 str(random.randint(10**9, 10**10)) + '.anki2')
    api = AnkiPackageImporter(collection, APKG_PATH)
    api.run()

    collection = api.col

    # get deck
    try:
        deck_id = collection.decks.id(DECK_NAME)
    except:
        print('invalid deck name')
        raise
    collection.decks.select(deck_id)

    # get model to use
    try:
        model = collection.models.byName(MODEL_NAME)
예제 #10
0
def test_anki2_diffmodels():
    # create a new empty deck
    dst = getEmptyDeck()
    # import the 1 card version of the model
    tmp = getUpgradeDeckPath("diffmodels2-1.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    before = dst.noteCount()
    # repeating the process should do nothing
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert before == dst.noteCount()
    # then the 2 card version
    tmp = getUpgradeDeckPath("diffmodels2-2.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    after = dst.noteCount()
    # as the model schemas differ, should have been imported as new model
    assert after == before + 1
    # and the new model should have both cards
    assert dst.cardCount() == 3
    # repeating the process should do nothing
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    after = dst.noteCount()
    assert after == before + 1
    assert dst.cardCount() == 3
예제 #11
0
def test_anki2_diffmodels():
    # create a new empty deck
    dst = getEmptyDeck()
    # import the 1 card version of the model
    tmp = getUpgradeDeckPath("diffmodels2-1.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    before = dst.noteCount()
    # repeating the process should do nothing
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert before == dst.noteCount()
    # then the 2 card version
    tmp = getUpgradeDeckPath("diffmodels2-2.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    after = dst.noteCount()
    # as the model schemas differ, should have been imported as new model
    assert after == before + 1
    # and the new model should have both cards
    assert dst.cardCount() == 3
    # repeating the process should do nothing
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    after = dst.noteCount()
    assert after == before + 1
    assert dst.cardCount() == 3
예제 #12
0
def test_apkg():
    tmp = getEmptyDeck()
    apkg = unicode(os.path.join(testDir, "support/media.apkg"))
    imp = AnkiPackageImporter(tmp, apkg)
    assert os.listdir(tmp.media.dir()) == []
    imp.run()
    assert os.listdir(tmp.media.dir()) == ['foo.wav']
    # importing again should be idempotent in terms of media
    tmp.remCards(tmp.db.list("select id from cards"))
    imp = AnkiPackageImporter(tmp, apkg)
    imp.run()
    assert os.listdir(tmp.media.dir()) == ['foo.wav']
    # but if the local file has different data, it will rename
    tmp.remCards(tmp.db.list("select id from cards"))
    open(os.path.join(tmp.media.dir(), "foo.wav"), "w").write("xyz")
    imp = AnkiPackageImporter(tmp, apkg)
    imp.run()
    assert len(os.listdir(tmp.media.dir())) == 2
예제 #13
0
def test_apkg():
    tmp = getEmptyCol()
    apkg = str(os.path.join(testDir, "support/media.apkg"))
    imp = AnkiPackageImporter(tmp, apkg)
    assert os.listdir(tmp.media.dir()) == []
    imp.run()
    assert os.listdir(tmp.media.dir()) == ["foo.wav"]
    # importing again should be idempotent in terms of media
    tmp.remove_cards_and_orphaned_notes(tmp.db.list("select id from cards"))
    imp = AnkiPackageImporter(tmp, apkg)
    imp.run()
    assert os.listdir(tmp.media.dir()) == ["foo.wav"]
    # but if the local file has different data, it will rename
    tmp.remove_cards_and_orphaned_notes(tmp.db.list("select id from cards"))
    with open(os.path.join(tmp.media.dir(), "foo.wav"), "w") as f:
        f.write("xyz")
    imp = AnkiPackageImporter(tmp, apkg)
    imp.run()
    assert len(os.listdir(tmp.media.dir())) == 2
예제 #14
0
def test_anki2_updates():
    # create a new empty deck
    dst = getEmptyCol()
    tmp = getUpgradeDeckPath("update1.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert imp.dupes == 0
    assert imp.added == 1
    assert imp.updated == 0
    # importing again should be idempotent
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert imp.dupes == 1
    assert imp.added == 0
    assert imp.updated == 0
    # importing a newer note should update
    assert dst.noteCount() == 1
    assert dst.db.scalar("select flds from notes").startswith("hello")
    tmp = getUpgradeDeckPath("update2.apkg")
    imp = AnkiPackageImporter(dst, tmp)
    imp.run()
    assert imp.dupes == 0
    assert imp.added == 0
    assert imp.updated == 1
    assert dst.noteCount() == 1
    assert dst.db.scalar("select flds from notes").startswith("goodbye")
예제 #15
0
# 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)

# Fetch db collections
client = MongoClient(MONGO_DB_URI)
db = client[DB]
deck_titles_collection = db.deckTitles
old_cards = db.oldCards

# Fetch deck titles
deck_titles = [doc['fullTitle'] for doc in deck_titles_collection.find()]

# Make new subdeck for every deck title
예제 #16
0
    def convert(self, in_file_str: str, out_file_str: str = None) -> None:
        """Convert a single file to ANKI deck."""

        log.info(
            f"Converting file '{in_file_str}' to ANKI deck @ '{out_file_str}'")

        # Create paths
        in_file = pathlib.Path(in_file_str)
        if out_file_str is not None:
            assert out_file_str.endswith(AnkiConvertor.ANKI_EXT)
            out_file = pathlib.Path(out_file_str).resolve()
        else:
            out_file = in_file.with_suffix(AnkiConvertor.ANKI_EXT).resolve()
        tmp_out_file = out_file.with_suffix(".tmp.apkg").resolve()

        # Convert the org nodes into list of Notes
        cards: typing.List[genanki.Note] = []

        # Preprocess and parse the file
        preprocessed_source = self.preprocessor.preprocess_file(str(in_file))
        org_file = orgparse.loads(preprocessed_source)

        # If user did not supplied the convert mode - try to get the convert mode
        # from the org file header fall back to NORMAL mode
        if not self.user_supplied_convert_mode:
            try:
                self.convert_mode = AnkiConvertMode[org_file._special_comments[
                    self.COMMENT_ANKI_CONVERT_MODE][0].upper()]
            except KeyError:
                self.convert_mode = AnkiConvertMode.NORMAL
        else:
            self.convert_mode = self._convert_mode

        self._get_cards(org_file, cards)

        # Try to set the deck name to a org file title comment
        try:
            deck_name = org_file._special_comments["TITLE"][0]
        except (KeyError, IndexError):
            deck_name = out_file.stem

        # TODO: Hash should be calculated from the cards
        deck = genanki.Deck(random.randrange(1 << 30, 1 << 31), deck_name)

        for c in cards:
            deck.add_note(c)

        package = genanki.Package(deck)
        package.media_files = self.node_convertor.media_files
        package.write_to_file(str(tmp_out_file))

        # Import and export the collection using Anki
        # This is neccessary to make mobile version work (include rendered equations)
        with utils.create_empty_anki_collection() as col:
            log.debug("Importing to tmp ANKI collection")
            imp = AnkiPackageImporter(col, str(tmp_out_file))
            imp.run()
            log.debug("Exporting from tmp ANKI collection")
            exp = AnkiPackageExporter(col)
            exp.exportInto(str(out_file))

        tmp_out_file.unlink()
예제 #17
0
def open_apkg(apkg_path):
    with utils.create_empty_anki_collection() as col:
        imp = AnkiPackageImporter(col, str(apkg_path))
        imp.run()

        yield col