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>
Add X-Archive-Charset: UTF-8 header so mod_zip sets the EFS flag on ZIP
entries, ensuring extractors interpret filenames as UTF-8 instead of
CP437. Also URL-encode the Content-Disposition filename to match
FileRedirectResponse behavior.
Add metadata.pegasus.txt export alongside the existing gamelist.xml
export. Restructure the export system: rename the gamelist endpoint to
a general-purpose export endpoint (`/api/export/`) with sub-routes for
each format (`/gamelist-xml`, `/pegasus`). Move config from flat
`scan.export_gamelist` to nested `scan.export.gamelist_xml` and
`scan.export.pegasus` for auto-export on scan.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use atomic getdel for pairing code exchange
- Add cascade="all, delete-orphan" to User.client_tokens
- Move generate/hash_client_token into AuthHandler as static methods
- Extract endpoint helpers to utils/client_tokens.py