"""Explicit original-language requests without changing shared quality defaults.""" import asyncio import copy import hashlib import json import re import httpx from fastapi import HTTPException _profile_lock = asyncio.Lock() _prefix = "Magent Original " def language_info(details): code = str(details.get("originalLanguage") or details.get("original_language") or "").lower() if not re.fullmatch(r"[a-z]{2}", code) or code in {"en", "xx", "zz"}: return None return {"code": code} def profile_body(profile): return {key: copy.deepcopy(value) for key, value in profile.items() if key not in {"id", "name"}} def profile_name(body): return _prefix + hashlib.sha256(json.dumps(body, sort_keys=True).encode()).hexdigest()[:16] def is_original_profile(profile): return ((profile.get("language") or {}).get("id") == -2 and profile.get("name") == profile_name(profile_body(profile))) async def original_profile(client, default_id): # Reuse immutable copies; never edit a profile already used by other titles. async with _profile_lock: try: profiles = await client.get_quality_profiles() except httpx.HTTPError as exc: raise HTTPException(502, "Radarr could not load the language profile. Try again.") from exc if not isinstance(profiles, list): raise HTTPException(502, "Radarr returned invalid quality profiles.") default = next((p for p in profiles if p.get("id") == default_id), None) if not default: raise HTTPException(409, "The default quality profile changed. Reload the request.") body = profile_body(default) body["language"] = {"id": -2, "name": "Original"} name = profile_name(body) match = next((p for p in profiles if p.get("name") == name and profile_body(p) == body), None) if match: return match["id"] try: result = await client.post("/api/v3/qualityprofile", payload={**body, "name": name}) except httpx.HTTPError as exc: raise HTTPException(502, "Radarr could not prepare the original-language profile. Try again.") from exc if not isinstance(result, dict) or not isinstance(result.get("id"), int): raise HTTPException(502, "Radarr could not prepare the original-language profile. Try again.") return result["id"]