Last active
May 8, 2025 12:20
-
-
Save hemna/573d384dd84fea8527ad7b65853f1c3e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S uv run --script | |
# /// script | |
# dependencies = [ | |
# "rich", | |
# ] | |
# /// | |
import os | |
import shutil | |
import string | |
import sys | |
import argparse | |
from rich.progress import Progress | |
from collections import defaultdict | |
def organize_by_alpha(target_dir, dry_run=False): | |
# Ensure the target directory exists | |
if not os.path.isdir(target_dir): | |
print(f"Error: {target_dir} is not a valid directory.") | |
return | |
# Define valid subfolder names (A-Z, 0-9) | |
valid_folders = list(string.ascii_uppercase) + list(string.digits) | |
subfolder_set = {os.path.join(target_dir, name) for name in valid_folders} | |
# Gather items to process (skip hidden files/dirs and alpha/number subfolders) | |
items = [ | |
f for f in os.listdir(target_dir) | |
if not f.startswith('.') | |
and os.path.join(target_dir, f) not in subfolder_set | |
] | |
total_items = len(items) | |
if total_items == 0: | |
print("No files or folders to process.") | |
return | |
# Determine which directories are needed | |
items_by_letter = defaultdict(list) | |
for name in items: | |
first_char = name[0].upper() | |
if first_char in valid_folders: | |
items_by_letter[first_char].append(name) | |
# Create only needed subfolders | |
for folder, folder_items in items_by_letter.items(): | |
subfolder = os.path.join(target_dir, folder) | |
if not os.path.exists(subfolder): | |
if dry_run: | |
print(f"Would create folder: {subfolder}") | |
else: | |
os.makedirs(subfolder, exist_ok=True) | |
with Progress() as progress: | |
task = progress.add_task("Organizing items", total=total_items) | |
for name in items: | |
path = os.path.join(target_dir, name) | |
first_char = name[0].upper() | |
if first_char in valid_folders: | |
dest_folder = os.path.join(target_dir, first_char) | |
dest_path = os.path.join(dest_folder, name) | |
if dry_run: | |
progress.console.print(f"[yellow]Would move {name} -> {dest_folder}/[/yellow]") | |
else: | |
progress.console.print(f"[green]Moving {name} -> {dest_folder}/[/green]") | |
shutil.move(path, dest_path) | |
else: | |
progress.console.print(f"[red]Skipping {name}: does not start with A-Z or 0-9.[/red]") | |
progress.update(task, advance=1) | |
def main(): | |
parser = argparse.ArgumentParser(description="Organize files and folders into A-Z and 0-9 subfolders.") | |
parser.add_argument("directory", help="Target directory to organize") | |
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without moving files or folders") | |
args = parser.parse_args() | |
organize_by_alpha(args.directory, dry_run=args.dry_run) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment