Allow serienen/videoen in media handoff

allowed_categories kannte nur serien4k|serien|video4k|video. Die englischen
Arr-Instanzen sonarrEN (Port 8991, Root /data/FHD/serienen) und radarrEN
(Port 7880, Root /data/FHD/videoen) nutzen eigene SAB-Kategorien.

Folge: POST /media/handoff antwortete 422 "Unsupported media category",
movetdarr.sh brach mit "n8n-Handoff konnte nicht registriert werden - kein
Move" ab und Mutiny.2026 x2 (~21 GB) lagen seit 08./09.09.2026 unangetastet
in /usenet/complete/videoen. radarrEN hat den Film weiter monitored,
hasFile=false, Queue leer.

Die Pfadpruefung (expected_prefix) bleibt unveraendert und gilt auch fuer die
neuen Kategorien.

3 neue Tests: serienen+videoen werden geproxyt, erfundene Kategorie bleibt
422, Pfad-Mismatch bei videoen bleibt 422.
6/6 media_handoff-Tests gruen. test_health_exposes_current_version schlug
schon vor dieser Aenderung fehl (Test erwartet 2.4.1, VERSION ist 2.4.6).
This commit is contained in:
Trulla 2026-09-16 12:11:31 +02:00
parent f24809a22a
commit f3b9a0c33a
2 changed files with 98 additions and 1 deletions

6
app.py
View file

@ -4121,7 +4121,11 @@ async def media_handoff(payload: MediaHandoffPayload, request: Request):
_audit("/media/handoff", "POST", 403, f"caller={caller} action={payload.action}")
raise HTTPException(403, "Media handoff caller is not allowed")
allowed_categories = {"serien4k", "serien", "video4k", "video"}
# 16.09.2026: serienen/videoen ergaenzt. Die englischen Arr-Instanzen
# sonarrEN (Port 8991, Root /data/FHD/serienen) und radarrEN (Port 7880,
# Root /data/FHD/videoen) nutzen eigene SAB-Kategorien. Ohne sie brach der
# Handoff mit 422 ab und Releases blieben in /usenet/complete liegen.
allowed_categories = {"serien4k", "serien", "serienen", "video4k", "video", "videoen"}
if payload.action == "start":
if payload.category not in allowed_categories:
raise HTTPException(422, "Unsupported media category")

View file

@ -117,6 +117,99 @@ def test_media_handoff_rejects_wrong_category_path(monkeypatch):
assert response.status_code == 422
def test_media_handoff_accepts_english_arr_categories(monkeypatch):
"""serienen/videoen muessen durchgehen (sonarrEN 8991 / radarrEN 7880).
16.09.2026: fehlten in allowed_categories -> HTTP 422 -> movetdarr.sh
brach mit "n8n-Handoff konnte nicht registriert werden" ab und liess
Mutiny.2026 x2 tagelang in /usenet/complete/videoen liegen.
"""
seen = []
class FakeResponse:
status_code = 200
def json(self):
return {"ok": True, "jobId": "test-job-5678", "state": "registered"}
class FakeClient:
def __init__(self, **_kwargs):
pass
async def __aenter__(self):
return self
async def __aexit__(self, *_args):
return None
async def post(self, url, json, headers):
seen.append(json)
return FakeResponse()
monkeypatch.setattr(app.httpx, "AsyncClient", FakeClient)
with TestClient(app.app) as client:
monkeypatch.setattr(app, "SERVICES", {"n8n": {"url": "http://n8n:5678", "auth": "n8n"}})
for category in ("serienen", "videoen"):
response = client.post(
"/media/handoff",
headers={"Authorization": "Bearer test-token"},
json={
"action": "start",
"category": category,
"directory": f"/usenet/complete/{category}/Release.2026",
"release": "Release.2026-GRP",
"cleanName": "Release 2026",
"expectedFiles": 1,
},
)
assert response.status_code == 200, (category, response.text)
assert response.json()["state"] == "registered", category
assert [item["category"] for item in seen] == ["serienen", "videoen"]
def test_media_handoff_still_rejects_unknown_category(monkeypatch):
"""Fail-closed bleibt: eine frei erfundene Kategorie wird nicht geproxyt."""
monkeypatch.setattr(
app.httpx,
"AsyncClient",
lambda **_kwargs: (_ for _ in ()).throw(AssertionError("must not proxy")),
)
with TestClient(app.app) as client:
response = client.post(
"/media/handoff",
headers={"Authorization": "Bearer test-token"},
json={
"action": "start",
"category": "hoerbuecher",
"directory": "/usenet/complete/hoerbuecher/Buch",
"release": "Buch",
},
)
assert response.status_code == 422
def test_media_handoff_english_category_path_must_match(monkeypatch):
"""Pfadpruefung gilt auch fuer die neuen Kategorien."""
monkeypatch.setattr(
app.httpx,
"AsyncClient",
lambda **_kwargs: (_ for _ in ()).throw(AssertionError("must not proxy")),
)
with TestClient(app.app) as client:
response = client.post(
"/media/handoff",
headers={"Authorization": "Bearer test-token"},
json={
"action": "start",
"category": "videoen",
"directory": "/usenet/complete/video4k/Wrong",
"release": "Wrong",
},
)
assert response.status_code == 422
def test_paperless_import_queues_pdf_through_butler(monkeypatch):
captured = {}