Commit Graph

1582 Commits

Author SHA1 Message Date
Georges-Antoine Assi
aed926ac9e Add playmatch as explicit metadata source 2026-05-22 21:44:33 -04:00
Georges-Antoine Assi
d7c789c4c4 Merge pull request #3400 from rommapp/copilot/fix-steamgriddb-igdb-matching
Fix IGDB/SGDB matching wrong game for standalone expansions (e.g. Ecco: The Tides of Time)
2026-05-21 18:38:58 -04:00
Georges-Antoine Assi
1377e2991d fix test again 2026-05-21 18:30:30 -04:00
Georges-Antoine Assi
f9c0a8f966 run fmt 2026-05-21 18:09:01 -04:00
Georges-Antoine Assi
7885f5eeb9 Merge pull request #3401 from rommapp/copilot/fix-metadata-id-fetch-issue
Fix: UNMATCHED scan ignores manually-set metadata IDs when metadata is absent
2026-05-21 18:08:40 -04:00
Georges-Antoine Assi
1be2ca2b3c soimplify 2026-05-21 17:17:30 -04:00
Georges-Antoine Assi
f40aa806ad manual cleanup 2026-05-21 17:12:05 -04:00
copilot-swe-agent[bot]
98bc9a9eea Optimize multi-ROM exclusion matching pass
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-21 18:52:55 +00:00
copilot-swe-agent[bot]
5a1e238a5f perf: pre-normalize exclusions once and use set for O(1) lookup in exclude_multi_roms
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-21 18:50:45 +00:00
copilot-swe-agent[bot]
90bbf6c9d1 fix: fetch metadata for manually-set IDs on UNMATCHED scan
When a user manually sets metadata IDs (e.g., ra_id, launchbox_id, hasheous_id)
via the UI and then runs "Refresh Metadata" (which defaults to UNMATCHED scan type),
no metadata was fetched because UNMATCHED conditions checked `not rom.xxx_id` — so
if the ID was already set, the handler was skipped entirely.

Fix: Change each handler's UNMATCHED condition to also trigger when the ID is set
but the corresponding metadata dict is empty (i.e., `not rom.xxx_id or not rom.xxx_metadata`).
For handlers that support ID-based lookup (RA, Launchbox, IGDB, MobyGames, SS,
Flashpoint), also add the `get_rom_by_id` path inside the function.

For Hasheous: when hash lookup fails but `hasheous_id` is set on an existing ROM
(not newly added), return a partial HasheousRom built from the existing sub-IDs
(igdb_id, ra_id, tgdb_id) so the downstream get_igdb_game / get_ra_game proxy
calls can still enrich the ROM.

Add three targeted tests to validate:
- UNMATCHED scan fetches RA metadata when ra_id is set but ra_metadata is empty
- UNMATCHED scan skips RA when both ra_id and ra_metadata are already populated
- UNMATCHED scan passes existing sub-IDs to Hasheous proxies when hash lookup fails

Agent-Logs-Url: https://github.com/rommapp/romm/sessions/098b482f-9f73-4f35-819a-b55004a79b13

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-21 11:41:23 +00:00
copilot-swe-agent[bot]
3ea960d008 fix: IGDB/SGDB scraping incorrectly matches standalone expansions to parent game
- Add `STANDALONE_EXPANSION` game type to the `with_game_type` filter in
  `_search_rom` so games like "Ecco: The Tides of Time" (which IGDB classifies
  as a standalone expansion) are included in the first search pass and are not
  confused with their parent game ("Ecco The Dolphin")
- Fix the expanded search fallback to fetch and compare ALL unique game IDs
  returned by the IGDB search endpoint, instead of only the first result
- Add tests to verify both fixes

