#!/usr/bin/env python3.10 import argparse import dataclasses import datetime import json import logging from pathlib import Path import re def parse_args(): arger = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) arger.add_argument('dirs', help='Path to the directories', type=Path, nargs='+') return arger.parse_args() def natural_sort_key(path: Path) -> tuple[str, ...]: s = path.stem return tuple(f'{int(p):010d}' if p.isnumeric() else p for p in re.findall(r'(\D+|\d+)', s)) def rename_children(cwd: Path) -> None: assert cwd.is_dir() files = [f for f in cwd.glob('*') if f.is_file()] files = sorted(files, key=natural_sort_key) new_stem = cwd.name jobs = [] for i, f in enumerate(files): target = f.with_stem(f'{new_stem}__{i:04d}') if f.suffix == '.jpeg': target = target.with_suffix('.jpg') if target.is_file(): logging.error(f'target already exists: {target}') continue jobs.append(MoveOp(source=f, target=target)) f.rename(target) if not jobs: return write_undo_script(Path.cwd(), jobs) @dataclasses.dataclass class MoveOp: source: Path target: Path def to_dict(self) -> dict: return { 'source': str(self.source), 'target': str(self.target), } def write_undo_script(save_dir: Path, ops: list[MoveOp]): now = datetime.datetime.now().isoformat().replace(':', '') save_path = save_dir / f'undo_{now}.json' with save_path.open('w', encoding='utf-8') as f: for it in ops: f.write(json.dumps(it.to_dict()) + '\n') def main(): args = parse_args() for d in args.dirs: rename_children(d) if __name__ == '__main__': main()