Rev 180 | Blame | Last modification | View Log | RSS feed
#!/usr/bin/pythonimport os, re, shutil, sysfrom optparse import OptionParser### DEFAULT CONFIGURATION VARIABLES ###DICT_FILE = os.path.expanduser('~/.config/animesorter/animesorter.dict')WORK_DIR = os.path.expanduser('~/downloads/usenet')SORT_DIR = os.path.expanduser('/data/Anime')class AnimeSorter:def __init__(self):self.options = {}self.move_status = []def parse_dict(self):"""Parses a dictionary file containing the sort definitions in the form:DIRECTORY = PATTERNReturns a list of tuples of the form (compiled_regex, to_directory)"""try:f = open(self.options.dict_file, 'r', 0)try:data = f.read()finally:f.close()except IOError:print 'Error opening %s ... exiting!' % options.dict_filesys.exit()### Get a LIST containing each line in the filelines = [l for l in data.split('\n') if len(l) > 0]### Split each line into a tuple, and strip each element of spacesresult = [(r, d) for r, d in [l.split('=') for l in lines]]result = [(r.strip() ,d.strip()) for r, d in result]result = [(re.compile(r), d) for r, d in result]return tuple(result)def get_types_re(self):"""Returns a compiled regular expression which will find objects of thetypes specified in this function's definition."""types = ('avi', 'ogm', 'mkv', 'mp4')types_regex = ''for i in types:types_regex += '%s|' % itypes_regex = '.*(%s)$' % types_regex[:-1]return re.compile(types_regex, re.IGNORECASE)def get_matches(self, files, pattern):"""get_matches(files, pattern):files is type LISTpattern is type sre.SRE_PatternReturns a list of the files matching the pattern as type sre.SRE_Match."""matches = [m for m in files if pattern.search(m)]return matchesdef move_files(self, files, fromdir, todir):"""move_files(files, fromdir, todir):Move the files represented by the list FILES from FROMDIR to TODIR"""## Check for a non-default directoryif todir[0] != '/':todir = os.path.join(self.options.output_dir, todir)## Create the directory if it doesn't existif not os.path.isdir(todir):try:os.makedirs(todir)except:self.move_status.append('FAILED to create directory: %s' % todir)## Try to move every file, one at a timefor f in files:srcname = os.path.join(fromdir, f)dstname = os.path.join(todir, f)try:shutil.move(srcname, dstname)except:self.move_status.append('FAILED to move %s to %s' % (f, todir))returnself.move_status.append('Moved %s to %s' % (f, todir))def print_prog_header(self):if self.options.verbose:print 'Regular Expression File Sorter (aka animesorter)'print '================================================================================'print 'Copyright (c) 2005, Ira W. Snyder (devel@irasnyder.com)'print 'All rights reserved.'print 'This program is licensed under the GNU GPL v2'def print_dir_header(self, dir):if self.options.verbose:print 'Working in directory: %s' % dirprint '================================================================================'def print_move_status(self):if self.options.verbose:for i in self.move_status:print idef get_parsed_options(self):parser = OptionParser()parser.add_option('-q', '--quiet', action='store_false', dest='verbose',default=True, help='don\'t print status messages to stdout')parser.add_option('-d', '--dict', dest='dict_file', default=DICT_FILE,help='read dictionary from FILE', metavar='FILE')#parser.add_option('-n', '--not-recursive', action='store_false', dest='recursive',# default=True, help='don\'t run recursively')parser.add_option('-s', '--start-dir', dest='start_dir', default=WORK_DIR,help='start running at directory DIR', metavar='DIR')parser.add_option('-o', '--output-dir', dest='output_dir', default=SORT_DIR,help='sort files into DIR', metavar='DIR')## Parse the options(options, args) = parser.parse_args()## Correct directoriesoptions.dict_file = os.path.abspath(options.dict_file)options.start_dir = os.path.abspath(options.start_dir)options.output_dir = os.path.abspath(options.output_dir)return optionsdef main(self):## Get Optionsself.options = self.get_parsed_options()## Print the program's headerself.print_prog_header()## Parse the dictionarydict = self.parse_dict()## Start walking through directoriesfor root, dirs, files in os.walk(self.options.start_dir):## Blank the status variableself.move_status = []## Get all of the files in the directory that are of the correct typestypes_re = self.get_types_re()raw_matches = [f for f in files if types_re.match(f)]### Loop through the dictionary and try to move everything that matchesfor regex, todir in dict:matches = self.get_matches(raw_matches, regex)## Move the files if we've found someif len(matches) > 0:self.move_files(matches, root, todir)if len(self.move_status) > 0:## print headerself.print_dir_header(root)## print statusself.print_move_status()### MAIN IS HERE ###if __name__ == '__main__':as = AnimeSorter()as.main()