258 Commits

Author SHA1 Message Date
zurdi
d7a896b5da
fix: re-parse tags from filename when renaming a rom
Renaming a rom via PUT /roms/{id} only updated fs_name and its
derivatives, leaving regions/languages/tags/revision/version stale
against the new filename. Re-parse them whenever fs_name changes so
edits like "patapon (Fr En)" -> "Patapon (Fr, En)" are reflected in
the database.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:23:33 +00: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
Spinnich
14342b5726 fix(tests): use client.request(\"DELETE\") to send JSON body in tests
Starlette's TestClient (httpx-based) does not expose body kwargs on the
delete() convenience method; client.request(\"DELETE\", ..., json=...) is
the correct approach. Also switch datetime.utcnow() to
datetime.now(timezone.utc) to silence Python 3.13 deprecation warnings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 21:02:26 -04:00
Spinnich
9aab88ad8b fix(tests): fix remaining DELETE body and timestamp comparison issues
- Switch content= to data= for DELETE requests (Starlette TestClient is
  requests-based and does not accept content= keyword argument)
- Fix test_bumps_updated_at to record time before the API call and use >=
  comparison, avoiding false failures when MariaDB truncates DATETIME to
  whole seconds and creation/update land in the same second

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 20:53:57 -04:00
Spinnich
fae6d869f1 fix(tests): correct test failures in collection endpoint tests
- Replace client.delete(json=...) with content=json.dumps()+Content-Type header
  (Starlette TestClient does not forward json= on DELETE requests)
- Adjust duplicate-name test to expect HTTP 500 matching CollectionAlreadyExistsException
- Add description="" to collections created without it to satisfy Pydantic schema
- Strip tzinfo before comparing updated_at to avoid offset-naive/aware TypeError

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 20:43:12 -04:00
Spinnich
1c9f010918 Fix isort import ordering in test_collection.py 2026-04-14 20:33:45 -04:00
Spinnich
4cc0c868b7 Fix linting and formatting issues from trunk CI 2026-04-14 20:27:45 -04:00
Spinnich
2ecefa3d3f Fix race condition in collection and favorite rom membership updates
Replace full rom_ids list replacement with atomic POST/DELETE endpoints
that add or remove individual ROMs from a collection. This prevents
concurrent rapid clicks from overwriting each other (last-write-wins).

Also fix missing session.flush() in add_rom_user() and add collection
endpoint tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:08:53 -04: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
628d8d8bae
refactor: pass RAGamesPlatform dict into calculate_hash, normalize extension
Callers now pass the full platform dict and rom.fs_extension; the service
normalizes the extension (optional leading dot, case-insensitive) before
checking the compressed-archive skip set, so ROMs stored with bare
extensions like "zip" correctly hit the skip path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:05:44 -04:00
Georges-Antoine Assi
8f1b8f41d7
perf: skip RAHasher subprocess for archived disc-platform ROMs
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>
2026-04-12 17:18:14 -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
4928041593
manual cleanu 2026-04-12 11:04:12 -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
686c609b3a
Merge pull request #3155 from tmgast/feature/play-session-ingest
Add play session ingest for game time tracking
2026-04-11 11:23:02 -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
ae03b0b322
ingest playtime with sync sessions 2026-04-06 21:32:13 -04:00
Georges-Antoine Assi
e5cb29ae80
Merge branch 'master' into feature/play-session-ingest 2026-04-06 12:42:15 -04:00
Georges-Antoine Assi
0e7a75010b
fix tests 2026-04-06 12:34:49 -04:00
Georges-Antoine Assi
bc58425fc9
fix tests 2026-04-06 11:29:33 -04:00
Georges-Antoine Assi
2dc1678931
changes from bot review 2026-04-06 11:22:44 -04:00
Georges-Antoine Assi
f2619ac0d1
Merge branch 'master' into pegasus-metadata-export 2026-04-06 11:06:08 -04:00
Georges-Antoine Assi
21eee327b0
Merge branch 'master' into save-sync 2026-04-06 09:09:53 -04:00
Georges-Antoine Assi
af69630481
more self review 2026-04-05 23:17:57 -04:00
Georges-Antoine Assi
fafb804bc6
mega cleanup 2026-04-05 22:35:37 -04:00
Georges-Antoine Assi
a61ff81e22
Merge branch 'master' into gamelist-customize 2026-04-05 22:11:02 -04:00
Georges-Antoine Assi
f2e8e337b2
Merge branch 'master' into save-sync 2026-04-05 21:47:53 -04:00
Georges-Antoine Assi
6837070512
again 2026-04-05 20:15:06 -04:00
Georges-Antoine Assi
6c2c1db7b0
remove unused test 2026-04-05 20:06:18 -04:00
Georges-Antoine Assi
e0214f100d
more bot cleanup 2026-04-05 19:15:33 -04:00
Georges-Antoine Assi
ef35ecaea9
props rom updte endpoint 2026-04-04 14:16:00 -04:00
Georges-Antoine Assi
494af9e4c8
Merge pull request #3217 from rommapp/copilot/fix-get-api-tasks-status-error
Fix GET /api/tasks/status 500 on expired job TTL (NoSuchJobError)
2026-04-03 14:37:21 -04:00
Georges-Antoine Assi
dbb3b9e469
run trunk fmt 2026-04-03 14:23:45 -04:00
copilot-swe-agent[bot]
674061c1d3
fix: narrow OSError catch and clean up test mock
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/303f2c27-6b65-41a9-b201-c055142b1edb

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-04-03 17:31:14 +00:00
copilot-swe-agent[bot]
394799d7c3
fix: wrap empty parent dir cleanup in try-except and add test coverage for it
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/303f2c27-6b65-41a9-b201-c055142b1edb

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-04-03 17:28:50 +00:00
copilot-swe-agent[bot]
e540d7c1a2
fix: handle nested ROM directories in delete endpoint and reorder FS/DB operations
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/303f2c27-6b65-41a9-b201-c055142b1edb

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-04-03 17:26:22 +00:00
copilot-swe-agent[bot]
789f8d4e31
fix: handle NoSuchJobError in get_tasks_status when job TTL expires
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/bc0915c3-2d5f-4ac1-ab89-24942eeac825

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-04-03 17:22:58 +00:00
Georges-Antoine Assi
6abf60b0fe
last fixes 2026-04-03 11:49:32 -04:00
Georges-Antoine Assi
bae0d0c698
more changes from rview 2026-04-03 11:29:55 -04:00
Georges-Antoine Assi
ceddf2f9e9
changes from bot review 2026-04-03 11:24:02 -04:00