105 Commits

Author SHA1 Message Date
Georges-Antoine Assi
c4431e0ae4
cleanup 2026-04-30 15:22:22 -04:00
Georges-Antoine Assi
962a9bfa7e
one more 2026-04-30 14:39:52 -04:00
Georges-Antoine Assi
fc8d69dc0c
update tests 2026-04-30 14:18:49 -04:00
Georges-Antoine Assi
0e7359132b
test: update fs handler tests for STRUCTURE_PATH_A/B refactor
Switch the get_platform_fs_structure, get_firmware_fs_structure,
get_platforms_directory and get_roms_fs_structure tests from mocking
os.path.exists to mocking glob.glob, matching the new STRUCTURE_PATH_B
detection logic. Rename the existing high_priority/normal_structure
variants to structure_a/structure_b for clarity, and fix
test_platform_specific_behavior so its monkeypatch wraps the calls
instead of being applied after them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 14:00:53 -04:00
Georges-Antoine Assi
b18edb1528
fix trunk issues 2026-04-16 11:15:58 -04:00
copilot-swe-agent[bot]
bf246f842f
fix: add cus region to default ScreenScraper fallback regions
Games where only custom (cus) region artwork exists were not fetched
unless users explicitly added 'cus' to their region priority config.
Adding 'cus' to the default fallback list ensures custom artwork is
always considered as a fallback when no other regional artwork exists.

Agent-Logs-Url: https://github.com/rommapp/romm/sessions/75c3e455-f7dd-4bd6-bec7-0460987e40a0

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-04-16 14:28:51 +00:00
Georges-Antoine Assi
154165fadf
final fixes 2026-04-12 19:26:34 -04:00
Georges-Antoine Assi
d45afb5dde
more fixes 2026-04-12 18:32:15 -04:00
Georges-Antoine Assi
1b5943bd93
feat: fetch libretro Named_Snaps/Titles/Logos gated by SCAN_MEDIA
get_rom now also fetches Named_Snaps, Named_Titles, and Named_Logos
when the matching MetadataMediaType (SCREENSHOT, TITLE_SCREEN, LOGO)
is in SCAN_MEDIA. Box art is still fetched unconditionally — it drives
url_cover and libretro_id. Matching extras are appended to
url_screenshots so the scan_handler artwork priority loop picks them
up without further changes. All enabled listings are fetched
concurrently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:01:37 -04:00
Georges-Antoine Assi
62e540d60e
changes from bot review 2026-04-12 15:43:14 -04:00
Georges-Antoine Assi
f94c1491e5
fix: respect SCAN_ARTWORK_PRIORITY for SGDB and align libretro search with SGDB pattern
SGDB's url_cover used to clobber whatever the artwork priority loop
picked, which meant user-set priorities (e.g. libretro > sgdb) and
manually uploaded covers were silently overridden. SGDB now only
replaces the current url_cover when it outranks every other source
that produced one under SCAN_ARTWORK_PRIORITY, and never over a
manual cover preserved on UPDATE/UNMATCHED scans. Default artwork
priority gains sgdb at the top so existing "SGDB wins" behavior is
preserved for default configs.

On the /search/roms endpoint, libretro is now an enrichment source
alongside SGDB instead of a primary match source: it decorates
entries resolved by IGDB/Moby/SS/Flashpoint/Launchbox with
libretro_id and libretro_url_cover, mirroring how SGDB works.
get_matched_roms_by_name is removed from the libretro handler since
nothing else calls it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:52:44 -04:00
Georges-Antoine Assi
6df31e2cc0
Merge branch 'master' into libretro-handler 2026-04-12 10:14:26 -04:00
Georges-Antoine Assi
f9f3dfd927
changes from bot review 2026-04-12 09:50:54 -04:00
Georges-Antoine Assi
abc69c790f
fix scanning 2026-04-12 09:35:34 -04:00
Georges-Antoine Assi
de9efb3da8
refactor: simplify mark_missing_roms with a single flips dict
Collapse the two parallel id lists and their mirrored chunked-update
loops into a `flips: dict[bool, list[int]]` keyed by desired state, and
drop unused rom assignments in the related tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:13:33 -04:00
Georges-Antoine Assi
522df9d31a
feat: add libretro thumbnails as an artwork source
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>
2026-04-11 22:57:20 -04:00
Georges-Antoine Assi
3991e1b6ed
fix: scan stalls on platforms with 10k+ already-scanned ROMs
The scan was spending excessive time on large platforms even when all ROMs
were already scanned. Root causes: per-ROM UPDATE queries for skipped ROMs
(10k individual writes), missing composite index on (platform_id, fs_name)
causing full table scans, NOT IN clauses with 10k+ values in
mark_missing_roms(), and redundant filesystem reads.

