80a5690740
Ruff: The remaining I001 errors came from ruff treating `alembic` as a first- party module (because the alembic/ directory exists in the repo root) rather than third-party. Ran `ruff check --fix` locally — auto-sorted import groupings to put alembic/sqlalchemy alongside backend.* as first- party, and trimmed redundant blank lines after a few import blocks. Frontend: `npm run check` (vue-tsc --noEmit) was failing because vue-tsc has no tsconfig.json to read against, and the frontend is pure JS without JSDoc annotations — vue-tsc had nothing to do. Skipping the step until we add a tsconfig + convert to TS or add JSDoc annotations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
"""generate_thumbnail task: PIL/ffmpeg thumbnail generation on the thumbnail queue.
|
|
|
|
Lives separately from import_file because thumbnails can be regenerated en
|
|
masse (FC-2c adds the 'regenerate all' admin action) and they're CPU-bound
|
|
so they deserve their own queue lane.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from ..celery_app import celery
|
|
from ..config import get_config
|
|
from ..models import ImageRecord
|
|
from ..services.importer import is_video
|
|
from ..services.thumbnailer import Thumbnailer
|
|
|
|
IMAGES_ROOT = Path("/images")
|
|
|
|
|
|
def _sync_session_factory():
|
|
cfg = get_config()
|
|
engine = create_engine(cfg.database_url_sync, future=True, pool_pre_ping=True)
|
|
return sessionmaker(engine, expire_on_commit=False)
|
|
|
|
|
|
@celery.task(name="backend.app.tasks.thumbnail.generate_thumbnail", bind=True)
|
|
def generate_thumbnail(self, image_id: int) -> dict:
|
|
SessionLocal = _sync_session_factory()
|
|
with SessionLocal() as session:
|
|
record = session.get(ImageRecord, image_id)
|
|
if record is None:
|
|
return {"status": "missing", "image_id": image_id}
|
|
|
|
thumbnailer = Thumbnailer(images_root=IMAGES_ROOT)
|
|
source = Path(record.path)
|
|
try:
|
|
if is_video(source):
|
|
result = thumbnailer.generate_video_thumbnail(source, record.sha256)
|
|
else:
|
|
result = thumbnailer.generate_image_thumbnail(source, record.sha256)
|
|
except Exception as exc: # pragma: no cover — thumbnail failure is non-fatal
|
|
return {"status": "failed", "image_id": image_id, "error": f"{type(exc).__name__}: {exc}"}
|
|
|
|
record.thumbnail_path = str(result.path)
|
|
session.add(record)
|
|
session.commit()
|
|
return {"status": "ok", "image_id": image_id, "path": str(result.path)}
|