feat: alt update

This commit is contained in:
rebel onion 2025-01-05 20:23:50 -06:00
parent 495322547e
commit 7fc69b4edd
2 changed files with 98 additions and 30 deletions

View file

@ -19,6 +19,7 @@ import ani.dantotsu.R
import ani.dantotsu.buildMarkwon import ani.dantotsu.buildMarkwon
import ani.dantotsu.client import ani.dantotsu.client
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.decodeBase64ToString
import ani.dantotsu.logError import ani.dantotsu.logError
import ani.dantotsu.openLinkInBrowser import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
@ -37,11 +38,34 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
object AppUpdater { object AppUpdater {
suspend fun check(activity: FragmentActivity, post: Boolean = false) { private val fallbackStableUrl: String
if (post) snackString(currContext()?.getString(R.string.checking_for_update)) get() = "aHR0cHM6Ly9hcGkuZGFudG90c3UuYXBwL3VwZGF0ZXMvc3RhYmxl".decodeBase64ToString()
val repo = activity.getString(R.string.repo) private val fallbackBetaUrl: String
tryWithSuspend { get() = "aHR0cHM6Ly9hcGkuZGFudG90c3UuYXBwL3VwZGF0ZXMvYmV0YQ==".decodeBase64ToString()
val (md, version) = if (BuildConfig.DEBUG) {
@Serializable
data class FallbackResponse(
val version: String,
val changelog: String,
val downloadUrl: String? = null
)
private suspend fun fetchUpdateInfo(repo: String, isDebug: Boolean): Pair<String, String>? {
return try {
fetchFromGithub(repo, isDebug)
} catch (e: Exception) {
Logger.log("Github fetch failed, trying fallback: ${e.message}")
try {
fetchFromFallback(isDebug)
} catch (e: Exception) {
Logger.log("Fallback fetch failed: ${e.message}")
null
}
}
}
private suspend fun fetchFromGithub(repo: String, isDebug: Boolean): Pair<String, String> {
return if (isDebug) {
val res = client.get("https://api.github.com/repos/$repo/releases") val res = client.get("https://api.github.com/repos/$repo/releases")
.parsed<JsonArray>().map { .parsed<JsonArray>().map {
Mapper.json.decodeFromJsonElement<GithubResponse>(it) Mapper.json.decodeFromJsonElement<GithubResponse>(it)
@ -53,10 +77,49 @@ object AppUpdater {
val v = r.tagName.substringAfter("v", "") val v = r.tagName.substringAfter("v", "")
(r.body ?: "") to v.ifEmpty { throw Exception("Weird Version : ${r.tagName}") } (r.body ?: "") to v.ifEmpty { throw Exception("Weird Version : ${r.tagName}") }
} else { } else {
val res = val res = client.get("https://raw.githubusercontent.com/$repo/main/stable.md").text
client.get("https://raw.githubusercontent.com/$repo/main/stable.md").text
res to res.substringAfter("# ").substringBefore("\n") res to res.substringAfter("# ").substringBefore("\n")
} }
}
private suspend fun fetchFromFallback(isDebug: Boolean): Pair<String, String> {
val url = if (isDebug) fallbackBetaUrl else fallbackStableUrl
val response = client.get(url).parsed<FallbackResponse>()
return response.changelog to response.version
}
private suspend fun fetchApkUrl(repo: String, version: String, isDebug: Boolean): String? {
return try {
fetchApkUrlFromGithub(repo, version)
} catch (e: Exception) {
Logger.log("Github APK fetch failed, trying fallback: ${e.message}")
try {
fetchApkUrlFromFallback(version, isDebug)
} catch (e: Exception) {
Logger.log("Fallback APK fetch failed: ${e.message}")
null
}
}
}
private suspend fun fetchApkUrlFromGithub(repo: String, version: String): String? {
val apks = client.get("https://api.github.com/repos/$repo/releases/tags/v$version")
.parsed<GithubResponse>().assets?.filter {
it.browserDownloadURL.endsWith(".apk")
}
return apks?.firstOrNull()?.browserDownloadURL
}
private suspend fun fetchApkUrlFromFallback(version: String, isDebug: Boolean): String? {
val url = if (isDebug) fallbackBetaUrl else fallbackStableUrl
return client.get("$url/$version").parsed<FallbackResponse>().downloadUrl
}
suspend fun check(activity: FragmentActivity, post: Boolean = false) {
if (post) snackString(currContext()?.getString(R.string.checking_for_update))
val repo = activity.getString(R.string.repo)
tryWithSuspend {
val (md, version) = fetchUpdateInfo(repo, BuildConfig.DEBUG) ?: return@tryWithSuspend
Logger.log("Git Version : $version") Logger.log("Git Version : $version")
val dontShow = PrefManager.getCustomVal("dont_ask_for_update_$version", false) val dontShow = PrefManager.getCustomVal("dont_ask_for_update_$version", false)
@ -69,7 +132,7 @@ object AppUpdater {
) )
addView( addView(
TextView(activity).apply { TextView(activity).apply {
val markWon = try { //slower phones can destroy the activity before this is done val markWon = try {
buildMarkwon(activity, false) buildMarkwon(activity, false)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
return@runOnUiThread return@runOnUiThread
@ -89,17 +152,11 @@ object AppUpdater {
setPositiveButton(currContext()!!.getString(R.string.lets_go)) { setPositiveButton(currContext()!!.getString(R.string.lets_go)) {
MainScope().launch(Dispatchers.IO) { MainScope().launch(Dispatchers.IO) {
try { try {
val apks = val apkUrl = fetchApkUrl(repo, version, BuildConfig.DEBUG)
client.get("https://api.github.com/repos/$repo/releases/tags/v$version") if (apkUrl != null) {
.parsed<GithubResponse>().assets?.filter { activity.downloadUpdate(version, apkUrl)
it.browserDownloadURL.endsWith( } else {
".apk" openLinkInBrowser("https://github.com/repos/$repo/releases/tag/v$version")
)
}
val apkToDownload = apks?.first()
apkToDownload?.browserDownloadURL.apply {
if (this != null) activity.downloadUpdate(version, this)
else openLinkInBrowser("https://github.com/repos/$repo/releases/tag/v$version")
} }
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
@ -112,8 +169,7 @@ object AppUpdater {
} }
show(activity.supportFragmentManager, "dialog") show(activity.supportFragmentManager, "dialog")
} }
} } else {
else {
if (post) snackString(currContext()?.getString(R.string.no_update_found)) if (post) snackString(currContext()?.getString(R.string.no_update_found))
} }
} }

View file

@ -157,6 +157,8 @@ import java.util.TimeZone
import java.util.Timer import java.util.Timer
import java.util.TimerTask import java.util.TimerTask
import kotlin.collections.set import kotlin.collections.set
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.math.log2 import kotlin.math.log2
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -1524,3 +1526,13 @@ fun getLanguageName(language: String): String? {
} }
return null return null
} }
@OptIn(ExperimentalEncodingApi::class)
fun String.decodeBase64ToString(): String {
return try {
String(Base64.decode(this), Charsets.UTF_8)
} catch (e: Exception) {
Logger.log(e)
""
}
}