github rommapp/romm 5.5.0-alpha.1

pre-releaseone hour ago

Caution

Let the first start finish its migrations.
Two migrations alter the roms table and one reads every ROM to flag custom sort names, which can take a while on a large library. Don't restart the container while they run.

Warning

Add your RomM credentials to Tinfoil.
The Tinfoil feed at /api/feeds/tinfoil now requires authentication, like every other feed. If your Tinfoil shop entry has no username and password, add your RomM ones. Instances running with DISABLE_DOWNLOAD_ENDPOINT_AUTH=true are unaffected. #5344

Warning

List your library's articles under sorting.articles if it isn't in English.
Titles now sort without a leading "the", "a" or "an" only, so "Die Hard Arcade" files under D instead of H. A library in another language can list its own articles in config.yml. When the list changes, RomM re-sorts every game on the next start, and a sort name you typed on a game is always kept as written. #5429

sorting:
  articles:
    - der
    - die
    - das

Warning

Add a [host]:port line to known_hosts for push-pull devices on a port other than 22.
Push-pull sync now refuses any host the admin's known_hosts doesn't already trust, before opening a connection. A handheld listening on another port needs its own [host]:port entry; a bare host entry only covers port 22. #5460

Technical changes

🌎 ENVIRONMENT VARIABLES
variable default description
OIDC_AUTH_PARAMS - JSON object of extra OIDC authorization request parameters, such as {"prompt":"select_account"}. Parameters RomM manages are rejected at startup
SEVEN_ZIP_TIMEOUT 180 Now also bounds Python-side reads of zip, tar, gzip, bz2 and xz archives during hashing
STREAMING_BROKER_SECRET - Now only used for streaming containers that set no broker_secret in config.yml
📡 API CHANGES

Auth and users

