Commit Graph

9706 Commits

Author SHA1 Message Date
Georges-Antoine Assi
69a7a13603 Merge pull request #3498 from rommapp/hasheous-lookup-all-hashes
Send all top-level file hashes to Hasheous lookup
2026-06-09 08:08:36 -04:00
Georges-Antoine Assi
08e8821b4b Fix mypy types in Hasheous _request and lookup_rom
Annotate request_kwargs as dict[str, Any] to accept the list json payload,
and file_hashes as dict[str, str | None] so the chd_sha1_hash branch and the
md5/sha1/crc branch unify cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 07:54:33 -04:00
Georges-Antoine Assi
650ab6925c Send all top-level file hashes to Hasheous lookup
The Hasheous ByHash endpoint now accepts an array of hash objects rather
than a single one. Send the hashes of every top-level file (using
chd_sha1_hash exclusively for files that have one) to improve lookup
accuracy, instead of picking only the largest file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 07:43:44 -04:00
Georges-Antoine Assi
f4960386e5 Merge pull request #3495 from rommapp/copilot/fix-smart-collection-crash
Fix smart collection status filter normalization for multi-value legacy payloads
4.9.0-beta.2
2026-06-08 12:01:28 -04:00
Georges-Antoine Assi
8366e288af run fmt 2026-06-08 11:53:42 -04:00
Georges-Antoine Assi
3f26398093 Merge pull request #3494 from rommapp/copilot/fix-safari-bezel-asset-error
Handle missing console bezel assets without rendering Safari broken-image overlay
2026-06-08 11:52:34 -04:00
Georges-Antoine Assi
3df3a8c712 Merge pull request #3490 from tmgast/feature/roms-list-include-expansions
Add opt-in files/siblings expansion to GET /api/roms
2026-06-08 11:31:41 -04:00
Georges-Antoine Assi
f077484b55 fix tests 2026-06-08 11:22:14 -04:00
Georges-Antoine Assi
cd101758fd cleanup for simplicity 2026-06-08 11:13:15 -04:00
Georges-Antoine Assi
036cf108f4 sinmplify siblings 2026-06-08 10:25:27 -04:00
copilot-swe-agent[bot]
7ab4052f93 Fix legacy smart collection status list normalization
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-06-08 12:25:56 +00:00
copilot-swe-agent[bot]
a7751c55cd fix(console): hide bezel overlay when bezel asset fails to load
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-06-08 12:17:15 +00:00
copilot-swe-agent[bot]
ed700c0075 Initial plan 2026-06-08 12:15:31 +00:00
copilot-swe-agent[bot]
0ff47ca5c2 Initial plan 2026-06-08 12:12:04 +00:00
nendo
cfdeab589a Derive sibling_ids from expanded siblings 2026-06-08 11:26:15 +09:00
nendo
f722d9234f Remove comment on files field 2026-06-08 10:57:54 +09:00
Georges-Antoine Assi
31512136a5 Merge pull request #3485 from rommapp/claude/fervent-bohr-4Db3f
Add rate limiting to metadata service API requests
2026-06-07 16:03:39 -04:00
Georges-Antoine Assi
5a5ae26590 changes from bot review 2026-06-07 15:16:40 -04:00
Georges-Antoine Assi
6acea1339f cahnges from bot review 2026-06-07 13:54:01 -04:00
Georges-Antoine Assi
41fd1eb6f1 wrap debugpy in DEV_MODE 2026-06-07 13:03:23 -04:00
Georges-Antoine Assi
e1bb3901b4 add debuggability 2026-06-07 09:16:50 -04:00
Georges-Antoine Assi
329f132389 remove comments 2026-06-07 08:34:34 -04:00
Georges-Antoine Assi
ab9b7bd775 changes from self review 2026-06-07 08:29:49 -04:00
Claude
105bca7e68 Add IGDBService rate-limiter unit test
The IGDB service acquires a rate-limiter slot before each request like the
other metadata services, but unlike them had no direct unit test asserting it
(IGDB is otherwise exercised via cassette-backed handler tests). Add a focused
test so the limiter call can't be silently removed or moved after the request.

