Skip to content

fix(docker): always start the RQ scheduler - #4033

Merged
gantoine merged 2 commits into
rommapp:masterfrom
XenuIsWatching:fix/scheduler-not-started-blocks-scans
Aug 1, 2026
Merged

fix(docker): always start the RQ scheduler#4033
gantoine merged 2 commits into
rommapp:masterfrom
XenuIsWatching:fix/scheduler-not-started-blocks-scans

Conversation

@XenuIsWatching

@XenuIsWatching XenuIsWatching commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Description

Explain the changes or enhancements you are proposing with this pull request.

The RQ scheduler only starts when one of four ENABLE_SCHEDULED_* flags is true:

# only start the scheduler if enabled
if [[ ${ENABLE_SCHEDULED_RESCAN} == "true" || ${ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB} == "true" \
   || ${ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA} == "true" || ${ENABLE_SCHEDULED_CLEANUP_ORPHANED_RESOURCES} == "true" ]]; then
    watchdog_process_pid rq_scheduler
fi

Nothing else respects that condition, and the list has fallen behind in three separate ways:

  • startup.py registers three cleanups unconditionally. cleanup_netplay (every 30 min), cleanup_upload_tmp (hourly) and cleanup_zip_cache (daily) are declared enabled=True with cron strings and init()ed regardless of any flag. On a default install none of them ever run.
  • Three more flags gate periodic tasks but are absent from the condition: ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP, ENABLE_SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC and ENABLE_SYNC_PUSH_PULL. Enabling any one of those alone silently does nothing.
  • The filesystem watcher defers its rescans through the scheduler (watcher.py:214, tasks_scheduler.enqueue_in(...)), but ENABLE_RESCAN_ON_FILESYSTEM_CHANGE is not in the list either.

entrypoint.sh starts the scheduler unconditionally and always has, so the two entry paths already disagree about this.

The user-visible failure

Reported in Discord on 5.1.0: clicking Scan is refused immediately and permanently with 🛑 Scan already in progress, ignoring request, with no scan running.

With the watcher on and none of the four listed tasks enabled, the watcher runs but the scheduler does not. A filesystem change leaves a delayed scan_platforms entry in the scheduler registry that nothing will ever execute, and #3974's concurrent scan guard counts it as a queued scan, so every manual scan is refused.

Only one entry is needed to cause this. The watcher deduplicates before scheduling (get_pending_scan_jobs() in watcher.py, which bails when a full rescan is already pending and skips per-platform slugs that already have one), so entries do not pile up. A single stuck one blocks indefinitely.

That matches the report: restarting the container does not help, because it is persisted Redis state rather than a running process; clearing redis-data does help; and the block returns once the next scan finishes, because that scan writes resources, the watcher fires, and a fresh entry is scheduled.

Reproduced on a live instance by creating one watcher-style entry:

queued scans BEFORE: []
created scheduler entry: a1f0a558-… | func: endpoints.sockets.scan.scan_platforms
queued scans AFTER : ['a1f0a558-…']
>>> GUARD WOULD BLOCK: True

The reporter's configuration, confirmed after the fact, is ENABLE_RESCAN_ON_FILESYSTEM_CHANGE, ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP and ENABLE_SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC all true. Three scheduler-dependent features enabled, none of which starts the scheduler.

The silent variant is visible on any default install. These are the unconditional cleanups on my own instance, all overdue, because no scheduler exists to run them:

cleanup_netplay             scheduled_for=2026-07-25 06:30:00
cleanup_upload_tmp          scheduled_for=2026-07-25 07:00:00
cleanup_zip_cache           scheduled_for=2026-07-30 04:00:00
cleanup_orphaned_resources  scheduled_for=2026-07-30 05:00:00

Changes

Start the scheduler unconditionally, matching entrypoint.sh. A hand-maintained boolean chain in bash is what drifted here, and since three periodic tasks are registered regardless of configuration, there is no case left for the condition to express.

