A simple interactive Python script for organizing messy folders on the computer, supports macOS and linux but not windows. The mini-program has the following features:
- Creation of Alpha-numeric (A-Z / 0-9) folders according to available set of letters present in the folder given in the path and move folders/files into relevant newly created folders.
- Creation of Type specific folders (Audio, Video ...) and move files in relevant type folders.
- Run directly from shell or from Python interpreter.
- Interactive.
It is intended to add more features to the code and maybe perform further optimizations / updates in the future, here's my implementation in Python, I hope this is to your liking, any suggestions for improvements/features to add/problems encountered while using the code are more than welcome. Program works perfectly well, no bugs found so far however, you might want to test it before use on a folder containing test files so you can get used to it.
#!/usr/bin/env python
import os
import string
import shutil
import random
def thank_user():
"""Print a thank you message and end program."""
print(5 * ' ' + 10 * '=')
print('Thank you for using file organizer.')
print(5 * ' ' + 10 * '=')
exit()
def get_folder_contents(path):
"""Return folder contents."""
while not os.path.exists(path):
path = input('Invalid path, please enter a valid path or q to exit: ').rstrip()
if path == 'q':
thank_user()
os.chdir(path)
return [file for file in os.listdir(path) if file != '.DS_Store']
def welcome_user():
"""Print a welcome message."""
print(5 * ' ' + 10 * '=')
print('Welcome to file organizer.')
print(5 * ' ' + 10 * '=')
action = input('Do you wish to continue? y/n: ')
while action != 'y' and action != 'n':
print(f'Invalid command {action}')
action = input('Do you wish to continue? y/n: ')
if action == 'n':
thank_user()
if action == 'y':
pass
def create_alpha_num_folders(path):
"""Create alpha-numeric folders for first characters present in files of the given path ."""
folder_contents = get_folder_contents(path)
if not folder_contents:
print(f"0 files found in {str(path).split('/')[-1]}")
print(105 * '=')
thank_user()
chars_to_produce = set([item[0].upper() for item in folder_contents])
invalid_folders = [folder for folder in folder_contents if folder in string.ascii_uppercase
or folder in string.digits]
if invalid_folders:
print(f'Found the following {len(invalid_folders)} folders named from A - Z/ 1 - n:')
for invalid_folder in invalid_folders:
print(invalid_folder)
while invalid_folders:
action = input(f'Enter q to exit. Do you want to to rename the {len(invalid_folders)}'
f' invalid folder(s)? y/n/q: ')
if action == 'q' or action == 'n':
print('Creating A - Z / 1 - n folders unsuccessful.')
thank_user()
if action == 'y':
confirm = input(f'Are you sure, do you want to rename {len(invalid_folders)} invalid folders? y/n: ')
while not confirm == 'y' and not confirm == 'n':
print(f'Invalid command {confirm}')
confirm = input(f'Are you sure, do you want to rename {len(invalid_folders)} '
f'invalid folders? y/n: ')
if confirm == 'y':
count = random.randint(10 ** 6, 10 ** 7)
for filename in invalid_folders:
new_name = filename + '_' + str(count)
os.rename(filename, new_name)
print(f'Changed {len(invalid_folders)} folder name(s) successful.')
break
if confirm == 'n':
thank_user()
else:
print(f'Invalid command {action}')
for char in sorted(chars_to_produce):
os.mkdir(char)
print(f'Creation of folder {char} successful.')
print(105 * '=')
def get_supported_formats():
"""Return supported formats."""
formats = {
'AUDIO': ['aif', 'cda', 'mid', 'midi', 'mp3', 'mpa', 'ogg', 'wav', 'wma', 'wpl'],
'COMPRESSED': ['arj', 'deb', 'pkg', 'rar', 'rpm', 'tar.gz', 'z', 'zip'],
'DISC': ['bin', 'dmg', 'iso', 'toast', 'vcd'],
'DATA': ['csv', 'dat', 'db', 'dbf', 'log', 'mdb', 'sav', 'sql', 'tar', 'xml'],
'EXECUTABLE': ['apk', 'bat', 'bin', 'cgi', 'pl', 'com', 'exe', 'gadget', 'jar', 'wsf'],
'FONT': ['fnt', 'fon', 'otf', 'ttf'],
'IMAGE': ['ai', 'bmp', 'gif', 'ico', 'jpeg', 'jpg', 'png', 'ps', 'psd', 'svg', 'tif', 'tiff'],
'INTERNET': ['asp', 'aspx', 'cer', 'cfm', 'css', 'htm', 'html', 'js', 'jsp',
'part', 'php', 'rss', 'xhtml'],
'PRESENTATION': ['key', 'odp', 'pps', 'ppt', 'pptx'],
'PROGRAMMING': ['c', 'class', 'cpp', 'cs', 'h', 'java', 'sh', 'swift', 'vb', 'py'],
'SPREADSHEET': ['ods', 'xlr', 'xls', 'xlsx'],
'SYSTEM': ['bak', 'cab', 'cfg', 'cpl', 'cur', 'dll', 'dmp', 'drv', 'icns', 'ini',
'lnk', 'msi', 'sys', 'tmp'],
'VIDEO': ['3g2', '3gp', 'avi', 'flv', 'h264', 'm4v', 'mkv', 'mov', 'mp4', 'mpg', 'mpeg',
'rm', 'swf', 'vob', 'wmv', 'webm'],
'WORD_PROCESSOR': ['doc', 'docx', 'odt', 'pdf', 'rtf', 'tex', 'txt', 'wks', 'wps', 'wpd'],
'SUBTITLES': ['srt', 'sub', 'sbv'],
'UNCLASSIFIED': []
}
return formats
def get_extension_type(extension):
"""Return extension type ex: mp3 --> AUDIO."""
formats = get_supported_formats()
possible_extensions = tuple(ext for ext, exts in formats.items() if extension.lower() in exts)
if not possible_extensions:
return ('UNCLASSIFIED',)
return possible_extensions
def get_file_extension(filename):
"""Return file extension"""
return filename.split('.')[-1].lower()
def get_folder_extensions(path):
"""Return all folder extensions."""
folder_contents = get_folder_contents(path)
return set([get_file_extension(filename) for filename in folder_contents])
def create_folders(path):
"""Create alpha-numeric folders or type specific folders in the given path."""
folder_contents = get_folder_contents(path)
print(f"Current folder: {str(path).split('/')[-1]}")
print(f'Folder contents ({len(folder_contents)}) items:')
print(105 * '=')
if not folder_contents:
print(f"0 files found in {str(path).split('/')[-1]}")
print(105 * '=')
thank_user()
for number, filename in enumerate(sorted(folder_contents), 1):
if os.path.isdir(filename):
print(f'{number}. Folder: {filename}')
if os.path.isfile(filename):
print(f'{number}. File: {filename}')
print(105 * '=')
action1 = input(f'Enter q to exit. Do you want to group the {len(folder_contents)}'
f' items above Alpha-numerically (A-Z / 0-9) or by type? a/t/q: ')
while action1 != 'a' and action1 != 't' and action1 != 'q':
print(f'Invalid command {action1}')
action1 = input(f'Enter q to exit. Do you want to group the {len(folder_contents)}'
f' items above Alpha-numerically (A-Z / 0-9) or by type? a/t/q: ')
if action1 == 'a':
action2 = input(f"Enter q to exit. Are you sure, do you want to create Alpha-numeric (A-Z / 0-9) folders in "
f"{str(path).split('/')[-1]}? y/n/q: ")
while action2 != 'y' and action2 != 'n' and action2 != 'q':
print(f'Invalid command {action2}')
action2 = input(
f"Enter q to exit. Are you sure, do you want to create Alpha-numeric (A-Z / 0-9) folders in "
f"{str(path).split('/')[-1]}? y/n/q: ")
if action2 == 'n' or action2 == 'q':
print('Creation of new Alpha-numeric (A-Z / 0-9) folders unsuccessful.')
thank_user()
if action2 == 'y':
create_alpha_num_folders(path)
return 'alpha'
if action1 == 't':
folder_extensions = get_folder_extensions(path)
new_folders = set([get_extension_type(extension) for extension in folder_extensions])
new_folder_names = [folder_name for folder_names in new_folders for folder_name in folder_names]
print('New type folders to create: ')
for number, name in enumerate(sorted(new_folder_names), 1):
print(number, name)
action2 = input(f"Enter q to exit. Are you sure do you want to create the {len(new_folder_names)} folders"
f" above in {str(path).split('/')[-1]}? y/n/q: ")
while action2 != 'y' and action2 != 'n' and action2 != 'q':
print(f'Invalid command {action2}')
action2 = input(f"Enter q to exit. Are you sure do you want to create the {len(new_folder_names)} folders"
f" above in {str(path).split('/')[-1]}? y/n/q: ")
if action2 == 'y':
for folder in sorted(new_folder_names):
try:
os.mkdir(folder)
print(f'Creation of {folder} folder successful.')
except FileExistsError:
print(f'Filename {folder} already exists.')
print(f'Creation of {folder} folder unsuccessful.')
return 'type'
if action2 == 'n' or action2 == 'q':
print(f'Creation of {len(new_folder_names)} folders unsuccessful.')
thank_user()
if action1 == 'q':
print('Creation of new folders unsuccessful.')
thank_user()
def organize_files(path):
"""Move files and folders into new organized relevant folders."""
folder_types = create_folders(path)
if folder_types == 'alpha':
new_folder_contents = get_folder_contents(path)
files_to_move = [folder for folder in new_folder_contents if folder not in string.ascii_uppercase
and folder not in string.digits]
new_alpha_folders = [folder for folder in new_folder_contents if folder in string.ascii_uppercase
or folder in string.digits]
print(f"Current folder: {str(path).split('/')[-1]}")
print(f'Folder contents to be moved ({len(files_to_move)}) items:')
print(105 * '=')
for number, filename in enumerate(sorted(files_to_move), 1):
if os.path.isdir(filename):
print(f'{number}. Folder: {filename}')
if os.path.isfile(filename):
print(f'{number}. File: {filename}')
print(105 * '=')
action = input(f'Enter q to exit. Are you sure, do you want to organize the {len(files_to_move)} files above'
f' to Alpha-numeric (A-Z / 0-9) folders? y/n/q: ')
while action != 'q' and action != 'y' and action != 'n':
print(f'Invalid command {action}')
action = input(
f'Enter q to exit. Are you sure, do you want to organize the {len(files_to_move)} files above'
f' to Alpha-numeric (A-Z / 0-9) folders? y/n/q: ')
if action == 'q' or action == 'n':
print(f'Organization of {len(files_to_move)} Alpha-numerically (A-Z / 0-9) unsuccessful.')
thank_user()
if action == 'y':
for filename in files_to_move:
for folder_name in new_alpha_folders:
if filename.startswith(folder_name.lower()) or filename.startswith(folder_name):
shutil.move(filename, folder_name)
print(f'Moving successful ... {filename} to {folder_name}')
if folder_types == 'type':
new_folder_contents = get_folder_contents(path)
files_to_move = [folder for folder in new_folder_contents if folder not in get_supported_formats()]
new_type_folders = [folder for folder in new_folder_contents if folder in get_supported_formats()]
print(f"Current folder: {str(path).split('/')[-1]}")
print(f'Folder contents to be moved ({len(files_to_move)}) items:')
print(105 * '=')
for number, filename in enumerate(sorted(files_to_move, key=get_file_extension), 1):
if os.path.isdir(filename):
print(f'{number}. Folder: {filename}')
if os.path.isfile(filename):
print(f'{number}. File: {filename}')
print(105 * '=')
action = input(f'Enter q to exit. Are you sure, do you want to organize the {len(files_to_move)} files above'
f' into type specific folders? y/n/q: ')
while action != 'y' and action != 'n' and action != 'q':
print(f'Invalid command {action}')
action = input(
f'Enter q to exit. Are you sure, do you want to organize the {len(files_to_move)} files above'
f' into type specific folders? y/n/q: ')
if action == 'n' or action == 'q':
print(f'Organization of {len(files_to_move)} by type unsuccessful.')
thank_user()
if action == 'y':
for filename in files_to_move:
file_type = get_extension_type(get_file_extension(filename))
for folder_name in new_type_folders:
if file_type[0] == folder_name:
shutil.move(filename, folder_name)
print(f'Moving successful ... {filename} to {folder_name}')
thank_user()
if __name__ == '__main__':
welcome_user()
path_to_folder = input('Please enter a valid path or q to exit: ').rstrip()
if path_to_folder == 'q':
thank_user()
organize_files(path_to_folder)