https://claude.ai/code/session_01133QQuWvq8Zm25DZMP9PVr
2026-06-07 12:16:02 +00:00
nendo
37f0feab8c Add opt-in files/siblings expansion to GET /api/roms 2026-06-07 16:12:21 +09:00
Zurdi
bb82cf470a Merge pull request #3489 from rommapp/copilot/fix-auth-header-handling
Handle malformed Authorization headers in HybridAuthBackend without 500s
2026-06-07 00:36:24 +02:00
copilot-swe-agent[bot]
a2775ca2b8 fix: handle malformed authorization header in hybrid auth backend
Co-authored-by: zurdi15 <34356590+zurdi15@users.noreply.github.com>
2026-06-06 22:22:41 +00:00
copilot-swe-agent[bot]
27725c26b3 Initial plan 2026-06-06 22:14:01 +00:00
Claude
cd41422660 Use a concurrency limiter for ScreenScraper, honoring account threads
ScreenScraper enforces a per-account *thread* (concurrency) cap rather than
a request rate. Requests can take several seconds, so spacing out request
starts at 1/s could still leave multiple requests overlapping in flight,
exceeding the cap and getting rejected with ScreenScraper's custom HTTP codes.

- Add ConcurrencyLimiter: a runtime-resizable, loop-agnostic limiter that
  bounds simultaneous in-flight operations (held for the whole request via
  async context manager), instead of spacing request starts.
- Switch the ScreenScraper service from the req/s RateLimiter to a module-level
  ConcurrencyLimiter defaulting to a single thread.
- Recognize contributor/donor accounts: parse `ssuser.maxthreads` from each
  response and raise the concurrency allowance to match, so supporters scrape
  with their full thread count instead of the conservative default.

Adds unit tests for the limiter (blocking, wake-on-release, runtime resize)
and for the ScreenScraper slot-holding and thread-allowance updates.

https://claude.ai/code/session_01133QQuWvq8Zm25DZMP9PVr
2026-06-06 16:02:13 +00:00
Claude
8cc79f9e5c Add pre-emptive rate limiting to metadata API services
Wire the existing RateLimiter into the IGDB, ScreenScraper, MobyGames and
RetroAchievements services so requests are spaced under each provider's
documented req/s cap, instead of only reacting to HTTP 429 after the fact.

- IGDB: 4 req/s (documented hard limit)
- MobyGames: 1 req/s (free-tier burst cap)
- ScreenScraper: 1 req/s (free-tier throttle)
- RetroAchievements: 4 req/s (conservative; no published hard limit)

A slot is acquired before both the initial request and the timeout/429
retry. The reactive 2s 429 backoff is kept as a fallback. Tests neutralize
the shared limiters via an autouse fixture and assert acquire() is awaited.

https://claude.ai/code/session_01133QQuWvq8Zm25DZMP9PVr
2026-06-06 14:34:56 +00:00
Georges-Antoine Assi
56f65bb266 Merge pull request #3484 from rommapp/claude/busy-keller-gd2Ue
Fix Docker volume mounts to enable hardlink optimization
2026-06-06 10:31:39 -04:00
Georges-Antoine Assi
21f60b64aa add smol comment 2026-06-06 10:28:02 -04:00
Georges-Antoine Assi
a69f09b7f8 cleanup 2026-06-06 10:24:08 -04:00
Claude
6d533e0a25 fix(docker): declare /romm as single volume to enable asset hardlinks
PR #3388 added hardlink-based asset import/export (os.link with a
shutil.copy2 fallback) to avoid duplicating disk space. The Dockerfile
VOLUME instruction listed each /romm subdirectory (resources, library,
assets, config, sync) separately, which makes Docker create an
independent mount point for each one — even when the user bind-mounts a
single parent at /romm. Each mount point is its own st_dev, so every
cross-directory os.link() failed with EXDEV and silently fell back to a
full copy, defeating the optimization.

