def rename_in_csvs(timestring="", fileext=".JPG"): """ use backup in saves; rename file reverences in csv in setexif directory :param timestring: time of backup :param fileext: file extension """ log_function_call(rename_in_csvs.__name__) dirname = get_saves_dir() tagFile = os.path.join(dirname, "Tags" + fileext + "_" + timestring + ".npz") if not timestring or os.path.isfile(tagFile): tagFiles = [x for x in os.listdir(dirname) if ".npz" in x] tagFile = os.path.join(dirname, tagFiles[-1]) Tagdict = np.load(tagFile, allow_pickle=True)["Tagdict"].item() log().debug("length of Tagdict: %d", len(list(Tagdict.values())[0])) csv_filenames = filterFiles(os.listdir(get_setexif_dir()), [".csv"]) csv_filenames = [ os.path.join(get_setexif_dir(), csv_filename) for csv_filename in csv_filenames ] for csv_filename in csv_filenames: with open(csv_filename, "r", encoding="utf-8") as file: data = file.read() for i in range(len(list(Tagdict.values())[0])): data = data.replace(Tagdict["File Name"][i], Tagdict["File Name new"][i]) with open(csv_filename, "w", encoding="utf-8") as file: file.write(data)
def copy_exif_via_mainname(origin: str, target: str, overwriteDateTime: bool = False, file_types: Iterable = settings.image_types): """ copy exif information from files in directory origin to target files are matched via main name -> processed files can get exif information of original files :param overwriteDateTime: whether to overwrite already exiting "Date/Time Original" :param origin: where exif infos should be read :param target: where exif infos should be written to :param file_types: of target files, default: all image types """ log_function_call(copy_exif_via_mainname.__name__, origin, target) inpath = os.getcwd() target_dict = {} exclusion_tags = ["--PreviewImage", "--ThumbnailImage", "--Rating"] command = "-TagsFromFile" for (dirpath, dirnames, filenames) in os.walk(os.path.join(inpath, target)): if is_invalid_path(dirpath): continue filenames = filterFiles(filenames, file_types) for filename in filenames: if not overwriteDateTime: tagDict = read_exiftag(dirpath, filename) if hasDateTime(tagDict): continue main = FilenameAccessor(filename).mainname() target_dict.setdefault(main, []).append(os.path.join(dirpath, filename)) for (dirpath, dirnames, filenames) in os.walk(os.path.join(inpath, origin)): if is_invalid_path(dirpath): continue filenames = filterFiles(filenames, settings.image_types) for filename in filenames: main = FilenameAccessor(filename).mainname() if not main in target_dict: continue if filename in [os.path.basename(target_file) for target_file in target_dict[main]]: continue orgin_file = os.path.join(dirpath, filename) for target_file in target_dict[main]: commands = [command, orgin_file, target_file] call_exiftool_direct(exclusion_tags + commands) del target_dict[main]
def fake_date(start='2000:01:01', write=True, folder_dict: OrderedDict = None): """ each file in a directory is one second later each dir is one day later :param start: the date on which to start generate fake dates :param write: whether should write or only print :param folder_dict: foldername to date """ log_function_call(fake_date.__name__, start) inpath = os.getcwd() start_time_part = ' 06:00:00.000' start_time = giveDatetime(start + start_time_part) dir_counter = -1 for (dirpath, dirnames, filenames) in os.walk(inpath): if is_invalid_path(dirpath): continue filenames = filterFiles(filenames, settings.image_types + settings.video_types) if not filenames or len(filenames) == 0: continue if folder_dict: dirpath_rel = os.path.relpath(dirpath, inpath) if not dirpath_rel in folder_dict: continue else: dirtime = giveDatetime(folder_dict[dirpath_rel] + start_time_part) else: dir_counter += 1 dirtime = start_time + dt.timedelta(days=dir_counter) log().info(dirtime) secounds = 0 minutes = 0 lastname = "" for filename in filenames: if len(filename) == len(lastname) and remove_ext(filename)[:-2] == remove_ext(lastname)[:-2]: secounds += 1 else: secounds = 0 minutes += 1 lastname = filename time = dirtime + dt.timedelta(minutes=minutes, seconds=secounds) time_string = dateformating(time, "YYYY:MM:DD HH:mm:ss") if write: # CreateDate is sometimes set and google fotos gives it precedence over DateTimeOriginal write_exiftag({"DateTimeOriginal": time_string}, dirpath, filename, ["-DateCreated=", "-TimeCreated=", "-CreateDate=", "-Artist=", "-DigitalCreationDate=", "-ModifyDate=", "-DateTimeDigitized="])
def create_rating_csv(rating: int = 4, subdir: str = ""): """ creates a csv file with all files in the directory the rating column is filled with param rating :param rating: rating to be written :param subdir: sub directory to make rating file of, if empty all directories will be taken """ log_function_call(create_rating_csv.__name__, rating, subdir) inpath = os.getcwd() out_filebasename = "rating" if subdir: out_filebasename += "_" + subdir out_filename = get_setexif_dir(out_filebasename + ".csv") rating_file, writer = fileop.create_csv_writer(out_filename, ["name_part", "rating"]) for (dirpath, dirnames, filenames) in os.walk(os.path.join(inpath, subdir)): if is_invalid_path(dirpath): continue for filename in filterFiles(filenames, settings.image_types): writer.writerow([filename, rating]) rating_file.close()
def create_names_csv_per_dir(start_after_dir=''): """ extract names from the file path write a csv file with those names for each directory This csv can be modified to be used with :func:`write_exif_using_csv` If you want to modify it with EXCEL or Calc take care to import all columns of the csv as text. """ log_function_call(create_names_csv_per_dir.__name__) inpath = os.getcwd() tag_set_names = OrderedSet() out_filename = get_info_dir("tags_names.csv") csvfile, writer = fileop.create_csv_writer( out_filename, ["directory", "name_main", "tags"]) for (dirpath, dirnames, filenames) in os.walk(inpath): if is_invalid_path(dirpath): continue filenameAccessors = [ FilenameAccessor(filename) for filename in filterFiles(filenames, image_types) ] if len(filenameAccessors) == 0: continue tags = [] found = False for part in dirpath.split(os.sep): if found: tags += part.split(', ') else: found = part == start_after_dir filenameAccessorLast = filenameAccessors[0] tag_set_names.add( (", ".join(tags), filenameAccessorLast.pre, ', '.join(OrderedSet(tags + [filenameAccessorLast.pre])))) for filenameAccessor in filenameAccessors[1:]: if not filenameAccessor.pre == filenameAccessorLast.pre: tag_set_names.add( (", ".join(tags), filenameAccessor.pre, ', '.join(OrderedSet(tags + [filenameAccessor.pre])))) filenameAccessorLast = filenameAccessor writer.writerows(tag_set_names) csvfile.close()
def name_to_exif(folder=r"", additional_tags=(), startdir=None): """ extract title, description and mode from name and write them to exif deprecated: try to use write_exif_using_csv() instead """ inpath = os.getcwd() clock = Clock() file_types = settings.image_types + settings.video_types log().info("process %d Files in %s, subdir: %r", count_files_in(inpath, file_types, ""), inpath, settings.includeSubdirs) askToContinue() for (dirpath, dirnames, filenames) in os.walk(inpath): if is_invalid_path(dirpath, regex=folder): continue filenames = filterFiles(filenames, file_types) for filename in filenames: meta_data = FileMetaData(dirpath, filename) if startdir: meta_data.import_fullname(startdir) else: meta_data.import_filename() meta_data.update({'tags': additional_tags}) write_exiftag(meta_data.to_tag_dict(), dirpath, filename) clock.finish()
def write_exif_using_csv(csv_filenames: Union[str, List[str]] = "*", folder: str = r"", start_folder: str = "", csv_folder: str = None, csv_restriction: str = "", import_filename: bool = True, import_exif: bool = True, only_when_changed: bool = False, overwrite_gps: bool = False, is_video: bool = False): """ csv files are used for setting tags the csv files have to be separated by semicolon empty values in a column or not present columns are not evaluated each '' in the following is a possible column name can also be used without csv files at all just to import filename to tags following restrictions to files are possible: 'directory': checks if value is part of directory 'name_main': checks if value is the first part of filename 'first': int counter min 'last': int counter max 'name_part': checks if value is part of filename :param csv_filenames: can be either "*" for all files in directory or a iterable of filenames can set follow exif information: ['title', 'tags', 'tags2', 'tags3', 'rating', 'description', 'gps'] tags are expected to be separated by ', ' rating is expected to be in interval [0,5] gps is expected to be 'lat, long' in decimal notation can set Location via ['Country', 'State', 'City', 'Location'] sets also structured description for image processing like HDR and Panorama columns starting with 'HDR' are evaluated as HDR description 'TM' are evaluated as HDR Tone Mapping description 'PANO' are evaluated as Panorama description :param csv_folder: location of csv files - standard is the .EXIFnaming/info :param csv_restriction: files that do not pass any of the restriction in this file are not modified at all :param folder: process only folders matching this regex :param start_folder: directories before this name will be ignored, does not needs to be a full directory name :param import_filename: whether to extract tags from filename :param import_exif: whether to extract tags from exif :param overwrite_gps: modifier for import_exif, overwrites gps data with information of csv :param only_when_changed: when true filename is not imported to tags for files without matching entries in csv useless if csv_restriction is set :param is_video: wheter video types should be written - video types might not handle tags right """ if not csv_folder: csv_folder = get_setexif_dir() log_function_call(write_exif_using_csv.__name__, csv_filenames, folder, start_folder, csv_folder, csv_restriction, import_filename, import_exif, only_when_changed, overwrite_gps) inpath = os.getcwd() clock = Clock() csv.register_dialect('semicolon', delimiter=';', lineterminator='\r\n') if csv_filenames == "*": csv_filenames = filterFiles(os.listdir(csv_folder), [".csv"]) elif csv_filenames: csv_filenames = [csv_filename + ".csv" for csv_filename in csv_filenames] csv_filenames = [os.path.join(csv_folder, csv_filename) for csv_filename in csv_filenames] if csv_restriction: csv_restriction = os.path.join(csv_folder, csv_restriction) + ".csv" filetypes = settings.video_types if is_video else settings.image_types for (dirpath, dirnames, filenames) in os.walk(inpath): if is_invalid_path(dirpath, regex=folder, start=start_folder): continue for filename in filterFiles(filenames, filetypes): meta_data = FileMetaData(dirpath, filename) if not _passes_restrictor(meta_data, csv_restriction): continue if import_filename: meta_data.import_filename() if import_exif: meta_data.import_exif(overwrite_gps) for csv_filename in csv_filenames: with open(csv_filename, "r", encoding="utf-8") as csvfile: reader = csv.DictReader(csvfile, dialect='semicolon') for row in reader: meta_data.update(row) if not only_when_changed or meta_data.has_changed: write_exiftag(meta_data.to_tag_dict(), meta_data.directory, meta_data.filename) clock.finish()