Compare commits

..
Author SHA1 Message Date
atsunatsu cbe3e50f86 build: release version 4.4.8-ba7opf.8 (563) 2026-10-04 11:57:03 +08:00
atsunatsu 38b29e3015 build: candidate version 4.4.8-ba7opf.7.2 (562) 2026-10-04 02:32:42 +08:00
atsunatsu 1a3a05c8b6 feat(sources): 默认 TLE 源对齐上游(9 项),保留 fork 新增源
新默认顺序(上游"most specific → most generic",fork 新增源保持原位):
LAPAN-A2 → ARISS → R4UAB → AutoTLE(GitHub) → AutoTLE(Mirror) → Classified
→ Amsat → All (CelesTrak active) → SatNOGS;Other 占位保留。
删掉 22 个 CelesTrak 分类组与 McCants inttles.zip(上游 4.4.4 起即如此,
单一 active 组已覆盖),同步请求数 32 → 9。

转发器源顺序维持 SatNOGS → R4UAB(与上游相反)并注明实测理由:两源同源
(共享 2760 uuid),去重先到先得,SatNOGS 副本更新鲜且独有最新星的发射机。
2026-10-04 02:32:39 +08:00
atsunatsu 1e33a10fb4 fix(satellites): All 类型名单为空时回退为不筛选
CelesTrak 对重复下载(2 小时内数据未更新)返回 403,同步会把该源的
type id 名单写成空串,选 All 时 resolveTypeIds 得空集 → 列表一条不剩。
现在只有 "All"(= CelesTrak active 全集)在名单为空时回退为不筛选(显示
全部卫星);其它源名类型与三个虚拟类型(AMSAT Live FM/Linear、Live SSTV)
保持"空即显示空"。Sources 增加 allSourceType 常量并注明背景。

Tests: SelectionRepoSearchTest 新增 2 例(All 空→显示全部、其它源空→仍空)
2026-10-04 02:32:31 +08:00
atsunatsu 6546e32360 docs(agents): release notes must be bilingual (English first, then Chinese) 2026-10-03 03:28:35 +08:00
5 changed files with 68 additions and 29 deletions

No files matched your search

