mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-05 20:17:29 +00:00
fix: update check via GitHub web endpoint, avoiding API 60 req/hour rate limit
This commit is contained in:
1 parent
5c73d5ed7a
commit
7abbeb6eb3
1 file changed
+27
-22
+27
-22
@@ -5,7 +5,6 @@ import com.rtbishop.look4sat.core.domain.repository.IUpdateRepository
|
|||||||
import com.rtbishop.look4sat.core.domain.source.IRemoteSource
|
import com.rtbishop.look4sat.core.domain.source.IRemoteSource
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.json.JSONObject
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class UpdateRepository(
|
class UpdateRepository(
|
||||||
@@ -13,11 +12,15 @@ class UpdateRepository(
|
|||||||
) : IUpdateRepository {
|
) : IUpdateRepository {
|
||||||
|
|
||||||
override suspend fun getLatestRelease(): LatestRelease? = withContext(Dispatchers.IO) {
|
override suspend fun getLatestRelease(): LatestRelease? = withContext(Dispatchers.IO) {
|
||||||
|
// Use the GitHub releases web page instead of the REST API endpoint:
|
||||||
|
// the API endpoint is rate-limited to 60 requests/hour per IP, which is
|
||||||
|
// quickly exhausted on shared egress IPs (e.g. VPN proxies), causing 403
|
||||||
|
// failures. The web endpoint redirects to the latest tag with no such limit.
|
||||||
val result = remoteSource.getNetworkStream(LATEST_RELEASE_URL)
|
val result = remoteSource.getNetworkStream(LATEST_RELEASE_URL)
|
||||||
val stream = result.stream ?: return@withContext null
|
val stream = result.stream ?: return@withContext null
|
||||||
try {
|
try {
|
||||||
val json = stream.bufferedReader().use { it.readText() }
|
val html = stream.bufferedReader().use { it.readText() }
|
||||||
parseRelease(json)
|
parseRelease(html)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("UpdateRepository parse failure: $e")
|
println("UpdateRepository parse failure: $e")
|
||||||
null
|
null
|
||||||
@@ -37,31 +40,33 @@ class UpdateRepository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseRelease(json: String): LatestRelease? {
|
private fun parseRelease(html: String): LatestRelease? {
|
||||||
val obj = JSONObject(json)
|
// The redirect target is the latest release's tag page. Extract the tag
|
||||||
val tag = obj.optString("tag_name")
|
// from the og:url meta tag ("…/releases/tag/v4.4.6-ba7opf.8") — stable and
|
||||||
if (tag.isBlank()) return null
|
// unambiguous. The <title> also holds the release name, but that is free
|
||||||
val assets = obj.optJSONArray("assets")
|
// text and cannot be used to build the asset URL.
|
||||||
var apkUrl: String? = null
|
val ogUrl = Regex("<meta\\s+property=\"og:url\"\\s+content=\"([^\"]*)\"").find(html)
|
||||||
if (assets != null) {
|
?.groupValues?.get(1) ?: return null
|
||||||
for (i in 0 until assets.length()) {
|
val tag = Regex("/releases/tag/(v[0-9][0-9A-Za-z.\\-]*)$").find(ogUrl)
|
||||||
val asset = assets.optJSONObject(i) ?: continue
|
?.groupValues?.get(1) ?: return null
|
||||||
val name = asset.optString("name", "")
|
val title = Regex("<title>(.*?)</title>", RegexOption.DOT_MATCHES_ALL)
|
||||||
if (name.endsWith(".apk")) {
|
.find(html)?.groupValues?.get(1)?.trim()
|
||||||
apkUrl = asset.optString("browser_download_url", "").ifBlank { null }
|
?.substringBefore("·")?.removePrefix("Release")?.trim() ?: tag
|
||||||
if (apkUrl != null) break
|
// The release APK asset follows the fixed naming scheme used by the build:
|
||||||
}
|
// Look4Sat-<tag without leading v>-release.apk
|
||||||
}
|
val apkUrl = "$DOWNLOAD_BASE_URL/$tag/Look4Sat-${tag.removePrefix("v")}-release.apk"
|
||||||
}
|
|
||||||
return LatestRelease(
|
return LatestRelease(
|
||||||
versionTag = tag,
|
versionTag = tag,
|
||||||
title = obj.optString("name", ""),
|
title = title,
|
||||||
body = obj.optString("body", ""),
|
body = "",
|
||||||
apkUrl = apkUrl
|
apkUrl = apkUrl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val LATEST_RELEASE_URL = "https://api.github.com/repos/atsunatsu/Look4Sat/releases/latest"
|
// Web pages are used instead of api.github.com to avoid the 60 req/hour
|
||||||
|
// anonymous rate limit (see getLatestRelease above).
|
||||||
|
const val LATEST_RELEASE_URL = "https://github.com/atsunatsu/Look4Sat/releases/latest"
|
||||||
|
const val DOWNLOAD_BASE_URL = "https://github.com/atsunatsu/Look4Sat/releases/download"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user