diff --git a/multi_rename.py b/multi_rename.py old mode 100644 new mode 100755 index 33130b4..04e7e3e --- a/multi_rename.py +++ b/multi_rename.py @@ -1,4 +1,6 @@ +#!/usr/bin/env python3 import argparse +from functools import cache import logging import os import shutil @@ -34,20 +36,22 @@ def edit_text(text: str) -> str | None: return temp_file_path.read_text() -def move_to_trash(file_path: Path): +def move_to_trash(file_path: Path) -> None: + """Move file to Trash using trash CLI.""" if not file_path.is_file(): - raise FileNotFoundError + raise FileNotFoundError(f"File not found: {file_path}") subprocess.run( - [ - "osascript", - "-e", - f'tell app "Finder" to move POSIX file "{file_path}" to trash', - ], + ["trash", str(file_path.resolve())], check=True, ) +@cache +def make_dir(path: Path) -> None: + path.mkdir(parents=True, exist_ok=True) + + def rename_files(files: list[Path], cwd: Path | None = None): if not cwd: cwd = files[0].parent @@ -58,25 +62,30 @@ def rename_files(files: list[Path], cwd: Path | None = None): return edited = edited_raw.splitlines(keepends=False) + if len(edited) != len(originals): + logging.error("number of edited lines does not match number of original lines") + return + deletables = [] - moveables = [] + moveables: list[tuple[Path, Path]] = [] for source, target in zip(originals, edited): if target.startswith("#") or target == "": - deletables.append(Path(source)) + deletables.append((cwd / source).resolve()) continue if source != target: moveables.append((cwd / source, cwd / target)) for source, target in moveables: logging.info(f"moving {source} -> {target}") + make_dir(target.parent) source.rename(target) for f in deletables: try: logging.info(f"trashing {f}") move_to_trash(f) - except: - logging.error(f"failed to trash {f}") + except Exception as e: + logging.error(f"failed to trash {f}: {e}") def parse_args():