Warning
When binary logging is on and the connecting user lacks SUPER, trigger DDL is refused unless the global log_bin_trust_function_creators flag is 1. Run this on your MariaDB as an admin/root user (not the romm app user):
SET GLOBAL log_bin_trust_function_creators = 1;SET GLOBAL is lost on DB restart. Either add to your MariaDB my.cnf under [mysqld]:
log_bin_trust_function_creators = 1Or grant the app user the privilege (MariaDB 10.5+):
`GRANT BINLOG ADMIN ON *.* TO 'romm'@'%';` -- or: GRANT SUPER ON *.* TO 'romm'@'%';Warning
If your reverse proxy caches responses itself, or overrides/strips Cache-Control, it will defeat our built-in cache and serve a stale index.html that points at bundles the new image no longer ships, which usually shows up as a blank page or a broken UI after upgrading. After upgrading, purge your proxy's or CDN's existing cache once so clients stop being served entries stored under the old (header-less) behaviour.
Highlights
Emulator streaming
Launches a game into a native emulator running in a separate container and streams the picture, sound, and input back to your browser. Unlike EmulatorJS, the emulation runs server-side on real emulator binaries (PCSX2, Dolphin, Xemu), so the heavy lifting happens on the host rather than in the client. #3211
Important
Emulator streaming is in early development, and documentation is coming soon! If you really want to try it today, refer to this pull request in the rommapp/docs repo.
Per-field artwork priority overrides
Optional per-field artwork priority to prioritize metadata sources differently for covers, screenshots, and manuals, which fall back to the shared scan.priority.artwork. #3838
scan:
priority:
cover: # Cover art only
- igdb
- ss
screenshot: # Screenshots only
- ss
- igdb
manual: # Game manuals only
- launchbox
region_mode: prefer_rom_tags Region tags win over priority listScan settings UI
Brand new UI to edit the whole scan.* section of config.yml. #3854
Manual cover search filters
Client-side filters to the manual cover-search dialog to quickly narrow SteamGridDB results instead of scrolling through dozens of community covers. #3857
Minor changes
- feat: add file deletion to the Files tab on the game details page by @zurdi15 with @Copilot in #3753
- feat(v2): add reduced-effects mode for low-power devices by @gantoine in #3766
- feat(v2): link Hasheous provider to game detail page by @gantoine in #3783
- feat: add soundtrack gallery filter by @gantoine in #3790
- feat(playmatch): support self-hosted Playmatch instances by @gantoine in #3827
- feat: Support Range requests for multi-file ROM downloads by @tmgast in #3167
- feat: add "Open in Flashpoint" game action by @gantoine in #3845
- feat: Surface never-scanned platform folders in the scan picker by @gantoine in #3847
- feat(platforms): add editable platform descriptions by @Spinnich in #3855
- feat(v2): add random-ROM button to collections by @gantoine in #3860
- feat(v2): show smart and virtual collections on the home screen by @gantoine in #3859
- feat(scan): reassociate renamed/moved ROMs with missing entries by file hash by @gantoine in #3861
- feat(v2): auto-mark now-playing on launch + confirm launching shelved games by @gantoine in #3867
- feat: add music favorites and playlists API by @tmgast in #3896
- feat: add
scan.priority.region_modeto let config regions drive media selection by @gantoine in #3917 - feat: add Scan Settings to the user dropdown menu by @gantoine in #3923
Note
Environment variables
| cariable | default | description |
|---|---|---|
| PLAYMATCH_API_URL | https://playmatch.retrorealm.dev/api/v2
| Use self-hosted instance of Playmatch |
| STREAMING_BROKER_SECRET | -
| Required for emulator streaming |
| STREAMING_SAVE_TIMEOUT | 45
| Save request timeout (in seconds) |
Fixes
- fix(scan): resolve "Reg-" prefixed region shortcodes to full names by @TowyTowy in #3754
- fix(playmatch): handle empty heartbeat query by @DevYukine in #3756
- fix(db): pin explicit collation in virtual_collections view for MariaDB 11.6+ by @kthistlewood in #3759
- fix(v2): render match-rom covers at full width in Safari by @gantoine in #3763
- fix(migrations): make DDL idempotent on partial-failure reruns by @gantoine in #3767
- fix(v2): link IGDB provider to game page by slug by @gantoine in #3782
- fix(v2): batch gallery cover fetches into windows by @gantoine in #3765
- fix(ss): tolerate ScreenScraper's invalid JSON escapes by @gantoine in #3778
- fix(backend): lightweight eager-load for /roms/{id}/simple by @gantoine in #3779
- fix(platforms): include TGDB handler in tgdb_id fallback for supported platforms by @TowyTowy in #3785
- fix: respect configured IGDB region priority by @gantoine in #3791
- fix(retroachievements): resolve m3u playlists to natively hashed discs by @Spinnich in #3804
- fix(retroachievements): extract non-zip archives before RAHasher hashing by @Spinnich in #3813
- fix(metadata): search the whole filename for Sony serial codes by @TowyTowy in #3802
- fix(docker): proxy nginx to gunicorn over TCP instead of unix socket by @gantoine in #3810
- fix(frontend): base v2 verified badge on real DB hash matches by @gantoine in #3815
- fix(v2): render visible labels on device-auth and token expiry selects by @gantoine in #3818
- fix(igdb): don't match series games to their base title by @gantoine in #3817
- fix(scan): make v2 per-ROM "Update metadata" run the update scan type by @gantoine in #3819
- fix(v2): batch gallery hydration into windows and cap concurrency by @gantoine in #3824
- fix(v2): clear gallery selection after deleting ROMs by @gantoine in #3828
- fix(player): keep origin save bound and surface save slots in v2 EmulatorJS by @gantoine in #3831
- fix: Missing last platform-stats progressbar by @AlmostEasyGoing in #3834
- fix(netplay): correct room-list and socket URLs behind a reverse proxy by @gantoine in #3839
- fix: don't re-stamp updated_at for unchanged ROMs during scans by @gantoine in #3843
- fix: load selected file with correct extension for multi-file roms by @gantoine in #3844
- Fix v2 gallery not refetching when filter logic operator changes by @gantoine in #3840
- Fix wrong error wording for flag-only providers in setup wizard by @gantoine in #3841
- Fix slot-less save upload DB/file desync by @gantoine in #3846
- fix: enforce hidden-ROM/platform visibility on asset download and streaming endpoints by @gantoine in #3853
- fix(v2): ignore phantom/non-standard gamepads in nav polling by @gantoine in #3852
- fix(v2): overlay body-scroll-lock leaks + Library Stats label clipping by @gantoine in #3858
- fix(collections): lazy-load collection mosaic artwork by @gantoine in #3870
- fix(v2): keep collection visibility toggle in sync after save by @gantoine in #3871
- fix(db): don't use STR_TO_DATE in a generated column (MariaDB 12.3) by @gantoine in #3879
- fix(v2): take the hotkey-mute playing flag from EmulatorJS' start hook by @gantoine in #3878
- fix(archives): read RAR archives through bsdtar so they can be hashed by @gantoine in #3887
- fix(nginx): cache only fingerprinted assets, revalidate the rest by @Spinnich in #3892
- fix(v2): hide empty platforms in Server Stats breakdown by @Spinnich in #3899
- fix(scan): reconcile rom_files in place instead of purging them by @gantoine in #3900
- fix(scan): emit a client update for ROMs that are no longer missing by @gantoine in #3903
- Fix/server stats duplicate slug key by @Spinnich in #3906
- Fix Playmatch health check failing on plain-text response by @gantoine in #3916
- Stop storing fanart and title_screen twice when screenshots are enabled by @gantoine in #3918
- fix(v2): restore backdrop-filter blur in production builds by @zurdi15 in #3922
- Keep config.yaml EmulatorJS core settings active after user changes settings by @gantoine in #3920
- fix(migrations): pin device FK column collations to match devices.id by @gantoine in #3929
- fix(backend): make roms_facets/collection migrations idempotent by @gantoine in #3930
- fix(roms): list the smart collections a ROM belongs to on its detail view by @Spinnich in #3936
- fix(player): guard v2 EmulatorJS against stale saved disc id by @Spinnich in #3940
- fix(player): render ScreenScraper bezel in v2 EmulatorJS player by @Spinnich in #3944
- fix: default EmulatorJS netplay username to the RomM account by @gantoine in #3919
Other changes
- docs: add agent repository instructions by @gantoine in #3755
- Reduce RQ worker registry sweep verbosity and frequency by @gantoine in #3731
- chore(i18n): add linter enforcing alphabetically sorted locale files by @gantoine in #3757
- perf(backend): index roms (platform_id, fs_size_bytes) by @gantoine in #3780
- perf(roms): make full rom id index opt-out on GET /api/roms by @gantoine in #3781
- revert(v2): hydrate gallery cards per-card via /roms/{id}/simple by @gantoine in #3789
- perf(backend): make roms_metadata fast via generated columns by @gantoine in #3826
- feat(platforms): add windows9x support by @gantoine in #3880
- chore: add security-audit skill for vetting diffs by @gantoine in #3872
- perf(backend): mirror ROM filter values into a narrow trigger-maintained table by @gantoine in #3885
- perf(backend): materialize virtual collection membership by @gantoine in #3886
- perf(stats): aggregate Server Stats breakdowns from roms_facets by @Spinnich in #3910
- build(deps): bump pillow from 12.2.0 to 12.3.0 by @dependabot[bot] in #3863
- build(deps): bump pydantic-settings from 2.14.1 to 2.14.2 by @dependabot[bot] in #3868
- build(deps-dev): bump fast-uri from 3.1.2 to 3.1.4 in /frontend by @dependabot[bot] in #3927
- build(deps): bump linkify-it from 5.0.1 to 5.0.2 in /frontend by @dependabot[bot] in #3926
API changes
| Change | Description |
|---|---|
PUT /config/scan
| Replace the scan.* section of the configuration.
|
GET /platform/filesystem
| Retrieve platform folders on disk that have no database row yet. |
GET /roms
| Now accepts a with_rom_id_index parameter.
|
DELETE /{rom_id}/files/{file_id}
| Delete a single file belonging to a ROM. |
BulkOperationResponse
| Swaps failed_items: int for failed_ids: list[int].
|
ConfigResponse
| Adds SCAN_ARTWORK_PRIORITY_OVERRIDES, GAMELIST_AUTO_EXPORT_ON_SCAN, and PEGASUS_AUTO_EXPORT_ON_SCAN.
|
Streaming endpoints
| Method | Path | Description |
|---|---|---|
GET
| /streaming/config
| Returns streaming config flag plus a sanitized container list |
POST
| /streaming/sessions
| Claims a session for a game to launch it |
POST
| /streaming/sessions/{platform}/save-and-exit
| Releases the session |
POST
| /streaming/sessions/{platform}/volume
| Set from 0-100 |
POST
| /streaming/sessions/{platform}/mute
| Toggles or explicitly sets mute state |
POST
| /streaming/sessions/{platform}/save-state
| Saves to a manual slot without stopping the emulator |
POST
| /streaming/sessions/{platform}/load-state
| Loads from a manual slot or the platform's autosave slot |
DELETE
| /streaming/sessions/{platform}
| Releases the session and best-effort tells the broker to stop the emulator |
GET
| /streaming/sessions
| Debug view of all active sessions |
DELETE
| /streaming/sessions
| Force-releases every active session. |
Music favorites endpoints
| Method | Path | Description |
|---|---|---|
GET
| /music/favorites
| The requester's favorite tracks; same page shape and filters as /music/tracks
|
POST
| /music/favorites
| Marks rom_file_ids as favorites, ignoring ones already favorited; returns {added}
|
DELETE
| /music/favorites
| Unmarks rom_file_ids as favorites; returns {removed}
|
Music playlist endpoints
| Method | Path | Description |
|---|---|---|
GET
| /music/playlists
| Lists the requester's playlists plus other users' public ones |
POST
| /music/playlists
| Creates a playlist (name, description, is_public); 409 on a duplicate name for that user
|
GET
| /music/playlists/{id}
| One playlist with its track count; owner-only unless public |
PUT
| /music/playlists/{id}
| Partially updates name/description/is_public; owner only |
DELETE
| /music/playlists/{id}
| Deletes the playlist, owner only; 204 on success |
GET
| /music/playlists/{id}/tracks
| Paginated tracks in playlist order by default; entries hidden from the viewer are omitted |
POST
| /music/playlists/{id}/tracks
| Appends tracks, ignoring ones already present; returns {added}
|
DELETE
| /music/playlists/{id}/tracks
| Removes tracks from the playlist; returns {removed}
|
PUT
| /music/playlists/{id}/tracks/order
| Reorders to match the given ids; unlisted entries keep their relative order after them |
GET
| /music/tracks
| New rom_id query param to restrict to one rom's tracks
|
GET
| /music/tracks
| MusicTrackSchema gains is_favorite, so every track-returning respons
|
New Contributors
- @kthistlewood made their first contribution in #3759
- @AlmostEasyGoing made their first contribution in #3834
- @SaveEditors made their first contribution in #3945
Full Changelog: 5.0.0...5.1.0-beta.1