Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1026473684 | ||
|
|
3f9c9893c3 | ||
|
|
574cdd65a3 | ||
|
|
5b9547669e | ||
|
|
35b5bbd13d | ||
|
|
6870ad0d8e | ||
|
|
17ac5949e1 | ||
|
|
ffb9af1965 | ||
|
|
595307a003 | ||
|
|
79a50b9e50 |
@@ -184,6 +184,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AaronVanGeffen",
|
||||
"name": "Aaron van Geffen",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/604665?v=4",
|
||||
"profile": "https://aaronweb.net/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
27
CHANGELOG.md
@@ -4,6 +4,33 @@ All notable changes to this project will be documented in this file. Dates are d
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [v0.41.3](https://github.com/RhetTbull/osxphotos/compare/v0.41.2...v0.41.3)
|
||||
|
||||
> 14 March 2021
|
||||
|
||||
- docs: add AaronVanGeffen as a contributor [`#398`](https://github.com/RhetTbull/osxphotos/pull/398)
|
||||
- Use original filename to export photos by default [`#396`](https://github.com/RhetTbull/osxphotos/pull/396)
|
||||
- Updated docs for --cleanup, #394 [`17ac594`](https://github.com/RhetTbull/osxphotos/commit/17ac5949e15057379eb13b979d4d7498bbb94d67)
|
||||
- Add --cleanup files to report, #395 [`5b95476`](https://github.com/RhetTbull/osxphotos/commit/5b9547669ed6622ae06607e024315e383c0b2d98)
|
||||
|
||||
#### [v0.41.2](https://github.com/RhetTbull/osxphotos/compare/v0.41.1...v0.41.2)
|
||||
|
||||
> 14 March 2021
|
||||
|
||||
- Fix for long descriptions with exiftool, #393 [`ffb9af1`](https://github.com/RhetTbull/osxphotos/commit/ffb9af1965668bcfc2422f08b2462964a7dae3e2)
|
||||
|
||||
#### [v0.41.1](https://github.com/RhetTbull/osxphotos/compare/v0.41.0...v0.41.1)
|
||||
|
||||
> 5 March 2021
|
||||
|
||||
- Bug fix, convert PosixPath to str, #392 [`595307a`](https://github.com/RhetTbull/osxphotos/commit/595307a003c8ae5d3bee3ad161bb880d884b3cc3)
|
||||
|
||||
#### [v0.41.0](https://github.com/RhetTbull/osxphotos/compare/v0.40.19...v0.41.0)
|
||||
|
||||
> 22 February 2021
|
||||
|
||||
- Template refactor [`#385`](https://github.com/RhetTbull/osxphotos/pull/385)
|
||||
|
||||
#### [v0.40.19](https://github.com/RhetTbull/osxphotos/compare/v0.40.18...v0.40.19)
|
||||
|
||||
> 20 February 2021
|
||||
|
||||
167
README.md
@@ -4,7 +4,7 @@
|
||||
[](https://github.com/RhetTbull/osxphotos/workflows/Tests/badge.svg)
|
||||

|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors)
|
||||
[](#contributors)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
OSXPhotos provides the ability to interact with and query Apple's Photos.app library on macOS. You can query the Photos library database — for example, file name, file path, and metadata such as keywords/tags, persons/faces, albums, etc. You can also easily export both the original and edited photos.
|
||||
@@ -183,41 +183,52 @@ Options:
|
||||
use in the following order: 1. last opened
|
||||
library, 2. system library, 3.
|
||||
~/Pictures/Photos Library.photoslibrary
|
||||
|
||||
-V, --verbose Print verbose output.
|
||||
--keyword KEYWORD Search for photos with keyword KEYWORD. If
|
||||
more than one keyword, treated as "OR", e.g.
|
||||
find photos matching any keyword
|
||||
|
||||
--person PERSON Search for photos with person PERSON. If more
|
||||
than one person, treated as "OR", e.g. find
|
||||
photos matching any person
|
||||
|
||||
--album ALBUM Search for photos in album ALBUM. If more than
|
||||
one album, treated as "OR", e.g. find photos
|
||||
matching any album
|
||||
|
||||
--folder FOLDER Search for photos in an album in folder
|
||||
FOLDER. If more than one folder, treated as
|
||||
"OR", e.g. find photos in any FOLDER. Only
|
||||
searches top level folders (e.g. does not look
|
||||
at subfolders)
|
||||
|
||||
--uuid UUID Search for photos with UUID(s).
|
||||
--uuid-from-file FILE Search for photos with UUID(s) loaded from
|
||||
FILE. Format is a single UUID per line. Lines
|
||||
preceded with # are ignored.
|
||||
|
||||
--title TITLE Search for TITLE in title of photo.
|
||||
--no-title Search for photos with no title.
|
||||
--description DESC Search for DESC in description of photo.
|
||||
--no-description Search for photos with no description.
|
||||
--place PLACE Search for PLACE in photo's reverse
|
||||
geolocation info
|
||||
|
||||
--no-place Search for photos with no associated place
|
||||
name info (no reverse geolocation info)
|
||||
|
||||
--label LABEL Search for photos with image classification
|
||||
label LABEL (Photos 5 only). If more than one
|
||||
label, treated as "OR", e.g. find photos
|
||||
matching any label
|
||||
|
||||
--uti UTI Search for photos whose uniform type
|
||||
identifier (UTI) matches UTI
|
||||
|
||||
-i, --ignore-case Case insensitive search for title,
|
||||
description, place, keyword, person, or album.
|
||||
|
||||
--edited Search for photos that have been edited.
|
||||
--external-edit Search for photos edited in external editor.
|
||||
--favorite Search for photos marked favorite.
|
||||
@@ -226,47 +237,67 @@ Options:
|
||||
--not-hidden Search for photos not marked hidden.
|
||||
--shared Search for photos in shared iCloud album
|
||||
(Photos 5 only).
|
||||
|
||||
--not-shared Search for photos not in shared iCloud album
|
||||
(Photos 5 only).
|
||||
|
||||
--burst Search for photos that were taken in a burst.
|
||||
--not-burst Search for photos that are not part of a
|
||||
burst.
|
||||
|
||||
--live Search for Apple live photos
|
||||
--not-live Search for photos that are not Apple live
|
||||
photos.
|
||||
|
||||
--portrait Search for Apple portrait mode photos.
|
||||
--not-portrait Search for photos that are not Apple portrait
|
||||
mode photos.
|
||||
|
||||
--screenshot Search for screenshot photos.
|
||||
--not-screenshot Search for photos that are not screenshot
|
||||
photos.
|
||||
|
||||
--slow-mo Search for slow motion videos.
|
||||
--not-slow-mo Search for photos that are not slow motion
|
||||
videos.
|
||||
|
||||
--time-lapse Search for time lapse videos.
|
||||
--not-time-lapse Search for photos that are not time lapse
|
||||
videos.
|
||||
|
||||
--hdr Search for high dynamic range (HDR) photos.
|
||||
--not-hdr Search for photos that are not HDR photos.
|
||||
--selfie Search for selfies (photos taken with front-
|
||||
facing cameras).
|
||||
|
||||
--not-selfie Search for photos that are not selfies.
|
||||
--panorama Search for panorama photos.
|
||||
--not-panorama Search for photos that are not panoramas.
|
||||
--has-raw Search for photos with both a jpeg and raw
|
||||
version
|
||||
|
||||
--only-movies Search only for movies (default searches both
|
||||
images and movies).
|
||||
|
||||
--only-photos Search only for photos/images (default
|
||||
searches both images and movies).
|
||||
--from-date DATETIME Search by start item date, e.g.
|
||||
|
||||
--from-date DATETIME Search by item start date, e.g.
|
||||
2000-01-12T12:00:00,
|
||||
2001-01-12T12:00:00-07:00, or 2000-12-31 (ISO
|
||||
8601).
|
||||
--to-date DATETIME Search by end item date, e.g.
|
||||
8601 with/without timezone).
|
||||
|
||||
--to-date DATETIME Search by item end date, e.g.
|
||||
2000-01-12T12:00:00,
|
||||
2001-01-12T12:00:00-07:00, or 2000-12-31 (ISO
|
||||
8601).
|
||||
8601 with/without timezone).
|
||||
|
||||
--from-time TIME Search by item start time of day, e.g. 12:00,
|
||||
or 12:00:00.
|
||||
|
||||
--to-time TIME Search by item end time of day, e.g. 12:00 or
|
||||
12:00:00.
|
||||
|
||||
--has-comment Search for photos that have comments.
|
||||
--no-comment Search for photos with no comments.
|
||||
--has-likes Search for photos that have likes.
|
||||
@@ -274,17 +305,23 @@ Options:
|
||||
--is-reference Search for photos that were imported as
|
||||
referenced files (not copied into Photos
|
||||
library).
|
||||
|
||||
--in-album Search for photos that are in one or more
|
||||
albums.
|
||||
|
||||
--not-in-album Search for photos that are not in any albums.
|
||||
--missing Export only photos missing from the Photos
|
||||
library; must be used with --download-missing.
|
||||
|
||||
--deleted Include photos from the 'Recently Deleted'
|
||||
folder.
|
||||
|
||||
--deleted-only Include only photos from the 'Recently
|
||||
Deleted' folder.
|
||||
|
||||
--update Only export new or updated files. See notes
|
||||
below on export and --update.
|
||||
|
||||
--ignore-signature When used with '--update', ignores file
|
||||
signature when updating files. This is useful
|
||||
if you have processed or edited exported
|
||||
@@ -303,12 +340,15 @@ Options:
|
||||
not; 3) if a sidecar does not exist for the
|
||||
photo, a sidecar will be written whether or
|
||||
not the photo file was written or updated.
|
||||
|
||||
--only-new If used with --update, ignores any previously
|
||||
exported files, even if missing from the
|
||||
export folder and only exports new files that
|
||||
haven't previously been exported.
|
||||
|
||||
--dry-run Dry run (test) the export but don't actually
|
||||
export any files; most useful with --verbose.
|
||||
|
||||
--export-as-hardlink Hardlink files instead of copying them. Cannot
|
||||
be used with --exiftool which creates copies
|
||||
of the files with embedded EXIF data. Note: on
|
||||
@@ -316,41 +356,53 @@ Options:
|
||||
giving many of the same advantages as
|
||||
hardlinks without having to use --export-as-
|
||||
hardlink.
|
||||
|
||||
--touch-file Sets the file's modification time to match
|
||||
photo date.
|
||||
|
||||
--overwrite Overwrite existing files. Default behavior is
|
||||
to add (1), (2), etc to filename if file
|
||||
already exists. Use this with caution as it
|
||||
may create name collisions on export. (e.g. if
|
||||
two files happen to have the same name)
|
||||
|
||||
--export-by-date Automatically create output folders to
|
||||
organize photos by date created (e.g.
|
||||
DEST/2019/12/20/photoname.jpg).
|
||||
|
||||
--skip-edited Do not export edited version of photo if an
|
||||
edited version exists.
|
||||
|
||||
--skip-original-if-edited Do not export original if there is an edited
|
||||
version (exports only the edited version).
|
||||
|
||||
--skip-bursts Do not export all associated burst images in
|
||||
the library if a photo is a burst photo.
|
||||
|
||||
--skip-live Do not export the associated live video
|
||||
component of a live photo.
|
||||
|
||||
--skip-raw Do not export associated raw images of a
|
||||
RAW+JPEG pair. Note: this does not skip raw
|
||||
photos if the raw photo does not have an
|
||||
associated jpeg image (e.g. the raw file was
|
||||
imported to Photos without a jpeg preview).
|
||||
|
||||
--current-name Use photo's current filename instead of
|
||||
original filename for export. Note: Starting
|
||||
with Photos 5, all photos are renamed upon
|
||||
import. By default, photos are exported with
|
||||
the the original name they had before import.
|
||||
|
||||
--convert-to-jpeg Convert all non-jpeg images (e.g. raw, HEIC,
|
||||
PNG, etc) to JPEG upon export. Only works if
|
||||
your Mac has a GPU.
|
||||
|
||||
--jpeg-quality FLOAT RANGE Value in range 0.0 to 1.0 to use with
|
||||
--convert-to-jpeg. A value of 1.0 specifies
|
||||
best quality, a value of 0.0 specifies maximum
|
||||
compression. Defaults to 1.0
|
||||
|
||||
--download-missing Attempt to download missing photos from
|
||||
iCloud. The current implementation uses
|
||||
Applescript to interact with Photos to export
|
||||
@@ -363,6 +415,7 @@ Options:
|
||||
export all burst images; only the primary
|
||||
photo will be exported--associated burst
|
||||
images will be skipped.
|
||||
|
||||
--sidecar FORMAT Create sidecar for each photo exported; valid
|
||||
FORMAT values: xmp, json, exiftool; --sidecar
|
||||
xmp: create XMP sidecar used by Digikam, Adobe
|
||||
@@ -389,6 +442,7 @@ Options:
|
||||
tags exported in the JSON and exiftool
|
||||
sidecar, see '--exiftool'. See also '--ignore-
|
||||
signature'.
|
||||
|
||||
--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',
|
||||
@@ -400,6 +454,7 @@ Options:
|
||||
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
|
||||
exported photos. To use this option, exiftool
|
||||
must be installed and in the path. exiftool
|
||||
@@ -421,8 +476,10 @@ Options:
|
||||
QuickTime:ModifyDate (see also --ignore-date-
|
||||
modified); QuickTime:GPSCoordinates;
|
||||
UserData:GPSCoordinates.
|
||||
|
||||
--exiftool-path EXIFTOOL_PATH Optionally specify path to exiftool; if not
|
||||
provided, will look for exiftool in $PATH.
|
||||
|
||||
--exiftool-option OPTION Optional flag/option to pass to exiftool when
|
||||
using --exiftool. For example, --exiftool-
|
||||
option '-m' to ignore minor warnings. Specify
|
||||
@@ -432,21 +489,27 @@ Options:
|
||||
full list of options. More than one option may
|
||||
be specified by repeating the option, e.g.
|
||||
--exiftool-option '-m' --exiftool-option '-F'.
|
||||
|
||||
--exiftool-merge-keywords Merge any keywords found in the original file
|
||||
with keywords used for '--exiftool' and '--
|
||||
sidecar'.
|
||||
|
||||
--exiftool-merge-persons Merge any persons found in the original file
|
||||
with persons used for '--exiftool' and '--
|
||||
sidecar'.
|
||||
|
||||
--ignore-date-modified If used with --exiftool or --sidecar, will
|
||||
ignore the photo modification date and set
|
||||
EXIF:ModifyDate to EXIF:DateTimeOriginal; this
|
||||
is consistent with how Photos handles the
|
||||
EXIF:ModifyDate tag.
|
||||
|
||||
--person-keyword Use person in image as keyword/tag when
|
||||
exporting metadata.
|
||||
|
||||
--album-keyword Use album name as keyword/tag when exporting
|
||||
metadata.
|
||||
|
||||
--keyword-template TEMPLATE For use with --exiftool, --sidecar; specify a
|
||||
template string to use as keyword in the form
|
||||
'{name,DEFAULT}' This is the same format as
|
||||
@@ -459,6 +522,7 @@ Options:
|
||||
"{folder_album}" --keyword-template
|
||||
"{created.year}". See '--replace-keywords' and
|
||||
Templating System below.
|
||||
|
||||
--replace-keywords Replace keywords with any values specified
|
||||
with --keyword-template. By default,
|
||||
--keyword-template will add keywords to any
|
||||
@@ -467,6 +531,7 @@ Options:
|
||||
from --keyword-template will replace any
|
||||
existing keywords instead of adding additional
|
||||
keywords.
|
||||
|
||||
--description-template TEMPLATE
|
||||
For use with --exiftool, --sidecar; specify a
|
||||
template string to use as description in the
|
||||
@@ -477,6 +542,7 @@ Options:
|
||||
--description-template "{descr} exported with
|
||||
osxphotos on {today.date}" See Templating
|
||||
System below.
|
||||
|
||||
--finder-tag-template TEMPLATE Set MacOS Finder tags to TEMPLATE. These tags
|
||||
can be searched in the Finder or Spotlight
|
||||
with 'tag:tagname' format. For example, '--
|
||||
@@ -485,11 +551,13 @@ Options:
|
||||
TEMPLATE values by using '--finder-tag-
|
||||
template' multiple times. See also '--finder-
|
||||
tag-keywords and Extended Attributes below.'.
|
||||
|
||||
--finder-tag-keywords Set MacOS Finder tags to keywords; any
|
||||
keywords specified via '--keyword-template', '
|
||||
--person-keyword', etc. will also be used as
|
||||
Finder tags. See also '--finder-tag-template
|
||||
and Extended Attributes below.'.
|
||||
|
||||
--xattr-template ATTRIBUTE TEMPLATE
|
||||
Set extended attribute ATTRIBUTE to TEMPLATE
|
||||
value. Valid attributes are: 'authors',
|
||||
@@ -500,16 +568,19 @@ Options:
|
||||
findercomment "{title}; {descr}" See Extended
|
||||
Attributes below for additional details on
|
||||
this option.
|
||||
|
||||
--directory DIRECTORY Optional template for specifying name of
|
||||
output directory in the form '{name,DEFAULT}'.
|
||||
See below for additional details on templating
|
||||
system.
|
||||
|
||||
--filename FILENAME Optional template for specifying name of
|
||||
output file in the form '{name,DEFAULT}'. File
|
||||
extension will be added automatically--do not
|
||||
include an extension in the FILENAME template.
|
||||
See below for additional details on templating
|
||||
system.
|
||||
|
||||
--jpeg-ext EXTENSION Specify file extension for JPEG files. Photos
|
||||
uses .jpeg for edited images but many images
|
||||
are imported with .jpg or .JPG which can
|
||||
@@ -519,12 +590,14 @@ Options:
|
||||
exported JPEG images. Valid values are jpeg,
|
||||
jpg, JPEG, JPG; e.g. '--jpeg-ext jpg' to use
|
||||
'.jpg' for all JPEGs.
|
||||
|
||||
--strip Optionally strip leading and trailing
|
||||
whitespace from any rendered templates. For
|
||||
example, if --filename template is "{title,}
|
||||
{original_name}" and image has no title,
|
||||
resulting file would have a leading space but
|
||||
if used with --strip, this will be removed.
|
||||
|
||||
--edited-suffix SUFFIX Optional suffix template for naming edited
|
||||
photos. Default name for edited photos is in
|
||||
form 'photoname_edited.ext'. For example, with
|
||||
@@ -534,6 +607,7 @@ Options:
|
||||
suffix is '_edited'. Multi-value templates
|
||||
(see Templating System) are not permitted with
|
||||
--edited-suffix.
|
||||
|
||||
--original-suffix SUFFIX Optional suffix template for naming original
|
||||
photos. Default name for original photos is
|
||||
in form 'filename.ext'. For example, with '--
|
||||
@@ -542,9 +616,11 @@ Options:
|
||||
default suffix is '' (no suffix). Multi-value
|
||||
templates (see Templating System) are not
|
||||
permitted with --original-suffix.
|
||||
|
||||
--use-photos-export Force the use of AppleScript or PhotoKit to
|
||||
export even if not missing (see also '--
|
||||
download-missing' and '--use-photokit').
|
||||
|
||||
--use-photokit Use with '--download-missing' or '--use-
|
||||
photos-export' to use direct Photos interface
|
||||
instead of AppleScript to export. Highly
|
||||
@@ -552,14 +628,23 @@ Options:
|
||||
iTerm2 (use with Terminal.app). This is faster
|
||||
and more reliable than the default AppleScript
|
||||
interface.
|
||||
|
||||
--report <path to export report>
|
||||
Write a CSV formatted report of all files that
|
||||
were exported.
|
||||
|
||||
--cleanup Cleanup export directory by deleting any files
|
||||
which were not included in this export set.
|
||||
For example, photos which had previously been
|
||||
exported and were subsequently deleted in
|
||||
Photos.
|
||||
Photos. WARNING: --cleanup will delete *any*
|
||||
files in the export directory that were not
|
||||
exported by osxphotos, for example, your own
|
||||
scripts or other files. Be sure this is what
|
||||
you intend before using --cleanup. Use --dry-
|
||||
run with --cleanup first if you're not
|
||||
certain.
|
||||
|
||||
--exportdb EXPORTDB_FILE Specify alternate name for database file which
|
||||
stores state information for export and
|
||||
--update. If --exportdb is not specified,
|
||||
@@ -568,6 +653,7 @@ Options:
|
||||
directory. Must be specified as filename
|
||||
only, not a path, as export database will be
|
||||
saved in export directory.
|
||||
|
||||
--load-config <config file path>
|
||||
Load options from file as written with --save-
|
||||
config. This allows you to save a complex
|
||||
@@ -579,9 +665,11 @@ Options:
|
||||
line options are used in conjunction with
|
||||
--load-config, they will override the
|
||||
corresponding values in the config file.
|
||||
|
||||
--save-config <config file path>
|
||||
Save options to file for use with --load-
|
||||
config. File format is TOML.
|
||||
|
||||
--help Show this message and exit.
|
||||
|
||||
** Export **
|
||||
@@ -636,25 +724,32 @@ The following attributes may be used with '--xattr-template':
|
||||
|
||||
authors The author, or authors, of the contents of the file. A list of
|
||||
strings. (com.apple.metadata:kMDItemAuthors)
|
||||
|
||||
comment A comment related to the file. This differs from the Finder
|
||||
comment, kMDItemFinderComment. A string.
|
||||
(com.apple.metadata:kMDItemComment)
|
||||
|
||||
copyright The copyright owner of the file contents. A string.
|
||||
(com.apple.metadata:kMDItemCopyright)
|
||||
|
||||
description A description of the content of the resource. The description
|
||||
may include an abstract, table of contents, reference to a
|
||||
graphical representation of content or a free-text account of
|
||||
the content. A string. (com.apple.metadata:kMDItemDescription)
|
||||
|
||||
findercomment Finder comments for this file. A string.
|
||||
(com.apple.metadata:kMDItemFinderComment)
|
||||
|
||||
headline A publishable entry providing a synopsis of the contents of the
|
||||
file. A string. (com.apple.metadata:kMDItemHeadline)
|
||||
|
||||
keywords Keywords associated with this file. For example, “Birthday”,
|
||||
“Important”, etc. This differs from Finder tags
|
||||
(_kMDItemUserTags) which are keywords/tags shown in the Finder
|
||||
and searchable in Spotlight using "tag:tag_name". A list of
|
||||
strings. (com.apple.metadata:kMDItemKeywords)
|
||||
|
||||
|
||||
For additional information on extended attributes see: https://developer.apple.c
|
||||
om/documentation/coreservices/file_metadata/mditem/common_metadata_attribute_key
|
||||
s
|
||||
@@ -820,6 +915,7 @@ Substitution Description
|
||||
{name} Current filename of the photo
|
||||
{original_name} Photo's original filename when imported to
|
||||
Photos
|
||||
|
||||
{title} Title of the photo
|
||||
{descr} Description of the photo
|
||||
{media_type} Special media type resolved in this
|
||||
@@ -829,30 +925,41 @@ Substitution Description
|
||||
'video' if no special type. Customize one or
|
||||
more media types using format: '{media_type,vi
|
||||
deo=vidéo;time_lapse=vidéo_accélérée}'
|
||||
|
||||
{photo_or_video} 'photo' or 'video' depending on what type the
|
||||
image is. To customize, use default value as
|
||||
in '{photo_or_video,photo=fotos;video=videos}'
|
||||
|
||||
{hdr} Photo is HDR?; True/False value, use in format
|
||||
'{hdr?VALUE_IF_TRUE,VALUE_IF_FALSE}'
|
||||
|
||||
{edited} Photo has been edited (has adjustments)?;
|
||||
True/False value, use in format
|
||||
'{edited?VALUE_IF_TRUE,VALUE_IF_FALSE}'
|
||||
|
||||
{created.date} Photo's creation date in ISO format, e.g.
|
||||
'2020-03-22'
|
||||
|
||||
{created.year} 4-digit year of photo creation time
|
||||
{created.yy} 2-digit year of photo creation time
|
||||
{created.mm} 2-digit month of the photo creation time (zero
|
||||
padded)
|
||||
|
||||
{created.month} Month name in user's locale of the photo
|
||||
creation time
|
||||
|
||||
{created.mon} Month abbreviation in the user's locale of the
|
||||
photo creation time
|
||||
|
||||
{created.dd} 2-digit day of the month (zero padded) of
|
||||
photo creation time
|
||||
|
||||
{created.dow} Day of week in user's locale of the photo
|
||||
creation time
|
||||
|
||||
{created.doy} 3-digit day of year (e.g Julian day) of photo
|
||||
creation time, starting from 1 (zero padded)
|
||||
|
||||
{created.hour} 2-digit hour of the photo creation time
|
||||
{created.min} 2-digit minute of the photo creation time
|
||||
{created.sec} 2-digit second of the photo creation time
|
||||
@@ -865,38 +972,51 @@ Substitution Description
|
||||
no template will return null value. See
|
||||
https://strftime.org/ for help on strftime
|
||||
templates.
|
||||
|
||||
{modified.date} Photo's modification date in ISO format, e.g.
|
||||
'2020-03-22'; uses creation date if photo is
|
||||
not modified
|
||||
|
||||
{modified.year} 4-digit year of photo modification time; uses
|
||||
creation date if photo is not modified
|
||||
|
||||
{modified.yy} 2-digit year of photo modification time; uses
|
||||
creation date if photo is not modified
|
||||
|
||||
{modified.mm} 2-digit month of the photo modification time
|
||||
(zero padded); uses creation date if photo is
|
||||
not modified
|
||||
|
||||
{modified.month} Month name in user's locale of the photo
|
||||
modification time; uses creation date if photo
|
||||
is not modified
|
||||
|
||||
{modified.mon} Month abbreviation in the user's locale of the
|
||||
photo modification time; uses creation date if
|
||||
photo is not modified
|
||||
|
||||
{modified.dd} 2-digit day of the month (zero padded) of the
|
||||
photo modification time; uses creation date if
|
||||
photo is not modified
|
||||
|
||||
{modified.dow} Day of week in user's locale of the photo
|
||||
modification time; uses creation date if photo
|
||||
is not modified
|
||||
|
||||
{modified.doy} 3-digit day of year (e.g Julian day) of photo
|
||||
modification time, starting from 1 (zero
|
||||
padded); uses creation date if photo is not
|
||||
modified
|
||||
|
||||
{modified.hour} 2-digit hour of the photo modification time;
|
||||
uses creation date if photo is not modified
|
||||
|
||||
{modified.min} 2-digit minute of the photo modification time;
|
||||
uses creation date if photo is not modified
|
||||
|
||||
{modified.sec} 2-digit second of the photo modification time;
|
||||
uses creation date if photo is not modified
|
||||
|
||||
{modified.strftime} Apply strftime template to file modification
|
||||
date/time. Should be used in form
|
||||
{modified.strftime,TEMPLATE} where TEMPLATE is
|
||||
@@ -907,21 +1027,28 @@ Substitution Description
|
||||
creation date if photo is not modified. See
|
||||
https://strftime.org/ for help on strftime
|
||||
templates.
|
||||
|
||||
{today.date} Current date in iso format, e.g. '2020-03-22'
|
||||
{today.year} 4-digit year of current date
|
||||
{today.yy} 2-digit year of current date
|
||||
{today.mm} 2-digit month of the current date (zero
|
||||
padded)
|
||||
|
||||
{today.month} Month name in user's locale of the current
|
||||
date
|
||||
|
||||
{today.mon} Month abbreviation in the user's locale of the
|
||||
current date
|
||||
|
||||
{today.dd} 2-digit day of the month (zero padded) of
|
||||
current date
|
||||
|
||||
{today.dow} Day of week in user's locale of the current
|
||||
date
|
||||
|
||||
{today.doy} 3-digit day of year (e.g Julian day) of
|
||||
current date, starting from 1 (zero padded)
|
||||
|
||||
{today.hour} 2-digit hour of the current date
|
||||
{today.min} 2-digit minute of the current date
|
||||
{today.sec} 2-digit second of the current date
|
||||
@@ -934,51 +1061,70 @@ Substitution Description
|
||||
no template will return null value. See
|
||||
https://strftime.org/ for help on strftime
|
||||
templates.
|
||||
|
||||
{place.name} Place name from the photo's reverse
|
||||
geolocation data, as displayed in Photos
|
||||
|
||||
{place.country_code} The ISO country code from the photo's reverse
|
||||
geolocation data
|
||||
|
||||
{place.name.country} Country name from the photo's reverse
|
||||
geolocation data
|
||||
|
||||
{place.name.state_province} State or province name from the photo's
|
||||
reverse geolocation data
|
||||
|
||||
{place.name.city} City or locality name from the photo's reverse
|
||||
geolocation data
|
||||
|
||||
{place.name.area_of_interest} Area of interest name (e.g. landmark or public
|
||||
place) from the photo's reverse geolocation
|
||||
data
|
||||
|
||||
{place.address} Postal address from the photo's reverse
|
||||
geolocation data, e.g. '2007 18th St NW,
|
||||
Washington, DC 20009, United States'
|
||||
|
||||
{place.address.street} Street part of the postal address, e.g. '2007
|
||||
18th St NW'
|
||||
|
||||
{place.address.city} City part of the postal address, e.g.
|
||||
'Washington'
|
||||
|
||||
{place.address.state_province} State/province part of the postal address,
|
||||
e.g. 'DC'
|
||||
|
||||
{place.address.postal_code} Postal code part of the postal address, e.g.
|
||||
'20009'
|
||||
|
||||
{place.address.country} Country name of the postal address, e.g.
|
||||
'United States'
|
||||
|
||||
{place.address.country_code} ISO country code of the postal address, e.g.
|
||||
'US'
|
||||
|
||||
{searchinfo.season} Season of the year associated with a photo,
|
||||
e.g. 'Summer'; (Photos 5+ only, applied
|
||||
automatically by Photos' image categorization
|
||||
algorithms).
|
||||
|
||||
{exif.camera_make} Camera make from original photo's EXIF
|
||||
information as imported by Photos, e.g.
|
||||
'Apple'
|
||||
|
||||
{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'
|
||||
|
||||
{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'
|
||||
|
||||
{comma} A comma: ','
|
||||
{semicolon} A semicolon: ';'
|
||||
{pipe} A vertical pipe: '|'
|
||||
@@ -1001,13 +1147,16 @@ Substitution Description
|
||||
{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
|
||||
{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)
|
||||
{comment} Comment(s) on shared Photos; format is 'Person name:
|
||||
comment text' (Photos 5+ only)
|
||||
|
||||
{exiftool} Format: '{exiftool:GROUP:TAGNAME}'; use exiftool
|
||||
(https://exiftool.org) to extract metadata, in form
|
||||
GROUP:TAGNAME, from image. E.g.
|
||||
@@ -1017,21 +1166,26 @@ Substitution Description
|
||||
names. You must specify group (e.g. EXIF, IPTC, etc)
|
||||
as used in `exiftool -G`. exiftool must be installed
|
||||
in the path to use this template.
|
||||
|
||||
{searchinfo.holiday} Holiday names associated with a photo, e.g.
|
||||
'Christmas Day'; (Photos 5+ only, applied
|
||||
automatically by Photos' image categorization
|
||||
algorithms).
|
||||
|
||||
{searchinfo.activity} Activities associated with a photo, e.g. 'Sporting
|
||||
Event'; (Photos 5+ only, applied automatically by
|
||||
Photos' image categorization algorithms).
|
||||
|
||||
{searchinfo.venue} Venues associated with a photo, e.g. name of
|
||||
restaurant; (Photos 5+ only, applied automatically by
|
||||
Photos' image categorization algorithms).
|
||||
|
||||
{searchinfo.venue_type} Venue types associated with a photo, e.g.
|
||||
'Restaurant'; (Photos 5+ only, applied automatically
|
||||
by Photos' image categorization algorithms).
|
||||
|
||||
|
||||
|
||||
```
|
||||
<!-- OSXPHOTOS-EXPORT-USAGE:END -->
|
||||
|
||||
@@ -2728,6 +2882,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="https://github.com/martinhrpi"><img src="https://avatars2.githubusercontent.com/u/19407684?v=4?s=75" width="75px;" alt=""/><br /><sub><b>Martin</b></sub></a><br /><a href="#research-martinhrpi" title="Research">🔬</a> <a href="#userTesting-martinhrpi" title="User Testing">📓</a></td>
|
||||
<td align="center"><a href="https://github.com/davidjroos"><img src="https://avatars.githubusercontent.com/u/15630844?v=4?s=75" width="75px;" alt=""/><br /><sub><b>davidjroos </b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/commits?author=davidjroos" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://neilpa.me"><img src="https://avatars.githubusercontent.com/u/42419?v=4?s=75" width="75px;" alt=""/><br /><sub><b>Neil Pankey</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/commits?author=neilpa" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://aaronweb.net/"><img src="https://avatars.githubusercontent.com/u/604665?v=4?s=75" width="75px;" alt=""/><br /><sub><b>Aaron van Geffen</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/commits?author=AaronVanGeffen" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: d0470550c1fa9feae481cebbbbc126af
|
||||
config: c43f566654ff6a66a64cd55da2e67fef
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Overview: module code — osxphotos 0.41.0 documentation</title>
|
||||
<title>Overview: module code — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||||
@@ -93,7 +93,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo._photoinfo_exifinfo — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos.photoinfo._photoinfo_exifinfo — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -183,7 +183,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo._photoinfo_export — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos.photoinfo._photoinfo_export — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -120,6 +120,8 @@
|
||||
<span class="n">exiftool_error</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">xattr_written</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">xattr_skipped</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">deleted_files</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">deleted_directories</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">exported</span> <span class="o">=</span> <span class="n">exported</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">new</span> <span class="o">=</span> <span class="n">new</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
@@ -140,6 +142,8 @@
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">exiftool_error</span> <span class="o">=</span> <span class="n">exiftool_error</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">xattr_written</span> <span class="o">=</span> <span class="n">xattr_written</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">xattr_skipped</span> <span class="o">=</span> <span class="n">xattr_skipped</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">deleted_files</span> <span class="o">=</span> <span class="n">deleted_files</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">deleted_directories</span> <span class="o">=</span> <span class="n">deleted_directories</span> <span class="ow">or</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">all_files</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return all filenames contained in results """</span>
|
||||
@@ -184,6 +188,8 @@
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">error</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">error</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">exiftool_warning</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">exiftool_warning</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">exiftool_error</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">exiftool_error</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">deleted_files</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">deleted_files</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">deleted_directories</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">deleted_directories</span>
|
||||
<span class="k">return</span> <span class="bp">self</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
@@ -206,6 +212,8 @@
|
||||
<span class="o">+</span> <span class="sa">f</span><span class="s2">",error=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">error</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="o">+</span> <span class="sa">f</span><span class="s2">",exiftool_warning=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">exiftool_warning</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="o">+</span> <span class="sa">f</span><span class="s2">",exiftool_error=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">exiftool_error</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="o">+</span> <span class="sa">f</span><span class="s2">",deleted_files=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">deleted_files</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="o">+</span> <span class="sa">f</span><span class="s2">",deleted_directories=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">deleted_directories</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="o">+</span> <span class="s2">")"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@@ -508,6 +516,9 @@
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">jpeg_ext</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">"""export photo, like export but with update and dry_run options</span>
|
||||
<span class="sd"> dest: must be valid destination path or exception raised</span>
|
||||
@@ -560,6 +571,9 @@
|
||||
<span class="sd"> merge_exif_keywords: boolean; if True, merged keywords found in file's exif data (requires exiftool)</span>
|
||||
<span class="sd"> merge_exif_persons: boolean; if True, merged persons found in file's exif data (requires exiftool)</span>
|
||||
<span class="sd"> jpeg_ext: if set, will use this value for extension on jpegs converted to jpeg with convert_to_jpeg; if not set, uses jpeg; do not include the leading "."</span>
|
||||
<span class="sd"> persons: if True, include persons in exported metadata</span>
|
||||
<span class="sd"> location: if True, include location in exported metadata</span>
|
||||
<span class="sd"> replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive</span>
|
||||
|
||||
<span class="sd"> Returns: ExportResults class </span>
|
||||
<span class="sd"> ExportResults has attributes: </span>
|
||||
@@ -640,9 +654,9 @@
|
||||
<span class="p">)</span>
|
||||
<span class="n">edited_name</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">)</span><span class="o">.</span><span class="n">name</span>
|
||||
<span class="n">edited_suffix</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">edited_name</span><span class="p">)</span><span class="o">.</span><span class="n">suffix</span>
|
||||
<span class="n">fname</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="n">edited_identifier</span> <span class="o">+</span> <span class="n">edited_suffix</span>
|
||||
<span class="n">fname</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span><span class="p">)</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="n">edited_identifier</span> <span class="o">+</span> <span class="n">edited_suffix</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">fname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span>
|
||||
<span class="n">fname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span>
|
||||
|
||||
<span class="n">uti</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span> <span class="k">if</span> <span class="n">edited</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_original</span>
|
||||
<span class="k">if</span> <span class="n">convert_to_jpeg</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span> <span class="ow">and</span> <span class="n">uti</span> <span class="o">!=</span> <span class="s2">"public.jpeg"</span><span class="p">:</span>
|
||||
@@ -974,6 +988,9 @@
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">sidecars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
|
||||
<span class="p">(</span>
|
||||
@@ -997,6 +1014,9 @@
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">sidecars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
|
||||
<span class="p">(</span>
|
||||
@@ -1016,6 +1036,9 @@
|
||||
<span class="n">keyword_template</span><span class="o">=</span><span class="n">keyword_template</span><span class="p">,</span>
|
||||
<span class="n">description_template</span><span class="o">=</span><span class="n">description_template</span><span class="p">,</span>
|
||||
<span class="n">extension</span><span class="o">=</span><span class="n">dest</span><span class="o">.</span><span class="n">suffix</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="k">if</span> <span class="n">dest</span><span class="o">.</span><span class="n">suffix</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">sidecars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
|
||||
<span class="p">(</span>
|
||||
@@ -1083,6 +1106,9 @@
|
||||
<span class="n">ignore_date_modified</span><span class="o">=</span><span class="n">ignore_date_modified</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">old_data</span> <span class="o">!=</span> <span class="n">current_data</span><span class="p">:</span>
|
||||
@@ -1103,6 +1129,9 @@
|
||||
<span class="n">flags</span><span class="o">=</span><span class="n">exiftool_flags</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">warning_</span><span class="p">:</span>
|
||||
<span class="n">all_results</span><span class="o">.</span><span class="n">exiftool_warning</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">exported_file</span><span class="p">,</span> <span class="n">warning_</span><span class="p">))</span>
|
||||
@@ -1120,6 +1149,9 @@
|
||||
<span class="n">ignore_date_modified</span><span class="o">=</span><span class="n">ignore_date_modified</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">export_db</span><span class="o">.</span><span class="n">set_stat_exif_for_file</span><span class="p">(</span>
|
||||
@@ -1142,6 +1174,9 @@
|
||||
<span class="n">flags</span><span class="o">=</span><span class="n">exiftool_flags</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">warning_</span><span class="p">:</span>
|
||||
<span class="n">all_results</span><span class="o">.</span><span class="n">exiftool_warning</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">exported_file</span><span class="p">,</span> <span class="n">warning_</span><span class="p">))</span>
|
||||
@@ -1159,6 +1194,9 @@
|
||||
<span class="n">ignore_date_modified</span><span class="o">=</span><span class="n">ignore_date_modified</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">export_db</span><span class="o">.</span><span class="n">set_stat_exif_for_file</span><span class="p">(</span>
|
||||
@@ -1378,6 +1416,9 @@
|
||||
<span class="n">flags</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">"""write exif data to image file at filepath</span>
|
||||
|
||||
@@ -1388,6 +1429,9 @@
|
||||
<span class="sd"> keyword_template: (list of strings); list of template strings to render as keywords</span>
|
||||
<span class="sd"> ignore_date_modified: if True, sets EXIF:ModifyDate to EXIF:DateTimeOriginal even if date_modified is set</span>
|
||||
<span class="sd"> flags: optional list of exiftool flags to prepend to exiftool command when writing metadata (e.g. -m or -F)</span>
|
||||
<span class="sd"> persons: if True, write person data to metadata</span>
|
||||
<span class="sd"> location: if True, write location data to metadata</span>
|
||||
<span class="sd"> replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> (warning, error) of warning and error strings if exiftool produces warnings or errors</span>
|
||||
@@ -1402,6 +1446,9 @@
|
||||
<span class="n">ignore_date_modified</span><span class="o">=</span><span class="n">ignore_date_modified</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">with</span> <span class="n">ExifTool</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="n">flags</span><span class="o">=</span><span class="n">flags</span><span class="p">,</span> <span class="n">exiftool</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_exiftool_path</span><span class="p">)</span> <span class="k">as</span> <span class="n">exiftool</span><span class="p">:</span>
|
||||
@@ -1424,6 +1471,9 @@
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">"""Return dict of EXIF details for building exiftool JSON sidecar or sending commands to ExifTool.</span>
|
||||
<span class="sd"> Does not include all the EXIF fields as those are likely already in the image.</span>
|
||||
@@ -1437,6 +1487,9 @@
|
||||
<span class="sd"> ignore_date_modified: if True, sets EXIF:ModifyDate to EXIF:DateTimeOriginal even if date_modified is set</span>
|
||||
<span class="sd"> merge_exif_keywords: merge keywords in the file's exif metadata (requires exiftool)</span>
|
||||
<span class="sd"> merge_exif_persons: merge persons in the file's exif metadata (requires exiftool)</span>
|
||||
<span class="sd"> persons: if True, include person data</span>
|
||||
<span class="sd"> location: if True, include location data</span>
|
||||
<span class="sd"> replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive</span>
|
||||
|
||||
<span class="sd"> Returns: dict with exiftool tags / values</span>
|
||||
|
||||
@@ -1444,8 +1497,10 @@
|
||||
<span class="sd"> EXIF:ImageDescription (may include template)</span>
|
||||
<span class="sd"> XMP:Description (may include template)</span>
|
||||
<span class="sd"> XMP:Title</span>
|
||||
<span class="sd"> IPTC:ObjectName</span>
|
||||
<span class="sd"> XMP:TagsList (may include album name, person name, or template)</span>
|
||||
<span class="sd"> IPTC:Keywords (may include album name, person name, or template)</span>
|
||||
<span class="sd"> IPTC:Caption-Abstract</span>
|
||||
<span class="sd"> XMP:Subject (set to keywords + persons)</span>
|
||||
<span class="sd"> XMP:PersonInImage</span>
|
||||
<span class="sd"> EXIF:GPSLatitudeRef, EXIF:GPSLongitudeRef</span>
|
||||
@@ -1461,6 +1516,9 @@
|
||||
<span class="sd"> QuickTime:ModifyDate (UTC)</span>
|
||||
<span class="sd"> QuickTime:GPSCoordinates</span>
|
||||
<span class="sd"> UserData:GPSCoordinates</span>
|
||||
|
||||
<span class="sd"> Reference: </span>
|
||||
<span class="sd"> https://iptc.org/std/photometadata/specification/IPTC-PhotoMetadata-201610_1.pdf</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">exif</span> <span class="o">=</span> <span class="p">(</span>
|
||||
@@ -1480,30 +1538,34 @@
|
||||
<span class="n">description</span> <span class="o">=</span> <span class="s2">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">rendered</span><span class="p">)</span> <span class="k">if</span> <span class="n">rendered</span> <span class="k">else</span> <span class="s2">""</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:ImageDescription"</span><span class="p">]</span> <span class="o">=</span> <span class="n">description</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"XMP:Description"</span><span class="p">]</span> <span class="o">=</span> <span class="n">description</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"IPTC:Caption-Abstract"</span><span class="p">]</span> <span class="o">=</span> <span class="n">description</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">description</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:ImageDescription"</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">description</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"XMP:Description"</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">description</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"IPTC:Caption-Abstract"</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">description</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"XMP:Title"</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"IPTC:ObjectName"</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
|
||||
|
||||
<span class="n">keyword_list</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="n">merge_exif_keywords</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_exif_keywords</span><span class="p">())</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">replace_keywords</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">)</span>
|
||||
|
||||
<span class="n">person_list</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="n">merge_exif_persons</span><span class="p">:</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_exif_persons</span><span class="p">())</span>
|
||||
<span class="k">if</span> <span class="n">persons</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">merge_exif_persons</span><span class="p">:</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_exif_persons</span><span class="p">())</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span><span class="p">:</span>
|
||||
<span class="c1"># filter out _UNKNOWN_PERSON</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span> <span class="k">if</span> <span class="n">p</span> <span class="o">!=</span> <span class="n">_UNKNOWN_PERSON</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span><span class="p">:</span>
|
||||
<span class="c1"># filter out _UNKNOWN_PERSON</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span> <span class="k">if</span> <span class="n">p</span> <span class="o">!=</span> <span class="n">_UNKNOWN_PERSON</span><span class="p">])</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">use_persons_as_keywords</span> <span class="ow">and</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">person_list</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">use_persons_as_keywords</span> <span class="ow">and</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">person_list</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">use_albums_as_keywords</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">albums</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">albums</span><span class="p">)</span>
|
||||
@@ -1547,25 +1609,26 @@
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"XMP:Subject"</span><span class="p">]</span> <span class="o">=</span> <span class="n">keyword_list</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"XMP:TagsList"</span><span class="p">]</span> <span class="o">=</span> <span class="n">keyword_list</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">persons</span> <span class="ow">and</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="n">person_list</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">person_list</span><span class="p">)))</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"XMP:PersonInImage"</span><span class="p">]</span> <span class="o">=</span> <span class="n">person_list</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># if self.favorite():</span>
|
||||
<span class="c1"># exif["Rating"] = 5</span>
|
||||
|
||||
<span class="p">(</span><span class="n">lat</span><span class="p">,</span> <span class="n">lon</span><span class="p">)</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span>
|
||||
<span class="k">if</span> <span class="n">lat</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">lon</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLatitude"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lat</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLongitude"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lon</span>
|
||||
<span class="n">lat_ref</span> <span class="o">=</span> <span class="s2">"N"</span> <span class="k">if</span> <span class="n">lat</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">"S"</span>
|
||||
<span class="n">lon_ref</span> <span class="o">=</span> <span class="s2">"E"</span> <span class="k">if</span> <span class="n">lon</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">"W"</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLatitudeRef"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lat_ref</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLongitudeRef"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lon_ref</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismovie</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"Keys:GPSCoordinates"</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">lat</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">lon</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"UserData:GPSCoordinates"</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">lat</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">lon</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="k">if</span> <span class="n">location</span><span class="p">:</span>
|
||||
<span class="p">(</span><span class="n">lat</span><span class="p">,</span> <span class="n">lon</span><span class="p">)</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span>
|
||||
<span class="k">if</span> <span class="n">lat</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">lon</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLatitude"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lat</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLongitude"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lon</span>
|
||||
<span class="n">lat_ref</span> <span class="o">=</span> <span class="s2">"N"</span> <span class="k">if</span> <span class="n">lat</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">"S"</span>
|
||||
<span class="n">lon_ref</span> <span class="o">=</span> <span class="s2">"E"</span> <span class="k">if</span> <span class="n">lon</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">"W"</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLatitudeRef"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lat_ref</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"EXIF:GPSLongitudeRef"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lon_ref</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismovie</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"Keys:GPSCoordinates"</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">lat</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">lon</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"UserData:GPSCoordinates"</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">lat</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">lon</span><span class="si">}</span><span class="s2">"</span>
|
||||
|
||||
<span class="c1"># process date/time and timezone offset</span>
|
||||
<span class="c1"># Photos exports the following fields and sets modify date to creation date</span>
|
||||
@@ -1624,6 +1687,13 @@
|
||||
<span class="n">exif</span><span class="p">[</span><span class="s2">"QuickTime:ModifyDate"</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime_tz_to_utc</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">date_modified</span>
|
||||
<span class="p">)</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y:%m:</span><span class="si">%d</span><span class="s2"> %H:%M:%S"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># remove any new lines in any fields</span>
|
||||
<span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">exif</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="nb">type</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="o">==</span> <span class="nb">list</span><span class="p">:</span>
|
||||
<span class="n">exif</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">v</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">val</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="n">exif</span>
|
||||
|
||||
|
||||
@@ -1673,6 +1743,9 @@
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">"""Return dict of EXIF details for building exiftool JSON sidecar or sending commands to ExifTool.</span>
|
||||
<span class="sd"> Does not include all the EXIF fields as those are likely already in the image.</span>
|
||||
@@ -1687,13 +1760,18 @@
|
||||
<span class="sd"> merge_exif_keywords: boolean; if True, merged keywords found in file's exif data (requires exiftool)</span>
|
||||
<span class="sd"> merge_exif_persons: boolean; if True, merged persons found in file's exif data (requires exiftool)</span>
|
||||
<span class="sd"> filename: filename of the destination image file for including in exiftool signature in JSON sidecar</span>
|
||||
<span class="sd"> persons: if True, include person data</span>
|
||||
<span class="sd"> location: if True, include location data</span>
|
||||
<span class="sd"> replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive</span>
|
||||
|
||||
<span class="sd"> Returns: dict with exiftool tags / values</span>
|
||||
|
||||
<span class="sd"> Exports the following:</span>
|
||||
<span class="sd"> EXIF:ImageDescription</span>
|
||||
<span class="sd"> XMP:Description (may include template)</span>
|
||||
<span class="sd"> IPTC:CaptionAbstract</span>
|
||||
<span class="sd"> XMP:Title</span>
|
||||
<span class="sd"> IPTC:ObjectName</span>
|
||||
<span class="sd"> XMP:TagsList</span>
|
||||
<span class="sd"> IPTC:Keywords (may include album name, person name, or template)</span>
|
||||
<span class="sd"> XMP:Subject (set to keywords + person)</span>
|
||||
@@ -1721,6 +1799,9 @@
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="n">merge_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="n">merge_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">persons</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="n">replace_keywords</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">tag_groups</span><span class="p">:</span>
|
||||
@@ -1743,6 +1824,9 @@
|
||||
<span class="n">extension</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">merge_exif_persons</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">persons</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="n">replace_keywords</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">"""returns string for XMP sidecar</span>
|
||||
<span class="sd"> use_albums_as_keywords: treat album names as keywords</span>
|
||||
@@ -1752,6 +1836,9 @@
|
||||
<span class="sd"> extension: which extension to use for SidecarForExtension property</span>
|
||||
<span class="sd"> merge_exif_keywords: boolean; if True, merged keywords found in file's exif data (requires exiftool)</span>
|
||||
<span class="sd"> merge_exif_persons: boolean; if True, merged persons found in file's exif data (requires exiftool)</span>
|
||||
<span class="sd"> persons: if True, include person data</span>
|
||||
<span class="sd"> location: if True, include location data</span>
|
||||
<span class="sd"> replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">xmp_template_file</span> <span class="o">=</span> <span class="p">(</span>
|
||||
@@ -1775,22 +1862,23 @@
|
||||
<span class="k">if</span> <span class="n">merge_exif_keywords</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_exif_keywords</span><span class="p">())</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">replace_keywords</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># TODO: keyword handling in this and _exiftool_json_sidecar is</span>
|
||||
<span class="c1"># good candidate for pulling out in a function</span>
|
||||
|
||||
<span class="n">person_list</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="n">merge_exif_persons</span><span class="p">:</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_exif_persons</span><span class="p">())</span>
|
||||
<span class="k">if</span> <span class="n">persons</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">merge_exif_persons</span><span class="p">:</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_exif_persons</span><span class="p">())</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span><span class="p">:</span>
|
||||
<span class="c1"># filter out _UNKNOWN_PERSON</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span> <span class="k">if</span> <span class="n">p</span> <span class="o">!=</span> <span class="n">_UNKNOWN_PERSON</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span><span class="p">:</span>
|
||||
<span class="c1"># filter out _UNKNOWN_PERSON</span>
|
||||
<span class="n">person_list</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span> <span class="k">if</span> <span class="n">p</span> <span class="o">!=</span> <span class="n">_UNKNOWN_PERSON</span><span class="p">])</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">use_persons_as_keywords</span> <span class="ow">and</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">person_list</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">use_persons_as_keywords</span> <span class="ow">and</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">person_list</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">use_albums_as_keywords</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">albums</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">albums</span><span class="p">)</span>
|
||||
@@ -1820,11 +1908,14 @@
|
||||
<span class="c1"># sorted mainly to make testing the XMP file easier</span>
|
||||
<span class="k">if</span> <span class="n">keyword_list</span><span class="p">:</span>
|
||||
<span class="n">keyword_list</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">keyword_list</span><span class="p">)))</span>
|
||||
<span class="k">if</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">persons</span> <span class="ow">and</span> <span class="n">person_list</span><span class="p">:</span>
|
||||
<span class="n">person_list</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">person_list</span><span class="p">)))</span>
|
||||
|
||||
<span class="n">subject_list</span> <span class="o">=</span> <span class="n">keyword_list</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">location</span><span class="p">:</span>
|
||||
<span class="n">latlon</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span>
|
||||
|
||||
<span class="n">xmp_str</span> <span class="o">=</span> <span class="n">xmp_template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span>
|
||||
<span class="n">photo</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span>
|
||||
<span class="n">description</span><span class="o">=</span><span class="n">description</span><span class="p">,</span>
|
||||
@@ -1832,6 +1923,7 @@
|
||||
<span class="n">persons</span><span class="o">=</span><span class="n">person_list</span><span class="p">,</span>
|
||||
<span class="n">subjects</span><span class="o">=</span><span class="n">subject_list</span><span class="p">,</span>
|
||||
<span class="n">extension</span><span class="o">=</span><span class="n">extension</span><span class="p">,</span>
|
||||
<span class="n">location</span><span class="o">=</span><span class="n">latlon</span><span class="p">,</span>
|
||||
<span class="n">version</span><span class="o">=</span><span class="n">__version__</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@@ -1912,7 +2004,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo._photoinfo_scoreinfo — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos.photoinfo._photoinfo_scoreinfo — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -208,7 +208,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo._photoinfo_searchinfo — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos.photoinfo._photoinfo_searchinfo — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -366,7 +366,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -60,6 +60,7 @@
|
||||
<span class="n">_PHOTOS_5_SHARED_PHOTO_PATH</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_VERSION</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">..adjustmentsinfo</span> <span class="kn">import</span> <span class="n">AdjustmentsInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..albuminfo</span> <span class="kn">import</span> <span class="n">AlbumInfo</span><span class="p">,</span> <span class="n">ImportInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..personinfo</span> <span class="kn">import</span> <span class="n">FaceInfo</span><span class="p">,</span> <span class="n">PersonInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..phototemplate</span> <span class="kn">import</span> <span class="n">PhotoTemplate</span>
|
||||
@@ -543,6 +544,30 @@
|
||||
<span class="sd">""" True if picture has adjustments / edits """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"hasAdjustments"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">adjustments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only """</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
<span class="n">library</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span>
|
||||
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
|
||||
<span class="n">plist_file</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">library</span><span class="p">)</span>
|
||||
<span class="o">/</span> <span class="s2">"resources"</span>
|
||||
<span class="o">/</span> <span class="s2">"renders"</span>
|
||||
<span class="o">/</span> <span class="n">directory</span>
|
||||
<span class="o">/</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">.plist"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">plist_file</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span> <span class="o">=</span> <span class="n">AdjustmentsInfo</span><span class="p">(</span><span class="n">plist_file</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">external_edit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if picture was edited outside of Photos using external editor """</span>
|
||||
@@ -856,8 +881,19 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">orientation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns EXIF orientation of the current photo version as int """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"orientation"</span><span class="p">]</span>
|
||||
<span class="sd">""" returns EXIF orientation of the current photo version as int or 0 if current orientation cannot be determined """</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"orientation"</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># For Photos 5+, try to get the adjusted orientation</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">adjustments</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">adjustments</span><span class="o">.</span><span class="n">adj_orientation</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># can't reliably determine orientation for edited photo if adjustmentinfo not available</span>
|
||||
<span class="k">return</span> <span class="mi">0</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"orientation"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">original_height</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
@@ -1185,7 +1221,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -2074,6 +2074,7 @@
|
||||
<span class="c1"># > 6 = portrait (sometimes, see ZDEPTHSTATE/ZDEPTHTYPE)</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"customRenderedValue"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"hdr"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span> <span class="k">else</span> <span class="kc">False</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"depth_state"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">36</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"portrait"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">36</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">False</span>
|
||||
|
||||
<span class="c1"># Set panorama from either KindSubType or RenderedValue</span>
|
||||
@@ -2951,7 +2952,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
7
docs/_static/doctools.js
vendored
@@ -29,9 +29,14 @@ if (!window.console || !console.firebug) {
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
return decodeURIComponent(x).replace(/\+/g, ' ');
|
||||
if (!x) {
|
||||
return x
|
||||
}
|
||||
return decodeURIComponent(x.replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
2
docs/_static/documentation_options.js
vendored
@@ -1,6 +1,6 @@
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
|
||||
VERSION: '0.41.0',
|
||||
VERSION: '0.41.4',
|
||||
LANGUAGE: 'None',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
4
docs/_static/language_data.js
vendored
@@ -13,7 +13,8 @@
|
||||
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
|
||||
|
||||
|
||||
/* Non-minified version JS is _stemmer.js if file is provided */
|
||||
/* Non-minified version is copied as a separate JS file, is available */
|
||||
|
||||
/**
|
||||
* Porter Stemmer
|
||||
*/
|
||||
@@ -199,7 +200,6 @@ var Stemmer = function() {
|
||||
|
||||
|
||||
|
||||
|
||||
var splitChars = (function() {
|
||||
var result = {};
|
||||
var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
|
||||
|
||||
6
docs/_static/pygments.css
vendored
@@ -1,7 +1,7 @@
|
||||
pre { line-height: 125%; }
|
||||
td.linenos pre { color: #000000; background-color: #f0f0f0; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos { color: #000000; background-color: #f0f0f0; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight { background: #f8f8f8; }
|
||||
|
||||
26
docs/_static/searchtools.js
vendored
@@ -248,7 +248,7 @@ var Search = {
|
||||
// results left, load the summary and display it
|
||||
if (results.length) {
|
||||
var item = results.pop();
|
||||
var listItem = $('<li style="display:none"></li>');
|
||||
var listItem = $('<li></li>');
|
||||
var requestUrl = "";
|
||||
var linkUrl = "";
|
||||
if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') {
|
||||
@@ -273,9 +273,9 @@ var Search = {
|
||||
if (item[3]) {
|
||||
listItem.append($('<span> (' + item[3] + ')</span>'));
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
setTimeout(function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}, 5);
|
||||
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
|
||||
$.ajax({url: requestUrl,
|
||||
dataType: "text",
|
||||
@@ -285,16 +285,16 @@ var Search = {
|
||||
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
|
||||
}
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
setTimeout(function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}, 5);
|
||||
}});
|
||||
} else {
|
||||
// no source available, just display title
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
setTimeout(function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}, 5);
|
||||
}
|
||||
}
|
||||
// search finished, update title and status message
|
||||
@@ -379,6 +379,13 @@ var Search = {
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
*/
|
||||
escapeRegExp : function(string) {
|
||||
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
},
|
||||
|
||||
/**
|
||||
* search for full-text terms in the index
|
||||
*/
|
||||
@@ -402,13 +409,14 @@ var Search = {
|
||||
];
|
||||
// add support for partial matches
|
||||
if (word.length > 2) {
|
||||
var word_regex = this.escapeRegExp(word);
|
||||
for (var w in terms) {
|
||||
if (w.match(word) && !terms[word]) {
|
||||
if (w.match(word_regex) && !terms[word]) {
|
||||
_o.push({files: terms[w], score: Scorer.partialTerm})
|
||||
}
|
||||
}
|
||||
for (var w in titleterms) {
|
||||
if (w.match(word) && !titleterms[word]) {
|
||||
if (w.match(word_regex) && !titleterms[word]) {
|
||||
_o.push({files: titleterms[w], score: Scorer.partialTitle})
|
||||
}
|
||||
}
|
||||
|
||||
2027
docs/_static/underscore-1.12.0.js
vendored
Normal file
37
docs/_static/underscore.js
vendored
452
docs/cli.html
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Index — osxphotos 0.41.0 documentation</title>
|
||||
<title>Index — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
@@ -327,6 +327,15 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-from-date">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-from-date">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--from-time <from_time>
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-from-time">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-from-time">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -776,6 +785,13 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-portrait">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-portrait">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--replace-keywords
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-replace-keywords">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -909,6 +925,15 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-to-date">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-to-date">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--to-time <to_time>
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-to-time">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-to-time">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -1017,6 +1042,8 @@
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.activities">activities() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.adjustments">adjustments() (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.album_info">album_info() (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
@@ -1032,10 +1059,10 @@
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_as_dict">albums_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_as_dict">albums_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared">albums_shared() (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared_as_dict">albums_shared_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
@@ -1461,6 +1488,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-folder">--folder <FOLDER></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-from-date">--from-date <from_date></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-from-time">--from-time <from_time></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-has-comment">--has-comment</a>
|
||||
</li>
|
||||
@@ -1553,6 +1582,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-place">--place <PLACE></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-portrait">--portrait</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-replace-keywords">--replace-keywords</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-report">--report <path to export report></a>
|
||||
</li>
|
||||
@@ -1587,6 +1618,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-title">--title <TITLE></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-to-date">--to-date <to_date></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-to-time">--to-time <to_time></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-touch-file">--touch-file</a>
|
||||
</li>
|
||||
@@ -1713,6 +1746,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-folder">--folder <FOLDER></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-from-date">--from-date <from_date></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-from-time">--from-time <from_time></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-has-comment">--has-comment</a>
|
||||
</li>
|
||||
@@ -1809,6 +1844,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-title">--title <TITLE></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-to-date">--to-date <to_date></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-to-time">--to-time <to_time></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-uti">--uti <UTI></a>
|
||||
</li>
|
||||
@@ -2108,7 +2145,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.41.0 documentation</title>
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
@@ -365,7 +365,7 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
|
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos — osxphotos 0.41.0 documentation</title>
|
||||
<title>osxphotos — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
@@ -91,7 +91,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
|
|
||||
|
||||
BIN
docs/objects.inv
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — osxphotos 0.41.0 documentation</title>
|
||||
<title>Search — osxphotos 0.41.4 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.4.3</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.41.0"
|
||||
__version__ = "0.41.4"
|
||||
|
||||
@@ -131,6 +131,21 @@ class DateTimeISO8601(click.ParamType):
|
||||
)
|
||||
|
||||
|
||||
class TimeISO8601(click.ParamType):
|
||||
|
||||
name = "TIME"
|
||||
|
||||
def convert(self, value, param, ctx):
|
||||
try:
|
||||
return datetime.time.fromisoformat(value).replace(tzinfo=None)
|
||||
except Exception:
|
||||
self.fail(
|
||||
f"Invalid value for --{param.name}: invalid time format {value}. "
|
||||
"Valid format: HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]] "
|
||||
"however, note that timezone will be ignored."
|
||||
)
|
||||
|
||||
|
||||
# Click CLI object & context settings
|
||||
class CLI_Obj:
|
||||
def __init__(self, db=None, json=False, debug=False):
|
||||
@@ -386,14 +401,24 @@ def query_options(f):
|
||||
),
|
||||
o(
|
||||
"--from-date",
|
||||
help="Search by start item date, e.g. 2000-01-12T12:00:00, 2001-01-12T12:00:00-07:00, or 2000-12-31 (ISO 8601).",
|
||||
help="Search by item start date, e.g. 2000-01-12T12:00:00, 2001-01-12T12:00:00-07:00, or 2000-12-31 (ISO 8601 with/without timezone).",
|
||||
type=DateTimeISO8601(),
|
||||
),
|
||||
o(
|
||||
"--to-date",
|
||||
help="Search by end item date, e.g. 2000-01-12T12:00:00, 2001-01-12T12:00:00-07:00, or 2000-12-31 (ISO 8601).",
|
||||
help="Search by item end date, e.g. 2000-01-12T12:00:00, 2001-01-12T12:00:00-07:00, or 2000-12-31 (ISO 8601 with/without timezone).",
|
||||
type=DateTimeISO8601(),
|
||||
),
|
||||
o(
|
||||
"--from-time",
|
||||
help="Search by item start time of day, e.g. 12:00, or 12:00:00.",
|
||||
type=TimeISO8601(),
|
||||
),
|
||||
o(
|
||||
"--to-time",
|
||||
help="Search by item end time of day, e.g. 12:00 or 12:00:00.",
|
||||
type=TimeISO8601(),
|
||||
),
|
||||
o("--has-comment", is_flag=True, help="Search for photos that have comments."),
|
||||
o("--no-comment", is_flag=True, help="Search for photos with no comments."),
|
||||
o("--has-likes", is_flag=True, help="Search for photos that have likes."),
|
||||
@@ -782,7 +807,10 @@ def cli(ctx, db, json_, debug):
|
||||
"--cleanup",
|
||||
is_flag=True,
|
||||
help="Cleanup export directory by deleting any files which were not included in this export set. "
|
||||
"For example, photos which had previously been exported and were subsequently deleted in Photos.",
|
||||
"For example, photos which had previously been exported and were subsequently deleted in Photos. "
|
||||
"WARNING: --cleanup will delete *any* files in the export directory that were not exported by osxphotos, "
|
||||
"for example, your own scripts or other files. Be sure this is what you intend before using "
|
||||
"--cleanup. Use --dry-run with --cleanup first if you're not certain.",
|
||||
)
|
||||
@click.option(
|
||||
"--exportdb",
|
||||
@@ -853,6 +881,8 @@ def export(
|
||||
not_shared,
|
||||
from_date,
|
||||
to_date,
|
||||
from_time,
|
||||
to_time,
|
||||
verbose,
|
||||
missing,
|
||||
update,
|
||||
@@ -1000,6 +1030,8 @@ def export(
|
||||
not_shared = cfg.not_shared
|
||||
from_date = cfg.from_date
|
||||
to_date = cfg.to_date
|
||||
from_time = cfg.from_time
|
||||
to_time = cfg.to_time
|
||||
verbose = cfg.verbose
|
||||
missing = cfg.missing
|
||||
update = cfg.update
|
||||
@@ -1347,6 +1379,8 @@ def export(
|
||||
not_incloud=False,
|
||||
from_date=from_date,
|
||||
to_date=to_date,
|
||||
from_time=from_time,
|
||||
to_time=to_time,
|
||||
portrait=portrait,
|
||||
not_portrait=not_portrait,
|
||||
screenshot=screenshot,
|
||||
@@ -1506,10 +1540,14 @@ def export(
|
||||
+ [str(pathlib.Path(export_db_path).resolve())]
|
||||
)
|
||||
click.echo(f"Cleaning up {dest}")
|
||||
(cleaned_files, cleaned_dirs) = cleanup_files(dest, all_files, fileutil)
|
||||
file_str = "files" if cleaned_files != 1 else "file"
|
||||
dir_str = "directories" if cleaned_dirs != 1 else "directory"
|
||||
click.echo(f"Deleted: {cleaned_files} {file_str}, {cleaned_dirs} {dir_str}")
|
||||
cleaned_files, cleaned_dirs = cleanup_files(dest, all_files, fileutil)
|
||||
file_str = "files" if len(cleaned_files) != 1 else "file"
|
||||
dir_str = "directories" if len(cleaned_dirs) != 1 else "directory"
|
||||
click.echo(
|
||||
f"Deleted: {len(cleaned_files)} {file_str}, {len(cleaned_dirs)} {dir_str}"
|
||||
)
|
||||
results.deleted_files = cleaned_files
|
||||
results.deleted_directories = cleaned_dirs
|
||||
|
||||
if report:
|
||||
verbose_(f"Writing export report to {report}")
|
||||
@@ -1631,6 +1669,8 @@ def query(
|
||||
not_incloud,
|
||||
from_date,
|
||||
to_date,
|
||||
from_time,
|
||||
to_time,
|
||||
portrait,
|
||||
not_portrait,
|
||||
screenshot,
|
||||
@@ -1679,6 +1719,8 @@ def query(
|
||||
has_raw,
|
||||
from_date,
|
||||
to_date,
|
||||
from_time,
|
||||
to_time,
|
||||
label,
|
||||
is_reference,
|
||||
]
|
||||
@@ -1773,6 +1815,8 @@ def query(
|
||||
not_incloud=not_incloud,
|
||||
from_date=from_date,
|
||||
to_date=to_date,
|
||||
from_time=from_time,
|
||||
to_time=to_time,
|
||||
portrait=portrait,
|
||||
not_portrait=not_portrait,
|
||||
screenshot=screenshot,
|
||||
@@ -1946,6 +1990,8 @@ def _query(
|
||||
not_incloud=None,
|
||||
from_date=None,
|
||||
to_date=None,
|
||||
from_time=None,
|
||||
to_time=None,
|
||||
portrait=None,
|
||||
not_portrait=None,
|
||||
screenshot=None,
|
||||
@@ -2210,6 +2256,12 @@ def _query(
|
||||
elif not_in_album:
|
||||
photos = [p for p in photos if not p.albums]
|
||||
|
||||
if from_time:
|
||||
photos = [p for p in photos if p.date.time() >= from_time]
|
||||
|
||||
if to_time:
|
||||
photos = [p for p in photos if p.date.time() <= to_time]
|
||||
|
||||
return photos
|
||||
|
||||
|
||||
@@ -2893,8 +2945,12 @@ def write_export_report(report_file, results):
|
||||
"exiftool_error": "",
|
||||
"extended_attributes_written": 0,
|
||||
"extended_attributes_skipped": 0,
|
||||
"cleanup_deleted_file": 0,
|
||||
"cleanup_deleted_directory": 0,
|
||||
}
|
||||
for result in results.all_files()
|
||||
+ results.deleted_files
|
||||
+ results.deleted_directories
|
||||
}
|
||||
|
||||
for result in results.exported:
|
||||
@@ -2960,6 +3016,12 @@ def write_export_report(report_file, results):
|
||||
for result in results.xattr_skipped:
|
||||
all_results[result]["extended_attributes_skipped"] = 1
|
||||
|
||||
for result in results.deleted_files:
|
||||
all_results[result]["cleanup_deleted_file"] = 1
|
||||
|
||||
for result in results.deleted_directories:
|
||||
all_results[result]["cleanup_deleted_directory"] = 1
|
||||
|
||||
report_columns = [
|
||||
"filename",
|
||||
"exported",
|
||||
@@ -2978,6 +3040,8 @@ def write_export_report(report_file, results):
|
||||
"exiftool_error",
|
||||
"extended_attributes_written",
|
||||
"extended_attributes_skipped",
|
||||
"cleanup_deleted_file",
|
||||
"cleanup_deleted_directory",
|
||||
]
|
||||
|
||||
try:
|
||||
@@ -3004,27 +3068,27 @@ def cleanup_files(dest_path, files_to_keep, fileutil):
|
||||
fileutile: FileUtil object
|
||||
|
||||
Returns:
|
||||
tuple of (number of files deleted, number of directories deleted)
|
||||
tuple of (list of files deleted, list of directories deleted)
|
||||
"""
|
||||
keepers = {filename.lower(): 1 for filename in files_to_keep}
|
||||
keepers = {str(filename).lower(): 1 for filename in files_to_keep}
|
||||
|
||||
deleted_files = 0
|
||||
deleted_files = []
|
||||
for p in pathlib.Path(dest_path).rglob("*"):
|
||||
path = str(p).lower()
|
||||
if p.is_file() and path not in keepers:
|
||||
verbose_(f"Deleting {p}")
|
||||
fileutil.unlink(p)
|
||||
deleted_files += 1
|
||||
deleted_files.append(str(p))
|
||||
|
||||
# delete empty directories
|
||||
deleted_dirs = 0
|
||||
deleted_dirs = []
|
||||
for p in pathlib.Path(dest_path).rglob("*"):
|
||||
path = str(p).lower()
|
||||
# if directory and directory is empty
|
||||
if p.is_dir() and not next(p.iterdir(), False):
|
||||
verbose_(f"Deleting empty directory {p}")
|
||||
fileutil.rmdir(p)
|
||||
deleted_dirs += 1
|
||||
deleted_dirs.append(str(p))
|
||||
|
||||
return (deleted_files, deleted_dirs)
|
||||
|
||||
|
||||
@@ -176,6 +176,10 @@ class ExifTool:
|
||||
command = [f"-{tag}={value}"]
|
||||
if self.overwrite and not self._context_mgr:
|
||||
command.append("-overwrite_original")
|
||||
|
||||
# avoid "Warning: Some character(s) could not be encoded in Latin" warning
|
||||
command.append("-iptc:codedcharacterset=utf8")
|
||||
|
||||
if self._context_mgr:
|
||||
self._commands.extend(command)
|
||||
return True
|
||||
|
||||
@@ -87,6 +87,8 @@ class ExportResults:
|
||||
exiftool_error=None,
|
||||
xattr_written=None,
|
||||
xattr_skipped=None,
|
||||
deleted_files=None,
|
||||
deleted_directories=None,
|
||||
):
|
||||
self.exported = exported or []
|
||||
self.new = new or []
|
||||
@@ -107,6 +109,8 @@ class ExportResults:
|
||||
self.exiftool_error = exiftool_error or []
|
||||
self.xattr_written = xattr_written or []
|
||||
self.xattr_skipped = xattr_skipped or []
|
||||
self.deleted_files = deleted_files or []
|
||||
self.deleted_directories = deleted_directories or []
|
||||
|
||||
def all_files(self):
|
||||
""" return all filenames contained in results """
|
||||
@@ -151,6 +155,8 @@ class ExportResults:
|
||||
self.error += other.error
|
||||
self.exiftool_warning += other.exiftool_warning
|
||||
self.exiftool_error += other.exiftool_error
|
||||
self.deleted_files += other.deleted_files
|
||||
self.deleted_directories += other.deleted_directories
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
@@ -173,6 +179,8 @@ class ExportResults:
|
||||
+ f",error={self.error}"
|
||||
+ f",exiftool_warning={self.exiftool_warning}"
|
||||
+ f",exiftool_error={self.exiftool_error}"
|
||||
+ f",deleted_files={self.deleted_files}"
|
||||
+ f",deleted_directories={self.deleted_directories}"
|
||||
+ ")"
|
||||
)
|
||||
|
||||
@@ -613,9 +621,9 @@ def export2(
|
||||
)
|
||||
edited_name = pathlib.Path(self.path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
fname = pathlib.Path(self.filename).stem + edited_identifier + edited_suffix
|
||||
fname = pathlib.Path(self.original_filename).stem + edited_identifier + edited_suffix
|
||||
else:
|
||||
fname = self.filename
|
||||
fname = self.original_filename
|
||||
|
||||
uti = self.uti if edited else self.uti_original
|
||||
if convert_to_jpeg and self.isphoto and uti != "public.jpeg":
|
||||
@@ -949,7 +957,7 @@ def export2(
|
||||
filename=dest.name,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
)
|
||||
sidecars.append(
|
||||
(
|
||||
@@ -975,7 +983,7 @@ def export2(
|
||||
filename=dest.name,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
)
|
||||
sidecars.append(
|
||||
(
|
||||
@@ -997,7 +1005,7 @@ def export2(
|
||||
extension=dest.suffix[1:] if dest.suffix else None,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
)
|
||||
sidecars.append(
|
||||
(
|
||||
@@ -1067,7 +1075,7 @@ def export2(
|
||||
merge_exif_persons=merge_exif_persons,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
)
|
||||
)[0]
|
||||
if old_data != current_data:
|
||||
@@ -1090,7 +1098,7 @@ def export2(
|
||||
merge_exif_persons=merge_exif_persons,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
)
|
||||
if warning_:
|
||||
all_results.exiftool_warning.append((exported_file, warning_))
|
||||
@@ -1110,7 +1118,7 @@ def export2(
|
||||
merge_exif_persons=merge_exif_persons,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
),
|
||||
)
|
||||
export_db.set_stat_exif_for_file(
|
||||
@@ -1135,7 +1143,7 @@ def export2(
|
||||
merge_exif_persons=merge_exif_persons,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
)
|
||||
if warning_:
|
||||
all_results.exiftool_warning.append((exported_file, warning_))
|
||||
@@ -1155,7 +1163,7 @@ def export2(
|
||||
merge_exif_persons=merge_exif_persons,
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords
|
||||
replace_keywords=replace_keywords,
|
||||
),
|
||||
)
|
||||
export_db.set_stat_exif_for_file(
|
||||
@@ -1646,6 +1654,13 @@ def _exiftool_dict(
|
||||
exif["QuickTime:ModifyDate"] = datetime_tz_to_utc(
|
||||
self.date_modified
|
||||
).strftime("%Y:%m:%d %H:%M:%S")
|
||||
|
||||
# remove any new lines in any fields
|
||||
for field, val in exif.items():
|
||||
if type(val) == str:
|
||||
exif[field] = val.replace("\n", " ")
|
||||
elif type(val) == list:
|
||||
exif[field] = [v.replace("\n", " ") for v in val]
|
||||
return exif
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ pathvalidate==2.2.1
|
||||
pexpect==4.8.0
|
||||
photoscript==0.1.0
|
||||
pickleshare==0.7.5
|
||||
Pillow==7.2.0
|
||||
Pillow==8.1.1
|
||||
pkginfo==1.5.0.1
|
||||
pluggy==0.12.0
|
||||
prompt-toolkit==3.0.4
|
||||
|
||||
|
Before Width: | Height: | Size: 528 KiB After Width: | Height: | Size: 528 KiB |
@@ -7,7 +7,7 @@
|
||||
<key>hostuuid</key>
|
||||
<string>9575E48B-8D5F-5654-ABAC-4431B1167324</string>
|
||||
<key>pid</key>
|
||||
<integer>55247</integer>
|
||||
<integer>86501</integer>
|
||||
<key>processname</key>
|
||||
<string>photolibraryd</string>
|
||||
<key>uid</key>
|
||||
|
||||
|
Before Width: | Height: | Size: 577 KiB After Width: | Height: | Size: 577 KiB |
|
After Width: | Height: | Size: 2.6 MiB |
@@ -3,24 +3,24 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BackgroundHighlightCollection</key>
|
||||
<date>2020-12-16T05:41:43Z</date>
|
||||
<date>2021-03-13T16:38:25Z</date>
|
||||
<key>BackgroundHighlightEnrichment</key>
|
||||
<date>2020-12-16T05:41:42Z</date>
|
||||
<date>2021-03-13T16:38:24Z</date>
|
||||
<key>BackgroundJobAssetRevGeocode</key>
|
||||
<date>2020-12-16T05:41:43Z</date>
|
||||
<date>2021-03-13T16:38:25Z</date>
|
||||
<key>BackgroundJobSearch</key>
|
||||
<date>2020-12-16T05:41:43Z</date>
|
||||
<date>2021-03-13T16:38:25Z</date>
|
||||
<key>BackgroundPeopleSuggestion</key>
|
||||
<date>2020-12-16T05:41:41Z</date>
|
||||
<date>2021-03-13T16:38:23Z</date>
|
||||
<key>BackgroundUserBehaviorProcessor</key>
|
||||
<date>2020-12-16T05:41:43Z</date>
|
||||
<date>2021-03-13T16:38:25Z</date>
|
||||
<key>PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey</key>
|
||||
<date>2020-10-17T23:45:33Z</date>
|
||||
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
|
||||
<date>2020-10-17T23:45:24Z</date>
|
||||
<key>PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate</key>
|
||||
<date>2020-12-16T05:41:44Z</date>
|
||||
<date>2021-03-13T16:38:25Z</date>
|
||||
<key>SiriPortraitDonation</key>
|
||||
<date>2020-12-16T05:41:43Z</date>
|
||||
<date>2021-03-13T16:38:25Z</date>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 46 KiB |
@@ -731,7 +731,7 @@ def test_export_1():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -776,7 +776,7 @@ def test_export_3():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -829,7 +829,7 @@ def test_export_5():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -994,7 +994,7 @@ def test_export_12():
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -618,7 +618,7 @@ def test_export_1(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -657,7 +657,7 @@ def test_export_3(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -704,7 +704,7 @@ def test_export_5(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -848,7 +848,7 @@ def test_export_12(photosdb):
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -418,7 +418,7 @@ def test_export_1():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -463,7 +463,7 @@ def test_export_3():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -516,7 +516,7 @@ def test_export_5():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -681,7 +681,7 @@ def test_export_12():
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -426,7 +426,7 @@ def test_export_1():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -471,7 +471,7 @@ def test_export_3():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -524,7 +524,7 @@ def test_export_5():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -689,7 +689,7 @@ def test_export_12():
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -640,7 +640,7 @@ def test_export_1():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -685,7 +685,7 @@ def test_export_3():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -738,7 +738,7 @@ def test_export_5():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -903,7 +903,7 @@ def test_export_12():
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -635,7 +635,7 @@ def test_export_1(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -666,7 +666,7 @@ def test_export_3(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -705,7 +705,7 @@ def test_export_5(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -823,7 +823,7 @@ def test_export_12(photosdb):
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -23,10 +23,10 @@ PHOTOS_DB = "tests/Test-10.15.7.photoslibrary/database/photos.db"
|
||||
PHOTOS_DB_PATH = "/Test-10.15.7.photoslibrary/database/photos.db"
|
||||
PHOTOS_LIBRARY_PATH = "/Test-10.15.7.photoslibrary"
|
||||
|
||||
PHOTOS_DB_LEN = 19
|
||||
PHOTOS_NOT_IN_TRASH_LEN = 17
|
||||
PHOTOS_DB_LEN = 20
|
||||
PHOTOS_NOT_IN_TRASH_LEN = 18
|
||||
PHOTOS_IN_TRASH_LEN = 2
|
||||
PHOTOS_DB_IMPORT_SESSIONS = 14
|
||||
PHOTOS_DB_IMPORT_SESSIONS = 15
|
||||
|
||||
KEYWORDS = [
|
||||
"Kids",
|
||||
@@ -41,6 +41,10 @@ KEYWORDS = [
|
||||
"foo/bar",
|
||||
"Travel",
|
||||
"Maria",
|
||||
"Drink",
|
||||
"Val d'Isère",
|
||||
"Wine",
|
||||
"Wine Bottle",
|
||||
]
|
||||
# Photos 5 includes blank person for detected face
|
||||
PERSONS = ["Katie", "Suzy", "Maria", _UNKNOWN_PERSON]
|
||||
@@ -67,6 +71,10 @@ KEYWORDS_DICT = {
|
||||
"foo/bar": 1,
|
||||
"Travel": 2,
|
||||
"Maria": 1,
|
||||
"Drink": 1,
|
||||
"Val d'Isère": 1,
|
||||
"Wine": 1,
|
||||
"Wine Bottle": 1,
|
||||
}
|
||||
PERSONS_DICT = {"Katie": 3, "Suzy": 2, "Maria": 2, _UNKNOWN_PERSON: 1}
|
||||
ALBUM_DICT = {
|
||||
@@ -102,6 +110,7 @@ UUID_DICT = {
|
||||
"intrash_person_keywords": "6FD38366-3BF2-407D-81FE-7153EB6125B6",
|
||||
"import_session": "8846E3E6-8AC8-4857-8448-E3D025784410",
|
||||
"movie": "D1359D09-1373-4F3B-B0E3-1A4DE573E4A3",
|
||||
"description_newlines": "7F74DD34-5920-4DA3-B284-479887A34F66",
|
||||
}
|
||||
|
||||
UUID_DICT_LOCAL = {
|
||||
@@ -693,7 +702,7 @@ def test_export_1(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -724,7 +733,7 @@ def test_export_3(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -763,7 +772,7 @@ def test_export_5(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -881,7 +890,7 @@ def test_export_12(photosdb):
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
@@ -1010,7 +1019,7 @@ def test_from_to_date(photosdb):
|
||||
time.tzset()
|
||||
|
||||
photos = photosdb.photos(from_date=datetime.datetime(2018, 10, 28))
|
||||
assert len(photos) == 10
|
||||
assert len(photos) == 11
|
||||
|
||||
photos = photosdb.photos(to_date=datetime.datetime(2018, 10, 28))
|
||||
assert len(photos) == 7
|
||||
@@ -1265,4 +1274,13 @@ def test_no_adjustments(photosdb):
|
||||
""" test adjustments when photo has no adjusments"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["no_adjustments"])
|
||||
assert photo.adjustments is None
|
||||
assert photo.adjustments is None
|
||||
|
||||
|
||||
def test_exiftool_newlines_in_description(photosdb):
|
||||
""" Test that exiftool code removes newlines embedded in description, issue #393"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["description_newlines"])
|
||||
exif = photo._exiftool_dict()
|
||||
assert photo.description.find("\n") > 0
|
||||
assert exif["EXIF:ImageDescription"].find("\n") == -1
|
||||
|
||||
@@ -611,6 +611,7 @@ UUID_NOT_IN_ALBUM = [
|
||||
"6191423D-8DB8-4D4C-92BE-9BBBA308AAC4",
|
||||
"35329C57-B963-48D6-BB75-6AFF9370CBBC",
|
||||
"8846E3E6-8AC8-4857-8448-E3D025784410",
|
||||
"7F74DD34-5920-4DA3-B284-479887A34F66",
|
||||
]
|
||||
|
||||
|
||||
@@ -1845,6 +1846,36 @@ def test_query_date_timezone():
|
||||
assert len(json_got) == 4
|
||||
|
||||
|
||||
def test_query_time():
|
||||
""" Test --from-time, --to-time"""
|
||||
import json
|
||||
import osxphotos
|
||||
import os
|
||||
import os.path
|
||||
import time
|
||||
from osxphotos.cli import query
|
||||
|
||||
os.environ["TZ"] = "US/Pacific"
|
||||
time.tzset()
|
||||
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
result = runner.invoke(
|
||||
query,
|
||||
[
|
||||
"--json",
|
||||
"--db",
|
||||
os.path.join(cwd, CLI_PHOTOS_DB),
|
||||
"--from-time=16:00",
|
||||
"--to-time=17:00",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
|
||||
json_got = json.loads(result.output)
|
||||
assert len(json_got) == 3
|
||||
|
||||
|
||||
def test_query_keyword_1():
|
||||
"""Test query --keyword """
|
||||
import json
|
||||
|
||||
@@ -95,7 +95,7 @@ def test_export_1(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
@@ -134,7 +134,7 @@ def test_export_3(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
filename2 = pathlib.Path(filename)
|
||||
filename2 = f"{filename2.stem} (1){filename2.suffix}"
|
||||
expected_dest_2 = os.path.join(dest, filename2)
|
||||
@@ -181,7 +181,7 @@ def test_export_5(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["export"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
@@ -326,7 +326,7 @@ def test_export_12(photosdb):
|
||||
|
||||
edited_name = pathlib.Path(photos[0].path_edited).name
|
||||
edited_suffix = pathlib.Path(edited_name).suffix
|
||||
filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
|
||||
filename = pathlib.Path(photos[0].original_filename).stem + "_edited" + edited_suffix
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
|
||||
@@ -29,7 +29,7 @@ def test_export_default_name(photosdb):
|
||||
# test basic export
|
||||
# get an unedited image and export it using default filename
|
||||
import os
|
||||
import os.path
|
||||
import pathlib
|
||||
import tempfile
|
||||
|
||||
import osxphotos
|
||||
@@ -38,11 +38,12 @@ def test_export_default_name(photosdb):
|
||||
dest = tempdir.name
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = pathlib.Path(dest) / filename
|
||||
expected_dest = expected_dest.parent / f"{expected_dest.stem}.jpeg"
|
||||
got_dest = photos[0].export(dest, use_photos_export=True)[0]
|
||||
|
||||
assert got_dest == expected_dest
|
||||
assert got_dest == str(expected_dest)
|
||||
assert os.path.isfile(got_dest)
|
||||
|
||||
|
||||
@@ -82,7 +83,7 @@ def test_export_edited(photosdb):
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||
|
||||
suffix = pathlib.Path(photos[0].path_edited).suffix
|
||||
filename = f"{pathlib.Path(photos[0].filename).stem}_edited{suffix}"
|
||||
filename = f"{pathlib.Path(photos[0].original_filename).stem}_edited{suffix}"
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest, use_photos_export=True, edited=True)[0]
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ UUID_DICT = {
|
||||
}
|
||||
|
||||
NAMES_DICT = {
|
||||
"raw": "D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068.jpeg",
|
||||
"heic": "7783E8E6-9CAC-40F3-BE22-81FB7051C266.jpeg",
|
||||
"raw": "DSC03584.jpeg",
|
||||
"heic": "IMG_3092.jpeg"
|
||||
}
|
||||
|
||||
UUID_LIVE_HEIC = "612CE30B-3D8F-417A-9B14-EC42CBA10ACC"
|
||||
NAMES_LIVE_HEIC = [
|
||||
"612CE30B-3D8F-417A-9B14-EC42CBA10ACC.jpeg",
|
||||
"612CE30B-3D8F-417A-9B14-EC42CBA10ACC.mov",
|
||||
"IMG_3259.jpeg",
|
||||
"IMG_3259.mov"
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -29,13 +29,13 @@ def test_export_1():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest, filename)
|
||||
got_dest = photos[0].export(dest)[0]
|
||||
|
||||
assert got_dest == expected_dest
|
||||
assert os.path.isfile(got_dest)
|
||||
assert pathlib.Path(got_dest).name == FILENAME_DICT["current"]
|
||||
assert pathlib.Path(got_dest).name == FILENAME_DICT["original"]
|
||||
|
||||
|
||||
def test_export_2():
|
||||
@@ -101,7 +101,7 @@ def test_export_edited_default():
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||
|
||||
got_dest = photos[0].export(dest, edited=True)[0]
|
||||
assert pathlib.Path(got_dest).name == FILENAME_DICT["current_edited"]
|
||||
assert pathlib.Path(got_dest).name == FILENAME_DICT["original_edited"]
|
||||
|
||||
|
||||
def test_export_edited_wrong_suffix():
|
||||
|
||||
@@ -21,6 +21,8 @@ EXPORT_RESULT_ATTRIBUTES = [
|
||||
"error",
|
||||
"exiftool_warning",
|
||||
"exiftool_error",
|
||||
"deleted_files",
|
||||
"deleted_directories",
|
||||
]
|
||||
|
||||
|
||||
@@ -43,6 +45,8 @@ def test_exportresults_init():
|
||||
assert results.error == []
|
||||
assert results.exiftool_warning == []
|
||||
assert results.exiftool_error == []
|
||||
assert results.deleted_files == []
|
||||
assert results.deleted_directories == []
|
||||
|
||||
|
||||
def test_exportresults_iadd():
|
||||
@@ -64,6 +68,12 @@ def test_exportresults_iadd():
|
||||
results1.exiftool_error = [("exiftool_error1", "foo")]
|
||||
results2.exiftool_error = [("exiftool_error2", "bar")]
|
||||
|
||||
results1.deleted_files = [("foo1")]
|
||||
results2.deleted_files = [("foo2")]
|
||||
|
||||
results1.deleted_directories = [("bar1")]
|
||||
results2.deleted_directories = [("bar2")]
|
||||
|
||||
results1 += results2
|
||||
|
||||
assert results1.exiftool_warning == [
|
||||
@@ -75,6 +85,9 @@ def test_exportresults_iadd():
|
||||
("exiftool_error2", "bar"),
|
||||
]
|
||||
|
||||
assert results1.deleted_files == ["foo1", "foo2"]
|
||||
assert results1.deleted_directories == ["bar1", "bar2"]
|
||||
|
||||
|
||||
def test_all_files():
|
||||
""" test ExportResults.all_files() """
|
||||
@@ -84,10 +97,12 @@ def test_all_files():
|
||||
results.exiftool_warning = [("exiftool_warning1", "foo")]
|
||||
results.exiftool_error = [("exiftool_error1", "foo")]
|
||||
results.error = [("error1", "foo")]
|
||||
results.deleted_files = ["deleted_files1"]
|
||||
results.deleted_directories = ["deleted_directories1"]
|
||||
|
||||
assert sorted(results.all_files()) == sorted(
|
||||
[f"{x}1" for x in EXPORT_RESULT_ATTRIBUTES]
|
||||
)
|
||||
assert sorted(
|
||||
results.all_files() + results.deleted_files + results.deleted_directories
|
||||
) == sorted([f"{x}1" for x in EXPORT_RESULT_ATTRIBUTES])
|
||||
|
||||
|
||||
def test_str():
|
||||
@@ -95,6 +110,6 @@ def test_str():
|
||||
results = ExportResults()
|
||||
assert (
|
||||
str(results)
|
||||
== "ExportResults(exported=[],new=[],updated=[],skipped=[],exif_updated=[],touched=[],converted_to_jpeg=[],sidecar_json_written=[],sidecar_json_skipped=[],sidecar_exiftool_written=[],sidecar_exiftool_skipped=[],sidecar_xmp_written=[],sidecar_xmp_skipped=[],missing=[],error=[],exiftool_warning=[],exiftool_error=[])"
|
||||
== "ExportResults(exported=[],new=[],updated=[],skipped=[],exif_updated=[],touched=[],converted_to_jpeg=[],sidecar_json_written=[],sidecar_json_skipped=[],sidecar_exiftool_written=[],sidecar_exiftool_skipped=[],sidecar_xmp_written=[],sidecar_xmp_skipped=[],missing=[],error=[],exiftool_warning=[],exiftool_error=[],deleted_files=[],deleted_directories=[])"
|
||||
)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ def test_export_live_1():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["live"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest.name, filename)
|
||||
got_dest = photos[0].export(dest.name, live_photo=True)[0]
|
||||
got_movie = f"{pathlib.Path(got_dest).parent / pathlib.Path(got_dest).stem}.mov"
|
||||
@@ -70,7 +70,7 @@ def test_export_live_2():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["live"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest.name, filename)
|
||||
got_dest = photos[0].export(dest.name, live_photo=False)[0]
|
||||
got_movie = f"{pathlib.Path(got_dest).parent / pathlib.Path(got_dest).stem}.mov"
|
||||
@@ -97,7 +97,7 @@ def test_export_live_3():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["live"]])
|
||||
|
||||
filename = photos[0].filename
|
||||
filename = photos[0].original_filename
|
||||
expected_dest = os.path.join(dest.name, filename)
|
||||
expected_mov = f"{dest.name}/{pathlib.Path(expected_dest).stem}.mov"
|
||||
got_files = photos[0].export(dest.name, live_photo=True)
|
||||
|
||||