Add a harsher rate limiting to image servers requests at Tsuki (#7531)

* Add rate limiting to image servers at Tsuki.

* Show a message if the UA permission is disabled by the website.
This commit is contained in:
Alessandro Jean 2021-06-07 16:30:23 -03:00 committed by GitHub
parent ad61957f81
commit 2932fde187
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 7 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'Tsuki Mangás' extName = 'Tsuki Mangás'
pkgNameSuffix = 'pt.tsukimangas' pkgNameSuffix = 'pt.tsukimangas'
extClass = '.TsukiMangas' extClass = '.TsukiMangas'
extVersionCode = 16 extVersionCode = 17
libVersion = '1.2' libVersion = '1.2'
containsNsfw = true containsNsfw = true
} }

View File

@ -1,7 +1,7 @@
package eu.kanade.tachiyomi.extension.pt.tsukimangas package eu.kanade.tachiyomi.extension.pt.tsukimangas
import eu.kanade.tachiyomi.annotations.Nsfw import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
@ -14,16 +14,18 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit
@Nsfw @Nsfw
class TsukiMangas : HttpSource() { class TsukiMangas : HttpSource() {
@ -37,7 +39,10 @@ class TsukiMangas : HttpSource() {
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS)) .addInterceptor(SpecificHostRateLimitInterceptor(baseUrl.toHttpUrl(), 1))
.addInterceptor(SpecificHostRateLimitInterceptor(CDN_1_URL, 1, period = 2))
.addInterceptor(SpecificHostRateLimitInterceptor(CDN_2_URL, 1, period = 2))
.addInterceptor(::tsukiPermissionIntercept)
.build() .build()
override fun headersBuilder(): Headers.Builder = Headers.Builder() override fun headersBuilder(): Headers.Builder = Headers.Builder()
@ -49,7 +54,7 @@ class TsukiMangas : HttpSource() {
private val json: Json by injectLazy() private val json: Json by injectLazy()
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/api/v2/mangas?page=$page&title=&filter=0", headers) return GET("$baseUrl/api/v2/mangas?page=$page&title=&adult_content=false&filter=0", headers)
} }
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
@ -274,6 +279,17 @@ class TsukiMangas : HttpSource() {
return GET(page.imageUrl!!, newHeaders) return GET(page.imageUrl!!, newHeaders)
} }
private fun tsukiPermissionIntercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
if (response.code == 403) {
response.close()
throw IOException(UA_DISABLED_MESSAGE)
}
return response
}
private class Genre(name: String) : Filter.CheckBox(name) private class Genre(name: String) : Filter.CheckBox(name)
private class DemographyFilter(demographies: List<String>) : Filter.Select<String>("Demografia", demographies.toTypedArray()) private class DemographyFilter(demographies: List<String>) : Filter.Select<String>("Demografia", demographies.toTypedArray())
@ -282,7 +298,7 @@ class TsukiMangas : HttpSource() {
private class StatusFilter(statusList: List<String>) : Filter.Select<String>("Status", statusList.toTypedArray()) private class StatusFilter(statusList: List<String>) : Filter.Select<String>("Status", statusList.toTypedArray())
private class AdultFilter : Filter.TriState("Conteúdo adulto") private class AdultFilter : Filter.TriState("Conteúdo adulto", STATE_EXCLUDE)
private class SortByFilter : Filter.Sort("Ordenar por", arrayOf("Visualizações", "Nota"), Selection(0, false)) private class SortByFilter : Filter.Sort("Ordenar por", arrayOf("Visualizações", "Nota"), Selection(0, false))
@ -424,7 +440,13 @@ class TsukiMangas : HttpSource() {
private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/*,*/*;q=0.8" private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/*,*/*;q=0.8"
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5" private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
// By request of site owner. Detailed at Issue #4912 (in Portuguese). // By request of site owner. Detailed at Issue #4912 (in Portuguese).
private val USER_AGENT = "Tachiyomi " + System.getProperty("http.agent") private val USER_AGENT = "Tachiyomi " + System.getProperty("http.agent")!!
private val CDN_1_URL = "https://cdn1.tsukimangas.com".toHttpUrl()
private val CDN_2_URL = "https://cdn2.tsukimangas.com".toHttpUrl()
private const val UA_DISABLED_MESSAGE = "Permissão de acesso da extensão desativada. " +
"Aguarde a reativação pelo site para continuar utilizando."
private val DATE_FORMATTER by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) } private val DATE_FORMATTER by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) }
} }