mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-09-10 19:03:21 +02:00
Minor changes
This commit is contained in:
parent
a30705f197
commit
bd8b9febd2
@ -7,6 +7,7 @@ import com.google.gson.reflect.TypeToken
|
|||||||
import com.jakewharton.disklrucache.DiskLruCache
|
import com.jakewharton.disklrucache.DiskLruCache
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page
|
import eu.kanade.tachiyomi.data.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.DiskUtils
|
import eu.kanade.tachiyomi.util.DiskUtils
|
||||||
|
import eu.kanade.tachiyomi.util.saveTo
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okio.Okio
|
import okio.Okio
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -194,10 +195,7 @@ class ChapterCache(private val context: Context) {
|
|||||||
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
||||||
|
|
||||||
// Get OutputStream and write image with Okio.
|
// Get OutputStream and write image with Okio.
|
||||||
Okio.buffer(Okio.sink(editor.newOutputStream(0))).use {
|
response.body().source().saveTo(editor.newOutputStream(0))
|
||||||
it.writeAll(response.body().source())
|
|
||||||
it.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
diskCache.flush()
|
diskCache.flush()
|
||||||
editor.commit()
|
editor.commit()
|
||||||
|
@ -33,7 +33,7 @@ class CoverCache(private val context: Context) {
|
|||||||
* @param headers headers included in Glide request.
|
* @param headers headers included in Glide request.
|
||||||
* @param onReady function to call when the image is ready
|
* @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.
|
// Check if url is empty.
|
||||||
if (thumbnailUrl.isNullOrEmpty())
|
if (thumbnailUrl.isNullOrEmpty())
|
||||||
return
|
return
|
||||||
@ -62,7 +62,7 @@ class CoverCache(private val context: Context) {
|
|||||||
* @param headers headers included in Glide request.
|
* @param headers headers included in Glide request.
|
||||||
* @param onReady function to call when the image is ready
|
* @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.
|
// Check if url is empty.
|
||||||
if (thumbnailUrl.isNullOrEmpty())
|
if (thumbnailUrl.isNullOrEmpty())
|
||||||
return
|
return
|
||||||
|
@ -95,6 +95,13 @@ public class Manga implements Serializable {
|
|||||||
return m;
|
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) {
|
public void setUrl(String url) {
|
||||||
this.url = UrlUtil.getPath(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.base.Source
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page
|
import eu.kanade.tachiyomi.data.source.model.Page
|
||||||
import eu.kanade.tachiyomi.event.DownloadChaptersEvent
|
import eu.kanade.tachiyomi.event.DownloadChaptersEvent
|
||||||
import eu.kanade.tachiyomi.util.DiskUtils
|
import eu.kanade.tachiyomi.util.*
|
||||||
import eu.kanade.tachiyomi.util.DynamicConcurrentMergeOperator
|
|
||||||
import eu.kanade.tachiyomi.util.UrlUtil
|
|
||||||
import eu.kanade.tachiyomi.util.toast
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -27,9 +24,7 @@ import rx.subjects.BehaviorSubject
|
|||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.FileReader
|
import java.io.FileReader
|
||||||
import java.io.IOException
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class DownloadManager(private val context: Context, private val sourceManager: SourceManager, private val preferences: PreferencesHelper) {
|
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
|
// Or if the page list already exists, start from the file
|
||||||
Observable.just(download.pages)
|
Observable.just(download.pages)
|
||||||
|
|
||||||
return Observable.defer<Download> { pageListObservable
|
return Observable.defer { pageListObservable
|
||||||
.doOnNext { pages ->
|
.doOnNext { pages ->
|
||||||
download.downloadedImages = 0
|
download.downloadedImages = 0
|
||||||
download.status = Download.DOWNLOADING
|
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> {
|
private fun downloadImage(page: Page, source: Source, directory: File, filename: String): Observable<Page> {
|
||||||
page.status = Page.DOWNLOAD_IMAGE
|
page.status = Page.DOWNLOAD_IMAGE
|
||||||
return source.getImageProgressResponse(page)
|
return source.getImageProgressResponse(page)
|
||||||
.flatMap({ resp ->
|
.flatMap {
|
||||||
try {
|
it.body().source().saveTo(File(directory, filename))
|
||||||
DiskUtils.saveBufferedSourceToDirectory(resp.body().source(), directory, filename)
|
|
||||||
} finally {
|
|
||||||
resp.body().close()
|
|
||||||
}
|
|
||||||
Observable.just(page)
|
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
|
// 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 chapterDir = getAbsoluteChapterDirectory(source, manga, chapter)
|
||||||
val pagesFile = File(chapterDir, PAGE_LIST_FILE)
|
val pagesFile = File(chapterDir, PAGE_LIST_FILE)
|
||||||
|
|
||||||
var reader: JsonReader? = null
|
return try {
|
||||||
try {
|
JsonReader(FileReader(pagesFile)).use {
|
||||||
if (pagesFile.exists()) {
|
val collectionType = object : TypeToken<List<Page>>() {}.type
|
||||||
reader = JsonReader(FileReader(pagesFile.absolutePath))
|
gson.fromJson(it, collectionType)
|
||||||
val collectionType = object : TypeToken<List<Page>>() {
|
|
||||||
|
|
||||||
}.type
|
|
||||||
return gson.fromJson<List<Page>>(reader, collectionType)
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e.cause, e.message)
|
null
|
||||||
} finally {
|
|
||||||
if (reader != null) try {
|
|
||||||
reader.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shortcut for the method above
|
// 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 chapterDir = getAbsoluteChapterDirectory(source, manga, chapter)
|
||||||
val pagesFile = File(chapterDir, PAGE_LIST_FILE)
|
val pagesFile = File(chapterDir, PAGE_LIST_FILE)
|
||||||
|
|
||||||
var out: FileOutputStream? = null
|
pagesFile.outputStream().use {
|
||||||
try {
|
try {
|
||||||
out = FileOutputStream(pagesFile)
|
it.write(gson.toJson(pages).toByteArray())
|
||||||
out.write(gson.toJson(pages).toByteArray())
|
it.flush()
|
||||||
out.flush()
|
} catch (e: Exception) {
|
||||||
} catch (e: IOException) {
|
Timber.e(e, e.message)
|
||||||
Timber.e(e.cause, e.message)
|
|
||||||
} finally {
|
|
||||||
if (out != null) try {
|
|
||||||
out.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,13 @@ import java.net.CookieStore
|
|||||||
|
|
||||||
class NetworkHelper(context: Context) {
|
class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
private val client: OkHttpClient
|
private val cacheDir = File(context.cacheDir, "network_cache")
|
||||||
private val forceCacheClient: OkHttpClient
|
|
||||||
|
|
||||||
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 ->
|
private val forceCacheInterceptor = { chain: Interceptor.Chain ->
|
||||||
val originalResponse = chain.proceed(chain.request())
|
val originalResponse = chain.proceed(chain.request())
|
||||||
@ -23,24 +26,17 @@ class NetworkHelper(context: Context) {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
private val client = OkHttpClient.Builder()
|
||||||
private val cacheDir = "network_cache"
|
.cookieJar(JavaNetCookieJar(cookieManager))
|
||||||
|
.cache(Cache(cacheDir, cacheSize))
|
||||||
|
.build()
|
||||||
|
|
||||||
init {
|
private val forceCacheClient = client.newBuilder()
|
||||||
val cacheDir = File(context.cacheDir, cacheDir)
|
.addNetworkInterceptor(forceCacheInterceptor)
|
||||||
|
.build()
|
||||||
|
|
||||||
cookieManager = CookieManager()
|
val cookies: CookieStore
|
||||||
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL)
|
get() = cookieManager.cookieStore
|
||||||
|
|
||||||
client = OkHttpClient.Builder()
|
|
||||||
.cookieJar(JavaNetCookieJar(cookieManager))
|
|
||||||
.cache(Cache(cacheDir, cacheSize))
|
|
||||||
.build()
|
|
||||||
|
|
||||||
forceCacheClient = client.newBuilder()
|
|
||||||
.addNetworkInterceptor(forceCacheInterceptor)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun request(request: Request, forceCache: Boolean = false): Observable<Response> {
|
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> {
|
fun requestBodyProgress(request: Request, listener: ProgressListener): Observable<Response> {
|
||||||
return Observable.fromCallable {
|
return Observable.fromCallable { requestBodyProgressBlocking(request, listener) }
|
||||||
val progressClient = client.newBuilder()
|
}
|
||||||
.cache(null)
|
|
||||||
.addNetworkInterceptor { chain ->
|
fun requestBodyProgressBlocking(request: Request, listener: ProgressListener): Response {
|
||||||
val originalResponse = chain.proceed(chain.request())
|
val progressClient = client.newBuilder()
|
||||||
originalResponse.newBuilder()
|
.cache(null)
|
||||||
.body(ProgressResponseBody(originalResponse.body(), listener))
|
.addNetworkInterceptor { chain ->
|
||||||
.build()
|
val originalResponse = chain.proceed(chain.request())
|
||||||
}
|
originalResponse.newBuilder()
|
||||||
.build()
|
.body(ProgressResponseBody(originalResponse.body(), listener))
|
||||||
|
.build()
|
||||||
progressClient.newCall(request).execute()
|
}
|
||||||
}
|
.build()
|
||||||
|
|
||||||
|
return progressClient.newCall(request).execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
val cookies: CookieStore
|
|
||||||
get() = cookieManager.cookieStore
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.data.source
|
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 EN = Language("EN", "English")
|
||||||
val RU = Language("Russian", "RU")
|
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;
|
package eu.kanade.tachiyomi.data.source.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
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 READY = 3;
|
||||||
public static final int ERROR = 4;
|
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) {
|
public Page(int pageNumber, String url, String imageUrl, String imagePath) {
|
||||||
this.pageNumber = pageNumber;
|
this.pageNumber = pageNumber;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
@ -32,10 +39,6 @@ public class Page implements ProgressListener {
|
|||||||
this.imagePath = imagePath;
|
this.imagePath = imagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page(int pageNumber, String url) {
|
|
||||||
this(pageNumber, url, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPageNumber() {
|
public int getPageNumber() {
|
||||||
return pageNumber;
|
return pageNumber;
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,6 @@ import java.io.IOException;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import okhttp3.internal.Util;
|
|
||||||
import okio.BufferedSink;
|
|
||||||
import okio.BufferedSource;
|
|
||||||
import okio.Okio;
|
|
||||||
|
|
||||||
public final class DiskUtils {
|
public final class DiskUtils {
|
||||||
|
|
||||||
private DiskUtils() {
|
private DiskUtils() {
|
||||||
@ -39,34 +34,7 @@ public final class DiskUtils {
|
|||||||
}
|
}
|
||||||
return sb.toString();
|
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) {
|
public static void deleteFiles(File inputFile) {
|
||||||
if (inputFile.isDirectory()) {
|
if (inputFile.isDirectory()) {
|
||||||
for (File childFile : inputFile.listFiles()) {
|
for (File childFile : inputFile.listFiles()) {
|
||||||
|
39
app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
Normal file
39
app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
Normal file
@ -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 com.dd.processbutton.iml.ActionProcessButton
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
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.base.listener.SimpleTextWatcher
|
||||||
|
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
||||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
|||||||
val dialog = MaterialDialog.Builder(activity)
|
val dialog = MaterialDialog.Builder(activity)
|
||||||
.customView(R.layout.pref_account_login, false)
|
.customView(R.layout.pref_account_login, false)
|
||||||
.negativeText(android.R.string.cancel)
|
.negativeText(android.R.string.cancel)
|
||||||
.build();
|
.build()
|
||||||
|
|
||||||
onViewCreated(dialog.view, savedState)
|
onViewCreated(dialog.view, savedState)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user