/* * Copyright (C) 2013 Alex Kuiper * * This file is part of PageTurner * * PageTurner 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. * * PageTurner 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 PageTurner. If not, see <http://www.gnu.org/licenses/>.* */ package net.nightwhistler.pageturner.catalog; import android.content.Context; import android.os.AsyncTask; import com.google.inject.Inject; import jedi.option.None; import jedi.option.Option; import net.nightwhistler.pageturner.Configuration; import net.nightwhistler.pageturner.library.LibraryService; import net.nightwhistler.pageturner.scheduling.QueueableAsyncTask; import nl.siegmann.epublib.domain.Book; import nl.siegmann.epublib.epub.EpubReader; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.Charset; import static jedi.functional.FunctionalPrimitives.isEmpty; import static jedi.option.Options.none; public class DownloadFileTask extends QueueableAsyncTask<String, Long, Void> { private File destFile; private Exception failure; private DownloadFileCallback callBack; @Inject private Context context; @Inject private Configuration config; @Inject private LibraryService libraryService; @Inject private HttpClient httpClient; private static final Logger LOG = LoggerFactory.getLogger("DownloadFileTask"); public interface DownloadFileCallback { void onDownloadStart(); void downloadSuccess(File destinationFile); void downloadFailed(); void progressUpdate( long progress, long total, int percentage ); } DownloadFileTask(){} public void setCallBack(DownloadFileCallback callBack) { this.callBack = callBack; } @Override public void doOnPreExecute() { callBack.onDownloadStart(); } @Override public Option<Void> doInBackground(String... params) { try { String url = params[0]; LOG.debug("Downloading: " + url); String fileName = url.substring(url.lastIndexOf('/') + 1); fileName = fileName.replaceAll("\\?|&|=", "_"); HttpGet get = new HttpGet(url); get.setHeader("User-Agent", config.getUserAgent() ); HttpResponse response = httpClient.execute(get); if (response.getStatusLine().getStatusCode() == 200) { Option<File> destFolderOption = config.getDownloadsFolder(); if ( isEmpty(destFolderOption) ) { throw new IllegalStateException("Could not get download folder!"); } File destFolder = destFolderOption.unsafeGet(); if (!destFolder.exists()) { destFolder.mkdirs(); } /** * Make sure we always store downloaded files as .epub, * so they show up in scans later on. */ if ( ! fileName.endsWith(".epub") ) { fileName = fileName + ".epub"; } // Default Charset for android is UTF-8* String charsetName = Charset.defaultCharset().name(); if (!Charset.isSupported(charsetName)) { LOG.warn("{} is not a supported Charset. Will fall back to UTF-8", charsetName); charsetName = "UTF-8"; } try { destFile = new File(destFolder, URLDecoder.decode(fileName,charsetName)); } catch (UnsupportedEncodingException e) { // Won't ever reach here throw new AssertionError(e); } if (destFile.exists()) { destFile.delete(); } // lenghtOfFile is used for calculating download progress long lenghtOfFile = response.getEntity().getContentLength(); // this is where the file will be seen after the download FileOutputStream f = new FileOutputStream(destFile); try { // file input is from the url InputStream in = response.getEntity().getContent(); // here's the download code byte[] buffer = new byte[1024]; int len1 = 0; long total = 0; while ((len1 = in.read(buffer)) > 0 && ! isCancelled() ) { // Make sure the user can cancel the download. if (isCancelled()) { return new None(); } total += len1; publishProgress(total, lenghtOfFile, (long) ((total * 100) / lenghtOfFile)); f.write(buffer, 0, len1); } } finally { f.close(); } if ( ! isCancelled() ) { //FIXME: This doesn't belong here really... Book book = new EpubReader().readEpubLazy( destFile.getAbsolutePath(), "UTF-8" ); libraryService.storeBook(destFile.getAbsolutePath(), book, false, config.getCopyToLibraryOnScan() ); } } else { this.failure = new RuntimeException(response .getStatusLine().getReasonPhrase()); LOG.error("Download failed: " + response.getStatusLine().getReasonPhrase()); } } catch (Exception e) { LOG.error("Download failed.", e); this.failure = e; } return none(); } @Override public void doOnProgressUpdate(Long... values) { callBack.progressUpdate(values[0], values[1], values[2].intValue() ); } @Override public void doOnPostExecute(Option<Void> unused) { if (!isCancelled() && failure == null) { callBack.downloadSuccess(destFile); } else if (failure != null) { callBack.downloadFailed(); } } }