#!/usr/bin/python3 """ This helper script is able to extract a date and time from the name of all files in a directory and set their respective UNIX mtime (the modified timestamp). Copyright (C) 2024 Benjamin Burkhardt 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 the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ """ Useful links: - https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior - https://www.datacamp.com/tutorial/converting-strings-datetime-objects - https://scrapfly.io/blog/parsing-datetime-strings-with-python-and-dateparser/ - https://stackoverflow.com/questions/466345/convert-string-jun-1-2005-133pm-into-datetime """ from datetime import datetime from argparse import ArgumentParser, RawTextHelpFormatter import os import sys class COLORS: HEADER = '\033[95m' OKBLUE = '\033[94m' OKCYAN = '\033[96m' OKGREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' class LOGGER: def __init__(self, verbose: bool = False): self.verbose = verbose def log(self, to_log, verbose=False, end="\n"): to_log = to_log + COLORS.ENDC if (self.verbose and verbose) or not verbose: # only print if it's not verbose or verbose is enabled print(to_log, end=end) # set up the ArgumentParser for the CLI parser = ArgumentParser( description='filename2mtime.py Copyright (C) 2024 Benjamin Burkhardt\r\n' 'This program comes with ABSOLUTELY NO WARRANTY and is licensed under the ' 'GNU General Public License 3.\r\n' 'You should have received a copy of the GNU General Public License\r\n' 'along with this program. If not, see .\r\n' '\r\n' 'This helper script is able to extract a date and time from the name of all \r\n' 'files in a directory and set their respective UNIX mtime (the modified timestamp).\r\n' 'BE AWARE THAT ALL CHANGES TO THE FILES CANNOT BE UNDONE! USE AT YOUR OWN RISK!', epilog='by Benjamin Burkhardt, 2024', add_help=False, formatter_class=RawTextHelpFormatter) parser.add_argument('-f', '--format', type=str, default="", help="give the format of the strings\r\nsee https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior for more details") parser.add_argument('-e', '--format-error-exit', action='store_true', default=False, help='exit if the format does not fit to one file') # on/off flag parser.add_argument('-v', '--verbose', action='store_true', default=False, help='enable verbose output') # on/off flag parser.add_argument('-h', '--help', action='store_true', default=False, help='display this help message and exit') # on/off flag # parse given arguments args = parser.parse_args() # print help and exit if prompted to if args.help or not len(sys.argv) > 1: parser.print_help() exit(0) # set up logger logger = LOGGER(args.verbose) # check for an empty format if args.format == '' and not args.auto_format: logger.log(COLORS.FAIL + 'You need to specify a format.') parser.print_usage() exit(1) # Start of the real program, format is surely set all_files = os.listdir() parsed_datetimes = {} longest_filename_len = max([len(f) for f in all_files]) for f in all_files: try: parsed_datetimes[f] = datetime.strptime(f, args.format) logger.log(f"Detecting: {f} -> {parsed_datetimes[f]}", verbose=True) except ValueError: if args.format_error_exit: logger.log(f"{COLORS.WARNING}{f.ljust(longest_filename_len + 1)}: Failed to parse the date and time.") logger.log(f"{COLORS.FAIL}EXITING (as -e flag was set)!") exit(1) else: logger.log(f"{f.ljust(longest_filename_len + 1)}: {COLORS.WARNING}Failed to parse the date and time.") for f, dt in parsed_datetimes.items(): # get atime timestamp (as os.utime requires this as an argument - we leave it unchanged) atime_timestamp = os.stat(f).st_atime # get the mtime timestamp from the respective datetime object mtime_timestamp = dt.timestamp() # set the new mtime (atime stays unchanged) os.utime(f, (atime_timestamp, mtime_timestamp))