Commit Graph

1610 Commits

Author SHA1 Message Date
Georges-Antoine Assi
b9b82c751b more cleanup 2026-05-25 11:07:03 -04:00
Georges-Antoine Assi
9a87348c22 cleanup 2026-05-25 11:02:35 -04:00
Claude
95b1a99f2a perf(roms): avoid hydrating full Rom rows for siblings on list endpoint
The paginated ROM list eager-loaded sibling_roms via selectinload, which
hydrated full Rom ORM instances (including heavy JSON metadata columns)
for every sibling even though only an existence/count check was needed
on the frontend. On large collections this dominated request latency.

Split sibling handling by response shape:
- SimpleRomSchema (list): siblings is now list[int]; populated per page
  by a single SELECT against the sibling_roms view projecting only
  (rom_id, sibling_rom_id) — no Rom row hydration.
- DetailedRomSchema (detail): keeps full SiblingRomSchema objects, with
  load_only on (id, name, fs_name_no_tags, fs_name_no_ext) so sibling
  rows stop dragging in JSON metadata.

Frontend usage already only consumes siblings.length on list views; the
detail-page VersionSwitcher continues to receive the richer schema.
2026-05-24 23:17:34 +00:00
Georges-Antoine Assi
63644d0c6f Merge pull request #3426 from rommapp/claude/loving-darwin-pveIr
Defer optional handler initialization with lazy factories
2026-05-24 16:18:24 -04:00
Georges-Antoine Assi
0eec8b0e47 Merge pull request #3424 from rommapp/copilot/fix-csrf-token-issue
Refresh CSRF cookie on OIDC session authentication changes
2026-05-24 15:57:30 -04:00
Georges-Antoine Assi
be476cb7dc Only set CSRF cookie on http.response.start
ASGI spec only allows headers on the http.response.start message;
appending Set-Cookie to body messages is out-of-spec and may break on
some servers. Early-return for non-start messages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:46:50 -04:00
Georges-Antoine Assi
8af556ee46 run fmt 2026-05-24 14:07:45 -04:00
Georges-Antoine Assi
acc1e630b7 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-24 14:05:58 -04:00
Georges-Antoine Assi
4d8c2ef54b Merge branch 'master' into copilot/fix-folder-tag-import-issue 2026-05-24 13:33:36 -04:00
Georges-Antoine Assi
e7bde8a190 simplify 2026-05-24 13:13:11 -04:00
Georges-Antoine Assi
5fdb69d53c fixes 2026-05-24 13:09:07 -04:00
Claude
26bdc11e13 refactor(filesystem): lazy-init launchbox + sync handlers, drop tolerate_missing_base
Apply the same lazy-factory pattern to FSLaunchboxHandler and FSSyncHandler
that ssh_sync_handler now uses. With both opt-in features deferred to
first-use, the tolerate_missing_base escape hatch on FSHandler is no longer
needed — every handler now fails loudly on mkdir failure, which is the
right behavior for the always-on core paths (assets, library, resources).

Touched call sites:
  - resources_handler._resolve_local_file_uri (launchbox)
  - sync_watcher.py, endpoints/device.py, tasks/manual/sync_folder_scan.py
    (fs_sync)

Net effect:
  - Default installs never poke /romm/launchbox or /romm/sync at startup.
  - Misconfigured opt-in users get a clear, actionable PermissionError at
    the call site instead of a silent warning followed by mystery failures.
  - tolerate_missing_base, its tests, and one stale log import are gone.
2026-05-24 14:59:03 +00:00
Claude
1890958ff2 refactor(sync): make SSH sync handler lazy-initialized
The module-level SSHSyncHandler() singleton ran filesystem side effects
(mkdir on SYNC_SSH_KEYS_PATH) at import time, which meant even default
installs with push-pull sync disabled would touch /romm/sync — and the
previous tolerate-and-warn fallback could leave users wondering why
sync silently does nothing.

Replace the eager singleton with a functools.cache'd factory. The
handler is now constructed on first use, so:

  - Default-install users (ENABLE_SYNC_PUSH_PULL=false, no manual sync
    triggered) never touch /romm/sync.
  - Users opting in get a clear, actionable RuntimeError pointing at
    the unwritable path and the env var to override, at the call site
    rather than buried in a startup stack trace.

Also document in env.template that enabling either sync mode requires
a writable volume at $ROMM_BASE_PATH/sync.
2026-05-24 14:49:53 +00:00
copilot-swe-agent[bot]
f94206aa53 Refresh CSRF cookie when auth user changes
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-24 14:46:31 +00:00
Claude
358e91d33c fix(sync): tolerate unwritable SSH keys directory at startup
The SSH sync handler is instantiated at module import time, so any
PermissionError on mkdir would crash the entire app rather than just
disabling the push-pull sync feature. This affected users whose /romm
mount didn't include a writable sync subdirectory (common on Unraid
and similar setups that mount specific subpaths).