+11
View File
@@ -112,6 +112,17 @@ transition to OMM/CSV automatically.
- `build-logic/convention/` contains all shared Gradle configuration — edit there, not in individual modules.
- ProGuard is enabled for release builds — don't add reflection-based libs or any other dependencies without asking.
## Release Notes Must Be Bilingual (BA7OPF fork convention)
Every GitHub release body carries **two sections — English first, then Chinese** (`## <tag>` each),
listing only that release's changes, in the same order with the same claims and the same numbers.
Both sections end with the verification line (which unit tests ran, APK signature / ABI check).
A single-language body is a defect: fix it before the release counts as done.
中文规则:每次 release 的说明必须**中英双语,先英文后中文**,两段一一对应(同一顺序、同一结论、
同一数字,不做自由意译),只列本版改动;两段末尾都写验证情况(跑了哪些单测、签名/ABI 校验)。
只写一种语言视为缺陷,需补齐后再算发布完成。
## Copilot Working Mode: Code-Only
- Default to code changes only. Provide explanations in chat only.
@@ -51,7 +51,15 @@ class SelectionRepo(
null // null = no filtering
} else {
val ids = resolveTypeIds(types)
if (ids.isEmpty()) emptySet() else ids.toHashSet()
when {
ids.isNotEmpty() -> ids.toHashSet()
// "All" is the CelesTrak active group, i.e. the whole catalogue: an empty
// persisted list must mean "no filtering" (show every satellite), not an
// empty list. Its list can be empty simply because CelesTrak answered 403
// to a repeated download inside the 2-hour update window.
Sources.allSourceType in types -> null
else -> emptySet()
}
}
currentItems.map { items ->
if (catnumSet == null) items else items.filter { it.catnum in catnumSet }
@@ -23,6 +23,7 @@ import com.rtbishop.look4sat.core.domain.predict.OrbitalObject
import com.rtbishop.look4sat.core.domain.repository.ISelectionRepo
import com.rtbishop.look4sat.core.domain.repository.ISettingsRepo
import com.rtbishop.look4sat.core.domain.source.ILocalSource
import com.rtbishop.look4sat.core.domain.source.Sources
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -241,6 +242,26 @@ class SelectionRepoSearchTest {
assertEquals(sampleItems.map { it.catnum }.toSet(), results.map { it.catnum }.toSet())
}
@Test
fun `All with empty persisted ids falls back to no filtering`() = runTest {
// CelesTrak answers 403 to a repeated download inside its 2-hour update window,
// so the persisted "All" id list can be empty. Selecting All then means "all
// satellites" (no filtering) instead of blanking the list.
val repo = createRepo(sampleItems)
repo.setTypes(listOf(Sources.allSourceType))
val results = repo.getEntriesFlow().first()
assertEquals(sampleItems.map { it.catnum }.toSet(), results.map { it.catnum }.toSet())
}
@Test
fun `other source type with empty persisted ids still shows empty`() = runTest {
// Only "All" falls back to no filtering; a regular source without persisted ids
// keeps the previous behaviour (empty list).
val repo = createRepo(sampleItems)
repo.setTypes(listOf("Amateur"))
assertTrue(repo.getEntriesFlow().first().isEmpty())
}
@Test
fun `getTypesList excludes only the Other placeholder`() = runTest {
val repo = createRepo(sampleItems)
@@ -18,41 +18,32 @@
package com.rtbishop.look4sat.core.domain.source
object Sources {
// Default TLE sources, aligned with upstream's "most specific to most generic" order:
// the first source that knows a satellite gets to name it, with the full catalogue
// (CelesTrak active) as the fallback. Upstream dropped the old CelesTrak category
// groups (amateur/cubesat/weather/...) — a single `active` group covers them and keeps
// the request count (and CelesTrak's 2-hourly "already downloaded" 403s) down.
// The three BA7OPF additions keep their own spots: Kaggle LAPAN-A2 first and the two
// AutoTLE mirrors next to R4UAB (Chinese amateur catalogues, freshest for CN sats).
val satelliteDataUrls = mapOf(
"LAPAN-A2" to "https://www.kaggle.com/api/v1/datasets/download/muazamnugroho/lapan-a2-satellite-two-line-element-tle-dataset/LAPAN-A2_TLE_latest.txt",
"ARISS" to "https://live.ariss.org/iss.txt",
"R4UAB" to "https://r4uab.ru/satonline.txt",
"BI4PYM AutoTLE (GitHub)" to "https://raw.githubusercontent.com/BI4PYM/AutoTLE/refs/heads/master/AutoTLE.txt",
"BI4PYM AutoTLE (Mirror)" to "https://autotle.bi4pym.cn/AutoTLE.txt",
"Classified" to "https://www.mmccants.org/tles/classfd.zip",
"Amsat" to "https://amsat.org/tle/current/nasabare.txt",
"All" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=active&FORMAT=csv",
"SatNOGS" to "https://db.satnogs.org/api/tle/?format=3le",
"Amateur" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=amateur&FORMAT=csv",
"Brightest" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=visual&FORMAT=csv",
"Cubesat" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=cubesat&FORMAT=csv",
"Education" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=education&FORMAT=csv",
"Engineer" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=engineering&FORMAT=csv",
"Geostationary" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=geo&FORMAT=csv",
"Globalstar" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=globalstar&FORMAT=csv",
"GNSS" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=gnss&FORMAT=csv",
"Intelsat" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=intelsat&FORMAT=csv",
"Iridium" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=iridium-NEXT&FORMAT=csv",
"Military" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=military&FORMAT=csv",
"New" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=last-30-days&FORMAT=csv",
"OneWeb" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=oneweb&FORMAT=csv",
"Orbcomm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=orbcomm&FORMAT=csv",
"Resource" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=resource&FORMAT=csv",
"CelesTrak SatNOGS" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=satnogs&FORMAT=csv",
"Science" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=science&FORMAT=csv",
"Spire" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=spire&FORMAT=csv",
"Starlink" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=starlink&FORMAT=csv",
"Swarm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=swarm&FORMAT=csv",
"Weather" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=weather&FORMAT=csv",
"X-Comm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=x-comm&FORMAT=csv",
"Amsat" to "https://amsat.org/tle/current/nasabare.txt",
"Classified" to "https://www.mmccants.org/tles/classfd.zip",
"McCants" to "https://www.mmccants.org/tles/inttles.zip",
"ARISS" to "https://live.ariss.org/iss.txt",
"Other" to "" // key for sats filter
)
// Transceiver sources. Both publish the same SatNOGS-uuid records (measured 2026-10-04:
// 2760 shared uuids), and the sync keeps the FIRST source's copy for a shared uuid
// (distinctBy { uuid }). SatNOGS is kept first on purpose: its copies carry the
// up-to-date descriptions (e.g. AO-91 "no CTCSS any longer") and it is the only source
// with the newest satellites' transmitters (T-18 objects etc.), while R4UAB mainly adds
// long-dead entries plus a handful of live extras. Upstream lists R4UAB first; this fork
// intentionally differs.
val transceiversDataUrls = mapOf(
"SatNOGS" to "https://db.satnogs.org/api/transmitters/?format=json&status=active",
"R4UAB" to "https://r4uab.ru/transmitters.json"
@@ -78,4 +69,12 @@ object Sources {
* per-type IDs, and are mutually exclusive with the regular TLE-source
* types in the picker. */
val virtualTypeNames = listOf("AMSAT Live FM", "AMSAT Live Linear", "Live SSTV")
/** Key of the CelesTrak "active" group source in [satelliteDataUrls] — the whole
* catalogue. Selecting it means "all satellites", so when its persisted id list
* is empty the picker must fall back to no filtering instead of showing an empty
* list. The list can legitimately be empty: CelesTrak answers 403 ("GP data has
* not updated since your last successful download", groups update every 2 hours)
* when a group is re-requested, and the sync then persists nothing for that type. */
val allSourceType = "All"
}
+2 -2
View File
@@ -1,8 +1,8 @@
[versions]
#noinspection UnusedVersionCatalogEntry
appVersionCode = "560"
appVersionCode = "563"
#noinspection UnusedVersionCatalogEntry
appVersionName = "4.4.8-ba7opf.6"
appVersionName = "4.4.8-ba7opf.8"
#noinspection UnusedVersionCatalogEntry
compileSdk = "37"
#noinspection UnusedVersionCatalogEntry