-
-
Notifications
You must be signed in to change notification settings - Fork 14
commit 911c495
abduznik edited this page May 23, 2026
·
1 revision
Commit: 911c495ee4ebffbb92bbd6881e3c7802244a22dc
Author: abduznik
Date: 2026-04-29
Why: Fixes a bug or regression in the existing codebase.
lib/core/romm/rom_scanner_service.dart | 13 ++++++++
lib/providers/downloaded_games_cache_provider.dart | 35 ++++++++++++++++++++--
2 files changed, 46 insertions(+), 2 deletions(-)
lib/core/romm/rom_scanner_service.dartlib/providers/downloaded_games_cache_provider.dart
diff --git a/lib/core/romm/rom_scanner_service.dart b/lib/core/romm/rom_scanner_service.dart
index 13c8532..e0925d7 100644
--- a/lib/core/romm/rom_scanner_service.dart
+++ b/lib/core/romm/rom_scanner_service.dart
@@ -182,4 +182,17 @@ class RomScannerService {
}
}
+
+ /// Prunes all mappings that point to non-existent files.
+ Future<int> pruneDeadMappings() async {
+ final mappings = _mappingService.getMappings();
+ int count = 0;
+ for (final entry in mappings.entries) {
+ if (!await File(entry.key).exists() && !await Directory(entry.key).exists()) {
+ await _mappingService.removeMapping(entry.key);
+ count++;
+ }
+ }
+ return count;
+ }
}
diff --git a/lib/providers/downloaded_games_cache_provider.dart b/lib/providers/downloaded_games_cache_provider.dart
index 32dbf1d..9370969 100644
--- a/lib/providers/downloaded_games_cache_provider.dart
+++ b/lib/providers/downloaded_games_cache_provider.dart
@@ -64,12 +64,19 @@ class DownloadedGamesCache extends StateNotifier<Map<String, bool>> {
/// Also verifies they actually exist on disk to prevent 'zombie' games.
Future<void> refresh() async {
final mappingServiceAsync = _ref.read(romMappingServiceProvider);
- if (!mappingServiceAsync.hasValue) return;
+ final metadataCacheAsync = _ref.read(metadataCacheServiceProvider);
+ final rommService = _ref.read(rommServiceProvider);
+
+ if (!mappingServiceAsync.hasValue || !metadataCacheAsync.hasValue) return;
final mappingService = mappingServiceAsync.value!;
+ final metadataCache = metadataCacheAsync.value!;
final mappings = mappingService.getMappings();
final Map<String, bool> newState = {};
+ final Set<String> missingMetadataIds = {};
+ final cachedIds = metadataCache.cachedGames.map((g) => g.id).toSet();
+
for (final entry in mappings.entries) {
final path = entry.key;
final romId = entry.value;
@@ -77,6 +84,9 @@ class DownloadedGamesCache extends StateNotifier<Map<String, bool>> {
// DISK CHECK: If the file was deleted manually, clean up the mapping
if (await io.File(path).exists() || await io.Directory(path).exists()) {
newState[romId] = true;
+ if (!cachedIds.contains(romId)) {
+ missingMetadataIds.add(romId);
+ }
} else {
debugPrint('[DownloadedGamesCache] Zombie detected: $path no longer exists. Removing.');
await mappingService.removeMapping(path);
@@ -84,7 +94,22 @@ class DownloadedGamesCache extends StateNotifier<Map<String, bool>> {
}
state = newState;
- debugPrint('[DownloadedGamesCache] Loaded ${state.length} active mappings.');
+ debugPrint('[DownloadedGamesCache] Loaded ${state.length} active mappings (${missingMetadataIds.length} missing metadata).');
+
+ // AUTO-REPAIR: Fetch missing metadata in small batches
+ if (missingMetadataIds.isNotEmpty && rommService != null) {
+ debugPrint('[DownloadedGamesCache] Repairing metadata for ${missingMetadataIds.length} games...');
+ final List<Game> repairedGames = [];
+ for (final id in missingMetadataIds.take(20)) { // Limit to 20 per refresh to avoid spam
+ final game = await rommService.getGame(id);
+ if (game != null) repairedGames.add(game);
+ }
+ if (repairedGames.isNotEmpty) {
+ await metadataCache.saveGames(repairedGames);
+ debugPrint('[DownloadedGamesCache] Repaired ${repairedGames.length} metadata entries.');
+ // Don't call refresh again to avoid loops, the next state update will pick it up
+ }
+ }
}
/// Runs the high-performance incremental sync.
@@ -106,6 +131,12 @@ class DownloadedGamesCache extends StateNotifier<Map<String, bool>> {
debugPrint('[DownloadedGamesCache] Starting incremental sync...');
try {
+ // 1. Global Pruning Phase
+ final prunedCount = await scanner.pruneDeadMappings();
+ if (prunedCount > 0) {
+ debugPrint('[DownloadedGamesCache] Pruned $prunedCount dead mappings.');
+ }
+
final romsRoot = await dirService.getRomsDirectory();
final List<Game> matchedMetadataBuffer = [];
final Map<String, bool> sessionMatches = {};