fix false positive

This commit is contained in:
Nathan
2026-02-04 12:51:05 -07:00
parent 60546b3c51
commit 791462d7c9
2 changed files with 1282 additions and 19 deletions

View File

@@ -82,10 +82,14 @@ def load_state(state_path: Path) -> dict | None:
return None return None
def state_changed(seq_state: dict, stored_state: dict | None) -> bool: def _canonical_path(p: str) -> str:
"""Normalize path for comparison (case-insensitive, consistent separators)."""
return Path(p).as_posix().lower()
def state_changed(seq_state: dict, stored_state: dict | None, *, verbose: bool = False) -> bool:
if stored_state is None: if stored_state is None:
return True return True
is_windows = platform.system() == "Windows"
def png_only(files): def png_only(files):
return [e for e in files if Path(e.get("path", "")).suffix.lower() == ".png"] return [e for e in files if Path(e.get("path", "")).suffix.lower() == ".png"]
@@ -95,19 +99,39 @@ def state_changed(seq_state: dict, stored_state: dict | None) -> bool:
for e in png_only(s.get("files", [])): for e in png_only(s.get("files", [])):
if Path(e.get("path", "")).name.lower() == "thumbs.db": if Path(e.get("path", "")).name.lower() == "thumbs.db":
continue continue
m = e.get("mtime_ns", 0) out.append({"path": _canonical_path(e["path"]), "size": e["size"]})
if is_windows: out.sort(key=lambda x: x["path"])
m = (m // 100) * 100
out.append({"path": e["path"], "size": e["size"], "mtime_ns": m})
return {"files": out} return {"files": out}
return norm(seq_state) != norm(stored_state) n_seq = norm(seq_state)
n_stored = norm(stored_state)
if n_seq == n_stored:
return False
if verbose:
seq_map = {f["path"]: f for f in n_seq["files"]}
stored_map = {f["path"]: f for f in n_stored["files"]}
seq_paths = set(seq_map.keys())
stored_paths = set(stored_map.keys())
if seq_paths != stored_paths:
missing = stored_paths - seq_paths
extra = seq_paths - stored_paths
if missing:
print(f" State diff: in archive but not on disk: {sorted(missing)[:3]}{'...' if len(missing) > 3 else ''}")
if extra:
print(f" State diff: on disk but not in archive: {sorted(extra)[:3]}{'...' if len(extra) > 3 else ''}")
else:
for p in sorted(seq_paths)[:3]:
a, b = seq_map[p], stored_map[p]
if a != b:
if a["size"] != b["size"]:
print(f" State diff: {p}: size {a['size']} vs {b['size']}")
return True
def compute_state(seq_dir: Path) -> dict: def compute_state(seq_dir: Path) -> dict:
entries = [] entries = []
is_windows = platform.system() == "Windows" is_windows = platform.system() == "Windows"
for p in sorted(iter_png_files(seq_dir), key=lambda x: x.relative_to(seq_dir).as_posix()): for p in sorted(iter_png_files(seq_dir), key=lambda x: x.relative_to(seq_dir).as_posix().lower()):
stat = p.stat() stat = p.stat()
mtime_ns = stat.st_mtime_ns mtime_ns = stat.st_mtime_ns
if is_windows: if is_windows:
@@ -254,7 +278,6 @@ def main() -> int:
parser = argparse.ArgumentParser(description="Compress PNGs in unchanged sequences; staging + Y/N overwrite.") parser = argparse.ArgumentParser(description="Compress PNGs in unchanged sequences; staging + Y/N overwrite.")
parser.add_argument("--8bit", "-8", action="store_true", dest="force_8bit") parser.add_argument("--8bit", "-8", action="store_true", dest="force_8bit")
parser.add_argument("--16bit", "-16", action="store_true", dest="force_16bit") parser.add_argument("--16bit", "-16", action="store_true", dest="force_16bit")
parser.add_argument("--verbose", action="store_true")
args = parser.parse_args() args = parser.parse_args()
force_bitdepth = "8" if args.force_8bit else ("16" if args.force_16bit else None) force_bitdepth = "8" if args.force_8bit else ("16" if args.force_16bit else None)
if args.force_8bit and args.force_16bit: if args.force_8bit and args.force_16bit:
@@ -282,11 +305,15 @@ def main() -> int:
continue continue
_, state_path = find_archive_and_state(seq_dir) _, state_path = find_archive_and_state(seq_dir)
if state_path is None or not state_path.exists(): if state_path is None or not state_path.exists():
changed.append(seq_dir) # New sequence, never zipped changed.append(seq_dir)
rel = seq_dir.relative_to(RENDER_ROOT)
print(f" Changed (no archive): {rel}")
continue continue
stored = load_state(state_path) stored = load_state(state_path)
if state_changed(current, stored): if state_changed(current, stored, verbose=True):
changed.append(seq_dir) changed.append(seq_dir)
rel = seq_dir.relative_to(RENDER_ROOT)
print(f" Changed: {rel}")
if not changed: if not changed:
print("No changed sequences with PNGs found. All sequences are up to date.") print("No changed sequences with PNGs found. All sequences are up to date.")
@@ -373,6 +400,7 @@ def main() -> int:
f"Elapsed: {elapsed_str} | ETA: {eta_str} | " f"Elapsed: {elapsed_str} | ETA: {eta_str} | "
f"Saved: {format_size(total_savings)} ({total_savings_pct:.1f}%)", f"Saved: {format_size(total_savings)} ({total_savings_pct:.1f}%)",
end="\r", end="\r",
flush=True,
) )
last_update_time = current_time last_update_time = current_time