Update engine.py
This commit is contained in:
46
engine.py
46
engine.py
@@ -1,10 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import threading
|
|
||||||
import hashlib
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from functools import lru_cache
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
@@ -285,33 +282,12 @@ class SorterEngine:
|
|||||||
return fid
|
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
|
@classmethod
|
||||||
def compress_for_web(cls, path: str, quality: int, target_size: Optional[int] = None) -> Optional[bytes]:
|
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."""
|
"""Loads image, resizes smart, and saves as WebP."""
|
||||||
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]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with Image.open(path) as img:
|
with Image.open(path) as img:
|
||||||
# Keep RGBA for WebP support, only convert unusual modes
|
# Keep RGBA for WebP support, only convert unusual modes
|
||||||
@@ -326,19 +302,8 @@ class SorterEngine:
|
|||||||
|
|
||||||
# Save as WebP
|
# Save as WebP
|
||||||
buf = BytesIO()
|
buf = BytesIO()
|
||||||
img.save(buf, format="WEBP", quality=quality, method=4) # method=4 is faster
|
img.save(buf, format="WEBP", quality=quality)
|
||||||
result = buf.getvalue()
|
return 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
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -350,7 +315,8 @@ class SorterEngine:
|
|||||||
def process_one(path):
|
def process_one(path):
|
||||||
return path, SorterEngine.compress_for_web(path, quality)
|
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}
|
future_to_path = {executor.submit(process_one, p): p for p in image_paths}
|
||||||
for future in concurrent.futures.as_completed(future_to_path):
|
for future in concurrent.futures.as_completed(future_to_path):
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user