mediawire: qBittorrent 5 answers a good login with 204 — accept it (found on Tester 1, Part G1); fake answers 204 like the app
gates / gates (push) Successful in 41s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-15 10:02:26 +02:00
parent f580d88a14
commit a09cab124a
3 changed files with 5 additions and 2 deletions
+2
View File
@@ -31,6 +31,8 @@ Not released yet (bake → vouch → floor, `09` §3 decision 247). Design: felh
with the API key named „felhom" read at use from Jellyfin's own database (no key → one household step, said on the
page). Keys read at use, never stored or logged; links never undone when an app stops. Idempotent:
`TestRun_SecondRunWritesNothing` (red-proved: the measured repeated qBittorrent writes).
- **Fixed on Tester 1 (Part G1):** qBittorrent 5 answers a good login with HTTP 204, not 200 — the wiring refused it
(`login: HTTP 204`). Both logins accept 204; the test fake now answers 204 as the real app does (red-proved).
- **Old Sonarr/Radarr installs repaired by themselves (R-1047)** — only when /media is no longer bound: same-path root
folder, `moveFiles:false` editor, rescan, old root removed, Radarr's collections too. `TestRepairOldRoot_K7`
(red-proved: moveFiles=true is caught).
+2 -2
View File
@@ -216,7 +216,7 @@ func (w *Wirer) qbittorrent(drives []Drive, pw string) Result {
form := url.Values{"username": {"admin"}, "password": {pw}}
code, _, hd, err := w.do("POST", base+"/api/v2/auth/login", map[string]string{"Referer": base}, strings.NewReader(form.Encode()), "application/x-www-form-urlencoded")
m := regexp.MustCompile(`((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)`).FindStringSubmatch(strings.Join(hd.Values("Set-Cookie"), "; "))
if err != nil || code != 200 || m == nil {
if err != nil || (code != 200 && code != 204) || m == nil { // qBittorrent 5 answers a good login 204 (measured on Tester 1)
r.State, r.Detail = "error", fmt.Sprintf("login: HTTP %d %v", code, err)
return r
}
@@ -834,7 +834,7 @@ func (w *Wirer) qbLogin(pw string) (string, map[string]string, error) {
form := url.Values{"username": {"admin"}, "password": {pw}}
code, _, hd, err := w.do("POST", base+"/api/v2/auth/login", map[string]string{"Referer": base}, strings.NewReader(form.Encode()), "application/x-www-form-urlencoded")
m := regexp.MustCompile(`((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)`).FindStringSubmatch(strings.Join(hd.Values("Set-Cookie"), "; "))
if err != nil || code != 200 || m == nil {
if err != nil || (code != 200 && code != 204) || m == nil { // qBittorrent 5 answers a good login 204 (measured on Tester 1)
return "", nil, fmt.Errorf("qBittorrent login: HTTP %d %v", code, err)
}
return base, map[string]string{"Referer": base, "Cookie": m[1] + "=" + m[2]}, nil
@@ -84,6 +84,7 @@ func (w *world) server(t *testing.T) *httptest.Server {
return
}
http.SetCookie(rw, &http.Cookie{Name: "QBT_SID_8080", Value: "sid"})
rw.WriteHeader(204) // qBittorrent 5.x: a good login is 204 No Content (measured on Tester 1, 2026-10-15)
case p == "/api/v2/app/preferences":
j(map[string]interface{}{"auto_tmm_enabled": w.autoTMM})
case p == "/api/v2/app/setPreferences":