from optparse import OptionParser import time, logging, os, sys, win32file, string, shutil from os import sep class DCIM_Mover: def __init__(self, src, dest, logger = None): # Setup Logger if logger is None: logger = logging.getLogger('DCIM_Mover') self.logger = logger self.src = src self.dest = dest def transfer(self): # The method called to transfer files from source to destination self.logger.warning('Moving All Pictures from %s to %s.' %(self.src, self.dest)) # Walk through the root source directory for root, dirs, files in os.walk(self.src, topdown=False): for name in files: src_path = os.path.join(root,name) dest_dir, dest_name = self.getDest(src_path) dest_dir = os.path.join(self.dest, dest_dir) if not os.access(dest_dir, os.F_OK): os.makedirs(dest_dir) dest_path = os.path.join(dest_dir, dest_name) self.logger.info('Moving %s to %s' %(src_path, dest_path)) try: # Move them or log an error. # By copying first you at least copy it over, it just still exists on the disk. shutil.copy(src_path, dest_path) os.remove(src_path) except: self.logger.error('Could not move file: %s' %src_path) for name in dirs: src_dir = os.path.join(root,name) try: os.rmdir(src_dir) except: self.logger.error('Could not remove folder: %s' %src_dir) def getDest(self, src_path): # This is where we format the folder structure ctime = time.gmtime(os.path.getctime(src_path)) dir = time.strftime('%Y', ctime) + sep dir += time.strftime('%m %b', ctime) name = src_path.split(sep)[-1] return dir, name def removabledisks(): # Find and return all drives that are removable driveletters=[] for drive in string.letters[len(string.letters)/2:]: if win32file.GetDriveType(drive+":")==win32file.DRIVE_REMOVABLE: driveletters.append(drive+":") return driveletters def getDCIMDirs(): # Find removable drives with a DCIM directory drives = [] for drive in removabledisks(): path = '%s\\DCIM' %drive if os.access(path, os.F_OK): drives.append(path) return drives def setupLogging(level): if not os.access('log', os.F_OK): os.mkdir('log') logging.basicConfig(level=level, format='%(asctime)s [%(levelname)s] %(message)s', filename=os.path.abspath('log/copy_pics.log'), filemode='w') # define a Handler which writes INFO messages or higher to the sys.stderr console = logging.StreamHandler() console.setLevel(level) # set a format which is simpler for console use formatter = logging.Formatter('%(name)-5s: %(asctime)-3s [%(levelname)-5s] %(message)s') # tell the handler to use this format console.setFormatter(formatter) # add the handler to the root logger logging.getLogger('').addHandler(console) logger = logging.getLogger('TestMonitor') return logger def main(): # This method parses the options set at the command line and initializes the logger. parser = OptionParser() parser.add_option("-l", "--logging", type='int', dest="debug", help="LOG level. See http://docs.python.org/library/logging.html. Default: INFO", metavar="LOG", default=logging.INFO) parser.add_option("-s", "--src", type='string', dest="src", help="Source drive or DIRECTORY. Script will search for all DCIM directories if not specified.", metavar="DIRECTORY", default=None) parser.add_option("-d", "--dest", type='string', dest="dest", help="Copy pictures to DIRECTORY(not including year or month). This is required.", metavar="DIRECTORY", default=None) opts, args = parser.parse_args() logger = setupLogging(opts.debug) return opts, args, logger if __name__ == "__main__": opts, args, logger = main() if opts.dest is None: logger.critical('Destination not provided. Please specify a destination via the --dest=DIR command line option') sys.exit(1) if opts.src is None: dirs = getDCIMDirs() for dir in dirs: logger.debug('Moving Pictures from: %s' %(dir)) mover = DCIM_Mover(dir, opts.dest) mover.transfer() else: mover = DCIM_Mover(opts.src, opts.dest) mover.transfer()