Agent-Logs-Url: https://github.com/rommapp/romm/sessions/d6a0c1dd-e541-4d8e-a272-9e5511a2077e

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-21 11:30:23 +00:00
copilot-swe-agent[bot]
9e3f85b085 Fix ES-DE multi-folder exclusion matching
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/2213cb94-9971-48a6-8d17-9efc5c209db4

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-21 11:22:21 +00:00
Georges-Antoine Assi
94d011ee5e tolerate launchbox basepath 2026-05-21 06:56:36 -04:00
Georges-Antoine Assi
ce20d403aa Merge pull request #3396 from rommapp/fix-ss-multi-region-priority
fix(screenscraper): respect region priority for multi-region ROMs
2026-05-20 20:21:50 -04:00
Georges-Antoine Assi
2e7beeec5b remove meta source fields 2026-05-20 17:43:50 -04:00
Georges-Antoine Assi
6c84241ef5 Extract METADATA_SOURCE_FIELDS constant in scan_handler
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:37:20 -04:00
Georges-Antoine Assi
fe5af3ef9c fix(screenscraper): respect region priority for multi-region ROMs
For ROMs tagged with multiple regions (e.g. "(Japan, USA)"), filename order
previously decided which region's name and box art won. Now reorder the rom's
filename-tagged regions by SCAN_REGION_PRIORITY before prepending, so the
user's configured preference wins among the regions the file is actually
tagged as. Untagged priority regions still cannot outrank a filename-tagged
region.

Also tweak the Total Rescan → Complete Rescan label in en_GB/en_US scan
locales.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:20:54 -04:00
copilot-swe-agent[bot]
440f55ba89 Fix Complete Rescan not clearing unselected metadata sources
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/e76abf0d-7039-4dae-ad88-5f1f1c4f422f

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-20 19:15:56 +00:00
Georges-Antoine Assi
21663fc922 cleanup fomratter 2026-05-20 09:17:35 -04:00
Georges-Antoine Assi
052245f344 Merge pull request #3384 from Spinnich/pr/screenscraper-api-and-redaction
fix(screenscraper): improve API handling, KO scrape data, and metadata sanitization
2026-05-20 09:11:36 -04:00
Spinnich
12c424f829 fix(screenscraper): improve API handling and redact credentials in logs
Fix several issues in ScreenScraper API request/response handling:

- Correctly handle SS-specific HTTP error codes (KO responses, 429, 431,
  and the SS-quirk of returning 401 when server CPU >60%).
- Construct requests with proper parameter encoding so jeuInfos lookups
  and search queries return the expected results.
- Store media URLs returned by SS as-is, preserving the dev credential
  query parameters required for media playback. Removing them broke
  downstream media fetches.

To keep dev credentials out of log output, add a redacting formatter in
the logger pipeline that scrubs ssid/sspassword/devid/devpassword query
parameters from any URL it sees.

Test coverage added for the new HTTP error paths and the as-is URL
storage behaviour.
2026-05-19 19:39:55 -04:00
Georges-Antoine Assi
405f678514 Merge pull request #3388 from rommapp/hardlink-resources-gamelist
feat(fs): hardlink import/export assets, harden sync init
2026-05-19 09:04:18 -04:00
Georges-Antoine Assi
adb050f164 commit and push 2026-05-19 07:31:25 -04:00
Georges-Antoine Assi
f84796da08 Merge pull request #3385 from Spinnich/pr/chd-raw-hashing
feat(hashing): compute raw CHD hashes and route disc-data SHA1 to Hasheous
2026-05-18 14:52:54 -04:00
Georges-Antoine Assi
591b07ec49 changes from bot review 2026-05-18 14:44:52 -04:00
Georges-Antoine Assi
e6d4ede939 cleanup 2026-05-18 07:40:59 -04:00
Georges-Antoine Assi
757fafae5f feat(fs): hardlink import/export assets when possible, harden sync init
Importer (gamelist/launchbox file:// flows) and exporters (gamelist.xml,
metadata.pegasus.txt local exports) now hardlink media assets when source
and destination share a filesystem, falling back transparently to a copy
on EXDEV / EPERM / EOPNOTSUPP / EMLINK / EACCES (cross-device, FAT32,
exFAT, network mounts, etc.). Saves disk space and is effectively
instantaneous on large files (videos, manuals, miximages).

