fix: AMSAT name matching token-based; SSTV filters to in-orbit only

- matchesAmSatName: exact token match instead of substring contains,
  so 'ISS' no longer matches AISSAT-1 and 'AO-7' no longer matches
  AO-73 (FUNCUBE-1); resolves missing ISS in FM and missing AO-7 in
  Linear lists
- resolveTypeIds: intersect SSTV catnums with current in-orbit TLE set,
  excluding retired satellites (e.g. TIROS) whose radios are tagged SSTV
- add regression tests for token matching
This commit is contained in:
atsunatsu committed 2026-09-24 02:53:34 +08:00
1 parent e7754a4c9e
commit 30000a913e
4 files changed
+27 -5

No files matched your search

@@ -128,10 +128,18 @@ class DataParser(private val dispatcher: CoroutineDispatcher) {
return keys.distinct()
}
/** True if a local entry name matches any of the AMSAT normalized keys. */
/** True if a local entry name matches any of the AMSAT normalized keys.
* Token-based exact match (split on spaces/brackets/slashes), so a key
* like "ISS" does not substring-match "AISSAT-1" — the key must equal a
* whole name token (case-insensitive). */
fun matchesAmSatName(localName: String, amSatKeys: List<String>): Boolean {
val localUpper = localName.uppercase()
return amSatKeys.any { key -> localUpper.contains(key) }
val localTokens = localName.uppercase()
.split(Regex("[\\s()\\[\\]/]+"))
.filter { it.isNotBlank() }
.toSet()
return amSatKeys.any { key ->
key.uppercase() in localTokens
}
}
private fun parseCSV(values: List<String>): OrbitalData? = runCatching {
@@ -279,6 +279,10 @@ class DataParserTest {
assert(dataParser.normalizeAmSatName("ISS") == listOf("ISS"))
assert(dataParser.matchesAmSatName("AO-91 (RADFXSAT)", listOf("AO-91", "RADFXSAT")))
assert(!dataParser.matchesAmSatName("SO-50", listOf("AO-91")))
// Regression: "ISS" must not substring-match "AISSAT-1" (token match only).
assert(dataParser.matchesAmSatName("ISS (ZARYA)", listOf("ISS")))
assert(!dataParser.matchesAmSatName("AISSAT-1", listOf("ISS")))
assert(!dataParser.matchesAmSatName("TESS", listOf("ISS")))
}
@Test