Moonlight
← back to tech

2026 年 7 月 2 日 · 3 min read

一个小脚本:把手机相册按日期整理进 NAS

胶片扫描件和手机照片混在一起太乱,写了个脚本按 EXIF 拍摄时间分目录,再同步到 NAS。

Pythonrsyncexiftool

照片越来越多,手机、相机、胶片扫描件全混在一个文件夹里。我要的只是一个简单的规则:按拍摄日期分目录,不重复,不丢。

读 EXIF

文件修改时间不可信(导出、拷贝都会改),要读 EXIF 里的 DateTimeOriginal。用 exiftool 最省事:

import json, subprocess
from pathlib import Path
from datetime import datetime

def taken_at(path: Path) -> datetime | None:
    out = subprocess.run(
        ["exiftool", "-json", "-DateTimeOriginal", "-CreateDate", str(path)],
        capture_output=True, text=True,
    ).stdout
    meta = json.loads(out)[0]
    raw = meta.get("DateTimeOriginal") or meta.get("CreateDate")
    if not raw:
        return None
    return datetime.strptime(raw[:19], "%Y:%m:%d %H:%M:%S")

胶片扫描件没有 EXIF,就退回到文件名里的日期,再不行就归到 undated/

分目录 + 去重

目录结构:YYYY/YYYY-MM-DD/。用内容哈希去重,同一张照片再导入一次也不会多一份:

import hashlib, shutil

def sha1(path: Path) -> str:
    h = hashlib.sha1()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(1 << 20), b""):
            h.update(chunk)
    return h.hexdigest()[:12]

def place(src: Path, root: Path):
    dt = taken_at(src)
    folder = root / (f"{dt:%Y}/{dt:%Y-%m-%d}" if dt else "undated")
    folder.mkdir(parents=True, exist_ok=True)
    dst = folder / f"{sha1(src)}{src.suffix.lower()}"
    if not dst.exists():
        shutil.copy2(src, dst)

同步到 NAS

整理完的目录用 rsync 推过去,只传新增:

rsync -av --ignore-existing ~/Pictures/sorted/ nas:/volume1/photos/

一点心得

  • 先整理再同步,不要在 NAS 上直接改;
  • 哈希用前 12 位就够了,文件名短一点好看;
  • 胶片扫描件我会手动在文件名里写上冲扫日期,脚本认得出来。