Mirror the FSHandler pattern: log a warning and continue. Keys are
expected to be pre-mounted per the module docstring, and
_resolve_key_path already handles a missing directory gracefully.

Fixes #3419
2026-05-24 14:36:14 +00:00
copilot-swe-agent[bot]
03d869e859 Fix gamelist parsing with alternativeEmulator fallback
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-24 14:15:24 +00:00
copilot-swe-agent[bot]
9611ebedb4 Support folder tags in gamelist metadata import
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-24 14:11:01 +00:00
Georges-Antoine Assi
22666631e9 Merge branch 'master' into fix/screenscraper-skip-name-search-after-notgame 2026-05-23 20:54:19 -04:00
Georges-Antoine Assi
599ccb5f14 refactor(screenscraper): return notgame flag as tuple from lookup_rom
Instead of smuggling an internal control flag through the SSRom dict,
lookup_rom now returns (SSRom, is_not_game: bool). scan_handler unpacks
the tuple and short-circuits the name-search fallback when either an
ss_id matched or the hash lookup flagged the entry as notgame.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:52:43 -04:00
Georges-Antoine Assi
5c980d82cc fix(screenscraper): wire notgame flag through to scan_handler
The previous commit added a notgame skip-name-search check in scan_handler
but used a different key ("notgame") than what lookup_rom returned
("not_game"), so the fallback was never actually skipped. Align both on
SSRom.not_game, pop the internal flag before returning the SSRom to the
rest of the scan pipeline, and rename the helper to _is_not_game for
consistency with the field name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:22:00 -04:00
Georges-Antoine Assi
1e66436ca1 Merge pull request #3414 from Spinnich/fix/screenscraper-add-user-credentials-media-endpoints
fix(screenscraper): re-add user credentials to media file downloads
2026-05-23 19:57:08 -04:00
Georges-Antoine Assi
ca6ecff4a0 cleanup 2026-05-23 19:07:43 -04:00
Georges-Antoine Assi
dce7101b4f Merge pull request #3407 from rommapp/playmatch-metadata-souce
Add playmatch as explicit metadata source
2026-05-23 13:20:56 -04:00
Spinnich
2ae6e1c07c fix(screenscraper): skip name search after notgame hash lookup
When jeuInfos.php returned a notgame entry (BIOS files, ZZZ hacks, etc.),
lookup_rom() had no notgame check, leading to two bugs:
- notgame entries with a real ID were stored as valid SS matches
- notgame entries with a falsy ID fell through to a jeuRecherche.php name
  search that always returned nothing (pointless quota usage)

Adds _is_notgame() and NOTGAME_NAME_PREFIX, returns SSRom(notgame=True)
from lookup_rom() on a notgame hit, and guards the get_rom() fallback in
scan_handler so the name search is skipped entirely. Also adds the missing
notgame filter to _search_rom() so ZZZ entries can't match by name either.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 17:01:41 +00:00
Spinnich
aec1c4ed33 fix(screenscraper): re-add user credentials to media file downloads
SS media URLs are stripped of ssid/sspassword before DB storage (correct),
but downloads were issued against the credential-less stored URLs, causing
them to count against the anonymous IP quota instead of the user's account.

Adds restore_sensitive_query_params() as the principled complement to
strip_sensitive_query_params(), and add_ss_auth_to_url() in ss_handler
which re-attaches credentials at download time without storing them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 15:27:43 +00:00
Georges-Antoine Assi
18ecc1f374 use intersection 2026-05-22 21:56:10 -04:00
Georges-Antoine Assi
aed926ac9e Add playmatch as explicit metadata source 2026-05-22 21:44:33 -04:00
Georges-Antoine Assi
da5675dca5 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-22 21:14:16 -04:00
Georges-Antoine Assi
a5ed1d95ea fix: wipe downloaded resources on COMPLETE rescan
A COMPLETE rescan never deleted previously downloaded asset files, and
the post-scan download steps skip work when a file already exists
(store_media_file) or when the source URL is unchanged (get_cover). This
meant covers, screenshots, manuals, and SS/gamelist/LaunchBox extended
media were reused even when a fresh fetch returned a different URL —
defeating the region-priority fix in #3396.

- scan socket: for a COMPLETE rescan of an existing ROM, remove the
  cover, manual, screenshots, and all extended media directories before
  re-fetching, so the download steps pull fresh files.
- scan_handler: reset url_cover/url_screenshots/url_manual and the
  matching path_* fields for COMPLETE rescans before the priority loops
  run, so stale DB values are nulled when no selected source supplies
  them (clearing for deselected sources falls out as a subset).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 17:32:02 -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