3.3.0 β async architecture, first-class aria2, movies/specials, security hardening
Merging this PR triggers the 3.3.0 release build (the release job fires on merged PRs from
*dev*branches; version is already bumped to 3.3.0).
Architecture (behavior- and API-compatible)
- Fully async database layer (
sqlite+aiosqlite, WAL + busy_timeout); repositories andDatabaseare async, composition over inheritance Programgod-object replaced by a lifespanAppContextcomposition root with a genericScheduler/PeriodicTask; startup is awaited and aborts on migration failure- Table-driven migrations with
already_appliedguards (v9βv12) DownloaderProtocol with capability flags; qBittorrent session reused across operations (#1039, #900)- Config reloads unified through
AppContext.reload_settings()
Features
- aria2 is now a first-class backend: real querying, gid-based dedup reconciled against aria2's live state, collision-safe filesystem renames
- Movies / OVA / Specials: ε§εΊη/Movie/OVA/SP token parsing (
episode_type), TMDBsearch/moviefallback,Title (Year)movie layout and Season 0 for specials β validated against Mikan's live feed (98/100 titles parsed, movie releases correctly classified) - Per-bangumi release preference: preferred group/resolution with best-release-per-episode dedup (no more double downloads when two groups match)
- Notifications: typed events (RSS feed failure, download-add failure, offset needs-review) and
{{title}}-style templates for every provider - Offset suggestions computed from real parsed episodes + one-click apply endpoints (single/bulk)
- Per-provider parser choice for custom search providers; OpenAI parser now rescues titles the regex parser misses instead of replacing it
- Configurable TMDB / bgm.tv base URLs (#1040, #1042)
- Security: login IP allowlist, MCP CIDR allowlist + Bearer token, WebAuthn/passkey hardening, env-gated dev auth bypass (
AB_DEV_NO_AUTH) - Unauthenticated
GET /health+ DockerHEALTHCHECK - New SSE endpoint (
/api/v1/events/stream) replacing the WebUI's three polling loops
Security & correctness fixes (post-review, all 10 verified findings fixed)
- PyJWT + bcrypt replace EOL
python-jose(CVE-2024-33663/33664) andpasslib; 72-byte truncation preserved so existing long passwords keep working - Failed torrent adds actually retry; duplicates no longer emit failure notifications (
AddResulttri-state) - Filter-rejected torrents no longer pollute offset scanning
- Multi-file movie torrents get distinct filenames; aria2 renames can never overwrite existing files
- Season floor restored: only specials may land in Season 0
- SSE stream can't be frozen by an unreachable downloader (3s bound + explicit degraded payload)
- Destructive API endpoints converted GETβPOST (CSRF hardening)
WebUI
- Component system unified on naive-ui (fixed a theme-token crash that blanked the Config page and restored all settings controls; naive-ui 2.39β2.44 for Vue 3.5 compatibility)
- Oversized editors split into a shared
useBangumiRuleFormcomposable; calendar split into components - RSS refresh buttons (per-feed + all), decluttered RSS table, calendar cards show titles without posters, log page copy fixes, mobile nav labels fixed, WCAG AA contrast pass
- API contract tests (path + verb) for every
api/*.tsmodule
Tooling & CI
- mypy in CI at 0 errors (176+ source files); ruff + frontend lint/vitest gates on dev-branch PRs
- E2E suite green again (67/67) after updating stale expectations
scripts/dev.sh: one-command seeded dev environment (qB + mock RSS + backend + webui)- Version-aware release changelog step; docker-compose example PUID/PGID fix
Test status
Backend: 984 passed (from 792), mypy 0 errors, ruff/black clean. Frontend: 131 passed, vue-tsc clean. E2E (Docker qB + mock RSS): 67/67.
π€ Generated with Claude Code