def rename(self, force=False): """ Rename a file according to its exif data""" logger.info("Start process for renaming photo %s", self.full_path) # Check if we continue on rename processing regex = re.compile(conf["regex"]["photo_file"], re.IGNORECASE) if force is False and regex.match(self.filename): logger.debug("File %s not renamed as it matches expected regex", self.full_path) return # Get exif data data = exif.load_exif_data(self.full_path) original_date = self.get_date(data) model = self.get_model(data) # Build new filename new_filename = self.build_filename(original_date, model) # Rename if self.full_path != new_filename: os.rename(self.full_path, new_filename) logger.info("Rename photo %s into %s", self.full_path, new_filename) else: logger.debug("File %s has not been renamed", self.full_path)
def rename_process(collection_name, force=False): """ Launch rename process on a particular collection or on all collections Rename process is run only if it has been activated in metadata collection file """ logger.info("Renaming photos from collection %s", collection_name) collections = [] if collection_name is not None: collections = PhotoCollectionFactory().get_collection(collection_name) else: collections = PhotoCollectionFactory().get_all_collections() for collection in collections: if collection.is_rename_enabled(): logger.debug("Retrieving photos from collection %s", collection.name) for photo in collection.get_collection_files(): try: photo.rename(force) except AttributeError as err: logger.error("Cannot rename file %s - error %s", photo.full_path, err) collection.update_rename_info()
def process(self): logger.info('Init Collection Process - collection %s, force flag %s', self.collection_name, self.force) collections = get_collection(self.collection_name) for item in collections: logger.debug('Processing collection : %s', item) item.generate_metadata_file(self.force)
def rename_cli(collection, force): """ Rename images from a collection Renaming process uses EXIF data of images for building a new filename """ logger.info("CLI Command - Rename collection : %s, force flag : %s", collection, force) RenameProcess().run(collection, force)
def backup(self): """Backup metadata file""" now = datetime.now() backup_filename = 'metadata_{0}.yaml'.format(now.strftime("%Y%m%d_%H%M%S")) dest_file = os.path.join(self.collection_path, backup_filename) shutil.copyfile(self.filename, dest_file) logger.info('%s backuped to %s', self.filename, dest_file)
def tag(collection, force): """ Catalog each image collection by applying tags from metadata Those tags are persisted in EXIF data in order to be reused by some other tools """ logger.info("CLI Command - Tag collection : %s, force flag : %s", collection, force) TagProcess().run(collection, force)
def generate_metadata_file(self, force): """ Create a metadata file """ if self.is_collection_path_exist() is False: logger.info('%s path does not exist, collection %s not created', self.path, self.name) return if self.metadata.is_metadata_exist(): self.metadata.backup() self.metadata.update() self.metadata.write()
def run(self, collection_name, force=False): logger.debug("Start Process for %s", collection_name) collections = get_collection(collection_name) for collection in collections: if self.is_enable(collection): logger.info("Retrieving photos from collection %s", collection.name) for photo in collection.get_collection_files(): logger.debug("Current Photo file %s", photo.full_path) try: self.process(photo, collection, force) except AttributeError as err: logger.error("Cannot process file %s - error %s", photo.full_path, err) self.update_metadata_file(collection)
def tag(self, tags, force=False): """Apply Exif Data from metadata file""" logger.info("Start process for tagging photo %s", self.full_path) data = exif.load_exif_data(self.full_path) # Extract tags to apply from conf remove_tags = tags["remove"] add_tags = tags["add"] # Remove tags for remove_tag in remove_tags: exif_values = exif.get_exif_data(data, remove_tag['name']) # Remove from existing list, values from configuration exif_values = [] if exif_values is None else exif_values new_values = list((exif for exif in exif_values if exif not in remove_tag['values'])) if new_values is None or len(new_values) == 0: # delete tag logger.debug("Remove tag %s on file %s", new_values, self.full_path) exif.remove_exif_data(data, remove_tag["name"]) elif Counter(exif_values) != Counter(new_values): # update tag data logger.debug("Apply those tags %s on file %s", new_values, self.full_path) exif.add_or_update_exif_data(data, remove_tag["name"], new_values) # Add tags for add_tag in add_tags: exif_values = exif.get_exif_data(data, add_tag['name']) logger.debug("existing tags %s with values %s", add_tag['name'], exif_values) exif_values = [] if exif_values is None else exif_values # Add new values from conf into existing list, without duplicates new_values = list(exif_values) new_values.extend( (x for x in add_tag['values'] if x not in new_values)) if Counter(exif_values) != Counter(new_values): # update tag data logger.debug("Apply those tags %s on file %s", new_values, self.full_path) exif.add_or_update_exif_data(data, add_tag["name"], new_values) exif.write_exif_data(data)
def sync(self, related_collection_files, metadata): """ Check if current file exist in related collection If it's not found, then move it to a trash folder Otherwise, keep it """ include_file_regex = '|'.join(metadata.content["sync"]["include"]) exclude_file_regex = '|'.join(metadata.content["sync"]["exclude"]) include = re.compile(include_file_regex, re.IGNORECASE) exclude = re.compile(exclude_file_regex, re.IGNORECASE) if include.match( self.filename) and exclude.match(self.filename) is None: # Build list of filenames from current filename filenames_list = self.build_filename_list(self.filename) found = False # If none of those filenames are found in related collections, delete it for filename in filenames_list: for related_file in related_collection_files: if related_file.filename == filename: found = True if found is False: # Move it to temp directpry logger.debug("Move file %s to temp directory", self.full_path) os.makedirs(os.path.join(conf["tmp_dir"], metadata.content["collection"]), exist_ok=True) copyfile( self.full_path, os.path.join(conf["tmp_dir"], metadata.content["collection"], self.filename + self.extension)) os.remove(self.full_path) else: logger.info("File %s not sync as it does not match configuration", self.filename)
def write(self): """ Write metadata file """ with open(self.filename, 'w') as yaml_file: yaml.dump(self.content, yaml_file, allow_unicode=True) logger.info('Collection %s Metadata file created %s', self.collection_name, self.filename)
def init_collection(collection, force): """ Create metadata file for collection """ logger.info("CLI Command - Init collection : %s, force flag : %s", collection, force) InitCollection(collection, force).process()