Use jsDelivr as fallback when GitHub can't be reached for extensions (closes #5517)

Re-implementation of 24bb2f02dce135e0ceb2856618ecfc0e30dce875

(cherry picked from commit d61bfd7cafa09ff6c5f159c945984f2e8d9904b9)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt
(cherry picked from commit 4458f74f6c06fb9a2879bd530a20aaec61c06658)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/extension/ExtensionScreen.kt
This commit is contained in:
arkon 2022-05-15 16:51:52 -04:00 committed by Jobobby04
parent 9e31806e5c
commit 153022df0a
3 changed files with 52 additions and 18 deletions

View File

@ -12,7 +12,9 @@ import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.source.BlacklistedSources import exh.source.BlacklistedSources
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import logcat.LogPriority
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -22,21 +24,38 @@ internal class ExtensionGithubApi {
private val networkService: NetworkHelper by injectLazy() private val networkService: NetworkHelper by injectLazy()
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
private var requiresFallbackSource = false
suspend fun findExtensions(): List<Extension.Available> { suspend fun findExtensions(): List<Extension.Available> {
return withIOContext { return withIOContext {
val extensions = networkService.client val response = try {
.newCall(GET("${REPO_URL_PREFIX}index.min.json")) networkService.client
.await() .newCall(GET("${REPO_URL_PREFIX}index.min.json"))
.await()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
requiresFallbackSource = true
networkService.client
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
.await()
}
val extensions = response
.parseAs<List<ExtensionJsonObject>>() .parseAs<List<ExtensionJsonObject>>()
.toExtensions() /* SY --> */ + preferences.extensionRepos() .toExtensions() /* SY --> */ + preferences.extensionRepos()
.get() .get()
.flatMap { repoPath -> .flatMap { repoPath ->
val url = "$BASE_URL$repoPath/repo/" val url = if (requiresFallbackSource) {
"$FALLBACK_BASE_URL$repoPath@repo/"
} else {
"$BASE_URL$repoPath/repo/"
}
networkService.client networkService.client
.newCall(GET("${url}index.min.json")) .newCall(GET("${url}index.min.json"))
.await() .await()
.parseAs<List<ExtensionJsonObject>>() .parseAs<List<ExtensionJsonObject>>()
.toExtensions(url) .toExtensions(url, repoSource = true)
} }
// SY <-- // SY <--
@ -85,7 +104,12 @@ internal class ExtensionGithubApi {
return extensionsWithUpdate return extensionsWithUpdate
} }
private fun List<ExtensionJsonObject>.toExtensions(/* SY --> */ repoUrl: String = REPO_URL_PREFIX /* SY <-- */): List<Extension.Available> { private fun List<ExtensionJsonObject>.toExtensions(
// SY -->
repoUrl: String = getUrlPrefix(),
repoSource: Boolean = false
// SY <--
): List<Extension.Available> {
return this return this
.filter { .filter {
val libVersion = it.version.substringBeforeLast('.').toDouble() val libVersion = it.version.substringBeforeLast('.').toDouble()
@ -106,6 +130,7 @@ internal class ExtensionGithubApi {
iconUrl = "${/* SY --> */ repoUrl /* SY <-- */}icon/${it.apk.replace(".apk", ".png")}", iconUrl = "${/* SY --> */ repoUrl /* SY <-- */}icon/${it.apk.replace(".apk", ".png")}",
// SY --> // SY -->
repoUrl = repoUrl, repoUrl = repoUrl,
isRepoSource = repoSource
// SY <-- // SY <--
) )
} }
@ -125,6 +150,14 @@ internal class ExtensionGithubApi {
return /* SY --> */ "${extension.repoUrl}/apk/${extension.apkName}" // SY <-- return /* SY --> */ "${extension.repoUrl}/apk/${extension.apkName}" // SY <--
} }
private fun getUrlPrefix(): String {
return if (requiresFallbackSource) {
FALLBACK_REPO_URL_PREFIX
} else {
REPO_URL_PREFIX
}
}
// SY --> // SY -->
private fun Extension.isBlacklisted( private fun Extension.isBlacklisted(
blacklistEnabled: Boolean = preferences.enableSourceBlacklist().get(), blacklistEnabled: Boolean = preferences.enableSourceBlacklist().get(),
@ -134,8 +167,10 @@ internal class ExtensionGithubApi {
// SY <-- // SY <--
} }
const val BASE_URL = "https://raw.githubusercontent.com/" private const val BASE_URL = "https://raw.githubusercontent.com/"
const val REPO_URL_PREFIX = "${BASE_URL}tachiyomiorg/tachiyomi-extensions/repo/" private const val REPO_URL_PREFIX = "${BASE_URL}tachiyomiorg/tachiyomi-extensions/repo/"
private const val FALLBACK_BASE_URL = "https://cdn.jsdelivr.net/gh/"
private const val FALLBACK_REPO_URL_PREFIX = "${FALLBACK_BASE_URL}tachiyomiorg/tachiyomi-extensions@repo/"
@Serializable @Serializable
private data class ExtensionJsonObject( private data class ExtensionJsonObject(

View File

@ -48,6 +48,7 @@ sealed class Extension {
val iconUrl: String, val iconUrl: String,
// SY --> // SY -->
val repoUrl: String, val repoUrl: String,
val isRepoSource: Boolean,
// SY <-- // SY <--
) : Extension() ) : Extension()

View File

@ -8,7 +8,6 @@ import coil.load
import eu.davidea.viewholders.FlexibleViewHolder import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.ExtensionItemBinding import eu.kanade.tachiyomi.databinding.ExtensionItemBinding
import eu.kanade.tachiyomi.extension.api.REPO_URL_PREFIX
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.extension.model.InstallStep
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
@ -57,15 +56,14 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
// SY --> // SY -->
private fun String.plusRepo(extension: Extension): String { private fun String.plusRepo(extension: Extension): String {
return if (extension is Extension.Available) { return if (extension is Extension.Available) {
when (extension.repoUrl) { if (!extension.isRepoSource) {
REPO_URL_PREFIX -> this this
else -> { } else {
if (isEmpty()) { if (isEmpty()) {
this this
} else { } else {
this + "" "$this"
} + itemView.context.getString(R.string.repo_source) } + itemView.context.getString(R.string.repo_source)
}
} }
} else this } else this
} }