Subversion Repositories programming

Compare Revisions

Ignore whitespace Rev 120 → Rev 121

/shell_programs/animesorter.py
1,24 → 1,31
#!/usr/bin/python
 
import sys, os, glob, re, shutil
import os, re, shutil, sys
from optparse import OptionParser
 
### DEFAULT CONFIGURATION VARIABLES ###
DICT_FILE = os.path.expanduser('~/bin/animesorter.dict')
WORK_DIR = os.path.expanduser('~/downloads/usenet')
SORT_DIR = '/data/Anime'
WORK_DIR = os.path.expanduser('~/downloads/usenet')
SORT_DIR = os.path.expanduser('/data/Anime')
 
def parsedict(dict=DICT_FILE):
### Globals
options = {}
move_status = []
 
 
def parse_dict():
"""Parses a dictionary file containing the sort definitions in the form:
DIRECTORY = PATTERN
 
Returns a list of tuples, each containing the contents of one line."""
Returns a list of tuples of the form (compiled_regex, to_directory)"""
try:
f = open(dict, 'r', 0)
f = open(options.dict_file, 'r', 0)
try:
data = f.read()
finally:
f.close()
except IOError:
print 'Error opening %s ... exiting!' % dict
print 'Error opening %s ... exiting!' % options.dict_file
sys.exit()
 
### Get a LIST containing each line in the file
25,47 → 32,28
lines = [l for l in data.split('\n') if len(l) > 0]
 
### Split each line into a tuple, and strip each element of spaces
tuples = [(k, v) for k, v in [l.split('=') for l in lines]]
tuples = [(k.strip() ,v.strip()) for k, v in tuples]
result = [(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(tuples)
return tuple(result)
 
def getfiles(dir=WORK_DIR):
"""getfiles(dir):
 
dir is type STRING
 
Return a LIST of the files of type *.{avi,ogm,mkv} that are in the
directory given as a parameter."""
files = []
def get_types_re():
"""Returns a compiled regular expression which will find objects of the
types specified in this function's definition."""
types = ('avi', 'ogm', 'mkv')
types_regex = ''
 
# Match every type in the type array
for t in types:
files.extend( glob.glob('%s/%s' % (dir, '*.%s' % t)) )
for i in types:
types_regex += '%s|' % i
 
files = [f for d,f in [os.path.split(f) for f in files]]
return files
types_regex = '.*(%s)$' % types_regex[:-1]
 
def getdirs(dir=WORK_DIR):
"""getdirs(dir):
return re.compile(types_regex, re.IGNORECASE)
 
dir is type STRING
def get_matches(files, pattern):
"""get_matches(files, pattern):
 
Return a LIST of the subdirectories of the directory given as a parameter."""
dirs = [os.path.join(dir, d) for d in os.listdir(dir) if os.path.isdir(os.path.join(dir, d))]
return dirs
 
def createpattern(string):
"""createpattern(string):
 
Returns a sre.SRE_Pattern created from the string given as a parameter."""
pattern = re.compile(string)
return pattern
 
def getmatches(files, pattern):
"""getmatches(files, pattern):
 
files is type LIST
pattern is type sre.SRE_Pattern
 
73,137 → 61,110
matches = [m for m in files if pattern.search(m)]
return matches
 
def fname_from_match(match):
"""fname_from_match(match):
def move_files(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 directory
if todir[0] != '/':
todir = os.path.join(options.output_dir, todir)
 
match is a LIST containing type sre.SRE_Match
## Create the directory if it doesn't exist
if not os.path.isdir(todir):
try:
os.makedirs(todir)
except:
move_status.append('FAILED to create directory: %s' % todir)
 
Returns a string (the filename) of the LIST match given as a parameter."""
fname = match.string
return fname
## Try to move every file, one at a time
for f in files:
srcname = os.path.join(fromdir, f)
dstname = os.path.join(todir, f)
 
