Search in sources :

Example 1 with Importer

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

the class ImportTest method testAnki2Mediadupes.

@Test
public void testAnki2Mediadupes() throws IOException, JSONException, ImportExportException {
    List<String> expected;
    List<String> actual;
    // add a note that references a sound
    Note n = testCol.newNote();
    n.setField(0, "[sound:foo.mp3]");
    long mid = n.model().getLong("id");
    testCol.addNote(n);
    // add that sound to the media folder
    FileOutputStream os;
    os = new FileOutputStream(new File(testCol.getMedia().dir(), "foo.mp3"), false);
    os.write("foo".getBytes());
    os.close();
    testCol.close();
    // it should be imported correctly into an empty deck
    Collection empty = Shared.getEmptyCol(InstrumentationRegistry.getInstrumentation().getTargetContext());
    Importer imp = new Anki2Importer(empty, testCol.getPath());
    imp.run();
    expected = Collections.singletonList("foo.mp3");
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    // and importing again will not duplicate, as the file content matches
    empty.remCards(empty.getDb().queryLongList("select id from cards"));
    imp = new Anki2Importer(empty, testCol.getPath());
    imp.run();
    expected = Collections.singletonList("foo.mp3");
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    n = empty.getNote(empty.getDb().queryLongScalar("select id from notes"));
    assertTrue(n.getFields()[0].contains("foo.mp3"));
    // if the local file content is different, and import should trigger a rename
    empty.remCards(empty.getDb().queryLongList("select id from cards"));
    os = new FileOutputStream(new File(empty.getMedia().dir(), "foo.mp3"), false);
    os.write("bar".getBytes());
    os.close();
    imp = new Anki2Importer(empty, testCol.getPath());
    imp.run();
    expected = Arrays.asList("foo.mp3", String.format("foo_%s.mp3", mid));
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    n = empty.getNote(empty.getDb().queryLongScalar("select id from notes"));
    assertTrue(n.getFields()[0].contains("_"));
    // if the localized media file already exists, we rewrite the note and media
    empty.remCards(empty.getDb().queryLongList("select id from cards"));
    os = new FileOutputStream(new File(empty.getMedia().dir(), "foo.mp3"));
    os.write("bar".getBytes());
    os.close();
    imp = new Anki2Importer(empty, testCol.getPath());
    imp.run();
    expected = Arrays.asList("foo.mp3", String.format("foo_%s.mp3", mid));
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    n = empty.getNote(empty.getDb().queryLongScalar("select id from notes"));
    assertTrue(n.getFields()[0].contains("_"));
    empty.close();
}
Also used : Anki2Importer(com.ichi2.libanki.importer.Anki2Importer) Note(com.ichi2.libanki.Note) FileOutputStream(java.io.FileOutputStream) Collection(com.ichi2.libanki.Collection) 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 2 with Importer

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

the class ImportTest method testAnki2Mediadupes.

