Clean up external repos

- Accept full URL as input instead, which allows for non-GitHub
- Remove automatic CDN fallback in favor of adding that as an external repo if needed
This commit is contained in:
arkon
2024-01-05 23:13:16 -05:00
parent 556f5a42a7
commit 9c899e97a9
20 changed files with 252 additions and 183 deletions

View File

@@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.extension
import android.content.Context
import android.graphics.drawable.Drawable
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
import eu.kanade.tachiyomi.extension.api.ExtensionApi
import eu.kanade.tachiyomi.extension.api.ExtensionUpdateNotifier
import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.extension.model.InstallStep
@@ -49,7 +49,7 @@ class ExtensionManager(
/**
* API where all the available extensions can be found.
*/
private val api = ExtensionGithubApi()
private val api = ExtensionApi()
/**
* The installer which installs, updates and uninstalls the extensions.

View File

@@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.extension.api
import android.content.Context
import eu.kanade.domain.source.interactor.OFFICIAL_REPO_BASE_URL
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.extension.model.Extension
@@ -21,7 +22,7 @@ import uy.kohesive.injekt.injectLazy
import java.time.Instant
import kotlin.time.Duration.Companion.days
internal class ExtensionGithubApi {
internal class ExtensionApi {
private val networkService: NetworkHelper by injectLazy()
private val preferenceStore: PreferenceStore by injectLazy()
@@ -33,52 +34,16 @@ internal class ExtensionGithubApi {
preferenceStore.getLong(Preference.appStateKey("last_ext_check"), 0)
}
private var requiresFallbackSource = false
suspend fun findExtensions(): List<Extension.Available> {
return withIOContext {
val githubResponse = if (requiresFallbackSource) {
null
} else {
try {
networkService.client
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
.awaitSuccess()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
requiresFallbackSource = true
null
}
}
val response = githubResponse ?: run {
networkService.client
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
.awaitSuccess()
}
val extensions = with(json) {
response
.parseAs<List<ExtensionJsonObject>>()
.toExtensions() + sourcePreferences.extensionRepos()
.get()
.flatMap { repoPath ->
val url = if (requiresFallbackSource) {
"$FALLBACK_BASE_URL$repoPath@repo/"
} else {
"$BASE_URL$repoPath/repo/"
}
networkService.client
.newCall(GET("${url}index.min.json"))
.awaitSuccess()
.parseAs<List<ExtensionJsonObject>>()
.toExtensions(url, repoSource = true)
}
val extensions = buildList {
addAll(getExtensions(OFFICIAL_REPO_BASE_URL, true))
sourcePreferences.extensionRepos().get().map { addAll(getExtensions(it, false)) }
}
// Sanity check - a small number of extensions probably means something broke
// with the repo generator
if (extensions.size < 100) {
if (extensions.size < 50) {
throw Exception()
}
@@ -86,6 +51,26 @@ internal class ExtensionGithubApi {
}
}
private suspend fun getExtensions(
repoBaseUrl: String,
isOfficialRepo: Boolean,
): List<Extension.Available> {
return try {
val response = networkService.client
.newCall(GET("$repoBaseUrl/index.min.json"))
.awaitSuccess()
with(json) {
response
.parseAs<List<ExtensionJsonObject>>()
.toExtensions(repoBaseUrl, isRepoSource = !isOfficialRepo)
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from $repoBaseUrl" }
emptyList()
}
}
suspend fun checkForUpdates(
context: Context,
fromAvailableExtensionList: Boolean = false,
@@ -127,8 +112,8 @@ internal class ExtensionGithubApi {
}
private fun List<ExtensionJsonObject>.toExtensions(
repoUrl: String = getUrlPrefix(),
repoSource: Boolean = false,
repoUrl: String,
isRepoSource: Boolean,
): List<Extension.Available> {
return this
.filter {
@@ -146,9 +131,9 @@ internal class ExtensionGithubApi {
isNsfw = it.nsfw == 1,
sources = it.sources?.map(extensionSourceMapper).orEmpty(),
apkName = it.apk,
iconUrl = "${repoUrl}icon/${it.pkg}.png",
iconUrl = "$repoUrl/icon/${it.pkg}.png",
repoUrl = repoUrl,
isRepoSource = repoSource,
isRepoSource = isRepoSource,
)
}
}
@@ -157,24 +142,11 @@ internal class ExtensionGithubApi {
return "${extension.repoUrl}/apk/${extension.apkName}"
}
private fun getUrlPrefix(): String {
return if (requiresFallbackSource) {
FALLBACK_REPO_URL_PREFIX
} else {
REPO_URL_PREFIX
}
}
private fun ExtensionJsonObject.extractLibVersion(): Double {
return version.substringBeforeLast('.').toDouble()
}
}
private const val BASE_URL = "https://raw.githubusercontent.com/"
private const val REPO_URL_PREFIX = "${BASE_URL}tachiyomiorg/tachiyomi-extensions/repo/"
private const val FALLBACK_BASE_URL = "https://gcore.jsdelivr.net/gh/"
private const val FALLBACK_REPO_URL_PREFIX = "${FALLBACK_BASE_URL}tachiyomiorg/tachiyomi-extensions@repo/"
@Serializable
private data class ExtensionJsonObject(
val name: String,