Example #1
0
def set_file_modified_time_from_metadata(path: str):
    """
    Traverse a path, seeking photos & videos, and when located,
    set the file's modification time on the file system to match the
    metadata value in the file (e.g. exif, or video metadata (if
    valid)).

    Preserves access time.

    :param path: the folder which to walk
    """

    with exiftool.ExifTool() as exiftool_process:
        for dir_name, subdirs, file_list in walk(path):
            for file_name in file_list:
                file_type = fileformats.file_type_from_splitext(
                    file_name=file_name)
                if file_type is not None:
                    file = os.path.join(dir_name, file_name)
                    modification_time = os.path.getmtime(file)
                    try:
                        if file_type == FileType.photo:
                            metadata = metadataphoto.MetaData(
                                full_file_name=file,
                                et_process=exiftool_process)
                        else:
                            metadata = metadatavideo.MetaData(
                                full_file_name=file,
                                et_process=exiftool_process)
                    except:
                        print("Could not load metadata for %s" % file)
                        break

                    dt = metadata.date_time(missing=None)
                    if dt is not None:
                        ts = time.mktime(dt.timetuple())
                        if ts != modification_time:
                            statinfo = os.stat(file)
                            access_time = statinfo.st_atime
                            print("Setting modification time for %s to %s" %
                                  (file_name, dt.strftime('%c')))
                            try:
                                os.utime(file, times=(access_time, ts))
                                print("Set modification time for %s to %s" %
                                      (file_name, dt.strftime('%c')))
                            except:
                                print(
                                    "Setting file modificaiton time failed for %s"
                                    % file_name)
 def do_work(self):
     if False:
         # exiv2 pumps out a LOT to stderr - use cautiously!
         context = show_errors()
         self.error_stream = sys.stderr
     else:
         # Redirect stderr, hiding error output from exiv2
         context = stdchannel_redirected(sys.stderr, os.devnull)
         self.error_stream = sys.stdout
     with context:
         # In some situations, using a context manager for exiftool can
         # result in exiftool processes not being terminated. So let's
         # handle starting and terminating it manually.
         self.exiftool_process = exiftool.ExifTool()
         self.exiftool_process.start()
         self.process_files()
         self.exit()
Example #3
0
        return '1920'

    def height(self, stream=0, missing=''):
        return '1080'

    def frames_per_second(self, stream=0, missing=''):
        return '24'

    def fourcc(self, stream=0, missing=''):
        return 'AVC1'


if __name__ == '__main__':
    import sys

    with exiftool.ExifTool() as et_process:
        if (len(sys.argv) != 2):
            print('Usage: ' + sys.argv[0] +
                  ' path/to/video/containing/metadata')
        else:
            file = sys.argv[1]

            print("ExifTool", EXIFTOOL_VERSION)
            m = MetaData(file, et_process)
            dt = m.date_time()
            print(dt)
            print("%sx%s" % (m.width(), m.height()))
            print("Length:", m.length())
            print("FPS: ", m.frames_per_second())
            print("Codec:", m.codec())
Example #4
0
    def orientation(self, missing=''):
        return 1

    def file_number(self, missing=''):
        return '428'


if __name__ == '__main__':
    import sys

    if (len(sys.argv) != 2):
        print('Usage: ' + sys.argv[0] + ' path/to/photo/containing/metadata')
        m = DummyMetaData()
        et_process = None
    else:
        et_process = exiftool.ExifTool()
        et_process.start()
        m = MetaData(full_file_name=sys.argv[1], et_process=et_process)

    print("f" + m.aperture('missing '))
    print("ISO " + m.iso('missing '))
    print(m.exposure_time(missing='missing ') + " sec")
    print(m.exposure_time(alternativeFormat=True, missing='missing '))
    print(m.focal_length('missing ') + "mm")
    print(m.camera_make())
    print(m.camera_model())
    print(m.short_camera_model())
    print(m.short_camera_model(includeCharacters="\-"))
    print(m.date_time())
    print(m.orientation())
    print('Serial number:', m.camera_serial(missing='missing'))
