rewrite without retrofit and kotlin-serialization

This commit is contained in:
Aria Moradi 2021-05-20 19:20:07 +04:30
parent 88b881b043
commit 154b9992eb
3 changed files with 76 additions and 59 deletions

View File

@ -28,13 +28,6 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttpVersion") implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttpVersion")
implementation("com.squareup.okio:okio:2.10.0") implementation("com.squareup.okio:okio:2.10.0")
// Retrofit, used in `ExtensionGithubService`
val retrofitVersion = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0")
implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
implementation("com.squareup.retrofit2:adapter-rxjava:$retrofitVersion")
// Javalin api // Javalin api
implementation("io.javalin:javalin:3.13.6") implementation("io.javalin:javalin:3.13.6")
// jackson version is tied to javalin, ref: `io.javalin.core.util.OptionalDependency` // jackson version is tied to javalin, ref: `io.javalin.core.util.OptionalDependency`
@ -54,9 +47,6 @@ dependencies {
implementation("com.dorkbox:SystemTray:4.1") implementation("com.dorkbox:SystemTray:4.1")
implementation("com.dorkbox:Utilities:1.9") implementation("com.dorkbox:Utilities:1.9")
// misc
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0")
// dependencies of Tachiyomi extensions, some are duplicate, keeping it here for reference // dependencies of Tachiyomi extensions, some are duplicate, keeping it here for reference
implementation("com.github.inorichi.injekt:injekt-core:65b0440") implementation("com.github.inorichi.injekt:injekt-core:65b0440")

View File

@ -7,13 +7,12 @@ package eu.kanade.tachiyomi.extension.api
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import com.github.salomonbrys.kotson.int
import com.github.salomonbrys.kotson.string
import com.google.gson.JsonArray
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.extension.util.ExtensionLoader
import ir.armor.tachidesk.model.dataclass.ExtensionDataClass import ir.armor.tachidesk.model.dataclass.ExtensionDataClass
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
object ExtensionGithubApi { object ExtensionGithubApi {
const val BASE_URL = "https://raw.githubusercontent.com" const val BASE_URL = "https://raw.githubusercontent.com"
@ -21,19 +20,20 @@ object ExtensionGithubApi {
private fun parseResponse(json: JsonArray): List<Extension.Available> { private fun parseResponse(json: JsonArray): List<Extension.Available> {
return json return json
.map { it.asJsonObject }
.filter { element -> .filter { element ->
val versionName = element.jsonObject["version"]!!.jsonPrimitive.content val versionName = element["version"].string
val libVersion = versionName.substringBeforeLast('.').toDouble() val libVersion = versionName.substringBeforeLast('.').toDouble()
libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX
} }
.map { element -> .map { element ->
val name = element.jsonObject["name"]!!.jsonPrimitive.content.substringAfter("Tachiyomi: ") val name = element["name"].string.substringAfter("Tachiyomi: ")
val pkgName = element.jsonObject["pkg"]!!.jsonPrimitive.content val pkgName = element["pkg"].string
val apkName = element.jsonObject["apk"]!!.jsonPrimitive.content val apkName = element["apk"].string
val versionName = element.jsonObject["version"]!!.jsonPrimitive.content val versionName = element["version"].string
val versionCode = element.jsonObject["code"]!!.jsonPrimitive.int val versionCode = element["code"].int
val lang = element.jsonObject["lang"]!!.jsonPrimitive.content val lang = element["lang"].string
val nsfw = element.jsonObject["nsfw"]!!.jsonPrimitive.int == 1 val nsfw = element["nsfw"].int == 1
val icon = "$REPO_URL_PREFIX/icon/${apkName.replace(".apk", ".png")}" val icon = "$REPO_URL_PREFIX/icon/${apkName.replace(".apk", ".png")}"
Extension.Available(name, pkgName, versionName, versionCode, lang, nsfw, apkName, icon) Extension.Available(name, pkgName, versionName, versionCode, lang, nsfw, apkName, icon)
@ -41,9 +41,8 @@ object ExtensionGithubApi {
} }
suspend fun findExtensions(): List<Extension.Available> { suspend fun findExtensions(): List<Extension.Available> {
val service: ExtensionGithubService = ExtensionGithubService.create()
val response = service.getRepo() val response = ExtensionGithubService.getRepo()
return parseResponse(response) return parseResponse(response)
} }

View File

@ -1,46 +1,74 @@
package eu.kanade.tachiyomi.extension.api package eu.kanade.tachiyomi.extension.api
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import com.google.gson.JsonParser
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import kotlinx.serialization.ExperimentalSerializationApi import okhttp3.Headers
import kotlinx.serialization.json.Json import okhttp3.Interceptor
import kotlinx.serialization.json.JsonArray import okhttp3.Interceptor.Chain
import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request
import retrofit2.Retrofit import okhttp3.Response
import retrofit2.http.GET import okhttp3.internal.http.RealResponseBody
import okio.GzipSource
import okio.buffer
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
/** /**
* Used to get the extension repo listing from GitHub. * Used to get the extension repo listing from GitHub.
*/ */
interface ExtensionGithubService { object ExtensionGithubService {
private val client by lazy {
companion object { val network: NetworkHelper by injectLazy()
private val client by lazy { network.client.newBuilder()
val network: NetworkHelper by injectLazy() .addNetworkInterceptor { chain ->
network.client.newBuilder() val originalResponse = chain.proceed(chain.request())
.addNetworkInterceptor { chain -> originalResponse.newBuilder()
val originalResponse = chain.proceed(chain.request()) .header("Content-Encoding", "gzip")
originalResponse.newBuilder() .header("Content-Type", "application/json")
.header("Content-Encoding", "gzip") .build()
.header("Content-Type", "application/json") }
.build() .addInterceptor(UnzippingInterceptor())
} .build()
.build()
}
@ExperimentalSerializationApi
fun create(): ExtensionGithubService {
val adapter = Retrofit.Builder() // TODO: rewrite in order to not depend on retrofit2
.baseUrl(ExtensionGithubApi.BASE_URL)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.client(client)
.build()
return adapter.create(ExtensionGithubService::class.java)
}
} }
@GET("${ExtensionGithubApi.REPO_URL_PREFIX}/index.json.gz") suspend fun getRepo(): com.google.gson.JsonArray {
suspend fun getRepo(): JsonArray val request = Request.Builder()
.url("${ExtensionGithubApi.REPO_URL_PREFIX}/index.json.gz")
.build()
val response = client.newCall(request).execute().use { response -> response.body!!.string() }
return JsonParser.parseString(response).asJsonArray
}
}
private class UnzippingInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Chain): Response {
val response: Response = chain.proceed(chain.request())
return unzip(response)
}
// ref: https://stackoverflow.com/questions/51901333/okhttp-3-how-to-decompress-gzip-deflate-response-manually-using-java-android
@Throws(IOException::class)
private fun unzip(response: Response): Response {
if (response.body == null) {
return response
}
// check if we have gzip response
val contentEncoding: String? = response.headers["Content-Encoding"]
// this is used to decompress gzipped responses
return if (contentEncoding != null && contentEncoding == "gzip") {
val body = response.body!!
val contentLength: Long = body.contentLength()
val responseBody = GzipSource(body.source())
val strippedHeaders: Headers = response.headers.newBuilder().build()
response.newBuilder().headers(strippedHeaders)
.body(RealResponseBody(body.contentType().toString(), contentLength, responseBody.buffer()))
.build()
} else {
response
}
}
} }