fix: remove duplicate extension code (#322)
* fix: remove duplicate extension code * fix: allow Material You icons to load * fix: remove unused preference item * fix: load mono on square setups
This commit is contained in:
parent
72c69e7c79
commit
f6c7b09d9b
7 changed files with 149 additions and 321 deletions
|
@ -30,7 +30,6 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
||||||
),
|
),
|
||||||
AnimeExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
AnimeExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
MangaExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
MangaExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
SharedRepositories(Pref(Location.General, Boolean::class, false)),
|
|
||||||
AnimeSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
AnimeSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
AnimeSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
AnimeSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
|
|
|
@ -6,10 +6,10 @@ import ani.dantotsu.snackString
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.anime.api.AnimeExtensionGithubApi
|
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeLoadResult
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeLoadResult
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AvailableAnimeSources
|
import eu.kanade.tachiyomi.extension.anime.model.AvailableAnimeSources
|
||||||
|
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstallReceiver
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstallReceiver
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||||
|
@ -47,7 +47,7 @@ class AnimeExtensionManager(
|
||||||
/**
|
/**
|
||||||
* API where all the available anime extensions can be found.
|
* API where all the available anime extensions can be found.
|
||||||
*/
|
*/
|
||||||
private val api = AnimeExtensionGithubApi()
|
private val api = ExtensionGithubApi()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The installer which installs, updates and uninstalls the anime extensions.
|
* The installer which installs, updates and uninstalls the anime extensions.
|
||||||
|
@ -118,7 +118,7 @@ class AnimeExtensionManager(
|
||||||
*/
|
*/
|
||||||
suspend fun findAvailableExtensions() {
|
suspend fun findAvailableExtensions() {
|
||||||
val extensions: List<AnimeExtension.Available> = try {
|
val extensions: List<AnimeExtension.Available> = try {
|
||||||
api.findExtensions()
|
api.findAnimeExtensions()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.log(e)
|
Logger.log(e)
|
||||||
withUIContext { snackString("Failed to get extensions list") }
|
withUIContext { snackString("Failed to get extensions list") }
|
||||||
|
@ -206,7 +206,7 @@ class AnimeExtensionManager(
|
||||||
* @param extension The anime extension to be installed.
|
* @param extension The anime extension to be installed.
|
||||||
*/
|
*/
|
||||||
fun installExtension(extension: AnimeExtension.Available): Observable<InstallStep> {
|
fun installExtension(extension: AnimeExtension.Available): Observable<InstallStep> {
|
||||||
return installer.downloadAndInstall(api.getApkUrl(extension), extension)
|
return installer.downloadAndInstall(api.getAnimeApkUrl(extension), extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,214 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.anime.api
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
|
||||||
import ani.dantotsu.util.Logger
|
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
|
||||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeLoadResult
|
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AvailableAnimeSources
|
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
|
||||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import tachiyomi.core.preference.Preference
|
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.Date
|
|
||||||
import kotlin.time.Duration.Companion.days
|
|
||||||
|
|
||||||
internal class AnimeExtensionGithubApi {
|
|
||||||
|
|
||||||
private val networkService: NetworkHelper by injectLazy()
|
|
||||||
private val preferenceStore: PreferenceStore by injectLazy()
|
|
||||||
private val animeExtensionManager: AnimeExtensionManager by injectLazy()
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
private val lastExtCheck: Preference<Long> by lazy {
|
|
||||||
preferenceStore.getLong("last_ext_check", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun findExtensions(): List<AnimeExtension.Available> {
|
|
||||||
return withIOContext {
|
|
||||||
|
|
||||||
val extensions: ArrayList<AnimeExtension.Available> = arrayListOf()
|
|
||||||
|
|
||||||
val repos =
|
|
||||||
PrefManager.getVal<Set<String>>(PrefName.AnimeExtensionRepos).toMutableList()
|
|
||||||
if (repos.isEmpty()) {
|
|
||||||
repos.add("https://raw.githubusercontent.com/aniyomiorg/aniyomi-extensions/repo")
|
|
||||||
PrefManager.setVal(PrefName.AnimeExtensionRepos, repos.toSet())
|
|
||||||
}
|
|
||||||
|
|
||||||
repos.forEach {
|
|
||||||
try {
|
|
||||||
val githubResponse = try {
|
|
||||||
networkService.client
|
|
||||||
.newCall(GET("${it}/index.min.json"))
|
|
||||||
.awaitSuccess()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Logger.log("Failed to get repo: $it")
|
|
||||||
Logger.log(e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val response = githubResponse ?: run {
|
|
||||||
networkService.client
|
|
||||||
.newCall(GET(fallbackRepoUrl(it) + "/index.min.json"))
|
|
||||||
.awaitSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
val repoExtensions = with(json) {
|
|
||||||
response
|
|
||||||
.parseAs<List<AnimeExtensionJsonObject>>()
|
|
||||||
.toExtensions(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity check - a small number of extensions probably means something broke
|
|
||||||
// with the repo generator
|
|
||||||
if (repoExtensions.size < 10) {
|
|
||||||
throw Exception()
|
|
||||||
}
|
|
||||||
|
|
||||||
extensions.addAll(repoExtensions)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Logger.log("Failed to get extensions from GitHub")
|
|
||||||
Logger.log(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extensions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun checkForUpdates(
|
|
||||||
context: Context,
|
|
||||||
fromAvailableExtensionList: Boolean = false
|
|
||||||
): List<AnimeExtension.Installed>? {
|
|
||||||
// Limit checks to once a day at most
|
|
||||||
if (fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val extensions = if (fromAvailableExtensionList) {
|
|
||||||
animeExtensionManager.availableExtensionsFlow.value
|
|
||||||
} else {
|
|
||||||
findExtensions().also { lastExtCheck.set(Date().time) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val installedExtensions = ExtensionLoader.loadAnimeExtensions(context)
|
|
||||||
.filterIsInstance<AnimeLoadResult.Success>()
|
|
||||||
.map { it.extension }
|
|
||||||
|
|
||||||
val extensionsWithUpdate = mutableListOf<AnimeExtension.Installed>()
|
|
||||||
for (installedExt in installedExtensions) {
|
|
||||||
val pkgName = installedExt.pkgName
|
|
||||||
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)
|
|
||||||
if (hasUpdate) {
|
|
||||||
extensionsWithUpdate.add(installedExt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extensionsWithUpdate.isNotEmpty()) {
|
|
||||||
ExtensionUpdateNotifier(context).promptUpdates(extensionsWithUpdate.map { it.name })
|
|
||||||
}
|
|
||||||
|
|
||||||
return extensionsWithUpdate
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<AnimeExtensionJsonObject>.toExtensions(repository: String): List<AnimeExtension.Available> {
|
|
||||||
return this
|
|
||||||
.filter {
|
|
||||||
val libVersion = it.extractLibVersion()
|
|
||||||
libVersion >= ExtensionLoader.ANIME_LIB_VERSION_MIN && libVersion <= ExtensionLoader.ANIME_LIB_VERSION_MAX
|
|
||||||
}
|
|
||||||
.map {
|
|
||||||
AnimeExtension.Available(
|
|
||||||
name = it.name.substringAfter("Aniyomi: "),
|
|
||||||
pkgName = it.pkg,
|
|
||||||
versionName = it.version,
|
|
||||||
versionCode = it.code,
|
|
||||||
libVersion = it.extractLibVersion(),
|
|
||||||
lang = it.lang,
|
|
||||||
isNsfw = it.nsfw == 1,
|
|
||||||
hasReadme = it.hasReadme == 1,
|
|
||||||
hasChangelog = it.hasChangelog == 1,
|
|
||||||
sources = it.sources?.toAnimeExtensionSources().orEmpty(),
|
|
||||||
apkName = it.apk,
|
|
||||||
repository = repository,
|
|
||||||
iconUrl = "${repository}/icon/${it.pkg}.png",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<AnimeExtensionSourceJsonObject>.toAnimeExtensionSources(): List<AvailableAnimeSources> {
|
|
||||||
return this.map {
|
|
||||||
AvailableAnimeSources(
|
|
||||||
id = it.id,
|
|
||||||
lang = it.lang,
|
|
||||||
name = it.name,
|
|
||||||
baseUrl = it.baseUrl,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getApkUrl(extension: AnimeExtension.Available): String {
|
|
||||||
return "${extension.repository}/apk/${extension.apkName}"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fallbackRepoUrl(repoUrl: String): String? {
|
|
||||||
var fallbackRepoUrl = "https://gcore.jsdelivr.net/gh/"
|
|
||||||
val strippedRepoUrl =
|
|
||||||
repoUrl.removePrefix("https://").removePrefix("http://").removeSuffix("/")
|
|
||||||
val repoUrlParts = strippedRepoUrl.split("/")
|
|
||||||
if (repoUrlParts.size < 3) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val repoOwner = repoUrlParts[1]
|
|
||||||
val repoName = repoUrlParts[2]
|
|
||||||
fallbackRepoUrl += "$repoOwner/$repoName"
|
|
||||||
val repoBranch = if (repoUrlParts.size > 3) {
|
|
||||||
repoUrlParts[3]
|
|
||||||
} else {
|
|
||||||
"main"
|
|
||||||
}
|
|
||||||
fallbackRepoUrl += "@$repoBranch"
|
|
||||||
return fallbackRepoUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun AnimeExtensionJsonObject.extractLibVersion(): Double {
|
|
||||||
return version.substringBeforeLast('.').toDouble()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
private data class AnimeExtensionJsonObject(
|
|
||||||
val name: String,
|
|
||||||
val pkg: String,
|
|
||||||
val apk: String,
|
|
||||||
val lang: String,
|
|
||||||
val code: Long,
|
|
||||||
val version: String,
|
|
||||||
val nsfw: Int,
|
|
||||||
val hasReadme: Int = 0,
|
|
||||||
val hasChangelog: Int = 0,
|
|
||||||
val sources: List<AnimeExtensionSourceJsonObject>?,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
private data class AnimeExtensionSourceJsonObject(
|
|
||||||
val id: Long,
|
|
||||||
val lang: String,
|
|
||||||
val name: String,
|
|
||||||
val baseUrl: String,
|
|
||||||
)
|
|
|
@ -1,14 +1,12 @@
|
||||||
package eu.kanade.tachiyomi.extension.manga.api
|
package eu.kanade.tachiyomi.extension.api
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
import eu.kanade.tachiyomi.extension.anime.model.AvailableAnimeSources
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources
|
import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult
|
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
|
@ -16,25 +14,143 @@ import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import tachiyomi.core.preference.Preference
|
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.Date
|
|
||||||
import kotlin.time.Duration.Companion.days
|
|
||||||
|
|
||||||
internal class MangaExtensionGithubApi {
|
|
||||||
|
|
||||||
|
internal class ExtensionGithubApi {
|
||||||
private val networkService: NetworkHelper by injectLazy()
|
private val networkService: NetworkHelper by injectLazy()
|
||||||
private val preferenceStore: PreferenceStore by injectLazy()
|
|
||||||
private val extensionManager: MangaExtensionManager by injectLazy()
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val lastExtCheck: Preference<Long> by lazy {
|
private fun List<ExtensionSourceJsonObject>.toAnimeExtensionSources(): List<AvailableAnimeSources> {
|
||||||
preferenceStore.getLong("last_ext_check", 0)
|
return this.map {
|
||||||
|
AvailableAnimeSources(
|
||||||
|
id = it.id,
|
||||||
|
lang = it.lang,
|
||||||
|
name = it.name,
|
||||||
|
baseUrl = it.baseUrl,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun findExtensions(): List<MangaExtension.Available> {
|
private fun List<ExtensionJsonObject>.toAnimeExtensions(repository: String): List<AnimeExtension.Available> {
|
||||||
|
return this
|
||||||
|
.filter {
|
||||||
|
val libVersion = it.extractLibVersion()
|
||||||
|
libVersion >= ExtensionLoader.ANIME_LIB_VERSION_MIN && libVersion <= ExtensionLoader.ANIME_LIB_VERSION_MAX
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
AnimeExtension.Available(
|
||||||
|
name = it.name.substringAfter("Aniyomi: "),
|
||||||
|
pkgName = it.pkg,
|
||||||
|
versionName = it.version,
|
||||||
|
versionCode = it.code,
|
||||||
|
libVersion = it.extractLibVersion(),
|
||||||
|
lang = it.lang,
|
||||||
|
isNsfw = it.nsfw == 1,
|
||||||
|
hasReadme = it.hasReadme == 1,
|
||||||
|
hasChangelog = it.hasChangelog == 1,
|
||||||
|
sources = it.sources?.toAnimeExtensionSources().orEmpty(),
|
||||||
|
apkName = it.apk,
|
||||||
|
repository = repository,
|
||||||
|
iconUrl = "${repository}/icon/${it.pkg}.png",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun findAnimeExtensions(): List<AnimeExtension.Available> {
|
||||||
|
return withIOContext {
|
||||||
|
|
||||||
|
val extensions: ArrayList<AnimeExtension.Available> = arrayListOf()
|
||||||
|
|
||||||
|
val repos =
|
||||||
|
PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos).toMutableList()
|
||||||
|
if (repos.isEmpty()) {
|
||||||
|
repos.add("https://raw.githubusercontent.com/keiyoushi/extensions/main")
|
||||||
|
PrefManager.setVal(PrefName.MangaExtensionRepos, repos.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
repos.forEach {
|
||||||
|
try {
|
||||||
|
val githubResponse = try {
|
||||||
|
networkService.client
|
||||||
|
.newCall(GET("${it}/index.min.json"))
|
||||||
|
.awaitSuccess()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.log("Failed to get repo: $it")
|
||||||
|
Logger.log(e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = githubResponse ?: run {
|
||||||
|
networkService.client
|
||||||
|
.newCall(GET(fallbackRepoUrl(it) + "/index.min.json"))
|
||||||
|
.awaitSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
val repoExtensions = with(json) {
|
||||||
|
response
|
||||||
|
.parseAs<List<ExtensionJsonObject>>()
|
||||||
|
.toAnimeExtensions(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check - a small number of extensions probably means something broke
|
||||||
|
// with the repo generator
|
||||||
|
if (repoExtensions.size < 10) {
|
||||||
|
throw Exception()
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.addAll(repoExtensions)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.log("Failed to get extensions from GitHub")
|
||||||
|
Logger.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAnimeApkUrl(extension: AnimeExtension.Available): String {
|
||||||
|
return "${extension.repository}/apk/${extension.apkName}"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<ExtensionSourceJsonObject>.toMangaExtensionSources(): List<AvailableMangaSources> {
|
||||||
|
return this.map {
|
||||||
|
AvailableMangaSources(
|
||||||
|
id = it.id,
|
||||||
|
lang = it.lang,
|
||||||
|
name = it.name,
|
||||||
|
baseUrl = it.baseUrl,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<ExtensionJsonObject>.toMangaExtensions(repository: String): List<MangaExtension.Available> {
|
||||||
|
return this
|
||||||
|
.filter {
|
||||||
|
val libVersion = it.extractLibVersion()
|
||||||
|
libVersion >= ExtensionLoader.MANGA_LIB_VERSION_MIN && libVersion <= ExtensionLoader.MANGA_LIB_VERSION_MAX
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
MangaExtension.Available(
|
||||||
|
name = it.name.substringAfter("Tachiyomi: "),
|
||||||
|
pkgName = it.pkg,
|
||||||
|
versionName = it.version,
|
||||||
|
versionCode = it.code,
|
||||||
|
libVersion = it.extractLibVersion(),
|
||||||
|
lang = it.lang,
|
||||||
|
isNsfw = it.nsfw == 1,
|
||||||
|
hasReadme = it.hasReadme == 1,
|
||||||
|
hasChangelog = it.hasChangelog == 1,
|
||||||
|
sources = it.sources?.toMangaExtensionSources().orEmpty(),
|
||||||
|
apkName = it.apk,
|
||||||
|
repository = repository,
|
||||||
|
iconUrl = "${repository}/icon/${it.pkg}.png",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun findMangaExtensions(): List<MangaExtension.Available> {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
|
|
||||||
val extensions: ArrayList<MangaExtension.Available> = arrayListOf()
|
val extensions: ArrayList<MangaExtension.Available> = arrayListOf()
|
||||||
|
@ -67,7 +183,7 @@ internal class MangaExtensionGithubApi {
|
||||||
val repoExtensions = with(json) {
|
val repoExtensions = with(json) {
|
||||||
response
|
response
|
||||||
.parseAs<List<ExtensionJsonObject>>()
|
.parseAs<List<ExtensionJsonObject>>()
|
||||||
.toExtensions(it)
|
.toMangaExtensions(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check - a small number of extensions probably means something broke
|
// Sanity check - a small number of extensions probably means something broke
|
||||||
|
@ -87,88 +203,10 @@ internal class MangaExtensionGithubApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun checkForUpdates(
|
fun getMangaApkUrl(extension: MangaExtension.Available): String {
|
||||||
context: Context,
|
|
||||||
fromAvailableExtensionList: Boolean = false
|
|
||||||
): List<MangaExtension.Installed>? {
|
|
||||||
// Limit checks to once a day at most
|
|
||||||
if (fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val extensions = if (fromAvailableExtensionList) {
|
|
||||||
extensionManager.availableExtensionsFlow.value
|
|
||||||
} else {
|
|
||||||
findExtensions().also { lastExtCheck.set(Date().time) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val installedExtensions = ExtensionLoader.loadMangaExtensions(context)
|
|
||||||
.filterIsInstance<MangaLoadResult.Success>()
|
|
||||||
.map { it.extension }
|
|
||||||
|
|
||||||
val extensionsWithUpdate = mutableListOf<MangaExtension.Installed>()
|
|
||||||
for (installedExt in installedExtensions) {
|
|
||||||
val pkgName = installedExt.pkgName
|
|
||||||
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)
|
|
||||||
if (hasUpdate) {
|
|
||||||
extensionsWithUpdate.add(installedExt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extensionsWithUpdate.isNotEmpty()) {
|
|
||||||
ExtensionUpdateNotifier(context).promptUpdates(extensionsWithUpdate.map { it.name })
|
|
||||||
}
|
|
||||||
|
|
||||||
return extensionsWithUpdate
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<ExtensionJsonObject>.toExtensions(repository: String): List<MangaExtension.Available> {
|
|
||||||
return this
|
|
||||||
.filter {
|
|
||||||
val libVersion = it.extractLibVersion()
|
|
||||||
libVersion >= ExtensionLoader.MANGA_LIB_VERSION_MIN && libVersion <= ExtensionLoader.MANGA_LIB_VERSION_MAX
|
|
||||||
}
|
|
||||||
.map {
|
|
||||||
MangaExtension.Available(
|
|
||||||
name = it.name.substringAfter("Tachiyomi: "),
|
|
||||||
pkgName = it.pkg,
|
|
||||||
versionName = it.version,
|
|
||||||
versionCode = it.code,
|
|
||||||
libVersion = it.extractLibVersion(),
|
|
||||||
lang = it.lang,
|
|
||||||
isNsfw = it.nsfw == 1,
|
|
||||||
hasReadme = it.hasReadme == 1,
|
|
||||||
hasChangelog = it.hasChangelog == 1,
|
|
||||||
sources = it.sources?.toExtensionSources().orEmpty(),
|
|
||||||
apkName = it.apk,
|
|
||||||
repository = repository,
|
|
||||||
iconUrl = "${repository}/icon/${it.pkg}.png",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<ExtensionSourceJsonObject>.toExtensionSources(): List<AvailableMangaSources> {
|
|
||||||
return this.map {
|
|
||||||
AvailableMangaSources(
|
|
||||||
id = it.id,
|
|
||||||
lang = it.lang,
|
|
||||||
name = it.name,
|
|
||||||
baseUrl = it.baseUrl,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getApkUrl(extension: MangaExtension.Available): String {
|
|
||||||
return "${extension.repository}/apk/${extension.apkName}"
|
return "${extension.repository}/apk/${extension.apkName}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExtensionJsonObject.extractLibVersion(): Double {
|
|
||||||
return version.substringBeforeLast('.').toDouble()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fallbackRepoUrl(repoUrl: String): String? {
|
private fun fallbackRepoUrl(repoUrl: String): String? {
|
||||||
var fallbackRepoUrl = "https://gcore.jsdelivr.net/gh/"
|
var fallbackRepoUrl = "https://gcore.jsdelivr.net/gh/"
|
||||||
val strippedRepoUrl =
|
val strippedRepoUrl =
|
||||||
|
@ -211,3 +249,7 @@ private data class ExtensionSourceJsonObject(
|
||||||
val name: String,
|
val name: String,
|
||||||
val baseUrl: String,
|
val baseUrl: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun ExtensionJsonObject.extractLibVersion(): Double {
|
||||||
|
return version.substringBeforeLast('.').toDouble()
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import ani.dantotsu.snackString
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.manga.api.MangaExtensionGithubApi
|
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources
|
import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult
|
import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult
|
||||||
|
@ -47,7 +47,7 @@ class MangaExtensionManager(
|
||||||
/**
|
/**
|
||||||
* API where all the available extensions can be found.
|
* API where all the available extensions can be found.
|
||||||
*/
|
*/
|
||||||
private val api = MangaExtensionGithubApi()
|
private val api = ExtensionGithubApi()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The installer which installs, updates and uninstalls the extensions.
|
* The installer which installs, updates and uninstalls the extensions.
|
||||||
|
@ -115,7 +115,7 @@ class MangaExtensionManager(
|
||||||
*/
|
*/
|
||||||
suspend fun findAvailableExtensions() {
|
suspend fun findAvailableExtensions() {
|
||||||
val extensions: List<MangaExtension.Available> = try {
|
val extensions: List<MangaExtension.Available> = try {
|
||||||
api.findExtensions()
|
api.findMangaExtensions()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.log(e)
|
Logger.log(e)
|
||||||
withUIContext { snackString("Failed to get manga extensions") }
|
withUIContext { snackString("Failed to get manga extensions") }
|
||||||
|
@ -203,7 +203,7 @@ class MangaExtensionManager(
|
||||||
* @param extension The extension to be installed.
|
* @param extension The extension to be installed.
|
||||||
*/
|
*/
|
||||||
fun installExtension(extension: MangaExtension.Available): Observable<InstallStep> {
|
fun installExtension(extension: MangaExtension.Available): Observable<InstallStep> {
|
||||||
return installer.downloadAndInstall(api.getApkUrl(extension), extension)
|
return installer.downloadAndInstall(api.getMangaApkUrl(extension), extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="768dp"
|
android:width="200dp"
|
||||||
android:height="768dp"
|
android:height="200dp"
|
||||||
android:viewportWidth="768"
|
android:viewportWidth="768"
|
||||||
android:viewportHeight="768">
|
android:viewportHeight="768">
|
||||||
<group>
|
<group>
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@drawable/ic_launcher_alpha_background" />
|
<background android:drawable="@drawable/ic_launcher_alpha_background" />
|
||||||
<foreground android:drawable="@drawable/ic_launcher_alpha_foreground" />
|
<foreground android:drawable="@drawable/ic_launcher_alpha_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/mono" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
Loading…
Add table
Add a link
Reference in a new issue