com.ichi2.libanki.importer.AnkiPackageImporter.java Source code

Java tutorial

Introduction

Here is the source code for com.ichi2.libanki.importer.AnkiPackageImporter.java

Source

/***************************************************************************************
  * Copyright (c) 2016 Houssam Salem <houssam.salem.au@gmail.com>                        *
 *                                                                                      *
 * This program is free software; you can redistribute it and/or modify it under        *
 * the terms of the GNU General Public License as published by the Free Software        *
 * Foundation; either version 3 of the License, or (at your option) any later           *
 * version.                                                                             *
 *                                                                                      *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
 *                                                                                      *
 * You should have received a copy of the GNU General Public License along with         *
 * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
 ****************************************************************************************/

package com.ichi2.libanki.importer;

import com.google.gson.stream.JsonReader;
import com.ichi2.anki.BackupManager;
import com.ichi2.anki.R;
import com.ichi2.libanki.Collection;
import com.ichi2.libanki.Storage;
import com.ichi2.libanki.Utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipFile;

import timber.log.Timber;

public class AnkiPackageImporter extends Anki2Importer {

    private ZipFile mZip;
    private Map<String, String> mNameToNum;

    public AnkiPackageImporter(Collection col, String file) {
        super(col, file);
    }

    @Override
    public void run() {
        publishProgress(0, 0, 0);
        File tempDir = new File(new File(mCol.getPath()).getParent(), "tmpzip");
        Collection tmpCol;
        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.
            try {
                // extract the deck from the zip file
                mZip = new ZipFile(new File(mFile), ZipFile.OPEN_READ);
                Utils.unzipFiles(mZip, tempDir.getAbsolutePath(), new String[] { "collection.anki2", "media" },
                        null);
            } catch (IOException e) {
                Timber.e(e, "Failed to unzip apkg.");
                mLog.add(getRes().getString(R.string.import_log_no_apkg));
                return;
            }
            String colpath = new File(tempDir, "collection.anki2").getAbsolutePath();
            if (!(new File(colpath)).exists()) {
                mLog.add(getRes().getString(R.string.import_log_no_apkg));
                return;
            }
            tmpCol = Storage.Collection(mContext, colpath);
            try {
                if (!tmpCol.validCollection()) {
                    mLog.add(getRes().getString(R.string.import_log_no_apkg));
                    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<>();
            // 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();
                String name;
                String num;
                while (jr.hasNext()) {
                    num = jr.nextName();
                    name = jr.nextString();
                    mNameToNum.put(name, num);
                    numToName.put(num, name);
                }
                jr.endObject();
                jr.close();
            } 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 {
            // Clean up our temporary files
            if (tempDir.exists()) {
                BackupManager.removeDir(tempDir);
            }
        }
        publishProgress(100, 100, 100);
    }

    @Override
    protected BufferedInputStream _srcMediaData(String fname) {
        if (mNameToNum.containsKey(fname)) {
            try {
                return new BufferedInputStream(mZip.getInputStream(mZip.getEntry(mNameToNum.get(fname))));
            } catch (IOException e) {
                Timber.e("Could not extract media file " + fname + "from zip file.");
            }
        }
        return null;
    }
}