mirror of
https://github.com/revanced/revanced-api.git
synced 2025-04-29 22:24:31 +02:00
feat: Add /list
route
This commit is contained in:
parent
e798a4c070
commit
6c930fff9a
@ -21,7 +21,7 @@ tasks {
|
||||
Because semantic-release is not designed to handle this case, we need to hack it.
|
||||
|
||||
RE: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
||||
*/
|
||||
*/
|
||||
register<DefaultTask>("publish") {
|
||||
group = "publishing"
|
||||
description = "Dummy task to hack gradle-semantic-release-plugin to release ReVanced API"
|
||||
@ -41,6 +41,9 @@ ktor {
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url = uri("https://jitpack.io") }
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -72,6 +75,9 @@ dependencies {
|
||||
implementation(libs.ktoml.file)
|
||||
implementation(libs.picocli)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.revanced.patcher)
|
||||
implementation(libs.revanced.library)
|
||||
implementation(libs.caffeine)
|
||||
|
||||
testImplementation(libs.mockk)
|
||||
testImplementation(libs.ktor.server.tests)
|
||||
|
@ -10,6 +10,9 @@ ktoml = "0.5.1"
|
||||
picocli = "4.7.3"
|
||||
datetime = "0.5.0"
|
||||
mockk = "1.13.9"
|
||||
revanced-patcher = "19.2.0"
|
||||
revanced-library = "1.5.0"
|
||||
caffeine = "3.1.8"
|
||||
|
||||
[libraries]
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core" }
|
||||
@ -43,6 +46,9 @@ ktoml-file = { module = "com.akuleshov7:ktoml-file", version.ref = "ktoml" }
|
||||
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
|
||||
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
|
||||
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
|
||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
||||
revanced-library = { module = "app.revanced:revanced-library", version.ref = "revanced-library" }
|
||||
caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" }
|
||||
|
||||
[plugins]
|
||||
serilization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
|
@ -19,8 +19,6 @@ fun Application.configureHTTP() {
|
||||
anyHost() // @TODO: Don't do this in production if possible. Try to limit it.
|
||||
}
|
||||
install(CachingHeaders) {
|
||||
options { _, _ ->
|
||||
CachingOptions(CacheControl.MaxAge(maxAgeSeconds = 5.minutes.inWholeSeconds.toInt()))
|
||||
}
|
||||
options { _, _ -> CachingOptions(CacheControl.MaxAge(maxAgeSeconds = 5.minutes.inWholeSeconds.toInt())) }
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package app.revanced.api.modules
|
||||
|
||||
import app.revanced.api.backend.Backend
|
||||
import app.revanced.api.schema.*
|
||||
import app.revanced.library.PatchUtils
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
@ -12,6 +15,8 @@ import io.ktor.server.routing.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import org.koin.ktor.ext.get as koinGet
|
||||
|
||||
fun Application.configureRouting() {
|
||||
@ -116,34 +121,70 @@ fun Application.configureRouting() {
|
||||
route("/patches") {
|
||||
route("latest") {
|
||||
get {
|
||||
val patches = backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||
val integrations =
|
||||
configuration.integrationsRepositoryNames.map {
|
||||
async { backend.getRelease(configuration.organization, it) }
|
||||
}.awaitAll()
|
||||
val patchesRelease =
|
||||
backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||
val integrationsReleases = configuration.integrationsRepositoryNames.map {
|
||||
async { backend.getRelease(configuration.organization, it) }
|
||||
}.awaitAll()
|
||||
|
||||
val assets =
|
||||
(patches.assets + integrations.flatMap { it.assets }).filter {
|
||||
it.downloadUrl.endsWith(".apk") || it.downloadUrl.endsWith(".jar")
|
||||
}.map { APIAsset(it.downloadUrl) }.toSet()
|
||||
val assets = (patchesRelease.assets + integrationsReleases.flatMap { it.assets })
|
||||
.map { APIAsset(it.downloadUrl) }
|
||||
.filter { it.type != APIAsset.Type.UNKNOWN }
|
||||
.toSet()
|
||||
|
||||
val release =
|
||||
APIRelease(
|
||||
patches.tag,
|
||||
patches.createdAt,
|
||||
patches.releaseNote,
|
||||
assets,
|
||||
)
|
||||
val apiRelease = APIRelease(
|
||||
patchesRelease.tag,
|
||||
patchesRelease.createdAt,
|
||||
patchesRelease.releaseNote,
|
||||
assets,
|
||||
)
|
||||
|
||||
call.respond(release)
|
||||
call.respond(apiRelease)
|
||||
}
|
||||
|
||||
get("/version") {
|
||||
val patches = backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||
val patchesRelease =
|
||||
backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||
|
||||
val release = APIReleaseVersion(patches.tag)
|
||||
val apiPatchesRelease = APIReleaseVersion(patchesRelease.tag)
|
||||
|
||||
call.respond(release)
|
||||
call.respond(apiPatchesRelease)
|
||||
}
|
||||
|
||||
val fileCache = Caffeine
|
||||
.newBuilder()
|
||||
.evictionListener<String, File> { _, value, _ -> value?.delete() }
|
||||
.maximumSize(1)
|
||||
.build<String, File>()
|
||||
|
||||
get("/list") {
|
||||
val patchesRelease =
|
||||
backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||
|
||||
// Get the cached patches file or download and cache a new one.
|
||||
// The old file is deleted on eviction.
|
||||
val patchesFile = fileCache.getIfPresent(patchesRelease.tag) ?: run {
|
||||
val downloadUrl = patchesRelease.assets
|
||||
.map { APIAsset(it.downloadUrl) }
|
||||
.find { it.type == APIAsset.Type.PATCHES }
|
||||
?.downloadUrl
|
||||
|
||||
kotlin.io.path.createTempFile().toFile().apply {
|
||||
outputStream().use { URL(downloadUrl).openStream().copyTo(it) }
|
||||
}.also {
|
||||
fileCache.put(patchesRelease.tag, it)
|
||||
it.deleteOnExit()
|
||||
}
|
||||
}
|
||||
|
||||
call.respondOutputStream(
|
||||
contentType = ContentType.Application.Json,
|
||||
) {
|
||||
PatchUtils.Json.serialize(
|
||||
PatchBundleLoader.Jar(patchesFile),
|
||||
outputStream = this,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app.revanced.api.schema
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@ -44,9 +45,20 @@ class APIAsset(
|
||||
val downloadUrl: String,
|
||||
) {
|
||||
val type = when {
|
||||
downloadUrl.endsWith(".jar") -> "patches"
|
||||
downloadUrl.endsWith(".apk") -> "integrations"
|
||||
else -> "unknown"
|
||||
downloadUrl.endsWith(".jar") -> Type.PATCHES
|
||||
downloadUrl.endsWith(".apk") -> Type.INTEGRATIONS
|
||||
else -> Type.UNKNOWN
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
@SerialName("patches")
|
||||
PATCHES,
|
||||
|
||||
@SerialName("integrations")
|
||||
INTEGRATIONS,
|
||||
|
||||
@SerialName("unknown")
|
||||
UNKNOWN,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user