No cleanup step is needed for instances already stuck: rq-scheduler enqueues past-due jobs as soon as it starts, so the orphaned entry is picked up, run, and gone.

Testing

  • Traced on a live 5.1.0 instance: reproduced the block by creating a single watcher-style scheduler entry, and confirmed rqscheduler is absent from the process list with the default configuration.
  • bash -n, shellcheck, shfmt 3.6.0 clean.

No new tests. The change is one line of the init script, which has no test harness in-repo, and the guard behaviour it feeds is already covered by TestScanConcurrency.

Note for #4019

The s6-overlay rewrite copies the same four-flag condition verbatim into docker/s6-overlay/s6-rc.d/romm-rq-scheduler/run and calls disable_service, so it currently reintroduces all of the above. Commented there. Whichever lands second should carry this across.

Checklist

Please check all that apply.

  • I've tested the changes locally
  • I've updated relevant comments
  • I've assigned reviewers for this PR
  • I've added unit tests that cover the changes

AI assistance disclosure

Per CONTRIBUTING.md: this change was written with AI assistance (Claude Code). The root cause was traced from the Discord report and reproduced on my own instance; the AI wrote the patch, and I reviewed the result.

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR starts the production RQ scheduler unconditionally and changes scan concurrency discovery to ignore scheduler entries more than 15 minutes overdue.

Confidence Score: 4/5

This PR should not merge until overdue delayed scans remain protected against later scheduler recovery.

A temporary scheduler outage lasting beyond the fixed grace period makes a still-executable delayed scan invisible to both concurrency prevention and cancellation, allowing it to overlap a manual scan or run after a stop request.

Files Needing Attention: backend/endpoints/sockets/scan.py

Important Files Changed

Filename Overview
backend/endpoints/sockets/scan.py Adds timestamp-aware scheduler discovery, but assumes an overdue persisted entry cannot execute after scheduler recovery.
backend/tests/endpoints/sockets/test_scan.py Adds naive/aware timestamp coverage and the intended stale-entry behavior, but does not cover scheduler recovery after the grace period.
docker/init_scripts/init Starts the scheduler unconditionally so delayed and periodic jobs are consistently drained.

Fix All in Claude Code

Prompt To Fix All With AI
### Issue 1
backend/endpoints/sockets/scan.py:153
**Overdue scans remain executable**

When the scheduler recovers after a delayed watcher scan is more than 15 minutes overdue, this filter hides the still-executable entry from both the concurrency guard and cancellation path, allowing it to overlap a manual scan or run after a stop request.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(docker): always start the RQ schedul..." | Re-trigger Greptile

Comment thread backend/endpoints/sockets/scan.py Outdated
@XenuIsWatching

Copy link
Copy Markdown
Contributor Author

Confirmation from the reporter in Discord. Their configuration is:

ENABLE_RESCAN_ON_FILESYSTEM_CHANGE=true
ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP=true
ENABLE_SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC=true

Three scheduler-dependent features enabled, and not one of them starts the scheduler. The condition on master checks only ENABLE_SCHEDULED_RESCAN, ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB, ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA and ENABLE_SCHEDULED_CLEANUP_ORPHANED_RESOURCES.

So the watcher runs, defers rescans through a scheduler that does not exist, and the entries accumulate until the scan guard refuses every manual scan. That is the reported symptom, reached through a configuration I had not specifically predicted, which I think makes the case for dropping the condition rather than extending it: any fixed list here is one more thing to keep in sync, and this one has already drifted three times.

Two further consequences on that same instance, both silent:

  • RetroAchievements progress sync has never run. Nothing outside the scheduler triggers it.
  • WebP conversion only half works. startup.py:_enqueue_convert_images_to_webp() puts a one-off backfill directly on the low priority queue, which the worker picks up, and the worker does run. So covers present at startup get converted and the feature looks healthy. The recurring cron never fires, so anything added between restarts has no .webp sibling until the next container start.

That second one is probably worth noting for its own sake: the backfill masking the missing cron is a good part of why this went unnoticed for so long.

