Subversion Repositories programming

Rev

Rev 116 | Blame | Last modification | View Log | RSS feed

#!/usr/bin/python

import sys, os, glob, re, shutil

DICT_FILE = os.path.expanduser('~/bin/animesorter.dict')
WORK_DIR = os.path.expanduser('~/downloads/usenet')
SORT_DIR = '/data/Anime'

def parsedict(dict=DICT_FILE):
    """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."""
    try:
        f = open(dict, 'r', 0)
        try:
            data = f.read()
        finally:
            f.close()
    except IOError:
        print 'Error opening %s ... exiting!' % dict
        sys.exit()

    ### Get a LIST containing each line in the file
    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]

    return tuple(tuples)

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 = []
    types = ('avi', 'ogm', 'mkv')

    # Match every type in the type array
    for t in types:
        files.extend( glob.glob('%s/%s' % (dir, '*.%s' % t)) )

    files = [f for d,f in [os.path.split(f) for f in files]]
    return files

def getdirs(dir=WORK_DIR):
    """getdirs(dir):

    dir is type STRING

    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

    Returns a list of the files matching the pattern as type sre.SRE_Match."""
    matches = [m for m in files if pattern.search(m)]
    return matches

def fname_from_match(match):
    """fname_from_match(match):

    match is a LIST containing type sre.SRE_Match

    Returns a string (the filename) of the LIST match given as a parameter."""
    fname = ''.join(match.string)
    return fname

def getmatchnames(matches):
    """getmatchnames(matches):

    matches is a String containing (many) objects of type sre.SRE_Match

    Returns a LIST of STRINGS representing the filenames of the matches."""
    matchnames = [fname_from_match(n) for n in matches]
    return matchnames

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:
        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 ):
        print '================================================================================'

    if( len(failed) > 0 and moved == 0 ):
        printwdheader(cwd)

    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 printmove(num, file, dstdir, cwd):
    if( num == 1 ):
        printwdheader(cwd)

    print "Moved %s to %s!" % (file, dstdir)

def mainloop(dir, dict):
    """mainloop(dir, dict):

    dir is of type STRING
    dict is of type LIST of TUPLES

    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 = []

    for regex, todir in dict:
        pattern = createpattern(regex)
        matches = getmatches(files, pattern)
        dstdir = get_dstdir(todir)

        for f in matches:
            ret = move_file(f, cwd, dstdir)

            if( ret == False ):
                failed.append(f)
            else:
                moved = moved + 1
                printmove(moved, f, dstdir, cwd)

    printfailed(moved, failed, cwd)

    # Call ourself recursively on the subdirectories
    for s in subdirs:
        mainloop(s, dict)

##### 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

    dict = parsedict()
    mainloop(WORK_DIR, dict)

    print 'Goodbye!'