Commit Graph

3687 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
bb2b99099b fix(sync): isolate SSH handler init errors to per-device failure
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:12:10 -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
d9040b29cf fix(screenscraper): re-add user credentials in rom update path + tests
The rom update endpoint downloads SS media via store_media_file without
re-attaching the user credentials that were stripped before storage, so
edit/update flows fall back to the anonymous quota. Wrap the URL with
add_ss_auth_to_url at the call site, matching the existing scan path.

Add unit tests covering the new URL helpers and edge cases:

- test_base_handler: strip/restore sensitive query params, including
  case-insensitive key matching, no-duplicate restoration, special-char
  encoding, blank values, and URL-component preservation.
- test_ss_handler: add_ss_auth_to_url honors empty user/password,
  doesn't duplicate pre-existing creds, handles the storage-shaped
  stripped URL, and round-trips with extract_media_from_ss_game so the
  stored URL never carries user creds while the download URL uses the
  current runtime creds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:50:23 -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
715ec658bd changes from bot review 2026-05-23 07:37:23 -04:00
Georges-Antoine Assi
4724f4538a add to watcher 2026-05-22 22:35:30 -04: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
c73899a884 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-22 21:13:22 -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
745d8b959c fix test 2026-05-21 18:25:46 -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
f4512cb968 run fmt 2026-05-21 17:59:44 -04:00
Georges-Antoine Assi
d1958f2aae run fmt 2026-05-21 17:19:12 -04:00
Georges-Antoine Assi
1be2ca2b3c soimplify 2026-05-21 17:17:30 -04:00
Georges-Antoine Assi
600adb2c33 drop unused tests 2026-05-21 17:14:32 -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