Covers keep a real copy (allow_link=False) because _store_cover resizes
the small cover in place via PIL.Image.save, which would truncate the
shared inode and corrupt the user's source image.

Also makes FSSyncHandler tolerate a missing/unwritable /romm/sync at
startup: an OSError from mkdir now logs a warning instead of crashing
the whole app at module-import time. Sync calls still fail at use time
if the mount remains broken — the right place to surface the error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:38:11 -04:00
Georges-Antoine Assi
90945685e4 Stuff 2026-05-17 12:43:33 -04:00
Spinnich
01f0b1d2b5 feat(hashing): compute raw CHD hashes and route disc-data SHA1 to Hasheous
CHD files now follow the same hash logic as all other file types — CRC32,
MD5, and SHA1 are computed from raw container bytes. This allows
ScreenScraper to log KO entries for unrecognised CHD files, which it
could not do when only the disc-data SHA1 was being computed.

The CHD header SHA1 (disc-data SHA1) is separately extracted and stored
in a new chd_sha1_hash field on RomFile, with a migration adding the
column to rom_files. Hasheous receives only this disc-data SHA1 (no
CRC/MD5) since it indexes disc-based games by disc-data SHA1, not raw
file hashes.

The RAHasher multi-file path now passes the largest CHD directly instead
of a /* wildcard, which RAHasher cannot expand. Hash computations are
wrapped in asyncio.to_thread to avoid blocking the event loop during
large reads.

Hash-lookup metadata handlers (ScreenScraper, Hasheous, Playmatch) now
fall back to rom.files (stored DB hashes) when fs_rom files are not
rehashed, fixing hash-based matching for UNMATCHED and UPDATE scan types.

The Disc SHA-1 is displayed in the ROM detail view for both single-file
(FileInfo.vue) and multi-file (FileSelectItem.vue) CHD games.
2026-05-17 08:01:05 -04:00
Georges-Antoine Assi
9bafd11993 Merge pull request #3381 from DevYukine/feat/playmatch-multi-provider
feat(playmatch): add SteamGridDB, ScreenScraper, MobyGames & Launchbox hash support
2026-05-16 15:53:50 -04:00
Georges-Antoine Assi
c3c6829962 refactor(playmatch): use dict as single source of truth for provider tags
Replace the tuple+derived-dict pair with PLAYMATCH_TAG_TO_ATTR as the
canonical mapping. Rename enum members to UPPER_CASE, expand
PlaymatchRomMatch to cover all provider ids, and inline the fallback
match in place of the _empty_playmatch_rom_match helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:41:33 -04:00
Georges-Antoine Assi
06eac10134 Merge pull request #3368 from rommapp/copilot/fix-ra-hashes-missing-ids
fix: include games without achievements in RA hash cache
2026-05-16 09:13:20 -04:00
Yukine
f307aeaca3 refactor(playmatch): move PLAYMATCH_SUPPORTED_SOURCES into playmatch_handler 2026-05-16 05:41:22 +02:00
Yukine
820595a160 refactor(playmatch): simplify comments 2026-05-16 05:21:22 +02:00
Yukine
563e1f4e76 feat(scan): lift IGDB gate from Playmatch and forward provider ids to fetch funcs 2026-05-16 05:17:37 +02:00
Yukine
d9427573dc feat(playmatch): align with upstream MetadataProvider enum and return all provider ids 2026-05-16 05:17:17 +02:00
Georges-Antoine Assi
1b164ee81b Merge pull request #3380 from EntropyEngineer/feature-gamelist-comma-separated-attributes
Add comma-separated metadata attribute support to gamelist
2026-05-15 21:15:08 -04:00
Georges-Antoine Assi
e7045446a8 run fmt 2026-05-15 21:01:33 -04:00
Entropy Engineer
4999214a92 Add comma-separated metadata attribute support to gamelist
Add comma-separated metadata attribute support to gamelist
2026-05-16 00:41:09 +05:00
Georges-Antoine Assi
3db3dd4434 run fmt 2026-05-14 15:41:32 -04:00
copilot-swe-agent[bot]
2c3335e8cf refactor: version RA hash cache and switch to O(1) hash-index format
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/f7097cd9-6bf4-42df-a14d-ff23e423291f

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-13 18:01:20 +00:00
Georges-Antoine Assi
c6a2f56fad Merge pull request #3367 from rommapp/regional-provider-tags
Prefer ROM's own region tag for ScreenScraper and IGDB artwork
2026-05-13 11:19:53 -04:00
copilot-swe-agent[bot]
157f719297 fix: include games without achievements in ra_hashes.json
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/d113d268-38fd-4564-892d-959fd5fddc68

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-13 15:17:47 +00:00
Georges-Antoine Assi
dad1250e15 case-insensitive region lookup for provider shortcode mapping
Rom.regions can contain raw filename text like "europe" or "EUROPE"
(filename parsing in roms_handler doesn't normalize casing), so the
direct dict lookup missed those tags and the locale silently fell back
to scan.priority.region. Replace the dict access with a helper that
lowercases both sides.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 09:34:10 -04:00
Georges-Antoine Assi
944514acc0 prefer rom's own region tag for ScreenScraper and IGDB artwork
When a ROM filename carries a region tag (e.g. (Europe)), use that
region first when picking artwork and localized titles, falling back to
the configured scan.priority.region. Previously the configured priority
was the only signal, so a US-first config would force US covers onto
European ROMs even when an EU asset was available.

Adds a shared name->provider-shortcode map and threads the rom through
the IGDB and SS lookup APIs so the rom-aware locale/region selection
can run for both providers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 09:06:11 -04:00
Georges-Antoine Assi
8999b66574 Preserve local LaunchBox data on UPDATE scans and video extensions
UPDATE scans with a known launchbox_id were calling get_rom_by_id(),
which only returns remote data and bypassed get_rom()'s local-first
merge — so local-only fields like Notes were getting clobbered and
local media matching fidelity dropped. get_rom_by_id() now optionally
takes fs_name/platform_slug and merges the local entry when its
DatabaseID matches the requested id.

Also fixes populate_rom_specific_paths writing every video as
video.mp4 regardless of source extension; since store_media_file is a
byte copy, .mkv/.webm contents would be served as .mp4 and break MIME
sniffing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:32:34 -04:00
Georges-Antoine Assi
d8ef6f0c05 Merge branch 'master' into local-lb-fix 2026-05-09 13:20:31 -04:00
Georges-Antoine Assi
547c64c4f5 update hltb api 2026-05-09 12:56:01 -04:00
Georges-Antoine Assi
e3aaa106a2 perf(backend): reuse libmagic instance for image upload validation
magic.Magic(mime=True) loads the magic database from disk on construction;
instantiating it per request was adding pointless overhead to every avatar
and artwork upload. Share a module-level instance guarded by a lock (the
underlying magic_t handle is not thread-safe), and surface MagicException
as a 400 so a sniffing failure fails closed instead of bubbling a 500.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 10:14:38 -04:00
Georges-Antoine Assi
53f14f5710 fix(backend): validate uploaded images with libmagic before storing
Avatar, ROM artwork, and collection artwork uploads now sniff the file
header with libmagic and reject anything that isn't PNG/JPEG/WebP/GIF,
saving the file with an extension derived from the detected MIME rather
than the user-supplied filename. Pairs with the raw asset endpoint,
which decides inline vs attachment from the on-disk extension.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:18:02 -04:00