Changes:
- Add bulk_mark_present() for batch-updating skipped ROMs in one query
- Move skip detection from _identify_rom to the batch loop so skipped ROMs
  never enter the async scan pipeline, and report progress for them
- Add composite index idx_roms_platform_id_fs_name via migration 0077
- Rewrite mark_missing_roms() with flip-based approach: mark all missing,
  then un-mark present ones in chunks of 1000
- Cache filesystem reads in scan_platforms() to avoid double directory
  traversal (precounting + scanning)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:20:40 -04:00
Georges-Antoine Assi
ccf5f656b7
Add if_not_exists/if_exists guards to all alembic add_column/drop_column ops 2026-04-09 22:50:07 -04:00
Georges-Antoine Assi
f227a3145d
changes from bot review 2026-04-07 22:32:40 -04:00
Georges-Antoine Assi
f2619ac0d1
Merge branch 'master' into pegasus-metadata-export 2026-04-06 11:06:08 -04:00
Georges-Antoine Assi
f2e8e337b2
Merge branch 'master' into save-sync 2026-04-05 21:47:53 -04:00
Georges-Antoine Assi
e0214f100d
more bot cleanup 2026-04-05 19:15:33 -04:00
Georges-Antoine Assi
f107dc2752
changes from bot rview 2026-03-22 17:17:14 -04:00
Georges-Antoine Assi
4c97eddfc3
fix trunk check 2026-03-22 16:30:14 -04:00
Georges-Antoine Assi
d13e7b6783
fix tests again 2026-03-22 00:03:29 -04:00
nendo
c59ea7790c test: add coverage for sync session handler, sync watcher, device masking, and auth utils
- test_sync_sessions_handler: increment_operations_completed (atomic
  counter, no-op on missing), NoResultFound on update/complete/fail
  with nonexistent session
- test_sync_watcher: _extract_device_and_platform path parsing (valid,
  non-incoming, too few parts, nested, outside base), _ensure_conflicts_dir
  creation and idempotency, process_sync_changes empty/disabled
- test_sync (endpoints): negotiate with untracked saves (no_op),
  server saves not mentioned by client (download), deleted-by-client
  detection (skip), complete on FAILED/CANCELLED session (400),
  trigger_push_pull passes session_id in enqueue kwargs
- test_device (endpoints): sync_config SSH credential masking
  (ssh_password/ssh_key_path -> "********"), null config passthrough,
  config without sensitive fields
- test_utils_auth: _get_device_name UA parsing (browser+OS, browser
  only, OS only, neither), create_or_find_web_device (creates new,
  returns existing on fingerprint match, updates last_seen)
2026-03-16 11:19:30 +09:00
nendo
55638d15dc fix: address bugs, security issues, and convention violations in save-sync
- Fix broken path construction in FSSyncHandler: build_* methods now
  return relative paths; sync_watcher uses paths relative to sync base
  instead of CWD (was completely non-functional in production)
- Fix SSH connection leak in push-pull task: conn.close() now in finally
- Add log.warning for disabled SSH host key verification
- Fix race condition in session operation counter: use atomic SQL
  increment instead of read-then-write
- Extract _increment_session_counter helper, add exc_info to warnings
- Replace legacy session.query() with select() in sync_sessions_handler
- Fix orphaned session: trigger_push_pull now passes session_id to job
- Fix wasteful SSH download when no matched_save exists
- Fix BaseModel import collision in sync.py (pydantic -> project base)
- Fix ORM mutation in UserSchema.from_orm_with_request: set field on
  schema instance instead of mutating live ORM object
