Subversion Repositories programming

Rev

Rev 180 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
116 ira 1
#!/usr/bin/python
2
 
121 ira 3
import os, re, shutil, sys
4
from optparse import OptionParser
116 ira 5
 
121 ira 6
### DEFAULT CONFIGURATION VARIABLES ###
175 ira 7
DICT_FILE = os.path.expanduser('~/.config/animesorter/animesorter.dict')
121 ira 8
WORK_DIR =  os.path.expanduser('~/downloads/usenet')
9
SORT_DIR =  os.path.expanduser('/data/Anime')
116 ira 10
 
181 ira 11
class AnimeSorter:
121 ira 12
 
181 ira 13
    def __init__(self):
14
        self.options = {}
15
        self.move_status = []
121 ira 16
 
181 ira 17
    def parse_dict(self):
18
        """Parses a dictionary file containing the sort definitions in the form:
19
        DIRECTORY = PATTERN
116 ira 20
 
181 ira 21
        Returns a list of tuples of the form (compiled_regex, to_directory)"""
22
 
116 ira 23
        try:
181 ira 24
            f = open(self.options.dict_file, 'r', 0)
25
            try:
26
                data = f.read()
27
            finally:
28
                f.close()
29
        except IOError:
30
            print 'Error opening %s ... exiting!' % options.dict_file
31
            sys.exit()
116 ira 32
 
181 ira 33
        ### Get a LIST containing each line in the file
34
        lines = [l for l in data.split('\n') if len(l) > 0]
116 ira 35
 
181 ira 36
        ### Split each line into a tuple, and strip each element of spaces
37
        result = [(r, d) for r, d in [l.split('=') for l in lines]]
38
        result = [(r.strip() ,d.strip()) for r, d in result]
39
        result = [(re.compile(r), d) for r, d in result]
116 ira 40
 
181 ira 41
        return tuple(result)
116 ira 42
 
181 ira 43
    def get_types_re(self):
44
        """Returns a compiled regular expression which will find objects of the
45
        types specified in this function's definition."""
116 ira 46
 
181 ira 47
        types = ('avi', 'ogm', 'mkv', 'mp4')
48
        types_regex = ''
116 ira 49
 
181 ira 50
        for i in types:
51
            types_regex += '%s|' % i
116 ira 52
 
181 ira 53
        types_regex = '.*(%s)$' % types_regex[:-1]
116 ira 54
 
181 ira 55
        return re.compile(types_regex, re.IGNORECASE)
116 ira 56
 
181 ira 57
    def get_matches(self, files, pattern):
58
        """get_matches(files, pattern):
116 ira 59
 
181 ira 60
        files is type LIST
61
        pattern is type sre.SRE_Pattern
116 ira 62
 
181 ira 63
        Returns a list of the files matching the pattern as type sre.SRE_Match."""
116 ira 64
 
181 ira 65
        matches = [m for m in files if pattern.search(m)]
66
        return matches
116 ira 67
 
181 ira 68
    def move_files(self, files, fromdir, todir):
69
        """move_files(files, fromdir, todir):
70
        Move the files represented by the list FILES from FROMDIR to TODIR"""
71
        ## Check for a non-default directory
72
        if todir[0] != '/':
73
            todir = os.path.join(self.options.output_dir, todir)
116 ira 74
 
181 ira 75
        ## Create the directory if it doesn't exist
76
        if not os.path.isdir(todir):
77
            try:
78
                os.makedirs(todir)
79
            except:
80
                self.move_status.append('FAILED to create directory: %s' % todir)
116 ira 81
 
181 ira 82
        ## Try to move every file, one at a time
83
        for f in files:
84
            srcname = os.path.join(fromdir, f)
85
            dstname = os.path.join(todir, f)
116 ira 86
 
181 ira 87
            try:
88
                shutil.move(srcname, dstname)
89
            except:
90
                self.move_status.append('FAILED to move %s to %s' % (f, todir))
91
                return
116 ira 92
 
181 ira 93
            self.move_status.append('Moved %s to %s' % (f, todir))
116 ira 94
 
181 ira 95
    def print_prog_header(self):
96
        if self.options.verbose:
97
            print 'Regular Expression File Sorter (aka animesorter)'
98
            print '================================================================================'
99
            print 'Copyright (c) 2005, Ira W. Snyder (devel@irasnyder.com)'
100
            print 'All rights reserved.'
101
            print 'This program is licensed under the GNU GPL v2'
102
            print
116 ira 103
 
181 ira 104
    def print_dir_header(self, dir):
105
        if self.options.verbose:
106
            print 'Working in directory: %s' % dir
107
            print '================================================================================'
116 ira 108
 
181 ira 109
    def print_move_status(self):
110
        if self.options.verbose:
111
            for i in self.move_status:
112
                print i
116 ira 113
 
181 ira 114
            print
116 ira 115
 
181 ira 116
    def get_parsed_options(self):
117
        parser = OptionParser()
118
        parser.add_option('-q', '--quiet', action='store_false', dest='verbose',
119
                          default=True, help='don\'t print status messages to stdout')
120
        parser.add_option('-d', '--dict', dest='dict_file', default=DICT_FILE,
121
                          help='read dictionary from FILE', metavar='FILE')
122
        #parser.add_option('-n', '--not-recursive', action='store_false', dest='recursive',
123
        #                   default=True, help='don\'t run recursively')
124
        parser.add_option('-s', '--start-dir', dest='start_dir', default=WORK_DIR,
125
                          help='start running at directory DIR', metavar='DIR')
126
        parser.add_option('-o', '--output-dir', dest='output_dir', default=SORT_DIR,
127
                          help='sort files into DIR', metavar='DIR')
116 ira 128
 
181 ira 129
        ## Parse the options
130
        (options, args) = parser.parse_args()
116 ira 131
 
181 ira 132
        ## Correct directories
133
        options.dict_file = os.path.abspath(options.dict_file)
134
        options.start_dir = os.path.abspath(options.start_dir)
135
        options.output_dir = os.path.abspath(options.output_dir)
116 ira 136
 
181 ira 137
        return options
116 ira 138
 
181 ira 139
    def main(self):
116 ira 140
 
181 ira 141
        ## Get Options
142
        self.options = self.get_parsed_options()
116 ira 143
 
181 ira 144
        ## Print the program's header
145
        self.print_prog_header()
116 ira 146
 
181 ira 147
        ## Parse the dictionary
148
        dict = self.parse_dict()
116 ira 149
 
181 ira 150
        ## Start walking through directories
151
        for root, dirs, files in os.walk(self.options.start_dir):
116 ira 152
 
181 ira 153
            ## Blank the status variable
154
            self.move_status = []
116 ira 155
 
181 ira 156
            ## Get all of the files in the directory that are of the correct types
157
            types_re = self.get_types_re()
158
            raw_matches = [f for f in files if types_re.match(f)]
116 ira 159
 
181 ira 160
            ### Loop through the dictionary and try to move everything that matches
161
            for regex, todir in dict:
162
                matches = self.get_matches(raw_matches, regex)
121 ira 163
 
181 ira 164
                ## Move the files if we've found some
165
                if len(matches) > 0:
166
                    self.move_files(matches, root, todir)
175 ira 167
 
181 ira 168
            if len(self.move_status) > 0:
169
                ## print header
170
                self.print_dir_header(root)
171
 
172
                ## print status
173
                self.print_move_status()
174
 
175 ira 175
### MAIN IS HERE ###
176
if __name__ == '__main__':
181 ira 177
    as = AnimeSorter()
178
    as.main()
175 ira 179