From d482f47ac8872768852a6d5d4c450db9fc1455cb Mon Sep 17 00:00:00 2001 From: Aria Moradi Date: Sat, 19 Mar 2022 02:28:29 +0330 Subject: [PATCH 1/3] closes #315 --- .../main/{kotlin => java}/eu/kanade/tachiyomi/BuildConfig.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename server/src/main/{kotlin => java}/eu/kanade/tachiyomi/BuildConfig.java (100%) diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/BuildConfig.java b/server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java similarity index 100% rename from server/src/main/kotlin/eu/kanade/tachiyomi/BuildConfig.java rename to server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java From 37b0ecab0caea6163661236cafa15384ea655e60 Mon Sep 17 00:00:00 2001 From: Aria Moradi Date: Sat, 19 Mar 2022 02:29:19 +0330 Subject: [PATCH 2/3] provide real values --- server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java b/server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java index d42a96f25a..a2574018b8 100644 --- a/server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java +++ b/server/src/main/java/eu/kanade/tachiyomi/BuildConfig.java @@ -1,6 +1,9 @@ package eu.kanade.tachiyomi; public class BuildConfig { - public static final int VERSION_CODE = -1; - public static final String VERSION_NAME = "stub"; + /** should be something like 74 */ + public static final int VERSION_CODE = Integer.parseInt(suwayomi.tachidesk.server.BuildConfig.REVISION.substring(1)); + + /** should be something like "0.13.1" */ + public static final String VERSION_NAME = suwayomi.tachidesk.server.BuildConfig.VERSION.substring(1); } From cde5db449ab6236b5b4b2a44065fb6aeec8ae18b Mon Sep 17 00:00:00 2001 From: Aria Moradi Date: Sat, 19 Mar 2022 02:33:36 +0330 Subject: [PATCH 3/3] add support for tachiyomi extensions lib 1.3 --- .../kotlin/eu/kanade/tachiyomi/AppInfo.kt | 11 +++ .../interceptor/RateLimitInterceptor.kt | 67 +++++++++++++++++ .../SpecificHostRateLimitInterceptor.kt | 75 +++++++++++++++++++ .../tachiyomi/source/UnmeteredSource.kt | 8 ++ .../kanade/tachiyomi/source/model/SManga.kt | 3 + .../tachidesk/manga/impl/util/PackageTools.kt | 2 +- 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 server/src/main/kotlin/eu/kanade/tachiyomi/AppInfo.kt create mode 100644 server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/RateLimitInterceptor.kt create mode 100644 server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt create mode 100644 server/src/main/kotlin/eu/kanade/tachiyomi/source/UnmeteredSource.kt diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/AppInfo.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/AppInfo.kt new file mode 100644 index 0000000000..7ec80cdb67 --- /dev/null +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/AppInfo.kt @@ -0,0 +1,11 @@ +package eu.kanade.tachiyomi + +/** + * Used by extensions. + * + * @since extension-lib 1.3 + */ +object AppInfo { + fun getVersionCode() = BuildConfig.VERSION_CODE + fun getVersionName() = BuildConfig.VERSION_NAME +} diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/RateLimitInterceptor.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/RateLimitInterceptor.kt new file mode 100644 index 0000000000..a776f2b5f7 --- /dev/null +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/RateLimitInterceptor.kt @@ -0,0 +1,67 @@ +package eu.kanade.tachiyomi.network.interceptor + +import android.os.SystemClock +import okhttp3.Interceptor +import okhttp3.OkHttpClient +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 + * + * @since extension-lib 1.3 + * + * @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. + */ +fun OkHttpClient.Builder.rateLimit( + permits: Int, + period: Long = 1, + unit: TimeUnit = TimeUnit.SECONDS, +) = addInterceptor(RateLimitInterceptor(permits, period, unit)) + +private class RateLimitInterceptor( + private val permits: Int, + period: Long, + unit: TimeUnit, +) : Interceptor { + + private val requestQueue = ArrayList(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()) + } +} diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt new file mode 100644 index 0000000000..ec7a8fdb1d --- /dev/null +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt @@ -0,0 +1,75 @@ +package eu.kanade.tachiyomi.network.interceptor + +import android.os.SystemClock +import okhttp3.HttpUrl +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.Response +import java.util.concurrent.TimeUnit + +/** + * An OkHttp interceptor that handles given url host's rate limiting. + * + * Examples: + * + * httpUrl = "api.manga.com".toHttpUrlOrNull(), permits = 5, period = 1, unit = seconds => 5 requests per second to api.manga.com + * httpUrl = "imagecdn.manga.com".toHttpUrlOrNull(), permits = 10, period = 2, unit = minutes => 10 requests per 2 minutes to imagecdn.manga.com + * + * @since extension-lib 1.3 + * + * @param httpUrl {HttpUrl} The url host that this interceptor should handle. Will get url's host by using HttpUrl.host() + * @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. + */ +fun OkHttpClient.Builder.rateLimitHost( + httpUrl: HttpUrl, + permits: Int, + period: Long = 1, + unit: TimeUnit = TimeUnit.SECONDS, +) = addInterceptor(SpecificHostRateLimitInterceptor(httpUrl, permits, period, unit)) + +class SpecificHostRateLimitInterceptor( + httpUrl: HttpUrl, + private val permits: Int, + period: Long, + unit: TimeUnit, +) : Interceptor { + + private val requestQueue = ArrayList(permits) + private val rateLimitMillis = unit.toMillis(period) + private val host = httpUrl.host + + override fun intercept(chain: Interceptor.Chain): Response { + if (chain.request().url.host != host) { + return chain.proceed(chain.request()) + } + 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()) + } +} diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/source/UnmeteredSource.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/source/UnmeteredSource.kt new file mode 100644 index 0000000000..7536ccb0ba --- /dev/null +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/source/UnmeteredSource.kt @@ -0,0 +1,8 @@ +package eu.kanade.tachiyomi.source + +/** + * A source that explicitly doesn't require traffic considerations. + * + * This typically applies for self-hosted sources. + */ +interface UnmeteredSource diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/source/model/SManga.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/source/model/SManga.kt index 8b7d74d69a..28fd48a8c5 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/source/model/SManga.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/source/model/SManga.kt @@ -55,6 +55,9 @@ interface SManga : Serializable { const val ONGOING = 1 const val COMPLETED = 2 const val LICENSED = 3 + const val PUBLISHING_FINISHED = 4 + const val CANCELLED = 5 + const val ON_HIATUS = 6 fun create(): SManga { return SMangaImpl() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/PackageTools.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/PackageTools.kt index 19938d1732..a2ba85ce04 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/PackageTools.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/PackageTools.kt @@ -41,7 +41,7 @@ object PackageTools { const val METADATA_SOURCE_FACTORY = "tachiyomi.extension.factory" const val METADATA_NSFW = "tachiyomi.extension.nsfw" const val LIB_VERSION_MIN = 1.2 - const val LIB_VERSION_MAX = 1.2 + const val LIB_VERSION_MAX = 1.3 private const val officialSignature = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" // inorichi's key private const val unofficialSignature = "64feb21075ba97ebc9cc981243645b331595c111cef1b0d084236a0403b00581" // ArMor's key