Change python exiftool wrapper to RhetTbull implementation

This commit is contained in:
Cédric Leporcq 2021-08-08 11:55:38 +02:00
parent 71f0ecaba1
commit a88a62d155
3 changed files with 17 additions and 25 deletions

View File

@ -252,10 +252,4 @@ main.add_command(_batch)
if __name__ == '__main__': if __name__ == '__main__':
#Initialize ExifTool Subprocess main()
exiftool_addedargs = [
u'-config',
u'"{}"'.format(constants.exiftool_config)
]
with ExifTool(executable_=get_exiftool(), addedargs=exiftool_addedargs) as et:
main()

View File

@ -1,10 +1,6 @@
""" Yet another simple exiftool wrapper """ Yet another simple exiftool wrapper from:
I rolled my own for following reasons: https://github.com/RhetTbull/osxphotos/blob/master/osxphotos/exiftool.py
1. I wanted something under MIT license (best alternative was licensed under GPL/BSD) """
2. I wanted singleton behavior so only a single exiftool process was ever running
3. When used as a context manager, I wanted the operations to batch until exiting the context (improved performance)
If these aren't important to you, I highly recommend you use Sven Marnach's excellent
pyexiftool: https://github.com/smarnach/pyexiftool which provides more functionality """
import atexit import atexit
import json import json
@ -55,14 +51,15 @@ class _ExifToolProc:
return cls.instance return cls.instance
def __init__(self, exiftool=None): def __init__(self, exiftool=None, logger=logging.getLogger()):
"""construct _ExifToolProc singleton object or return instance of already created object """construct _ExifToolProc singleton object or return instance of already created object
exiftool: optional path to exiftool binary (if not provided, will search path to find it)""" exiftool: optional path to exiftool binary (if not provided, will search path to find it)"""
self.logger = logger
if hasattr(self, "_process_running") and self._process_running: if hasattr(self, "_process_running") and self._process_running:
# already running # already running
if exiftool is not None and exiftool != self._exiftool: if exiftool is not None and exiftool != self._exiftool:
logging.warning( self.logger.warning(
f"exiftool subprocess already running, " f"exiftool subprocess already running, "
f"ignoring exiftool={exiftool}" f"ignoring exiftool={exiftool}"
) )
@ -95,7 +92,7 @@ class _ExifToolProc:
""" start exiftool in batch mode """ """ start exiftool in batch mode """
if self._process_running: if self._process_running:
logging.warning("exiftool already running: {self._process}") self.logger.warning("exiftool already running: {self._process}")
return return
# open exiftool process # open exiftool process
@ -145,7 +142,7 @@ class _ExifToolProc:
class ExifTool: class ExifTool:
""" Basic exiftool interface for reading and writing EXIF tags """ """ Basic exiftool interface for reading and writing EXIF tags """
def __init__(self, filepath, exiftool=None, overwrite=True, flags=None): def __init__(self, filepath, exiftool=None, overwrite=True, flags=None, logger=logging.getLogger()):
"""Create ExifTool object """Create ExifTool object
Args: Args:
@ -165,7 +162,7 @@ class ExifTool:
self.error = None self.error = None
# if running as a context manager, self._context_mgr will be True # if running as a context manager, self._context_mgr will be True
self._context_mgr = False self._context_mgr = False
self._exiftoolproc = _ExifToolProc(exiftool=exiftool) self._exiftoolproc = _ExifToolProc(exiftool=exiftool, logger=logger)
self._read_exif() self._read_exif()
@property @property
@ -391,15 +388,16 @@ class ExifToolCaching(ExifTool):
_singletons = {} _singletons = {}
def __new__(cls, filepath, exiftool=None): def __new__(cls, filepath, exiftool=None, logger=logging.getLogger()):
""" create new object or return instance of already created singleton """ """ create new object or return instance of already created singleton """
if filepath not in cls._singletons: if filepath not in cls._singletons:
cls._singletons[filepath] = _ExifToolCaching(filepath, exiftool=exiftool) cls._singletons[filepath] = _ExifToolCaching(filepath,
exiftool=exiftool, logger=logger)
return cls._singletons[filepath] return cls._singletons[filepath]
class _ExifToolCaching(ExifTool): class _ExifToolCaching(ExifTool):
def __init__(self, filepath, exiftool=None): def __init__(self, filepath, exiftool=None, logger=logging.getLogger()):
"""Create read-only ExifTool object that caches values """Create read-only ExifTool object that caches values
Args: Args:
@ -411,7 +409,8 @@ class _ExifToolCaching(ExifTool):
""" """
self._json_cache = None self._json_cache = None
self._asdict_cache = {} self._asdict_cache = {}
super().__init__(filepath, exiftool=exiftool, overwrite=False, flags=None) super().__init__(filepath, exiftool=exiftool, overwrite=False,
flags=None, logger=logger)
def run_commands(self, *commands, no_file=False): def run_commands(self, *commands, no_file=False):
if commands[0] not in ["-json", "-ver"]: if commands[0] not in ["-json", "-ver"]:

View File

@ -12,7 +12,7 @@ import logging
# load modules # load modules
from dateutil.parser import parse from dateutil.parser import parse
import re import re
from elodie.external.pyexiftool import ExifTool from dozo.exiftool import ExifToolCaching
class Media(): class Media():
@ -576,7 +576,6 @@ class Media():
return None return None
status = '' status = ''
status = ExifTool().set_tags(tags, path)
for tag, value in tags.items(): for tag, value in tags.items():
status = ExifToolCaching(path, self.logger).setvalue(tag, value) status = ExifToolCaching(path, self.logger).setvalue(tag, value)
if status.decode().find('unchanged') != -1 or status == '': if status.decode().find('unchanged') != -1 or status == '':