Fix wrong-picture bug: thumbs keyed by sha256 (was filename); single-item actions via fetch+remove (reliable)
This commit is contained in:
@@ -44,13 +44,15 @@ def _is_image(p: Path) -> bool:
|
||||
return p.suffix.lower() in EXT_IMAGES and p.exists()
|
||||
|
||||
|
||||
def _thumb(path: str):
|
||||
"""Return thumbnail URL WITHOUT generating (lazy — /thumbs/ generates on first hit)."""
|
||||
src = Path(path)
|
||||
if not src.exists():
|
||||
def _thumb(path: str, sha: str = None):
|
||||
"""Return thumbnail URL keyed by sha256 (the image's unique identity).
|
||||
|
||||
Never uses filename — duplicate filenames across folders caused wrong
|
||||
thumbnails/full-size images. sha256 is unique per image content.
|
||||
"""
|
||||
if not sha:
|
||||
return None
|
||||
key = src.stem + "_" + str(abs(hash(str(src))))[:8] + ".jpg"
|
||||
return f"/thumbs/{key}"
|
||||
return f"/thumbs/{sha}.jpg"
|
||||
|
||||
|
||||
def _load_item(row: sqlite3.Row) -> dict:
|
||||
@@ -61,7 +63,7 @@ def _load_item(row: sqlite3.Row) -> dict:
|
||||
"name": p.name,
|
||||
"status": row["status"],
|
||||
"source": row["source"],
|
||||
"thumb": _thumb(row["path"]) if _is_image(p) else None,
|
||||
"thumb": _thumb(row["path"], row["sha256"]) if _is_image(p) else None,
|
||||
"exists": p.exists(),
|
||||
"size_mb": round(p.stat().st_size / 1e6, 1) if p.exists() else None,
|
||||
"flag_reason": row["flag_reason"] if "flag_reason" in row.keys() else None,
|
||||
@@ -229,39 +231,31 @@ def full_file(sha: str):
|
||||
|
||||
@app.get("/thumbs/{name}")
|
||||
def thumb_file(name: str):
|
||||
"""Serve thumbnail; generate on first request (cached after)."""
|
||||
"""Serve thumbnail keyed by sha256; generate on first request (cached)."""
|
||||
f = THUMB_DIR / name
|
||||
if not f.exists():
|
||||
# lazy generate — reconstruct source path from key (stem is orig filename)
|
||||
THUMB_DIR.mkdir(parents=True, exist_ok=True)
|
||||
# find the source image: key = <stem>_<hash8>.jpg
|
||||
stem = name.rsplit("_", 1)[0]
|
||||
src = _find_source(stem)
|
||||
if not src:
|
||||
raise HTTPException(404)
|
||||
try:
|
||||
with Image.open(src) as im:
|
||||
im.convert("RGB")
|
||||
im.thumbnail(THUMB_SIZE)
|
||||
im.save(f, "JPEG", quality=70)
|
||||
except Exception:
|
||||
raise HTTPException(404)
|
||||
if f.exists():
|
||||
return FileResponse(f)
|
||||
# key = <sha256>.jpg — resolve exact image via the DB (unique identity)
|
||||
sha = name.rsplit(".", 1)[0]
|
||||
conn = _conn()
|
||||
row = conn.execute("SELECT path FROM image_hashes WHERE sha256=?", (sha,)).fetchone()
|
||||
conn.close()
|
||||
if not row:
|
||||
raise HTTPException(404)
|
||||
src = Path(row["path"])
|
||||
if not src.exists():
|
||||
raise HTTPException(404)
|
||||
THUMB_DIR.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
with Image.open(src) as im:
|
||||
im.convert("RGB")
|
||||
im.thumbnail(THUMB_SIZE)
|
||||
im.save(f, "JPEG", quality=70)
|
||||
except Exception:
|
||||
raise HTTPException(404)
|
||||
return FileResponse(f)
|
||||
|
||||
|
||||
def _find_source(stem: str):
|
||||
"""Find the original image for a thumbnail key (by filename stem)."""
|
||||
import os
|
||||
|
||||
for root_dir in ("/mnt/ubuntu_storage_3TB/archive/03_photos",
|
||||
"/mnt/data/01_keep", "/mnt/data/02_review", "/mnt/data/03_delete"):
|
||||
for dirpath, _, files in os.walk(root_dir):
|
||||
for fn in files:
|
||||
if fn.rsplit(".", 1)[0] == stem:
|
||||
return Path(dirpath) / fn
|
||||
return None
|
||||
|
||||
|
||||
@app.get("/upload", response_class=HTMLResponse)
|
||||
def upload_page(request: Request):
|
||||
"""Upload page — drop files/archives into the incoming folder."""
|
||||
|
||||
Reference in New Issue
Block a user