Change Description
⚠️ PUT /api/users/{id} current password Changing your own username, password or email needs the new current_password form field: 400 when missing, 403 when wrong. Your own email is 403 when OIDC manages it (#5351)
UserSchema New has_password and email_managed_by_oidc (#5351)
PUT /api/users/{id} empty values email="" clears the email (#5472); ra_username="" unlinks RetroAchievements and resets ra_progression (#5475)
⚠️ Acting on other users PUT/DELETE /api/users/{id} and POST /api/users/{id}/ra/refresh on another user need users.write in the caller's scopes; a non-admin targeting an admin, or granting the admin role, gets 403 (#5346)
⚠️ OAuth token revocation Changing a password or username, or deleting a user, revokes that user's OAuth access and refresh tokens; rmm_ client tokens are unaffected (#5496)
⚠️ own_only permissions Rejected with 422 on entities without owners; GET /api/permissions/catalog adds ownable_entities (#5346)

Client tokens and devices

Change Description
⚠️ Client token scopes POST /api/client-tokens and the device approval flow cap scopes at the calling credential's; regenerate and pair return 403 unless the caller holds every stored scope; DELETE returns 403 for a token broader than the caller (#5346)
DELETE /api/client-tokens/{id} A client token can revoke itself without me.write; the route no longer declares a scope in OpenAPI (#5419)
DeviceAuthTokenResponse.id POST /api/auth/device/token returns the token's id (#5419)
⚠️ Device-bound tokens A token paired to a device gets 404 for any other device on the devices, sync, saves, play session and activity heartbeat routes, and 403 on POST /api/client-tokens; deleting a device deletes its tokens (#5460)

Visibility and validation

Change Description
⚠️ GET /api/feeds/tinfoil Requires roms.read, unless DISABLE_DOWNLOAD_ENDPOINT_AUTH is set (#5344)
⚠️ GET /api/stats Requires roms.read; totals leave out ROMs and assets hidden from the caller (#5496, #5498)
⚠️ ROM visibility Saves, states, screenshots, memory cards, virtual collections, feeds, recommendations, playlists, sync negotiation and /api/setup/library answer a hidden ROM or platform like a missing one (#5496, #5498)
POST /api/sync/sessions/{id}/complete play_sessions need roms.user.write and are capped at 100 entries (#5496)
POST /api/roms/upload/{id}/complete Returns 400 when the target platform became hidden or was deleted after /start (#5458)
Validation errors Empty slug/fs_slug in POST /api/config/system/platforms and /system/versions, a non-object smart collection filter_criteria, and a non-list rom_ids in PUT /api/collections/{id} return 422 (#5496)
Cover and manual URLs file:// and launchbox-file:// URLs are refused for collection covers and ROM covers or manuals unless sent back unchanged (#5496)

ROMs, saves and states

Change Description
GET /api/roms New with_provider_metadata (default true); false returns every provider *_metadata blob as null, keeping manual_metadata (#5228)
ROM schemas version New version field; revision and version are null instead of "" when the file name has none (#5255)
ROM schema name lists Provider {id, name} entries in genres, companies and other name lists are returned as plain names (#5249)
RomFileSchema.category Patch files are categorised as patch (#5538)
StateSchema.origin_device_id New field; POST /api/states and PUT /api/states/{id} take an optional device_id (#5531)

Platforms

Change Description
PlatformSchema.first_release_year New field, filled from IGDB during scans (#5433)
PlatformSchema counts rom_count and fs_size_bytes count only ROMs the caller can see (#5313)
Arcade platform slugs New mame, mame-advmame, fbneo, fba and board slugs; cps1, cps2, cps3, model1, system16, system32 and system-32 are retired into arcade (#5273)

Streaming

Change Description
Streaming admin routes Listing containers and sessions needs users.read; opening a desktop, force-releasing or driving another user's session needs users.write (#5346)
POST /api/streaming/sessions Optional disc_file_id picks the starting disc; 400 when it isn't one of the ROM's playlist discs (#5446)

Heartbeat, setup, tasks and config

Change Description
GET /api/heartbeat Adds FILESYSTEM.FS_PLATFORM_SLUGS (#5473), EMULATION.EJS_CORES and EMULATION.EJS_NIGHTLY_CORES (#5533), ROM_PATCHER.SUPPORTED_EXTENSIONS (#5538)
GET /api/setup/library Existing platforms add slug (#5473)
Tasks New manual task recompute_name_sort_keys (#5429)
config.yml New sorting.articles (#5429)

Highlights

Farewell console mode 🫡

The classic UI and console mode are gone, along with the /console/* routes, and anyone who had picked the classic UI in Settings now gets the current one. Tailwind CSS and Vuetify went with them. The page background and default text colour now come from RomM's theme tokens, so the background shade shifts slightly in both themes. #5309 #5315

Arcade platforms by emulator family

Arcade folders no longer all fold into one arcade platform. MAME, AdvanceMAME, FinalBurn Neo and FinalBurn Alpha sets get their own platforms (mame, mame-advmame, fbneo, fba), and so do boards that need an emulator of their own, such as naomi, atomiswave, triforce, lindbergh, daphne and teknoparrot. A new platform without an icon of its own gets the arcade cabinet with its name on the marquee. #5273

Minor changes

  • feat(frontend): add an Open in Steam action for Steam-matched games by @sdornan in #5358
  • feat: classify ROMs by release type (homebrew, hack, translation, ...) by @sdornan in #5363
  • feat(i18n): add Swedish locale by @yeager in #5231
  • feat(frontend): switch similar games between RomM and IGDB sources by @sdornan in #5382
  • feat: expose the parsed ROM version in the API and game overview by @bercedev in #5255
  • feat(auth): add Plex and Jellyfin OIDC provider icons by @gantoine in #5418
  • feat(ra): sync a player's achievements after they play an RA game by @sdornan in #5425
  • feat(oidc): add OIDC_AUTH_PARAMS for extra authorization request parameters by @gantoine in #5431
  • feat(platforms): facet filters and a group-by menu on the platforms index by @sdornan in #5434
  • feat(media): JPEG XL library images and cover uploads by @sdornan in #5438
  • feat(platforms): enrich discovery cards and preserve AVIF animations by @sdornan in #5433
  • feat(recommendations): show 10 similar games to match IGDB by @sdornan in #5497
  • feat(gallery): keep results on screen and animate the swap on search by @sdornan in #5500
  • feat(frontend): restyle mobile bottom nav as a glass tab bar by @sdornan in #5522
  • feat(frontend): bring the bottom nav closer to Slack's tab bar by @sdornan in #5541
  • feat(frontend): show compact mobile page titles after scrolling by @sdornan in #5553

Fixes

  • fix(frontend): expose RSelect as a combobox with an active descendant by @sdornan in #5318
  • fix(docker): bump nginx to 1.30.6 and drop pip from the runtime image by @gantoine in #5339
  • fix(tasks): give the recommendations rebuild a one-hour timeout by @sdornan in #5352
  • fix(logs): keep password reset links out of the log viewer buffer by @gantoine in #5343
  • fix(feeds): require authentication on the Tinfoil feed by @gantoine in #5344
  • fix(auth): bound new client tokens by the caller's scopes and stop delegates removing admins by @gantoine in #5346
  • fix(auth): require the current password to change your own username, password or email by @gantoine in #5351
  • fix(platforms): share provider entries across duplicate platform slugs by @sdornan in #5359
  • fix(notifications): start a pasted Apprise URL from defaults, not stale values by @enieuwy in #5217
  • fix(i18n): placeholder parity check, one locale list, memory card plurals by @gantoine in #5375
  • fix(scan): fall back to filename name when only libretro matches by @nkrebs13 in #5241
  • fix(v2): stop game videos from holding connections they no longer need by @enieuwy in #5236
  • fix(auth): point the OpenAPI token URL at /api/token by @andest01 in #5245
  • fix(docker): stop the init watchdog spawning duplicate gunicorns on slow starts by @EdwardSalter in #5250
  • fix(metadata): read names from {id, name} facet entries in recommendations and ROM responses by @mrjeremystookey in #5249
  • fix(streaming): let a container's broker_secret override STREAMING_BROKER_SECRET by @LoneAngelFayt in #5259
  • fix(migrations): add GAME to a romfilecategory enum made before 4.5.0 by @bercedev in #5269
  • fix(sigil): classify routine extraction failures by type by @alsd4git in #5304
  • fix(worker): close database pools before work horse exit by @alsd4git in #5303
  • fix(player): preserve arcade BIOS archive bytes by @alsd4git in #5305
  • fix(streaming): give standalone PPSSPP the broker's working state slot by @bercedev in #5256
  • fix(collections): drop hidden roms' covers from collection responses by @ryanpf in #5311
  • fix(platforms): count only the roms the caller can see in rom_count and fs_size_bytes by @ryanpf in #5313
  • fix(i18n): Russian "metadata-sources" translation by @LucRen in #5370
  • fix(scan): Fix scan failure when ROM name is missing by @cfranz-medsoto in #5377
  • fix(db): bump client token and device last-used timestamps without a prior read by @pcbeingused333 in #5384
  • fix(streaming): release a desktop claim when activation is cancelled by @gantoine in #5392
  • fix(scan): consult sources from one rule table and keep stored matches on refresh by @gantoine in #5394
  • fix(frontend): pad A picks the active option in an open select by @sdornan in #5389
  • fix(frontend): give RComboboxField combobox semantics by @sdornan in #5399
  • fix(frontend): let pad A toggle checkboxes, open read-only fields and keep focus after a pick by @sdornan in #5401
  • fix(frontend): give white text on the brand fill AA contrast in dark mode by @sdornan in #5402
  • fix(misc): Rename paths, rescan artwork, scan lookups and streaming teardown fixes by @gantoine in #5396
  • fix(scan): clean up unreferenced rescan media, split scan_rom and move its parts into handler/scan by @gantoine in #5408
  • fix(ui/ux): make age rating and player count badges clickable by @Yi-111-a in #5237
  • fix(webp): raise the cover WebP quality to 95 by @gantoine in #5410
  • fix(ui): keep top nav contents still when a gallery scrollbar appears by @sdornan in #5411
  • fix: keep summary line breaks and strip provider HTML by @gantoine in #5413
  • fix(ui): hide the anniversaries widget on days without anniversaries by @gantoine in #5414
  • fix(ra): extract zips RAHasher can't unzip before hashing them by @sdornan in #5416
  • fix(scan): skip AppleDouble files and ES-DE media roots by default by @sdornan in #5422
  • fix(scan): hash game folders in sorted file order by @sdornan in #5421
  • fix(ra): count earned achievements that share a badge separately by @sdornan in #5423
  • fix(client-tokens): let a client token revoke itself without me.write by @gantoine in #5419
  • fix(scan): strip .p8 from PICO-8 cart titles so LaunchBox can match them by @sdornan in #5427
  • fix(sort): strip only configured articles, and keep custom sort keys as typed by @sdornan in #5429
  • fix(switch): explain why encrypted dumps get no title id by @gantoine in #5428
  • fix(menu): return focus to the activator when the menu closes by @sdornan in #5437
  • fix(player): keep the CD-i BIOS archive whole for same_cdi by @gantoine in #5440
  • fix(firmware): verify firmware by hash regardless of name or platform by @gantoine in #5441
  • fix(downloads): keep converted copies' ETag stable so downloads resume by @gantoine in #5442
  • fix(tasks): re-register RQ workers whose registration expired by @gantoine in #5443
  • fix(upload): recheck platform visibility when completing a chunked upload by @gantoine in #5458
  • fix(player): point RetroArch's system directory at PUAE Kickstarts by @gantoine in #5444
  • fix(sync): match RetroArch saves named after a ROM's files by @gantoine in #5445
  • fix(users): clear an email sent empty under FastAPI 0.162, and lift the pin by @sdornan in #5472
  • fix(users): unlink RetroAchievements when ra_username is sent empty by @sdornan in #5475
  • fix(streaming): let multi-disc games pick a starting disc by @gantoine in #5446
  • fix(sync): bind device tokens to their device; dial only known push-pull hosts by @gantoine in #5460
  • fix: permission, validation and resource-limit hardening by @gantoine in #5496
  • fix: enforce ROM visibility on assets, sync, collections, stats and scan events by @gantoine in #5498
  • fix(scan): wrap live counter chips instead of overlapping on narrow screens by @sdornan in #5515
  • fix(scan): look a file named by several titles up by each of them by @TylerVigario in #5478
  • fix(setup): resolve folder aliases when identifying platforms in the setup wizard by @pcbeingused333 in #5473
  • fix(platforms): point Apple II at LaunchBox platform 111 by @danielcopper in #5507
  • fix(platforms): give pc-8800-series libretro's PC-88 name by @danielcopper in #5508
  • fix(platforms): use libretro's names for Xbox and drop two it does not have by @danielcopper in #5509
  • fix(platforms): file amigacdtv as the CDTV and give it libretro's name by @danielcopper in #5513
  • fix(platforms): give amiga-cd32 libretro's CD32 name by @danielcopper in #5511
  • fix(platforms): drop the PICO-8 slug's mapping to MobyGames' PICO VR platform by @danielcopper in #5525
  • fix(search): reword the physical filter's file option by @gantoine in #5529
  • fix(platforms): stop filing sgb folders as Game Boy Color by @gantoine in #5530
  • fix(retroachievements): ride out rate limits during the progress sync by @gantoine in #5532
  • fix(player): record the device that wrote a state and skip other devices' states at start by @gantoine in #5531
  • fix(sync): resolve RetroArch save names to the core's platform by @gantoine in #5533
  • fix(scan): hash compressed ROMs by their content in every format by @gantoine in #5537
  • fix(player): boot the base game, not a patch or translation by @gantoine in #5538
  • fix(frontend): highlight tapped bottom-nav tab immediately by @sdornan in #5558
  • fix(scan): name a game by metadata priority, whatever order the scans ran in by @TylerVigario in #5546
  • fix(firmware): add the three missing PS2 v2.00 BIOS dumps of 2004-06-14 by @danielcopper in #5551
  • fix(scan): read revision tags written without a separator by @NevesHenry in #5559
  • fix(frontend): split collections and platforms empty messages into title and hint by @sdornan in #5563

Other changes

  • chore(docker): build the dev image on production's Alpine base by @gantoine in #5335
  • chore(deps): update dependency happy-dom to v21 [security] by @renovate[bot] in #5317
  • chore(deps): bump oauthlib, OpenTelemetry, vitest, markdown-it and undici for security advisories by @gantoine in #5342
  • chore(deps): update github actions by @renovate[bot] in #5348
  • test(auth): cover refresh-token rejection paths by @sdornan in #5357
  • refactor(frontend): emit themed tokens as light-dark() pairs by @sdornan in #5356
  • chore(frontend): remove unused locale keys by @sdornan in #5353
  • docs: rewrite the frontend architecture guide for the current UI by @sdornan in #5355
  • chore(frontend): remove the deprecated gallery-list state from the roms store by @sdornan in #5354
  • chore(deps): update dependency vite-plugin-pwa to v2 by @renovate[bot] in #5350
  • chore(trunk): Upgrade trunk by @github-actions[bot] in #5360
  • chore(deps): update backend dependencies by @renovate[bot] in #5347
  • chore(deps): update frontend dependencies by @renovate[bot] in #5349
  • docs(readme): add R-Shop, RomMMobile and KONSORU to community projects by @gantoine in #5361
  • revert: feat(frontend): add an Open in Steam action for Steam-matched games by @gantoine in #5366
  • revert: feat: classify ROMs by release type (homebrew, hack, translation, ...) by @gantoine in #5365
  • chore: Library support for zelda classic games by @ianfhunter in #5214
  • chore(deps): update dependency happy-dom to v21.0.4 [security] by @renovate[bot] in #5372
  • chore(security): verify dev toolchain downloads by @gantoine in #5218
  • chore(converto): bump rom-converto to v0.24.0 in both images by @DevYukine in #5220
  • perf(roms): let a list fetch leave the provider metadata off each item by @danielcopper in #5228
  • refactor(docker): simplify the production Dockerfile by @sdornan in #5376
  • perf(roms): cheaper grouped gallery window on PostgreSQL and MariaDB by @andest01 in #5267
  • refactor(frontend): rename RSliderBtnGroup to RSegmentedControl by @sdornan in #5383
  • refactor(frontend): drop !important from RSegmentedControl by @sdornan in #5386
  • refactor(frontend): rename RImg to RImage by @sdornan in #5387
  • docs(readme): add CoreHost as a hosted deploy option by @gantoine in #5380
  • chore: add reverted-fix, reach and test checks to security-audit by @gantoine in #5390
  • refactor(roms): drive update_rom's provider refetches from one table by @gantoine in #5393
  • refactor(streaming): type the session record as a StreamingSession TypedDict by @gantoine in #5395
  • refactor(frontend): share the primitives' tone and rounded maps by @sdornan in #5400
  • refactor(player): build the EmulatorJS globals in one pure function by @gantoine in #5397
  • ci(coverage): measure frontend coverage with v8 and backend branch coverage by @sdornan in #5407
  • chore(seed): realistic, fast, debuggable seeded images by @andest01 in #5253
  • test(game-details): cover the achievements tab's earned/total badge by @sdornan in #5426
  • test: keep the NUL media path out of the PostgreSQL seed by @gantoine in #5420
  • test: raise libretro HEAD timeout in fake-server fixture to fix flaky test by @sdornan in #5436
  • chore(docker): refresh base image digests and let Renovate track them by @sdornan in #5439
  • chore(deps): update frontend dependencies by @renovate[bot] in #5450
  • chore(deps): bump dnspython to 2.9.0 for CVE-2026-114605 by @sdornan in #5448
  • chore(trunk): Upgrade trunk by @github-actions[bot] in #5456
  • docs(readme): add RomP and RommPS, drop Syncthing sync by @gantoine in #5459
  • chore(deps): update backend dependencies by @renovate[bot] in #5449
  • docs(agents): note gh --attach needs 2.99.0 and fails in cloud sessions by @sdornan in #5470
  • chore(deps): update frontend dependencies by @renovate[bot] in #5468
  • test: date "later" saves and states a year ahead, not in 2099 by @sdornan in #5474
  • chore(deps): update astral-sh/setup-uv action to v10.3.3 by @renovate[bot] in #5466
  • chore(deps): update valkey/valkey docker tag to v9.0.7 by @renovate[bot] in #5467
  • chore(deps): update frontend dependencies to v10.6.5 by @renovate[bot] in #5484
  • chore(deps): update backend dependencies by @renovate[bot] in #5483
  • chore(deps): update node.js to v26 by @renovate[bot] in #5469
  • chore(deps): update dependency @types/node to v26.6.6 by @renovate[bot] in #5491
  • chore(deps): update dependency mypy to v2.4.1 by @renovate[bot] in #5492
  • chore(deps): update dependency rq to v3 by @renovate[bot] in #5493
  • chore(deps): update github actions by @renovate[bot] in #5494
  • refactor(gallery): track the displayed result, refresh sorts in place, defer to page morphs by @sdornan in #5502
  • perf(scan): stop quick scan re-reading unchanged ROMs by @sdornan in #5516
  • chore(scan): recognize Brazilian Portuguese as a language by @NathanAlcantara in #5499
  • chore(deps): update dependency tornado to v6.6 [security] by @renovate[bot] in #5527
  • chore(deps): update dependency oauthlib to v4.0.1 [security] by @renovate[bot] in #5526
  • test(frontend): add BottomNav stories by @sdornan in #5528
  • chore(trunk): Upgrade trunk to 1.29.0 by @github-actions[bot] in #5523
  • chore(deps): update frontend dependencies by @renovate[bot] in #5521
  • chore(deps): update backend dependencies by @renovate[bot] in #5520
  • chore(deps): update docker base images by @renovate[bot] in #5534
  • chore(deps): update peter-evans/create-pull-request action to v8.1.2 by @renovate[bot] in #5535
  • test(frontend): disable MdPreview image zoom in mdeditor test by @sdornan in #5542
  • perf(frontend): stop promoting every virtual scroller item to a layer by @andest01 in #5550
  • chore(deps): update dependency croniter to v7 by @renovate[bot] in #5536
  • chore(storybook): add the pseudo-states addon by @andest01 in #5549
  • perf(frontend): poll the gamepad only while one is connected by @andest01 in #5547
  • perf(frontend): drop lodash for small native helpers by @sdornan in #5561

New Contributors

Full Changelog: 5.4.1...5.5.0

Don't miss a new romm release

NewReleases is sending notifications on new releases.