Search in sources :

Example 1 with Media

use of com.ichi2.libanki.Media 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 Media

use of com.ichi2.libanki.Media in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundImportReplace.

private TaskData doInBackgroundImportReplace(TaskData param) {
    Timber.d("doInBackgroundImportReplace");
    String path = param.getString();
    Resources res = AnkiDroidApp.getInstance().getBaseContext().getResources();
    // extract the deck from the zip file
    String colPath = CollectionHelper.getCollectionPath(mContext);
    File dir = new File(new File(colPath).getParentFile(), "tmpzip");
    if (dir.exists()) {
        BackupManager.removeDir(dir);
    }
    // from anki2.py
    String colname = "collection.anki21";
    ZipFile zip;
    try {
        zip = new ZipFile(new File(path));
    } catch (IOException e) {
        Timber.e(e, "doInBackgroundImportReplace - Error while unzipping");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundImportReplace0");
        return new TaskData(false);
    }
    try {
        // v2 scheduler?
        if (zip.getEntry(colname) == null) {
            colname = CollectionHelper.COLLECTION_FILENAME;
        }
        Utils.unzipFiles(zip, dir.getAbsolutePath(), new String[] { colname, "media" }, null);
    } catch (IOException e) {
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundImportReplace - unzip");
        return new TaskData(false);
    }
    String colFile = new File(dir, colname).getAbsolutePath();
    if (!(new File(colFile)).exists()) {
        return new TaskData(false);
    }
    Collection tmpCol = null;
    try {
        tmpCol = Storage.Collection(mContext, colFile);
        if (!tmpCol.validCollection()) {
            tmpCol.close();
            return new TaskData(false);
        }
    } catch (Exception e) {
        Timber.e("Error opening new collection file... probably it's invalid");
        try {
            tmpCol.close();
        } catch (Exception e2) {
        // do nothing
        }
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundImportReplace - open col");
        return new TaskData(false);
    } finally {
        if (tmpCol != null) {
            tmpCol.close();
        }
    }
    publishProgress(new TaskData(res.getString(R.string.importing_collection)));
    if (hasValidCol()) {
        // unload collection and trigger a backup
        Time time = CollectionHelper.getInstance().getTimeSafe(mContext);
        CollectionHelper.getInstance().closeCollection(true, "Importing new collection");
        CollectionHelper.getInstance().lockCollection();
        BackupManager.performBackupInBackground(colPath, true, time);
    }
    // overwrite collection
    File f = new File(colFile);
    if (!f.renameTo(new File(colPath))) {
        // Exit early if this didn't work
        return new TaskData(false);
    }
    int addedCount = -1;
    try {
        CollectionHelper.getInstance().unlockCollection();
        // because users don't have a backup of media, it's safer to import new
        // data and rely on them running a media db check to get rid of any
        // unwanted media. in the future we might also want to duplicate this step
        // import media
        HashMap<String, String> nameToNum = new HashMap<>();
        HashMap<String, String> numToName = new HashMap<>();
        File mediaMapFile = new File(dir.getAbsolutePath(), "media");
        if (mediaMapFile.exists()) {
            JsonReader jr = new JsonReader(new FileReader(mediaMapFile));
            jr.beginObject();
            String name;
            String num;
            while (jr.hasNext()) {
                num = jr.nextName();
                name = jr.nextString();
                nameToNum.put(name, num);
                numToName.put(num, name);
            }
            jr.endObject();
            jr.close();
        }
        String mediaDir = Media.getCollectionMediaPath(colPath);
        int total = nameToNum.size();
        int i = 0;
        for (Map.Entry<String, String> entry : nameToNum.entrySet()) {
            String file = entry.getKey();
            String c = entry.getValue();
            File of = new File(mediaDir, file);
            if (!of.exists()) {
                Utils.unzipFiles(zip, mediaDir, new String[] { c }, numToName);
            }
            ++i;
            publishProgress(new TaskData(res.getString(R.string.import_media_count, (i + 1) * 100 / total)));
        }
        zip.close();
        // delete tmp dir
        BackupManager.removeDir(dir);
        return new TaskData(true);
    } catch (RuntimeException e) {
        Timber.e(e, "doInBackgroundImportReplace - RuntimeException");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundImportReplace1");
        return new TaskData(false);
    } catch (FileNotFoundException e) {
        Timber.e(e, "doInBackgroundImportReplace - FileNotFoundException");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundImportReplace2");
        return new TaskData(false);
    } catch (IOException e) {
        Timber.e(e, "doInBackgroundImportReplace - IOException");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundImportReplace3");
        return new TaskData(false);
    }
}
Also used : HashMap(java.util.HashMap) FileNotFoundException(java.io.FileNotFoundException) Time(com.ichi2.libanki.utils.Time) IOException(java.io.IOException) JSONException(com.ichi2.utils.JSONException) CancellationException(java.util.concurrent.CancellationException) FileNotFoundException(java.io.FileNotFoundException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) ImportExportException(com.ichi2.anki.exception.ImportExportException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) Collection(com.ichi2.libanki.Collection) JsonReader(com.google.gson.stream.JsonReader) FileReader(java.io.FileReader) Resources(android.content.res.Resources) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 3 with Media

