Callers now pass the full platform dict and rom.fs_extension; the service
normalizes the extension (optional leading dot, case-insensitive) before
checking the compressed-archive skip set, so ROMs stored with bare
extensions like "zip" correctly hit the skip path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RAHasher was being spawned for every hashable ROM regardless of file
type. When the source file is a zip/7z/tar and the RA platform needs
an on-disk disc image (PSX, PS2, PSP, Saturn, Dreamcast, Sega CD,
3DO, PC-FX, Neo Geo CD, TurboGrafx CD, Atari Jaguar CD, Wii), the
subprocess fails with "Unsupported console for buffer hash: {id}"
after paying full process-spawn overhead per ROM — a serious slowdown
when indexing large zipped collections (e.g. myrient PS2/PSP sets).
calculate_hash now short-circuits those combinations with a debug log
and no subprocess. Raw disc images (.iso, .chd, .cue/.bin) and
archives on cartridge platforms still go through RAHasher as before.
Also centralize COMPRESSED_FILE_EXTENSIONS in utils/filesystem.py so
roms_handler (is_compressed_file / hashing), rahasher (skip logic),
and feeds (PKGi passthrough) share one source of truth. The shared
set adds .rar, which is_compressed_file now recognizes too.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds the libretro thumbnail repository as a first-class artwork source so
region-correct box art (PAL/Europe, Japan, etc.) can be matched directly
to ROM filenames, addressing rommapp/romm#3239.
Implementation follows the SGDB handler pattern (artwork-only, no game
metadata): MetadataSource enum entry, scan-time fetch wired into the
SCAN_ARTWORK_PRIORITY loop, /search/roms integration, MatchRom dialog
chip + cover selection, and a heartbeat flag.
Matching is exact case-insensitive against the directory listing first
(so a ROM named "(Europe)" lands on the (Europe) artwork), with a
JaroWinkler fuzzy fallback at 0.8 that strips parenthetical tags from
both sides. Listings are cached in Redis with a 24h TTL.
`libretro_id` is persisted on the Rom model as the SHA1 hex of the
matched libretro filename — stable across scans, distinct per region,
indexed for lookup. Migration 0077 adds the column.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a new service adapter for the IGDB API, to separate concerns with
RomM's handler for metadata. This adapter is agnostic to the handler and
only provides methods to interact with the API, and correctly return
typed responses.
The API authorization was also improved to not rely on decorating each
method that makes requests, but instead using an `aiohttp` middleware
to automatically add the required headers to each request.
Utils `mark_expanded` and `mark_list_expanded` where added to help
narrow the types of IGDB's expandable fields when we know they are
expanded, for `mypy` type checking.
Add a new service adapter for the MobyGames API, to separate concerns
with RomM's handler for metadata.
This adapter is agnostic to the handler and only provides methods to
interact with the API, and correctly return typed responses.
Add a new service adapter for the SteamGridDB API, to separate
concerns with RomM's handler for metadata.
This adapter is agnostic to the handler and only provides methods to
interact with the API, and correctly return typed responses.
Add a new service adapter for the ScreenScraper API, to separate
concerns with RomM's handler for metadata.
This adapter is agnostic to the handler and only provides methods to
interact with the API, and correctly return typed responses.
Iterate through all pages of user completion progress in the
RetroAchievements service, instead of limiting the data retrieval to the
first 500 results.
This change replaces the `httpx` client with `aiohttp` for the
RetroAchievements API service.
The main reason for this change is that `httpx` has an unavoidable log
line with `INFO` level, which includes the request full URL, containing
the user's API key.
`httpx` has had an
[open discussion](https://github.com/encode/httpx/discussions/2765)
regarding this security issue for almost two years.
The change to `aiohttp` is painless, and would allow us to migrate more
of the codebase to it in the future, to avoid leaking sensitive
information in logs.
Add a new service adapter for the RetroAchievements API, to separate
concerns with RomM's handler for metadata. This adapter is agnostic
to the handler and only provides methods to interact with the
API, and correctly return typed responses.
The API authorization was also improved to be handled by a specific
`httpx.Auth` class that sets the `y` parameter for each request.