Files
rippy/docker/api/image_downloader.py
T
Hitonabi 518155051f Etappe 3: Metadaten-Lookup + Pre-Scan
- SQLite-Cache für API-Rate-Limits (LRU, 10k Einträge)
- TMDB/MusicBrainz/TheTVDB Clients
- Pre-Scan-Modul für TOC-Lesung ohne Ripping
- Metadaten-Preview UI
- Jellyfin-Formatierung (NFO + Images)
- API Endpoints für Lookup, Confirm, Format
2026-07-21 17:17:35 +02:00

113 lines
3.9 KiB
Python

"""Jellyfin Image Downloader."""
import requests
from pathlib import Path
from typing import Dict, Optional
from urllib.parse import urlparse
from .clients.tmdb import TMDBClient
from .clients.thetvdb import TheTVDBClient
from .config import settings
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