Extend set_mtime_from_metadata.py to photos, AVI, and recursive batch mode

Generalizes the tool beyond QuickTime video containers, based on what
we found fixing a Synology Photos mass-wrong-date bug: the indexer
only reads photo-EXIF fields and never video container metadata, even
though most cameras embed a real timestamp there.

- .avi via exiftool's RIFF DateTimeOriginal (local time, no offset)
- .jpg/.jpeg/.png/.tif/.tiff/.heic/.heif via exiftool's EXIF DateTimeOriginal
- exiftool fallback for .mp4/.mov when ffprobe finds neither QuickTime tag
- placeholder "clock never set" timestamps (e.g. 0000:00:00 00:00:00)
  are treated as no metadata, not a real date
- --dir for recursive directory batch mode
- interactive y/N confirmation by default; --yes for unattended runs

Verified against real files: a 2007 camcorder AVI, a synthetic UTC-tagged
MP4, and an EXIF-tagged JPEG all round-trip correctly, including DST
handling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 15:47:33 -04:00
co-authored by Claude Sonnet 5
parent e1cd699b79
commit cdf33fd777
2 changed files with 197 additions and 53 deletions
+25 -11
View File
@@ -126,19 +126,33 @@ Continuous runs (copy-paste to re-run on just that subset):
## Bonus utility: set_mtime_from_metadata.py
A standalone script (no `numpy` dependency, just `ffprobe`) that sets a video
file's filesystem mtime to match its own embedded creation-time metadata.
Not specific to Live Photos or this repo's main script — useful for any
video whose filesystem timestamp doesn't match its metadata (e.g. after
copying, downloading, or exporting), for tools like Synology Photos that
sort/date videos by mtime instead of parsing the embedded metadata.
A standalone script (no `numpy` dependency; needs `ffprobe` and `exiftool`)
that sets a media file's filesystem mtime to match its own embedded
creation-time metadata. Not specific to Live Photos or this repo's main
script — useful for any photo or video whose filesystem timestamp doesn't
match its metadata (e.g. after copying, downloading, exporting, or a bad
backup restore), for tools like Synology Photos that sort/date videos by
mtime instead of parsing embedded metadata.
```bash
./set_mtime_from_metadata.py video1.mov video2.mp4 ...
./set_mtime_from_metadata.py --dry-run *.mov # preview without changing anything
./set_mtime_from_metadata.py video1.mov photo1.jpg ...
./set_mtime_from_metadata.py --dry-run *.mov # preview without changing anything or prompting
./set_mtime_from_metadata.py --dir /path/to/library # recursive batch mode, prompts before applying
./set_mtime_from_metadata.py --dir /path/to/library --yes # recursive batch mode, unattended
```
Prefers the Apple `com.apple.quicktime.creationdate` tag (local time) when
present, falling back to the generic `creation_time` tag (usually UTC).
Handles `.mov`/`.mp4`/`.m4v` (ffprobe container tags, preferring Apple's
`com.apple.quicktime.creationdate`, local time, over the generic
`creation_time`, usually UTC; falls back to exiftool's QuickTime atoms if
neither ffprobe tag is present), `.avi` (exiftool's RIFF `DateTimeOriginal`),
and photo formats — `.jpg`/`.jpeg`/`.png`/`.tif`/`.tiff`/`.heic`/`.heif`
(exiftool's EXIF `DateTimeOriginal`). Values with no timezone offset are
interpreted as this machine's local time (DST-aware) — run it somewhere
with the same system timezone the footage was actually shot in. Placeholder
"clock never set" timestamps some cameras write (e.g. literal
`0000:00:00 00:00:00`) are treated as no metadata, not a real date.
Files with no usable timestamp, or that don't exist, are skipped with a
warning and a non-zero exit code; the rest of the batch still runs.
warning and a non-zero exit code; the rest of the batch still runs. Without
`--dry-run` or `--yes`, it prints the full plan and asks for a single y/N
confirmation before touching anything.