feat: editable taken_at + folder-based date repair and filter

Lets operators fix corrupted capture dates at scale. Adds an editable
Date Taken field with a folder/filename-derived suggestion hint, a bulk
Date Taken section in the multi-select sidebar that either applies one
date to the whole selection or infers a per-photo date from each path,
a warning badge on thumbnails whose stored date disagrees with the
path, and a "Date issues" filter pill so suspicious photos can be
surfaced and fixed as a group. Edits are written back to EXIF on disk
so rescans don't clobber the fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 11:48:55 +02:00
parent 339e1be510
commit 30d03d8d4d
19 changed files with 1281 additions and 26 deletions

View File

@@ -21,6 +21,7 @@ from app.models import Photo, Folder, SourceRoot
from app.config import settings
from app.tasks.thumbs import generate_thumbnails
from app.services.metadata import extract_metadata
from app.services.date_guess import has_date_warning
logger = logging.getLogger(__name__)
@@ -231,6 +232,7 @@ async def _scan_folder_async(folder_path: str, source_root_id: Optional[str], ta
effective_hidden = await is_folder_effectively_hidden(folder)
# Create photo entry
mtime_dt = datetime.fromtimestamp(stat.st_mtime)
photo = Photo(
filepath=filepath,
filename=filename,
@@ -239,8 +241,13 @@ async def _scan_folder_async(folder_path: str, source_root_id: Optional[str], ta
media_type=get_media_type(filepath),
original_format=Path(filepath).suffix.upper()[1:],
file_size=stat.st_size,
taken_at=datetime.fromtimestamp(stat.st_mtime),
taken_at=mtime_dt,
taken_at_source='filesystem',
# First-pass flag based on the filesystem mtime;
# metadata.extract_metadata re-runs this once
# EXIF has been parsed so a real DateTimeOriginal
# can clear the warning.
has_date_warning=has_date_warning(filepath, mtime_dt),
is_duplicate=is_dup,
is_hidden=effective_hidden,
processing_status='pending'