Worth adding that the workaround is not "enable any scheduled task", which is the natural assumption and the one I gave them first. It has to be one of the four in the condition. On this instance, ENABLE_SCHEDULED_CLEANUP_ORPHANED_RESOURCES=true plus a restart starts the scheduler and drains the backlog.

The scheduler only started when one of four ENABLE_SCHEDULED_* flags was
true, but nothing else respects that condition. startup.py registers the
netplay, upload-tmp and zip-cache cleanups unconditionally, three more
flags gate periodic tasks that are absent from the list, and the
filesystem watcher defers its rescans through the scheduler as well.

Any of those leaves jobs sitting in the scheduler registry with no
process to run them. On a default install the three cleanups never fire
at all. A watcher running with none of the four listed tasks enabled
leaves a delayed scan_platforms entry that nothing will execute, and the
concurrent scan guard reads it as a scan already queued, so every manual
scan is refused with "A scan is already in progress". Restarting does not
help, because the entry is persisted state rather than a running process.

Start the scheduler unconditionally, matching entrypoint.sh, which never
gated it. A stuck entry then clears on its own, since the scheduler
enqueues past-due jobs as soon as it comes up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@XenuIsWatching
XenuIsWatching force-pushed the fix/scheduler-not-started-blocks-scans branch from 0681c86 to 0ae753e Compare July 31, 2026 19:13
@XenuIsWatching

Copy link
Copy Markdown
Contributor Author

Good catch, and correct. _get_queued_scan_jobs() also feeds stop_scan_handler, so the grace filter hid overdue entries from cancellation as well as from the guard, and an overdue entry is not dead: rq-scheduler enqueues past-due jobs the moment it comes up. Hiding it meant a manual scan could overlap it, and Stop would not cancel it.

I have dropped that part entirely rather than patch around it. It was defence in depth against a scheduler that stalls anyway, and it bought that at the cost of weakening a guard that works. The PR is now just the init script change.

Nothing is needed in its place: once the scheduler always starts, a stuck entry resolves itself, because the scheduler enqueues past-due jobs at startup and the worker runs them.

Separately, I have corrected the description. I had written that watcher entries accumulate. They do not, get_pending_scan_jobs() in watcher.py deduplicates before scheduling, bailing when a full rescan is already pending and skipping per-platform slugs that already have one. It is a single stuck entry that blocks indefinitely, not a growing pile. Same symptom, wrong mechanism on my part.

@gantoine
gantoine self-requested a review July 31, 2026 20:00

@gantoine gantoine left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes 100%

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 15:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a Docker startup inconsistency by ensuring the RQ scheduler is always supervised and running in the legacy docker/init_scripts/init path, matching entrypoint.sh behavior. This prevents scheduler-backed features (watcher-delayed rescans and periodic cleanups) from silently never executing due to a drifted, incomplete flag-gated condition.

Changes:

  • Start/supervise rq_scheduler unconditionally in the main watchdog loop.
  • Remove the brittle multi-flag conditional that had fallen out of sync with actual scheduled-task usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@gantoine
gantoine merged commit dea964f into rommapp:master Aug 1, 2026
3 checks passed
gantoine added a commit that referenced this pull request Aug 1, 2026
The s6 service carried over the four-flag ENABLE_SCHEDULED_* gate from the
init script, which #4033 has since removed on master. Since this branch
deletes that script, the fix would be lost on rebase.

