diff options
Diffstat (limited to 'rapid/filemodify.py')
-rw-r--r-- | rapid/filemodify.py | 159 |
1 files changed, 98 insertions, 61 deletions
diff --git a/rapid/filemodify.py b/rapid/filemodify.py index 98921ae..49a4d24 100644 --- a/rapid/filemodify.py +++ b/rapid/filemodify.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: latin1 -*- -### Copyright (C) 2011-2012 Damon Lynch <damonlynch@gmail.com> +### Copyright (C) 2011-2014 Damon Lynch <damonlynch@gmail.com> ### This program is free software; you can redistribute it and/or modify ### it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ import os.path, fractions import subprocess +import hashlib import multiprocessing import logging logger = multiprocessing.get_logger() @@ -28,9 +29,14 @@ import rpdmultiprocessing as rpdmp import rpdfile import metadataxmp as mxmp import subfolderfile +import config +import problemnotification as pn + +from gettext import gettext as _ WRITE_XMP_INPLACE = rpdfile.NON_RAW_IMAGE_EXTENSIONS + ['dng'] + def lossless_rotate(jpeg): """using exiftran, performs a lossless, inplace translation of a jpeg, preserving time stamps""" try: @@ -40,17 +46,20 @@ def lossless_rotate(jpeg): except OSError: v = None return v - + class FileModify(multiprocessing.Process): - def __init__(self, auto_rotate_jpeg, focal_length, results_pipe, terminate_queue, + def __init__(self, auto_rotate_jpeg, focal_length, verify_file, + refresh_md5_on_file_change, results_pipe, terminate_queue, run_event): multiprocessing.Process.__init__(self) self.results_pipe = results_pipe self.terminate_queue = terminate_queue self.run_event = run_event - + self.auto_rotate_jpeg = auto_rotate_jpeg self.focal_length = focal_length + self.verify_file = verify_file + self.refresh_md5_on_file_change = refresh_md5_on_file_change def check_termination_request(self): """ @@ -61,17 +70,17 @@ class FileModify(multiprocessing.Process): # terminate immediately return True return False - + def create_rational(self, value): return '%s/%s' % (value.numerator, value.denominator) - + def run(self): - + download_count = 0 copy_finished = False - while not copy_finished: + while not copy_finished: logger.debug("Finished %s. Getting next task.", download_count) - + data = self.results_pipe.recv() if len(data) > 2: rpd_file, download_count, temp_full_file_name, thumbnail_icon, thumbnail, copy_finished = data @@ -83,61 +92,89 @@ class FileModify(multiprocessing.Process): return None # pause if instructed by the caller self.run_event.wait() - + if self.check_termination_request(): return None - - if self.auto_rotate_jpeg and rpd_file.file_type == rpdfile.FILE_TYPE_PHOTO: - if rpd_file.extension in rpdfile.JPEG_EXTENSIONS: - lossless_rotate(rpd_file.temp_full_file_name) - - xmp_sidecar = None - # check to see if focal length and aperture data should be manipulated - if self.focal_length is not None and rpd_file.file_type == rpdfile.FILE_TYPE_PHOTO: - if subfolderfile.load_metadata(rpd_file, temp_file=True): - a = rpd_file.metadata.aperture() - if a == '0.0': - logger.info("Adjusting focal length and aperture for %s (%s)", rpd_file.temp_full_file_name, rpd_file.name) - - new_focal_length = fractions.Fraction(self.focal_length,1) - new_aperture = fractions.Fraction(8,1) - if rpd_file.extension in WRITE_XMP_INPLACE: - try: - rpd_file.metadata["Exif.Photo.FocalLength"] = new_focal_length - rpd_file.metadata["Exif.Photo.FNumber"] = new_aperture - rpd_file.metadata.write(preserve_timestamps=True) - logger.debug("Wrote new focal length and aperture to %s (%s)", rpd_file.temp_full_file_name, rpd_file.name) - except: - logger.error("failed to write new focal length and aperture to %s (%s)!", rpd_file.temp_full_file_name, rpd_file.name) - else: - # write to xmp sidecar - xmp_sidecar = mxmp.XmpMetadataSidecar(rpd_file.temp_full_file_name) - xmp_sidecar.set_exif_value('FocalLength', self.create_rational(new_focal_length)) - xmp_sidecar.set_exif_value('FNumber', self.create_rational(new_aperture)) - # store values in rpd_file, so they can be used in the subfolderfile process - rpd_file.new_focal_length = new_focal_length - rpd_file.new_aperture = new_aperture - - if False: - xmp_sidecar.set_contact_url('http://www.website.net') - xmp_sidecar.set_contact_email('user@email.com') - - if xmp_sidecar is not None: - # need to write out xmp sidecar - o = xmp_sidecar.write_xmp_sidecar() - logger.debug("Wrote XMP sidecar file") - logger.debug("exiv2 output: %s", o) - rpd_file.temp_xmp_full_name = rpd_file.temp_full_file_name + '.xmp' - - + copy_succeeded = True + redo_md5 = False + + if self.verify_file: + logger.debug("Verifying file %s....", rpd_file.name) + md5 = hashlib.md5(open(temp_full_file_name).read()).hexdigest() + if md5 <> rpd_file.md5: + logger.critical("%s file verification FAILED", rpd_file.name) + logger.critical("The %s did not download correctly!", rpd_file.title) + + rpd_file.status = config.STATUS_DOWNLOAD_FAILED + + rpd_file.add_problem(None, pn.FILE_VERIFICATION_FAILED, + {'filetype': rpd_file.title}) + rpd_file.error_title = rpd_file.problem.get_title() + rpd_file.error_msg = _("%(problem)s\nFile: %(file)s") % \ + {'problem': rpd_file.problem.get_problems(), + 'file': rpd_file.full_file_name} + copy_succeeded = False + else: + logger.debug("....file %s verified", rpd_file.name) + + + if copy_succeeded: + if self.auto_rotate_jpeg and rpd_file.file_type == rpdfile.FILE_TYPE_PHOTO: + if rpd_file.extension in rpdfile.JPEG_EXTENSIONS: + lossless_rotate(rpd_file.temp_full_file_name) + redo_md5 = True + + xmp_sidecar = None + # check to see if focal length and aperture data should be manipulated + if self.focal_length is not None and rpd_file.file_type == rpdfile.FILE_TYPE_PHOTO: + if subfolderfile.load_metadata(rpd_file, temp_file=True): + a = rpd_file.metadata.aperture() + if a == '0.0': + logger.info("Adjusting focal length and aperture for %s (%s)", rpd_file.temp_full_file_name, rpd_file.name) + + new_focal_length = fractions.Fraction(self.focal_length,1) + new_aperture = fractions.Fraction(8,1) + if rpd_file.extension in WRITE_XMP_INPLACE: + try: + rpd_file.metadata["Exif.Photo.FocalLength"] = new_focal_length + rpd_file.metadata["Exif.Photo.FNumber"] = new_aperture + rpd_file.metadata.write(preserve_timestamps=True) + redo_md5 = True + logger.debug("Wrote new focal length and aperture to %s (%s)", rpd_file.temp_full_file_name, rpd_file.name) + except: + logger.error("failed to write new focal length and aperture to %s (%s)!", rpd_file.temp_full_file_name, rpd_file.name) + else: + # write to xmp sidecar + xmp_sidecar = mxmp.XmpMetadataSidecar(rpd_file.temp_full_file_name) + xmp_sidecar.set_exif_value('FocalLength', self.create_rational(new_focal_length)) + xmp_sidecar.set_exif_value('FNumber', self.create_rational(new_aperture)) + # store values in rpd_file, so they can be used in the subfolderfile process + rpd_file.new_focal_length = new_focal_length + rpd_file.new_aperture = new_aperture + + + + if xmp_sidecar is not None: + # need to write out xmp sidecar + o = xmp_sidecar.write_xmp_sidecar() + logger.debug("Wrote XMP sidecar file") + logger.debug("exiv2 output: %s", o) + rpd_file.temp_xmp_full_name = rpd_file.temp_full_file_name + '.xmp' + + if self.refresh_md5_on_file_change and redo_md5: + rpd_file.md5 = hashlib.md5(open(temp_full_file_name).read()).hexdigest() + + + rpd_file.metadata = None #purge metadata, as it cannot be pickled - - self.results_pipe.send((rpdmp.CONN_PARTIAL, + + + self.results_pipe.send((rpdmp.CONN_PARTIAL, (copy_succeeded, rpd_file, download_count, - temp_full_file_name, + temp_full_file_name, thumbnail_icon, thumbnail))) - - self.results_pipe.send((rpdmp.CONN_COMPLETE, None)) - - + + self.results_pipe.send((rpdmp.CONN_COMPLETE, None)) + + |