171 Commits
Author SHA1 Message Date
dependabot[bot] 9dcba51122 chore(deps): bump mako from 1.3.12 to 1.4.2 (#5166) 2026-10-06 14:31:43 -04:00
dependabot[bot] a022415d90 chore(deps): bump multidict from 6.7.1 to 6.9.1 (#5165) 2026-10-06 14:31:19 -04:00
renovate[bot] 9c23817887 chore(deps): update backend dependencies (#5136) 2026-10-05 04:38:19 -04:00
Sam Dornan 93c98c71c0 chore(deps): upgrade apprise to 2.0 (#5102) 2026-10-04 10:18:38 -04:00
renovate[bot] 4f44b7219e chore(deps): update backend dependencies (#5104) 2026-10-04 10:00:40 -04:00
Sam Dornan 3b4e230b7c Upgrade SQLAlchemy to 2.1 (#5007) 2026-10-01 19:17:30 -04:00
renovate[bot] b535ed0e6f chore(deps): update backend dependencies 2026-10-01 17:03:30 +00:00
dependabot[bot] acafe37287 chore(deps): bump tornado from 6.5.8 to 6.5.9 (#4985) 2026-09-30 22:46:20 -04:00
Georges-Antoine Assi ce980b677f Merge pull request #4957 from beemines/feat/configurable-cleanup-schedules
feat: make netplay and upload cleanup schedules configurable
2026-09-30 16:48:05 -04:00
Georges-Antoine AssiandClaude Opus 5.5 640e8eb96b Skip scheduled tasks whose cron expression is invalid
rq only parses the cron when the scheduler loads it, then logs and drops
the job while cron_config had already logged it as scheduled. Validate it
up front and log an error instead. croniter was a transitive rq dependency
and is now declared directly, with its typeshed stubs for mypy.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-30 16:32:49 -04:00
dependabot[bot] bf08a54ab8 chore(deps): bump urllib3 from 2.7.0 to 2.8.0 (#4964)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.7.0...2.8.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.8.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-30 11:15:36 -05:00
Sam Dornan 0a25b384fd fix(auth): hash passwords with bcrypt directly and upgrade to bcrypt 5 (#4916) 2026-09-30 10:51:32 -04:00
renovate[bot] 6d1bbab087 chore(deps): update dependency streaming-form-data to v2 (#4924) 2026-09-28 22:30:40 -04:00
renovate[bot] b6181f05b3 chore(deps): update dependency ipykernel to v7 (#4919) 2026-09-28 22:01:53 -04:00
renovate[bot] 5a891ed448 chore(deps): update dependency certifi to v2026 (#4915) 2026-09-28 20:49:33 -04:00
renovate[bot] 99675a4db5 chore(deps): update dependency pytest-cov to v7 (#4911) 2026-09-28 19:45:10 -04:00
Georges-Antoine AssiandClaude Opus 5.5 8d7566e567 fix(auth): address Greptile review on OIDC CA bundle loading
Skip CA files that can't be read instead of failing startup, type the
PKI test fixture, and declare certifi as a direct dependency.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 16:53:03 -04:00
Sam DornanandClaude Opus 5.5 6b13fd1698 chore(deps): bump redis to 8.1 and fakeredis to 2.38, drop types-redis (#4844)
* chore(deps): bump redis to 8.1 and fakeredis to 2.38

redis-py 6.2.0 -> 8.1.0 and fakeredis 2.30.1 -> 2.38.0. RQ 2.12
(redis!=6,>=3.5) and fakeredis (redis>=4.3) both accept redis 8.

fakeredis 2.38 types FakeServer's version argument as a tuple, so pass
(7,) instead of 7. Behaviour is unchanged since fakeredis normalises an
int to a one-element tuple.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014wzuPg8vDEjsQ8xqvZgFwx

* chore(deps): drop types-redis in favour of redis-py's own types

types-redis only covers redis 4.6 and shadowed the inline types that
redis 8 ships, so mypy was checking calls against a stale API. Removing
it also drops its transitive stub packages (types-cffi, types-pyopenssl,
types-setuptools), which nothing else uses.

redis-py's types differ from the stubs in three ways:
- Redis, AsyncRedis and Pipeline are not generic, so drop the [str] and
  [bytes] parameters.
- Responses are typed bytes | str regardless of decode_responses, so cast
  at the few call sites that rely on the decoded (or raw) type.
- watch, unwatch, multi, aclose and execute_command are unannotated, so
  add redis to untyped_calls_exclude, as is done for rq and apprise.

Also replace setex, deprecated in redis 8, with set(..., ex=...).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014wzuPg8vDEjsQ8xqvZgFwx

* fix(device-auth): replace deprecated GETSET with SET ... GET

code-review step. GETSET is deprecated since Redis 6.2 in favour of
SET with GET. Using it with ex= also sets the poll key's TTL in the same
command, instead of a separate EXPIRE that a crash could skip.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014wzuPg8vDEjsQ8xqvZgFwx

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-27 13:28:09 -05:00
Sam Dornan a89f7167a2 fix(deps): bump asyncssh, click, pygments and requests for open advisories (#4833) 2026-09-27 10:23:29 -04:00
Sam Dornan 23191407c1 chore(backend): replace zstandard with stdlib compression.zstd (#4831) 2026-09-26 21:20:34 -04:00
Sam Dornan 3206bc541f chore(deps): move from httpx to httpx2 (#4830) 2026-09-26 21:17:13 -04:00
Sam Dornan 0c6e85f923 chore(deps): upgrade Authlib to 1.8 and joserfc to 1.7 (#4829) 2026-09-26 21:10:35 -04:00
Sam Dornan 3679c42732 chore(mypy): report untyped imports instead of disabling the check (#4828) 2026-09-26 20:41:04 -04:00
Georges-Antoine AssiandClaude Opus 5.5 0f219b268b fix(deps): bump mariadb connector to 1.1.14 for Python 3.14
1.1.12 predates Python 3.14 support and has NULL-dereference crashes
(CONPY-318, CONPY-306) fixed in 1.1.13 and 1.1.14. The image moved to
Python 3.14 in 5.3.0, which matches reports of alembic segfaulting inside
_mariadb.cpython-314 at startup.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-26 13:58:33 -04:00
zurdiandClaude Opus 5.5 8089040bfd feat(notifications): rebuild notification channels on Apprise
Forward notifications to any of the 100+ services Apprise reaches instead
of the two hand-coded webhook formats. The channel form lists every
Apprise service with the fields it takes, and the backend builds the
Apprise URL from them.

- New `apprise` channel type, admin only: Apprise opens its own
  connections, past the SSRF guard. The owner's role is checked again at
  every delivery.
- GET /api/notification-channels/apprise-services describes each service
  from Apprise's plugin details: URL tokens as fields, options as
  advanced fields. A field is required only when every URL template
  needs it.
- A channel stores the service and its fields sealed; the URL is built
  from the template those fields fill at each send. Local schemas, the
  options that read files and the ones RomM sets are never offered.
  Apprise follows no redirects, does not retry and its timeouts are
  capped.
- The RomM JSON webhook keeps its payload and HMAC signature; its
  Discord and ntfy formats go, Apprise covers them. Email is unchanged.
- The v2 dialog picks the type from one searchable list and renders the
  service's fields, options folded under "Advanced options".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 09:01:39 +02:00
Sam Dornan b834b35cb4 chore(deps): bump fastapi to 0.141.1 and replace fastapi-pagination with a local page model (#4715) 2026-09-24 21:09:04 -04:00
Sam DornanandClaude Opus 5.5 ef7ad548da build(deps): bump uvicorn to 0.53 and uvicorn-worker to 0.4
uvicorn 0.35 predates official Python 3.14 support (added in 0.38), and
uvicorn-worker 0.4 requires uvicorn>=0.36. The lock also moves
websockets from 12.0 to 17.1, since uvicorn's standard extra now needs
websockets>=13 for its default websockets-sansio implementation.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013rrhKiFFB4CKzyVDXf3oHT
2026-09-23 01:19:39 +00:00
Sam DornanandClaude Opus 5 0b37017dcd build: pin mypy to the 2.3 patch line and trim the exclude comment
`~= 2.3` allowed any release below 3.0, so a later `uv lock` could pick
2.4 while Trunk stayed on 2.3.0 and quietly reintroduce the skew this
change exists to remove. `~= 2.3.0` holds the same minor line as Trunk.
The resolved version is unchanged at 2.3.1; only the recorded specifier
moves in the lockfile.

The config comment now states what the current value is rather than what
the previous one did.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SPpv6W2ygP9tQ61fTQxdYp
2026-09-20 17:53:22 +00:00
Sam DornanandClaude Opus 5 c0f290e9b8 build: align the mypy dev dependency with the version CI enforces
`pyproject.toml` asked for `mypy ~= 1.19` (lock: 1.19.1) while
`.trunk/trunk.yaml` runs `[email protected]`, so `uv run mypy` and the build
were a major version apart and could disagree on the same file.

Moving the dependency up rather than pinning Trunk down keeps CI
enforcement exactly as it is today and changes only the local side. The
two agree: over the whole backend, 2.3.1 and 2.3.0 produce byte-identical
output (151 errors in 39 files).

The lockfile moves mypy and its three transitives (ast-serialize, librt,
pathspec). None is reachable from application code, so the runtime
dependency set is unchanged.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SPpv6W2ygP9tQ61fTQxdYp
2026-09-20 17:45:18 +00:00
Sam DornanandClaude Sonnet 5 3a01f6d359 test(backend): stop the suite emitting warnings (#4597)
* test(backend): stop the suite emitting warnings

The backend suite reported 4838 warnings. Three sources, all now clear:

- 18 uses of the deprecated HTTP_422_UNPROCESSABLE_ENTITY, renamed to
  HTTP_422_UNPROCESSABLE_CONTENT.
- Unawaited coroutines in the streaming and scan tests. A bare MagicMock
  drops the coroutine handed to spawn_sync_task, and a bare AsyncMock's
  return_value is itself an AsyncMock, so the to_dict() call on it leaked
  out of the scan handler.
- About 4780 from sentry-sdk 2.32 and opentelemetry 1.36 calling
  asyncio.iscoroutinefunction, which Python 3.14 deprecates and 3.16
  removes. Bumping both in the lock clears them.

The remaining starlette warning wants httpx2 in place of the httpx 0.27 the
metadata providers pin, so it is filtered rather than fixed: a second HTTP
stack for the test client is a larger change than the warning justifies.

4815 passed, 2 skipped, 0 warnings.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* test(backend): address review on the warning fixes

Greptile flagged the pytest.ini rationale as over the two-line comment limit,
and the new scan fake as untyped. Both fixed: the filter comment is one
non-obvious fact, and the fake now takes `scan_stats` as a typed keyword-only
parameter, which is a real contract rather than `**kwargs`.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5 <[email protected]>
2026-09-17 13:33:48 -05:00
Sam DornanandClaude Opus 5 3491bc8f46 chore(deps): upgrade rq to 2.12 (#4428)
RomM runs `rq cron` as a long-lived process, and 2.12 fixes the case
that process is most exposed to: CronScheduler.heartbeat() now re-creates
its Redis hash when the key has expired, so a scheduler whose host slept
past the 120s TTL comes back registered instead of running unlisted. The
TTL itself moves to DEFAULT_CRON_SCHEDULER_TTL, shared with the registry
cleanup threshold that prunes it, so the two can no longer drift apart.

2.12 also adds a CronJobRegistry, which makes a cron job's history
readable without an active scheduler. Nothing reads it yet; the task
endpoints report queue and job state, not cron history.

The one API removed, CronScheduler.save_jobs_data(), is internal to the
scheduler loop and is not called here. cron_config.py only calls
cron.register().

The constraint stays under 3.0 for the reasons the 2.11 bump recorded:
that release moves get_current_job() to contextvars, reworks dependency
handling behind a ReadyJobRegistry, and changes the
Worker.handle_job_success() signature, which RomMWorker subclasses around.


Claude-Session: https://claude.ai/code/session_01EXV6RTfrRjgH88P9CrtYPQ

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-10 18:03:19 -05:00
Georges-Antoine AssiandClaude Opus 5 a3aecdf045 chore(python): restore the C accelerators lost on 3.14
The runtime moved to 3.14 but the pinned versions did not, so packages
without cp314 wheels silently resolved to their pure-Python universal
wheels. Bump each to the first release that ships cp314 wheels, all
within the existing pyproject specs:

- SQLAlchemy 2.0.41 -> 2.0.52 (cyextension, and greenlet is back so
  sqlalchemy.ext.asyncio is functional rather than merely importable)
- multidict, propcache, frozenlist (aiohttp/yarl accelerators)
- wrapt 1.17.2 -> 1.17.3 (OpenTelemetry instrumentation proxies)
- coverage 7.9.2 -> 7.16.0 (CTracer, and CI runs the suite under --cov)
- mysql-connector-python 9.3.0 -> 9.7.0 (C extension protocol)
- debugpy 1.8.14 -> 1.8.21 (pydevd accelerators)
- pyinstrument 5.0.3 -> 5.1.3 (no longer compiled from sdist on every
  `uv sync --all-extras`, which broke the no-toolchain dev setup)
- anyio 4.9.0 -> 4.14.2, dropping a PEP 765 SyntaxWarning printed on
  every process start

Run pytest and the migrations workflow when the runtime or the lock
changes: nothing in the 3.14 bump lives under `backend/`, so neither
workflow triggered on it. `e2e.yml` already listed those paths.

Make `.python-version` the single home for the version: `uv python
install` and `actions/setup-python` both read it. In the dev Dockerfile
that also fixes the interpreter layer not being invalidated when the pin
changes, and the sigil install now derives site-packages from the venv.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-05 21:48:52 -04:00
Sam DornanandClaude Fable 5.1 3c547dfbd0 chore(python): move the backend to Python 3.14
Bumps the runtime everywhere it is pinned: requires-python, the
.python-version uv reads, both Dockerfiles (with the python:3.14-alpine3.23
and uv 3.14 image digests), the six workflows that install Python, and the
contributor docs.

Several locked C-extension versions had no cp314 wheels, so the Alpine
image fell back to building them from source and failed on the missing
C++ and Rust toolchains. Those packages are upgraded within their existing
pyproject ranges: pydantic 2.11.7 -> 2.13.5 (pydantic-core 2.46.5), uvloop
0.22.1, grpcio 1.83.1, httptools 0.8.0, inflate64 1.0.4, markupsafe 3.0.3,
pyyaml 6.0.3 and streaming-form-data 1.20.0. The lockfile also drops the
3.13-only resolution branches.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-05 08:57:10 -05:00
dependabot[bot] b4e493cfb7 chore(deps): Bump cryptography from 49.0.0 to 50.0.0
Bumps [cryptography](https://github.com/pyca/cryptography) from 49.0.0 to 50.0.0.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/49.0.0...50.0.0)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 50.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-04 07:40:07 +00:00
Georges-Antoine Assi 32f9e338e7 Merge pull request #4274 from sdornan/claude/rq-native-scheduler
refactor(tasks): schedule with RQ instead of rq-scheduler
2026-09-03 11:50:20 -04:00
Sam DornanandClaude Fable 5.1 b13a2373fb chore: drop the vcrpy exclude-newer override
The override let vcrpy 8.2.1 past the rolling 7-day exclude-newer window
on the day after its release. The window has since caught up, and the
fixed 2026-06-17 cutoff was now holding vcrpy back from 8.3.0. The
aiohttp 3.14 compatibility fix the comment referred to landed in 8.2.0
and is present in every later release, so nothing needs the override.

Upgrade vcrpy to 8.3.0 in the lock so the change exercises what the
removal permits; all cassette-backed tests pass on it.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-02 18:41:22 -05:00
Sam DornanandClaude Opus 5 535db9a415 chore(deps): drop the rq freshness-window exclusion
The rolling seven-day window has reached rq 2.11.0, so `rq ~= 2.11`
resolves without an exclusion of its own.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 15:02:04 -05:00
Sam DornanandClaude Opus 5 4e59217275 refactor(tasks): schedule with RQ instead of rq-scheduler
rq-scheduler has one release since 2023, 109 open issues, and RomM ran a
fork of it for Redis username and SSL options that upstream never took.
Everything it was here for now ships with RQ.

Its two failure modes were the reason for the workarounds in 9e9f59c04.
It reads a job's function name before taking the job out of its registry,
so one unreadable job stalls it for good; RQ's scheduler removes every id
it looked at whether or not the job could be read. And cancelling a
delayed job needed both `Scheduler.cancel` and `Job.cancel`, because the
first left the status alone and the second left the registry entry, which
the scheduler then queued anyway; `Job.cancel` on its own now clears the
scheduled registry.

Delayed jobs, which is how the watcher defers a rescan, go onto the queue
with `Queue.enqueue_in` and are released by the worker running with
`--with-scheduler`. Periodic tasks are declared in `tasks/cron_config.py`
and loaded by an `rq cron` process, replacing `rqscheduler`. A task is
registered only when it is enabled and has a cron string, so the
schedule-then-unschedule dance around the env toggles is gone, and with
it `PeriodicTask.init/schedule/unschedule`.

Jobs are enqueued by task name through `run_task_by_name`, resolved
against a catalog in `tasks/registry.py`. Nothing pickles a task instance
into Redis any more, which is what made a payload unreadable across
upgrades in the first place. The catalog also gives the tasks endpoint
one home for what a task is, rather than a list of its own.

Scan discovery keys off the type a job carries rather than the scheduled
rescan's function name, since every task now shares one entry point. That
also drops SCAN_LIBRARY_TASK_FUNC, which only existed to name a function
across an import cycle.

The watcher's dedupe worked on `job.args[0]` while scans are enqueued with
keyword arguments, so it never matched and every filesystem change
scheduled another scan. It reads `platform_ids` from the payload now, and
deliberately ignores a scan already running: that one may have walked past
the folder that just changed.

Startup clears what the old scheduler left in Redis, once.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 15:02:04 -05:00
Sam DornanandClaude Opus 5 ac52682495 chore(deps): upgrade rq to 2.11
The lockfile sat on 2.9.0 while the constraint allowed anything under
3.0, so the floor now names the version the code is tested against.

2.11 carries what the scheduler work ahead needs: RQScheduler acquires
and refreshes its lock before enqueueing, each CronJob has a name and
keeps the ids of the jobs it created, and calling create_cron() twice no
longer duplicates jobs. 2.10 added webhook notifications and a stable
scheduler identity, and 2.9.1 covers redis-py >= 8.

2.11.0 was published inside the rolling 7-day window, so it needs a
per-package exclusion until 2026-08-24, when the window reaches it and
the entry can go.

The constraint stays under 3.0 deliberately. That release moves
get_current_job() to contextvars, reworks dependency handling behind a
ReadyJobRegistry, and changes the Worker.handle_job_success() signature,
which RomMWorker subclasses around.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 15:02:04 -05:00
dependabot[bot] 9098b4d165 chore(deps): Bump tornado from 6.5.7 to 6.5.8
Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.5.7 to 6.5.8.
- [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst)
- [Commits](https://github.com/tornadoweb/tornado/compare/v6.5.7...v6.5.8)

---
updated-dependencies:
- dependency-name: tornado
  dependency-version: 6.5.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-01 21:13:50 +00:00
dependabot[bot] d8f4641f03 chore(deps): Bump asyncssh from 2.23.0 to 2.23.1
Bumps [asyncssh](https://github.com/ronf/asyncssh) from 2.23.0 to 2.23.1.
- [Changelog](https://github.com/ronf/asyncssh/blob/develop/docs/changes.rst)
- [Commits](https://github.com/ronf/asyncssh/compare/v2.23.0...v2.23.1)

---
updated-dependencies:
- dependency-name: asyncssh
  dependency-version: 2.23.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-08-27 17:13:23 +00:00
Sam DornanandClaude Opus 5 e93eb879a2 chore(deps): bump starlette from 1.0.1 to 1.6.0
Drop the `exclude-newer-package` pin that froze starlette resolution at
1.0.1, and widen the version specifier to allow the 1.6.x line.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 09:00:58 -05:00
dependabot[bot] 7bd3f64b0b chore(deps): bump aiohttp from 3.14.1 to 3.14.3
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.14.1 to 3.14.3.
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.14.1...v3.14.3)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-version: 3.14.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-08-04 21:21:11 +00:00
dependabot[bot] e77dd2c34d build(deps): bump pydantic-settings from 2.14.1 to 2.14.2
Bumps [pydantic-settings](https://github.com/pydantic/pydantic-settings) from 2.14.1 to 2.14.2.
- [Release notes](https://github.com/pydantic/pydantic-settings/releases)
- [Commits](https://github.com/pydantic/pydantic-settings/compare/v2.14.1...v2.14.2)

---
updated-dependencies:
- dependency-name: pydantic-settings
  dependency-version: 2.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-07-21 11:57:04 +00:00
dependabot[bot] 00345956e0 build(deps): bump pillow from 12.2.0 to 12.3.0
Bumps [pillow](https://github.com/python-pillow/Pillow) from 12.2.0 to 12.3.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/12.2.0...12.3.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-version: 12.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-07-21 10:10:45 +00:00
dependabot[bot] 6f834ae29b chore(deps): bump joserfc from 1.6.7 to 1.6.8
Bumps [joserfc](https://github.com/authlib/joserfc) from 1.6.7 to 1.6.8.
- [Release notes](https://github.com/authlib/joserfc/releases)
- [Changelog](https://github.com/authlib/joserfc/blob/main/docs/changelog.rst)
- [Commits](https://github.com/authlib/joserfc/compare/1.6.7...1.6.8)

---
updated-dependencies:
- dependency-name: joserfc
  dependency-version: 1.6.8
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-07-04 16:19:40 +00:00
SpinnichandClaude Fable 5 174fad915e fix(retroachievements): hash GameCube and Wii RVZ/WIA images natively
RAHasher can't read the block-compressed RVZ/WIA containers Dolphin
creates, so GameCube and Wii games stored as .rvz/.wia never matched on
RetroAchievements ("Not a Gamecube disc" / "Not a supported Wii file").

Add utils/rvz_hasher.py, which reconstructs only the disc byte ranges
the RA hash covers, mirroring rcheevos:

- An RVZ/WIA reader with random access over raw-data and partition
  groups (NONE/bzip2/LZMA/LZMA2/Zstandard codecs, RVZ packing with the
  lagged-Fibonacci junk PRNG, and stored hash exceptions).
- GameCube: MD5 of the boot header, apploader and main.dol segments.
- Wii: the hash additionally covers encrypted cluster bytes, so the
  reader recalculates the H0/H1/H2 hash tree, applies the container's
  hash exceptions and re-encrypts clusters with the embedded title key
  (AES-128-CBC) to reproduce the exact retail disc bytes.

RAHasherService tries the native path for .rvz/.wia on the GameCube and
Wii platforms and falls back to RAHasher on any failure.

Verified against Mario Kart: Double Dash!! (USA) and Super Mario Galaxy
(USA) RVZ dumps: the computed hashes are present in the official RA
hash lists (games 7693 and 189), and RAHasher 1.8.3 produces identical
hashes when run on disc images reconstructed by the same reader.

Closes #3649
Closes #3650

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-01 21:58:10 +00:00
Georges-Antoine Assi 9740793673 Merge pull request #3628 from rommapp/dependabot/uv/python-socketio-5.16.2
build(deps): bump python-socketio from 5.14.0 to 5.16.2
2026-06-29 10:10:42 -04:00
Georges-Antoine Assi 6b5300771a Merge pull request #3627 from rommapp/dependabot/uv/joserfc-1.6.7
build(deps): bump joserfc from 1.6.3 to 1.6.7
2026-06-29 10:04:48 -04:00
dependabot[bot] d2d2b87a9f build(deps): bump python-socketio from 5.14.0 to 5.16.2
Bumps [python-socketio](https://github.com/miguelgrinberg/python-socketio) from 5.14.0 to 5.16.2.
- [Release notes](https://github.com/miguelgrinberg/python-socketio/releases)
- [Changelog](https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md)
- [Commits](https://github.com/miguelgrinberg/python-socketio/compare/v5.14.0...v5.16.2)

---
updated-dependencies:
- dependency-name: python-socketio
  dependency-version: 5.16.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-06-29 11:42:28 +00:00