use of com.ichi2.libanki.Media in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundCheckMedia.

/**
 * @return The results list from the check, or false if any errors.
 */
private TaskData doInBackgroundCheckMedia() {
    Timber.d("doInBackgroundCheckMedia");
    Collection col = getCol();
    // A media check on AnkiDroid will also update the media db
    col.getMedia().findChanges(true);
    // Then do the actual check
    List<List<String>> result = col.getMedia().check();
    return new TaskData(0, new Object[] { result }, true);
}
Also used : Collection(com.ichi2.libanki.Collection) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList)

Example 4 with Media

use of com.ichi2.libanki.Media in project AnkiChinaAndroid by ankichinateam.

the class NoteService method saveMedia.

/**
 * Saves the multimedia associated with this card to proper path inside anki folder. For each field associated with
 * the note it checks for the following condition a. The field content should have changed b. The field content does
 * not already point to a media inside anki media path If both condition satisfies then it copies the file inside
 * the media path and deletes the file referenced by the note
 *
 * @param noteNew
 */
public static void saveMedia(Collection col, final MultimediaEditableNote noteNew) {
    // if (noteNew.getModelId() == noteOld.getModelId())
    // {
    // int fieldCount = noteNew.getNumberOfFields();
    // for (int i = 0; i < fieldCount; i++)
    // {
    // IField newField = noteNew.getField(i);
    // IField oldField = noteOld.getField(i);
    // if
    // (newField.getFormattedValue().equals(oldField.getFormattedValue()))
    // {
    // continue;
    // }
    // importMediaToDirectory(newField);
    // }
    // }
    // else
    // {
    int fieldCount = noteNew.getNumberOfFields();
    for (int i = 0; i < fieldCount; i++) {
        IField newField = noteNew.getField(i);
        importMediaToDirectory(col, newField);
    }
// }
}
Also used : IField(com.ichi2.anki.multimediacard.fields.IField)

Example 5 with Media

use of com.ichi2.libanki.Media in project AnkiChinaAndroid by ankichinateam.

the class ZipFile method _exportMedia.

private JSONObject _exportMedia(ZipFile z, File[] files, ValidateFiles validateFiles) throws IOException {
    int c = 0;
    JSONObject media = new JSONObject();
    for (File file : files) {
        // todo: deflate SVG files, as in dae/anki@a5b0852360b132c0d04094f5ca8f1933f64d7c7e
        if (validateFiles == ValidateFiles.VALIDATE && !file.exists()) {
            // Anki 2.1.30 does the same
            Timber.d("Skipping missing file %s", file);
            continue;
        }
        z.write(file.getPath(), Integer.toString(c));
        try {
            media.put(Integer.toString(c), file.getName());
            c++;
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    return media;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONException(com.ichi2.utils.JSONException) File(java.io.File)

Aggregations

File (java.io.File)43 IOException (java.io.IOException)26 Collection (com.ichi2.libanki.Collection)25 JSONObject (com.ichi2.utils.JSONObject)19 ArrayList (java.util.ArrayList)17 Test (org.junit.Test)17 ZipFile (java.util.zip.ZipFile)14 JSONException (com.ichi2.utils.JSONException)10 FileOutputStream (java.io.FileOutputStream)10 List (java.util.List)10 JSONArray (com.ichi2.utils.JSONArray)9 FileInputStream (java.io.FileInputStream)9 FileNotFoundException (java.io.FileNotFoundException)9 SharedPreferences (android.content.SharedPreferences)8 JSONObject (org.json.JSONObject)8 Resources (android.content.res.Resources)7 Uri (android.net.Uri)7 RobolectricTest (com.ichi2.anki.RobolectricTest)7 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)7 AnkiPackageImporter (com.ichi2.libanki.importer.AnkiPackageImporter)7