#!/usr/bin/env python3 """ Fast manual grouping helper. Drag files or directories onto this script, or run: python3 grouping.py path/to/file/or/directory [...] Files are sorted by their current path and moved into one folder named [first stem]-[last stem] inside the working directory. """ from __future__ import annotations import shutil import sys from pathlib import Path from tools.console import pause_if_interactive from tools.filenames import group_stem from tools.filesystem import ( cleanup_roots_from_args, collect_files, determine_working_dir, remove_empty_dirs, unique_path, ) def collect_group_files(args: list[str]) -> list[Path]: return collect_files(args, sort_by_name=True) def group_files(files: list[Path], working_dir: Path) -> Path | None: if not files: return None sorted_files = sorted(files, key=lambda item: item.name.lower()) first = group_stem(sorted_files[0]) last = group_stem(sorted_files[-1]) target_dir = working_dir / f"{first}-{last}" target_dir.mkdir(parents=True, exist_ok=True) for source in sorted_files: destination = unique_path(target_dir / source.name) shutil.move(str(source), str(destination)) return target_dir def print_removed_dirs(removed_dirs: list[Path]) -> None: if not removed_dirs: return print("Removed empty director" + ("y:" if len(removed_dirs) == 1 else "ies:")) for directory in removed_dirs: print(f" - {directory}") def run(argv: list[str]) -> int: if len(argv) < 2: print("Usage: python3 grouping.py path/to/file/or/directory [...]") return 2 try: working_dir = determine_working_dir(argv[1:]) except RuntimeError as exc: print(exc) return 1 cleanup_roots = cleanup_roots_from_args(argv[1:]) files = collect_group_files(argv[1:]) if not files: print("No files to group.") return 0 target_dir = group_files(files, working_dir) if target_dir is not None: print(f"Moved {len(files)} file(s) into {target_dir}") removed_dirs = remove_empty_dirs(cleanup_roots, keep_dirs={working_dir.resolve()}) print_removed_dirs(removed_dirs) return 0 def main(argv: list[str]) -> int: try: return run(argv) finally: pause_if_interactive() if __name__ == "__main__": raise SystemExit(main(sys.argv))