Extension repo fixes and improvements (#811)

This commit is contained in:
Mitchell Syer
2024-01-09 19:42:53 -05:00
committed by GitHub
parent 188fb188ce
commit e5476f8a01
6 changed files with 37 additions and 51 deletions
@@ -61,7 +61,11 @@ object Extension {
val extensionRecord = extensionTableAsDataClass().first { it.pkgName == pkgName }
return installAPK {
val apkURL = ExtensionGithubApi.getApkUrl(extensionRecord)
val apkURL =
ExtensionGithubApi.getApkUrl(
extensionRecord.repo ?: throw NullPointerException("Could not find extension repo"),
extensionRecord.apkName,
)
val apkName = Uri.parse(apkURL).lastPathSegment!!
val apkSavePath = "${applicationDirs.extensionsRoot}/$apkName"
// download apk file
@@ -36,9 +36,9 @@ object ExtensionsList {
suspend fun fetchExtensions() {
// update if 60 seconds has passed or requested offline and database is empty
val extensions =
(listOf(ExtensionGithubApi.REPO_URL_PREFIX) + serverConfig.extensionRepos.value).map { repo ->
serverConfig.extensionRepos.value.map { repo ->
kotlin.runCatching {
ExtensionGithubApi.findExtensions(repo)
ExtensionGithubApi.findExtensions(repo.repoUrlReplace())
}.onFailure {
logger.warn(it) {
"Failed to fetch extensions for repo: $repo"
@@ -119,8 +119,9 @@ object ExtensionsList {
BatchUpdateStatement(ExtensionTable).apply {
installedExtensionsToUpdate.forEach { (foundExtension, extensionRecord) ->
addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable))
// Always update icon url
// Always update icon url and repo
this[ExtensionTable.iconUrl] = foundExtension.iconUrl
this[ExtensionTable.repo] = foundExtension.repo
// add these because batch updates need matching columns
this[ExtensionTable.hasUpdate] = extensionRecord[ExtensionTable.hasUpdate]
@@ -199,4 +200,23 @@ object ExtensionsList {
}
}
}
private fun String.repoUrlReplace(): String {
return if (contains("github")) {
replace(repoMatchRegex) {
"https://raw.githubusercontent.com/${it.groupValues[2]}/${it.groupValues[3]}/" +
(it.groupValues.getOrNull(4)?.ifBlank { null } ?: "repo") +
"/" +
(it.groupValues.getOrNull(5)?.ifBlank { null } ?: "index.min.json")
}
} else {
this
}
}
private val repoMatchRegex =
(
"https:\\/\\/(?>www\\.|raw\\.)?(github|githubusercontent)\\.com" +
"\\/([^\\/]+)\\/([^\\/]+)(?>(?>\\/tree|\\/blob)?\\/([^\\/\\n]*))?(?>\\/([^\\/\\n]*\\.json)?)?"
).toRegex()
}
@@ -16,12 +16,9 @@ import kotlinx.serialization.json.Json
import mu.KotlinLogging
import suwayomi.tachidesk.manga.impl.util.PackageTools.LIB_VERSION_MAX
import suwayomi.tachidesk.manga.impl.util.PackageTools.LIB_VERSION_MIN
import suwayomi.tachidesk.manga.model.dataclass.ExtensionDataClass
import uy.kohesive.injekt.injectLazy
object ExtensionGithubApi {
const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/"
private const val FALLBACK_REPO_URL_PREFIX = "https://gcore.jsdelivr.net/gh/tachiyomiorg/tachiyomi-extensions@repo/"
private val logger = KotlinLogging.logger {}
private val json: Json by injectLazy()
@@ -47,36 +44,22 @@ object ExtensionGithubApi {
val baseUrl: String,
)
private var requiresFallbackSource = false
suspend fun findExtensions(repo: String): List<OnlineExtension> {
val githubResponse =
if (requiresFallbackSource) {
null
} else {
try {
client.newCall(GET("${repo.repoUrlReplace()}index.min.json")).awaitSuccess()
} catch (e: Throwable) {
logger.error(e) { "Failed to get extensions from GitHub" }
requiresFallbackSource = true
null
}
}
val response =
githubResponse ?: run {
client.newCall(GET("${repo.fallbackRepoUrlReplace()}index.min.json")).awaitSuccess()
}
client.newCall(GET(repo)).awaitSuccess()
return with(json) {
response
.parseAs<List<ExtensionJsonObject>>()
.toExtensions(repo.repoUrlReplace())
.toExtensions(repo.substringBeforeLast('/') + '/')
}
}
fun getApkUrl(extension: ExtensionDataClass): String {
return "${extension.repo!!.repoUrlReplace()}/apk/${extension.apkName}"
fun getApkUrl(
repo: String,
apkName: String,
): String {
return "${repo}apk/$apkName"
}
private val client by lazy {
@@ -125,22 +108,4 @@ object ExtensionGithubApi {
)
}
}
private fun String.repoUrlReplace() =
replace(repoMatchRegex) {
"https://raw.githubusercontent.com/${it.groupValues[1]}/${it.groupValues[2]}/" +
"${it.groupValues.getOrNull(3)?.ifBlank { null } ?: "repo"}/"
}
private fun String.fallbackRepoUrlReplace() =
replace(repoMatchRegex) {
"https://gcore.jsdelivr.net/gh/${it.groupValues[1]}/${it.groupValues[2]}@" +
"${it.groupValues.getOrNull(3)?.ifBlank { null } ?: "repo"}/"
}
private val repoMatchRegex =
(
"https:\\/\\/(?:www|raw)?(?:github|githubusercontent)\\.com" +
"\\/([^\\/]+)\\/([^\\/]+)(?:\\/(?:tree|blob)\\/(.*))?\\/?"
).toRegex()
}
@@ -43,9 +43,6 @@ object PackageTools {
const val LIB_VERSION_MIN = 1.3
const val LIB_VERSION_MAX = 1.5
private const val OFFICIAL_SIGNATURE = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" // inorichi's key
val trustedSignatures = setOf(OFFICIAL_SIGNATURE)
/**
* Convert dex to jar, a wrapper for the dex2jar library
*/