diff --git a/app.py b/app.py index 44508ca..7ddb58a 100644 --- a/app.py +++ b/app.py @@ -12,7 +12,7 @@ from contextlib import asynccontextmanager from contextvars import ContextVar log = logging.getLogger("butler") -VERSION = "2.4.8" +VERSION = "2.4.9" API_DIR = os.environ.get("API_KEY_DIR", "/data/api") VAULT_CACHE_DIR = os.environ.get("VAULT_CACHE_DIR", "/data/vault-cache") @@ -1558,7 +1558,7 @@ MEDIA_VERIFY_PROBES = { class MediaVerifyRequest(BaseModel): host: str = Field(..., max_length=64) path: str = Field(..., max_length=1000) - expected_minutes: float | None = Field(None, gt=0, le=1440) + expected_minutes: float | None = Field(None, ge=0, le=1440) tolerance_pct: float = Field(20.0, gt=0, le=100) @@ -1588,6 +1588,21 @@ async def media_verify(payload: MediaVerifyRequest, _=Depends(_verify)): if not target: raise HTTPException(404, f"Host {payload.host} not found in inventory") + # expected_minutes == 0 or None: no reference runtime available, skip verification gracefully + if not payload.expected_minutes or payload.expected_minutes <= 0: + return { + "host": payload.host, + "path": payload.path, + "duration_seconds": None, + "duration_minutes": None, + "expected_minutes": payload.expected_minutes, + "verified": False, + "suspect": False, + "skipped": True, + "skip_reason": "no_reference_runtime", + "deviation_pct": None, + } + probe_cmd = ( f"docker exec {container} ffprobe -v error " f"-show_entries format=duration -of default=noprint_wrappers=1:nokey=1 {shlex.quote(payload.path)}" diff --git a/tests/test_app.py b/tests/test_app.py index 1bc0857..45011c2 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1006,7 +1006,7 @@ def test_media_verify_returns_502_on_unparsable_ffprobe_output(monkeypatch): response = client.post( "/media/verify", headers={"Authorization": "Bearer test-token"}, - json={"host": "arrapps", "path": "/data/UHD/serien/ep.mkv"}, + json={"host": "arrapps", "path": "/data/UHD/serien/ep.mkv", "expected_minutes": 49.5}, ) assert response.status_code == 502