diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/UpdateRepository.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/UpdateRepository.kt index c03ed82f..2408a83f 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/UpdateRepository.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/UpdateRepository.kt @@ -5,7 +5,6 @@ import com.rtbishop.look4sat.core.domain.repository.IUpdateRepository import com.rtbishop.look4sat.core.domain.source.IRemoteSource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import org.json.JSONObject import java.io.File class UpdateRepository( @@ -13,11 +12,15 @@ class UpdateRepository( ) : IUpdateRepository { 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 stream = result.stream ?: return@withContext null try { - val json = stream.bufferedReader().use { it.readText() } - parseRelease(json) + val html = stream.bufferedReader().use { it.readText() } + parseRelease(html) } catch (e: Exception) { println("UpdateRepository parse failure: $e") null @@ -37,31 +40,33 @@ class UpdateRepository( } } - private fun parseRelease(json: String): LatestRelease? { - val obj = JSONObject(json) - val tag = obj.optString("tag_name") - if (tag.isBlank()) return null - val assets = obj.optJSONArray("assets") - var apkUrl: String? = null - if (assets != null) { - for (i in 0 until assets.length()) { - val asset = assets.optJSONObject(i) ?: continue - val name = asset.optString("name", "") - if (name.endsWith(".apk")) { - apkUrl = asset.optString("browser_download_url", "").ifBlank { null } - if (apkUrl != null) break - } - } - } + private fun parseRelease(html: String): LatestRelease? { + // The redirect target is the latest release's tag page. Extract the tag + // from the og:url meta tag ("…/releases/tag/v4.4.6-ba7opf.8") — stable and + // unambiguous. The