Files
rippy/docker/api/image_downloader.py
T
Hitonabi 0ea5f10b31
Ampel / ampel (push) Failing after 12m31s
Fix-Runde nach Review: alle Befunde behoben + echte Tests
- Metadaten-Preview WIEDERHERGESTELLT (Stub ueberschattete echte
  prescan-Implementierung), tote Altmodule geloescht
- Celery update_state statt Phantom-Task/erfundener API
- abcde-Kommando korrigiert (CD-Ripping war nie funktionsfaehig)
- JWT: fester Schluessel Pflicht, echtes Logout, Cleanup nur Abgelaufene
- main.py: crashende Endpoints (Path/secrets/api_keys), year-Bug,
  Admin-Login aus .env
- Ruff gruen (29 Funde), Tests: auth/cache_keys/ripping_helpers,
  Placebo-test_health raus
- SAVEPOINT: offene MakeMKV-Entscheidung SICHTBAR gemacht (Regel B)
2026-07-22 19:31:48 +02:00

111 lines
3.9 KiB
Python

"""Jellyfin Image Downloader."""
import requests
from pathlib import Path
from typing import Dict, Optional
from clients.tmdb import TMDBClient
from clients.thetvdb import TheTVDBClient
class ImageDownloader:
def __init__(self):
self.tmdb = TMDBClient()
self.thetvdb = TheTVDBClient()
self.base_url = "https://image.tmdb.org/t/p"
def download_image(self, url: str, output_path: Path, width: int = 500) -> bool:
"""Lade Image herunter."""
try:
# TMDB URL anpassen
if url.startswith("https://image.tmdb.org"):
# Konvertiere zu gewünschter Größe
path = url.replace(f"{self.base_url}/", "")
url = f"{self.base_url}/w{width}/{path}"
response = requests.get(url, timeout=30)
response.raise_for_status()
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'wb') as f:
f.write(response.content)
return True
except Exception as e:
print(f"Image download error: {e}")
return False
def download_poster(self, title: str, output_dir: Path, width: int = 500) -> Optional[Path]:
"""Lade Poster herunter."""
# TMDB Search
movies = self.tmdb.search_movie(title)
if movies:
movie = movies[0]
images = self.tmdb.get_movie_images(movie["id"])
if images.get("poster"):
output_path = output_dir / "poster.jpg"
if self.download_image(images["poster"], output_path, width):
return output_path
return None
def download_fanart(self, title: str, output_dir: Path, width: int = 1920) -> Optional[Path]:
"""Lade Fanart herunter."""
# TMDB Search
movies = self.tmdb.search_movie(title)
if movies:
movie = movies[0]
images = self.tmdb.get_movie_images(movie["id"])
if images.get("fanart"):
output_path = output_dir / "fanart.jpg"
if self.download_image(images["fanart"], output_path, width):
return output_path
return None
def download_series_images(self, title: str, output_dir: Path) -> Dict[str, Optional[Path]]:
"""Lade Serien-Poster und Fanart herunter."""
result = {
"poster": None,
"fanart": None
}
tv_shows = self.tmdb.search_tv(title)
if tv_shows:
tv = tv_shows[0]
images = self.tmdb.get_tv_images(tv["id"])
if images.get("poster"):
output_path = output_dir / "poster.jpg"
if self.download_image(images["poster"], output_path, 500):
result["poster"] = output_path
if images.get("fanart"):
output_path = output_dir / "fanart.jpg"
if self.download_image(images["fanart"], output_path, 1920):
result["fanart"] = output_path
return result
def download_music_images(self, artist: str, album: str, output_dir: Path) -> Dict[str, Optional[Path]]:
"""Lade Musik-Album-Cover herunter (via TMDB als Fallback)."""
result = {
"album": None
}
# TMDB Search für Soundtracks
query = f"{album} soundtrack"
movies = self.tmdb.search_movie(query)
if movies:
movie = movies[0]
images = self.tmdb.get_movie_images(movie["id"])
if images.get("poster"):
output_path = output_dir / "album.jpg"
if self.download_image(images["poster"], output_path, 500):
result["album"] = output_path
return result