kv-netflix/backend/image_service.py
2025-12-24 10:50:25 +07:00

61 lines
1.9 KiB
Python

import os
import httpx
import hashlib
from PIL import Image
from io import BytesIO
from fastapi.responses import Response
from typing import Optional
CACHE_DIR = "cache/images"
os.makedirs(CACHE_DIR, exist_ok=True)
async def get_proxied_image(url: str, width: Optional[int] = None):
"""
Fetch an image, resize it, convert to WebP, and cache it.
"""
# Create a unique cache key based on URL and width
cache_key = hashlib.md5(f"{url}_{width}".encode()).hexdigest()
cache_path = os.path.join(CACHE_DIR, f"{cache_key}.webp")
# 1. Check if cached version exists
if os.path.exists(cache_path):
with open(cache_path, "rb") as f:
return Response(content=f.read(), media_type="image/webp")
# 2. Fetch original image
async with httpx.AsyncClient(follow_redirects=True) as client:
try:
response = await client.get(url, timeout=10.0)
response.raise_for_status()
except Exception as e:
# Fallback or error
return None
# 3. Process image with Pillow
try:
img = Image.open(BytesIO(response.content))
# Convert to RGB if necessary (e.g., from RGBA or CMYK)
if img.mode in ("RGBA", "P"):
img = img.convert("RGB")
# Resize if width specified
if width and img.width > width:
ratio = width / float(img.width)
height = int(float(img.height) * float(ratio))
img = img.resize((width, height), Image.LANCZOS)
# 4. Save to buffer as WebP
output = BytesIO()
img.save(output, format="WEBP", quality=80)
webp_data = output.getvalue()
# 5. Save to cache
with open(cache_path, "wb") as f:
f.write(webp_data)
return Response(content=webp_data, media_type="image/webp")
except Exception as e:
print(f"Error processing image: {e}")
return None