fix: address open triage issues (#21,#26,#45,#46,#47,#30-33)
CI / skip-ci-check (pull_request) Successful in 6s
CI / docker-ci (pull_request) Successful in 7s
CI / secret-scan (pull_request) Successful in 11s

- #45: re-read local folder when recursive checkbox toggles
- #47: clear Identify crop spinner when image is already cached
- #46: search selected people by person_ids; AND for "First Last"
- #21: enqueue network import without blocking API walk
- #26: serve resized grid thumbnails for photos
- #30/#31/#33: re-enable small-face filters in auto-match
This commit is contained in:
2026-07-09 14:42:08 -04:00
parent d69ad1576d
commit ffddeca268
10 changed files with 218 additions and 94 deletions
+34 -11
View File
@@ -37,7 +37,6 @@ from backend.schemas.search import (
SearchPhotosResponse,
)
from backend.services.photo_service import (
find_photos_in_folder,
import_photo_from_path,
)
from backend.services.search_service import (
@@ -63,6 +62,10 @@ def search_photos(
current_user: Annotated[dict, Depends(get_current_user)],
search_type: str = Query("name", description="Search type: name, date, tags, no_faces, no_tags, processed, unprocessed, favorites"),
person_name: Optional[str] = Query(None, description="Person name for name search"),
person_ids: Optional[str] = Query(
None,
description="Comma-separated person IDs for exact name search (preferred over substring when selecting people)",
),
tag_names: Optional[str] = Query(None, description="Comma-separated tag names for tag search"),
match_all: bool = Query(False, description="Match all tags (for tag search)"),
date_from: Optional[str] = Query(None, description="Date from (YYYY-MM-DD)"),
@@ -111,13 +114,36 @@ def search_photos(
tag_list = [t.strip() for t in tag_names.split(",") if t.strip()]
if search_type == "name":
if not person_name:
parsed_person_ids: list[int] = []
if person_ids:
for part in person_ids.split(","):
part = part.strip()
if not part:
continue
try:
parsed_person_ids.append(int(part))
except ValueError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid person_ids value: {part}",
)
if not person_name and not parsed_person_ids:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="person_name is required for name search",
detail="person_name or person_ids is required for name search",
)
results, total = search_photos_by_name(
db, person_name, folder_path, media_type, df, dt, tag_list, match_all, page, page_size
db,
person_name or "",
folder_path,
media_type,
df,
dt,
tag_list,
match_all,
page,
page_size,
person_ids=parsed_person_ids or None,
)
for photo, full_name in results:
tags = get_photo_tags(db, photo.id)
@@ -360,23 +386,20 @@ def import_photos(
detail=f"Folder not found: {request.folder_path}",
)
# Estimate number of photos (quick scan)
estimated_photos = len(find_photos_in_folder(request.folder_path, request.recursive))
# Enqueue job
# Pass function as string path to avoid serialization issues
# Do NOT walk the tree on the API thread (#21) — that blocked SharePoint/SMB
# imports for minutes with no progress. Counting happens inside the RQ job.
job = queue.enqueue(
"backend.services.tasks.import_photos_task",
request.folder_path,
request.recursive,
job_timeout="1h", # Allow up to 1 hour for large imports
job_timeout="2h", # Network shares can be slow
)
return PhotoImportResponse(
job_id=job.id,
message=f"Photo import job queued for {request.folder_path}",
folder_path=request.folder_path,
estimated_photos=estimated_photos,
estimated_photos=None,
)