"""Thumbnail admin API: backfill trigger.""" import asyncio from quart import Blueprint, jsonify thumbnails_bp = Blueprint("thumbnails", __name__, url_prefix="/api/thumbnails") @thumbnails_bp.route("/backfill", methods=["POST"]) async def trigger_backfill(): """Run the backfill scan synchronously, return the counts. The actual thumbnail generation work is still off-loaded to the thumbnail Celery queue via `generate_thumbnail.delay()` per missing row — so this handler is fast even on a 100k-image library (a scan is just SELECT id, thumbnail_path + a file.stat() per row, no heavy work). Operator-flagged 2026-06-01: the previous fire-and-forget shape returned `{celery_task_id}` only, so the admin UI had no idea whether backfill found 0 or 5000 candidates — \"found nothing\" was indistinguishable from \"the worker isn't picking up the task.\"""" from ..tasks.thumbnail import _run_backfill_scan # Sync scan inside an executor so we don't block the event loop. counts = await asyncio.get_running_loop().run_in_executor( None, _run_backfill_scan, ) return jsonify(counts), 200