From 83426f7f3618ad455708502e395af536e223c0ee Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 4 Jun 2025 12:50:19 -0700 Subject: [PATCH] Update check update logic --- .../topjohnwu/magisk/core/model/UpdateInfo.kt | 19 +++++---- .../magisk/core/repository/NetworkService.kt | 41 ++++++++++++++----- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt index 9f2b503f1..0470e8900 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt @@ -38,18 +38,13 @@ data class ReleaseAssets( @Json(name = "browser_download_url") val url: String, ) -@Retention(AnnotationRetention.RUNTIME) -@JsonQualifier -annotation class DateTime - class DateTimeAdapter { @ToJson - fun toJson(@DateTime date: LocalDateTime): String { + fun toJson(date: LocalDateTime): String { return date.toString() } @FromJson - @DateTime fun fromJson(date: String): LocalDateTime { return LocalDateTime.parse(date, ISO_OFFSET_DATE_TIME) } @@ -62,5 +57,13 @@ data class Release( val prerelease: Boolean, val assets: List, val body: String, - @Json(name = "created_at") @DateTime val createdTime: LocalDateTime, -) + @Json(name = "created_at") val createdTime: LocalDateTime, +) { + val versionCode: Int get() { + return if (tag[0] == 'v') { + (tag.drop(1).toFloat() * 1000).toInt() + } else { + tag.drop(7).toInt() + } + } +} diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt index 9d9043d90..effd34dfe 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt @@ -11,6 +11,7 @@ import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.data.GithubApiServices import com.topjohnwu.magisk.core.data.RawUrl import com.topjohnwu.magisk.core.model.Release +import com.topjohnwu.magisk.core.model.ReleaseAssets import com.topjohnwu.magisk.core.model.UpdateInfo import retrofit2.HttpException import timber.log.Timber @@ -44,6 +45,8 @@ class NetworkService( while (true) { val response = api.fetchReleases(page = page) val releases = response.body() ?: throw HttpException(response) + // Remove all non Magisk releases + releases.removeAll { it.tag[0] != 'v' && !it.tag.startsWith("canary") } // Make sure it's sorted correctly releases.sortByDescending { it.createdTime } releases.find(predicate)?.let { return it } @@ -55,35 +58,51 @@ class NetworkService( } } - private fun Release.asPublicInfo(): UpdateInfo { + suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }?.asInfo() + + private inline fun Release.asInfo( + selector: (ReleaseAssets) -> Boolean = { + // Default selector picks the non-debug APK + it.name.run { endsWith(".apk") && !contains("debug") } + }): UpdateInfo { + return if (tag[0] == 'v') asPublicInfo(selector) + else asCanaryInfo(selector) + } + + private inline fun Release.asPublicInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo { val version = tag.drop(1) val date = createdTime.format(DateTimeFormatter.ofPattern("yyyy.M.d")) return UpdateInfo( version = version, - versionCode = (version.toFloat() * 1000).toInt(), - link = assets[0].url, + versionCode = versionCode, + link = assets.find(selector)!!.url, note = "## $date $name\n\n$body" ) } - private fun Release.asCanaryInfo(assetSelector: String): UpdateInfo { + private inline fun Release.asCanaryInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo { return UpdateInfo( version = name.substring(8, 16), - versionCode = tag.drop(7).toInt(), - link = assets.find { it.name == assetSelector }!!.url, + versionCode = versionCode, + link = assets.find(selector)!!.url, note = "## $name\n\n$body" ) } - private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asPublicInfo() + // Version number: canary == debug >= beta >= stable - private suspend fun fetchBetaUpdate() = findRelease { it.tag[0] == 'v' }!!.asPublicInfo() + // Find the latest non-prerelease + private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asInfo() - private suspend fun fetchCanary() = findRelease { it.tag.startsWith("canary-") }!! + // Find the latest non-canary release + private suspend fun fetchBetaUpdate() = findRelease { it.tag[0] == 'v' }!!.asInfo() - private suspend fun fetchCanaryUpdate() = fetchCanary().asCanaryInfo("app-release.apk") + // Find the latest release, regardless whether it's prerelease + private suspend fun fetchCanary() = findRelease { true }!! - private suspend fun fetchDebugUpdate() = fetchCanary().asCanaryInfo("app-debug.apk") + private suspend fun fetchCanaryUpdate() = fetchCanary().asInfo() + + private suspend fun fetchDebugUpdate() = fetchCanary().asInfo { it.name == "app-debug.apk" } private suspend fun fetchCustomUpdate(url: String): UpdateInfo { val info = raw.fetchUpdateJson(url).magisk