From f6c7b09d9bc66fc7cb85ae274b2e70f3dce72d0e Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX <1173913+AbandonedCart@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:50:40 -0400 Subject: [PATCH] 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 --- .../dantotsu/settings/saving/Preferences.kt | 1 - .../extension/anime/AnimeExtensionManager.kt | 8 +- .../anime/api/AnimeExtensionGithubApi.kt | 214 ---------------- .../ExtensionGithubApi.kt} | 234 +++++++++++------- .../extension/manga/MangaExtensionManager.kt | 8 +- app/src/main/res/drawable/mono.xml | 4 +- .../mipmap-anydpi-v26/ic_launcher_alpha.xml | 1 + 7 files changed, 149 insertions(+), 321 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/extension/anime/api/AnimeExtensionGithubApi.kt rename app/src/main/java/eu/kanade/tachiyomi/extension/{manga/api/MangaExtensionGithubApi.kt => api/ExtensionGithubApi.kt} (54%) diff --git a/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt b/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt index fb59a98c..65da7555 100644 --- a/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt +++ b/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt @@ -30,7 +30,6 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files ), AnimeExtensionRepos(Pref(Location.General, Set::class, setOf())), MangaExtensionRepos(Pref(Location.General, Set::class, setOf())), - SharedRepositories(Pref(Location.General, Boolean::class, false)), AnimeSourcesOrder(Pref(Location.General, List::class, listOf())), AnimeSearchHistory(Pref(Location.General, Set::class, setOf())), MangaSourcesOrder(Pref(Location.General, List::class, listOf())), diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/anime/AnimeExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/anime/AnimeExtensionManager.kt index d47af52c..9bb07824 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/anime/AnimeExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/anime/AnimeExtensionManager.kt @@ -6,10 +6,10 @@ import ani.dantotsu.snackString import ani.dantotsu.util.Logger import eu.kanade.domain.source.service.SourcePreferences 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.AnimeLoadResult 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.ExtensionInstaller import eu.kanade.tachiyomi.extension.util.ExtensionLoader @@ -47,7 +47,7 @@ class AnimeExtensionManager( /** * 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. @@ -118,7 +118,7 @@ class AnimeExtensionManager( */ suspend fun findAvailableExtensions() { val extensions: List = try { - api.findExtensions() + api.findAnimeExtensions() } catch (e: Exception) { Logger.log(e) withUIContext { snackString("Failed to get extensions list") } @@ -206,7 +206,7 @@ class AnimeExtensionManager( * @param extension The anime extension to be installed. */ fun installExtension(extension: AnimeExtension.Available): Observable { - return installer.downloadAndInstall(api.getApkUrl(extension), extension) + return installer.downloadAndInstall(api.getAnimeApkUrl(extension), extension) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/anime/api/AnimeExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/anime/api/AnimeExtensionGithubApi.kt deleted file mode 100644 index 0c0fd25e..00000000 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/anime/api/AnimeExtensionGithubApi.kt +++ /dev/null @@ -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 by lazy { - preferenceStore.getLong("last_ext_check", 0) - } - - suspend fun findExtensions(): List { - return withIOContext { - - val extensions: ArrayList = arrayListOf() - - val repos = - PrefManager.getVal>(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>() - .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? { - // 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() - .map { it.extension } - - val extensionsWithUpdate = mutableListOf() - 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.toExtensions(repository: String): List { - 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.toAnimeExtensionSources(): List { - 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?, -) - -@Serializable -private data class AnimeExtensionSourceJsonObject( - val id: Long, - val lang: String, - val name: String, - val baseUrl: String, -) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/manga/api/MangaExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt similarity index 54% rename from app/src/main/java/eu/kanade/tachiyomi/extension/manga/api/MangaExtensionGithubApi.kt rename to app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index 8791f572..5b630c10 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/manga/api/MangaExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -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.PrefName import ani.dantotsu.util.Logger -import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier -import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager +import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension +import eu.kanade.tachiyomi.extension.anime.model.AvailableAnimeSources import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources 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.network.GET import eu.kanade.tachiyomi.network.NetworkHelper @@ -16,25 +14,143 @@ 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 MangaExtensionGithubApi { +internal class ExtensionGithubApi { 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 lastExtCheck: Preference by lazy { - preferenceStore.getLong("last_ext_check", 0) + private fun List.toAnimeExtensionSources(): List { + return this.map { + AvailableAnimeSources( + id = it.id, + lang = it.lang, + name = it.name, + baseUrl = it.baseUrl, + ) + } } - suspend fun findExtensions(): List { + private fun List.toAnimeExtensions(repository: String): List { + 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 { + return withIOContext { + + val extensions: ArrayList = arrayListOf() + + val repos = + PrefManager.getVal>(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>() + .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.toMangaExtensionSources(): List { + return this.map { + AvailableMangaSources( + id = it.id, + lang = it.lang, + name = it.name, + baseUrl = it.baseUrl, + ) + } + } + + private fun List.toMangaExtensions(repository: String): List { + 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 { return withIOContext { val extensions: ArrayList = arrayListOf() @@ -67,7 +183,7 @@ internal class MangaExtensionGithubApi { val repoExtensions = with(json) { response .parseAs>() - .toExtensions(it) + .toMangaExtensions(it) } // Sanity check - a small number of extensions probably means something broke @@ -87,88 +203,10 @@ internal class MangaExtensionGithubApi { } } - suspend fun checkForUpdates( - context: Context, - fromAvailableExtensionList: Boolean = false - ): List? { - // 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() - .map { it.extension } - - val extensionsWithUpdate = mutableListOf() - 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.toExtensions(repository: String): List { - 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.toExtensionSources(): List { - return this.map { - AvailableMangaSources( - id = it.id, - lang = it.lang, - name = it.name, - baseUrl = it.baseUrl, - ) - } - } - - fun getApkUrl(extension: MangaExtension.Available): String { + fun getMangaApkUrl(extension: MangaExtension.Available): String { return "${extension.repository}/apk/${extension.apkName}" } - private fun ExtensionJsonObject.extractLibVersion(): Double { - return version.substringBeforeLast('.').toDouble() - } - private fun fallbackRepoUrl(repoUrl: String): String? { var fallbackRepoUrl = "https://gcore.jsdelivr.net/gh/" val strippedRepoUrl = @@ -211,3 +249,7 @@ private data class ExtensionSourceJsonObject( val name: String, val baseUrl: String, ) + +private fun ExtensionJsonObject.extractLibVersion(): Double { + return version.substringBeforeLast('.').toDouble() +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/manga/MangaExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/manga/MangaExtensionManager.kt index 09fb725d..3dcb4cf8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/manga/MangaExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/manga/MangaExtensionManager.kt @@ -6,7 +6,7 @@ import ani.dantotsu.snackString import ani.dantotsu.util.Logger import eu.kanade.domain.source.service.SourcePreferences 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.MangaExtension import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult @@ -47,7 +47,7 @@ class MangaExtensionManager( /** * 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. @@ -115,7 +115,7 @@ class MangaExtensionManager( */ suspend fun findAvailableExtensions() { val extensions: List = try { - api.findExtensions() + api.findMangaExtensions() } catch (e: Exception) { Logger.log(e) withUIContext { snackString("Failed to get manga extensions") } @@ -203,7 +203,7 @@ class MangaExtensionManager( * @param extension The extension to be installed. */ fun installExtension(extension: MangaExtension.Available): Observable { - return installer.downloadAndInstall(api.getApkUrl(extension), extension) + return installer.downloadAndInstall(api.getMangaApkUrl(extension), extension) } /** diff --git a/app/src/main/res/drawable/mono.xml b/app/src/main/res/drawable/mono.xml index aa925d64..6379c96c 100644 --- a/app/src/main/res/drawable/mono.xml +++ b/app/src/main/res/drawable/mono.xml @@ -1,6 +1,6 @@ diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alpha.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alpha.xml index c841f28b..2ef1656e 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alpha.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alpha.xml @@ -2,4 +2,5 @@ + \ No newline at end of file