Added label and label_normalized to template system, closes #130
This commit is contained in:
@@ -21,7 +21,7 @@ import osxphotos
|
|||||||
from ._constants import _EXIF_TOOL_URL, _PHOTOS_4_VERSION, _UNKNOWN_PLACE
|
from ._constants import _EXIF_TOOL_URL, _PHOTOS_4_VERSION, _UNKNOWN_PLACE
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
from .exiftool import get_exiftool_path
|
from .exiftool import get_exiftool_path
|
||||||
from .template import TEMPLATE_SUBSTITUTIONS, TEMPLATE_SUBSTITUTIONS_MULTI_VALUED
|
from .photoinfo.template import TEMPLATE_SUBSTITUTIONS, TEMPLATE_SUBSTITUTIONS_MULTI_VALUED
|
||||||
from .utils import _copy_file, create_path_by_date
|
from .utils import _copy_file, create_path_by_date
|
||||||
|
|
||||||
|
|
||||||
@@ -1695,9 +1695,9 @@ def export_photo(
|
|||||||
dest_paths = []
|
dest_paths = []
|
||||||
for dirname in dirnames:
|
for dirname in dirnames:
|
||||||
dirname = sanitize_filepath(dirname, platform="auto")
|
dirname = sanitize_filepath(dirname, platform="auto")
|
||||||
if not is_valid_filepath(dirname, platform="auto"):
|
|
||||||
raise ValueError(f"Invalid file path: {dirname}")
|
|
||||||
dest_path = os.path.join(dest, dirname)
|
dest_path = os.path.join(dest, dirname)
|
||||||
|
if not is_valid_filepath(dest_path, platform="auto"):
|
||||||
|
raise ValueError(f"Invalid file path: '{dest_path}'")
|
||||||
if not os.path.isdir(dest_path):
|
if not os.path.isdir(dest_path):
|
||||||
os.makedirs(dest_path)
|
os.makedirs(dest_path)
|
||||||
dest_paths.append(dest_path)
|
dest_paths.append(dest_path)
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ from pprint import pformat
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from mako.template import Template
|
from mako.template import Template
|
||||||
|
|
||||||
|
|
||||||
from .._constants import (
|
from .._constants import (
|
||||||
_MAX_IPTC_KEYWORD_LEN,
|
_MAX_IPTC_KEYWORD_LEN,
|
||||||
_MOVIE_TYPE,
|
_MOVIE_TYPE,
|
||||||
@@ -35,20 +33,20 @@ from ..albuminfo import AlbumInfo
|
|||||||
from ..datetime_formatter import DateTimeFormatter
|
from ..datetime_formatter import DateTimeFormatter
|
||||||
from ..exiftool import ExifTool
|
from ..exiftool import ExifTool
|
||||||
from ..placeinfo import PlaceInfo4, PlaceInfo5
|
from ..placeinfo import PlaceInfo4, PlaceInfo5
|
||||||
from ..template import (
|
|
||||||
MULTI_VALUE_SUBSTITUTIONS,
|
|
||||||
TEMPLATE_SUBSTITUTIONS,
|
|
||||||
TEMPLATE_SUBSTITUTIONS_MULTI_VALUED,
|
|
||||||
)
|
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
_hardlink_file,
|
|
||||||
_copy_file,
|
_copy_file,
|
||||||
_export_photo_uuid_applescript,
|
_export_photo_uuid_applescript,
|
||||||
_get_resource_loc,
|
_get_resource_loc,
|
||||||
|
_hardlink_file,
|
||||||
dd_to_dms_str,
|
dd_to_dms_str,
|
||||||
findfiles,
|
findfiles,
|
||||||
get_preferred_uti_extension,
|
get_preferred_uti_extension,
|
||||||
)
|
)
|
||||||
|
from .template import (
|
||||||
|
MULTI_VALUE_SUBSTITUTIONS,
|
||||||
|
TEMPLATE_SUBSTITUTIONS,
|
||||||
|
TEMPLATE_SUBSTITUTIONS_MULTI_VALUED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PhotoInfo:
|
class PhotoInfo:
|
||||||
@@ -964,13 +962,11 @@ class PhotoInfo:
|
|||||||
# for explanation of regex see https://regex101.com/r/4JJg42/1
|
# for explanation of regex see https://regex101.com/r/4JJg42/1
|
||||||
# pylint: disable=anomalous-backslash-in-string
|
# pylint: disable=anomalous-backslash-in-string
|
||||||
regex = r"(?<!\{)\{([^\\,}]+)(,{0,1}(([\w\-. ]+))?)(?=\}(?!\}))\}"
|
regex = r"(?<!\{)\{([^\\,}]+)(,{0,1}(([\w\-. ]+))?)(?=\}(?!\}))\}"
|
||||||
|
|
||||||
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)}")
|
||||||
|
|
||||||
def make_subst_function(self, none_str, get_func=self.get_template_value):
|
def make_subst_function(self, none_str, get_func=self.get_template_value):
|
||||||
""" returns: substitution function for use in re.sub
|
""" returns: substitution function for use in re.sub
|
||||||
photo: a PhotoInfo object
|
|
||||||
none_str: value to use if substitution lookup is None and no default provided
|
none_str: value to use if substitution lookup is None and no default provided
|
||||||
get_func: function that gets the substitution value for a given template field
|
get_func: function that gets the substitution value for a given template field
|
||||||
default is get_template_value which handles the single-value fields """
|
default is get_template_value which handles the single-value fields """
|
||||||
@@ -1037,6 +1033,10 @@ class PhotoInfo:
|
|||||||
values = self.persons
|
values = self.persons
|
||||||
# remove any _UNKNOWN_PERSON values
|
# remove any _UNKNOWN_PERSON values
|
||||||
values = [val for val in values if val != _UNKNOWN_PERSON]
|
values = [val for val in values if val != _UNKNOWN_PERSON]
|
||||||
|
elif field == "label":
|
||||||
|
values = self.labels
|
||||||
|
elif field == "label_normalized":
|
||||||
|
values = self.labels_normalized
|
||||||
elif field == "folder_album":
|
elif field == "folder_album":
|
||||||
values = []
|
values = []
|
||||||
# photos must be in an album to be in a folder
|
# photos must be in an album to be in a folder
|
||||||
@@ -1049,7 +1049,6 @@ class PhotoInfo:
|
|||||||
else:
|
else:
|
||||||
# album not in folder
|
# album not in folder
|
||||||
values.append(album.title)
|
values.append(album.title)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unhandleded template value: {field}")
|
raise ValueError(f"Unhandleded template value: {field}")
|
||||||
|
|
||||||
@@ -1057,7 +1056,7 @@ class PhotoInfo:
|
|||||||
values = values or [None]
|
values = values or [None]
|
||||||
|
|
||||||
# Build a regex that matches only the field being processed
|
# Build a regex that matches only the field being processed
|
||||||
re_str = r"(?<!\\)\{(" + field + r")(,{0,1}(([\w\-. ]+))?)\}"
|
re_str = r"(?<!\\)\{(" + field + r")(,(([\w\-. ]{0,})))?\}"
|
||||||
regex_multi = re.compile(re_str)
|
regex_multi = re.compile(re_str)
|
||||||
|
|
||||||
# holds each of the new rendered_strings, set() to avoid duplicates
|
# holds each of the new rendered_strings, set() to avoid duplicates
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ TEMPLATE_SUBSTITUTIONS_MULTI_VALUED = {
|
|||||||
"{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",
|
||||||
"{keyword}": "Keyword(s) assigned to photo",
|
"{keyword}": "Keyword(s) assigned to photo",
|
||||||
"{person}": "Person(s) / face(s) in a photo",
|
"{person}": "Person(s) / face(s) in a photo",
|
||||||
|
"{label}": "Image categorization label associated with a photo (Photos 5 only)",
|
||||||
|
"{label_normalized}": "All lower case version of 'label' (Photos 5 only)",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Just the multi-valued substitution names without the braces
|
# Just the multi-valued substitution names without the braces
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ def test_lookup():
|
|||||||
""" Test that a lookup is returned for every possible value """
|
""" Test that a lookup is returned for every possible value """
|
||||||
import re
|
import re
|
||||||
import osxphotos
|
import osxphotos
|
||||||
from osxphotos.template import TEMPLATE_SUBSTITUTIONS
|
from osxphotos.photoinfo.template import TEMPLATE_SUBSTITUTIONS
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
|
||||||
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
|
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user