Refactor to use app-provided rate limiting interceptors (#12088)
This commit is contained in:
parent
341d067afc
commit
93e6774da0
|
@ -135,16 +135,6 @@ The extension's version name is generated automatically by concatenating `libVer
|
||||||
|
|
||||||
Extensions rely on [extensions-lib](https://github.com/tachiyomiorg/extensions-lib), which provides some interfaces and stubs from the [app](https://github.com/tachiyomiorg/tachiyomi) for compilation purposes. The actual implementations can be found [here](https://github.com/tachiyomiorg/tachiyomi/tree/master/app/src/main/java/eu/kanade/tachiyomi/source). Referencing the actual implementation will help with understanding extensions' call flow.
|
Extensions rely on [extensions-lib](https://github.com/tachiyomiorg/extensions-lib), which provides some interfaces and stubs from the [app](https://github.com/tachiyomiorg/tachiyomi) for compilation purposes. The actual implementations can be found [here](https://github.com/tachiyomiorg/tachiyomi/tree/master/app/src/main/java/eu/kanade/tachiyomi/source). Referencing the actual implementation will help with understanding extensions' call flow.
|
||||||
|
|
||||||
#### Rate limiting library
|
|
||||||
|
|
||||||
[`lib-ratelimit`](https://github.com/tachiyomiorg/tachiyomi-extensions/tree/master/lib/ratelimit) is a library for adding rate limiting functionality as an [OkHttp interceptor](https://square.github.io/okhttp/interceptors/).
|
|
||||||
|
|
||||||
```gradle
|
|
||||||
dependencies {
|
|
||||||
implementation(project(':lib-ratelimit'))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### DataImage library
|
#### DataImage library
|
||||||
|
|
||||||
[`lib-dataimage`](https://github.com/tachiyomiorg/tachiyomi-extensions/tree/master/lib/dataimage) is a library for handling [base 64 encoded image data](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) using an [OkHttp interceptor](https://square.github.io/okhttp/interceptors/).
|
[`lib-dataimage`](https://github.com/tachiyomiorg/tachiyomi-extensions/tree/master/lib/dataimage) is a library for handling [base 64 encoded image data](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) using an [OkHttp interceptor](https://square.github.io/okhttp/interceptors/).
|
||||||
|
|
|
@ -6,12 +6,12 @@ ext {
|
||||||
extName = 'MangaDex'
|
extName = 'MangaDex'
|
||||||
pkgNameSuffix = 'all.mangadex'
|
pkgNameSuffix = 'all.mangadex'
|
||||||
extClass = '.MangaDexFactory'
|
extClass = '.MangaDexFactory'
|
||||||
extVersionCode = 159
|
extVersionCode = 160
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':lib-ratelimit')
|
compileOnly(libs.okhttp)
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.all.mangadex
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ImageReportDto
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ImageReportDto
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.mangadex
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An OkHttp interceptor that handles rate limiting.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* permits = 5, period = 1, unit = seconds => 5 requests per second
|
||||||
|
* permits = 10, period = 2, unit = minutes => 10 requests per 2 minutes
|
||||||
|
*
|
||||||
|
* @param permits {Int} Number of requests allowed within a period of units.
|
||||||
|
* @param period {Long} The limiting duration. Defaults to 1.
|
||||||
|
* @param unit {TimeUnit} The unit of time for the period. Defaults to seconds.
|
||||||
|
*/
|
||||||
|
class RateLimitInterceptor(
|
||||||
|
private val permits: Int,
|
||||||
|
private val period: Long = 1,
|
||||||
|
private val unit: TimeUnit = TimeUnit.SECONDS) : Interceptor {
|
||||||
|
|
||||||
|
private val requestQueue = ArrayList<Long>(permits)
|
||||||
|
private val rateLimitMillis = unit.toMillis(period)
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
synchronized(requestQueue) {
|
||||||
|
val now = SystemClock.elapsedRealtime()
|
||||||
|
val waitTime = if (requestQueue.size < permits) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
val oldestReq = requestQueue[0]
|
||||||
|
val newestReq = requestQueue[permits - 1]
|
||||||
|
|
||||||
|
if (newestReq - oldestReq > rateLimitMillis) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
oldestReq + rateLimitMillis - now // Remaining time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestQueue.size == permits) {
|
||||||
|
requestQueue.removeAt(0)
|
||||||
|
}
|
||||||
|
if (waitTime > 0) {
|
||||||
|
requestQueue.add(now + waitTime)
|
||||||
|
Thread.sleep(waitTime) // Sleep inside synchronized to pause queued requests
|
||||||
|
} else {
|
||||||
|
requestQueue.add(now)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain.proceed(chain.request())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,11 +6,7 @@ ext {
|
||||||
extName = 'Digital Comic Museum'
|
extName = 'Digital Comic Museum'
|
||||||
pkgNameSuffix = 'en.digitalcomicmuseum'
|
pkgNameSuffix = 'en.digitalcomicmuseum'
|
||||||
extClass = '.DigitalComicMuseum'
|
extClass = '.DigitalComicMuseum'
|
||||||
extVersionCode = 1
|
extVersionCode = 2
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(':lib-ratelimit')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -5,11 +5,7 @@ ext {
|
||||||
extName = 'Baimangu (Darpou)'
|
extName = 'Baimangu (Darpou)'
|
||||||
pkgNameSuffix = 'zh.baimangu'
|
pkgNameSuffix = 'zh.baimangu'
|
||||||
extClass = '.Baimangu'
|
extClass = '.Baimangu'
|
||||||
extVersionCode = 2
|
extVersionCode = 3
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(path: ':lib-ratelimit')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.extension.zh.baimangu
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
@ -36,16 +36,13 @@ class Baimangu : ConfigurableSource, ParsedHttpSource() {
|
||||||
|
|
||||||
override val baseUrl = preferences.getString(MAINSITE_URL_PREF, MAINSITE_URL_PREF_DEFAULT)!!
|
override val baseUrl = preferences.getString(MAINSITE_URL_PREF, MAINSITE_URL_PREF_DEFAULT)!!
|
||||||
|
|
||||||
// Client configs
|
|
||||||
private val mainSiteRateLimitInterceptor = SpecificHostRateLimitInterceptor(
|
|
||||||
baseUrl.toHttpUrlOrNull()!!,
|
|
||||||
preferences.getString(MAINSITE_RATEPERMITS_PREF, MAINSITE_RATEPERMITS_PREF_DEFAULT)!!.toInt(),
|
|
||||||
preferences.getString(MAINSITE_RATEPERIOD_PREF, MAINSITE_RATEPERIOD_PREF_DEFAULT)!!.toLong(),
|
|
||||||
TimeUnit.MILLISECONDS,
|
|
||||||
)
|
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
.addNetworkInterceptor(mainSiteRateLimitInterceptor)
|
.rateLimitHost(
|
||||||
|
baseUrl.toHttpUrlOrNull()!!,
|
||||||
|
preferences.getString(MAINSITE_RATEPERMITS_PREF, MAINSITE_RATEPERMITS_PREF_DEFAULT)!!.toInt(),
|
||||||
|
preferences.getString(MAINSITE_RATEPERIOD_PREF, MAINSITE_RATEPERIOD_PREF_DEFAULT)!!.toLong(),
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||||
|
|
|
@ -6,12 +6,8 @@ ext {
|
||||||
extName = 'Jinmantiantang'
|
extName = 'Jinmantiantang'
|
||||||
pkgNameSuffix = 'zh.jinmantiantang'
|
pkgNameSuffix = 'zh.jinmantiantang'
|
||||||
extClass = '.Jinmantiantang'
|
extClass = '.Jinmantiantang'
|
||||||
extVersionCode = 25
|
extVersionCode = 26
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(':lib-ratelimit')
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -4,9 +4,9 @@ import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.EditTextPreference
|
import androidx.preference.EditTextPreference
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
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.network.interceptor.rateLimitHost
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
@ -44,13 +44,15 @@ class Jinmantiantang : ConfigurableSource, ParsedHttpSource() {
|
||||||
SITE_ENTRIES_ARRAY[preferences.getString(USE_MIRROR_URL_PREF, "0")!!.toInt()]
|
SITE_ENTRIES_ARRAY[preferences.getString(USE_MIRROR_URL_PREF, "0")!!.toInt()]
|
||||||
private val baseHttpUrl: HttpUrl = baseUrl.toHttpUrlOrNull()!!
|
private val baseHttpUrl: HttpUrl = baseUrl.toHttpUrlOrNull()!!
|
||||||
|
|
||||||
// Add rate limit to fix manga thumbnail load failure
|
|
||||||
private val mainSiteRateLimitInterceptor = SpecificHostRateLimitInterceptor(baseHttpUrl, preferences.getString(MAINSITE_RATELIMIT_PREF, "1")!!.toInt(), preferences.getString(MAINSITE_RATELIMIT_PERIOD, "3")!!.toLong())
|
|
||||||
|
|
||||||
// 处理URL请求
|
// 处理URL请求
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.addNetworkInterceptor(mainSiteRateLimitInterceptor)
|
// Add rate limit to fix manga thumbnail load failure
|
||||||
|
.rateLimitHost(
|
||||||
|
baseHttpUrl,
|
||||||
|
preferences.getString(MAINSITE_RATELIMIT_PREF, "1")!!.toInt(),
|
||||||
|
preferences.getString(MAINSITE_RATELIMIT_PERIOD, "3")!!.toLong(),
|
||||||
|
)
|
||||||
.addInterceptor(ScrambledImageInterceptor).build()
|
.addInterceptor(ScrambledImageInterceptor).build()
|
||||||
|
|
||||||
// 点击量排序(人气)
|
// 点击量排序(人气)
|
||||||
|
|
Loading…
Reference in New Issue