#!/usr/bin/env python3 """Complete the Monster High ClientPicker after transfer finished late. - Regenerates Photos.js from every CR3 in the shoot (sorted by id). - Only includes photos whose preview jpg actually exists. - Rewrites Photos.list and RenderScratch/Photos.paths with absolute paths at the final location. """ import json from pathlib import Path SHOOT = Path("/Volumes/Sam Storage/YellowMellow/2026/Monster High Theme (10:01:2026)") PICKER = SHOOT / "ClientPicker" PREVIEWS = PICKER / "Previews" # Exclude AppleDouble ._* metadata twins that SMB materializes on write cr3_ids = sorted(p.stem for p in SHOOT.glob("*.CR3") if not p.name.startswith("._")) have_previews = {p.stem for p in PREVIEWS.glob("*.jpg") if not p.name.startswith("._")} ids_with_preview = [i for i in cr3_ids if i in have_previews] missing_preview = [i for i in cr3_ids if i not in have_previews] # Photos.js — match existing style: one entry per line, trailing comma except last lines = ["window.PHOTOS=["] for n, i in enumerate(ids_with_preview): comma = "," if n < len(ids_with_preview) - 1 else "" lines.append(f' {{ id: "{i}", img: "Previews/{i}.jpg" }}{comma}') lines.append("];") (PICKER / "Photos.js").write_text("\n".join(lines) + "\n", encoding="utf-8") # Photos.list and RenderScratch/Photos.paths — absolute CR3 paths, sorted paths = "\n".join(str(SHOOT / f"{i}.CR3") for i in ids_with_preview) + "\n" (PICKER / "Photos.list").write_text(paths, encoding="utf-8") (PICKER / "RenderScratch" / "Photos.paths").write_text(paths, encoding="utf-8") print(json.dumps({ "cr3_total": len(cr3_ids), "previews_on_disk": len(have_previews), "entries_written": len(ids_with_preview), "still_missing_preview": missing_preview, }, indent=2))