def getmatchnames(matches):
"""getmatchnames(matches):
try:
shutil.move(srcname, dstname)
except:
move_status.append('FAILED to move %s to %s' % (f, todir))
return
 
matches is a String containing (many) objects of type sre.SRE_Match
move_status.append('Moved %s to %s' % (f, todir))
 
Returns a LIST of STRINGS representing the filenames of the matches."""
matchnames = [fname_from_match(n) for n in matches]
return matchnames
def print_prog_header():
if 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'
print
 
def move_file(file, fromdir=WORK_DIR, todir=SORT_DIR):
"""move_file(file, dir):
 
file is a STRING representing a complete filename (with full path)
fromdir is a STRING representing where the file exists currently
destdir is a STRING representing the directory to move the file to
 
Returns either True if the move was successful, False otherwise."""
fromfile = os.path.join(fromdir, file)
destfile = os.path.join(todir, file)
 
try:
if not os.path.isdir(dstdir):
os.makedirs(dstdir)
except:
return False
 
if os.path.exists(destfile):
return False
 
try:
shutil.move(fromfile, destfile)
except:
return False
 
return True
 
def get_dstdir(dir):
"""get_dstdir(dir):
 
Get an appropriate destination directory depending on whether dir
has a slash on the beginning"""
if( dir[0] == '/' ):
return dir
 
return os.path.join(SORT_DIR, dir)
 
def printfailed(moved, failed, cwd):
"""printfailed(moved, failed, cwd):
 
moved is an INTEGER number representing the number of files successfully moved
failed is a LIST of the filenames which could not be moved
cwd is a STRING containing the current working directory"""
if( len(failed) > 0 and moved > 0 ):
def print_dir_header(dir):
if options.verbose:
print 'Working in directory: %s' % dir
print '================================================================================'
 
if( len(failed) > 0 and moved == 0 ):
printwdheader(cwd)
def print_move_status():
if options.verbose:
for i in move_status:
print i
 
for f in failed:
print "Failed to move %s" % f
 
if( len(failed) == 0 and moved == 0 ):
pass
else:
print
 
def printwdheader(dir):
"""Prints out a header telling the user we're working in the directory
passed as an argument"""
print 'Working in directory: %s' % dir
print '================================================================================'
def get_parsed_options():
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')
 
def printmove(num, file, dstdir, cwd):
if( num == 1 ):
printwdheader(cwd)
## Parse the options
(options, args) = parser.parse_args()
 
print "Moved %s to %s!" % (file, dstdir)
## Correct directories
options.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)
 
def mainloop(dir, dict):
"""mainloop(dir, dict):
return options
 
dir is of type STRING
dict is of type LIST of TUPLES
### MAIN IS HERE ###
if( __name__ == '__main__' ):
 
Runs the main sort algorithm on the given directory using the pre-parsed
dictionary passed as a parameter."""
files = getfiles(dir)
subdirs = getdirs(dir)
cwd=dir
moved = 0
failed = []
## Get Options
options = get_parsed_options()
 
for regex, todir in dict:
pattern = createpattern(regex)
matches = getmatches(files, pattern)
dstdir = get_dstdir(todir)
## Print the program's header
print_prog_header()
 
for f in matches:
ret = move_file(f, cwd, dstdir)
## Parse the dictionary
dict = parse_dict()
 
if( ret == False ):
failed.append(f)
else:
moved = moved + 1
printmove(moved, f, dstdir, cwd)
## Start walking through directories
for root, dirs, files in os.walk(options.start_dir):
 
printfailed(moved, failed, cwd)
## Blank the status variable
move_status = []
 
# Call ourself recursively on the subdirectories
for s in subdirs:
mainloop(s, dict)
## Get all of the files in the directory that are of the correct types
types_re = get_types_re()
raw_matches = [f for f in files if types_re.match(f)]
 
##### THE MAIN PROGRAM STARTS HERE #####
if( __name__ == '__main__' ):
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'
print
### Loop through the dictionary and try to move everything that matches
for regex, todir in dict:
matches = get_matches(raw_matches, regex)
 
dict = parsedict()
mainloop(WORK_DIR, dict)
## Move the files if we've found some
if len(matches) > 0:
move_files(matches, root, todir)
 
print 'Goodbye!'
if len(move_status) > 0:
## print header
print_dir_header(root)
 
## print status
print_move_status()