Change path format syntax

This commit is contained in:
Cédric Leporcq 2022-04-18 08:57:47 +02:00
parent a4746cbf60
commit 002404d82c
7 changed files with 59 additions and 56 deletions

View File

@ -93,8 +93,8 @@ pattern.
Default folder structure: Default folder structure:
``` ```
dirs_path={%Y}/{%m-%b}-{city}-{folder} dirs_path=<%Y>/<%m-%b>-<city>-<folder>
name={%Y%m%d-%H%M%S}-%u{original_name}.%l{ext}|{%Y%m%d-%H%M%S}-%u{basename}.%l{ext} name=<%Y%m%d-%H%M%S>-<%u<original_name>|%u<basename>>.%l<ext>
``` ```
Example folder structure: Example folder structure:
@ -115,7 +115,7 @@ Example folder structure:
│ └── 20150927_014138-_dsc8705.nef │ └── 20150927_014138-_dsc8705.nef
``` ```
The folder structure use standard unix path separator (`/`). Fallback folder part can be optionally specified using a pipe (`|`) separator. The folder structure use standard unix path separator (`/`). Fallback folder part can be optionally specified using a pipe separator and brackets (`<.*|.*>`).
Valid keywords are: Valid keywords are:

View File

@ -14,5 +14,5 @@ timeout=1
day_begins=4 day_begins=4
# Path format # Path format
dirs_path={%Y}/{%m-%b}-{city}-{folder} dirs_path=<%Y>/<%m-%b>-<city>-<folder>
name={%Y%m%d-%H%M%S}-(%u{original_name}|%u{name}).%l{ext} name=<%Y%m%d-%H%M%S>-<%u<original_name>|%u<name>>.%l<ext>

View File

@ -38,22 +38,22 @@ class FPath:
def get_items(self): def get_items(self):
"""Return features items of Fpath class""" """Return features items of Fpath class"""
return { return {
'album': '{album}', 'album': '<album>',
'stem': '{stem}', 'stem': '<stem>',
'camera_make': '{camera_make}', 'camera_make': '<camera_make>',
'camera_model': '{camera_model}', 'camera_model': '<camera_model>',
'city': '{city}', 'city': '<city>',
'custom': r'{".*"}', 'custom': r'<".*">',
'country': '{country}', 'country': '<country>',
'date': r'{(%[a-zA-Z][^a-zA-Z]*){1,8}}', # search for date format string 'date': r'<(%[a-zA-Z][^a-zA-Z]*){1,8}>', # search for date format string
'ext': '{ext}', 'ext': '<ext>',
'folder': '{folder}', 'folder': '<folder>',
'folders': r'{folders(\[[0-9:]{0,3}\])?}', 'folders': r'<folders(\[[0-9:]{0,3}\])?>',
'location': '{location}', 'location': '<location>',
'name': '{name}', 'name': '<name>',
'original_name': '{original_name}', 'original_name': '<original_name>',
'state': '{state}', 'state': '<state>',
'title': '{title}', 'title': '<title>',
} }
def get_early_morning_photos_date(self, date, mask): def get_early_morning_photos_date(self, date, mask):
@ -140,6 +140,9 @@ class FPath:
part = stem part = stem
for regex in utils.get_date_regex().values(): for regex in utils.get_date_regex().values():
part = re.sub(regex, '', part) part = re.sub(regex, '', part)
# Delete separator
if re.search('^[-_ .]', part):
part = part[1:]
elif item == 'date': elif item == 'date':
date = metadata['date_media'] date = metadata['date_media']
# early morning photos can be grouped with previous day # early morning photos can be grouped with previous day
@ -194,7 +197,7 @@ class FPath:
for item, regex in self.items.items(): for item, regex in self.items.items():
matched = re.search(regex, this_part) matched = re.search(regex, this_part)
if matched: if matched:
self.log.debug(f'item: {item}, mask: {matched.group()[1:-1]}') self.log.debug(f'item: {item}, mask: <matched.group()[1:-1]>')
part = self.get_part(item, matched.group()[1:-1], metadata) part = self.get_part(item, matched.group()[1:-1], metadata)
self.log.debug(f'part: {part}') self.log.debug(f'part: {part}')
@ -213,16 +216,16 @@ class FPath:
this_part = self._substitute(regex, part, this_part) this_part = self._substitute(regex, part, this_part)
# remove alternate parts inside bracket separated by | # remove alternate parts inside bracket separated by |
regex = r'[-_ .]?\(\|\)' regex = r'[-_ .]?\<\|\>'
if re.search(regex, this_part): if re.search(regex, this_part):
# Delete substitute part and separator if empty # Delete substitute part and separator if empty
this_part = re.sub(regex, '', this_part) this_part = re.sub(regex, '', this_part)
elif re.search(r'\(.*\)', this_part): elif re.search(r'\<.*\>', this_part):
regex = r'\(\|' regex = r'\<\|'
this_part = re.sub(regex, '', this_part) this_part = re.sub(regex, '', this_part)
regex = r'\|.*\)' regex = r'\|.*\>'
this_part = re.sub(regex, '', this_part) this_part = re.sub(regex, '', this_part)
regex = r'\)' regex = r'\>'
this_part = re.sub(regex, '', this_part) this_part = re.sub(regex, '', this_part)
# Delete separator char at the begining of the string if any: # Delete separator char at the begining of the string if any:
@ -238,7 +241,7 @@ class FPath:
def get_path(self, metadata: dict) -> list: def get_path(self, metadata: dict) -> list:
""" """
path_format: {%Y-%d-%m}/%u{city}/{album} path_format: <%Y-%d-%m>/%u<city>/<album>
Returns file path. Returns file path.
""" """
path_format = self.path_format path_format = self.path_format
@ -252,9 +255,9 @@ class FPath:
if part != '': if part != '':
# Check if all masks are substituted # Check if all masks are substituted
if True in [c in part for c in '{}']: if True in [c in part for c in '<>']:
self.log.error( self.log.error(
f"Format path part invalid: {this_part}" f"Format path part invalid: {part}"
) )
sys.exit(1) sys.exit(1)

