Added {album_seq} and {folder_album_seq}, #496
This commit is contained in:
58
README.md
58
README.md
@@ -1803,11 +1803,55 @@ Substitution Description
|
|||||||
|
|
||||||
{id} A unique number for the photo based on its
|
{id} A unique number for the photo based on its
|
||||||
primary key in the Photos database. A
|
primary key in the Photos database. A
|
||||||
sequential integer, e.g. 1, 2, 3...etc. May be
|
sequential integer, e.g. 1, 2, 3...etc. Each
|
||||||
|
asset associated with a photo (e.g. an image
|
||||||
|
and Live Photo preview) will share the same
|
||||||
|
id. May be formatted using a python string
|
||||||
|
format code. For example, to format as a
|
||||||
|
5-digit integer and pad with zeros, use
|
||||||
|
'{id:05d}' which results in 00001, 00002,
|
||||||
|
00003...etc.
|
||||||
|
|
||||||
|
{album_seq} An integer, starting at 0, indicating the
|
||||||
|
photo's index (sequence) in the containing
|
||||||
|
album. Only valid when used in a '--filename'
|
||||||
|
template and only when '{album}' or
|
||||||
|
'{folder_album}' is used in the '--directory'
|
||||||
|
template. For example '--directory
|
||||||
|
"{folder_album}" --filename
|
||||||
|
"{album_seq}_{original_name}"'. To start
|
||||||
|
counting at a value other than 0, append
|
||||||
|
append a period and the starting value to the
|
||||||
|
field name. For example, to start counting at
|
||||||
|
1 instead of 0: '{album_seq.1}'. May be
|
||||||
formatted using a python string format code.
|
formatted using a python string format code.
|
||||||
For example, to format as a 5-digit integer
|
For example, to format as a 5-digit integer
|
||||||
and pad with zeros, use '{id:05d}' which
|
and pad with zeros, use '{album_seq:05d}'
|
||||||
results in 00001, 00002, 00003...etc.
|
which results in 00001, 00002, 00003...etc.
|
||||||
|
This may result in incorrect sequences if you
|
||||||
|
have duplicate albums with the same name; see
|
||||||
|
also '{folder_album_seq}'.
|
||||||
|
|
||||||
|
{folder_album_seq} An integer, starting at 0, indicating the
|
||||||
|
photo's index (sequence) in the containing
|
||||||
|
album and folder path. Only valid when used in
|
||||||
|
a '--filename' template and only when
|
||||||
|
'{folder_album}' is used in the '--directory'
|
||||||
|
template. For example '--directory
|
||||||
|
"{folder_album}" --filename
|
||||||
|
"{folder_album_seq}_{original_name}"'. To
|
||||||
|
start counting at a value other than 0, append
|
||||||
|
append a period and the starting value to the
|
||||||
|
field name. For example, to start counting at
|
||||||
|
1 instead of 0: '{folder_album_seq.1}' May be
|
||||||
|
formatted using a python string format code.
|
||||||
|
For example, to format as a 5-digit integer
|
||||||
|
and pad with zeros, use
|
||||||
|
'{folder_album_seq:05d}' which results in
|
||||||
|
00001, 00002, 00003...etc. This may result in
|
||||||
|
incorrect sequences if you have duplicate
|
||||||
|
albums with the same name in the same folder;
|
||||||
|
see also '{album_seq}'.
|
||||||
|
|
||||||
{comma} A comma: ','
|
{comma} A comma: ','
|
||||||
{semicolon} A semicolon: ';'
|
{semicolon} A semicolon: ';'
|
||||||
@@ -1823,7 +1867,7 @@ Substitution Description
|
|||||||
{lf} A line feed: '\n', alias for {newline}
|
{lf} A line feed: '\n', alias for {newline}
|
||||||
{cr} A carriage return: '\r'
|
{cr} A carriage return: '\r'
|
||||||
{crlf} a carriage return + line feed: '\r\n'
|
{crlf} a carriage return + line feed: '\r\n'
|
||||||
{osxphotos_version} The osxphotos version, e.g. '0.42.66'
|
{osxphotos_version} The osxphotos version, e.g. '0.42.67'
|
||||||
{osxphotos_cmd_line} The full command line used to run osxphotos
|
{osxphotos_cmd_line} The full command line used to run osxphotos
|
||||||
|
|
||||||
The following substitutions may result in multiple values. Thus if specified for
|
The following substitutions may result in multiple values. Thus if specified for
|
||||||
@@ -3657,7 +3701,9 @@ The following template field substitutions are availabe for use the templating s
|
|||||||
|{exif.camera_model}|Camera model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s'|
|
|{exif.camera_model}|Camera model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s'|
|
||||||
|{exif.lens_model}|Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'|
|
|{exif.lens_model}|Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'|
|
||||||
|{uuid}|Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'|
|
|{uuid}|Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'|
|
||||||
|{id}|A unique number for the photo based on its primary key in the Photos database. A sequential integer, e.g. 1, 2, 3...etc. May be formatted using a python string format code. For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in 00001, 00002, 00003...etc. |
|
|{id}|A unique number for the photo based on its primary key in the Photos database. A sequential integer, e.g. 1, 2, 3...etc. Each asset associated with a photo (e.g. an image and Live Photo preview) will share the same id. May be formatted using a python string format code. For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in 00001, 00002, 00003...etc. |
|
||||||
|
|{album_seq}|An integer, starting at 0, indicating the photo's index (sequence) in the containing album. Only valid when used in a '--filename' template and only when '{album}' or '{folder_album}' is used in the '--directory' template. For example '--directory "{folder_album}" --filename "{album_seq}_{original_name}"'. To start counting at a value other than 0, append append a period and the starting value to the field name. For example, to start counting at 1 instead of 0: '{album_seq.1}'. May be formatted using a python string format code. For example, to format as a 5-digit integer and pad with zeros, use '{album_seq:05d}' which results in 00001, 00002, 00003...etc. This may result in incorrect sequences if you have duplicate albums with the same name; see also '{folder_album_seq}'.|
|
||||||
|
|{folder_album_seq}|An integer, starting at 0, indicating the photo's index (sequence) in the containing album and folder path. Only valid when used in a '--filename' template and only when '{folder_album}' is used in the '--directory' template. For example '--directory "{folder_album}" --filename "{folder_album_seq}_{original_name}"'. To start counting at a value other than 0, append append a period and the starting value to the field name. For example, to start counting at 1 instead of 0: '{folder_album_seq.1}' May be formatted using a python string format code. For example, to format as a 5-digit integer and pad with zeros, use '{folder_album_seq:05d}' which results in 00001, 00002, 00003...etc. This may result in incorrect sequences if you have duplicate albums with the same name in the same folder; see also '{album_seq}'.|
|
||||||
|{comma}|A comma: ','|
|
|{comma}|A comma: ','|
|
||||||
|{semicolon}|A semicolon: ';'|
|
|{semicolon}|A semicolon: ';'|
|
||||||
|{questionmark}|A question mark: '?'|
|
|{questionmark}|A question mark: '?'|
|
||||||
@@ -3672,7 +3718,7 @@ The following template field substitutions are availabe for use the templating s
|
|||||||
|{lf}|A line feed: '\n', alias for {newline}|
|
|{lf}|A line feed: '\n', alias for {newline}|
|
||||||
|{cr}|A carriage return: '\r'|
|
|{cr}|A carriage return: '\r'|
|
||||||
|{crlf}|a carriage return + line feed: '\r\n'|
|
|{crlf}|a carriage return + line feed: '\r\n'|
|
||||||
|{osxphotos_version}|The osxphotos version, e.g. '0.42.66'|
|
|{osxphotos_version}|The osxphotos version, e.g. '0.42.67'|
|
||||||
|{osxphotos_cmd_line}|The full command line used to run osxphotos|
|
|{osxphotos_cmd_line}|The full command line used to run osxphotos|
|
||||||
|{album}|Album(s) photo is contained in|
|
|{album}|Album(s) photo is contained in|
|
||||||
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.42.66"
|
__version__ = "0.42.67"
|
||||||
|
|||||||
@@ -128,9 +128,28 @@ TEMPLATE_SUBSTITUTIONS = {
|
|||||||
"{exif.lens_model}": "Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'",
|
"{exif.lens_model}": "Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'",
|
||||||
"{uuid}": "Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'",
|
"{uuid}": "Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'",
|
||||||
"{id}": "A unique number for the photo based on its primary key in the Photos database. "
|
"{id}": "A unique number for the photo based on its primary key in the Photos database. "
|
||||||
+ "A sequential integer, e.g. 1, 2, 3...etc. May be formatted using a python string format code. "
|
+ "A sequential integer, e.g. 1, 2, 3...etc. Each asset associated with a photo (e.g. an image and Live Photo preview) will share the same id. "
|
||||||
|
+ "May be formatted using a python string format code. "
|
||||||
+ "For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in "
|
+ "For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in "
|
||||||
+ "00001, 00002, 00003...etc. ",
|
+ "00001, 00002, 00003...etc. ",
|
||||||
|
"{album_seq}": "An integer, starting at 0, indicating the photo's index (sequence) in the containing album. "
|
||||||
|
+ "Only valid when used in a '--filename' template and only when '{album}' or '{folder_album}' is used in the '--directory' template. "
|
||||||
|
+ 'For example \'--directory "{folder_album}" --filename "{album_seq}_{original_name}"\'. '
|
||||||
|
+ "To start counting at a value other than 0, append append a period and the starting value to the field name. "
|
||||||
|
+ "For example, to start counting at 1 instead of 0: '{album_seq.1}'. "
|
||||||
|
+ "May be formatted using a python string format code. "
|
||||||
|
+ "For example, to format as a 5-digit integer and pad with zeros, use '{album_seq:05d}' which results in "
|
||||||
|
+ "00001, 00002, 00003...etc. "
|
||||||
|
+ "This may result in incorrect sequences if you have duplicate albums with the same name; see also '{folder_album_seq}'.",
|
||||||
|
"{folder_album_seq}": "An integer, starting at 0, indicating the photo's index (sequence) in the containing album and folder path. "
|
||||||
|
+ "Only valid when used in a '--filename' template and only when '{folder_album}' is used in the '--directory' template. "
|
||||||
|
+ 'For example \'--directory "{folder_album}" --filename "{folder_album_seq}_{original_name}"\'. '
|
||||||
|
+ "To start counting at a value other than 0, append append a period and the starting value to the field name. "
|
||||||
|
+ "For example, to start counting at 1 instead of 0: '{folder_album_seq.1}' "
|
||||||
|
+ "May be formatted using a python string format code. "
|
||||||
|
+ "For example, to format as a 5-digit integer and pad with zeros, use '{folder_album_seq:05d}' which results in "
|
||||||
|
+ "00001, 00002, 00003...etc. "
|
||||||
|
+ "This may result in incorrect sequences if you have duplicate albums with the same name in the same folder; see also '{album_seq}'.",
|
||||||
"{comma}": "A comma: ','",
|
"{comma}": "A comma: ','",
|
||||||
"{semicolon}": "A semicolon: ';'",
|
"{semicolon}": "A semicolon: ';'",
|
||||||
"{questionmark}": "A question mark: '?'",
|
"{questionmark}": "A question mark: '?'",
|
||||||
@@ -297,13 +316,10 @@ class PhotoTemplateParser:
|
|||||||
"""Parse a template_statement string"""
|
"""Parse a template_statement string"""
|
||||||
return self.metamodel.model_from_str(template_statement)
|
return self.metamodel.model_from_str(template_statement)
|
||||||
|
|
||||||
|
def fields(self, template_statement):
|
||||||
def format_id_str(value, format_str):
|
"""Return list of fields found in a template statement; does not verify that fields are valid"""
|
||||||
"""Format value based on format code in field in format id:02d"""
|
model = self.parse(template_statement)
|
||||||
if not format_str:
|
return [ts.template.field for ts in model.template_strings if ts.template]
|
||||||
return str(value)
|
|
||||||
format_str = "{0:" + f"{format_str}" + "}"
|
|
||||||
return format_str.format(value)
|
|
||||||
|
|
||||||
|
|
||||||
class PhotoTemplate:
|
class PhotoTemplate:
|
||||||
@@ -329,6 +345,7 @@ class PhotoTemplate:
|
|||||||
# initialize render options
|
# initialize render options
|
||||||
# this will be done in render() but for testing, some of the lookup functions are called directly
|
# this will be done in render() but for testing, some of the lookup functions are called directly
|
||||||
options = RenderOptions()
|
options = RenderOptions()
|
||||||
|
self.options = options
|
||||||
self.path_sep = options.path_sep
|
self.path_sep = options.path_sep
|
||||||
self.inplace_sep = options.inplace_sep
|
self.inplace_sep = options.inplace_sep
|
||||||
self.edited_version = options.edited_version
|
self.edited_version = options.edited_version
|
||||||
@@ -340,6 +357,7 @@ class PhotoTemplate:
|
|||||||
self.export_dir = options.export_dir
|
self.export_dir = options.export_dir
|
||||||
self.filepath = options.filepath
|
self.filepath = options.filepath
|
||||||
self.quote = options.quote
|
self.quote = options.quote
|
||||||
|
self.dest_path = options.dest_path
|
||||||
|
|
||||||
def render(
|
def render(
|
||||||
self,
|
self,
|
||||||
@@ -359,6 +377,7 @@ class PhotoTemplate:
|
|||||||
if type(template) is not str:
|
if type(template) is not str:
|
||||||
raise TypeError(f"template must be type str, not {type(template)}")
|
raise TypeError(f"template must be type str, not {type(template)}")
|
||||||
|
|
||||||
|
self.options = options
|
||||||
self.path_sep = options.path_sep
|
self.path_sep = options.path_sep
|
||||||
self.inplace_sep = options.inplace_sep
|
self.inplace_sep = options.inplace_sep
|
||||||
self.edited_version = options.edited_version
|
self.edited_version = options.edited_version
|
||||||
@@ -371,7 +390,7 @@ class PhotoTemplate:
|
|||||||
self.dest_path = options.dest_path
|
self.dest_path = options.dest_path
|
||||||
self.filepath = options.filepath
|
self.filepath = options.filepath
|
||||||
self.quote = options.quote
|
self.quote = options.quote
|
||||||
self.options = options
|
self.dest_path = options.dest_path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
model = self.parser.parse(template)
|
model = self.parser.parse(template)
|
||||||
@@ -499,7 +518,10 @@ class PhotoTemplate:
|
|||||||
conditional_value = []
|
conditional_value = []
|
||||||
|
|
||||||
vals = []
|
vals = []
|
||||||
if field in SINGLE_VALUE_SUBSTITUTIONS:
|
if (
|
||||||
|
field in SINGLE_VALUE_SUBSTITUTIONS
|
||||||
|
or field.split(".")[0] in SINGLE_VALUE_SUBSTITUTIONS
|
||||||
|
):
|
||||||
vals = self.get_template_value(
|
vals = self.get_template_value(
|
||||||
field,
|
field,
|
||||||
default=default,
|
default=default,
|
||||||
@@ -578,12 +600,8 @@ class PhotoTemplate:
|
|||||||
f"comparison operators may only be used with a single value: {vals} {conditional_value}"
|
f"comparison operators may only be used with a single value: {vals} {conditional_value}"
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
match = (
|
match = bool(
|
||||||
True
|
test_function(float(vals[0]), float(conditional_value[0]))
|
||||||
if test_function(
|
|
||||||
float(vals[0]), float(conditional_value[0])
|
|
||||||
)
|
|
||||||
else False
|
|
||||||
)
|
)
|
||||||
if (match and not negation) or (negation and not match):
|
if (match and not negation) or (negation and not match):
|
||||||
return ["True"]
|
return ["True"]
|
||||||
@@ -683,9 +701,6 @@ class PhotoTemplate:
|
|||||||
if self.photo.uuid is None:
|
if self.photo.uuid is None:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if field not in FIELD_NAMES:
|
|
||||||
raise ValueError(f"SyntaxError: Unknown field: {field}")
|
|
||||||
|
|
||||||
# initialize today with current date/time if needed
|
# initialize today with current date/time if needed
|
||||||
if self.today is None:
|
if self.today is None:
|
||||||
self.today = datetime.datetime.now()
|
self.today = datetime.datetime.now()
|
||||||
@@ -938,8 +953,26 @@ class PhotoTemplate:
|
|||||||
value = self.photo.exif_info.lens_model if self.photo.exif_info else None
|
value = self.photo.exif_info.lens_model if self.photo.exif_info else None
|
||||||
elif field == "uuid":
|
elif field == "uuid":
|
||||||
value = self.photo.uuid
|
value = self.photo.uuid
|
||||||
elif field.startswith("id"):
|
elif field == "id":
|
||||||
value = format_id_str(self.photo._info["pk"], subfield)
|
value = format_str_value(self.photo._info["pk"], subfield)
|
||||||
|
elif field.startswith("album_seq") or field.startswith("folder_album_seq"):
|
||||||
|
dest_path = self.dest_path
|
||||||
|
if not dest_path:
|
||||||
|
value = None
|
||||||
|
else:
|
||||||
|
if field.startswith("album_seq"):
|
||||||
|
album = pathlib.Path(dest_path).name
|
||||||
|
album_info = _get_album_by_name(self.photo, album)
|
||||||
|
else:
|
||||||
|
album_info = _get_album_by_path(self.photo, dest_path)
|
||||||
|
value = album_info.photo_index(self.photo) if album_info else None
|
||||||
|
if value is not None:
|
||||||
|
try:
|
||||||
|
start_id = field.split(".", 1)
|
||||||
|
value = int(value) + int(start_id[1])
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
value = format_str_value(value, subfield)
|
||||||
elif field in PUNCTUATION:
|
elif field in PUNCTUATION:
|
||||||
value = PUNCTUATION[field]
|
value = PUNCTUATION[field]
|
||||||
elif field == "osxphotos_version":
|
elif field == "osxphotos_version":
|
||||||
@@ -1353,3 +1386,31 @@ def _get_pathlib_value(field, value, quote):
|
|||||||
return val_str
|
return val_str
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError("Illegal value for path template: {attribute}")
|
raise ValueError("Illegal value for path template: {attribute}")
|
||||||
|
|
||||||
|
|
||||||
|
def format_str_value(value, format_str):
|
||||||
|
"""Format value based on format code in field in format id:02d"""
|
||||||
|
if not format_str:
|
||||||
|
return str(value)
|
||||||
|
format_str = "{0:" + f"{format_str}" + "}"
|
||||||
|
return format_str.format(value)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_album_by_name(photo, album):
|
||||||
|
"""Finds first album named album that photo is in and returns the AlbumInfo object, otherwise returns None"""
|
||||||
|
for album_info in photo.album_info:
|
||||||
|
if album_info.title == album:
|
||||||
|
return album_info
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_album_by_path(photo, folder_album_path):
|
||||||
|
"""finds the first album whose folder_album path matches and folder_album_path and returns the AlbumInfo object, otherwise, returns None"""
|
||||||
|
|
||||||
|
for album_info in photo.album_info:
|
||||||
|
# following code is how {folder_album} builds the folder path
|
||||||
|
folder = "/".join(sanitize_dirname(f) for f in album_info.folder_names)
|
||||||
|
folder += "/" + sanitize_dirname(album_info.title)
|
||||||
|
if folder_album_path.endswith(folder):
|
||||||
|
return album_info
|
||||||
|
return None
|
||||||
|
|||||||
@@ -778,6 +778,21 @@ UUID_DICT_MISSING = {
|
|||||||
"D79B8D77-BFFC-460B-9312-034F2877D35B": "Pumkins2.jpg", # not missing
|
"D79B8D77-BFFC-460B-9312-034F2877D35B": "Pumkins2.jpg", # not missing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UUID_DICT_FOLDER_ALBUM_SEQ = {
|
||||||
|
"7783E8E6-9CAC-40F3-BE22-81FB7051C266": {
|
||||||
|
"directory": "{folder_album}",
|
||||||
|
"album": "Sorted Oldest First",
|
||||||
|
"filename": "{album?{folder_album_seq.1}_,}{original_name}",
|
||||||
|
"result": "3_IMG_3092.heic",
|
||||||
|
},
|
||||||
|
"3DD2C897-F19E-4CA6-8C22-B027D5A71907": {
|
||||||
|
"directory": "{album}",
|
||||||
|
"album": "Sorted Oldest First",
|
||||||
|
"filename": "{album?{album_seq}_,}{original_name}",
|
||||||
|
"result": "0_IMG_4547.jpg",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def modify_file(filename):
|
def modify_file(filename):
|
||||||
"""appends data to a file to modify it"""
|
"""appends data to a file to modify it"""
|
||||||
@@ -7070,3 +7085,39 @@ def test_export_query_function():
|
|||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
assert "exported: 1" in result.output
|
assert "exported: 1" in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_album_seq():
|
||||||
|
"""Test {album_seq} template"""
|
||||||
|
import glob
|
||||||
|
from osxphotos.cli import cli
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
for uuid in UUID_DICT_FOLDER_ALBUM_SEQ:
|
||||||
|
result = runner.invoke(
|
||||||
|
cli,
|
||||||
|
[
|
||||||
|
"export",
|
||||||
|
"--db",
|
||||||
|
os.path.join(cwd, PHOTOS_DB_15_7),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--album",
|
||||||
|
UUID_DICT_FOLDER_ALBUM_SEQ[uuid]["album"],
|
||||||
|
"--directory",
|
||||||
|
UUID_DICT_FOLDER_ALBUM_SEQ[uuid]["directory"],
|
||||||
|
"--filename",
|
||||||
|
UUID_DICT_FOLDER_ALBUM_SEQ[uuid]["filename"],
|
||||||
|
"--uuid",
|
||||||
|
uuid,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
files = glob.glob(f"{UUID_DICT_FOLDER_ALBUM_SEQ[uuid]['album']}/*")
|
||||||
|
assert (
|
||||||
|
f"{UUID_DICT_FOLDER_ALBUM_SEQ[uuid]['album']}/{UUID_DICT_FOLDER_ALBUM_SEQ[uuid]['result']}"
|
||||||
|
in files
|
||||||
|
)
|
||||||
|
|||||||
@@ -343,6 +343,49 @@ UUID_CONDITIONAL = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UUID_ALBUM_SEQ = {
|
||||||
|
"7783E8E6-9CAC-40F3-BE22-81FB7051C266": {
|
||||||
|
"album": "/Sorted Manual",
|
||||||
|
"templates": {
|
||||||
|
"{album_seq}": "0",
|
||||||
|
"{album_seq:02d}": "00",
|
||||||
|
"{album_seq.1}": "1",
|
||||||
|
"{album_seq.1:03d}": "001",
|
||||||
|
"{folder_album_seq}": "0",
|
||||||
|
"{folder_album_seq:02d}": "00",
|
||||||
|
"{folder_album_seq.1}": "1",
|
||||||
|
"{folder_album_seq.1:03d}": "001",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"F12384F6-CD17-4151-ACBA-AE0E3688539E": {
|
||||||
|
"album": "/Sorted Manual",
|
||||||
|
"templates": {
|
||||||
|
"{album_seq}": "2",
|
||||||
|
"{album_seq:02d}": "02",
|
||||||
|
"{album_seq.1}": "3",
|
||||||
|
"{album_seq.1:03d}": "003",
|
||||||
|
"{folder_album_seq}": "2",
|
||||||
|
"{folder_album_seq:02d}": "02",
|
||||||
|
"{folder_album_seq.1}": "3",
|
||||||
|
"{folder_album_seq.1:03d}": "003",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51": {
|
||||||
|
"album": "/Folder1/SubFolder2/AlbumInFolder",
|
||||||
|
"templates": {
|
||||||
|
"{album_seq}": "1",
|
||||||
|
"{album_seq:02d}": "01",
|
||||||
|
"{album_seq.1}": "2",
|
||||||
|
"{album_seq.1:03d}": "002",
|
||||||
|
"{folder_album_seq}": "1",
|
||||||
|
"{folder_album_seq:02d}": "01",
|
||||||
|
"{folder_album_seq.1}": "2",
|
||||||
|
"{folder_album_seq.0}": "1",
|
||||||
|
"{folder_album_seq.1:03d}": "002",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def photosdb_places():
|
def photosdb_places():
|
||||||
@@ -1105,3 +1148,16 @@ def test_id(photosdb):
|
|||||||
|
|
||||||
rendered, _ = photo.render_template("{id:03d}")
|
rendered, _ = photo.render_template("{id:03d}")
|
||||||
assert rendered[0] == "007"
|
assert rendered[0] == "007"
|
||||||
|
|
||||||
|
|
||||||
|
def test_album_seq(photosdb):
|
||||||
|
"""Test {album_seq} and {folder_album_seq} templates"""
|
||||||
|
from osxphotos.phototemplate import RenderOptions
|
||||||
|
|
||||||
|
for uuid in UUID_ALBUM_SEQ:
|
||||||
|
photo = photosdb.get_photo(uuid)
|
||||||
|
album = UUID_ALBUM_SEQ[uuid]["album"]
|
||||||
|
options = RenderOptions(dest_path=album)
|
||||||
|
for template, value in UUID_ALBUM_SEQ[uuid]["templates"].items():
|
||||||
|
rendered, _ = photo.render_template(template, options=options)
|
||||||
|
assert rendered[0] == value
|
||||||
|
|||||||
Reference in New Issue
Block a user