|
1 | | -from shutil import move |
2 | 1 | import os |
| 2 | +from pathlib import Path |
| 3 | +from shutil import move |
3 | 4 |
|
4 | | -folder_ex = { |
5 | | - 'Programming Files': set(['ipynb', 'py', 'java', 'cs', 'js', 'vsix', 'jar', 'cc', 'ccc', 'html', 'xml', 'kt', 'c', 'css']), |
6 | | - 'Compressed': set(['zip', 'rar', 'arj', 'gz', 'sit', 'sitx', 'sea', 'ace', 'bz2', '7z']), |
7 | | - 'Applications': set(['exe', 'msi', 'deb', 'rpm']), |
8 | | - 'Pictures': set(['jpeg', 'jpg', 'png', 'gif', 'tiff', 'raw', 'webp', 'jfif', 'ico', 'psd', 'svg', 'ai']), |
9 | | - 'Videos': set(['mp4', 'webm', 'mkv', 'MPG', 'MP2', 'MPEG', 'MPE', 'MPV', 'OGG', 'M4P', 'M4V', 'WMV', 'MOV', 'QT', 'FLV', 'SWF', 'AVCHD', 'avi', 'mpg', 'mpe', 'mpeg', 'asf', 'wmv', 'mov', 'qt', 'rm']), |
10 | | - 'Documents': set(['txt', 'pdf', 'doc', 'xlsx', 'pdf', 'ppt', 'pps', 'docx', 'pptx']), |
11 | | - 'Music': set(['mp3', 'wav', 'wma', 'mpa', 'ram', 'ra', 'aac', 'aif', 'm4a', 'tsa']), |
12 | | - 'Torrents': set(['torrent']), |
13 | | - 'Other': set([]) |
| 5 | +# Define categories with subfolders and file extensions |
| 6 | +FOLDER_STRUCTURE = { |
| 7 | + # Programming |
| 8 | + 'Programming/Python': {'py', 'ipynb', 'pyd', 'pyc'}, |
| 9 | + 'Programming/JavaScript': {'js', 'ts', 'tsx'}, |
| 10 | + 'Programming/Java': {'java', 'jar'}, |
| 11 | + 'Programming/C_CPP': {'c', 'cpp', 'cc', 'h', 'hpp'}, |
| 12 | + 'Programming/CSharp': {'cs'}, |
| 13 | + 'Programming/Web': {'html', 'css', 'xml', 'php'}, |
| 14 | + 'Programming/Kotlin': {'kt'}, |
| 15 | + 'Programming/VS Extensions': {'vsix'}, |
| 16 | + 'Programming/Others': {'r', 'go', 'rs', 'dart', 'swift', 'lua', 'sh', 'bat'}, |
| 17 | + |
| 18 | + # Compressed files |
| 19 | + 'Compressed': {'zip', 'rar', 'arj', 'gz', 'bz2', '7z', 'xz', 'tar', 'iso'}, |
| 20 | + |
| 21 | + # Applications / Executables |
| 22 | + 'Applications/Windows': {'exe', 'msi'}, |
| 23 | + 'Applications/Linux': {'deb', 'rpm', 'AppImage'}, |
| 24 | + 'Applications/Android': {'apk'}, |
| 25 | + |
| 26 | + # Images |
| 27 | + 'Pictures/RAW': {'raw', 'arw', 'cr2', 'nef', 'orf', 'rw2', 'dng', 'raf', 'pef', 'srw', 'x3f', 'cr3'}, |
| 28 | + 'Pictures/Photos': {'jpeg', 'jpg', 'png', 'gif', 'tiff', 'webp', 'bmp', 'ico', 'heic', 'jfif'}, |
| 29 | + 'Pictures/3D': {'3ds', 'blend', 'fbx', 'obj', 'stl', 'dae', 'ply'}, |
| 30 | + 'Pictures/Vector': {'svg', 'ai'}, |
| 31 | + |
| 32 | + # Videos |
| 33 | + 'Videos/Standard': {'mp4', 'webm', 'mkv', 'mov', 'avi', 'flv', 'wmv'}, |
| 34 | + 'Videos/Legacy': {'qt', 'rm', 'vob', 'mpg', 'mpeg', 'm4v', '3gp', 'mts'}, |
| 35 | + 'Videos/Streaming': {'ts'}, |
| 36 | + |
| 37 | + |
| 38 | + # Audio / Music |
| 39 | + 'Music': {'mp3', 'aac', 'wma', 'm4a', 'flac', 'ogg', 'opus', 'wav', 'aiff', 'ape', 'mid', 'midi', 'ra'}, |
| 40 | + |
| 41 | + # Torrents |
| 42 | + 'Torrents': {'torrent'}, |
| 43 | + |
| 44 | + # Documents |
| 45 | + 'Documents/PDF': {'pdf'}, |
| 46 | + 'Documents/Word': {'doc', 'docx'}, |
| 47 | + 'Documents/Excel': {'xls', 'xlsx', 'csv'}, |
| 48 | + 'Documents/PowerPoint': {'ppt', 'pptx', 'pps'}, |
| 49 | + 'Documents/Text': {'txt', 'md', 'rtf', 'log'}, |
| 50 | + 'Documents/Notebooks': {'ipynb'}, |
| 51 | + 'Documents/LaTeX': {'tex', 'bib'}, |
| 52 | + 'Documents/Code Snippets': {'json', 'yaml', 'yml', 'toml', 'ini'}, |
| 53 | + 'Documents/Others': {'odt', 'odp', 'ods', 'epub'}, |
| 54 | + |
| 55 | + # Fallback |
| 56 | + 'Other': set() |
14 | 57 | } |
15 | 58 |
|
16 | 59 |
|
17 | | -def create_folder(folder_name: str): |
18 | | - ''' |
19 | | - Creates the folder |
20 | | -
|
21 | | - Args: |
22 | | - folder_name (str): folder to be created |
23 | | - ''' |
| 60 | +def create_folder(path: Path) -> None: |
| 61 | + """Create a folder if it doesn't exist.""" |
24 | 62 | try: |
25 | | - os.mkdir(folder_name) |
26 | | - print('{} Created ✔'.format(folder_name)) |
27 | | - except OSError: |
28 | | - print('{} Already Exists'.format(folder_name)) |
29 | | - |
30 | | - |
31 | | -def move_files(folder_path:str, file_folder_map: dict): |
32 | | - ''' |
33 | | - Move files to respective folder |
34 | | -
|
35 | | - Args: |
36 | | - ext_file_map (dict) : File to Folder map |
37 | | - ''' |
38 | | - for folder, files in file_folder_map.items(): |
39 | | - os.makedirs(os.path.join(folder_path, folder), exist_ok=True) |
40 | | - for file in files: |
41 | | - old_file_path = os.path.join(folder_path, file) |
42 | | - new_file_path = os.path.join(folder_path, folder) |
43 | | - move(old_file_path, new_file_path) |
44 | | - |
| 63 | + path.mkdir(parents=True, exist_ok=True) |
| 64 | + print(f"[✔] Folder ready: {path}") |
| 65 | + except Exception as e: |
| 66 | + print(f"[✖] Failed to create {path}: {e}") |
45 | 67 |
|
46 | | -def get_folder(ext): |
47 | | - ''' |
48 | | - Returns the Folder that corresponds to the given extension. |
49 | 68 |
|
50 | | - Args: |
51 | | - ext (String): The extension of the file. |
52 | | -
|
53 | | - Returns: |
54 | | - String: The name of the Folder that holds the ext. |
55 | | - ''' |
56 | | - for f, ex in folder_ex.items(): |
57 | | - if ext in ex: |
58 | | - return f |
| 69 | +def classify_extension(extension: str) -> str: |
| 70 | + """Return the folder path based on file extension.""" |
| 71 | + for folder, extensions in FOLDER_STRUCTURE.items(): |
| 72 | + if extension.lower() in extensions: |
| 73 | + return folder |
59 | 74 | return 'Other' |
60 | 75 |
|
61 | 76 |
|
62 | | -# TODO need to change function name |
63 | | -def start(folder_path: str): |
64 | | - ''' |
65 | | - Organize files on the current directory, each to the corresponding folder. |
| 77 | +def organize_files_in_directory(folder_path: str) -> None: |
| 78 | + """ |
| 79 | + Organize files in the given folder into subfolders based on their extensions. |
66 | 80 | |
67 | | - folder_path: The path of the folder to be organized. |
68 | | - ''' |
69 | | - |
70 | | - file_folder_map = dict() |
71 | | - for filename in os.listdir(folder_path): |
72 | | - # ignore filemover.py, hidden files or a directory |
73 | | - if filename == os.path.basename(__file__) or filename[0] == '.' or '.' not in filename: |
74 | | - continue |
75 | | - |
76 | | - file_extension = os.path.basename(filename).split('.')[-1] |
77 | | - folder = get_folder(file_extension) |
78 | | - |
79 | | - # ignore files present in the folders |
80 | | - if os.path.isfile(os.path.join(folder, filename)): |
81 | | - continue |
82 | | - |
83 | | - # insert file to file_folder_map |
84 | | - if folder not in file_folder_map: |
85 | | - file_folder_map[folder] = [] |
86 | | - file_folder_map[folder].append(filename) |
87 | | - |
88 | | - # create required folders |
89 | | - for folder in file_folder_map.keys(): |
90 | | - create_folder(folder) |
91 | | - |
92 | | - # move files to folder |
93 | | - move_files(folder_path, file_folder_map) |
94 | | - |
| 81 | + Args: |
| 82 | + folder_path (str): Path of the folder to organize. |
| 83 | + """ |
| 84 | + folder = Path(folder_path) |
| 85 | + if not folder.exists(): |
| 86 | + print(f"[!] Provided path does not exist: {folder_path}") |
| 87 | + return |
| 88 | + |
| 89 | + files_to_move = {} |
| 90 | + |
| 91 | + for item in folder.iterdir(): |
| 92 | + if item.is_file() and not item.name.startswith('.') and '.' in item.name: |
| 93 | + if item.name == Path(__file__).name: |
| 94 | + continue # Avoid moving the script itself |
| 95 | + extension = item.suffix[1:] # Remove the dot |
| 96 | + destination_folder = classify_extension(extension) |
| 97 | + files_to_move.setdefault(destination_folder, []).append(item) |
| 98 | + |
| 99 | + for category in files_to_move: |
| 100 | + full_folder_path = folder / category |
| 101 | + create_folder(full_folder_path) |
| 102 | + for file in files_to_move[category]: |
| 103 | + try: |
| 104 | + move(str(file), str(full_folder_path / file.name)) |
| 105 | + print(f" ↳ Moved: {file.name} → {full_folder_path}") |
| 106 | + except Exception as e: |
| 107 | + print(f"[✖] Could not move {file.name}: {e}") |
| 108 | + |
| 109 | + |
| 110 | +if __name__ == '__main__': |
| 111 | + import sys |
| 112 | + if len(sys.argv) > 1: |
| 113 | + organize_files_in_directory(sys.argv[1]) |
| 114 | + else: |
| 115 | + organize_files_in_directory(os.getcwd()) |
0 commit comments