mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-22 22:41:48 +01:00
Fix network unsubscription crashes, refactor network methods
This commit is contained in:
parent
79bb207a8d
commit
efd36388b0
@ -91,7 +91,6 @@ kapt {
|
|||||||
dependencies {
|
dependencies {
|
||||||
final SUPPORT_LIBRARY_VERSION = '23.4.0'
|
final SUPPORT_LIBRARY_VERSION = '23.4.0'
|
||||||
final DAGGER_VERSION = '2.4'
|
final DAGGER_VERSION = '2.4'
|
||||||
final OKHTTP_VERSION = '3.2.0'
|
|
||||||
final RETROFIT_VERSION = '2.0.2'
|
final RETROFIT_VERSION = '2.0.2'
|
||||||
final NUCLEUS_VERSION = '3.0.0'
|
final NUCLEUS_VERSION = '3.0.0'
|
||||||
final STORIO_VERSION = '1.8.0'
|
final STORIO_VERSION = '1.8.0'
|
||||||
@ -118,7 +117,7 @@ dependencies {
|
|||||||
compile 'com.f2prateek.rx.preferences:rx-preferences:1.0.1'
|
compile 'com.f2prateek.rx.preferences:rx-preferences:1.0.1'
|
||||||
|
|
||||||
// Network client
|
// Network client
|
||||||
compile "com.squareup.okhttp3:okhttp:$OKHTTP_VERSION"
|
compile "com.squareup.okhttp3:okhttp:3.3.0"
|
||||||
|
|
||||||
// REST
|
// REST
|
||||||
compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
|
compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
|
||||||
@ -141,7 +140,7 @@ dependencies {
|
|||||||
compile 'com.jakewharton:disklrucache:2.0.2'
|
compile 'com.jakewharton:disklrucache:2.0.2'
|
||||||
|
|
||||||
// Parse HTML
|
// Parse HTML
|
||||||
compile 'org.jsoup:jsoup:1.9.1'
|
compile 'org.jsoup:jsoup:1.9.2'
|
||||||
|
|
||||||
// Changelog
|
// Changelog
|
||||||
compile 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
|
compile 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
|
||||||
@ -176,9 +175,7 @@ dependencies {
|
|||||||
compile 'eu.davidea:flexible-adapter:4.2.0'
|
compile 'eu.davidea:flexible-adapter:4.2.0'
|
||||||
compile 'com.nononsenseapps:filepicker:2.5.2'
|
compile 'com.nononsenseapps:filepicker:2.5.2'
|
||||||
compile 'com.github.amulyakhare:TextDrawable:558677e'
|
compile 'com.github.amulyakhare:TextDrawable:558677e'
|
||||||
compile('com.github.afollestad.material-dialogs:core:0.8.5.5@aar') {
|
compile 'com.afollestad.material-dialogs:core:0.8.5.9'
|
||||||
transitive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
|
@ -28,7 +28,7 @@ class AppGlideModule : GlideModule {
|
|||||||
override fun registerComponents(context: Context, glide: Glide) {
|
override fun registerComponents(context: Context, glide: Glide) {
|
||||||
App.get(context).component.inject(this)
|
App.get(context).component.inject(this)
|
||||||
glide.register(GlideUrl::class.java, InputStream::class.java,
|
glide.register(GlideUrl::class.java, InputStream::class.java,
|
||||||
OkHttpUrlLoader.Factory(networkHelper.defaultClient))
|
OkHttpUrlLoader.Factory(networkHelper.client))
|
||||||
glide.register(Manga::class.java, InputStream::class.java, MangaModelLoader.Factory())
|
glide.register(Manga::class.java, InputStream::class.java, MangaModelLoader.Factory())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ import android.util.Xml
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaSync
|
import eu.kanade.tachiyomi.data.database.models.MangaSync
|
||||||
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService
|
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService
|
||||||
import eu.kanade.tachiyomi.data.network.get
|
import eu.kanade.tachiyomi.data.network.GET
|
||||||
import eu.kanade.tachiyomi.data.network.post
|
import eu.kanade.tachiyomi.data.network.POST
|
||||||
import eu.kanade.tachiyomi.util.selectInt
|
import eu.kanade.tachiyomi.util.selectInt
|
||||||
import eu.kanade.tachiyomi.util.selectText
|
import eu.kanade.tachiyomi.util.selectText
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
@ -65,7 +65,8 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
|
|||||||
|
|
||||||
override fun login(username: String, password: String): Observable<Boolean> {
|
override fun login(username: String, password: String): Observable<Boolean> {
|
||||||
createHeaders(username, password)
|
createHeaders(username, password)
|
||||||
return networkService.request(get(getLoginUrl(), headers))
|
return networkService.request(GET(getLoginUrl(), headers))
|
||||||
|
.doOnNext { it.close() }
|
||||||
.map { it.code() == 200 }
|
.map { it.code() == 200 }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun search(query: String): Observable<List<MangaSync>> {
|
fun search(query: String): Observable<List<MangaSync>> {
|
||||||
return networkService.request(get(getSearchUrl(query), headers))
|
return networkService.request(GET(getSearchUrl(query), headers))
|
||||||
.map { Jsoup.parse(it.body().string()) }
|
.map { Jsoup.parse(it.body().string()) }
|
||||||
.flatMap { Observable.from(it.select("entry")) }
|
.flatMap { Observable.from(it.select("entry")) }
|
||||||
.filter { it.select("type").text() != "Novel" }
|
.filter { it.select("type").text() != "Novel" }
|
||||||
@ -102,7 +103,7 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
|
|||||||
|
|
||||||
// MAL doesn't support score with decimals
|
// MAL doesn't support score with decimals
|
||||||
fun getList(): Observable<List<MangaSync>> {
|
fun getList(): Observable<List<MangaSync>> {
|
||||||
return networkService.request(get(getListUrl(username), headers), networkService.forceCacheClient)
|
return networkService.request(GET(getListUrl(username), headers), networkService.forceCacheClient)
|
||||||
.map { Jsoup.parse(it.body().string()) }
|
.map { Jsoup.parse(it.body().string()) }
|
||||||
.flatMap { Observable.from(it.select("manga")) }
|
.flatMap { Observable.from(it.select("manga")) }
|
||||||
.map {
|
.map {
|
||||||
@ -130,7 +131,7 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
|
|||||||
if (manga.total_chapters != 0 && manga.last_chapter_read == manga.total_chapters) {
|
if (manga.total_chapters != 0 && manga.last_chapter_read == manga.total_chapters) {
|
||||||
manga.status = COMPLETED
|
manga.status = COMPLETED
|
||||||
}
|
}
|
||||||
networkService.request(post(getUpdateUrl(manga), headers, getMangaPostPayload(manga)))
|
networkService.request(POST(getUpdateUrl(manga), headers, getMangaPostPayload(manga)))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -144,7 +145,7 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
|
|||||||
|
|
||||||
override fun add(manga: MangaSync): Observable<Response> {
|
override fun add(manga: MangaSync): Observable<Response> {
|
||||||
return Observable.defer {
|
return Observable.defer {
|
||||||
networkService.request(post(getAddUrl(manga), headers, getMangaPostPayload(manga)))
|
networkService.request(POST(getAddUrl(manga), headers, getMangaPostPayload(manga)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class CloudflareInterceptor(private val cookies: PersistentCookieStore) : Interc
|
|||||||
|
|
||||||
// Check if we already solved a challenge
|
// Check if we already solved a challenge
|
||||||
if (response.code() != 502 &&
|
if (response.code() != 502 &&
|
||||||
cookies.get(response.request().url()).find { it.name() == "cf_clearance" } != null) {
|
cookies.get(response.request().url()).any { it.name() == "cf_clearance" }) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ class CloudflareInterceptor(private val cookies: PersistentCookieStore) : Interc
|
|||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
val referer = originalRequest.url().toString()
|
val referer = originalRequest.url().toString()
|
||||||
return get(url, originalRequest.headers().newBuilder().add("Referer", referer).build())
|
return GET(url, originalRequest.headers().newBuilder().add("Referer", referer).build())
|
||||||
} finally {
|
} finally {
|
||||||
duktape.close()
|
duktape.close()
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package eu.kanade.tachiyomi.data.network
|
package eu.kanade.tachiyomi.data.network
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import okhttp3.*
|
import okhttp3.Cache
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subscriptions.Subscriptions
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class NetworkHelper(context: Context) {
|
class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
@ -16,74 +16,30 @@ class NetworkHelper(context: Context) {
|
|||||||
|
|
||||||
private val cookieManager = PersistentCookieJar(context)
|
private val cookieManager = PersistentCookieJar(context)
|
||||||
|
|
||||||
val defaultClient = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.cookieJar(cookieManager)
|
.cookieJar(cookieManager)
|
||||||
.cache(Cache(cacheDir, cacheSize))
|
.cache(Cache(cacheDir, cacheSize))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val forceCacheClient = defaultClient.newBuilder()
|
val forceCacheClient = client.newBuilder()
|
||||||
.addNetworkInterceptor({ chain ->
|
.addNetworkInterceptor { chain ->
|
||||||
val originalResponse = chain.proceed(chain.request())
|
val originalResponse = chain.proceed(chain.request())
|
||||||
originalResponse.newBuilder()
|
originalResponse.newBuilder()
|
||||||
.removeHeader("Pragma")
|
.removeHeader("Pragma")
|
||||||
.header("Cache-Control", "max-age=" + 600)
|
.header("Cache-Control", "max-age=600")
|
||||||
.build()
|
.build()
|
||||||
})
|
}
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val cloudflareClient = defaultClient.newBuilder()
|
val cloudflareClient = client.newBuilder()
|
||||||
.addInterceptor(CloudflareInterceptor(cookies))
|
.addInterceptor(CloudflareInterceptor(cookies))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val cookies: PersistentCookieStore
|
val cookies: PersistentCookieStore
|
||||||
get() = cookieManager.store
|
get() = cookieManager.store
|
||||||
|
|
||||||
fun request(request: Request, client: OkHttpClient = defaultClient): Observable<Response> {
|
fun request(request: Request, client: OkHttpClient = this.client): Observable<Response> {
|
||||||
return Observable.create { subscriber ->
|
return client.newCall(request).asObservable()
|
||||||
val call = client.newCall(request)
|
|
||||||
subscriber.add(Subscriptions.create {
|
|
||||||
call.cancel()
|
|
||||||
Timber.i("Cancel call on thread ${Thread.currentThread().id}")
|
|
||||||
})
|
|
||||||
|
|
||||||
call.enqueue(object : Callback {
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
|
||||||
if (!subscriber.isUnsubscribed) {
|
|
||||||
subscriber.add(Subscriptions.create {
|
|
||||||
response.body().close()
|
|
||||||
Timber.i("Close body on thread ${Thread.currentThread().id}")
|
|
||||||
})
|
|
||||||
subscriber.onNext(response)
|
|
||||||
Timber.i("Emit response on thread ${Thread.currentThread().id}")
|
|
||||||
subscriber.onCompleted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call, error: IOException) {
|
|
||||||
if (!subscriber.isUnsubscribed) {
|
|
||||||
subscriber.onError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestBodyProgress(request: Request, listener: ProgressListener): Observable<Response> {
|
|
||||||
return Observable.fromCallable { requestBodyProgressBlocking(request, listener) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestBodyProgressBlocking(request: Request, listener: ProgressListener): Response {
|
|
||||||
val progressClient = defaultClient.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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.network
|
||||||
|
|
||||||
|
import okhttp3.Call
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import rx.Observable
|
||||||
|
import rx.subscriptions.Subscriptions
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
fun Call.asObservable(): Observable<Response> {
|
||||||
|
return Observable.create { subscriber ->
|
||||||
|
subscriber.add(Subscriptions.create { cancel() })
|
||||||
|
|
||||||
|
try {
|
||||||
|
val response = execute()
|
||||||
|
if (!subscriber.isUnsubscribed) {
|
||||||
|
subscriber.onNext(response)
|
||||||
|
subscriber.onCompleted()
|
||||||
|
}
|
||||||
|
} catch (error: IOException) {
|
||||||
|
if (!subscriber.isUnsubscribed) {
|
||||||
|
subscriber.onError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
|
||||||
|
val progressClient = newBuilder()
|
||||||
|
.cache(null)
|
||||||
|
.addNetworkInterceptor { chain ->
|
||||||
|
val originalResponse = chain.proceed(chain.request())
|
||||||
|
originalResponse.newBuilder()
|
||||||
|
.body(ProgressResponseBody(originalResponse.body(), listener))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return progressClient.newCall(request)
|
||||||
|
}
|
@ -70,6 +70,6 @@ class PersistentCookieStore(context: Context) {
|
|||||||
return cookieMap[url].orEmpty().filter { !it.hasExpired() }
|
return cookieMap[url].orEmpty().filter { !it.hasExpired() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Cookie.hasExpired() = System.currentTimeMillis() >= expiresAt()
|
private fun Cookie.hasExpired() = System.currentTimeMillis() >= expiresAt()
|
||||||
|
|
||||||
}
|
}
|
@ -7,8 +7,7 @@ private val DEFAULT_CACHE_CONTROL = CacheControl.Builder().maxAge(10, MINUTES).b
|
|||||||
private val DEFAULT_HEADERS = Headers.Builder().build()
|
private val DEFAULT_HEADERS = Headers.Builder().build()
|
||||||
private val DEFAULT_BODY: RequestBody = FormBody.Builder().build()
|
private val DEFAULT_BODY: RequestBody = FormBody.Builder().build()
|
||||||
|
|
||||||
@JvmOverloads
|
fun GET(url: String,
|
||||||
fun get(url: String,
|
|
||||||
headers: Headers = DEFAULT_HEADERS,
|
headers: Headers = DEFAULT_HEADERS,
|
||||||
cache: CacheControl = DEFAULT_CACHE_CONTROL): Request {
|
cache: CacheControl = DEFAULT_CACHE_CONTROL): Request {
|
||||||
|
|
||||||
@ -19,8 +18,7 @@ fun get(url: String,
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
fun POST(url: String,
|
||||||
fun post(url: String,
|
|
||||||
headers: Headers = DEFAULT_HEADERS,
|
headers: Headers = DEFAULT_HEADERS,
|
||||||
body: RequestBody = DEFAULT_BODY,
|
body: RequestBody = DEFAULT_BODY,
|
||||||
cache: CacheControl = DEFAULT_CACHE_CONTROL): Request {
|
cache: CacheControl = DEFAULT_CACHE_CONTROL): Request {
|
@ -5,8 +5,10 @@ import eu.kanade.tachiyomi.App
|
|||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.network.GET
|
||||||
import eu.kanade.tachiyomi.data.network.NetworkHelper
|
import eu.kanade.tachiyomi.data.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.data.network.get
|
import eu.kanade.tachiyomi.data.network.asObservable
|
||||||
|
import eu.kanade.tachiyomi.data.network.newCallWithProgress
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.source.Language
|
import eu.kanade.tachiyomi.data.source.Language
|
||||||
import eu.kanade.tachiyomi.data.source.Source
|
import eu.kanade.tachiyomi.data.source.Source
|
||||||
@ -57,7 +59,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
* Default network client for doing requests.
|
* Default network client for doing requests.
|
||||||
*/
|
*/
|
||||||
open val client: OkHttpClient
|
open val client: OkHttpClient
|
||||||
get() = network.defaultClient
|
get() = network.client
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Inject dependencies.
|
// Inject dependencies.
|
||||||
@ -114,7 +116,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
if (page.page == 1) {
|
if (page.page == 1) {
|
||||||
page.url = popularMangaInitialUrl()
|
page.url = popularMangaInitialUrl()
|
||||||
}
|
}
|
||||||
return get(page.url, headers)
|
return GET(page.url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,7 +161,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
if (page.page == 1) {
|
if (page.page == 1) {
|
||||||
page.url = searchMangaInitialUrl(query)
|
page.url = searchMangaInitialUrl(query)
|
||||||
}
|
}
|
||||||
return get(page.url, headers)
|
return GET(page.url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -201,7 +203,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
* @param manga the manga to be updated.
|
* @param manga the manga to be updated.
|
||||||
*/
|
*/
|
||||||
open protected fun mangaDetailsRequest(manga: Manga): Request {
|
open protected fun mangaDetailsRequest(manga: Manga): Request {
|
||||||
return get(baseUrl + manga.url, headers)
|
return GET(baseUrl + manga.url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -236,7 +238,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
* @param manga the manga to look for chapters.
|
* @param manga the manga to look for chapters.
|
||||||
*/
|
*/
|
||||||
open protected fun chapterListRequest(manga: Manga): Request {
|
open protected fun chapterListRequest(manga: Manga): Request {
|
||||||
return get(baseUrl + manga.url, headers)
|
return GET(baseUrl + manga.url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,7 +283,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
* @param chapter the chapter whose page list has to be fetched
|
* @param chapter the chapter whose page list has to be fetched
|
||||||
*/
|
*/
|
||||||
open protected fun pageListRequest(chapter: Chapter): Request {
|
open protected fun pageListRequest(chapter: Chapter): Request {
|
||||||
return get(baseUrl + chapter.url, headers)
|
return GET(baseUrl + chapter.url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -321,7 +323,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
* @param page the chapter whose page list has to be fetched
|
* @param page the chapter whose page list has to be fetched
|
||||||
*/
|
*/
|
||||||
open protected fun imageUrlRequest(page: Page): Request {
|
open protected fun imageUrlRequest(page: Page): Request {
|
||||||
return get(page.url, headers)
|
return GET(page.url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -347,11 +349,12 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
*
|
*
|
||||||
* @param page the page whose source image has to be downloaded.
|
* @param page the page whose source image has to be downloaded.
|
||||||
*/
|
*/
|
||||||
fun imageResponse(page: Page): Observable<Response> = network
|
fun imageResponse(page: Page): Observable<Response> = client
|
||||||
.requestBodyProgress(imageRequest(page), page)
|
.newCallWithProgress(imageRequest(page), page)
|
||||||
|
.asObservable()
|
||||||
.doOnNext {
|
.doOnNext {
|
||||||
if (!it.isSuccessful) {
|
if (!it.isSuccessful) {
|
||||||
it.body().close()
|
it.close()
|
||||||
throw RuntimeException("Not a valid response")
|
throw RuntimeException("Not a valid response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,7 +366,7 @@ abstract class OnlineSource(context: Context) : Source {
|
|||||||
* @param page the chapter whose page list has to be fetched
|
* @param page the chapter whose page list has to be fetched
|
||||||
*/
|
*/
|
||||||
open protected fun imageRequest(page: Page): Request {
|
open protected fun imageRequest(page: Page): Request {
|
||||||
return get(page.imageUrl, headers)
|
return GET(page.imageUrl, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.data.source.online
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.network.get
|
import eu.kanade.tachiyomi.data.network.GET
|
||||||
import eu.kanade.tachiyomi.data.network.post
|
import eu.kanade.tachiyomi.data.network.POST
|
||||||
import eu.kanade.tachiyomi.data.source.getLanguages
|
import eu.kanade.tachiyomi.data.source.getLanguages
|
||||||
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page
|
import eu.kanade.tachiyomi.data.source.model.Page
|
||||||
@ -32,7 +32,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con
|
|||||||
|
|
||||||
override val client = when(map.client) {
|
override val client = when(map.client) {
|
||||||
"cloudflare" -> network.cloudflareClient
|
"cloudflare" -> network.cloudflareClient
|
||||||
else -> network.defaultClient
|
else -> network.client
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id = map.id.let {
|
override val id = map.id.let {
|
||||||
@ -44,8 +44,8 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con
|
|||||||
page.url = popularMangaInitialUrl()
|
page.url = popularMangaInitialUrl()
|
||||||
}
|
}
|
||||||
return when (map.popular.method?.toLowerCase()) {
|
return when (map.popular.method?.toLowerCase()) {
|
||||||
"post" -> post(page.url, headers, map.popular.createForm())
|
"post" -> POST(page.url, headers, map.popular.createForm())
|
||||||
else -> get(page.url, headers)
|
else -> GET(page.url, headers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +74,8 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con
|
|||||||
page.url = searchMangaInitialUrl(query)
|
page.url = searchMangaInitialUrl(query)
|
||||||
}
|
}
|
||||||
return when (map.search.method?.toLowerCase()) {
|
return when (map.search.method?.toLowerCase()) {
|
||||||
"post" -> post(page.url, headers, map.search.createForm())
|
"post" -> POST(page.url, headers, map.search.createForm())
|
||||||
else -> get(page.url, headers)
|
else -> GET(page.url, headers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import android.net.Uri
|
|||||||
import android.text.Html
|
import android.text.Html
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.network.get
|
import eu.kanade.tachiyomi.data.network.GET
|
||||||
import eu.kanade.tachiyomi.data.network.post
|
import eu.kanade.tachiyomi.data.network.POST
|
||||||
import eu.kanade.tachiyomi.data.source.EN
|
import eu.kanade.tachiyomi.data.source.EN
|
||||||
import eu.kanade.tachiyomi.data.source.Language
|
import eu.kanade.tachiyomi.data.source.Language
|
||||||
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
||||||
@ -20,7 +20,6 @@ import org.jsoup.nodes.Document
|
|||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URISyntaxException
|
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -58,12 +57,12 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
|
|||||||
|
|
||||||
override fun mangaDetailsRequest(manga: Manga): Request {
|
override fun mangaDetailsRequest(manga: Manga): Request {
|
||||||
val mangaId = manga.url.substringAfterLast("r")
|
val mangaId = manga.url.substringAfterLast("r")
|
||||||
return get("$baseUrl/comic_pop?id=$mangaId", headers)
|
return GET("$baseUrl/comic_pop?id=$mangaId", headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: Chapter): Request {
|
override fun pageListRequest(chapter: Chapter): Request {
|
||||||
val id = chapter.url.substringAfterLast("#")
|
val id = chapter.url.substringAfterLast("#")
|
||||||
return get("$baseUrl/areader?id=$id&p=1", headers)
|
return GET("$baseUrl/areader?id=$id&p=1", headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlRequest(page: Page): Request {
|
override fun imageUrlRequest(page: Page): Request {
|
||||||
@ -71,7 +70,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
|
|||||||
val start = pageUrl.indexOf("#") + 1
|
val start = pageUrl.indexOf("#") + 1
|
||||||
val end = pageUrl.indexOf("_", start)
|
val end = pageUrl.indexOf("_", start)
|
||||||
val id = pageUrl.substring(start, end)
|
val id = pageUrl.substring(start, end)
|
||||||
return get("$baseUrl/areader?id=$id&p=${pageUrl.substring(end+1)}", headers)
|
return GET("$baseUrl/areader?id=$id&p=${pageUrl.substring(end+1)}", headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response, page: MangasPage) {
|
override fun popularMangaParse(response: Response, page: MangasPage) {
|
||||||
@ -216,9 +215,8 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun login(username: String, password: String) =
|
override fun login(username: String, password: String) =
|
||||||
network.request(get("$baseUrl/forums/index.php?app=core&module=global§ion=login", headers))
|
network.request(GET("$baseUrl/forums/index.php?app=core&module=global§ion=login", headers))
|
||||||
.map { it.body().string() }
|
.flatMap { doLogin(it.body().string(), username, password) }
|
||||||
.flatMap { doLogin(it, username, password) }
|
|
||||||
.map { isAuthenticationSuccessful(it) }
|
.map { isAuthenticationSuccessful(it) }
|
||||||
|
|
||||||
private fun doLogin(response: String, username: String, password: String): Observable<Response> {
|
private fun doLogin(response: String, username: String, password: String): Observable<Response> {
|
||||||
@ -235,7 +233,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
|
|||||||
add("rememberMe", "1")
|
add("rememberMe", "1")
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
return network.request(post(url, headers, payload))
|
return network.request(POST(url, headers, payload))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isLoginRequired() = true
|
override fun isLoginRequired() = true
|
||||||
@ -244,12 +242,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
|
|||||||
response.priorResponse() != null && response.priorResponse().code() == 302
|
response.priorResponse() != null && response.priorResponse().code() == 302
|
||||||
|
|
||||||
override fun isLogged(): Boolean {
|
override fun isLogged(): Boolean {
|
||||||
try {
|
return network.cookies.get(URI(baseUrl)).any { it.name() == "pass_hash" }
|
||||||
return network.cookies.get(URI(baseUrl)).find { it.name() == "pass_hash" } != null
|
|
||||||
} catch (e: URISyntaxException) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchChapterList(manga: Manga): Observable<List<Chapter>> {
|
override fun fetchChapterList(manga: Manga): Observable<List<Chapter>> {
|
||||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.data.source.online.english
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.network.get
|
import eu.kanade.tachiyomi.data.network.GET
|
||||||
import eu.kanade.tachiyomi.data.network.post
|
import eu.kanade.tachiyomi.data.network.POST
|
||||||
import eu.kanade.tachiyomi.data.source.EN
|
import eu.kanade.tachiyomi.data.source.EN
|
||||||
import eu.kanade.tachiyomi.data.source.Language
|
import eu.kanade.tachiyomi.data.source.Language
|
||||||
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
||||||
@ -54,7 +54,7 @@ class Kissmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
|
|||||||
add("genres", "")
|
add("genres", "")
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
return post(page.url, headers, form)
|
return POST(page.url, headers, form)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaInitialUrl(query: String) = "$baseUrl/AdvanceSearch"
|
override fun searchMangaInitialUrl(query: String) = "$baseUrl/AdvanceSearch"
|
||||||
@ -95,7 +95,7 @@ class Kissmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
|
|||||||
} ?: 0
|
} ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: Chapter) = post(baseUrl + chapter.url, headers)
|
override fun pageListRequest(chapter: Chapter) = POST(baseUrl + chapter.url, headers)
|
||||||
|
|
||||||
override fun pageListParse(response: Response, pages: MutableList<Page>) {
|
override fun pageListParse(response: Response, pages: MutableList<Page>) {
|
||||||
//language=RegExp
|
//language=RegExp
|
||||||
@ -111,7 +111,7 @@ class Kissmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
|
|||||||
// Not used
|
// Not used
|
||||||
override fun pageListParse(document: Document, pages: MutableList<Page>) {}
|
override fun pageListParse(document: Document, pages: MutableList<Page>) {}
|
||||||
|
|
||||||
override fun imageUrlRequest(page: Page) = get(page.url)
|
override fun imageUrlRequest(page: Page) = GET(page.url)
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = ""
|
override fun imageUrlParse(document: Document) = ""
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.data.source.online.english
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.network.post
|
import eu.kanade.tachiyomi.data.network.POST
|
||||||
import eu.kanade.tachiyomi.data.source.EN
|
import eu.kanade.tachiyomi.data.source.EN
|
||||||
import eu.kanade.tachiyomi.data.source.Language
|
import eu.kanade.tachiyomi.data.source.Language
|
||||||
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
import eu.kanade.tachiyomi.data.source.model.MangasPage
|
||||||
@ -47,7 +47,7 @@ class Readmangatoday(context: Context, override val id: Int) : ParsedOnlineSourc
|
|||||||
var builder = okhttp3.FormBody.Builder()
|
var builder = okhttp3.FormBody.Builder()
|
||||||
builder.add("query", query)
|
builder.add("query", query)
|
||||||
|
|
||||||
return post(page.url, headers, builder.build())
|
return POST(page.url, headers, builder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaSelector() = "div.content-list > div.style-list > div.box"
|
override fun searchMangaSelector() = "div.content-list > div.style-list > div.box"
|
||||||
|
@ -11,9 +11,10 @@ import android.support.v4.app.NotificationCompat
|
|||||||
import eu.kanade.tachiyomi.App
|
import eu.kanade.tachiyomi.App
|
||||||
import eu.kanade.tachiyomi.Constants
|
import eu.kanade.tachiyomi.Constants
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.network.GET
|
||||||
import eu.kanade.tachiyomi.data.network.NetworkHelper
|
import eu.kanade.tachiyomi.data.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.data.network.ProgressListener
|
import eu.kanade.tachiyomi.data.network.ProgressListener
|
||||||
import eu.kanade.tachiyomi.data.network.get
|
import eu.kanade.tachiyomi.data.network.newCallWithProgress
|
||||||
import eu.kanade.tachiyomi.util.notificationManager
|
import eu.kanade.tachiyomi.util.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.saveTo
|
import eu.kanade.tachiyomi.util.saveTo
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -100,12 +101,14 @@ class UpdateDownloader(private val context: Context) :
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Make the request and download the file
|
// Make the request and download the file
|
||||||
val response = network.requestBodyProgressBlocking(get(result.url), progressListener)
|
val response = network.client.newCallWithProgress(GET(result.url), progressListener).execute()
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
response.body().source().saveTo(apkFile)
|
response.body().source().saveTo(apkFile)
|
||||||
// Set download successful
|
// Set download successful
|
||||||
result.successful = true
|
result.successful = true
|
||||||
|
} else {
|
||||||
|
response.close()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, e.message)
|
Timber.e(e, e.message)
|
||||||
|
Loading…
Reference in New Issue
Block a user