mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-12 12:08:56 +01:00
Remove built-in official extension repo support
This commit is contained in:
@@ -178,7 +178,7 @@ class ExtensionManager(
|
||||
val pkgName = installedExt.pkgName
|
||||
val availableExt = availableExtensions.find { it.pkgName == pkgName }
|
||||
|
||||
if (!installedExt.isUnofficial && availableExt == null && !installedExt.isObsolete) {
|
||||
if (availableExt == null && !installedExt.isObsolete) {
|
||||
mutInstalledExtensions[index] = installedExt.copy(isObsolete = true)
|
||||
changed = true
|
||||
} else if (availableExt != null) {
|
||||
@@ -187,13 +187,11 @@ class ExtensionManager(
|
||||
if (installedExt.hasUpdate != hasUpdate) {
|
||||
mutInstalledExtensions[index] = installedExt.copy(
|
||||
hasUpdate = hasUpdate,
|
||||
isFromExternalRepo = availableExt.isFromExternalRepo,
|
||||
repoUrl = availableExt.repoUrl,
|
||||
)
|
||||
changed = true
|
||||
} else if (availableExt.isFromExternalRepo) {
|
||||
} else {
|
||||
mutInstalledExtensions[index] = installedExt.copy(
|
||||
isFromExternalRepo = true,
|
||||
repoUrl = availableExt.repoUrl,
|
||||
)
|
||||
changed = true
|
||||
@@ -363,7 +361,7 @@ class ExtensionManager(
|
||||
|
||||
private fun Extension.Installed.updateExists(availableExtension: Extension.Available? = null): Boolean {
|
||||
val availableExt = availableExtension ?: _availableExtensionsFlow.value.find { it.pkgName == pkgName }
|
||||
if (isUnofficial || availableExt == null) return false
|
||||
?: return false
|
||||
|
||||
return (availableExt.versionCode > versionCode || availableExt.libVersion > libVersion)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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
|
||||
@@ -36,14 +35,11 @@ internal class ExtensionApi {
|
||||
|
||||
suspend fun findExtensions(): List<Extension.Available> {
|
||||
return withIOContext {
|
||||
val extensions = buildList {
|
||||
addAll(getExtensions(OFFICIAL_REPO_BASE_URL, true))
|
||||
sourcePreferences.extensionRepos().get().map { addAll(getExtensions(it, false)) }
|
||||
}
|
||||
val extensions = sourcePreferences.extensionRepos().get().flatMap { getExtensions(it) }
|
||||
|
||||
// Sanity check - a small number of extensions probably means something broke
|
||||
// with the repo generator
|
||||
if (extensions.size < 50) {
|
||||
if (extensions.isEmpty()) {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
@@ -51,10 +47,7 @@ internal class ExtensionApi {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getExtensions(
|
||||
repoBaseUrl: String,
|
||||
isOfficialRepo: Boolean,
|
||||
): List<Extension.Available> {
|
||||
private suspend fun getExtensions(repoBaseUrl: String): List<Extension.Available> {
|
||||
return try {
|
||||
val response = networkService.client
|
||||
.newCall(GET("$repoBaseUrl/index.min.json"))
|
||||
@@ -63,7 +56,7 @@ internal class ExtensionApi {
|
||||
with(json) {
|
||||
response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions(repoBaseUrl, isRepoSource = !isOfficialRepo)
|
||||
.toExtensions(repoBaseUrl)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to get extensions from $repoBaseUrl" }
|
||||
@@ -98,7 +91,7 @@ internal class ExtensionApi {
|
||||
val availableExt = extensions.find { it.pkgName == pkgName } ?: continue
|
||||
val hasUpdatedVer = availableExt.versionCode > installedExt.versionCode
|
||||
val hasUpdatedLib = availableExt.libVersion > installedExt.libVersion
|
||||
val hasUpdate = installedExt.isUnofficial.not() && (hasUpdatedVer || hasUpdatedLib)
|
||||
val hasUpdate = hasUpdatedVer || hasUpdatedLib
|
||||
if (hasUpdate) {
|
||||
extensionsWithUpdate.add(installedExt)
|
||||
}
|
||||
@@ -111,10 +104,7 @@ internal class ExtensionApi {
|
||||
return extensionsWithUpdate
|
||||
}
|
||||
|
||||
private fun List<ExtensionJsonObject>.toExtensions(
|
||||
repoUrl: String,
|
||||
isRepoSource: Boolean,
|
||||
): List<Extension.Available> {
|
||||
private fun List<ExtensionJsonObject>.toExtensions(repoUrl: String): List<Extension.Available> {
|
||||
return this
|
||||
.filter {
|
||||
val libVersion = it.extractLibVersion()
|
||||
@@ -133,7 +123,6 @@ internal class ExtensionApi {
|
||||
apkName = it.apk,
|
||||
iconUrl = "$repoUrl/icon/${it.pkg}.png",
|
||||
repoUrl = repoUrl,
|
||||
isFromExternalRepo = isRepoSource,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,8 @@ sealed class Extension {
|
||||
val icon: Drawable?,
|
||||
val hasUpdate: Boolean = false,
|
||||
val isObsolete: Boolean = false,
|
||||
val isUnofficial: Boolean = false,
|
||||
val isShared: Boolean,
|
||||
val repoUrl: String? = null,
|
||||
val isFromExternalRepo: Boolean = false,
|
||||
) : Extension()
|
||||
|
||||
data class Available(
|
||||
@@ -45,7 +43,6 @@ sealed class Extension {
|
||||
val apkName: String,
|
||||
val iconUrl: String,
|
||||
val repoUrl: String,
|
||||
val isFromExternalRepo: Boolean,
|
||||
) : Extension() {
|
||||
|
||||
data class Source(
|
||||
|
||||
@@ -59,9 +59,6 @@ internal object ExtensionLoader {
|
||||
PackageManager.GET_SIGNATURES or
|
||||
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) PackageManager.GET_SIGNING_CERTIFICATES else 0)
|
||||
|
||||
// inorichi's key
|
||||
private const val officialSignature = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23"
|
||||
|
||||
private const val PRIVATE_EXTENSION_EXTENSION = "ext"
|
||||
|
||||
private fun getPrivateExtensionDir(context: Context) = File(context.filesDir, "exts")
|
||||
@@ -255,7 +252,7 @@ internal object ExtensionLoader {
|
||||
if (signatures.isNullOrEmpty()) {
|
||||
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
|
||||
return LoadResult.Error
|
||||
} else if (!isTrusted(pkgInfo, signatures)) {
|
||||
} else if (!trustExtension.isTrusted(pkgInfo, signatures.last())) {
|
||||
val extension = Extension.Untrusted(
|
||||
extName,
|
||||
pkgName,
|
||||
@@ -323,7 +320,6 @@ internal object ExtensionLoader {
|
||||
isNsfw = isNsfw,
|
||||
sources = sources,
|
||||
pkgFactory = appInfo.metaData.getString(METADATA_SOURCE_FACTORY),
|
||||
isUnofficial = !isOfficiallySigned(signatures),
|
||||
icon = appInfo.loadIcon(pkgManager),
|
||||
isShared = extensionInfo.isShared,
|
||||
)
|
||||
@@ -383,18 +379,6 @@ internal object ExtensionLoader {
|
||||
?.toList()
|
||||
}
|
||||
|
||||
private fun isTrusted(pkgInfo: PackageInfo, signatures: List<String>): Boolean {
|
||||
if (officialSignature in signatures) {
|
||||
return true
|
||||
}
|
||||
|
||||
return trustExtension.isTrusted(pkgInfo, signatures.last())
|
||||
}
|
||||
|
||||
private fun isOfficiallySigned(signatures: List<String>): Boolean {
|
||||
return signatures.all { it == officialSignature }
|
||||
}
|
||||
|
||||
/**
|
||||
* On Android 13+ the ApplicationInfo generated by getPackageArchiveInfo doesn't
|
||||
* have sourceDir which breaks assets loading (used for getting icon here).
|
||||
|
||||
@@ -5,7 +5,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
@@ -30,13 +29,11 @@ data class ExtensionDetailsScreen(
|
||||
}
|
||||
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
ExtensionDetailsScreen(
|
||||
navigateUp = navigator::pop,
|
||||
state = state,
|
||||
onClickSourcePreferences = { navigator.push(SourcePreferencesScreen(it)) },
|
||||
onClickWhatsNew = { uriHandler.openUri(screenModel.getChangelogUrl()) },
|
||||
onClickEnableAll = { screenModel.toggleSources(true) },
|
||||
onClickDisableAll = { screenModel.toggleSources(false) },
|
||||
onClickClearCookies = screenModel::clearCookies,
|
||||
|
||||
@@ -29,9 +29,6 @@ import tachiyomi.core.util.system.logcat
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
private const val URL_EXTENSION_COMMITS =
|
||||
"https://github.com/tachiyomiorg/tachiyomi-extensions/commits/master"
|
||||
|
||||
class ExtensionDetailsScreenModel(
|
||||
pkgName: String,
|
||||
context: Context,
|
||||
@@ -86,16 +83,6 @@ class ExtensionDetailsScreenModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun getChangelogUrl(): String {
|
||||
val extension = state.value.extension ?: return ""
|
||||
|
||||
val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.")
|
||||
val pkgFactory = extension.pkgFactory
|
||||
|
||||
// Falling back on GitHub commit history because there is no explicit changelog in extension
|
||||
return createUrl(URL_EXTENSION_COMMITS, pkgName, pkgFactory)
|
||||
}
|
||||
|
||||
fun clearCookies() {
|
||||
val extension = state.value.extension ?: return
|
||||
|
||||
@@ -131,22 +118,6 @@ class ExtensionDetailsScreenModel(
|
||||
?.let { toggleSource.await(it, enable) }
|
||||
}
|
||||
|
||||
private fun createUrl(
|
||||
url: String,
|
||||
pkgName: String,
|
||||
pkgFactory: String?,
|
||||
path: String = "",
|
||||
): String {
|
||||
return if (!pkgFactory.isNullOrEmpty()) {
|
||||
when (path.isEmpty()) {
|
||||
true -> "$url/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/$pkgFactory"
|
||||
else -> "$url/multisrc/overrides/$pkgFactory/" + (pkgName.split(".").lastOrNull() ?: "") + path
|
||||
}
|
||||
} else {
|
||||
url + "/src/" + pkgName.replace(".", "/") + path
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val extension: Extension.Installed? = null,
|
||||
|
||||
@@ -56,12 +56,12 @@ class CrashLogUtil(
|
||||
val availableExtension = availableExtensions[it.pkgName]
|
||||
val hasUpdate = (availableExtension?.versionCode ?: 0) > it.versionCode
|
||||
|
||||
if (!hasUpdate && !it.isObsolete && !it.isUnofficial) return@mapNotNull null
|
||||
if (!hasUpdate && !it.isObsolete) return@mapNotNull null
|
||||
|
||||
"""
|
||||
- ${it.name}
|
||||
Installed: ${it.versionName} / Available: ${availableExtension?.versionName ?: "?"}
|
||||
Obsolete: ${it.isObsolete} / Unofficial: ${it.isUnofficial}
|
||||
Obsolete: ${it.isObsolete}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ fun Long.toDateKey(): Date {
|
||||
return Date.from(instant.truncatedTo(ChronoUnit.DAYS))
|
||||
}
|
||||
|
||||
private const val MILLISECONDS_IN_DAY = 86_400_000L
|
||||
|
||||
fun Date.toRelativeString(
|
||||
context: Context,
|
||||
relative: Boolean = true,
|
||||
@@ -69,6 +67,8 @@ fun Date.toRelativeString(
|
||||
}
|
||||
}
|
||||
|
||||
private const val MILLISECONDS_IN_DAY = 86_400_000L
|
||||
|
||||
private val Date.timeWithOffset: Long
|
||||
get() {
|
||||
return Calendar.getInstance().run {
|
||||
@@ -78,6 +78,6 @@ private val Date.timeWithOffset: Long
|
||||
}
|
||||
}
|
||||
|
||||
fun Long.floorNearest(to: Long): Long {
|
||||
private fun Long.floorNearest(to: Long): Long {
|
||||
return this.floorDiv(to) * to
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user