Detect CloudFlare blocks
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
package org.koitharu.kotatsu.core.exceptions
|
||||
|
||||
import okhttp3.Headers
|
||||
import okio.IOException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
class CloudFlareBlockedException(
|
||||
val url: String,
|
||||
val source: MangaSource?,
|
||||
) : IOException("Blocked by CloudFlare")
|
||||
@@ -4,6 +4,7 @@ import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.closeQuietly
|
||||
import org.jsoup.Jsoup
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareBlockedException
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import java.net.HttpURLConnection.HTTP_FORBIDDEN
|
||||
@@ -17,14 +18,23 @@ class CloudFlareInterceptor : Interceptor {
|
||||
val content = response.body?.let { response.peekBody(Long.MAX_VALUE) }?.byteStream()?.use {
|
||||
Jsoup.parse(it, Charsets.UTF_8.name(), response.request.url.toString())
|
||||
} ?: return response
|
||||
if (content.getElementById("challenge-error-title") != null) {
|
||||
val hasCaptcha = content.getElementById("challenge-error-title") != null
|
||||
val isBlocked = content.selectFirst("h2[data-translate=\"blocked_why_headline\"]") != null
|
||||
if (hasCaptcha || isBlocked) {
|
||||
val request = response.request
|
||||
response.closeQuietly()
|
||||
throw CloudFlareProtectedException(
|
||||
url = request.url.toString(),
|
||||
source = request.tag(MangaSource::class.java),
|
||||
headers = request.headers,
|
||||
)
|
||||
if (isBlocked) {
|
||||
throw CloudFlareBlockedException(
|
||||
url = request.url.toString(),
|
||||
source = request.tag(MangaSource::class.java),
|
||||
)
|
||||
} else {
|
||||
throw CloudFlareProtectedException(
|
||||
url = request.url.toString(),
|
||||
source = request.tag(MangaSource::class.java),
|
||||
headers = request.headers,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jsoup.HttpStatusException
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.BadBackupFormatException
|
||||
import org.koitharu.kotatsu.core.exceptions.CaughtException
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareBlockedException
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
|
||||
import org.koitharu.kotatsu.core.exceptions.NoDataReceivedException
|
||||
@@ -38,6 +39,7 @@ private const val IMAGE_FORMAT_NOT_SUPPORTED = "Image format not supported"
|
||||
fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
||||
is AuthRequiredException -> resources.getString(R.string.auth_required)
|
||||
is CloudFlareProtectedException -> resources.getString(R.string.captcha_required)
|
||||
is CloudFlareBlockedException -> resources.getString(R.string.blocked_by_server_message)
|
||||
is ActivityNotFoundException,
|
||||
is UnsupportedOperationException,
|
||||
-> resources.getString(R.string.operation_not_supported)
|
||||
@@ -79,6 +81,8 @@ fun Throwable.getDisplayIcon() = when (this) {
|
||||
is SocketTimeoutException,
|
||||
-> R.drawable.ic_plug_large
|
||||
|
||||
is CloudFlareBlockedException -> R.drawable.ic_denied_large
|
||||
|
||||
else -> R.drawable.ic_error_large
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||
import org.koitharu.kotatsu.list.ui.model.toErrorFooter
|
||||
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
||||
import org.koitharu.kotatsu.list.ui.model.toUi
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
@@ -88,7 +89,7 @@ open class RemoteListViewModel @Inject constructor(
|
||||
list.isNullOrEmpty() && error != null -> add(
|
||||
error.toErrorState(
|
||||
canRetry = true,
|
||||
secondaryAction = if (browserUrl != null) R.string.open_in_browser else 0,
|
||||
secondaryAction = if (error !is NotFoundException && browserUrl != null) R.string.open_in_browser else 0,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -640,4 +640,5 @@
|
||||
<string name="recent_queries">Recent queries</string>
|
||||
<string name="suggested_queries">Suggested queries</string>
|
||||
<string name="authors">Authors</string>
|
||||
<string name="blocked_by_server_message">You are blocked by the server. Try to use a different network connection (VPN, Proxy, etc.)</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user