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();
}
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);
}
}
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);
}
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);
}
// }
}
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;
}
Aggregations