Added --sidecar-drop-ext, issue #291
This commit is contained in:
12
README.md
12
README.md
@@ -328,6 +328,18 @@ Options:
|
|||||||
photoname.ext.json; For a list of tags
|
photoname.ext.json; For a list of tags
|
||||||
exported in the JSON and exiftool sidecar,
|
exported in the JSON and exiftool sidecar,
|
||||||
see '--exiftool'.
|
see '--exiftool'.
|
||||||
|
--sidecar-drop-ext Drop the photo's extension when naming
|
||||||
|
sidecar files. By default, sidecar files are
|
||||||
|
named in format
|
||||||
|
'photo_filename.photo_ext.sidecar_ext', e.g.
|
||||||
|
'IMG_1234.JPG.json'. Use '--sidecar-drop-
|
||||||
|
ext' to ignore the photo extension.
|
||||||
|
Resulting sidecar files will have name in
|
||||||
|
format 'IMG_1234.json'. Warning: this may
|
||||||
|
result in sidecar filename collisions if
|
||||||
|
there are files of different types but the
|
||||||
|
same name in the output directory, e.g.
|
||||||
|
'IMG_1234.JPG' and 'IMG_1234.MOV'.
|
||||||
--exiftool Use exiftool to write metadata directly to
|
--exiftool Use exiftool to write metadata directly to
|
||||||
exported photos. To use this option,
|
exported photos. To use this option,
|
||||||
exiftool must be installed and in the path.
|
exiftool must be installed and in the path.
|
||||||
|
|||||||
@@ -1357,6 +1357,16 @@ def query(
|
|||||||
"Sidecar filename is in format photoname.ext.json; "
|
"Sidecar filename is in format photoname.ext.json; "
|
||||||
"For a list of tags exported in the JSON and exiftool sidecar, see '--exiftool'.",
|
"For a list of tags exported in the JSON and exiftool sidecar, see '--exiftool'.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--sidecar-drop-ext",
|
||||||
|
is_flag=True,
|
||||||
|
help="Drop the photo's extension when naming sidecar files. "
|
||||||
|
"By default, sidecar files are named in format 'photo_filename.photo_ext.sidecar_ext', "
|
||||||
|
"e.g. 'IMG_1234.JPG.json'. Use '--sidecar-drop-ext' to ignore the photo extension. "
|
||||||
|
"Resulting sidecar files will have name in format 'IMG_1234.json'. "
|
||||||
|
"Warning: this may result in sidecar filename collisions if there are files of different "
|
||||||
|
"types but the same name in the output directory, e.g. 'IMG_1234.JPG' and 'IMG_1234.MOV'.",
|
||||||
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--exiftool",
|
"--exiftool",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
@@ -1366,7 +1376,7 @@ def query(
|
|||||||
"Cannot be used with --export-as-hardlink. Writes the following metadata: "
|
"Cannot be used with --export-as-hardlink. Writes the following metadata: "
|
||||||
"EXIF:ImageDescription, XMP:Description (see also --description-template); "
|
"EXIF:ImageDescription, XMP:Description (see also --description-template); "
|
||||||
"XMP:Title; XMP:TagsList, IPTC:Keywords, XMP:Subject "
|
"XMP:Title; XMP:TagsList, IPTC:Keywords, XMP:Subject "
|
||||||
"(see also --keyword-template, --person-keyword, --album-keyword); "
|
"(see also --keyword-template, --person-keyword, --album-keyword); "
|
||||||
"XMP:PersonInImage; EXIF:GPSLatitudeRef; EXIF:GPSLongitudeRef; EXIF:GPSLatitude; EXIF:GPSLongitude; "
|
"XMP:PersonInImage; EXIF:GPSLatitudeRef; EXIF:GPSLongitudeRef; EXIF:GPSLatitude; EXIF:GPSLongitude; "
|
||||||
"EXIF:GPSPosition; EXIF:DateTimeOriginal; EXIF:OffsetTimeOriginal; "
|
"EXIF:GPSPosition; EXIF:DateTimeOriginal; EXIF:OffsetTimeOriginal; "
|
||||||
"EXIF:ModifyDate (see --ignore-date-modified); IPTC:DateCreated; IPTC:TimeCreated; "
|
"EXIF:ModifyDate (see --ignore-date-modified); IPTC:DateCreated; IPTC:TimeCreated; "
|
||||||
@@ -1571,6 +1581,7 @@ def export(
|
|||||||
convert_to_jpeg,
|
convert_to_jpeg,
|
||||||
jpeg_quality,
|
jpeg_quality,
|
||||||
sidecar,
|
sidecar,
|
||||||
|
sidecar_drop_ext,
|
||||||
only_photos,
|
only_photos,
|
||||||
only_movies,
|
only_movies,
|
||||||
burst,
|
burst,
|
||||||
@@ -2036,6 +2047,7 @@ def export(
|
|||||||
verbose=verbose,
|
verbose=verbose,
|
||||||
export_by_date=export_by_date,
|
export_by_date=export_by_date,
|
||||||
sidecar=sidecar,
|
sidecar=sidecar,
|
||||||
|
sidecar_drop_ext=sidecar_drop_ext,
|
||||||
update=update,
|
update=update,
|
||||||
ignore_signature=ignore_signature,
|
ignore_signature=ignore_signature,
|
||||||
export_as_hardlink=export_as_hardlink,
|
export_as_hardlink=export_as_hardlink,
|
||||||
@@ -2084,6 +2096,7 @@ def export(
|
|||||||
verbose=verbose,
|
verbose=verbose,
|
||||||
export_by_date=export_by_date,
|
export_by_date=export_by_date,
|
||||||
sidecar=sidecar,
|
sidecar=sidecar,
|
||||||
|
sidecar_drop_ext=sidecar_drop_ext,
|
||||||
update=update,
|
update=update,
|
||||||
ignore_signature=ignore_signature,
|
ignore_signature=ignore_signature,
|
||||||
export_as_hardlink=export_as_hardlink,
|
export_as_hardlink=export_as_hardlink,
|
||||||
@@ -2616,6 +2629,7 @@ def export_photo(
|
|||||||
verbose=None,
|
verbose=None,
|
||||||
export_by_date=None,
|
export_by_date=None,
|
||||||
sidecar=None,
|
sidecar=None,
|
||||||
|
sidecar_drop_ext=False,
|
||||||
update=None,
|
update=None,
|
||||||
ignore_signature=None,
|
ignore_signature=None,
|
||||||
export_as_hardlink=None,
|
export_as_hardlink=None,
|
||||||
@@ -2654,6 +2668,7 @@ def export_photo(
|
|||||||
verbose: boolean; print verbose output
|
verbose: boolean; print verbose output
|
||||||
export_by_date: boolean; create export folder in form dest/YYYY/MM/DD
|
export_by_date: boolean; create export folder in form dest/YYYY/MM/DD
|
||||||
sidecar: list zero, 1 or 2 of ["json","xmp"] of sidecar variety to export
|
sidecar: list zero, 1 or 2 of ["json","xmp"] of sidecar variety to export
|
||||||
|
sidecar_drop_ext: boolean; if True, drops photo extension from sidecar name
|
||||||
export_as_hardlink: boolean; hardlink files instead of copying them
|
export_as_hardlink: boolean; hardlink files instead of copying them
|
||||||
overwrite: boolean; overwrite dest file if it already exists
|
overwrite: boolean; overwrite dest file if it already exists
|
||||||
original_name: boolean; use original filename instead of current filename
|
original_name: boolean; use original filename instead of current filename
|
||||||
@@ -2804,6 +2819,7 @@ def export_photo(
|
|||||||
dest_path,
|
dest_path,
|
||||||
original_filename,
|
original_filename,
|
||||||
sidecar=sidecar_flags,
|
sidecar=sidecar_flags,
|
||||||
|
sidecar_drop_ext=sidecar_drop_ext,
|
||||||
live_photo=export_live,
|
live_photo=export_live,
|
||||||
raw_photo=export_raw,
|
raw_photo=export_raw,
|
||||||
export_as_hardlink=export_as_hardlink,
|
export_as_hardlink=export_as_hardlink,
|
||||||
@@ -2908,6 +2924,7 @@ def export_photo(
|
|||||||
dest_path,
|
dest_path,
|
||||||
edited_filename,
|
edited_filename,
|
||||||
sidecar=sidecar_flags,
|
sidecar=sidecar_flags,
|
||||||
|
sidecar_drop_ext=sidecar_drop_ext,
|
||||||
export_as_hardlink=export_as_hardlink,
|
export_as_hardlink=export_as_hardlink,
|
||||||
overwrite=overwrite,
|
overwrite=overwrite,
|
||||||
edited=True,
|
edited=True,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.38.16"
|
__version__ = "0.38.17"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -430,6 +430,7 @@ def export2(
|
|||||||
overwrite=False,
|
overwrite=False,
|
||||||
increment=True,
|
increment=True,
|
||||||
sidecar=0,
|
sidecar=0,
|
||||||
|
sidecar_drop_ext=False,
|
||||||
use_photos_export=False,
|
use_photos_export=False,
|
||||||
timeout=120,
|
timeout=120,
|
||||||
exiftool=False,
|
exiftool=False,
|
||||||
@@ -475,6 +476,7 @@ def export2(
|
|||||||
sidecar filename will be dest/filename.json; does not include exiftool tag group names (e.g. `exiftool -j`)
|
sidecar filename will be dest/filename.json; does not include exiftool tag group names (e.g. `exiftool -j`)
|
||||||
SIDECAR_XMP: if set will write an XMP sidecar with IPTC data
|
SIDECAR_XMP: if set will write an XMP sidecar with IPTC data
|
||||||
sidecar filename will be dest/filename.xmp
|
sidecar filename will be dest/filename.xmp
|
||||||
|
sidecar_drop_ext: (boolean, default=False); if True, drops the photo's extension from sidecar filename (e.g. 'IMG_1234.json' instead of 'IMG_1234.JPG.json')
|
||||||
use_photos_export: (boolean, default=False); if True will attempt to export photo via applescript interaction with Photos
|
use_photos_export: (boolean, default=False); if True will attempt to export photo via applescript interaction with Photos
|
||||||
timeout: (int, default=120) timeout in seconds used with use_photos_export
|
timeout: (int, default=120) timeout in seconds used with use_photos_export
|
||||||
exiftool: (boolean, default = False); if True, will use exiftool to write metadata to export file
|
exiftool: (boolean, default = False); if True, will use exiftool to write metadata to export file
|
||||||
@@ -893,8 +895,9 @@ def export2(
|
|||||||
sidecar_xmp_files_skipped = []
|
sidecar_xmp_files_skipped = []
|
||||||
sidecar_xmp_files_written = []
|
sidecar_xmp_files_written = []
|
||||||
|
|
||||||
|
dest_suffix = "" if sidecar_drop_ext else dest.suffix
|
||||||
if sidecar & SIDECAR_JSON:
|
if sidecar & SIDECAR_JSON:
|
||||||
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.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,
|
||||||
@@ -913,7 +916,7 @@ def export2(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if sidecar & SIDECAR_EXIFTOOL:
|
if sidecar & SIDECAR_EXIFTOOL:
|
||||||
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.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,
|
||||||
@@ -933,7 +936,7 @@ def export2(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if sidecar & SIDECAR_XMP:
|
if sidecar & SIDECAR_XMP:
|
||||||
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.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,
|
||||||
|
|||||||
@@ -306,6 +306,11 @@ 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.jpg.json", "Pumkins2.jpg.xmp"]
|
CLI_EXPORT_SIDECAR_FILENAMES = ["Pumkins2.jpg", "Pumkins2.jpg.json", "Pumkins2.jpg.xmp"]
|
||||||
|
CLI_EXPORT_SIDECAR_DROP_EXT_FILENAMES = [
|
||||||
|
"Pumkins2.jpg",
|
||||||
|
"Pumkins2.json",
|
||||||
|
"Pumkins2.xmp",
|
||||||
|
]
|
||||||
|
|
||||||
CLI_EXPORT_LIVE = [
|
CLI_EXPORT_LIVE = [
|
||||||
"51F2BEF7-431A-4D31-8AC1-3284A57826AE.jpeg",
|
"51F2BEF7-431A-4D31-8AC1-3284A57826AE.jpeg",
|
||||||
@@ -1974,6 +1979,7 @@ def test_query_deleted_4():
|
|||||||
|
|
||||||
|
|
||||||
def test_export_sidecar():
|
def test_export_sidecar():
|
||||||
|
""" test --sidecar """
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
@@ -2003,6 +2009,38 @@ def test_export_sidecar():
|
|||||||
assert sorted(files) == sorted(CLI_EXPORT_SIDECAR_FILENAMES)
|
assert sorted(files) == sorted(CLI_EXPORT_SIDECAR_FILENAMES)
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_sidecar_drop_ext():
|
||||||
|
""" test --sidecar with --sidecar-drop-ext option """
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import osxphotos
|
||||||
|
|
||||||
|
from osxphotos.__main__ import cli
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
cli,
|
||||||
|
[
|
||||||
|
"export",
|
||||||
|
"--db",
|
||||||
|
os.path.join(cwd, CLI_PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"--sidecar=json",
|
||||||
|
"--sidecar=xmp",
|
||||||
|
"--sidecar-drop-ext",
|
||||||
|
f"--uuid={CLI_EXPORT_UUID}",
|
||||||
|
"-V",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
files = glob.glob("*.*")
|
||||||
|
assert sorted(files) == sorted(CLI_EXPORT_SIDECAR_DROP_EXT_FILENAMES)
|
||||||
|
|
||||||
|
|
||||||
def test_export_sidecar_exiftool():
|
def test_export_sidecar_exiftool():
|
||||||
""" test --sidecar exiftool """
|
""" test --sidecar exiftool """
|
||||||
import glob
|
import glob
|
||||||
|
|||||||
Reference in New Issue
Block a user