|
11 | 11 | from adapters.services.retroachievements import RetroAchievementsService |
12 | 12 | from adapters.services.retroachievements_types import ( |
13 | 13 | RAGameExtendedDetails, |
14 | | - RAGameListItem, |
15 | 14 | ) |
16 | 15 | from config import ( |
17 | 16 | REFRESH_RETROACHIEVEMENTS_CACHE_DAYS, |
@@ -128,7 +127,7 @@ def parse_release_timestamp(): |
128 | 127 | class RAHandler(MetadataHandler): |
129 | 128 | def __init__(self) -> None: |
130 | 129 | self.ra_service = RetroAchievementsService() |
131 | | - self.HASHES_FILE_NAME = "ra_hashes.json" |
| 130 | + self.HASHES_FILE_NAME = "ra_hashes_v2.json" |
132 | 131 |
|
133 | 132 | @classmethod |
134 | 133 | def is_enabled(cls) -> bool: |
@@ -174,47 +173,44 @@ async def _days_since_last_cache_file_update(self, platform_id: int) -> int: |
174 | 173 | file_stat = await AnyioPath(str(full_path)).stat() |
175 | 174 | return int((time.time() - file_stat.st_mtime) / (24 * 3600)) |
176 | 175 |
|
177 | | - async def _search_rom(self, rom: Rom, ra_hash: str) -> RAGameListItem | None: |
| 176 | + async def _search_rom(self, rom: Rom, ra_hash: str) -> int | None: |
178 | 177 | if not rom.platform.ra_id: |
179 | 178 | return None |
180 | 179 |
|
181 | | - # Fetch all hashes for specific platform |
182 | | - roms: list[RAGameListItem] |
| 180 | + # hash_index maps lowercase hash -> game ID for O(1) lookups |
| 181 | + hash_index: dict[str, int] |
183 | 182 | if ( |
184 | 183 | REFRESH_RETROACHIEVEMENTS_CACHE_DAYS |
185 | 184 | <= await self._days_since_last_cache_file_update(rom.platform.id) |
186 | 185 | or not await self._exists_cache_file(rom.platform.id) |
187 | 186 | ): |
188 | | - # Write the roms result to a JSON file if older than REFRESH_RETROACHIEVEMENTS_CACHE_DAYS days |
| 187 | + # Fetch all games (including those without achievements) and build index |
189 | 188 | roms = await self.ra_service.get_game_list( |
190 | 189 | system_id=rom.platform.ra_id, |
191 | | - only_games_with_achievements=True, |
| 190 | + only_games_with_achievements=False, |
192 | 191 | include_hashes=True, |
193 | 192 | ) |
194 | 193 |
|
| 194 | + hash_index = {h.lower(): r["ID"] for r in roms for h in r.get("Hashes", ())} |
| 195 | + |
195 | 196 | platform_resources_path = fs_resource_handler.get_platform_resources_path( |
196 | 197 | rom.platform.id |
197 | 198 | ) |
198 | 199 |
|
199 | | - json_file = json.dumps(roms, indent=4) |
| 200 | + json_file = json.dumps(hash_index, indent=4) |
200 | 201 | await fs_resource_handler.write_file( |
201 | 202 | json_file.encode("utf-8"), |
202 | 203 | platform_resources_path, |
203 | 204 | self.HASHES_FILE_NAME, |
204 | 205 | ) |
205 | 206 | else: |
206 | | - # Read the roms result from the JSON file |
| 207 | + # Read the hash index from the JSON file |
207 | 208 | json_file_bytes = await fs_resource_handler.read_file( |
208 | 209 | self._get_hashes_file_path(rom.platform.id) |
209 | 210 | ) |
210 | | - roms = json.loads(json_file_bytes.decode("utf-8")) |
211 | | - |
212 | | - ra_hash_lower = ra_hash.lower() |
213 | | - for r in roms: |
214 | | - if any(ra_hash_lower == h.lower() for h in r.get("Hashes", ())): |
215 | | - return r |
| 211 | + hash_index = json.loads(json_file_bytes.decode("utf-8")) |
216 | 212 |
|
217 | | - return None |
| 213 | + return hash_index.get(ra_hash.lower()) |
218 | 214 |
|
219 | 215 | def get_platform(self, slug: str) -> RAGamesPlatform: |
220 | 216 | if slug not in RA_PLATFORM_LIST: |
@@ -250,15 +246,13 @@ async def get_rom(self, rom: Rom, ra_hash: str) -> RAGameRom: |
250 | 246 | if not ra_hash: |
251 | 247 | return RAGameRom(ra_id=None) |
252 | 248 |
|
253 | | - ra_game_list_item = await self._search_rom(rom, ra_hash) |
| 249 | + ra_game_id = await self._search_rom(rom, ra_hash) |
254 | 250 |
|
255 | | - if not ra_game_list_item: |
| 251 | + if ra_game_id is None: |
256 | 252 | return RAGameRom(ra_id=None) |
257 | 253 |
|
258 | 254 | try: |
259 | | - rom_details = await self.ra_service.get_game_extended_details( |
260 | | - ra_game_list_item["ID"] |
261 | | - ) |
| 255 | + rom_details = await self.ra_service.get_game_extended_details(ra_game_id) |
262 | 256 |
|
263 | 257 | return RAGameRom( |
264 | 258 | ra_id=rom_details["ID"], |
|
0 commit comments