Declare the parent /romm directory instead so all subdirectories share a
single filesystem and hardlinks can succeed when paths reside on the same
underlying host filesystem.
2026-06-06 14:20:29 +00:00
Georges-Antoine Assi
84d4bf1235 Merge pull request #3482 from DevYukine/feat/playmatch-rate-limit
feat(playmatch): add ratelimiting
2026-06-06 10:10:22 -04:00
Georges-Antoine Assi
ec172dfeb1 use const 2026-06-06 09:58:17 -04:00
DevYukine
8006e4391d feat(playmatch): pre-emptive 4 req/s rate limiting with best-effort lookups 2026-06-06 04:16:21 +02:00
Georges-Antoine Assi
031fb57947 Merge pull request #3479 from tmgast/fix/save-device-attribution
Expose per-device save sync attribution and origin device
2026-06-05 19:37:47 -04:00
Georges-Antoine Assi
7e7368f3c2 Merge pull request #3480 from rommapp/fix/unauthenticated-asset-exposure
fix: stop serving private user assets via unauthenticated nginx static route
2026-06-05 19:20:44 -04:00
Georges-Antoine Assi
619e03ab32 fix: stop serving private user assets via unauthenticated nginx static route
The default Docker image symlinked /romm/assets into the nginx static web
root (/assets/romm/assets), where it was served by an unauthenticated
`location /assets { try_files ... }` block. /romm/assets holds private user
data (save files, save states, screenshots, avatars) that is meant to be
accessible only through the authenticated /api/raw/assets/{path} route
(Scope.ASSETS_READ). The static symlink bypassed that protection, letting any
unauthenticated caller read another user's files given a (guessable) path.
Avatar URLs leaked the hex user ID through the same static route, making path
construction straightforward.

Fix:
- Drop the /romm/assets symlink from the Docker image build and both
  entrypoint scripts; only /romm/resources (public cover art, screenshots,
  manuals) remains statically served.
- Point the frontend avatar URLs at the authenticated /api/raw/assets/ route
  instead of /assets/romm/assets/. Browser <img> loads authenticate via the
  existing session cookie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 17:34:30 -04:00
nendo
842bb29718 add device_id tiebreaker to device_syncs ordering 2026-06-05 20:43:14 +09:00
nendo
96534add05 address CI/CD failures 2026-06-05 20:30:14 +09:00
nendo
287c487308 feat(saves): expose per-device sync attribution and origin device
saves responses now include one device_syncs entry per device that has
synced a save, not just the caller's, so clients can tell which devices
hold a save. is_current is computed per entry and the caller's own entry
is ordered first for backward compatibility.

add a saves.origin_device_id column (migration 0081) recording the
device that created a save, set on initial upload only, surfaced as
origin_device_id on the save schema.
2026-06-05 20:25:01 +09:00
Georges-Antoine Assi
064a65698c add non-global IPs as forbidden 4.9.0-beta.1 2026-06-03 16:21:27 -04:00
Georges-Antoine Assi
96efc36d52 Merge pull request #3475 from Spinnich/fix/ss-jeuinfos-romnom-unhashed
fix(screenscraper): utilize ss.fr jeuinfos.php endpoint for non-hashable platforms
2026-06-03 16:07:25 -04:00
Georges-Antoine Assi
5cf67cd87c Merge pull request #3473 from Spinnich/fix/rom-content-404-on-stale-file-ids
fix(roms): return 404 when content file_ids match no files
2026-06-03 15:52:28 -04:00
Georges-Antoine Assi
20bae48ea9 add ot HEAD 2026-06-03 15:41:55 -04:00
Georges-Antoine Assi
fd78c7927a Merge pull request #3476 from rommapp/copilot/fix-network-error-emulatorjs
Invalidate EmulatorJS ROM cache when a ROM filename changes
2026-06-03 15:40:27 -04:00
Georges-Antoine Assi
1a1effd315 Merge pull request #3472 from Spinnich/test/update-rom-region-tag-reparse
test(roms): cover region-tag re-parse on rename (#3471)
2026-06-03 15:15:36 -04:00
Georges-Antoine Assi
ceaab1875b Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-03 15:08:51 -04:00