package com.erakk.lnreader.task; import android.annotation.SuppressLint; import android.os.AsyncTask; import android.preference.PreferenceManager; import android.util.Log; import com.erakk.lnreader.Constants; import com.erakk.lnreader.LNReaderApplication; import com.erakk.lnreader.UIHelper; import com.erakk.lnreader.callback.CallbackEventData; import com.erakk.lnreader.callback.DownloadCallbackEventData; import com.erakk.lnreader.callback.ICallbackNotifier; import com.erakk.lnreader.dao.NovelsDao; import com.erakk.lnreader.helper.Util; import com.erakk.lnreader.model.ImageModel; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.Date; import javax.net.ssl.HttpsURLConnection; public class DownloadFileTask extends AsyncTask<Void, Integer, AsyncTaskResult<ImageModel>> { private static final String TAG = DownloadFileTask.class.toString(); private ICallbackNotifier notifier = null; private String source; private final URL url; private final String parent; public DownloadFileTask(URL url, String parent, ICallbackNotifier notifier) { this.notifier = notifier; this.url = url; this.parent = parent; } @Override protected AsyncTaskResult<ImageModel> doInBackground(Void... urls) { try { return new AsyncTaskResult<ImageModel>(downloadImage(), ImageModel.class); } catch (Exception e) { return new AsyncTaskResult<ImageModel>(null, ImageModel.class, e); } } /** * Download image and save it to DB. * @return * @throws Exception */ public ImageModel downloadImage() throws Exception { return downloadImage(this.url, this.parent); } @SuppressLint("DefaultLocale") public ImageModel downloadImage(URL imageUrl, String parent) throws Exception { if (imageUrl.getProtocol().equalsIgnoreCase("file")) return null; Log.d(TAG, "Start Downloading: " + imageUrl.toString()); InputStream input = null; OutputStream output = null; String filename = imageUrl.getFile(); // thumbnail handling // thumb.php_f=Masou_Gakuen_HxH_V09_Cover.jpg&width=84 // thumbs/M/Masou_Gakuen_HxH_V09_Cover-84px.jpg if(filename.toLowerCase().contains("thumb.php?f=")) { filename = filename.replaceAll("thumb.php.f=(.)(.*)(\\..*)&width=(\\d+)", "thumbs/$1/$1$2-$4px$3"); } String filepath = UIHelper.getImageRoot(LNReaderApplication.getInstance().getApplicationContext()) + filename; @SuppressWarnings("deprecation") String decodedUrl = Util.sanitizeFilename(URLDecoder.decode(filepath)); Log.d(TAG, "Saving to: " + decodedUrl); // create dir if not exist String path = decodedUrl.substring(0, decodedUrl.lastIndexOf("/")); File cacheDir = new File(path); if (cacheDir.mkdirs() || cacheDir.isDirectory()) { Log.d(TAG, "Path to: " + path); } else { Log.e(TAG, "Failed to create Path: " + path); } // try to move the old thumbnail if available if(imageUrl.getFile().toLowerCase().contains("thumb.php?")) { // /project/thumb.php?f=Masou_Gakuen_HxH_V09_Cover.jpg&width=84 // file:///storage/emulated/0/.bakareaderex2/project/thumb.php_f=Masou_Gakuen_HxH_V09_Cover.jpg&width=84 // file:///storage/emulated/0/.bakareaderex2/project/thumbs/Masou_Gakuen_HxH_V09_Cover-84px.jpg String old_filename = UIHelper.getImageRoot(LNReaderApplication.getInstance().getApplicationContext()) + imageUrl.getFile().replace("thumb.php?", "thumb.php_"); File f = new File(old_filename); if(f.exists()) { f.renameTo(new File(decodedUrl)); Log.d(TAG, "Moved old thumbnail file from " + old_filename + " to " + decodedUrl); } } File tempFilename = new File(decodedUrl + ".!tmp"); File decodedFile = new File(decodedUrl); Log.d(TAG, "Start downloading image: " + imageUrl); // remove temp file if exist if (tempFilename.exists()) { tempFilename.delete(); } HttpURLConnection connection = null; if (imageUrl.getProtocol().toLowerCase().equals("https")) { boolean useKeyStore = UIHelper.getUseAppKeystore(LNReaderApplication.getInstance().getApplicationContext()); if (useKeyStore) { HttpsURLConnection.setDefaultSSLSocketFactory(Util.initMySecureSSL()); Log.w(TAG, "Using my https cert key store"); } HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); if (useKeyStore) https.setHostnameVerifier(Util.DO_NOT_VERIFY); connection = https; } else { connection = (HttpURLConnection) imageUrl.openConnection(); } int timeout = UIHelper.getIntFromPreferences(Constants.PREF_TIMEOUT, 60) * 1000; connection.setConnectTimeout(timeout); connection.setReadTimeout(timeout); connection.connect(); // this will be useful so that you can show a typical 0-100% progress bar // I'm not using it AT them moment, but don't remove, might be useful for real. int fileLength = connection.getContentLength(); // check saved filesize if already downloaded boolean download = true; if (decodedFile.exists()) { if (decodedFile.length() == fileLength) { download = false; Log.d(TAG, "File exists: " + decodedUrl + " Size: " + fileLength); } else { decodedFile.delete(); Log.d(TAG, "File exists but different size: " + decodedUrl + " " + decodedFile.length() + "!=" + fileLength); } } if (download) { for (int i = 0; i < UIHelper.getIntFromPreferences(Constants.PREF_RETRY, 3); ++i) { try { boolean increase_retry = PreferenceManager.getDefaultSharedPreferences(LNReaderApplication.getInstance().getApplicationContext()).getBoolean(Constants.PREF_INCREASE_RETRY, false); if (increase_retry) { timeout = timeout * (i + 1); connection.setConnectTimeout(timeout); connection.setReadTimeout(timeout); } // download the file input = new BufferedInputStream(imageUrl.openStream()); output = new FileOutputStream(tempFilename); byte data[] = new byte[1024]; long downloaded = 0; int count; while ((count = input.read(data)) != -1) { downloaded += count; // publishing the progress.... int progress = (int) (downloaded * 100 / fileLength); publishProgress(progress); // via notifier, C# style :) if (notifier != null) { DownloadCallbackEventData message = new DownloadCallbackEventData(null, downloaded, fileLength, source); message.setUrl(imageUrl.toString()); message.setFilePath(decodedUrl); notifier.onProgressCallback(message); } // Log.d(TAG, "Downloading: " + url + " " + progress + "%"); output.write(data, 0, count); } Log.d(TAG, "Filesize: " + downloaded); if (downloaded > 0) break; } catch (Exception ex) { Log.e(TAG, ex.getMessage(), ex); if (i > UIHelper.getIntFromPreferences(Constants.PREF_RETRY, 3)) { Log.e(TAG, "Failed to download: " + imageUrl.toString(), ex); throw ex; } else { if (notifier != null) { notifier.onProgressCallback(new CallbackEventData("Downloading: " + imageUrl + "\nRetry: " + i + "x", source)); } } } finally { if (output != null) { output.flush(); output.close(); } if (input != null) { input.close(); } } } // Rename file tempFilename.renameTo(decodedFile); Log.d(TAG, "Downloading image complete, saved to: " + decodedUrl); } ImageModel image = new ImageModel(); image.setName(filename); image.setUrl(imageUrl); image.setPath(filepath); image.setLastCheck(new Date()); image.setLastUpdate(new Date()); image.setParent(parent); image = NovelsDao.getInstance().insertImage(image); Log.d(TAG, "Complete Downloading: " + imageUrl); return image; } }