Search in sources :

Example 6 with AnkiPackageImporter

use of com.ichi2.libanki.importer.AnkiPackageImporter in project AnkiChinaAndroid by ankichinateam.

the class ImportTest method testApkg.

@Test
public void testApkg() throws IOException, ImportExportException {
    List<String> expected;
    List<String> actual;
    String apkg = Shared.getTestFilePath(InstrumentationRegistry.getInstrumentation().getTargetContext(), "media.apkg");
    Importer imp = new AnkiPackageImporter(testCol, apkg);
    expected = Collections.emptyList();
    actual = Arrays.asList(new File(testCol.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(actual.size(), expected.size());
    imp.run();
    expected = Collections.singletonList("foo.wav");
    actual = Arrays.asList(new File(testCol.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    // import again should be idempotent in terms of media
    testCol.remCards(testCol.getDb().queryLongList("select id from cards"));
    imp = new AnkiPackageImporter(testCol, apkg);
    imp.run();
    expected = Collections.singletonList("foo.wav");
    actual = Arrays.asList(new File(testCol.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    // but if the local file has different data, it will rename
    testCol.remCards(testCol.getDb().queryLongList("select id from cards"));
    FileOutputStream os;
    os = new FileOutputStream(new File(testCol.getMedia().dir(), "foo.wav"), false);
    os.write("xyz".getBytes());
    os.close();
    imp = new AnkiPackageImporter(testCol, apkg);
    imp.run();
    assertEquals(2, new File(testCol.getMedia().dir()).list().length);
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) FileOutputStream(java.io.FileOutputStream) File(java.io.File) Anki2Importer(com.ichi2.libanki.importer.Anki2Importer) Importer(com.ichi2.libanki.importer.Importer) AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) NoteImporter(com.ichi2.libanki.importer.NoteImporter) TextImporter(com.ichi2.libanki.importer.TextImporter) Test(org.junit.Test)

Example 7 with AnkiPackageImporter

use of com.ichi2.libanki.importer.AnkiPackageImporter in project AnkiChinaAndroid by ankichinateam.

the class AnkiPackageImporter method run.

@Override
public void run() throws ImportExportException {
    publishProgress(0, 0, 0);
    File tempDir = new File(new File(mCol.getPath()).getParent(), "tmpzip");
    // self.col into Anki.
    Collection tmpCol;
    Timber.d("Attempting to import package %s", mFile);
    String tmpApkgPath = "";
    if (mFile.endsWith(".card")) {
        tmpApkgPath = mFile.replace(".card", ".apkg");
        AESUtil.decryptionFile(mFile, tmpApkgPath);
        mFile = tmpApkgPath;
    }
    try {
        // We extract the zip contents into a temporary directory and do a little more
        // validation than the desktop client to ensure the extracted collection is an apkg.
        String colname = "collection.anki21";
        try {
            // extract the deck from the zip file
            try {
                mZip = new ZipFile(new File(mFile));
            } catch (FileNotFoundException fileNotFound) {
                // The cache can be cleared between copying the file in and importing. This is temporary
                if (fileNotFound.getMessage().contains("ENOENT")) {
                    mLog.add(getRes().getString(R.string.import_log_file_cache_cleared));
                    return;
                }
                // displays: failed to unzip
                throw fileNotFound;
            }
            // v2 scheduler?
            if (mZip.getEntry(colname) == null) {
                colname = CollectionHelper.COLLECTION_FILENAME;
            }
            // Make sure we have sufficient free space
            long uncompressedSize = Utils.calculateUncompressedSize(mZip);
            long availableSpace = Utils.determineBytesAvailable(mCol.getPath());
            Timber.d("Total uncompressed size will be: %d", uncompressedSize);
            Timber.d("Total available size is:         %d", availableSpace);
            if (uncompressedSize > availableSpace) {
                Timber.e("Not enough space to unzip, need %d, available %d", uncompressedSize, availableSpace);
                mLog.add(getRes().getString(R.string.import_log_insufficient_space, uncompressedSize, availableSpace));
                return;
            }
            // The filename that we extract should be collection.anki2
            // Importing collection.anki21 fails due to some media regexes expecting collection.anki2.
            // We follow how Anki does it and fix the problem here.
            HashMap<String, String> mediaToFileNameMap = new HashMap<>();
            mediaToFileNameMap.put(colname, CollectionHelper.COLLECTION_FILENAME);
            Utils.unzipFiles(mZip, tempDir.getAbsolutePath(), new String[] { colname, "media" }, mediaToFileNameMap);
            colname = CollectionHelper.COLLECTION_FILENAME;
        } catch (IOException e) {
            Timber.e(e, "Failed to unzip apkg.");
            AnkiDroidApp.sendExceptionReport(e, "AnkiPackageImporter::run() - unzip");
            mLog.add(getRes().getString(R.string.import_log_failed_unzip, e.getLocalizedMessage()));
            return;
        }
        String colpath = new File(tempDir, colname).getAbsolutePath();
        if (!(new File(colpath)).exists()) {
            mLog.add(getRes().getString(R.string.import_log_failed_copy_to, colpath));
            return;
        }
        tmpCol = Storage.Collection(mContext, colpath);
        try {
            if (!tmpCol.validCollection()) {
                mLog.add(getRes().getString(R.string.import_log_failed_validate));
                return;
            }
        } finally {
            if (tmpCol != null) {
                tmpCol.close();
            }
        }
        mFile = colpath;
        // we need the media dict in advance, and we'll need a map of fname ->
        // number to use during the import
        File mediaMapFile = new File(tempDir, "media");
        mNameToNum = new HashMap<>();
        String dirPath = tmpCol.getMedia().dir();
        File dir = new File(dirPath);
        // We need the opposite mapping in AnkiDroid since our extraction method requires it.
        Map<String, String> numToName = new HashMap<>();
        try (JsonReader jr = new JsonReader(new FileReader(mediaMapFile))) {
            jr.beginObject();
            // v in anki
            String name;
            // k in anki
            String num;
            while (jr.hasNext()) {
                num = jr.nextName();
                name = jr.nextString();
                File file = new File(dir, name);
                if (!Utils.isInside(file, dir)) {
                    throw (new RuntimeException("Invalid file"));
                }
                Utils.nfcNormalized(num);
                mNameToNum.put(name, num);
                numToName.put(num, name);
            }
            jr.endObject();
        } catch (FileNotFoundException e) {
            Timber.e("Apkg did not contain a media dict. No media will be imported.");
        } catch (IOException e) {
            Timber.e("Malformed media dict. Media import will be incomplete.");
        }
        // run anki2 importer
        super.run();
        // import static media
        for (Map.Entry<String, String> entry : mNameToNum.entrySet()) {
            String file = entry.getKey();
            String c = entry.getValue();
            if (!file.startsWith("_") && !file.startsWith("latex-")) {
                continue;
            }
            File path = new File(mCol.getMedia().dir(), Utils.nfcNormalized(file));
            if (!path.exists()) {
                try {
                    Utils.unzipFiles(mZip, mCol.getMedia().dir(), new String[] { c }, numToName);
                } catch (IOException e) {
                    Timber.e("Failed to extract static media file. Ignoring.");
                }
            }
        }
    } finally {
        long availableSpace = Utils.determineBytesAvailable(mCol.getPath());
        Timber.d("Total available size is: %d", availableSpace);
        // Clean up our temporary files
        if (tempDir.exists()) {
            BackupManager.removeDir(tempDir);
        }
    }
    publishProgress(100, 100, 100);
// if(!tmpApkgPath.isEmpty()){
// new File(tmpApkgPath).delete();
// }
}
Also used : HashMap(java.util.HashMap) FileNotFoundException(java.io.FileNotFoundException) IOException(java.io.IOException) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) Collection(com.ichi2.libanki.Collection) JsonReader(com.google.gson.stream.JsonReader) FileReader(java.io.FileReader) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) HashMap(java.util.HashMap) Map(java.util.Map)

Example 8 with AnkiPackageImporter

use of com.ichi2.libanki.importer.AnkiPackageImporter in project Anki-Android by ankidroid.

the class ImportTest method testAnki2Updates.

@Test
public void testAnki2Updates() throws IOException, ImportExportException {
    // create a new empty deck
    String tmp = Shared.getTestFilePath(getTestContext(), "update1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    assertEquals(0, imp.getDupes());
    assertEquals(1, imp.getAdded());
    assertEquals(0, imp.getUpdated());
    // importing again should be idempotent
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    assertEquals(1, imp.getDupes());
    assertEquals(0, imp.getAdded());
    assertEquals(0, imp.getUpdated());
    // importing a newer note should update
    assertEquals(1, mTestCol.noteCount());
    assertTrue(mTestCol.getDb().queryString("select flds from notes").startsWith("hello"));
    tmp = Shared.getTestFilePath(getTestContext(), "update2.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    assertEquals(1, imp.getDupes());
    assertEquals(0, imp.getAdded());
    assertEquals(1, imp.getUpdated());
    assertTrue(mTestCol.getDb().queryString("select flds from notes").startsWith("goodbye"));
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 9 with AnkiPackageImporter

use of com.ichi2.libanki.importer.AnkiPackageImporter in project Anki-Android by ankidroid.

the class ImportTest method testAnki2DiffmodelTemplates.

@Test
public void testAnki2DiffmodelTemplates() throws IOException, JSONException, ImportExportException {
    // different from the above as this one tests only the template text being
    // changed, not the number of cards/fields
    // import the first version of the model
    String tmp = Shared.getTestFilePath(getTestContext(), "diffmodeltemplates-1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.setDupeOnSchemaChange(true);
    imp.run();
    // then the version with updated template
    tmp = Shared.getTestFilePath(getTestContext(), "diffmodeltemplates-2.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.setDupeOnSchemaChange(true);
    imp.run();
    // collection should contain the note we imported
    assertEquals(1, mTestCol.noteCount());
    // the front template should contain the text added in the 2nd package
    Long tcid = mTestCol.findCards("").get(0);
    Note tnote = mTestCol.getCard(tcid).note();
    assertTrue(mTestCol.findTemplates(tnote).get(0).getString("qfmt").contains("Changed Front Template"));
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Note(com.ichi2.libanki.Note) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 10 with AnkiPackageImporter

use of com.ichi2.libanki.importer.AnkiPackageImporter in project Anki-Android by ankidroid.

the class ImportTest method testDupeIgnore.

/**
 * Custom tests for AnkiDroid.
 */
@Test
public void testDupeIgnore() throws IOException, ImportExportException {
    // create a new empty deck
    String tmp = Shared.getTestFilePath(getTestContext(), "update1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    tmp = Shared.getTestFilePath(getTestContext(), "update3.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    // there is a dupe, but it was ignored
    assertEquals(1, imp.getDupes());
    assertEquals(0, imp.getAdded());
    assertEquals(0, imp.getUpdated());
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Aggregations

AnkiPackageImporter (com.ichi2.libanki.importer.AnkiPackageImporter)9 Test (org.junit.Test)8 InstrumentedTest (com.ichi2.anki.tests.InstrumentedTest)4 File (java.io.File)3 Collection (com.ichi2.libanki.Collection)2 Note (com.ichi2.libanki.Note)2 Anki2Importer (com.ichi2.libanki.importer.Anki2Importer)2 Importer (com.ichi2.libanki.importer.Importer)2 NoteImporter (com.ichi2.libanki.importer.NoteImporter)2 TextImporter (com.ichi2.libanki.importer.TextImporter)2 FileOutputStream (java.io.FileOutputStream)2 Resources (android.content.res.Resources)1 JsonReader (com.google.gson.stream.JsonReader)1 ImportExportException (com.ichi2.anki.exception.ImportExportException)1 FileNotFoundException (java.io.FileNotFoundException)1 FileReader (java.io.FileReader)1 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 ZipFile (org.apache.commons.compress.archivers.zip.ZipFile)1