Example #5
0
    def run(self) -> None:
        """
        Generate subfolder and filename, and attempt to move the file
        from its temporary directory.

        Move video THM and/or audio file if there is one.

        If successful, increment sequence values.

        Report any success or failure.
        """
        i = 0

        # Dict of filename keys and int values used to track ints to add as
        # suffixes to duplicate files
        self.duplicate_files = {}

        self.initialise_downloads_today_stored_number()

        self.sequences = gn.Sequences(self.downloads_today_tracker,
                                      self.prefs.stored_sequence_no)

        with stdchannel_redirected(sys.stderr, os.devnull):
            with exiftool.ExifTool() as self.exiftool_process:
                while True:
                    if i:
                        logging.debug("Finished %s. Getting next task.", i)

                    # rename file and move to generated subfolder
                    directive, content = self.receiver.recv_multipart()

                    self.check_for_command(directive, content)

                    data = pickle.loads(content)  # type: RenameAndMoveFileData
                    if data.message == RenameAndMoveStatus.download_started:

                        # reinitialize downloads today and stored sequence number
                        # in case the user has updated them via the user interface
                        self.initialise_downloads_today_stored_number()
                        self.sequences.downloads_today_tracker = self.downloads_today_tracker
                        self.sequences.stored_sequence_no = self.prefs.stored_sequence_no

                        dl_today = self.downloads_today_tracker.get_or_reset_downloads_today(
                        )
                        logging.debug("Completed downloads today: %s",
                                      dl_today)

                        self.initialise_sequence_number_usage()

                        self.must_synchronize_raw_jpg = self.prefs.must_synchronize_raw_jpg(
                        )

                        self.problems = RenamingProblems()

                    elif data.message == RenameAndMoveStatus.download_completed:
                        if len(self.problems):
                            self.content = pickle.dumps(
                                RenameAndMoveFileResults(
                                    problems=self.problems),
                                pickle.HIGHEST_PROTOCOL)
                            self.send_message_to_sink()

                        # Ask main application process to update prefs with stored
                        # sequence number and downloads today values. Cannot do it
                        # here because to save QSettings, QApplication should be
                        # used.
                        self.content = pickle.dumps(
                            RenameAndMoveFileResults(
                                stored_sequence_no=self.sequences.
                                stored_sequence_no,
                                downloads_today=self.downloads_today_tracker.
                                downloads_today), pickle.HIGHEST_PROTOCOL)
                        dl_today = self.downloads_today_tracker.get_or_reset_downloads_today(
                        )
                        logging.debug("Downloads today: %s", dl_today)
                        self.send_message_to_sink()
                    else:
                        rpd_file = data.rpd_file
                        download_count = data.download_count

                        if data.download_succeeded:
                            move_succeeded = self.process_file(
                                rpd_file, download_count)
                            if not move_succeeded:
                                self.process_rename_failure(rpd_file)
                            else:
                                # Record file as downloaded in SQLite database
                                try:
                                    self.downloaded.add_downloaded_file(
                                        name=rpd_file.name,
                                        size=rpd_file.size,
                                        modification_time=rpd_file.
                                        modification_time,
                                        download_full_file_name=rpd_file.
                                        download_full_file_name)
                                except sqlite3.OperationalError as e:
                                    # This should never happen because this is the only process
                                    # writing to the database..... but just in case
                                    logging.error(
                                        "Database error adding download file %s: %s. Will not "
                                        "retry.",
                                        rpd_file.download_full_file_name, e)
                        else:
                            move_succeeded = False

                        rpd_file.metadata = None
                        self.content = pickle.dumps(
                            RenameAndMoveFileResults(
                                move_succeeded=move_succeeded,
                                rpd_file=rpd_file,
                                download_count=download_count),
                            pickle.HIGHEST_PROTOCOL)
                        self.send_message_to_sink()

                        i += 1