Files
rippy/docker/api/clients/omdb.py
T
Hitonabi 90eb17d407
Ampel / ampel (push) Failing after 38s
UX-Runde: echte Disc-Titel via BD-Metadaten, Preview-Crash, Dashboard, Ziele
Commander-Befunde 23.07. abends:
1. Metadaten "klappen nicht": Wurzel = kryptisches Volume-Label + kein
   TMDB-Key. Jetzt: API mountet die Disc read-only (CAP_SYS_ADMIN ist da)
   und liest den KLARTEXT-Titel aus BDMV/META/DL/bdmt_*.xml; dazu
   progressive Suchdegradation (Titel-Varianten) und OMDb-Unscharf-Suche
   (s= + imdbID-Nachladen) — mit dem vorhandenen OMDb-Key gibt es damit
   Titel/Jahr/Poster auch ohne TMDB
2. Weisses Fenster beim Pre-Scan: Lucide-Icons sind forwardRef —
   Direktaufruf getIcon(...)({size}) crashte die Seite; als JSX gerendert
3. Dashboard sortiert: System-Leiste (Encoder + aktiver Job) oben,
   Disc/Geraete -> Stats -> Jobs, Live-Log ans Ende
4. Ziel-Dialog mit ORDNER-BROWSER (GET /browse, nur unter /app/media);
   Schnellwahl nutzt die Settings-Unterordner statt Hartkodierung;
   Tab "Verzeichnisse" in "Speicherziele" aufgegangen (redundant)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:07:55 +02:00

95 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""OMDb API Client — Fallback-Quelle für die Metadaten-Erkennung.
Kommt zum Zug, wenn TMDB nichts (Sicheres) findet. Kostenloser Key von
https://www.omdbapi.com/apikey.aspx (1000 Anfragen/Tag reichen fürs Heimlab).
"""
from typing import Dict, Optional
import requests
from cache import get, set as cache_set
from config import settings
OMDB_BASE_URL = "https://www.omdbapi.com/"
def parse_runtime_minutes(runtime: str) -> int:
"""OMDb liefert '142 min' als Text → Minuten als Zahl (pure Funktion, testbar)."""
if not runtime:
return 0
teil = runtime.strip().split(" ")[0]
return int(teil) if teil.isdigit() else 0
def parse_year(year: str) -> Optional[int]:
"""OMDb-Jahr kann '1999' oder '20052012' (Serie) sein → erstes Jahr."""
if not year:
return None
erste = year.strip()[:4]
return int(erste) if erste.isdigit() else None
class OMDbClient:
def __init__(self):
# DB-Einstellung (Settings-UI/Wizard) gewinnt gegen die Env-Variable
from db import get_settings
self.api_key = get_settings().get("omdbApiKey") or settings.omdb_api_key
self.session = requests.Session()
def lookup(self, title: str, year: Optional[int] = None) -> Optional[Dict]:
"""Sucht per Titel (t=), liefert normalisierte Metadaten oder None."""
if not self.api_key:
return None
cache_key = f"omdb:{title.lower()}:{year or ''}"
cached = get(cache_key)
if cached:
return cached
params = {"apikey": self.api_key, "t": title, "r": "json"}
if year:
params["y"] = str(year)
try:
response = self.session.get(OMDB_BASE_URL, params=params, timeout=10)
response.raise_for_status()
data = response.json()
# t= ist exakt — wenn leer, unscharfe Suche (s=) und den besten
# Treffer per imdbID nachladen
if data.get("Response") != "True":
suche = self.session.get(
OMDB_BASE_URL,
params={"apikey": self.api_key, "s": title, "r": "json"},
timeout=10,
).json()
treffer = (suche.get("Search") or []) if suche.get("Response") == "True" else []
if treffer:
data = self.session.get(
OMDB_BASE_URL,
params={"apikey": self.api_key, "i": treffer[0]["imdbID"], "r": "json"},
timeout=10,
).json()
except Exception as e:
print(f"OMDb API Error: {e}")
return None
if data.get("Response") != "True":
return None
ergebnis = {
"type": "tv" if data.get("Type") == "series" else "movie",
"id": data.get("imdbID", ""),
"title": data.get("Title", title),
"year": parse_year(data.get("Year", "")),
"overview": data.get("Plot", ""),
"poster_path": data.get("Poster", "") if data.get("Poster") != "N/A" else "",
"backdrop_path": "",
"runtime": parse_runtime_minutes(data.get("Runtime", "")),
"genres": [g.strip() for g in data.get("Genre", "").split(",") if g.strip()],
"source": "omdb",
}
cache_set(cache_key, ergebnis)
return ergebnis