Update check update logic

This commit is contained in:
topjohnwu
2025-06-04 12:50:19 -07:00
parent 0e86d4dbcb
commit 83426f7f36
2 changed files with 41 additions and 19 deletions

View File

@@ -38,18 +38,13 @@ data class ReleaseAssets(
@Json(name = "browser_download_url") val url: String, @Json(name = "browser_download_url") val url: String,
) )
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class DateTime
class DateTimeAdapter { class DateTimeAdapter {
@ToJson @ToJson
fun toJson(@DateTime date: LocalDateTime): String { fun toJson(date: LocalDateTime): String {
return date.toString() return date.toString()
} }
@FromJson @FromJson
@DateTime
fun fromJson(date: String): LocalDateTime { fun fromJson(date: String): LocalDateTime {
return LocalDateTime.parse(date, ISO_OFFSET_DATE_TIME) return LocalDateTime.parse(date, ISO_OFFSET_DATE_TIME)
} }
@@ -62,5 +57,13 @@ data class Release(
val prerelease: Boolean, val prerelease: Boolean,
val assets: List<ReleaseAssets>, val assets: List<ReleaseAssets>,
val body: String, 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()
}
}
}

View File

@@ -11,6 +11,7 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.data.GithubApiServices import com.topjohnwu.magisk.core.data.GithubApiServices
import com.topjohnwu.magisk.core.data.RawUrl import com.topjohnwu.magisk.core.data.RawUrl
import com.topjohnwu.magisk.core.model.Release import com.topjohnwu.magisk.core.model.Release
import com.topjohnwu.magisk.core.model.ReleaseAssets
import com.topjohnwu.magisk.core.model.UpdateInfo import com.topjohnwu.magisk.core.model.UpdateInfo
import retrofit2.HttpException import retrofit2.HttpException
import timber.log.Timber import timber.log.Timber
@@ -44,6 +45,8 @@ class NetworkService(
while (true) { while (true) {
val response = api.fetchReleases(page = page) val response = api.fetchReleases(page = page)
val releases = response.body() ?: throw HttpException(response) 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 // Make sure it's sorted correctly
releases.sortByDescending { it.createdTime } releases.sortByDescending { it.createdTime }
releases.find(predicate)?.let { return it } 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 version = tag.drop(1)
val date = createdTime.format(DateTimeFormatter.ofPattern("yyyy.M.d")) val date = createdTime.format(DateTimeFormatter.ofPattern("yyyy.M.d"))
return UpdateInfo( return UpdateInfo(
version = version, version = version,
versionCode = (version.toFloat() * 1000).toInt(), versionCode = versionCode,
link = assets[0].url, link = assets.find(selector)!!.url,
note = "## $date $name\n\n$body" note = "## $date $name\n\n$body"
) )
} }
private fun Release.asCanaryInfo(assetSelector: String): UpdateInfo { private inline fun Release.asCanaryInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo {
return UpdateInfo( return UpdateInfo(
version = name.substring(8, 16), version = name.substring(8, 16),
versionCode = tag.drop(7).toInt(), versionCode = versionCode,
link = assets.find { it.name == assetSelector }!!.url, link = assets.find(selector)!!.url,
note = "## $name\n\n$body" 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 { private suspend fun fetchCustomUpdate(url: String): UpdateInfo {
val info = raw.fetchUpdateJson(url).magisk val info = raw.fetchUpdateJson(url).magisk