#!/usr/bin/env python3 from unidecode import unidecode from os import rename from os.path import basename, dirname from os.path import join as joinpath from argparse import ArgumentParser from sys import exit class normalisename: @property def operation(self): return self._operation @operation.setter def operation(self, value): if not callable(value): raise ValueError('Operation must be callable!') self._operation = value @property def separator(self): return self._separator @property def whitelist(self): return self._whitelist def __init__(self, operation, separator, whitelist): self._operation = None self.operation = operation self._separator = separator self._whitelist = set(whitelist) def normalise(self, files): for path in files: if not self.check_normal(path): dir = dirname(path) file = basename(path) normalpath = joinpath(dir, self.normalname(file)) self.operation(path, normalpath) def check_normal(self, file): file = basename(file) return file == self.normalname(file) def normalname(self, filename): return unidecode(''.join(ch for ch in filename.replace(' ', self.separator) if ch.isalnum() or ch in self.whitelist)) if __name__ == '__main__': # parse arguments parser = ArgumentParser(description='Eliminate funky stuff from filenames.') parser.add_argument('--separator', '-s', type=str, nargs='?', default='_', help='Set separator to use (to replace spaces with).') parser.add_argument('--allow', '-a', type=str, nargs='?', action='append', help='Specify a special character to allow (it will not be removed).') parser.add_argument('--disallow', '-d', type=str, nargs='?', action='append', help='Specify a special character to disallow (it will removed).') parser.add_argument('--whitelist', '-w', type=str, help='Overwrite default whitelist (format: whitespace separated string).') mgroup = parser.add_mutually_exclusive_group() mgroup.add_argument('--dryrun', '-n', action='store_true', help='Do not touch anything, just tell me what would change!') mgroup.add_argument('--funky', '-f', action='store_true', help='List filenames with special characters') parser.add_argument('files', type=str, nargs='+', help='File(s) to normalise the name of (relative or absolute path).') args = parser.parse_args() # verify arguments if args.disallow: if args.separator in args.disallow: exit('Disallowing your chosen separator makes no sense!') # declare special characters that will not be removed (spaces are handled elsewhere) whitelist = {' ', '.', '-'} if args.whitelist: whitelist = set(args.whitelist.split()) # modify whitelist based on arguments whitelist.add(args.separator) if args.allow: whitelist = whitelist.union(set(args.allow)) if args.disallow: whitelist = whitelist.difference(set(args.disallow)) # define operations listchanges = lambda a, b: print('{}{} --> {}'.format(a, ' '*(60-len(a)), b)) listfunky = lambda a, b: print(b) operation = rename if args.dryrun: operation = listchanges elif args.funky: operation = listfunky normalisename(operation, args.separator, whitelist).normalise(args.files)