Minor changes
Cette révision appartient à :
Parent
a30705f197
révision
bd8b9febd2
10 fichiers modifiés avec 112 ajouts et 128 suppressions
|
@ -7,6 +7,7 @@ import com.google.gson.reflect.TypeToken
|
|||
import com.jakewharton.disklrucache.DiskLruCache
|
||||
import eu.kanade.tachiyomi.data.source.model.Page
|
||||
import eu.kanade.tachiyomi.util.DiskUtils
|
||||
import eu.kanade.tachiyomi.util.saveTo
|
||||
import okhttp3.Response
|
||||
import okio.Okio
|
||||
import rx.Observable
|
||||
|
@ -194,10 +195,7 @@ class ChapterCache(private val context: Context) {
|
|||
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
||||
|
||||
// Get OutputStream and write image with Okio.
|
||||
Okio.buffer(Okio.sink(editor.newOutputStream(0))).use {
|
||||
it.writeAll(response.body().source())
|
||||
it.flush()
|
||||
}
|
||||
response.body().source().saveTo(editor.newOutputStream(0))
|
||||
|
||||
diskCache.flush()
|
||||
editor.commit()
|
||||
|
|
|
@ -33,7 +33,7 @@ class CoverCache(private val context: Context) {
|
|||
* @param headers headers included in Glide request.
|
||||
* @param onReady function to call when the image is ready
|
||||
*/
|
||||
fun save(thumbnailUrl: String?, headers: LazyHeaders, onReady: ((File) -> Unit)? = null) {
|
||||
fun save(thumbnailUrl: String?, headers: LazyHeaders?, onReady: ((File) -> Unit)? = null) {
|
||||
// Check if url is empty.
|
||||
if (thumbnailUrl.isNullOrEmpty())
|
||||
return
|
||||
|
@ -62,7 +62,7 @@ class CoverCache(private val context: Context) {
|
|||
* @param headers headers included in Glide request.
|
||||
* @param onReady function to call when the image is ready
|
||||
*/
|
||||
fun saveOrLoadFromCache(thumbnailUrl: String?, headers: LazyHeaders, onReady: ((File) -> Unit)?) {
|
||||
fun saveOrLoadFromCache(thumbnailUrl: String?, headers: LazyHeaders?, onReady: ((File) -> Unit)?) {
|
||||
// Check if url is empty.
|
||||
if (thumbnailUrl.isNullOrEmpty())
|
||||
return
|
||||
|
|
|
@ -95,6 +95,13 @@ public class Manga implements Serializable {
|
|||
return m;
|
||||
}
|
||||
|
||||
public static Manga create(String pathUrl, int source) {
|
||||
Manga m = new Manga();
|
||||
m.url = pathUrl;
|
||||
m.source = source;
|
||||
return m;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = UrlUtil.getPath(url);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,7 @@ import eu.kanade.tachiyomi.data.source.SourceManager
|
|||
import eu.kanade.tachiyomi.data.source.base.Source
|
||||
import eu.kanade.tachiyomi.data.source.model.Page
|
||||
import eu.kanade.tachiyomi.event.DownloadChaptersEvent
|
||||
import eu.kanade.tachiyomi.util.DiskUtils
|
||||
import eu.kanade.tachiyomi.util.DynamicConcurrentMergeOperator
|
||||
import eu.kanade.tachiyomi.util.UrlUtil
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import eu.kanade.tachiyomi.util.*
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
|
@ -27,9 +24,7 @@ import rx.subjects.BehaviorSubject
|
|||
import rx.subjects.PublishSubject
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.FileReader
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class DownloadManager(private val context: Context, private val sourceManager: SourceManager, private val preferences: PreferencesHelper) {
|
||||
|
@ -176,7 +171,7 @@ class DownloadManager(private val context: Context, private val sourceManager: S
|
|||
// Or if the page list already exists, start from the file
|
||||
Observable.just(download.pages)
|
||||
|
||||
return Observable.defer<Download> { pageListObservable
|
||||
return Observable.defer { pageListObservable
|
||||
.doOnNext { pages ->
|
||||
download.downloadedImages = 0
|
||||
download.status = Download.DOWNLOADING
|
||||
|
@ -232,14 +227,11 @@ class DownloadManager(private val context: Context, private val sourceManager: S
|
|||
private fun downloadImage(page: Page, source: Source, directory: File, filename: String): Observable<Page> {
|
||||
page.status = Page.DOWNLOAD_IMAGE
|
||||
return source.getImageProgressResponse(page)
|
||||
.flatMap({ resp ->
|
||||
try {
|
||||
DiskUtils.saveBufferedSourceToDirectory(resp.body().source(), directory, filename)
|
||||
} finally {
|
||||
resp.body().close()
|
||||
}
|
||||
.flatMap {
|
||||
it.body().source().saveTo(File(directory, filename))
|
||||
Observable.just(page)
|
||||
}).retry(2)
|
||||
}
|
||||
.retry(2)
|
||||
}
|
||||
|
||||
// Public method to get the image from the filesystem. It does NOT provide any way to download the image
|
||||
|
@ -311,26 +303,14 @@ class DownloadManager(private val context: Context, private val sourceManager: S
|
|||
val chapterDir = getAbsoluteChapterDirectory(source, manga, chapter)
|
||||
val pagesFile = File(chapterDir, PAGE_LIST_FILE)
|
||||
|
||||
var reader: JsonReader? = null
|
||||
try {
|
||||
if (pagesFile.exists()) {
|
||||
reader = JsonReader(FileReader(pagesFile.absolutePath))
|
||||
val collectionType = object : TypeToken<List<Page>>() {
|
||||
|
||||
}.type
|
||||
return gson.fromJson<List<Page>>(reader, collectionType)
|
||||
return try {
|
||||
JsonReader(FileReader(pagesFile)).use {
|
||||
val collectionType = object : TypeToken<List<Page>>() {}.type
|
||||
gson.fromJson(it, collectionType)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e.cause, e.message)
|
||||
} finally {
|
||||
if (reader != null) try {
|
||||
reader.close()
|
||||
} catch (e: IOException) {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Shortcut for the method above
|
||||
|
@ -343,20 +323,13 @@ class DownloadManager(private val context: Context, private val sourceManager: S
|
|||
val chapterDir = getAbsoluteChapterDirectory(source, manga, chapter)
|
||||
val pagesFile = File(chapterDir, PAGE_LIST_FILE)
|
||||
|
||||
var out: FileOutputStream? = null
|
||||
try {
|
||||
out = FileOutputStream(pagesFile)
|
||||
out.write(gson.toJson(pages).toByteArray())
|
||||
out.flush()
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e.cause, e.message)
|
||||
} finally {
|
||||
if (out != null) try {
|
||||
out.close()
|
||||
} catch (e: IOException) {
|
||||
/* Do nothing */
|
||||
pagesFile.outputStream().use {
|
||||
try {
|
||||
it.write(gson.toJson(pages).toByteArray())
|
||||
it.flush()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, e.message)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,13 @@ import java.net.CookieStore
|
|||
|
||||
class NetworkHelper(context: Context) {
|
||||
|
||||
private val client: OkHttpClient
|
||||
private val forceCacheClient: OkHttpClient
|
||||
private val cacheDir = File(context.cacheDir, "network_cache")
|
||||
|
||||
private val cookieManager: CookieManager
|
||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
||||
|
||||
private val cookieManager = CookieManager().apply {
|
||||
setCookiePolicy(CookiePolicy.ACCEPT_ALL)
|
||||
}
|
||||
|
||||
private val forceCacheInterceptor = { chain: Interceptor.Chain ->
|
||||
val originalResponse = chain.proceed(chain.request())
|
||||
|
@ -23,24 +26,17 @@ class NetworkHelper(context: Context) {
|
|||
.build()
|
||||
}
|
||||
|
||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
||||
private val cacheDir = "network_cache"
|
||||
private val client = OkHttpClient.Builder()
|
||||
.cookieJar(JavaNetCookieJar(cookieManager))
|
||||
.cache(Cache(cacheDir, cacheSize))
|
||||
.build()
|
||||
|
||||
init {
|
||||
val cacheDir = File(context.cacheDir, cacheDir)
|
||||
private val forceCacheClient = client.newBuilder()
|
||||
.addNetworkInterceptor(forceCacheInterceptor)
|
||||
.build()
|
||||
|
||||
cookieManager = CookieManager()
|
||||
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL)
|
||||
|
||||
client = OkHttpClient.Builder()
|
||||
.cookieJar(JavaNetCookieJar(cookieManager))
|
||||
.cache(Cache(cacheDir, cacheSize))
|
||||
.build()
|
||||
|
||||
forceCacheClient = client.newBuilder()
|
||||
.addNetworkInterceptor(forceCacheInterceptor)
|
||||
.build()
|
||||
}
|
||||
val cookies: CookieStore
|
||||
get() = cookieManager.cookieStore
|
||||
|
||||
@JvmOverloads
|
||||
fun request(request: Request, forceCache: Boolean = false): Observable<Response> {
|
||||
|
@ -59,22 +55,22 @@ class NetworkHelper(context: Context) {
|
|||
}
|
||||
|
||||
fun requestBodyProgress(request: Request, listener: ProgressListener): Observable<Response> {
|
||||
return Observable.fromCallable {
|
||||
val progressClient = client.newBuilder()
|
||||
.cache(null)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val originalResponse = chain.proceed(chain.request())
|
||||
originalResponse.newBuilder()
|
||||
.body(ProgressResponseBody(originalResponse.body(), listener))
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
|
||||
progressClient.newCall(request).execute()
|
||||
}
|
||||
return Observable.fromCallable { requestBodyProgressBlocking(request, listener) }
|
||||
}
|
||||
|
||||
fun requestBodyProgressBlocking(request: Request, listener: ProgressListener): Response {
|
||||
val progressClient = client.newBuilder()
|
||||
.cache(null)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val originalResponse = chain.proceed(chain.request())
|
||||
originalResponse.newBuilder()
|
||||
.body(ProgressResponseBody(originalResponse.body(), listener))
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
|
||||
return progressClient.newCall(request).execute()
|
||||
}
|
||||
|
||||
val cookies: CookieStore
|
||||
get() = cookieManager.cookieStore
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package eu.kanade.tachiyomi.data.source
|
||||
|
||||
class Language(val lang: String, val code: String)
|
||||
class Language(val code: String, val lang: String)
|
||||
|
||||
val EN = Language("English", "EN")
|
||||
val RU = Language("Russian", "RU")
|
||||
val EN = Language("EN", "English")
|
||||
val RU = Language("RU", "Russian")
|
||||
|
||||
fun getLanguages(): List<Language> = listOf(EN, RU)
|
||||
fun getLanguages() = listOf(EN, RU)
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.tachiyomi.data.source.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
||||
|
@ -25,6 +24,14 @@ public class Page implements ProgressListener {
|
|||
public static final int READY = 3;
|
||||
public static final int ERROR = 4;
|
||||
|
||||
public Page(int pageNumber, String url) {
|
||||
this(pageNumber, url, null, null);
|
||||
}
|
||||
|
||||
public Page(int pageNumber, String url, String imageUrl) {
|
||||
this(pageNumber, url, imageUrl, null);
|
||||
}
|
||||
|
||||
public Page(int pageNumber, String url, String imageUrl, String imagePath) {
|
||||
this.pageNumber = pageNumber;
|
||||
this.url = url;
|
||||
|
@ -32,10 +39,6 @@ public class Page implements ProgressListener {
|
|||
this.imagePath = imagePath;
|
||||
}
|
||||
|
||||
public Page(int pageNumber, String url) {
|
||||
this(pageNumber, url, null, null);
|
||||
}
|
||||
|
||||
public int getPageNumber() {
|
||||
return pageNumber;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,6 @@ import java.io.IOException;
|
|||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import okhttp3.internal.Util;
|
||||
import okio.BufferedSink;
|
||||
import okio.BufferedSource;
|
||||
import okio.Okio;
|
||||
|
||||
public final class DiskUtils {
|
||||
|
||||
private DiskUtils() {
|
||||
|
@ -39,34 +34,7 @@ public final class DiskUtils {
|
|||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static File saveBufferedSourceToDirectory(BufferedSource bufferedSource, File directory, String name) throws IOException {
|
||||
createDirectory(directory);
|
||||
|
||||
File writeFile = new File(directory, name);
|
||||
if (writeFile.exists()) {
|
||||
if (writeFile.delete()) {
|
||||
writeFile = new File(directory, name);
|
||||
} else {
|
||||
throw new IOException("Failed Deleting Existing File for Overwrite");
|
||||
}
|
||||
}
|
||||
|
||||
BufferedSink bufferedSink = null;
|
||||
try {
|
||||
bufferedSink = Okio.buffer(Okio.sink(writeFile));
|
||||
bufferedSink.writeAll(bufferedSource);
|
||||
Util.closeQuietly(bufferedSink);
|
||||
} catch (Exception e) {
|
||||
Util.closeQuietly(bufferedSink);
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
writeFile.delete();
|
||||
throw new IOException("Unable to save image");
|
||||
}
|
||||
|
||||
return writeFile;
|
||||
}
|
||||
|
||||
|
||||
public static void deleteFiles(File inputFile) {
|
||||
if (inputFile.isDirectory()) {
|
||||
for (File childFile : inputFile.listFiles()) {
|
||||
|
|
39
app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
Fichier normal
39
app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
Fichier normal
|
@ -0,0 +1,39 @@
|
|||
package eu.kanade.tachiyomi.util
|
||||
|
||||
import okio.BufferedSource
|
||||
import okio.Okio
|
||||
import java.io.File
|
||||
import java.io.OutputStream
|
||||
|
||||
/**
|
||||
* Saves the given source to a file and closes it. Directories will be created if needed.
|
||||
*
|
||||
* @param file the file where the source is copied.
|
||||
*/
|
||||
fun BufferedSource.saveTo(file: File) {
|
||||
try {
|
||||
// Create parent dirs if needed
|
||||
file.parentFile.mkdirs()
|
||||
|
||||
// Copy to destination
|
||||
saveTo(file.outputStream())
|
||||
} catch (e: Exception) {
|
||||
close()
|
||||
file.delete()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given source to an output stream and closes both resources.
|
||||
*
|
||||
* @param stream the stream where the source is copied.
|
||||
*/
|
||||
fun BufferedSource.saveTo(stream: OutputStream) {
|
||||
use { input ->
|
||||
Okio.buffer(Okio.sink(stream)).use {
|
||||
it.writeAll(input)
|
||||
it.flush()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,8 +11,8 @@ import com.afollestad.materialdialogs.MaterialDialog
|
|||
import com.dd.processbutton.iml.ActionProcessButton
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
||||
import eu.kanade.tachiyomi.ui.base.listener.SimpleTextWatcher
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||
import rx.Subscription
|
||||
|
||||
|
@ -30,7 +30,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
|||
val dialog = MaterialDialog.Builder(activity)
|
||||
.customView(R.layout.pref_account_login, false)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.build();
|
||||
.build()
|
||||
|
||||
onViewCreated(dialog.view, savedState)
|
||||
|
||||
|
|
Référencer dans un nouveau ticket