#!/usr/bin/env python3 """照片入库处理器:把 content/photos/ 下超限图片压缩到站内规范。 为什么存在:gitea web/本地上传的是原图(曾发生 196M/21 张入仓事故, 见 git log aea21c8 的重写说明);sharp 只派生 dist 缩略图不管仓内体积。 工作流:上传照片到 content/photos/(顺带跑一次 sidecar 生成或手写)后、 git commit 前执行本脚本;幂等,已在规范内的文件原样跳过(零 diff)。 规范与迁移器一致:长边 ≤2400px、JPEG q86(scripts/migrate/photos_migrate.py)。 """ import sys from pathlib import Path PHOTOS = Path("content/photos") MAX_EDGE = 2400 QUALITY = 86 # 跳过阈值:小于此字节数的 jpg 视为已处理过(2400px q86 成片通常 200KB-1MB) SKIP_BELOW_BYTES = 1_500_000 def main() -> int: from PIL import Image changed, skipped = [], 0 for jpg in sorted(PHOTOS.glob("*.jpg")): size = jpg.stat().st_size if size < SKIP_BELOW_BYTES: skipped += 1 continue STORE = Path.home() / "docker_apps/blog/photos-originals" STORE.mkdir(parents=True, exist_ok=True) # 压缩覆写仓内文件前原件先进 store(幂等:store 已有同名则跳过) if not (STORE / jpg.name).exists(): (STORE / jpg.name).write_bytes(jpg.read_bytes()) img = Image.open(jpg) # EXIF 显式保留:重存默认剥离会抽走图库参数条的构建期数据源 exif = img.info.get("exif") if img.mode not in ("RGB", "L"): img = img.convert("RGB") img.thumbnail((MAX_EDGE, MAX_EDGE)) kwargs = {"exif": exif} if exif else {} img.save(jpg, "JPEG", quality=QUALITY, optimize=True, **kwargs) changed.append((jpg.name, size, jpg.stat().st_size)) for name, before, after in changed: print(f" compressed: {name} {before/1e6:.1f}M -> {after/1e6:.2f}M") print(f"photos ingest: {len(changed)} compressed, {skipped} skipped (within spec)") return 0 if __name__ == "__main__": sys.exit(main())