diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index f43fa1317..8001cc2ce 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -10,7 +10,11 @@ import rx.Producer import rx.Subscription import java.util.concurrent.atomic.AtomicBoolean -fun Call.asObservable(): Observable { +fun Call.asObservableWithAsyncStacktrace(): Observable> { + // Record stacktrace at creation time for easier debugging + // asObservable is involved in a lot of crashes so this is worth the performance hit + val asyncStackTrace = Exception("Async stacktrace") + return Observable.unsafeCreate { subscriber -> // Since Call is a one-shot type, clone it for each new subscriber. val call = clone() @@ -23,12 +27,12 @@ fun Call.asObservable(): Observable { try { val response = call.execute() if (!subscriber.isUnsubscribed) { - subscriber.onNext(response) + subscriber.onNext(asyncStackTrace to response) subscriber.onCompleted() } } catch (error: Exception) { if (!subscriber.isUnsubscribed) { - subscriber.onError(error) + subscriber.onError(error.withRootCause(asyncStackTrace)) } } } @@ -47,19 +51,14 @@ fun Call.asObservable(): Observable { } } -fun Call.asObservableSuccess(): Observable { - // Record stacktrace at creation time for easier debugging - // asObservable is involved in a lot of crashes so this is worth the performance hit - val asyncStackTrace = Exception("Async stacktrace") +fun Call.asObservable() = asObservableWithAsyncStacktrace().map { it.second } - return asObservable().doOnNext { response -> +fun Call.asObservableSuccess(): Observable { + return asObservableWithAsyncStacktrace().map { (asyncStacktrace, response) -> if (!response.isSuccessful) { response.close() - throw Exception("HTTP error ${response.code()}") - } - }.onErrorReturn { - // Set root cause to async stacktrace and throw again - throw it.withRootCause(asyncStackTrace) + throw Exception("HTTP error ${response.code()}", asyncStacktrace) + } else response } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt index 3b37e4511..d2df9e12d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.asObservableWithAsyncStacktrace import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.LewdSource @@ -32,6 +33,7 @@ import uy.kohesive.injekt.injectLazy import java.net.URLEncoder import java.util.* import exh.metadata.metadata.base.RaisedTag +import java.lang.RuntimeException class EHentai(override val id: Long, val exh: Boolean, @@ -236,11 +238,21 @@ class EHentai(override val id: Long, */ override fun fetchMangaDetails(manga: SManga): Observable { return client.newCall(mangaDetailsRequest(manga)) - .asObservableSuccess() - .flatMap { - parseToManga(manga, it).andThen(Observable.just(manga.apply { - initialized = true - })) + .asObservableWithAsyncStacktrace() + .flatMap { (stacktrace, response) -> + if(response.isSuccessful) { + parseToManga(manga, response).andThen(Observable.just(manga.apply { + initialized = true + })) + } else { + response.close() + + if(response.code() == 404) { + throw GalleryNotFoundException(stacktrace) + } else { + throw Exception("HTTP error ${response.code()}", stacktrace) + } + } } } @@ -522,6 +534,8 @@ class EHentai(override val id: Long, else "E-Hentai" + class GalleryNotFoundException(cause: Throwable): RuntimeException("Gallery not found!", cause) + companion object { private const val QUERY_PREFIX = "?f_apply=Apply+Filter" private const val TR_SUFFIX = "TR" diff --git a/app/src/main/java/exh/GalleryAdder.kt b/app/src/main/java/exh/GalleryAdder.kt index 61fafcd63..714552d4c 100755 --- a/app/src/main/java/exh/GalleryAdder.kt +++ b/app/src/main/java/exh/GalleryAdder.kt @@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.util.syncChaptersWithSource import exh.metadata.metadata.EHentaiSearchMetadata import okhttp3.MediaType @@ -186,6 +187,11 @@ class GalleryAdder { return GalleryAddEvent.Success(url, manga) } catch(e: Exception) { XLog.w("Could not add gallery!", e) + + if(e is EHentai.GalleryNotFoundException) { + return GalleryAddEvent.Fail.NotFound(url) + } + return GalleryAddEvent.Fail.Error(url, ((e.message ?: "Unknown error!") + " (Gallery: $url)").trim()) } @@ -223,7 +229,10 @@ sealed class GalleryAddEvent { override val logMessage = "Unknown gallery type for gallery: $galleryUrl" } - class Error(override val galleryUrl: String, + open class Error(override val galleryUrl: String, override val logMessage: String): Fail() + + class NotFound(galleryUrl: String): + Error(galleryUrl, "Gallery does not exist: $galleryUrl") } } \ No newline at end of file diff --git a/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt b/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt index f4e6504e8..679136e00 100644 --- a/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt +++ b/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt @@ -323,6 +323,12 @@ class FavoritesSyncHelper(val context: Context) { EXH_SOURCE_ID) if(result is GalleryAddEvent.Fail) { + if(result is GalleryAddEvent.Fail.NotFound) { + XLog.e("Remote gallery does not exist, skipping: %s!", it.getUrl()) + // Skip this gallery, it no longer exists + return@forEachIndexed + } + val errorString = "Failed to add gallery to local database: " + when (result) { is GalleryAddEvent.Fail.Error -> "'${it.title}' ${result.logMessage}" is GalleryAddEvent.Fail.UnknownType -> "'${it.title}' (${result.galleryUrl}) is not a valid gallery!" diff --git a/app/src/main/java/exh/ui/batchadd/BatchAddPresenter.kt b/app/src/main/java/exh/ui/batchadd/BatchAddPresenter.kt index 6f94717be..a6216a626 100644 --- a/app/src/main/java/exh/ui/batchadd/BatchAddPresenter.kt +++ b/app/src/main/java/exh/ui/batchadd/BatchAddPresenter.kt @@ -43,7 +43,6 @@ class BatchAddPresenter: BasePresenter() { eventRelay?.call((when (result) { is GalleryAddEvent.Success -> "[OK]" is GalleryAddEvent.Fail -> "[ERROR]" - else -> "[???]" }) + " " + result.logMessage) }