Nothing else respects the condition: startup.py registers the netplay,
upload-tmp and zip-cache cleanups unconditionally, three more flags gate
periodic tasks absent from the list, and the watcher defers its rescans
through the scheduler. Any of those leaves jobs in the scheduler registry
with no process to run them, and a stuck delayed scan_platforms entry reads
to the concurrent scan guard as a scan already queued, refusing every
manual scan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bigSmooth7867 pushed a commit to bigSmooth7867/swarm that referenced this pull request Aug 21, 2026
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [rommapp/romm](https://github.com/rommapp/romm) | minor | `5.1.0` → `5.2.0` |

---

### Release Notes

<details>
<summary>rommapp/romm (rommapp/romm)</summary>

### [`v5.2.0`](https://github.com/rommapp/romm/releases/tag/5.2.0)

[Compare Source](rommapp/romm@5.1.0...5.2.0)

#### Minor changes

- feat(screenscraper): pace and report scans against the account's reported limits by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;3989](rommapp/romm#3989)
- feat: reorderable region and language priority lists in scan settings by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4015](rommapp/romm#4015)
- feat(frontend): autofocus the search field on the Search view by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4022](rommapp/romm#4022)
- feat(home): make the random pick widget clickable and denser by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4056](rommapp/romm#4056)
- feat(rating): show provider ratings by [@&#8203;wadiebs](https://github.com/wadiebs) in [#&#8203;4096](rommapp/romm#4096)
- feat(soundtrack player): improve artwork by [@&#8203;wadiebs](https://github.com/wadiebs) in [#&#8203;4168](rommapp/romm#4168)
- feat(v2): previous / next game buttons on the details page by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4012](rommapp/romm#4012)
- feat(v2): search platforms by slug, folder, category and family by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4136](rommapp/romm#4136)
- feat(hasheous): map famicom to the NES platform by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4162](rommapp/romm#4162)
- feat(v2): show IGDB ports on the game overview by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4184](rommapp/romm#4184)

#### Fixes

- fix(steamgriddb): skip DMCA-locked grids when scraping SteamGridDB by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4004](rommapp/romm#4004)
- fix(security): close three permission gaps found auditing 5.1.0 by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;3993](rommapp/romm#3993)
- fix(backend): re-run the Hasheous hash lookup on a hashes scan by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4013](rommapp/romm#4013)
- fix(v2): keep RSelect menus inside the viewport and tidy the selection text by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4014](rommapp/romm#4014)
- fix(roms): give each FPKGi package a unique name within its rom by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4021](rommapp/romm#4021)
- fix(backend): scope ScreenScraper French fallback to taxonomy fields by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4026](rommapp/romm#4026)
- fix(v2): pivot to a filtered search from the overview info grid by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4023](rommapp/romm#4023)
- fix(backend): tolerate calendar-invalid gamelist dates on PostgreSQL by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4024](rommapp/romm#4024)
- fix(player): skip the save load a state immediately discards by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4025](rommapp/romm#4025)
- fix(roms): search the gallery by CRC32, MD5, SHA-1 and RA hash by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4032](rommapp/romm#4032)
- fix(docker): always start the RQ scheduler by [@&#8203;XenuIsWatching](https://github.com/XenuIsWatching) in [#&#8203;4033](rommapp/romm#4033)
- fix(backend): scope the kiosk read-only cap to the anonymous visitor by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4047](rommapp/romm#4047)
- fix: batch of open bug fixes ([#&#8203;4027](rommapp/romm#4027), [#&#8203;4034](rommapp/romm#4034), [#&#8203;4035](rommapp/romm#4035), [#&#8203;4038](rommapp/romm#4038), [#&#8203;4040](rommapp/romm#4040), [#&#8203;4043](rommapp/romm#4043), [#&#8203;4045](rommapp/romm#4045)) by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4051](rommapp/romm#4051)
- fix(scan): report only newly discovered firmware by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4055](rommapp/romm#4055)
- fix(rom-details): render the manual viewer on mobile by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4058](rommapp/romm#4058)
- fix(hasheous): read the CHD and DOS signature sources by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4060](rommapp/romm#4060)
- fix(stats): pluralize the platform game count and lift meta legibility by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4065](rommapp/romm#4065)
- fix(config): map tic80 to the tic-80 platform slug by [@&#8203;XenuIsWatching](https://github.com/XenuIsWatching) in [#&#8203;4090](rommapp/romm#4090)
- fix(docker): keep the Redis password out of the RQ worker command line by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4093](rommapp/romm#4093)
- fix(v2): make hashes recoverable without HTTPS and show all firmware hashes by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4083](rommapp/romm#4083)
- fix(home): stop scanning the library filesystem on every home page load by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4069](rommapp/romm#4069)
- fix(auth): accept a stale user-bound CSRF token on anonymous requests by [@&#8203;bikeborb](https://github.com/bikeborb) in [#&#8203;4086](rommapp/romm#4086)
- fix(v2): drop a random pick after leaving the platform by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4113](rommapp/romm#4113)
- fix(states): repoint the row when a re-upload changes emulator by [@&#8203;TowyTowy](https://github.com/TowyTowy) in [#&#8203;4112](rommapp/romm#4112)
- fix(v2): keep Playmatch selectable when providers are set to All by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4120](rommapp/romm#4120)
- fix(hashing): extract CHD SHA-1 for folder-based ROMs by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4129](rommapp/romm#4129)
- fix(v2): compute game-card cover width instead of deriving it by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4135](rommapp/romm#4135)
- fix(media): stop recording paths for media that never landed by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4131](rommapp/romm#4131)
- fix(screenscraper): report rejected credentials instead of a bare 403 by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4130](rommapp/romm#4130)
- fix(launchbox): match ROMs during a scan the way Match ROM does by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4121](rommapp/romm#4121)
- fix(hltb): renew rejected HLTB sessions instead of failing the scan by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4125](rommapp/romm#4125)
- fix(v2): drop a random pick that lands after leaving the gallery by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4138](rommapp/romm#4138)
- fix(ss): store the ScreenScraper box-2D front locally by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4139](rommapp/romm#4139)
- fix(v2): show a running scan on pages loaded mid-scan by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4142](rommapp/romm#4142)
- fix(resources): fetch each cover once instead of once per size by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4143](rommapp/romm#4143)
- fix(metadata): identify archives and folder ROMs by the right file by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4146](rommapp/romm#4146)
- fix(match-rom): show the saving overlay above the grid match panel by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4147](rommapp/romm#4147)
- refactor(i18n): name gallery filters by property instead of "Show X" by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4149](rommapp/romm#4149)
- fix(v2): bulk favorite no-ops on a fresh instance and reports the wrong direction by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4151](rommapp/romm#4151)
- fix: refresh the v2 gallery when a ROM is edited or matched by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4153](rommapp/romm#4153)
- fix(v2): pin mobile bottom nav with sticky instead of fixed by [@&#8203;nickybmon](https://github.com/nickybmon) in [#&#8203;4155](rommapp/romm#4155)
- fix(export): stop miximage\_v2 colliding with miximage, persist gamelist back covers by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4156](rommapp/romm#4156)
- fix(hashing): surface unreadable zip and tar archives by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4163](rommapp/romm#4163)
- fix: remove double URL-encoding of MobyGames search terms by [@&#8203;justinjd00](https://github.com/justinjd00) in [#&#8203;4181](rommapp/romm#4181)
- fix(i18n): correct Breton pt\_BR player-count and align ja\_JP/tr\_TR by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4183](rommapp/romm#4183)
- fix(i18n): translate pt\_BR strings left in English by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4185](rommapp/romm#4185)
- fix(v2): close open overlays when the route changes by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4193](rommapp/romm#4193)
- Changed default compose, will explain more in pull by [@&#8203;danblu3](https://github.com/danblu3) in [#&#8203;4202](rommapp/romm#4202)
- fix(v2): drop the roms from the gallery when they leave the collection on screen by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4204](rommapp/romm#4204)
- fix(scan): normalize region and language tags to one canonical spelling by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4206](rommapp/romm#4206)
- fix: demote uvicorn HTTP access logs to WARNING/DEBUG only by [@&#8203;gantoine](https://github.com/gantoine) with [@&#8203;Copilot](https://github.com/Copilot) in [#&#8203;4214](rommapp/romm#4214)
- fix: Add `.xdelta` support to server-side ROM patcher and v2 patcher UI by [@&#8203;gantoine](https://github.com/gantoine) with [@&#8203;Copilot](https://github.com/Copilot) in [#&#8203;4215](rommapp/romm#4215)
- fix(states): enforce ROM visibility when uploading a state by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4216](rommapp/romm#4216)
- fix(auth): build invite links from ROMM\_BASE\_URL by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4217](rommapp/romm#4217)
- fix(scan): re-read filename tags on a complete rescan by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4218](rommapp/romm#4218)
- fix(libretro): cache missing thumbnail listings by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4219](rommapp/romm#4219)
- fix(launchbox): match titles differing only by punctuation by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4224](rommapp/romm#4224)
- fix(hltb): match titles whose series prefix the catalogue omits by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4225](rommapp/romm#4225)
- fix(ss): don't use the Switch icon URL as the manual URL by [@&#8203;TowyTowy](https://github.com/TowyTowy) in [#&#8203;4228](rommapp/romm#4228)
- fix(resources): publish downloaded resources atomically by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4230](rommapp/romm#4230)
- fix(i18n): translate route titles once locale messages are loaded by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4231](rommapp/romm#4231)
- fix(i18n): add the missing playlists permission entity label by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4234](rommapp/romm#4234)
- fix(hltb): fetch metadata when a HowLongToBeat ID is set by hand by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4235](rommapp/romm#4235)
- fix(launchbox): match LaunchBox dumps that separate words with underscores by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4239](rommapp/romm#4239)
- fix(backend): make filters match against all grouped versions instead of only the main version of each game entry by [@&#8203;darkpaul91](https://github.com/darkpaul91) in [#&#8203;4240](rommapp/romm#4240)
- feat(metadata): warn when ScreenScraper dev credentials are missing by [@&#8203;gantoine](https://github.com/gantoine) in [#&#8203;4243](rommapp/romm#4243)
- fix(scan): ignore Windows Zone.Identifier files by [@&#8203;Florian-Cullmann](https://github.com/Florian-Cullmann) in [#&#8203;4245](rommapp/romm#4245)

#### Other changes

- perf(roms): stop the Missing tab scanning the whole library by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4005](rommapp/romm#4005)
- perf(scan): stop hashing single-file ROMs twice by [@&#8203;XenuIsWatching](https://github.com/XenuIsWatching) in [#&#8203;4017](rommapp/romm#4017)
- perf(collections): serve smart and standard collections from a composed query by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4039](rommapp/romm#4039)
- perf(roms): extend the sibling covering index to cover the ROM grouping query by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4054](rommapp/romm#4054)
- perf(roms): let a gallery window fetch skip the library count by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4062](rommapp/romm#4062)
- perf(roms): pick a random rom without paging to a random offset by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4071](rommapp/romm#4071)
- perf(roms): sort metadata fields on the indexed roms column by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4078](rommapp/romm#4078)
- perf(gallery): resolve the random rom button in one request by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4097](rommapp/romm#4097)
- perf(home): stop counting the whole library for the two home rows by [@&#8203;Spinnich](https://github.com/Spinnich) in [#&#8203;4110](rommapp/romm#4110)
- perf(scan): scope a rom-id scan to the selected roms by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4188](rommapp/romm#4188)
- perf(scan): cut scan memory and drop a quadratic file listing check by [@&#8203;XenuIsWatching](https://github.com/XenuIsWatching) in [#&#8203;4198](rommapp/romm#4198)
- perf(scan): stop re-hashing unchanged firmware on every scan by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4211](rommapp/romm#4211)
- test: fix flaky LaunchBox release date property test (DST fold) by [@&#8203;sdornan](https://github.com/sdornan) in [#&#8203;4242](rommapp/romm#4242)
- chore(deps): bump aiohttp from 3.14.1 to 3.14.3 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;4115](rommapp/romm#4115)
- chore(deps-dev): bump fast-uri from 3.1.4 to 3.1.5 in /frontend by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;4118](rommapp/romm#4118)
- chore(deps): bump socket.io-parser from 4.2.6 to 4.2.7 in /frontend by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;4119](rommapp/romm#4119)
- chore(deps-dev): bump js-yaml from 4.2.0 to 4.3.1 in /frontend by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;4189](rommapp/romm#4189)

> \[!NOTE]
>
> ### API changes
>
> | Change                                   | Description                                                                                                                                                                                                     |
> | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
> | `GET /roms/random`                       | Retrieve one rom picked at random, or `null` when the scope holds none. Accepts `platform_ids`, `collection_id`, `virtual_collection_id` and `smart_collection_id`.                                             |
> | `GET /roms`                              | Now accepts a `with_total` parameter (default `true`). Set it to `false` when the caller already knows the total; `total` then comes back `null` unless the rom id index is being built and already carries it. |
> | `GET /setup/library`                     | `existing_platforms` now comes back empty once the database holds roms, instead of walking every platform directory.                                                                                            |
> | `POST /states`                           | Now rejects an upload against a rom the caller cannot see.                                                                                                                                                      |
> | `DELETE /roms/{rom_id}/files/{file_id}`  | Now requires the `ROMS`/`DELETE` grant instead of `ROMS`/`WRITE`.                                                                                                                                               |
> | `GET /feeds/fpkgi`                       | Package names are deduplicated within a rom, so two packages that share a title id no longer overwrite each other on the console.                                                                               |
> | `GET /collections/smart/{id}`            | The cached `rom_ids`, `rom_count` and covers are now resolved as the collection owner, not the requesting viewer. The live rom listing is still per-requester.                                                  |
> | `CustomLimitOffsetPage[SimpleRomSchema]` | `total` is now nullable.                                                                                                                                                                                        |
> | `InviteLinkSchema`                       | Adds `url`, the full registration link built from `ROMM_BASE_URL`, or `null` when that points at loopback.                                                                                                      |
> | `MetadataSourcesDict`                    | Adds `SS_DEV_CREDENTIALS_SET`.                                                                                                                                                                                  |
> | `RomSSMetadata`                          | Adds `box2d_path`.                                                                                                                                                                                              |
> | `RomGamelistMetadata`                    | Adds `box2d_back_path`, `fanart_path` and `title_screen_path`.                                                                                                                                                  |
> | `RomHasheousMetadata`                    | Adds `mame_redump_match`.                                                                                                                                                                                       |
>
> #### Streaming endpoints
>
> These moved from `ROMS_READ` to `ROMS_USER_WRITE`, which is always-on for authenticated users but absent from the read-only set a kiosk visitor gets.

#### New Contributors

- [@&#8203;wadiebs](https://github.com/wadiebs) made their first contribution in [#&#8203;4096](rommapp/romm#4096)
- [@&#8203;sdornan](https://github.com/sdornan) made their first contribution in [#&#8203;4120](rommapp/romm#4120)
- [@&#8203;nickybmon](https://github.com/nickybmon) made their first contribution in [#&#8203;4155](rommapp/romm#4155)
- [@&#8203;justinjd00](https://github.com/justinjd00) made their first contribution in [#&#8203;4181](rommapp/romm#4181)
- [@&#8203;danblu3](https://github.com/danblu3) made their first contribution in [#&#8203;4202](rommapp/romm#4202)
- [@&#8203;darkpaul91](https://github.com/darkpaul91) made their first contribution in [#&#8203;4240](rommapp/romm#4240)
- [@&#8203;Florian-Cullmann](https://github.com/Florian-Cullmann) made their first contribution in [#&#8203;4245](rommapp/romm#4245)

**Full Changelog**: <rommapp/romm@5.1.0...5.2.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMC40IiwidXBkYXRlZEluVmVyIjoiNDQuMzAuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsibWlub3IiLCJyZW5vdmF0ZSJdfQ==-->

Reviewed-on: https://gitea.vcasaserver.com/omar/swarm/pulls/740
Co-authored-by: Renovate Bot <renovate-bot@vcasaserver.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants