Fixed sidecar collisions, closes #210

This commit is contained in:
Rhet Turnbull
2020-08-31 06:30:44 -07:00
parent 1f343c1c11
commit c2fecc9d30
6 changed files with 98 additions and 29 deletions

View File

@@ -1,3 +1,3 @@
""" version info """ """ version info """
__version__ = "0.33.7" __version__ = "0.33.8"

View File

@@ -688,7 +688,7 @@ def export2(
if sidecar_json: if sidecar_json:
logging.debug("writing exiftool_json_sidecar") logging.debug("writing exiftool_json_sidecar")
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}.json") sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.json")
sidecar_str = self._exiftool_json_sidecar( sidecar_str = self._exiftool_json_sidecar(
use_albums_as_keywords=use_albums_as_keywords, use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords, use_persons_as_keywords=use_persons_as_keywords,
@@ -704,12 +704,13 @@ def export2(
if sidecar_xmp: if sidecar_xmp:
logging.debug("writing xmp_sidecar") logging.debug("writing xmp_sidecar")
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}.xmp") sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.xmp")
sidecar_str = self._xmp_sidecar( sidecar_str = self._xmp_sidecar(
use_albums_as_keywords=use_albums_as_keywords, use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords, use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template, keyword_template=keyword_template,
description_template=description_template, description_template=description_template,
extension=dest.suffix[1:] if dest.suffix else None,
) )
if not dry_run: if not dry_run:
try: try:
@@ -1120,6 +1121,7 @@ def _xmp_sidecar(
use_persons_as_keywords=False, use_persons_as_keywords=False,
keyword_template=None, keyword_template=None,
description_template=None, description_template=None,
extension=None
): ):
""" returns string for XMP sidecar """ returns string for XMP sidecar
use_albums_as_keywords: treat album names as keywords use_albums_as_keywords: treat album names as keywords
@@ -1129,11 +1131,10 @@ def _xmp_sidecar(
xmp_template = Template(filename=os.path.join(_TEMPLATE_DIR, _XMP_TEMPLATE_NAME)) xmp_template = Template(filename=os.path.join(_TEMPLATE_DIR, _XMP_TEMPLATE_NAME))
if self.path is not None: if extension is None:
extension = pathlib.Path(self.path).suffix[1:].upper() extension = pathlib.Path(self.original_filename)
else: extension = extension.suffix[1:] if extension.suffix else None
extension = None
if description_template is not None: if description_template is not None:
description = self.render_template( description = self.render_template(
description_template, expand_inplace=True, inplace_sep=", " description_template, expand_inplace=True, inplace_sep=", "

View File

@@ -202,7 +202,7 @@ CLI_EXPORT_BY_DATE_NEED_TOUCH_UUID = [
CLI_EXPORT_BY_DATE_NEED_TOUCH_TIMES = [1538165227, 1539436692] CLI_EXPORT_BY_DATE_NEED_TOUCH_TIMES = [1538165227, 1539436692]
CLI_EXPORT_BY_DATE = ["2018/09/28/Pumpkins3.jpg", "2018/09/28/Pumkins1.jpg"] CLI_EXPORT_BY_DATE = ["2018/09/28/Pumpkins3.jpg", "2018/09/28/Pumkins1.jpg"]
CLI_EXPORT_SIDECAR_FILENAMES = ["Pumkins2.jpg", "Pumkins2.json", "Pumkins2.xmp"] CLI_EXPORT_SIDECAR_FILENAMES = ["Pumkins2.jpg", "Pumkins2.jpg.json", "Pumkins2.jpg.xmp"]
CLI_EXPORT_LIVE = [ CLI_EXPORT_LIVE = [
"51F2BEF7-431A-4D31-8AC1-3284A57826AE.jpeg", "51F2BEF7-431A-4D31-8AC1-3284A57826AE.jpeg",
@@ -224,7 +224,7 @@ CLI_UUID_DICT_15_5 = {
"template": "F12384F6-CD17-4151-ACBA-AE0E3688539E", "template": "F12384F6-CD17-4151-ACBA-AE0E3688539E",
} }
CLI_TEMPLATE_SIDECAR_FILENAME = "Pumkins1.json" CLI_TEMPLATE_SIDECAR_FILENAME = "Pumkins1.jpg.json"
CLI_UUID_DICT_14_6 = {"intrash": "3tljdX43R8+k6peNHVrJNQ"} CLI_UUID_DICT_14_6 = {"intrash": "3tljdX43R8+k6peNHVrJNQ"}
@@ -2256,7 +2256,7 @@ def test_export_sidecar_keyword_template():
"EXIF:ModifyDate": "2020:04:11 12:34:16"}]""" "EXIF:ModifyDate": "2020:04:11 12:34:16"}]"""
)[0] )[0]
json_file = open("Pumkins2.json", "r") json_file = open("Pumkins2.jpg.json", "r")
json_got = json.load(json_file)[0] json_got = json.load(json_file)[0]
json_file.close() json_file.close()

View File

@@ -59,12 +59,13 @@ UUID_DICT = {
"external_edit": "DC99FBDD-7A52-4100-A5BB-344131646C30", "external_edit": "DC99FBDD-7A52-4100-A5BB-344131646C30",
"no_external_edit": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51", "no_external_edit": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
"export": "D79B8D77-BFFC-460B-9312-034F2877D35B", # "Pumkins2.jpg" "export": "D79B8D77-BFFC-460B-9312-034F2877D35B", # "Pumkins2.jpg"
"xmp": "F12384F6-CD17-4151-ACBA-AE0E3688539E", # Pumkins1.jpg "xmp": "F12384F6-CD17-4151-ACBA-AE0E3688539E", # Pumkins1.jpg
} }
# used with UUID_DICT["xmp"] # used with UUID_DICT["xmp"]
XMP_FILENAME = "Pumkins1.xmp" XMP_FILENAME = "Pumkins1.jpg.xmp"
XMP_JPG_FILENAME = "Pumkins1.jpg" XMP_JPG_FILENAME = "Pumkins1.jpg"
def test_export_1(): def test_export_1():
# test basic export # test basic export
@@ -576,12 +577,13 @@ def test_xmp_sidecar_is_valid(tmp_path):
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["xmp"]]) photos = photosdb.photos(uuid=[UUID_DICT["xmp"]])
photos[0].export(str(tmp_path), XMP_JPG_FILENAME, sidecar_xmp = True) photos[0].export(str(tmp_path), XMP_JPG_FILENAME, sidecar_xmp=True)
xmp_file = tmp_path / XMP_FILENAME xmp_file = tmp_path / XMP_FILENAME
assert xmp_file.is_file() assert xmp_file.is_file()
exiftool = ExifTool(str(xmp_file)) exiftool = ExifTool(str(xmp_file))
output = exiftool.run_commands("-validate", "-warning") output = exiftool.run_commands("-validate", "-warning")
assert output == b'[ExifTool] Validate : 0 0 0' assert output == b"[ExifTool] Validate : 0 0 0"
def test_xmp_sidecar(): def test_xmp_sidecar():
import osxphotos import osxphotos
@@ -596,7 +598,73 @@ def test_xmp_sidecar():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPEG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does -->
<dc:subject>
<rdf:Seq>
<rdf:li>Kids</rdf:li>
<rdf:li>Suzy</rdf:li>
<rdf:li>Katie</rdf:li>
</rdf:Seq>
</dc:subject>
<photoshop:DateCreated>2018-09-28T15:35:49.063000-04:00</photoshop:DateCreated>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:Iptc4xmpExt='http://iptc.org/std/Iptc4xmpExt/2008-02-29/'>
<Iptc4xmpExt:PersonInImage>
<rdf:Bag>
<rdf:li>Suzy</rdf:li>
<rdf:li>Katie</rdf:li>
</rdf:Bag>
</Iptc4xmpExt:PersonInImage>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:digiKam='http://www.digikam.org/ns/1.0/'>
<digiKam:TagsList>
<rdf:Seq>
<rdf:li>Kids</rdf:li>
</rdf:Seq>
</digiKam:TagsList>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
<xmp:CreateDate>2018-09-28T15:35:49</xmp:CreateDate>
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:exif='http://ns.adobe.com/exif/1.0/'>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(extension="jpg")
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(
sorted(xmp_expected_lines), sorted(xmp_got_lines)
):
assert line_expected == line_got
def test_xmp_sidecar_extension():
""" test XMP sidecar when no extension is passed """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["xmp"]])
xmp_expected = """<!-- Created with osxphotos https://github.com/RhetTbull/osxphotos -->
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0">
<!-- mirrors Photos 5 "Export IPTC as XMP" option -->
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description> <dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title> <dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -661,7 +729,7 @@ def test_xmp_sidecar_use_persons_keyword():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPEG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description> <dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title> <dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -706,7 +774,7 @@ def test_xmp_sidecar_use_persons_keyword():
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")] xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(use_persons_as_keywords=True) xmp_got = photos[0]._xmp_sidecar(use_persons_as_keywords=True, extension="jpg")
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")] xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip( for line_expected, line_got in zip(
@@ -728,7 +796,7 @@ def test_xmp_sidecar_use_albums_keyword():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPEG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description> <dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title> <dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -773,7 +841,7 @@ def test_xmp_sidecar_use_albums_keyword():
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")] xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(use_albums_as_keywords=True) xmp_got = photos[0]._xmp_sidecar(use_albums_as_keywords=True, extension="jpg")
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")] xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip( for line_expected, line_got in zip(
@@ -796,7 +864,7 @@ def test_xmp_sidecar_gps():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPEG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description></dc:description> <dc:description></dc:description>
<dc:title>St. James's Park</dc:title> <dc:title>St. James's Park</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -845,7 +913,7 @@ def test_xmp_sidecar_gps():
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")] xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar() xmp_got = photos[0]._xmp_sidecar(extension="jpg")
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")] xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip( for line_expected, line_got in zip(

View File

@@ -166,7 +166,7 @@ def test_xmp_sidecar_keyword_template():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPEG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description> <dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title> <dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -213,7 +213,7 @@ def test_xmp_sidecar_keyword_template():
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")] xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar( xmp_got = photos[0]._xmp_sidecar(
keyword_template=["{created.year}", "{folder_album}"] keyword_template=["{created.year}", "{folder_album}"], extension="jpg"
) )
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")] xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]

View File

@@ -418,7 +418,7 @@ def test_xmp_sidecar():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description> <dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title> <dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -461,7 +461,7 @@ def test_xmp_sidecar():
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")] xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar() xmp_got = photos[0]._xmp_sidecar(extension="jpg")
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")] xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(xmp_expected_lines, xmp_got_lines): for line_expected, line_got in zip(xmp_expected_lines, xmp_got_lines):
@@ -481,7 +481,7 @@ def test_xmp_sidecar_keyword_template():
<rdf:Description rdf:about="" <rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:SidecarForExtension>JPG</photoshop:SidecarForExtension> <photoshop:SidecarForExtension>jpg</photoshop:SidecarForExtension>
<dc:description>Girls with pumpkins</dc:description> <dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title> <dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does --> <!-- keywords and persons listed in <dc:subject> as Photos does -->
@@ -528,7 +528,7 @@ def test_xmp_sidecar_keyword_template():
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")] xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar( xmp_got = photos[0]._xmp_sidecar(
keyword_template=["{folder_album}", "{created.year}"] keyword_template=["{folder_album}", "{created.year}"], extension="jpg"
) )
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")] xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]