diff --git a/config.py b/config.py index fac7545..86f5af5 100755 --- a/config.py +++ b/config.py @@ -9,8 +9,9 @@ class Config(object): DEFAULTS = { 'main': { 'out_time_format': '%%Y-%%m-%%d_%%H-%%M-%%S', - 'use_exif_first': True, + 'time_src': 'exif,name,attr', 'remove_garbage': True, + 'threads_count': 2, } } diff --git a/fileprop.py b/fileprop.py index c7e0fcb..ac70bf0 100755 --- a/fileprop.py +++ b/fileprop.py @@ -54,17 +54,7 @@ class FileProp(object): self.__type = self.__type_by_ext(ext) - if self.__type == self.IMAGE: - if self.__config['main']['use_exif_first']: - self.__time = self.__time_by_exif(fullname) - if self.__time is None: - self.__time = self.__time_by_name(fname) - else: - self.__time = self.__time_by_name(fname) - if self.__time is None: - self.__time = self.__time_by_exif(fullname) - else: - self.__time = self.__time_by_name(fname) + self.__time = self.__time(fullname, fname) out_name = self.out_name() if out_name: @@ -79,6 +69,21 @@ class FileProp(object): logging.warning('Unknown ext: ' + ext) return self.OTHER + def __time(self, fullname, name): + for src in self.__config['main']['time_src'].split(','): + time = None + if src == 'exif': + time = self.__time_by_exif(fullname) + elif src == 'name': + time = self.__time_by_name(name) + elif src == 'attr': + time = self.__time_by_attr(name) + else: + raise Exception('Wrong time_src: ' + src) + + if time: + return time + def __time_by_name(self, fname): for exp, fs in self.DATE_REX: mat = exp.findall(fname) @@ -95,16 +100,22 @@ class FileProp(object): return None def __time_by_exif(self, fullname): + if self.__type != self.IMAGE: + return None + try: with open(fullname, 'rb') as f: tags = exifread.process_file(f) strtime = tags['EXIF DateTimeOriginal'].values return datetime.datetime.strptime(strtime, '%Y:%m:%d %H:%M:%S') - except (OSError, KeyError): + except (FileNotFoundError, KeyError): return None def __time_by_attr(self, fullname): - self.__time = time.localtime(os.stat(fullname)[stat.ST_MTIME]) + try: + self.__time = time.localtime(os.stat(fullname)[stat.ST_MTIME]) + except (FileNotFoundError, KeyError): + return None def out_name(self): if self.__time: diff --git a/rotate.py b/rotate.py new file mode 100755 index 0000000..b127556 --- /dev/null +++ b/rotate.py @@ -0,0 +1,77 @@ +#!/usr/bin/python3 + +import logging +import subprocess +import concurrent.futures + +import config + + +class Rotator(object): + def __init__(self, config, filenames): + self.__config = config + self.__filenames = filenames + self.__processed = 0 + self.__good = 0 + self.__errors = 0 + + def run(self): + tc = int(self.__config['main']['threads_count']) + with concurrent.futures.ThreadPoolExecutor(max_workers=tc) as executor: + + futures = { + executor.submit(self.__process, fn): + fn for fn in self.__filenames} + + for future in concurrent.futures.as_completed(futures): + self.__processed += 1 + if future.result(): + self.__good += 1 + else: + self.__errors += 1 + + def __process(self, filename): + ok = False + try: + cmd = 'exiftran -aip %s' % filename + p = subprocess.Popen( + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).stderr + + error = '' + while 1: + line = p.readline().decode("utf-8") + if not line: + break + + if line.startswith('processing '): + ok = True + else: + ok = False + error += line + + if error != '': + logging.error('exiftran (%s) error: %s' % (filename, error)) + + except Exception as ex: + logging.error('Rotator process exeption: %s' % ex) + + return ok + + def status(self): + return ( + len(self.__filenames), + self.__processed, + self.__good, + self.__errors) + + +if __name__ == '__main__': + import sys + + rot = Rotator(config.Config(False), sys.argv[1:]) + rot.run() + + print(rot.status())