fix: resolve Jellyfin usernames to internal Id and harden qBittorrent login

Jellyfin: get_user_id() returned the configured user_id verbatim, so a
username like "admin" hit /Users/admin/Views and got HTTP 400 ("The value
'admin' is not valid."). The index worker already had username->Id
resolution, but the live API paths (dashboard counts, media query) did not.
Route all user-scoped paths through the new JellyfinClient.resolve_user_id()
(exact Id match -> Name match -> first user), cached per service/credentials
in get_user_id() so repeated requests don't re-list users. The worker is
simplified to call the same method.

qBittorrent: _login() raised "qBittorrent login failed: " (empty) on a 200
with an empty body, which happens when base_url doesn't reach the qBittorrent
login handler (wrong URL/path or a reverse proxy misroute) — not a credentials
issue. Now accepts the SID cookie as a success signal (reverse proxies that
mangle the body), returns a clear "invalid username or password" for "Fails.",
and surfaces a diagnostic error (HTTP status + body + base_url/proxy hint) for
any other/empty body.

Tests: new tests/test_jellyfin_client.py (5) + 3 qBittorrent login tests.
Full backend suite (384) passes; ruff clean.
This commit is contained in:
Developer
2026-07-11 11:21:31 +00:00
parent ecabc65dd4
commit 84dcf9e010
12 changed files with 196 additions and 66 deletions
@@ -2,7 +2,7 @@
dir: backend/src/media_library_viewer_api/clients
## role
Provides HTTP and command-line client wrappers for integrating with external media services (Jellyfin, Authentik, Jellyseerr, qBittorrent) and executing local/remote filesystem operations.
Provides external service integration layer with read-only API client wrappers and remote/local execution helpers for aggregating data from media, directory, torrent, and authentication services.
## parent
index: backend/src/media_library_viewer_api/.pi-map.index.md
map: backend/src/media_library_viewer_api/.pi-map.md
@@ -11,6 +11,7 @@ map: backend/src/media_library_viewer_api/.pi-map.md
## files
- __init__.py
- authentik.py
- http_timeout.py
- jellyfin.py
- jellyseerr.py
- local.py
@@ -21,6 +22,6 @@ index: backend/src/media_library_viewer_api/clients/.pi-map.index.md
map: backend/src/media_library_viewer_api/clients/.pi-map.md
## workflows
- change clients behavior
read: __init__.py, authentik.py, jellyfin.py
read: __init__.py, authentik.py, http_timeout.py
## dirty
-