- Mask ssh_password and ssh_key_path in DeviceSchema API response
- Fix migration PostgreSQL compatibility: condition ON UPDATE clause
  on MySQL, drop enum in downgrade
- Rename copy-paste artifact rom_user_status_enum
2026-03-16 10:56:43 +09:00
Georges-Antoine Assi
55ca39cacb
fix deprecations in pydantic 2026-03-15 09:34:48 -04:00
Georges-Antoine Assi
b3fbbf59fb
add tests 2026-03-14 23:35:04 -04:00
HydroSulphide
6a1c1597ce Fix: directly import constants from config and preventing silent fallback on wrong user input for env variable 2026-03-12 20:18:48 +01:00
HydroSulphide
48091225c7 Fix: imports in all test files with renamed constants 2026-03-12 20:04:19 +01:00
Georges-Antoine Assi
f0e5abadc9
fix tests again 2026-03-10 09:23:12 -04:00
HydroSulphide
b9ea937373
Merge branch 'master' into fix-oauth-token-expiry-and-refresh-rotation 2026-03-10 08:51:44 +01:00
HydroSulphide
02336974a6 Implemented greptile suggestions 2026-03-10 08:04:07 +01:00
HydroSulphide
8758cb31b7 Tried to fix everything the bot complained about and the failed pytests.
Three tests were also implemented to check initial implementation that now invalidates expired access and refresh tokens and also rotating refresh tokens.

Since I introduced wrapper functions for create_oauth_token to distinguish between access and refresh token there is no need to set the token type in the data dict, since the type is now enforced in the wrapper functions create_access_token and create_refresh_token.

By convention I renamed create_oauth_token to _create_oauth_token as it is considered a private helper function now.
2026-03-10 07:22:02 +01:00
copilot-swe-agent[bot]
2a7c86e304 Fix OIDC login downgrading existing user roles when no claims provided
Co-authored-by: pacnpal <183241239+pacnpal@users.noreply.github.com>
2026-03-09 18:26:49 +00:00
copilot-swe-agent[bot]
ae73da7c27 Fix 500 error from empty fs_name_no_tags causing mass sibling matching and incorrect ROM grouping
- Add migration 0071 to fix sibling_roms view: add guard against empty string matching for fs_name_no_tags
- Fix group_by_meta_id in filter_roms: use func.nullif to treat empty fs_name_no_tags as NULL in grouping key
- Add group_by_meta_id support to get_roms_scalar
- Add tests for sibling matching behavior with empty/non-empty fs_name_no_tags

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-03-08 23:17:51 +00:00
Georges-Antoine Assi
29a09d3787
fix tests 2026-03-08 10:52:56 -04:00
Georges-Antoine Assi
75d38cc937
add tests 2026-03-08 10:27:01 -04:00
Georges-Antoine Assi
aa4abe6b7c
end me 2026-03-07 23:43:58 -05:00
Georges-Antoine Assi
2feb43571b
my brain is bumb 2026-03-07 23:32:04 -05:00
Georges-Antoine Assi
606799e19c
my own cleanup 2026-03-07 21:34:45 -05:00
Georges-Antoine Assi
61aface9ae
cleanup 2026-03-07 19:04:14 -05:00
Georges-Antoine Assi
92ef2cf676
some fixes 2026-03-07 18:37:29 -05:00
Georges-Antoine Assi
5f2c1a6b3b
fix tests 2026-03-07 18:24:31 -05:00
Georges-Antoine Assi
b21aa662b5
add test file 2026-03-07 16:24:22 -05:00
Georges-Antoine Assi
661a5504d7
find a couple more uses 2026-02-09 17:26:21 -05:00
Georges-Antoine Assi
37436fddb7
changes from self review 2026-02-06 10:31:08 -05:00
Georges-Antoine Assi
e36d7650e7
[ROMM-2989] Split search term by | 2026-02-06 10:20:14 -05:00
nendo
220d7531e7 refactor(saves): replace order_by_updated_at_desc with flexible order_by
Add order_by and order_dir parameters to get_saves() for flexible
sorting. Supports "updated_at" and "created_at" fields with "asc" or
"desc" direction (default: desc). Enables ascending order for pruning
scenarios.
2026-02-03 20:06:09 +09:00