@Test
public void testAnki2Mediadupes() throws IOException, JSONException, ImportExportException {
    // add a note that references a sound
    Note n = mTestCol.newNote();
    n.setField(0, "[sound:foo.mp3]");
    long mid = n.model().getLong("id");
    mTestCol.addNote(n);
    // add that sound to the media directory
    FileOutputStream os = new FileOutputStream(new File(mTestCol.getMedia().dir(), "foo.mp3"), false);
    os.write("foo".getBytes());
    os.close();
    mTestCol.close();
    // it should be imported correctly into an empty deck
    Collection empty = getEmptyCol();
    Importer imp = new Anki2Importer(empty, mTestCol.getPath());
    imp.run();
    List<String> expected = Collections.singletonList("foo.mp3");
    List<String> actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    // and importing again will not duplicate, as the file content matches
    empty.remCards(empty.getDb().queryLongList("select id from cards"));
    imp = new Anki2Importer(empty, mTestCol.getPath());
    imp.run();
    expected = Collections.singletonList("foo.mp3");
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    n = empty.getNote(empty.getDb().queryLongScalar("select id from notes"));
    assertTrue(n.getFields()[0].contains("foo.mp3"));
    // if the local file content is different, and import should trigger a rename
    empty.remCards(empty.getDb().queryLongList("select id from cards"));
    os = new FileOutputStream(new File(empty.getMedia().dir(), "foo.mp3"), false);
    os.write("bar".getBytes());
    os.close();
    imp = new Anki2Importer(empty, mTestCol.getPath());
    imp.run();
    expected = Arrays.asList("foo.mp3", String.format("foo_%s.mp3", mid));
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    n = empty.getNote(empty.getDb().queryLongScalar("select id from notes"));
    assertTrue(n.getFields()[0].contains("_"));
    // if the localized media file already exists, we rewrite the note and media
    empty.remCards(empty.getDb().queryLongList("select id from cards"));
    os = new FileOutputStream(new File(empty.getMedia().dir(), "foo.mp3"));
    os.write("bar".getBytes());
    os.close();
    imp = new Anki2Importer(empty, mTestCol.getPath());
    imp.run();
    expected = Arrays.asList("foo.mp3", String.format("foo_%s.mp3", mid));
    actual = Arrays.asList(new File(empty.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    n = empty.getNote(empty.getDb().queryLongScalar("select id from notes"));
    assertTrue(n.getFields()[0].contains("_"));
    empty.close();
}
Also used : Anki2Importer(com.ichi2.libanki.importer.Anki2Importer) Note(com.ichi2.libanki.Note) FileOutputStream(java.io.FileOutputStream) Collection(com.ichi2.libanki.Collection) 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) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 3 with Importer

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

the class ImportTest method testApkg.

@Test
public void testApkg() throws IOException, ImportExportException {
    String apkg = Shared.getTestFilePath(getTestContext(), "media.apkg");
    Importer imp = new AnkiPackageImporter(mTestCol, apkg);
    List<String> expected = Collections.emptyList();
    List<String> actual = Arrays.asList(new File(mTestCol.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(actual.size(), expected.size());
    imp.run();
    expected = Collections.singletonList("foo.wav");
    actual = Arrays.asList(new File(mTestCol.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    // import again should be idempotent in terms of media
    mTestCol.remCards(mTestCol.getDb().queryLongList("select id from cards"));
    imp = new AnkiPackageImporter(mTestCol, apkg);
    imp.run();
    expected = Collections.singletonList("foo.wav");
    actual = Arrays.asList(new File(mTestCol.getMedia().dir()).list());
    actual.retainAll(expected);
    assertEquals(expected.size(), actual.size());
    // but if the local file has different data, it will rename
    mTestCol.remCards(mTestCol.getDb().queryLongList("select id from cards"));
    FileOutputStream os = new FileOutputStream(new File(mTestCol.getMedia().dir(), "foo.wav"), false);
    os.write("xyz".getBytes());
    os.close();
    imp = new AnkiPackageImporter(mTestCol, apkg);
    imp.run();
    assertEquals(2, new File(mTestCol.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) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 4 with Importer

use of com.ichi2.libanki.importer.Importer 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 5 with Importer

use of com.ichi2.libanki.importer.Importer 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)

Aggregations

File (java.io.File)5 Anki2Importer (com.ichi2.libanki.importer.Anki2Importer)4 AnkiPackageImporter (com.ichi2.libanki.importer.AnkiPackageImporter)4 Importer (com.ichi2.libanki.importer.Importer)4 NoteImporter (com.ichi2.libanki.importer.NoteImporter)4 TextImporter (com.ichi2.libanki.importer.TextImporter)4 FileOutputStream (java.io.FileOutputStream)4 Test (org.junit.Test)4 Collection (com.ichi2.libanki.Collection)3 InstrumentedTest (com.ichi2.anki.tests.InstrumentedTest)2 Note (com.ichi2.libanki.Note)2 JsonReader (com.google.gson.stream.JsonReader)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