mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-11 23:04:33 -05:00
[skip ci] Formatting
This commit is contained in:
@@ -49,7 +49,9 @@ class MemoryCookieJar : CookieJar {
|
||||
}
|
||||
}
|
||||
|
||||
class WrappedCookie private constructor(val cookie: Cookie) {
|
||||
class WrappedCookie private constructor(
|
||||
val cookie: Cookie,
|
||||
) {
|
||||
fun unwrap() = cookie
|
||||
|
||||
fun isExpired() = cookie.expiresAt < System.currentTimeMillis()
|
||||
|
||||
@@ -30,7 +30,9 @@ import java.net.CookieManager
|
||||
import java.net.CookiePolicy
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class NetworkHelper(context: Context) {
|
||||
class NetworkHelper(
|
||||
context: Context,
|
||||
) {
|
||||
// private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
// private val cacheDir = File(context.cacheDir, "network_cache")
|
||||
@@ -53,9 +55,7 @@ class NetworkHelper(context: Context) {
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
)
|
||||
|
||||
fun defaultUserAgentProvider(): String {
|
||||
return userAgent.value
|
||||
}
|
||||
fun defaultUserAgentProvider(): String = userAgent.value
|
||||
|
||||
init {
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@@ -63,14 +63,14 @@ class NetworkHelper(context: Context) {
|
||||
.drop(1)
|
||||
.onEach {
|
||||
GetCatalogueSource.unregisterAllCatalogueSources() // need to reset the headers
|
||||
}
|
||||
.launchIn(GlobalScope)
|
||||
}.launchIn(GlobalScope)
|
||||
}
|
||||
|
||||
private val baseClientBuilder: OkHttpClient.Builder
|
||||
get() {
|
||||
val builder =
|
||||
OkHttpClient.Builder()
|
||||
OkHttpClient
|
||||
.Builder()
|
||||
.cookieJar(PersistentCookieJar(cookieStore))
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
@@ -80,8 +80,7 @@ class NetworkHelper(context: Context) {
|
||||
directory = File.createTempFile("tachidesk_network_cache", null),
|
||||
maxSize = 5L * 1024 * 1024, // 5 MiB
|
||||
),
|
||||
)
|
||||
.addInterceptor(UncaughtExceptionInterceptor())
|
||||
).addInterceptor(UncaughtExceptionInterceptor())
|
||||
.addInterceptor(UserAgentInterceptor(::defaultUserAgentProvider))
|
||||
.addNetworkInterceptor(IgnoreGzipInterceptor())
|
||||
.addNetworkInterceptor(BrotliInterceptor)
|
||||
|
||||
@@ -50,9 +50,7 @@ fun Call.asObservable(): Observable<Response> {
|
||||
// call.cancel()
|
||||
}
|
||||
|
||||
override fun isUnsubscribed(): Boolean {
|
||||
return call.isCanceled()
|
||||
}
|
||||
override fun isUnsubscribed(): Boolean = call.isCanceled()
|
||||
}
|
||||
|
||||
subscriber.add(requestArbiter)
|
||||
@@ -60,15 +58,14 @@ fun Call.asObservable(): Observable<Response> {
|
||||
}
|
||||
}
|
||||
|
||||
fun Call.asObservableSuccess(): Observable<Response> {
|
||||
return asObservable()
|
||||
fun Call.asObservableSuccess(): Observable<Response> =
|
||||
asObservable()
|
||||
.doOnNext { response ->
|
||||
if (!response.isSuccessful) {
|
||||
response.close()
|
||||
throw HttpException(response.code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@@ -135,29 +132,28 @@ fun OkHttpClient.newCachelessCallWithProgress(
|
||||
.cache(null)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val originalResponse = chain.proceed(chain.request())
|
||||
originalResponse.newBuilder()
|
||||
originalResponse
|
||||
.newBuilder()
|
||||
.body(ProgressResponseBody(originalResponse.body, listener))
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
}.build()
|
||||
|
||||
return progressClient.newCall(request)
|
||||
}
|
||||
|
||||
context(Json)
|
||||
inline fun <reified T> Response.parseAs(): T {
|
||||
return decodeFromJsonResponse(serializer(), this)
|
||||
}
|
||||
inline fun <reified T> Response.parseAs(): T = decodeFromJsonResponse(serializer(), this)
|
||||
|
||||
context(Json)
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun <T> decodeFromJsonResponse(
|
||||
deserializer: DeserializationStrategy<T>,
|
||||
response: Response,
|
||||
): T {
|
||||
return response.body.source().use {
|
||||
): T =
|
||||
response.body.source().use {
|
||||
decodeFromBufferedSource(deserializer, it)
|
||||
}
|
||||
}
|
||||
|
||||
class HttpException(val code: Int) : IllegalStateException("HTTP error $code")
|
||||
class HttpException(
|
||||
val code: Int,
|
||||
) : IllegalStateException("HTTP error $code")
|
||||
|
||||
@@ -5,7 +5,9 @@ import okhttp3.CookieJar
|
||||
import okhttp3.HttpUrl
|
||||
|
||||
// from TachiWeb-Server
|
||||
class PersistentCookieJar(private val store: PersistentCookieStore) : CookieJar {
|
||||
class PersistentCookieJar(
|
||||
private val store: PersistentCookieStore,
|
||||
) : CookieJar {
|
||||
override fun saveFromResponse(
|
||||
url: HttpUrl,
|
||||
cookies: List<Cookie>,
|
||||
@@ -13,7 +15,5 @@ class PersistentCookieJar(private val store: PersistentCookieStore) : CookieJar
|
||||
store.addAll(url, cookies)
|
||||
}
|
||||
|
||||
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
||||
return store.get(url)
|
||||
}
|
||||
override fun loadForRequest(url: HttpUrl): List<Cookie> = store.get(url)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
// from TachiWeb-Server
|
||||
class PersistentCookieStore(context: Context) : CookieStore {
|
||||
class PersistentCookieStore(
|
||||
context: Context,
|
||||
) : CookieStore {
|
||||
private val cookieMap = ConcurrentHashMap<String, List<Cookie>>()
|
||||
private val prefs = context.getSharedPreferences("cookie_store", Context.MODE_PRIVATE)
|
||||
|
||||
@@ -23,7 +25,8 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
|
||||
init {
|
||||
val domains =
|
||||
prefs.all.keys.map { it.substringBeforeLast(".") }
|
||||
prefs.all.keys
|
||||
.map { it.substringBeforeLast(".") }
|
||||
.toSet()
|
||||
domains.forEach { domain ->
|
||||
val cookies = prefs.getStringSet(domain, emptySet())
|
||||
@@ -31,7 +34,8 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
try {
|
||||
val url = "http://$domain".toHttpUrlOrNull() ?: return@forEach
|
||||
val nonExpiredCookies =
|
||||
cookies.mapNotNull { Cookie.parse(url, it) }
|
||||
cookies
|
||||
.mapNotNull { Cookie.parse(url, it) }
|
||||
.filter { !it.hasExpired() }
|
||||
cookieMap[domain] = nonExpiredCookies
|
||||
} catch (e: Exception) {
|
||||
@@ -63,14 +67,13 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAll(): Boolean {
|
||||
return lock.withLock {
|
||||
override fun removeAll(): Boolean =
|
||||
lock.withLock {
|
||||
val wasNotEmpty = cookieMap.isEmpty()
|
||||
prefs.edit().clear().apply()
|
||||
cookieMap.clear()
|
||||
wasNotEmpty
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(uri: URI) {
|
||||
val url = uri.toURL()
|
||||
@@ -87,9 +90,7 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
}
|
||||
}
|
||||
|
||||
fun get(url: HttpUrl): List<Cookie> {
|
||||
return get(url.host)
|
||||
}
|
||||
fun get(url: HttpUrl): List<Cookie> = get(url.host)
|
||||
|
||||
override fun add(
|
||||
uri: URI?,
|
||||
@@ -105,19 +106,17 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCookies(): List<HttpCookie> {
|
||||
return cookieMap.values.flatMap {
|
||||
override fun getCookies(): List<HttpCookie> =
|
||||
cookieMap.values.flatMap {
|
||||
it.map {
|
||||
it.toHttpCookie()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getURIs(): List<URI> {
|
||||
return cookieMap.keys().toList().map {
|
||||
override fun getURIs(): List<URI> =
|
||||
cookieMap.keys().toList().map {
|
||||
URI("http://$it")
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(
|
||||
uri: URI?,
|
||||
@@ -145,9 +144,7 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
}
|
||||
}
|
||||
|
||||
private fun get(url: String): List<Cookie> {
|
||||
return cookieMap[url].orEmpty().filter { !it.hasExpired() }
|
||||
}
|
||||
private fun get(url: String): List<Cookie> = cookieMap[url].orEmpty().filter { !it.hasExpired() }
|
||||
|
||||
private fun saveToDisk(url: URL) {
|
||||
// Get cookies to be stored in disk
|
||||
@@ -165,7 +162,8 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
private fun Cookie.hasExpired() = System.currentTimeMillis() >= expiresAt
|
||||
|
||||
private fun HttpCookie.toCookie(uri: URI) =
|
||||
Cookie.Builder()
|
||||
Cookie
|
||||
.Builder()
|
||||
.name(name)
|
||||
.value(value)
|
||||
.domain(uri.toURL().host)
|
||||
@@ -176,22 +174,19 @@ class PersistentCookieStore(context: Context) : CookieStore {
|
||||
} else {
|
||||
it.expiresAt(Long.MAX_VALUE)
|
||||
}
|
||||
}
|
||||
.let {
|
||||
}.let {
|
||||
if (secure) {
|
||||
it.secure()
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
.let {
|
||||
}.let {
|
||||
if (isHttpOnly) {
|
||||
it.httpOnly()
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
.build()
|
||||
}.build()
|
||||
|
||||
private fun Cookie.toHttpCookie(): HttpCookie {
|
||||
val it = this
|
||||
|
||||
@@ -9,22 +9,19 @@ import okio.Source
|
||||
import okio.buffer
|
||||
import java.io.IOException
|
||||
|
||||
class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() {
|
||||
class ProgressResponseBody(
|
||||
private val responseBody: ResponseBody,
|
||||
private val progressListener: ProgressListener,
|
||||
) : ResponseBody() {
|
||||
private val bufferedSource: BufferedSource by lazy {
|
||||
source(responseBody.source()).buffer()
|
||||
}
|
||||
|
||||
override fun contentType(): MediaType? {
|
||||
return responseBody.contentType()
|
||||
}
|
||||
override fun contentType(): MediaType? = responseBody.contentType()
|
||||
|
||||
override fun contentLength(): Long {
|
||||
return responseBody.contentLength()
|
||||
}
|
||||
override fun contentLength(): Long = responseBody.contentLength()
|
||||
|
||||
override fun source(): BufferedSource {
|
||||
return bufferedSource
|
||||
}
|
||||
override fun source(): BufferedSource = bufferedSource
|
||||
|
||||
private fun source(source: Source): Source {
|
||||
return object : ForwardingSource(source) {
|
||||
|
||||
@@ -18,13 +18,13 @@ fun GET(
|
||||
url: String,
|
||||
headers: Headers = DEFAULT_HEADERS,
|
||||
cache: CacheControl = DEFAULT_CACHE_CONTROL,
|
||||
): Request {
|
||||
return Request.Builder()
|
||||
): Request =
|
||||
Request
|
||||
.Builder()
|
||||
.url(url)
|
||||
.headers(headers)
|
||||
.cacheControl(cache)
|
||||
.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* @since extensions-lib 1.4
|
||||
@@ -33,52 +33,52 @@ fun GET(
|
||||
url: HttpUrl,
|
||||
headers: Headers = DEFAULT_HEADERS,
|
||||
cache: CacheControl = DEFAULT_CACHE_CONTROL,
|
||||
): Request {
|
||||
return Request.Builder()
|
||||
): Request =
|
||||
Request
|
||||
.Builder()
|
||||
.url(url)
|
||||
.headers(headers)
|
||||
.cacheControl(cache)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun POST(
|
||||
url: String,
|
||||
headers: Headers = DEFAULT_HEADERS,
|
||||
body: RequestBody = DEFAULT_BODY,
|
||||
cache: CacheControl = DEFAULT_CACHE_CONTROL,
|
||||
): Request {
|
||||
return Request.Builder()
|
||||
): Request =
|
||||
Request
|
||||
.Builder()
|
||||
.url(url)
|
||||
.post(body)
|
||||
.headers(headers)
|
||||
.cacheControl(cache)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun PUT(
|
||||
url: String,
|
||||
headers: Headers = DEFAULT_HEADERS,
|
||||
body: RequestBody = DEFAULT_BODY,
|
||||
cache: CacheControl = DEFAULT_CACHE_CONTROL,
|
||||
): Request {
|
||||
return Request.Builder()
|
||||
): Request =
|
||||
Request
|
||||
.Builder()
|
||||
.url(url)
|
||||
.put(body)
|
||||
.headers(headers)
|
||||
.cacheControl(cache)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun DELETE(
|
||||
url: String,
|
||||
headers: Headers = DEFAULT_HEADERS,
|
||||
body: RequestBody = DEFAULT_BODY,
|
||||
cache: CacheControl = DEFAULT_CACHE_CONTROL,
|
||||
): Request {
|
||||
return Request.Builder()
|
||||
): Request =
|
||||
Request
|
||||
.Builder()
|
||||
.url(url)
|
||||
.delete(body)
|
||||
.headers(headers)
|
||||
.cacheControl(cache)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -117,12 +117,12 @@ object CFClearance {
|
||||
serverConfig.flareSolverrTimeout
|
||||
.map { timeoutInt ->
|
||||
val timeout = timeoutInt.seconds
|
||||
network.client.newBuilder()
|
||||
network.client
|
||||
.newBuilder()
|
||||
.callTimeout(timeout.plus(10.seconds).toJavaDuration())
|
||||
.readTimeout(timeout.plus(5.seconds).toJavaDuration())
|
||||
.build()
|
||||
}
|
||||
.stateIn(GlobalScope, SharingStarted.Eagerly, network.client)
|
||||
}.stateIn(GlobalScope, SharingStarted.Eagerly, network.client)
|
||||
}
|
||||
private val json: Json by injectLazy()
|
||||
private val jsonMediaType = "application/json".toMediaType()
|
||||
@@ -190,26 +190,29 @@ object CFClearance {
|
||||
|
||||
return with(json) {
|
||||
mutex.withLock {
|
||||
client.value.newCall(
|
||||
POST(
|
||||
url = serverConfig.flareSolverrUrl.value.removeSuffix("/") + "/v1",
|
||||
body =
|
||||
Json.encodeToString(
|
||||
FlareSolverRequest(
|
||||
"request.get",
|
||||
originalRequest.url.toString(),
|
||||
session = serverConfig.flareSolverrSessionName.value,
|
||||
sessionTtlMinutes = serverConfig.flareSolverrSessionTtl.value,
|
||||
cookies =
|
||||
network.cookieStore.get(originalRequest.url).map {
|
||||
FlareSolverCookie(it.name, it.value)
|
||||
},
|
||||
returnOnlyCookies = onlyCookies,
|
||||
maxTimeout = timeout.inWholeMilliseconds.toInt(),
|
||||
),
|
||||
).toRequestBody(jsonMediaType),
|
||||
),
|
||||
).awaitSuccess().parseAs<FlareSolverResponse>()
|
||||
client.value
|
||||
.newCall(
|
||||
POST(
|
||||
url = serverConfig.flareSolverrUrl.value.removeSuffix("/") + "/v1",
|
||||
body =
|
||||
Json
|
||||
.encodeToString(
|
||||
FlareSolverRequest(
|
||||
"request.get",
|
||||
originalRequest.url.toString(),
|
||||
session = serverConfig.flareSolverrSessionName.value,
|
||||
sessionTtlMinutes = serverConfig.flareSolverrSessionTtl.value,
|
||||
cookies =
|
||||
network.cookieStore.get(originalRequest.url).map {
|
||||
FlareSolverCookie(it.name, it.value)
|
||||
},
|
||||
returnOnlyCookies = onlyCookies,
|
||||
maxTimeout = timeout.inWholeMilliseconds.toInt(),
|
||||
),
|
||||
).toRequestBody(jsonMediaType),
|
||||
),
|
||||
).awaitSuccess()
|
||||
.parseAs<FlareSolverResponse>()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +227,8 @@ object CFClearance {
|
||||
val cookies =
|
||||
flareSolverResponse.solution.cookies
|
||||
.map { cookie ->
|
||||
Cookie.Builder()
|
||||
Cookie
|
||||
.Builder()
|
||||
.name(cookie.name)
|
||||
.value(cookie.value)
|
||||
.domain(cookie.domain.removePrefix("."))
|
||||
@@ -233,13 +237,12 @@ object CFClearance {
|
||||
if (cookie.httpOnly != null && cookie.httpOnly) it.httpOnly()
|
||||
if (cookie.secure != null && cookie.secure) it.secure()
|
||||
if (!cookie.path.isNullOrEmpty()) it.path(cookie.path)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
.groupBy { it.domain }
|
||||
}.build()
|
||||
}.groupBy { it.domain }
|
||||
.flatMap { (domain, cookies) ->
|
||||
network.cookieStore.addAll(
|
||||
HttpUrl.Builder()
|
||||
HttpUrl
|
||||
.Builder()
|
||||
.scheme("http")
|
||||
.host(domain.removePrefix("."))
|
||||
.build(),
|
||||
@@ -254,7 +257,8 @@ object CFClearance {
|
||||
"${it.name}=${it.value}"
|
||||
}
|
||||
logger.trace { "Final cookies\n$finalCookies" }
|
||||
return originalRequest.newBuilder()
|
||||
return originalRequest
|
||||
.newBuilder()
|
||||
.header("Cookie", finalCookies)
|
||||
.header("User-Agent", flareSolverResponse.solution.userAgent)
|
||||
.build()
|
||||
|
||||
@@ -13,8 +13,8 @@ import java.io.IOException
|
||||
* See https://square.github.io/okhttp/4.x/okhttp/okhttp3/-interceptor/
|
||||
*/
|
||||
class UncaughtExceptionInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
return try {
|
||||
override fun intercept(chain: Interceptor.Chain): Response =
|
||||
try {
|
||||
chain.proceed(chain.request())
|
||||
} catch (e: Exception) {
|
||||
if (e is IOException) {
|
||||
@@ -23,5 +23,4 @@ class UncaughtExceptionInterceptor : Interceptor {
|
||||
throw IOException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.network.interceptor
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
class UserAgentInterceptor(private val userAgentProvider: () -> String) : Interceptor {
|
||||
class UserAgentInterceptor(
|
||||
private val userAgentProvider: () -> String,
|
||||
) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val originalRequest = chain.request()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user