View File

@ -23,8 +23,8 @@ def get_config_dir(name):
APPLICATION_DIRECTORY = get_config_dir('ordigi') APPLICATION_DIRECTORY = get_config_dir('ordigi')
DEFAULT_PATH = '{%Y-%m-%b}/{album}|{city}' DEFAULT_PATH = '<%Y-%m-%b>/<album>|<city>'
DEFAULT_NAME = '{%Y-%m-%d_%H-%M-%S}-{name}-{title}.%l{ext}' DEFAULT_NAME = '<%Y-%m-%d_%H-%M-%S>-<name>-<title>.%l<ext>'
DEFAULT_PATH_FORMAT = DEFAULT_PATH + '/' + DEFAULT_NAME DEFAULT_PATH_FORMAT = DEFAULT_PATH + '/' + DEFAULT_NAME
DEFAULT_GEOCODER = 'Nominatim' DEFAULT_GEOCODER = 'Nominatim'

View File

@ -60,8 +60,8 @@ def conf_path():
conf = RawConfigParser() conf = RawConfigParser()
conf['Path'] = { conf['Path'] = {
'day_begins': '4', 'day_begins': '4',
'dirs_path':'%u{%Y-%m}/{city}|{city}-{%Y}/{folders[:1]}/{folder}', 'dirs_path':'%u<%Y-%m>/<city>|<city>-<%Y>/<folders[:1]>/<folder>',
'name':'{%Y-%m-%b-%H-%M-%S}-{basename}.%l{ext}' 'name':'<%Y-%m-%b-%H-%M-%S>-<basename>.%l<ext>'
} }
conf['Geolocation'] = { conf['Geolocation'] = {
'geocoder': 'Nominatium' 'geocoder': 'Nominatium'

View File

@ -33,24 +33,24 @@ class TestFPath:
# Item to search for: # Item to search for:
items = fpath.get_items() items = fpath.get_items()
masks = [ masks = [
'{album}', '<album>',
'{basename}', '<basename>',
'{camera_make}', '<camera_make>',
'{camera_model}', '<camera_model>',
'{city}', '<city>',
'{"custom"}', '<"custom">',
'{country}', '<country>',
'{ext}', '<ext>',
'{folder}', '<folder>',
'{folders[1:3]}', '<folders[1:3]>',
'{location}', '<location>',
'{name}', '<name>',
'{original_name}', '<original_name>',
'{state}', '<state>',
'{title}', '<title>',
'{%Y-%m-%d}', '<%Y-%m-%d>',
'{%Y-%m-%d_%H-%M-%S}', '<%Y-%m-%d_%H-%M-%S>',
'{%Y-%m-%b}' '<%Y-%m-%b>'
] ]
for file_path in self.file_paths: for file_path in self.file_paths:
@ -165,7 +165,7 @@ class TestCollection:
collection = Collection(tmp_path, cli_options=cli_options) collection = Collection(tmp_path, cli_options=cli_options)
# Try to change path format and sort files again # Try to change path format and sort files again
path_format = 'test_exif/{city}/{%Y}-{name}.%l{ext}' path_format = 'test_exif/<city>/<%Y>-<name>.%l<ext>'
summary = collection.sort_files([tmp_path], path_format, loc) summary = collection.sort_files([tmp_path], path_format, loc)
self.assert_sort(summary, 27) self.assert_sort(summary, 27)

View File

@ -32,8 +32,8 @@ class TestConfig:
Read files from config and return variables Read files from config and return variables
""" """
# test valid config file # test valid config file
assert conf['Path']['dirs_path'] == '%u{%Y-%m}/{city}|{city}-{%Y}/{folders[:1]}/{folder}' assert conf['Path']['dirs_path'] == '%u<%Y-%m>/<city>|<city>-<%Y>/<folders[:1]>/<folder>'
assert conf['Path']['name'] == '{%Y-%m-%b-%H-%M-%S}-{basename}.%l{ext}' assert conf['Path']['name'] == '<%Y-%m-%b-%H-%M-%S>-<basename>.%l<ext>'
assert conf['Path']['day_begins'] == '4' assert conf['Path']['day_begins'] == '4'
assert conf['Geolocation']['geocoder'] == 'Nominatium' assert conf['Geolocation']['geocoder'] == 'Nominatium'
@ -56,7 +56,7 @@ class TestConfig:
# """ # """
# config = Config(conf=conf) # config = Config(conf=conf)
# path = config.get_path_definition() # path = config.get_path_definition()
# assert path == '%u{%Y-%m}/{city}|{city}-{%Y}/{folders[:1]}/{folder}/{%Y-%m-%b-%H-%M-%S}-{basename}.%l{ext}' # assert path == '%u<%Y-%m>/<city>|<city>-<%Y>/<folders[:1]>/<folder>/<%Y-%m-%b-%H-%M-%S>-<basename>.%l<ext>'
def test_get_config_options(self, conf): def test_get_config_options(self, conf):
config = Config(conf=conf) config = Config(conf=conf)