Two changes, verified with local builds:
- Drop UV_COMPILE_BYTECODE=1: shipped .pyc files were 51MB. The venv is
root-owned and the app runs long-lived as 'ab', so bytecode only saved
a few seconds of import time once per container start. This also
matches the boot_overlay uv-sync path, which never compiled bytecode.
- mcp[cli] -> mcp: the app only imports mcp.server; the cli extra pulled
typer/rich/pygments/markdown-it (~14MB) for an unused console script.
python-dotenv, the extra's other member, is already a direct dep.
Compressed pull size drops 64.2MB -> 48.8MB. Image verified: packages
absent, no __pycache__, 'import main' succeeds; pytest and mypy green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEnmRvBJL93fAURbRf1koK
Bump version, uv lock, and CHANGELOG for 3.3.0-beta.5 — ships the
overlayfs EXDEV fix for in-app updates (needs a fresh image to take
effect) and moves the Software Update card into Settings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
CHANGELOG: fold the unreleased in-app updater + multi-provider LLM
entries into 3.3.0-beta.2 and add the WebUI UX/a11y/perf pass and
post-review backend fixes. docs/changelog/3.3.md (the release body)
gains the beta.2 highlights.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
Closes the update-chain trust gap: the sha256 came from the same GitHub
release as the bundle (integrity, not authenticity), and the boot overlay
re-applied ab-writable content as root — including uv sync on an
attacker-controllable lockfile.
- signing: new module/update/signing.py verifies an ed25519 signature;
public key embedded in the image at /app/ab_update_pubkey.pem (outside
the overlay-replaceable tree, so it is the trust root). Private key lives
only in CI (UPDATE_SIGNING_KEY secret).
- updater: discover the .zip.sig asset, verify the signature after the
sha256 check, reject any release without a signature, retain the verified
bundle.zip+.sig for boot re-verification, and swap them on rollback.
- boot_overlay: re-verify the signed bundle at every boot and extract the
module tree / webui dist FROM the verified zip — never from the
ab-writable current/ tree; read the version from the zip manifest, not
the ab-writable applied.json; drop to the ab user before any fallback
uv sync so lockfile build hooks can't run as root; zip-slip guard uses
is_relative_to (also fixed in updater._safe_extract).
- CI: build.yml signs the bundle with UPDATE_SIGNING_KEY and publishes the
.zip.sig; the build fails if the secret is unset.
- deps: cryptography made an explicit dependency.
Tests cover bad-signature reject, unsigned-release reject, legacy overlay
without a signed bundle reject, verified-bundle retention, and boot-overlay
signature verification. Full backend suite: 1079 passed.
Ops: run `gh secret set UPDATE_SIGNING_KEY < ~/.autobangumi/update-signing-key.pem`
before the 3.3 release.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
Generalizes the OpenAI-only title parser into a provider-dispatching
LLMParser (openai-compatible / Anthropic / Gemini) with a parse-mode
switch:
- fallback (default): regex parser runs first, LLM only rescues titles
the regex can't handle — minimal LLM spend
- primary: LLM parses every title first, regex is the safety net so no
title is dropped on LLM failure
The openai provider takes a base_url, covering any OpenAI-compatible
endpoint (DeepSeek, Ollama, LM Studio, OpenRouter, OneAPI). Anthropic
uses structured JSON output with refusal handling; Gemini uses
response_mime_type=application/json.
Config auto-migrates the legacy experimental_openai section into a new
llm section on load (migrated users get mode=primary, preserving their
original LLM-first behavior); the old section is kept for downgrade
safety and llm.api_key is redacted by the config API. Settings page
swaps the OpenAI panel for an LLM panel with provider + mode selects.
1018 backend tests, mypy 0, ruff clean; 131 frontend tests, vue-tsc clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTnuEgR78cBk32bLNKar3z
Drop python-jose and passlib in favor of direct pyjwt (with pinned
decode algorithm) and bcrypt 4.x hashpw/checkpw calls. Existing
passlib-generated $2b$ hashes keep validating unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTnuEgR78cBk32bLNKar3z
- Decouple HTTPS scheme selection from TLS certificate verification:
`verify=False` always, since self-signed certs are the norm for
home-server/NAS/Docker qBittorrent setups
- Bump connect timeout from 3.1s to 5.0s for slow TLS handshakes
- Add actionable error messages when HTTPS connection fails
- Fix `continue` → `break` bug in torrents_rename_file verification loop
- Consolidate json imports to top-level
- Add 31 unit tests for QbDownloader constructor, auth, and error handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- useAuth: replace watcher with explicit router.replace on login/logout
- useMyI18n: create single i18n instance at module level (avoid dupes)
- usePasskey: detect WebAuthn support synchronously (no onMounted)
- main.ts: import i18n from hook module instead of calling composable
- ab-add-rss: hoist useApi composables outside functions to avoid
recreating them on each call
- calendar: prevent duplicate refreshes when already refreshing
- downloader: guard interval polling against stale activation state
- router: only mark setupChecked on successful status check
- log store: stop SSE log updates on logout
- i18n: add missing "edit" translation key (en + zh-CN)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When users have a SOCKS proxy configured (via HTTP_PROXY or ALL_PROXY
environment variables), httpx's AsyncClient automatically tries to use
it but fails without the socksio package installed.
Changed httpx dependency from httpx>=0.25.0 to httpx[socks]>=0.25.0 to
include the socksio package as an extra dependency.
Fixes#961
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- Update requires-python to >=3.13 in pyproject.toml
- Update ruff and black target versions to py313
- Update Dockerfile to use python:3.13-alpine
- Add explicit Python 3.13 setup in CI workflow
- Regenerate uv.lock for Python 3.13
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use RSS type instead of non-existent RSSItem/RSSResponse
- Add expire field to mockLoginSuccess
- Replace offset with episode_offset/season_offset in mockBangumiAPI
- Add needs_review_reason field to mockBangumiAPI
- Add missing RSS fields (connection_status, last_checked_at, last_error)
- Fix generic types in test utilities
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cover RSS engine, downloader, renamer, auth, notifications, search,
config, API endpoints, and end-to-end integration flows. When all
210 tests pass, the program's key behavioral contracts are verified.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- Fix search store exports to match component expectations (inputValue,
bangumiList, onSearch) and transform data to SearchResult format
- Fix poster endpoint path check that incorrectly blocked all requests
- Add resolvePosterUrl utility to handle both external URLs and local paths
- Move tags into hover overlay on homepage cards and calendar cards
- Show title and tags on poster hover with dark semi-transparent styling
- Add downloader API, store, and page
- Update backend to async patterns and uv migration changes
- Remove .claude/settings.local.json from tracking
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace pip + requirements.txt with uv for dependency management.
- Multi-stage Dockerfile using ghcr.io/astral-sh/uv builder image
- CI updated to use astral-sh/setup-uv@v4
- Ruff config moved to [tool.ruff.lint] (fixes deprecation)
- Transitive deps removed, missing direct deps added (requests, PySocks, urllib3)
- Database layer migrated to async (AsyncSession + aiosqlite)
- Tests updated to match async database interface
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>