diff --git a/engine.py b/engine.py index c963aad..603cc66 100644 --- a/engine.py +++ b/engine.py @@ -1,10 +1,7 @@ import os import shutil import sqlite3 -import threading -import hashlib from contextlib import contextmanager -from functools import lru_cache from PIL import Image from io import BytesIO from typing import Dict, List, Optional, Tuple @@ -285,33 +282,12 @@ class SorterEngine: return fid # ========================================== - # IMAGE COMPRESSION (OPTIMIZED WITH CACHING) + # IMAGE COMPRESSION # ========================================== - - # Simple in-memory cache for thumbnails - _thumbnail_cache: Dict[str, bytes] = {} - _cache_max_items = 500 - _cache_lock = threading.Lock() - - @classmethod - def _get_cache_key(cls, path: str, quality: int, target_size: Optional[int]) -> str: - """Generate cache key including file modification time.""" - try: - mtime = os.path.getmtime(path) - except OSError: - mtime = 0 - return hashlib.md5(f"{path}:{quality}:{target_size}:{mtime}".encode()).hexdigest() @classmethod def compress_for_web(cls, path: str, quality: int, target_size: Optional[int] = None) -> Optional[bytes]: - """Loads image, resizes smart, and saves as WebP with caching.""" - cache_key = cls._get_cache_key(path, quality, target_size) - - # Check cache first - with cls._cache_lock: - if cache_key in cls._thumbnail_cache: - return cls._thumbnail_cache[cache_key] - + """Loads image, resizes smart, and saves as WebP.""" try: with Image.open(path) as img: # Keep RGBA for WebP support, only convert unusual modes @@ -326,19 +302,8 @@ class SorterEngine: # Save as WebP buf = BytesIO() - img.save(buf, format="WEBP", quality=quality, method=4) # method=4 is faster - result = buf.getvalue() - - # Cache the result - with cls._cache_lock: - if len(cls._thumbnail_cache) >= cls._cache_max_items: - # Simple eviction: remove oldest 20% - keys_to_remove = list(cls._thumbnail_cache.keys())[:cls._cache_max_items // 5] - for k in keys_to_remove: - del cls._thumbnail_cache[k] - cls._thumbnail_cache[cache_key] = result - - return result + img.save(buf, format="WEBP", quality=quality) + return buf.getvalue() except Exception: return None @@ -350,7 +315,8 @@ class SorterEngine: def process_one(path): return path, SorterEngine.compress_for_web(path, quality) - with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: + # Reduced from 8 to 2 workers to prevent memory issues + with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: future_to_path = {executor.submit(process_one, p): p for p in image_paths} for future in concurrent.futures.as_completed(future_to_path): try: