diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/DatabaseRepo.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/DatabaseRepo.kt index 14393a65..5ed07958 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/DatabaseRepo.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/DatabaseRepo.kt @@ -140,7 +140,7 @@ class DatabaseRepo( fun resolve(names: List): Set = names.mapNotNull { name -> val keys = dataParser.normalizeAmSatName(name) nameToCatnum.entries.firstOrNull { (localName, _) -> - keys.any { key -> localName.contains(key) } + dataParser.matchesAmSatName(localName, keys) }?.value }.toSet() val fmCatnums = resolve(fmNames) diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SelectionRepo.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SelectionRepo.kt index db9e340a..d9e183b1 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SelectionRepo.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SelectionRepo.kt @@ -74,7 +74,17 @@ class SelectionRepo( when (type) { Sources.virtualTypeNames[0] -> idsSet.addAll(settingsRepo.getAmSatFmCatnums()) Sources.virtualTypeNames[1] -> idsSet.addAll(settingsRepo.getAmSatLinearCatnums()) - Sources.virtualTypeNames[2] -> idsSet.addAll(localSource.getIdsWithModes(listOf("SSTV"))) + // Live SSTV: mode=SSTV transponder records intersected with the + // currently-tracked (in-orbit, from the selected TLE sources) + // satellites. The raw mode query alone would include retired + // weather/experimental birds (e.g. TIROS catnum 1430 whose old + // TV downlink is labelled SSTV but is long gone from orbit). + Sources.virtualTypeNames[2] -> { + val inOrbitIds = currentItems.value.map { it.catnum }.toHashSet() + idsSet.addAll( + localSource.getIdsWithModes(listOf("SSTV")).filter { it in inOrbitIds } + ) + } else -> idsSet.addAll(settingsRepo.getSatelliteTypesIds(listOf(type))) } } diff --git a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/utility/DataParser.kt b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/utility/DataParser.kt index 9e28a2c3..4e162a21 100644 --- a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/utility/DataParser.kt +++ b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/utility/DataParser.kt @@ -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): 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): OrbitalData? = runCatching { diff --git a/core/domain/src/test/java/com/rtbishop/look4sat/core/domain/DataParserTest.kt b/core/domain/src/test/java/com/rtbishop/look4sat/core/domain/DataParserTest.kt index 90abcd82..eb30be83 100644 --- a/core/domain/src/test/java/com/rtbishop/look4sat/core/domain/DataParserTest.kt +++ b/core/domain/src/test/java/com/rtbishop/look4sat/core/domain/DataParserTest.kt @@ -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