Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43e1cb18cc | ||
|
|
26f916e4cb | ||
|
|
4e9e877b27 | ||
|
|
3a990e3997 | ||
|
|
4d1b1db2a7 | ||
|
|
173e3ccc37 | ||
|
|
9964fd0635 | ||
|
|
e789cd5e9d | ||
|
|
6cb7dedd9b | ||
|
|
39ba17dd1c | ||
|
|
5b66962ac1 | ||
|
|
c05340f631 | ||
|
|
f24c461cbb | ||
|
|
c8ee679799 | ||
|
|
2966c9a60f | ||
|
|
acfcb0c49a | ||
|
|
b92a681795 | ||
|
|
1941e79d21 | ||
|
|
5290fae2e0 | ||
|
|
ecbd370a47 | ||
|
|
d8204e65eb | ||
|
|
9c26e5519b | ||
|
|
060729c4c4 | ||
|
|
65d51ab129 | ||
|
|
afbda030bc | ||
|
|
d111d07fb7 |
51
CHANGELOG.md
51
CHANGELOG.md
@@ -4,6 +4,57 @@ 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.46.5](https://github.com/RhetTbull/osxphotos/compare/v0.46.4...v0.46.5)
|
||||
|
||||
> 24 February 2022
|
||||
|
||||
- Updated tested versions [`4d1b1db`](https://github.com/RhetTbull/osxphotos/commit/4d1b1db2a7cf34afaa2dc5dbebc69021ff77964f)
|
||||
|
||||
#### [v0.46.4](https://github.com/RhetTbull/osxphotos/compare/v0.46.1...v0.46.4)
|
||||
|
||||
> 24 February 2022
|
||||
|
||||
- Removed debug code from exiftool, fixed #641 [`#641`](https://github.com/RhetTbull/osxphotos/issues/641)
|
||||
- Added debug output to exiftool [`39ba17d`](https://github.com/RhetTbull/osxphotos/commit/39ba17dd1cb4d8a61ab4dc8d5cff12ff9871eee0)
|
||||
- Fixed export of bursts with --uuid and --selected, #640 [`5b66962`](https://github.com/RhetTbull/osxphotos/commit/5b66962ac1bc1f48106fb8eeb600e6010088dc3b)
|
||||
- Added --sql command to exportdb [`c8ee679`](https://github.com/RhetTbull/osxphotos/commit/c8ee6797999af954c32e96ac3799a19002f4f0fe)
|
||||
- Updated docs [skip ci] [`2966c9a`](https://github.com/RhetTbull/osxphotos/commit/2966c9a60fc828afdf34263b759159a3ade31897)
|
||||
- Updated debug info [`6cb7ded`](https://github.com/RhetTbull/osxphotos/commit/6cb7dedd9be53d2c62489125fc44b9f4dccfb7ae)
|
||||
|
||||
#### [v0.46.1](https://github.com/RhetTbull/osxphotos/compare/v0.46.0...v0.46.1)
|
||||
|
||||
> 21 February 2022
|
||||
|
||||
- Added --ramdb option [`#639`](https://github.com/RhetTbull/osxphotos/pull/639)
|
||||
|
||||
#### [v0.46.0](https://github.com/RhetTbull/osxphotos/compare/v0.45.12...v0.46.0)
|
||||
|
||||
> 21 February 2022
|
||||
|
||||
- Exportdb refactor [`#638`](https://github.com/RhetTbull/osxphotos/pull/638)
|
||||
- Updated docs [skip ci] [`5290fae`](https://github.com/RhetTbull/osxphotos/commit/5290fae2e0ad062750348aedfee4feaf7b2e769f)
|
||||
|
||||
#### [v0.45.12](https://github.com/RhetTbull/osxphotos/compare/v0.45.11...v0.45.12)
|
||||
|
||||
> 14 February 2022
|
||||
|
||||
- Allow multiple characters as path_sep, #634 [`d8204e6`](https://github.com/RhetTbull/osxphotos/commit/d8204e65eb740cece468ef021cbdf45d896d954e)
|
||||
- Added --debug and crash reporter to export, #628 [`060729c`](https://github.com/RhetTbull/osxphotos/commit/060729c4c4255651c6ee8149989d9de541d0a6aa)
|
||||
- Added crash_reporter.py [`9c26e55`](https://github.com/RhetTbull/osxphotos/commit/9c26e5519b2d48f3a0ae80d1cc4a765c12b62d40)
|
||||
|
||||
#### [v0.45.11](https://github.com/RhetTbull/osxphotos/compare/v0.45.10...v0.45.11)
|
||||
|
||||
> 13 February 2022
|
||||
|
||||
- beta fix for #633, fix face regions in exiftool [`afbda03`](https://github.com/RhetTbull/osxphotos/commit/afbda030bce87f914445ebbced3f0e110e2e203b)
|
||||
- Updated docs [skip ci] [`65d51ab`](https://github.com/RhetTbull/osxphotos/commit/65d51ab1290e7c7804021e24829b93f5dce81245)
|
||||
|
||||
#### [v0.45.10](https://github.com/RhetTbull/osxphotos/compare/v0.45.9...v0.45.10)
|
||||
|
||||
> 12 February 2022
|
||||
|
||||
- Added --force-update, #621 [`30abddd`](https://github.com/RhetTbull/osxphotos/commit/30abdddaf3765f1d604984d4781b78b7806871e1)
|
||||
|
||||
#### [v0.45.9](https://github.com/RhetTbull/osxphotos/compare/v0.45.8...v0.45.9)
|
||||
|
||||
> 12 February 2022
|
||||
|
||||
19
README.md
19
README.md
@@ -1173,6 +1173,11 @@ Options:
|
||||
'.osxphotos_export.db' in the export
|
||||
directory. If --exportdb is specified, it
|
||||
will be saved to the specified file.
|
||||
--ramdb Copy export database to memory during export;
|
||||
may improve performance when exporting over a
|
||||
network or slow disk but could result in
|
||||
losing update state information if the program
|
||||
is interrupted or crashes.
|
||||
--load-config <config file path>
|
||||
Load options from file as written with --save-
|
||||
config. This allows you to save a complex
|
||||
@@ -1186,7 +1191,11 @@ Options:
|
||||
corresponding values in the config file.
|
||||
--save-config <config file path>
|
||||
Save options to file for use with --load-
|
||||
config. File format is TOML.
|
||||
config. File format is TOML. See also
|
||||
--config-only.
|
||||
--config-only If specified, saves the config file but does
|
||||
not export any files; must be used with
|
||||
--save-config.
|
||||
--help Show this message and exit.
|
||||
|
||||
** Export **
|
||||
@@ -1732,7 +1741,7 @@ Substitution Description
|
||||
{lf} A line feed: '\n', alias for {newline}
|
||||
{cr} A carriage return: '\r'
|
||||
{crlf} a carriage return + line feed: '\r\n'
|
||||
{osxphotos_version} The osxphotos version, e.g. '0.45.10'
|
||||
{osxphotos_version} The osxphotos version, e.g. '0.46.6'
|
||||
{osxphotos_cmd_line} The full command line used to run osxphotos
|
||||
|
||||
The following substitutions may result in multiple values. Thus if specified for
|
||||
@@ -3636,7 +3645,7 @@ The following template field substitutions are availabe for use the templating s
|
||||
|{lf}|A line feed: '\n', alias for {newline}|
|
||||
|{cr}|A carriage return: '\r'|
|
||||
|{crlf}|a carriage return + line feed: '\r\n'|
|
||||
|{osxphotos_version}|The osxphotos version, e.g. '0.45.10'|
|
||||
|{osxphotos_version}|The osxphotos version, e.g. '0.46.6'|
|
||||
|{osxphotos_cmd_line}|The full command line used to run osxphotos|
|
||||
|{album}|Album(s) photo is contained in|
|
||||
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
||||
@@ -3736,7 +3745,7 @@ Args:
|
||||
|
||||
Returns: ExportResults instance
|
||||
|
||||
*Note*: to use dry run mode, you must set options.dry_run=True and also pass in memory version of export_db, and no-op fileutil (e.g. ExportDBInMemory and FileUtilNoOp) in options.export_db and options.fileutil respectively.
|
||||
*Note*: to use dry run mode, you must set options.dry_run=True and also pass in memory version of export_db, and no-op fileutil (e.g. `ExportDBInMemory` and `FileUtilNoOp`) in options.export_db and options.fileutil respectively.
|
||||
|
||||
#### `ExportOptions`
|
||||
|
||||
@@ -3752,7 +3761,7 @@ Attributes:
|
||||
- exiftool_flags (list of str): optional list of flags to pass to exiftool when using exiftool option, e.g ["-m", "-F"]
|
||||
- exiftool: (bool, default = False): if True, will use exiftool to write metadata to export file
|
||||
- export_as_hardlink: (bool, default=False): if True, will hardlink files instead of copying them
|
||||
- export_db: (ExportDB_ABC): instance of a class that conforms to ExportDB_ABC with methods for getting/setting data related to exported files to compare update state
|
||||
- export_db: (ExportDB): instance of a class that conforms to ExportDB with methods for getting/setting data related to exported files to compare update state
|
||||
- fileutil: (FileUtilABC): class that conforms to FileUtilABC with various file utilities
|
||||
- ignore_date_modified (bool): for use with sidecar and exiftool; if True, sets EXIF:ModifyDate to EXIF:DateTimeOriginal even if date_modified is set
|
||||
- ignore_signature (bool, default=False): ignore file signature when used with update (look only at filename)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
build
|
||||
m2r2
|
||||
pdbpp
|
||||
pyinstaller==4.4
|
||||
pytest-mock
|
||||
pytest==6.2.4
|
||||
Sphinx
|
||||
sphinx_click
|
||||
sphinx_rtd_theme
|
||||
sphinxcontrib-programoutput
|
||||
twine
|
||||
wheel
|
||||
Sphinx
|
||||
wheel
|
||||
@@ -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: 5bcb39b8d7265fb2c5780a64f97662ef
|
||||
config: e2d3552a863fb9f9607fd8327fe2075b
|
||||
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.43.9 documentation</title>
|
||||
<title>Overview: module code — osxphotos 0.46.6 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css" />
|
||||
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
|
||||
@@ -31,11 +31,7 @@
|
||||
<div class="body" role="main">
|
||||
|
||||
<h1>All modules for which code is available</h1>
|
||||
<ul><li><a href="osxphotos/photoinfo/_photoinfo_exifinfo.html">osxphotos.photoinfo._photoinfo_exifinfo</a></li>
|
||||
<li><a href="osxphotos/photoinfo/_photoinfo_export.html">osxphotos.photoinfo._photoinfo_export</a></li>
|
||||
<li><a href="osxphotos/photoinfo/_photoinfo_scoreinfo.html">osxphotos.photoinfo._photoinfo_scoreinfo</a></li>
|
||||
<li><a href="osxphotos/photoinfo/_photoinfo_searchinfo.html">osxphotos.photoinfo._photoinfo_searchinfo</a></li>
|
||||
<li><a href="osxphotos/photoinfo/photoinfo.html">osxphotos.photoinfo.photoinfo</a></li>
|
||||
<ul><li><a href="osxphotos/photoinfo.html">osxphotos.photoinfo</a></li>
|
||||
<li><a href="osxphotos/photosdb/photosdb.html">osxphotos.photosdb.photosdb</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -93,7 +89,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.1</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
1868
docs/_modules/osxphotos/photoinfo.html
Normal file
1868
docs/_modules/osxphotos/photoinfo.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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.43.8 documentation</title>
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.46.6 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
|
||||
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -60,22 +60,28 @@
|
||||
<span class="n">_PHOTO_TYPE</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_3_VERSION</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_ALBUM_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_ALBUM_TYPE_ALBUM</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_ALBUM_TYPE_PROJECT</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_ALBUM_TYPE_SLIDESHOW</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_ROOT_FOLDER</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_TOP_LEVEL_ALBUM</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_VERSION</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_ALBUM_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_FOLDER_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_PROJECT_ALBUM_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_ROOT_FOLDER_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_SHARED_ALBUM_KIND</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_5_VERSION</span><span class="p">,</span>
|
||||
<span class="n">_TESTED_OS_VERSIONS</span><span class="p">,</span>
|
||||
<span class="n">_UNKNOWN_PERSON</span><span class="p">,</span>
|
||||
<span class="n">BURST_KEY</span><span class="p">,</span>
|
||||
<span class="n">BURST_PICK_TYPE_NONE</span><span class="p">,</span>
|
||||
<span class="n">BURST_SELECTED</span><span class="p">,</span>
|
||||
<span class="n">TIME_DELTA</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">.._version</span> <span class="kn">import</span> <span class="n">__version__</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">FolderInfo</span><span class="p">,</span> <span class="n">ImportInfo</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">FolderInfo</span><span class="p">,</span> <span class="n">ImportInfo</span><span class="p">,</span> <span class="n">ProjectInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..datetime_utils</span> <span class="kn">import</span> <span class="n">datetime_has_tz</span><span class="p">,</span> <span class="n">datetime_naive_to_local</span>
|
||||
<span class="kn">from</span> <span class="nn">..fileutil</span> <span class="kn">import</span> <span class="n">FileUtil</span>
|
||||
<span class="kn">from</span> <span class="nn">..personinfo</span> <span class="kn">import</span> <span class="n">PersonInfo</span>
|
||||
@@ -94,6 +100,8 @@
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">.photosdb_utils</span> <span class="kn">import</span> <span class="n">get_db_model_version</span><span class="p">,</span> <span class="n">get_db_version</span>
|
||||
|
||||
<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"PhotosDB"</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># TODO: Add test for imageTimeZoneOffsetSeconds = None</span>
|
||||
<span class="c1"># TODO: Add test for __str__</span>
|
||||
<span class="c1"># TODO: Add special albums and magic albums</span>
|
||||
@@ -462,7 +470,7 @@
|
||||
<span class="k">for</span> <span class="n">folder</span><span class="p">,</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"intrash"</span><span class="p">]</span>
|
||||
<span class="ow">and</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"isMagic"</span><span class="p">]</span>
|
||||
<span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"parentFolderUuid"</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUM</span>
|
||||
<span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"parentFolderUuid"</span><span class="p">]</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span>
|
||||
<span class="p">]</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="p">[</span>
|
||||
@@ -483,7 +491,7 @@
|
||||
<span class="k">for</span> <span class="n">folder</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="o">.</span><span class="n">values</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">folder</span><span class="p">[</span><span class="s2">"intrash"</span><span class="p">]</span>
|
||||
<span class="ow">and</span> <span class="ow">not</span> <span class="n">folder</span><span class="p">[</span><span class="s2">"isMagic"</span><span class="p">]</span>
|
||||
<span class="ow">and</span> <span class="n">folder</span><span class="p">[</span><span class="s2">"parentFolderUuid"</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUM</span>
|
||||
<span class="ow">and</span> <span class="n">folder</span><span class="p">[</span><span class="s2">"parentFolderUuid"</span><span class="p">]</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span>
|
||||
<span class="p">]</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">folder_names</span> <span class="o">=</span> <span class="p">[</span>
|
||||
@@ -562,6 +570,18 @@
|
||||
<span class="p">]</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_import_info</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">project_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return list of AlbumInfo projects for each project in the database"""</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">_project_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_project_info</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="n">ProjectInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">album</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">project</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="p">]</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_project_info</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">db_version</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return the database version as stored in LiGlobals table"""</span>
|
||||
@@ -673,14 +693,18 @@
|
||||
|
||||
<span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">pk</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">fullname</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">_UNKNOWN_PERSON</span>
|
||||
<span class="n">fullname</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
|
||||
<span class="k">else</span> <span class="n">_UNKNOWN_PERSON</span>
|
||||
<span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"pk"</span><span class="p">:</span> <span class="n">pk</span><span class="p">,</span>
|
||||
<span class="s2">"uuid"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
|
||||
<span class="s2">"fullname"</span><span class="p">:</span> <span class="n">fullname</span><span class="p">,</span>
|
||||
<span class="s2">"facecount"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
|
||||
<span class="s2">"keyface"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
|
||||
<span class="s2">"displayname"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span>
|
||||
<span class="s2">"displayname"</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">4</span><span class="p">]),</span>
|
||||
<span class="s2">"photo_uuid"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="s2">"keyface_uuid"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
@@ -747,13 +771,6 @@
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Finished walking through persons"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># Get info on albums</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing albums."</span><span class="p">)</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
@@ -881,24 +898,15 @@
|
||||
<span class="c1"># build folder hierarchy</span>
|
||||
<span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">details</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
|
||||
<span class="n">parent_folder</span> <span class="o">=</span> <span class="n">details</span><span class="p">[</span><span class="s2">"folderUuid"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">details</span><span class="p">[</span>
|
||||
<span class="s2">"albumSubclass"</span>
|
||||
<span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span> <span class="ow">and</span> <span class="n">parent_folder</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span>
|
||||
<span class="n">_PHOTOS_4_TOP_LEVEL_ALBUM</span>
|
||||
<span class="p">]:</span>
|
||||
<span class="k">if</span> <span class="p">(</span>
|
||||
<span class="n">details</span><span class="p">[</span><span class="s2">"albumSubclass"</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span>
|
||||
<span class="ow">and</span> <span class="n">parent_folder</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span>
|
||||
<span class="p">):</span>
|
||||
<span class="n">folder_hierarchy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_album_folder_hierarchy_4</span><span class="p">(</span><span class="n">parent_folder</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="n">folder_hierarchy</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Finished walking through albums"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># Get info on keywords</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing keywords."</span><span class="p">)</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
@@ -914,13 +922,16 @@
|
||||
<span class="sd"> RKMaster.uuid = RKVersion.masterUuid</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">keyword</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
|
||||
<span class="k">for</span> <span class="n">keyword_title</span><span class="p">,</span> <span class="n">keyword_uuid</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">keyword_title</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_uuid</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># Get info on disk volumes</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"select RKVolume.modelId, RKVolume.name from RKVolume"</span><span class="p">)</span>
|
||||
@@ -1042,13 +1053,11 @@
|
||||
|
||||
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"uuid = '</span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2">, master = '</span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"_uuid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">uuid</span> <span class="c1"># stored here for easier debugging</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"modelID"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"masterUuid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"filename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"filename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>
|
||||
|
||||
<span class="c1"># There are sometimes negative values for lastmodifieddate in the database</span>
|
||||
<span class="c1"># I don't know what these mean but they will raise exception in datetime if</span>
|
||||
@@ -1287,13 +1296,13 @@
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"volumeId"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"imagePath"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"isMissing"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"originalFilename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"originalFilename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"UTI"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"modelID"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"fileSize"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"isTrulyRAW"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"alternateMasterUuid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"filename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"filename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">])</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="n">info</span>
|
||||
|
||||
<span class="c1"># get details needed to find path of the edited photos</span>
|
||||
@@ -1565,39 +1574,6 @@
|
||||
|
||||
<span class="c1"># done processing, dump debug data if requested</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Done processing details from Photos library."</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Faces (_dbfaces_uuid):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Persons (_dbpersons_pk):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Keywords by uuid (_dbkeywords_uuid):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Keywords by keyword (_dbkeywords_keywords):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Albums by uuid (_dbalbums_uuid):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Albums by album (_dbalbums_albums):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Album details (_dbalbum_details):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Album titles (_dbalbum_titles):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Volumes (_dbvolumes):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Photos (_dbphotos):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Burst Photos (dbphotos_burst:"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">))</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_build_album_folder_hierarchy_4</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">folders</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="sd">"""recursively build folder/album hierarchy</span>
|
||||
@@ -1615,7 +1591,7 @@
|
||||
<span class="k">if</span> <span class="n">parent_uuid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">folders</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">parent_uuid</span> <span class="o">==</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUM</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">parent_uuid</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
|
||||
<span class="c1"># this is a top-level folder with no sub-folders</span>
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">uuid</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span>
|
||||
@@ -1688,7 +1664,7 @@
|
||||
<span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">pk</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">fullname</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">""</span> <span class="ow">and</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="k">else</span> <span class="n">_UNKNOWN_PERSON</span>
|
||||
<span class="p">)</span>
|
||||
@@ -1698,7 +1674,7 @@
|
||||
<span class="s2">"fullname"</span><span class="p">:</span> <span class="n">fullname</span><span class="p">,</span>
|
||||
<span class="s2">"facecount"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
|
||||
<span class="s2">"keyface"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span>
|
||||
<span class="s2">"displayname"</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
|
||||
<span class="s2">"displayname"</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">5</span><span class="p">]),</span>
|
||||
<span class="s2">"photo_uuid"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="s2">"keyface_uuid"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
@@ -1762,13 +1738,6 @@
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Finished walking through persons"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># get details about albums</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing albums."</span><span class="p">)</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
@@ -1885,13 +1854,6 @@
|
||||
<span class="c1"># shared albums can't be in folders</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Finished walking through albums"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># get details on keywords</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing keywords."</span><span class="p">)</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
@@ -1901,29 +1863,22 @@
|
||||
<span class="s2"> JOIN Z_1KEYWORDS ON Z_1KEYWORDS.Z_1ASSETATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK </span>
|
||||
<span class="s2"> JOIN ZKEYWORD ON ZKEYWORD.Z_PK = </span><span class="si">{</span><span class="n">keyword_join</span><span class="si">}</span><span class="s2"> """</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">keyword_title</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">keyword_title</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Finished walking through keywords"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">))</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">))</span>
|
||||
<span class="k">for</span> <span class="n">keyword_title</span><span class="p">,</span> <span class="n">keyword_uuid</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">keyword_title</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_uuid</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># get details on disk volumes</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"SELECT ZUUID, ZNAME from ZFILESYSTEMVOLUME"</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">vol</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span><span class="n">vol</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">=</span> <span class="n">vol</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Finished walking through volumes"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># get details about photos</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing photo details."</span><span class="p">)</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
@@ -2057,8 +2012,8 @@
|
||||
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"hidden"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"favorite"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"originalFilename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"filename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"originalFilename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"filename"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">12</span><span class="p">])</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"directory"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># set latitude and longitude</span>
|
||||
@@ -2534,50 +2489,7 @@
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing moments."</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_process_moments</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># done processing, dump debug data if requested</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Done processing details from Photos library."</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Faces (_dbfaces_uuid):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Persons (_dbpersons_pk):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Keywords by uuid (_dbkeywords_uuid):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Keywords by keyword (_dbkeywords_keywords):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Albums by uuid (_dbalbums_uuid):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Albums by album (_dbalbums_albums):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Album details (_dbalbum_details):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Album titles (_dbalbum_titles):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Album folders (_dbalbum_folders):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Album parent folders (_dbalbum_parent_folders):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_parent_folders</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Albums pk (_dbalbums_pk):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_pk</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Volumes (_dbvolumes):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Photos (_dbphotos):"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">))</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Burst Photos (dbphotos_burst:"</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">pformat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">))</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_process_moments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Process data from ZMOMENT table"""</span>
|
||||
@@ -2638,8 +2550,8 @@
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"modificationDate"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"representativeDate"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"startDate"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"subtitle"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"title"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"subtitle"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">])</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"title"</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">])</span>
|
||||
<span class="n">moment_info</span><span class="p">[</span><span class="s2">"uuid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># if both lat/lon == -180, then it means location undefined</span>
|
||||
@@ -2858,7 +2770,7 @@
|
||||
<span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">hierarchy</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_get_album_uuids</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">import_session</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
<span class="k">def</span> <span class="nf">_get_album_uuids</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">import_session</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">project</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
<span class="sd">"""Return list of album UUIDs found in photos database</span>
|
||||
|
||||
<span class="sd"> Filters out albums in the trash and any special album types</span>
|
||||
@@ -2866,20 +2778,21 @@
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> shared: boolean; if True, returns shared albums, else normal albums</span>
|
||||
<span class="sd"> import_session: boolean, if True, returns import session albums, else normal or shared albums</span>
|
||||
<span class="sd"> project: boolean, if True, returns albums that are part of My Projects</span>
|
||||
<span class="sd"> Note: flags (shared, import_session) are mutually exclusive</span>
|
||||
|
||||
|
||||
<span class="sd"> Raises:</span>
|
||||
<span class="sd"> ValueError: raised if mutually exclusive flags passed</span>
|
||||
|
||||
<span class="sd"> Returns: list of album UUIDs</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="n">shared</span> <span class="ow">and</span> <span class="n">import_session</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="nb">bool</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="n">shared</span><span class="p">,</span> <span class="n">import_session</span><span class="p">,</span> <span class="n">project</span><span class="p">])</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
|
||||
<span class="s2">"flags are mutually exclusive: pass zero or one of shared, import_session"</span>
|
||||
<span class="s2">"flags are mutually exclusive: pass zero or one of shared, import_session, projects"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</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="n">version4</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="k">if</span> <span class="n">shared</span><span class="p">:</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"Shared albums not implemented for Photos library version </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="si">}</span><span class="s2">"</span>
|
||||
@@ -2890,16 +2803,44 @@
|
||||
<span class="sa">f</span><span class="s2">"Import sessions not implemented for Photos library version </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">[]</span> <span class="c1"># not implemented for _PHOTOS_4_VERSION</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">elif</span> <span class="n">project</span><span class="p">:</span>
|
||||
<span class="n">album_type</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="n">_PHOTOS_4_ALBUM_TYPE_PROJECT</span><span class="p">,</span>
|
||||
<span class="n">_PHOTOS_4_ALBUM_TYPE_SLIDESHOW</span><span class="p">,</span>
|
||||
<span class="p">]</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">version4</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="k">if</span> <span class="n">shared</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_SHARED_ALBUM_KIND</span>
|
||||
<span class="k">elif</span> <span class="n">import_session</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_ALBUM_KIND</span>
|
||||
<span class="n">album_type</span> <span class="o">=</span> <span class="p">[</span><span class="n">_PHOTOS_4_ALBUM_TYPE_ALBUM</span><span class="p">]</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span>
|
||||
|
||||
<span class="n">album_list</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="c1"># look through _dbalbum_details because _dbalbums_album won't have empty albums it</span>
|
||||
<span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="p">(</span>
|
||||
<span class="n">detail</span><span class="p">[</span><span class="s2">"kind"</span><span class="p">]</span> <span class="o">==</span> <span class="n">album_kind</span>
|
||||
<span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"albumType"</span><span class="p">]</span> <span class="ow">in</span> <span class="n">album_type</span>
|
||||
<span class="ow">and</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"intrash"</span><span class="p">]</span>
|
||||
<span class="ow">and</span> <span class="p">(</span>
|
||||
<span class="p">(</span><span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"cloudownerhashedpersonid"</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="ow">or</span> <span class="p">(</span><span class="ow">not</span> <span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"cloudownerhashedpersonid"</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"folderUuid"</span><span class="p">]</span> <span class="o">!=</span> <span class="n">_PHOTOS_4_ROOT_FOLDER</span>
|
||||
<span class="c1"># in Photos <= 4, special albums like "printAlbum" have kind _PHOTOS_4_ALBUM_KIND</span>
|
||||
<span class="c1"># but should not be listed here; they can be distinguished by looking</span>
|
||||
<span class="c1"># for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM</span>
|
||||
<span class="p">):</span>
|
||||
<span class="n">album_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">album_list</span>
|
||||
|
||||
<span class="c1"># Photos version 5+</span>
|
||||
<span class="k">if</span> <span class="n">shared</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_SHARED_ALBUM_KIND</span>
|
||||
<span class="k">elif</span> <span class="n">import_session</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND</span>
|
||||
<span class="k">elif</span> <span class="n">project</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_PROJECT_ALBUM_KIND</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_ALBUM_KIND</span>
|
||||
|
||||
<span class="n">album_list</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="c1"># look through _dbalbum_details because _dbalbums_album won't have empty albums it</span>
|
||||
@@ -2911,13 +2852,6 @@
|
||||
<span class="p">(</span><span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"cloudownerhashedpersonid"</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="ow">or</span> <span class="p">(</span><span class="ow">not</span> <span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"cloudownerhashedpersonid"</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="ow">and</span> <span class="p">(</span>
|
||||
<span class="ow">not</span> <span class="n">version4</span>
|
||||
<span class="c1"># in Photos 4, special albums like "printAlbum" have kind _PHOTOS_4_ALBUM_KIND</span>
|
||||
<span class="c1"># but should not be listed here; they can be distinguished by looking</span>
|
||||
<span class="c1"># for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM</span>
|
||||
<span class="ow">or</span> <span class="p">(</span><span class="n">version4</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">"folderUuid"</span><span class="p">]</span> <span class="o">!=</span> <span class="n">_PHOTOS_4_ROOT_FOLDER</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="p">):</span>
|
||||
<span class="n">album_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">album_list</span>
|
||||
@@ -3020,6 +2954,7 @@
|
||||
<span class="k">if</span> <span class="n">keywords</span><span class="p">:</span>
|
||||
<span class="n">keyword_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
|
||||
<span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">keywords</span><span class="p">:</span>
|
||||
<span class="n">keyword</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">:</span>
|
||||
<span class="n">keyword_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword</span><span class="p">])</span>
|
||||
<span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_set</span><span class="p">)</span>
|
||||
@@ -3027,6 +2962,7 @@
|
||||
<span class="k">if</span> <span class="n">persons</span><span class="p">:</span>
|
||||
<span class="n">person_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
|
||||
<span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">persons</span><span class="p">:</span>
|
||||
<span class="n">person</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">person</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">pk</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">[</span><span class="n">person</span><span class="p">]:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
@@ -3058,6 +2994,7 @@
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">"burst"</span><span class="p">]</span> <span class="ow">and</span> <span class="ow">not</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">"burstPickType"</span><span class="p">]</span> <span class="o">&</span> <span class="n">BURST_SELECTED</span>
|
||||
<span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">"burstPickType"</span><span class="p">]</span> <span class="o">&</span> <span class="n">BURST_KEY</span>
|
||||
<span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">"burstPickType"</span><span class="p">]</span> <span class="o">==</span> <span class="n">BURST_PICK_TYPE_NONE</span>
|
||||
<span class="p">):</span>
|
||||
<span class="c1"># not a key/selected burst photo, don't include in returned results</span>
|
||||
<span class="k">continue</span>
|
||||
@@ -3068,8 +3005,6 @@
|
||||
<span class="p">):</span>
|
||||
<span class="n">info</span> <span class="o">=</span> <span class="n">PhotoInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">p</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">])</span>
|
||||
<span class="n">photoinfo</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">info</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">:</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"photoinfo: </span><span class="si">{</span><span class="n">pformat</span><span class="p">(</span><span class="n">photoinfo</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">photoinfo</span></div>
|
||||
|
||||
@@ -3377,27 +3312,6 @@
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">:</span>
|
||||
<span class="n">photos</span> <span class="o">=</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="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o"><=</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">burst_photos</span><span class="p">:</span>
|
||||
<span class="c1"># add the burst_photos to the export set</span>
|
||||
<span class="n">photos_burst</span> <span class="o">=</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="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">burst</span><span class="p">]</span>
|
||||
<span class="k">for</span> <span class="n">burst</span> <span class="ow">in</span> <span class="n">photos_burst</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">missing_bursts</span><span class="p">:</span>
|
||||
<span class="c1"># include burst photos that are missing</span>
|
||||
<span class="n">photos</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">burst</span><span class="o">.</span><span class="n">burst_photos</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># don't include missing burst images (these can't be downloaded with AppleScript)</span>
|
||||
<span class="n">photos</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="n">burst</span><span class="o">.</span><span class="n">burst_photos</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">ismissing</span><span class="p">])</span>
|
||||
|
||||
<span class="c1"># remove duplicates as each burst photo in the set that's selected would</span>
|
||||
<span class="c1"># result in the entire set being added above</span>
|
||||
<span class="c1"># can't use set() because PhotoInfo not hashable</span>
|
||||
<span class="n">seen_uuids</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">uuid</span> <span class="ow">in</span> <span class="n">seen_uuids</span><span class="p">:</span>
|
||||
<span class="k">continue</span>
|
||||
<span class="n">seen_uuids</span><span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="n">p</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">seen_uuids</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">name</span><span class="p">:</span>
|
||||
<span class="c1"># search filename fields for text</span>
|
||||
<span class="c1"># if more than one, find photos with all title values in filename</span>
|
||||
@@ -3406,23 +3320,35 @@
|
||||
<span class="c1"># case-insensitive</span>
|
||||
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">name</span><span class="p">:</span>
|
||||
<span class="n">n</span> <span class="o">=</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</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="n">photos</span>
|
||||
<span class="k">if</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="ow">or</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">original_filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">>=</span> <span class="n">_PHOTOS_5_VERSION</span><span class="p">:</span>
|
||||
<span class="c1"># search only original_filename (#594)</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</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="n">photos</span> <span class="k">if</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">original_filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</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="n">photos</span>
|
||||
<span class="k">if</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="ow">or</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">original_filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">name</span><span class="p">:</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</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="n">photos</span>
|
||||
<span class="k">if</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">filename</span> <span class="ow">or</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">original_filename</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">>=</span> <span class="n">_PHOTOS_5_VERSION</span><span class="p">:</span>
|
||||
<span class="c1"># search only original_filename (#594)</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</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="n">photos</span> <span class="k">if</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">original_filename</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">extend</span><span class="p">(</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="n">photos</span>
|
||||
<span class="k">if</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">filename</span> <span class="ow">or</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">original_filename</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="n">photo_list</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">min_size</span><span class="p">:</span>
|
||||
@@ -3536,6 +3462,28 @@
|
||||
<span class="k">for</span> <span class="n">function</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">function</span><span class="p">:</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="n">function</span><span class="p">[</span><span class="mi">0</span><span class="p">](</span><span class="n">photos</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># burst should be checked last, ref #640</span>
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">burst_photos</span><span class="p">:</span>
|
||||
<span class="c1"># add the burst_photos to the export set</span>
|
||||
<span class="n">photos_burst</span> <span class="o">=</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="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">burst</span><span class="p">]</span>
|
||||
<span class="k">for</span> <span class="n">burst</span> <span class="ow">in</span> <span class="n">photos_burst</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">missing_bursts</span><span class="p">:</span>
|
||||
<span class="c1"># include burst photos that are missing</span>
|
||||
<span class="n">photos</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">burst</span><span class="o">.</span><span class="n">burst_photos</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># don't include missing burst images (these can't be downloaded with AppleScript)</span>
|
||||
<span class="n">photos</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="n">burst</span><span class="o">.</span><span class="n">burst_photos</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">ismissing</span><span class="p">])</span>
|
||||
|
||||
<span class="c1"># remove duplicates as each burst photo in the set that's selected would</span>
|
||||
<span class="c1"># result in the entire set being added above</span>
|
||||
<span class="c1"># can't use set() because PhotoInfo not hashable</span>
|
||||
<span class="n">seen_uuids</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">uuid</span> <span class="ow">in</span> <span class="n">seen_uuids</span><span class="p">:</span>
|
||||
<span class="k">continue</span>
|
||||
<span class="n">seen_uuids</span><span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="n">p</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">seen_uuids</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">photos</span></div>
|
||||
|
||||
<div class="viewcode-block" id="PhotosDB.execute"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.execute">[docs]</a> <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sql</span><span class="p">):</span>
|
||||
@@ -3659,7 +3607,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.1</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -3,4 +3,6 @@ osxphotos command line interface (CLI)
|
||||
|
||||
.. click:: osxphotos.cli:cli
|
||||
:prog: osxphotos
|
||||
:nested: full
|
||||
:nested: full
|
||||
|
||||
.. program-output:: python3 -m osxphotos --help
|
||||
2
docs/_static/documentation_options.js
vendored
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.45.10',
|
||||
VERSION: '0.46.6',
|
||||
LANGUAGE: 'None',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
2228
docs/cli.html
2228
docs/cli.html
File diff suppressed because it is too large
Load Diff
2714
docs/genindex.html
2714
docs/genindex.html
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.45.10 documentation</title>
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.46.6 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
@@ -281,7 +281,32 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
<p>Reference full documentation on <a class="reference external" href="https://github.com/RhetTbull/osxphotos/blob/master/README.md">GitHub</a></p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="cli.html">osxphotos command line interface (CLI)</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="cli.html">osxphotos command line interface (CLI)</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="cli.html#osxphotos">osxphotos</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-about">about</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-albums">albums</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-diff">diff</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-dump">dump</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-export">export</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-help">help</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-info">info</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-install">install</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-keywords">keywords</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-labels">labels</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-list">list</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-persons">persons</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-places">places</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-query">query</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-repl">repl</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-run">run</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-snap">snap</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-tutorial">tutorial</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-uninstall">uninstall</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-uuid">uuid</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="reference.html">osxphotos package</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos-module">osxphotos module</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>osxphotos — osxphotos 0.45.10 documentation</title>
|
||||
<title>osxphotos — osxphotos 0.46.6 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
|
||||
BIN
docs/objects.inv
BIN
docs/objects.inv
Binary file not shown.
@@ -6,7 +6,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>osxphotos package — osxphotos 0.45.10 documentation</title>
|
||||
<title>osxphotos package — osxphotos 0.46.6 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
@@ -36,6 +36,883 @@
|
||||
<h1>osxphotos package<a class="headerlink" href="#osxphotos-package" title="Permalink to this headline">¶</a></h1>
|
||||
<section id="osxphotos-module">
|
||||
<h2>osxphotos module<a class="headerlink" href="#osxphotos-module" title="Permalink to this headline">¶</a></h2>
|
||||
<dl class="py class">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB">
|
||||
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">osxphotos.</span></span><span class="sig-name descname"><span class="pre">PhotosDB</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">dbfile</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">verbose</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">exiftool</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Processes a Photos.app library database to extract information about photos</p>
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.album_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">album_info</span></span><a class="headerlink" href="#osxphotos.PhotosDB.album_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of AlbumInfo objects for each album in the photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.album_info_shared">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">album_info_shared</span></span><a class="headerlink" href="#osxphotos.PhotosDB.album_info_shared" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of AlbumInfo objects for each shared album in the photos database
|
||||
only valid for Photos 5; on Photos <= 4, prints warning and returns empty list</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.albums">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">albums</span></span><a class="headerlink" href="#osxphotos.PhotosDB.albums" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of albums found in photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.albums_as_dict">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">albums_as_dict</span></span><a class="headerlink" href="#osxphotos.PhotosDB.albums_as_dict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return albums as dict of albums, count in reverse sorted order (descending)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.albums_shared">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">albums_shared</span></span><a class="headerlink" href="#osxphotos.PhotosDB.albums_shared" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of shared albums found in photos database
|
||||
only valid for Photos 5; on Photos <= 4, prints warning and returns empty list</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.albums_shared_as_dict">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">albums_shared_as_dict</span></span><a class="headerlink" href="#osxphotos.PhotosDB.albums_shared_as_dict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns shared albums as dict of albums, count in reverse sorted order (descending)
|
||||
valid only on Photos 5; on Photos <= 4, prints warning and returns empty dict</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.db_path">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">db_path</span></span><a class="headerlink" href="#osxphotos.PhotosDB.db_path" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns path to the Photos library database PhotosDB was initialized with</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.db_version">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">db_version</span></span><a class="headerlink" href="#osxphotos.PhotosDB.db_version" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return the database version as stored in LiGlobals table</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.execute">
|
||||
<span class="sig-name descname"><span class="pre">execute</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">sql</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.execute"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.execute" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Execute sql statement and return cursor</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.folder_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">folder_info</span></span><a class="headerlink" href="#osxphotos.PhotosDB.folder_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list FolderInfo objects representing top-level folders in the photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.folders">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">folders</span></span><a class="headerlink" href="#osxphotos.PhotosDB.folders" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of top-level folder names in the photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.get_db_connection">
|
||||
<span class="sig-name descname"><span class="pre">get_db_connection</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.get_db_connection"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.get_db_connection" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Get connection to the working copy of the Photos database</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Returns</dt>
|
||||
<dd class="field-odd"><p>tuple of (connection, cursor) to sqlite3 database</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.get_photo">
|
||||
<span class="sig-name descname"><span class="pre">get_photo</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">uuid</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.get_photo"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.get_photo" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns a single photo matching uuid</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><p><strong>uuid</strong> – the UUID of photo to get</p>
|
||||
</dd>
|
||||
<dt class="field-even">Returns</dt>
|
||||
<dd class="field-even"><p>PhotoInfo instance for photo with UUID matching uuid or None if no match</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.import_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">import_info</span></span><a class="headerlink" href="#osxphotos.PhotosDB.import_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of ImportInfo objects for each import session in the database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.keywords">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">keywords</span></span><a class="headerlink" href="#osxphotos.PhotosDB.keywords" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of keywords found in photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.keywords_as_dict">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">keywords_as_dict</span></span><a class="headerlink" href="#osxphotos.PhotosDB.keywords_as_dict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return keywords as dict of keyword, count in reverse sorted order (descending)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.labels">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">labels</span></span><a class="headerlink" href="#osxphotos.PhotosDB.labels" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of all search info labels found in the library</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.labels_as_dict">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">labels_as_dict</span></span><a class="headerlink" href="#osxphotos.PhotosDB.labels_as_dict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>count in reverse sorted order (descending)</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Type</dt>
|
||||
<dd class="field-odd"><p>return labels as dict of label</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.labels_normalized">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">labels_normalized</span></span><a class="headerlink" href="#osxphotos.PhotosDB.labels_normalized" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of all normalized search info labels found in the library</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.labels_normalized_as_dict">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">labels_normalized_as_dict</span></span><a class="headerlink" href="#osxphotos.PhotosDB.labels_normalized_as_dict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>count in reverse sorted order (descending)</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Type</dt>
|
||||
<dd class="field-odd"><p>return normalized labels as dict of label</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.library_path">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">library_path</span></span><a class="headerlink" href="#osxphotos.PhotosDB.library_path" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns path to the Photos library PhotosDB was initialized with</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.person_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">person_info</span></span><a class="headerlink" href="#osxphotos.PhotosDB.person_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of PersonInfo objects for each person in the photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.persons">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">persons</span></span><a class="headerlink" href="#osxphotos.PhotosDB.persons" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of persons found in photos database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.persons_as_dict">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">persons_as_dict</span></span><a class="headerlink" href="#osxphotos.PhotosDB.persons_as_dict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return persons as dict of person, count in reverse sorted order (descending)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.photos">
|
||||
<span class="sig-name descname"><span class="pre">photos</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">keywords</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">uuid</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">persons</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">albums</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">images</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">movies</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">from_date</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">to_date</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">intrash</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.photos"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.photos" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Return a list of PhotoInfo objects
|
||||
If called with no args, returns the entire database of photos
|
||||
If called with args, returns photos matching the args (e.g. keywords, persons, etc.)
|
||||
If more than one arg, returns photos matching all the criteria (e.g. keywords AND persons)
|
||||
If more than one keyword, uuid, persons, albums is passed, they are treated as “OR” criteria
|
||||
e.g. keywords=[“wedding”,”vacation”] returns photos matching either keyword
|
||||
from_date and to_date may be either naive or timezone-aware datetime.datetime objects.
|
||||
If naive, timezone will be assumed to be local timezone.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><ul class="simple">
|
||||
<li><p><strong>keywords</strong> – list of keywords to search for</p></li>
|
||||
<li><p><strong>uuid</strong> – list of UUIDs to search for</p></li>
|
||||
<li><p><strong>persons</strong> – list of persons to search for</p></li>
|
||||
<li><p><strong>albums</strong> – list of album names to search for</p></li>
|
||||
<li><p><strong>images</strong> – if True, returns image files, if False, does not return images; default is True</p></li>
|
||||
<li><p><strong>movies</strong> – if True, returns movie files, if False, does not return movies; default is True</p></li>
|
||||
<li><p><strong>from_date</strong> – return photos with creation date >= from_date (datetime.datetime object, default None)</p></li>
|
||||
<li><p><strong>to_date</strong> – return photos with creation date <= to_date (datetime.datetime object, default None)</p></li>
|
||||
<li><p><strong>intrash</strong> – if True, returns only images in “Recently deleted items” folder,
|
||||
if False returns only photos that aren’t deleted; default is False</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt class="field-even">Returns</dt>
|
||||
<dd class="field-even"><p>list of PhotoInfo objects</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.photos_by_uuid">
|
||||
<span class="sig-name descname"><span class="pre">photos_by_uuid</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">uuids</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.photos_by_uuid"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.photos_by_uuid" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><dl class="simple">
|
||||
<dt>Returns a list of photos with UUID in uuids.</dt><dd><p>Does not generate error if invalid or missing UUID passed.
|
||||
This is faster than using PhotosDB.photos if you have list of UUIDs.
|
||||
Returns photos regardless of intrash state.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><p><strong>uuid</strong> – list of UUIDs of photos to get</p>
|
||||
</dd>
|
||||
<dt class="field-even">Returns</dt>
|
||||
<dd class="field-even"><p>list of PhotoInfo instance for photo with UUID matching uuid or [] if no match</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.project_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">project_info</span></span><a class="headerlink" href="#osxphotos.PhotosDB.project_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of AlbumInfo projects for each project in the database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.query">
|
||||
<span class="sig-name descname"><span class="pre">query</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">options</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">osxphotos.queryoptions.QueryOptions</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">List</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="#osxphotos.PhotoInfo" title="osxphotos.photoinfo.PhotoInfo"><span class="pre">osxphotos.photoinfo.PhotoInfo</span></a><span class="p"><span class="pre">]</span></span></span></span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.query"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.query" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Run a query against PhotosDB to extract the photos based on user supplied options</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><p><strong>options</strong> – a QueryOptions instance</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py class">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo">
|
||||
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">osxphotos.</span></span><span class="sig-name descname"><span class="pre">PhotoInfo</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">db</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">uuid</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">info</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoinfo.html#PhotoInfo"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoInfo" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Info about a specific photo, contains all the details about the photo
|
||||
including keywords, persons, albums, uuid, path, etc.</p>
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.adjustments">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">adjustments</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.adjustments" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.album_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">album_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.album_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of AlbumInfo objects representing albums the photo is contained in</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.albums">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">albums</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.albums" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of albums picture is contained in</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.asdict">
|
||||
<span class="sig-name descname"><span class="pre">asdict</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoinfo.html#PhotoInfo.asdict"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoInfo.asdict" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return dict representation</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is part of a Burst photo set, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst_album_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst_album_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst_album_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>If photo is a burst photo, returns list of AlbumInfo objects representing albums the photo is contained in as well as albums the burst key photo is contained in, otherwise returns self.album_info.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst_albums">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst_albums</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst_albums" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>If photo is burst photo, list of albums it is contained in as well as any albums the key photo is contained in, otherwise returns self.albums</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst_default_pick">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst_default_pick</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst_default_pick" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a burst image and is the photo that Photos selected as the default image for the burst set, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst_key">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst_key</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst_key" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a burst photo and is the key image for the burst set (the image that Photos shows on top of the burst stack), otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst_photos">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst_photos</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst_photos" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>If photo is a burst photo, returns list of PhotoInfo objects
|
||||
that are part of the same burst photo set; otherwise returns empty list.
|
||||
self is not included in the returned list</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.burst_selected">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">burst_selected</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.burst_selected" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a burst photo and has been selected from the burst set by the user, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.comments">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">comments</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.comments" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns list of Comment objects for any comments on the photo (sorted by date)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.date">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">date</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.date" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>image creation date as timezone aware datetime object</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.date_added">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">date_added</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.date_added" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Date photo was added to the database</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.date_modified">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">date_modified</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.date_modified" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>image modification date as timezone aware datetime object
|
||||
or None if no modification date set</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.date_trashed">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">date_trashed</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.date_trashed" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Date asset was placed in the trash or None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.description">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">description</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.description" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>long / extended description of picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.detected_text">
|
||||
<span class="sig-name descname"><span class="pre">detected_text</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">confidence_threshold</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0.75</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoinfo.html#PhotoInfo.detected_text"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoInfo.detected_text" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Detects text in photo and returns lists of results as (detected text, confidence)</p>
|
||||
<p>confidence_threshold: float between 0.0 and 1.0. If text detection confidence is below this threshold,
|
||||
text will not be returned. Default is TEXT_DETECTION_CONFIDENCE_THRESHOLD</p>
|
||||
<p>If photo is edited, uses the edited photo, otherwise the original; falls back to the preview image if neither edited or original is available</p>
|
||||
<p>Returns: list of (detected text, confidence) tuples</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.duplicates">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">duplicates</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.duplicates" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return list of PhotoInfo objects for possible duplicates (matching signature of original size, date, height, width) or empty list if no matching duplicates</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.exif_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">exif_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.exif_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns an ExifInfo object with the EXIF data for photo
|
||||
Note: the returned EXIF data is the data Photos stores in the database on import;
|
||||
ExifInfo does not provide access to the EXIF info in the actual image file
|
||||
Some or all of the fields may be None
|
||||
Only valid for Photos 5; on earlier database returns None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.exiftool">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">exiftool</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.exiftool" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns a ExifToolCaching (read-only instance of ExifTool) object for the photo.
|
||||
Requires that exiftool (<a class="reference external" href="https://exiftool.org/">https://exiftool.org/</a>) be installed
|
||||
If exiftool not installed, logs warning and returns None
|
||||
If photo path is missing, returns None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.export">
|
||||
<span class="sig-name descname"><span class="pre">export</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">dest</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">edited</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">live_photo</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">raw_photo</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">export_as_hardlink</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">overwrite</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">increment</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">sidecar_json</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">sidecar_exiftool</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">sidecar_xmp</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">use_photos_export</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">timeout</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">120</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">exiftool</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">use_albums_as_keywords</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">use_persons_as_keywords</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">keyword_template</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">description_template</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">render_options</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">osxphotos.phototemplate.RenderOptions</span><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoinfo.html#PhotoInfo.export"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoInfo.export" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>export photo
|
||||
dest: must be valid destination path (or exception raised)
|
||||
filename: (optional): name of exported picture; if not provided, will use current filename</p>
|
||||
<blockquote>
|
||||
<div><p><strong>NOTE</strong>: if provided, user must ensure file extension (suffix) is correct.
|
||||
For example, if photo is .CR2 file, edited image may be .jpeg.
|
||||
If you provide an extension different than what the actual file is,
|
||||
export will print a warning but will export the photo using the
|
||||
incorrect file extension (unless use_photos_export is true, in which case export will
|
||||
use the extension provided by Photos upon export; in this case, an incorrect extension is
|
||||
silently ignored).
|
||||
e.g. to get the extension of the edited photo,
|
||||
reference PhotoInfo.path_edited</p>
|
||||
</div></blockquote>
|
||||
<dl class="simple">
|
||||
<dt>edited: (boolean, default=False); if True will export the edited version of the photo, otherwise exports the original version</dt><dd><p>(or raise exception if no edited version)</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>live_photo: (boolean, default=False); if True, will also export the associated .mov for live photos
|
||||
raw_photo: (boolean, default=False); if True, will also export the associated RAW photo
|
||||
export_as_hardlink: (boolean, default=False); if True, will hardlink files instead of copying them
|
||||
overwrite: (boolean, default=False); if True will overwrite files if they already exist
|
||||
increment: (boolean, default=True); if True, will increment file name until a non-existant name is found</p>
|
||||
<blockquote>
|
||||
<div><p>if overwrite=False and increment=False, export will fail if destination file already exists</p>
|
||||
</div></blockquote>
|
||||
<dl class="simple">
|
||||
<dt>sidecar_json: if set will write a json sidecar with data in format readable by exiftool</dt><dd><p>sidecar filename will be dest/filename.json; includes exiftool tag group names (e.g. <cite>exiftool -G -j</cite>)</p>
|
||||
</dd>
|
||||
<dt>sidecar_exiftool: if set will write a json sidecar with data in format readable by exiftool</dt><dd><p>sidecar filename will be dest/filename.json; does not include exiftool tag group names (e.g. <cite>exiftool -j</cite>)</p>
|
||||
</dd>
|
||||
<dt>sidecar_xmp: if set will write an XMP sidecar with IPTC data</dt><dd><p>sidecar filename will be dest/filename.xmp</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>use_photos_export: (boolean, default=False); if True will attempt to export photo via applescript interaction with Photos
|
||||
timeout: (int, default=120) timeout in seconds used with use_photos_export
|
||||
exiftool: (boolean, default = False); if True, will use exiftool to write metadata to export file
|
||||
returns list of full paths to the exported files
|
||||
use_albums_as_keywords: (boolean, default = False); if True, will include album names in keywords
|
||||
when exporting metadata with exiftool or sidecar
|
||||
use_persons_as_keywords: (boolean, default = False); if True, will include person names in keywords
|
||||
when exporting metadata with exiftool or sidecar
|
||||
keyword_template: (list of strings); list of template strings that will be rendered as used as keywords
|
||||
description_template: string; optional template string that will be rendered for use as photo description
|
||||
render_options: an optional osxphotos.phototemplate.RenderOptions instance with options to pass to template renderer</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Returns</dt>
|
||||
<dd class="field-odd"><p>list of photos exported</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.external_edit">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">external_edit</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.external_edit" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if picture was edited outside of Photos using external editor</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.face_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">face_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.face_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of FaceInfo objects for faces in picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.favorite">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">favorite</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.favorite" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>True if picture is marked as favorite</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.filename">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">filename</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.filename" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>filename of the picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.has_raw">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">has_raw</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.has_raw" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns True if photo has an associated raw image (that is, it’s a RAW+JPEG pair), otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.hasadjustments">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">hasadjustments</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.hasadjustments" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>True if picture has adjustments / edits</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.hdr">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">hdr</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.hdr" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is an HDR photo, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.height">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">height</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.height" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns height of the current photo version in pixels</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.hidden">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">hidden</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.hidden" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>True if picture is hidden</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.import_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">import_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.import_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>ImportInfo object representing import session for the photo or None if no import session</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.incloud">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">incloud</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.incloud" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is cloud asset and is synched to cloud
|
||||
False if photo is cloud asset and not yet synched to cloud
|
||||
None if photo is not cloud asset</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.intrash">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">intrash</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.intrash" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>True if picture is in trash (‘Recently Deleted’ folder)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.iscloudasset">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">iscloudasset</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.iscloudasset" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a cloud asset (in an iCloud library),
|
||||
otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.ismissing">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">ismissing</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.ismissing" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns true if photo is missing from disk (which means it’s not been downloaded from iCloud)</p>
|
||||
<dl class="simple">
|
||||
<dt>NOTE: the photos.db database uses an asynchrounous write-ahead log so changes in Photos</dt><dd><p>do not immediately get written to disk. In particular, I’ve noticed that downloading
|
||||
an image from the cloud does not force the database to be updated until something else
|
||||
e.g. an edit, keyword, etc. occurs forcing a database synch
|
||||
The exact process / timing is a mystery to be but be aware that if some photos were recently
|
||||
downloaded from cloud to local storate their status in the database might still show
|
||||
isMissing = 1</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.ismovie">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">ismovie</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.ismovie" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if file is a movie, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.isphoto">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">isphoto</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.isphoto" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if file is an image, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.israw">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">israw</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.israw" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns True if photo is a raw image. For images with an associated RAW+JPEG pair, see has_raw</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.isreference">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">isreference</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.isreference" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a reference (not copied to the Photos library), otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.json">
|
||||
<span class="sig-name descname"><span class="pre">json</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoinfo.html#PhotoInfo.json"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoInfo.json" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Return JSON representation</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.keywords">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">keywords</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.keywords" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of keywords for picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.labels">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">labels</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.labels" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns list of labels applied to photo by Photos image categorization
|
||||
only valid on Photos 5, on older libraries returns empty list</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.labels_normalized">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">labels_normalized</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.labels_normalized" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns normalized list of labels applied to photo by Photos image categorization
|
||||
only valid on Photos 5, on older libraries returns empty list</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.likes">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">likes</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.likes" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns list of Like objects for any likes on the photo (sorted by date)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.live_photo">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">live_photo</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.live_photo" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a live photo, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.location">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">location</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.location" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns (latitude, longitude) as float in degrees or None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.moment">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">moment</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.moment" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Moment photo belongs to</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.orientation">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">orientation</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.orientation" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns EXIF orientation of the current photo version as int or 0 if current orientation cannot be determined</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.original_filename">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">original_filename</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.original_filename" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>original filename of the picture
|
||||
Photos 5 mangles filenames upon import</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.original_filesize">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">original_filesize</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.original_filesize" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns filesize of original photo in bytes as int</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.original_height">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">original_height</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.original_height" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns height of the original photo version in pixels</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.original_orientation">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">original_orientation</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.original_orientation" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns EXIF orientation of the original photo version as int</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.original_width">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">original_width</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.original_width" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns width of the original photo version in pixels</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.owner">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">owner</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.owner" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Return name of photo owner for shared photos (Photos 5+ only), or None if not shared</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.panorama">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">panorama</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.panorama" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a panorama, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.path">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">path</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.path" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>absolute path on disk of the original picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.path_derivatives">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">path_derivatives</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.path_derivatives" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Return any derivative (preview) images associated with the photo as a list of paths, sorted by file size (largest first)</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.path_edited">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">path_edited</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.path_edited" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>absolute path on disk of the edited picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.path_edited_live_photo">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">path_edited_live_photo</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.path_edited_live_photo" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>return path to edited version of live photo movie; only valid for Photos 5+</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.path_live_photo">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">path_live_photo</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.path_live_photo" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns path to the associated video file for a live photo
|
||||
If photo is not a live photo, returns None
|
||||
If photo is missing, returns None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.path_raw">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">path_raw</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.path_raw" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>absolute path of associated RAW image or None if there is not one</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.person_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">person_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.person_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of PersonInfo objects for person in picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.persons">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">persons</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.persons" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of persons in picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.place">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">place</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.place" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns PlaceInfo object containing reverse geolocation info</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.portrait">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">portrait</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.portrait" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a portrait, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.project_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">project_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.project_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>list of AlbumInfo objects representing projects for the photo or None if no projects</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.raw_original">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">raw_original</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.raw_original" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns True if associated raw image and the raw image is selected in Photos
|
||||
via “Use RAW as Original ”
|
||||
otherwise returns False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.render_template">
|
||||
<span class="sig-name descname"><span class="pre">render_template</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">template_str</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">options</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">osxphotos.phototemplate.RenderOptions</span><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoinfo.html#PhotoInfo.render_template"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoInfo.render_template" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Renders a template string for PhotoInfo instance using PhotoTemplate</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><ul class="simple">
|
||||
<li><p><strong>template_str</strong> – a template string with fields to render</p></li>
|
||||
<li><p><strong>options</strong> – a RenderOptions instance</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt class="field-even">Returns</dt>
|
||||
<dd class="field-even"><p>tuple of list of rendered strings and list of unmatched template values</p>
|
||||
</dd>
|
||||
<dt class="field-odd">Return type</dt>
|
||||
<dd class="field-odd"><p>([rendered_strings], [unmatched])</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.score">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">score</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.score" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Computed score information for a photo</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Returns</dt>
|
||||
<dd class="field-odd"><p>ScoreInfo instance</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.screenshot">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">screenshot</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.screenshot" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is an HDR photo, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.search_info">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">search_info</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.search_info" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns SearchInfo object for photo
|
||||
only valid on Photos 5, on older libraries, returns None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.search_info_normalized">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">search_info_normalized</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.search_info_normalized" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns SearchInfo object for photo that produces normalized results
|
||||
only valid on Photos 5, on older libraries, returns None</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.selfie">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">selfie</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.selfie" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a selfie (front facing camera), otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.shared">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">shared</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.shared" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns True if photos is in a shared iCloud album otherwise false
|
||||
Only valid on Photos 5; returns None on older versions</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.slow_mo">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">slow_mo</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.slow_mo" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a slow motion video, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.time_lapse">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">time_lapse</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.time_lapse" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns True if photo is a time lapse video, otherwise False</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.title">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">title</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.title" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>name / title of picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.tzoffset">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">tzoffset</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.tzoffset" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>timezone offset from UTC in seconds</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.uti">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">uti</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.uti" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns Uniform Type Identifier (UTI) for the image
|
||||
for example: public.jpeg or com.apple.quicktime-movie</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.uti_edited">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">uti_edited</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.uti_edited" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns Uniform Type Identifier (UTI) for the edited image
|
||||
if the photo has been edited, otherwise None;
|
||||
for example: public.jpeg</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.uti_original">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">uti_original</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.uti_original" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns Uniform Type Identifier (UTI) for the original image
|
||||
for example: public.jpeg or com.apple.quicktime-movie</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.uti_raw">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">uti_raw</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.uti_raw" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Returns Uniform Type Identifier (UTI) for the RAW image if there is one
|
||||
for example: com.canon.cr2-raw-image
|
||||
Returns None if no associated RAW image</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.uuid">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">uuid</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.uuid" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>UUID of picture</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.visible">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">visible</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.visible" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>True if picture is visble</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.width">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">width</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.width" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>returns width of the current photo version in pixels</p>
|
||||
</dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — osxphotos 0.45.10 documentation</title>
|
||||
<title>Search — osxphotos 0.46.6 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,4 +3,6 @@ osxphotos command line interface (CLI)
|
||||
|
||||
.. click:: osxphotos.cli:cli
|
||||
:prog: osxphotos
|
||||
:nested: full
|
||||
:nested: full
|
||||
|
||||
.. program-output:: python3 -m osxphotos --help
|
||||
@@ -16,7 +16,7 @@ import sys
|
||||
|
||||
import sphinx_rtd_theme
|
||||
|
||||
sys.path.insert(0, os.path.abspath(".."))
|
||||
sys.path.insert(0, os.path.abspath("../.."))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from ._constants import AlbumSortOrder
|
||||
from ._version import __version__
|
||||
from .exiftool import ExifTool
|
||||
from .export_db import ExportDB, ExportDBInMemory, ExportDBNoOp
|
||||
from .export_db import ExportDB
|
||||
from .fileutil import FileUtil, FileUtilNoOp
|
||||
from .momentinfo import MomentInfo
|
||||
from .personinfo import PersonInfo
|
||||
@@ -25,8 +25,7 @@ __all__ = [
|
||||
"CommentInfo",
|
||||
"ExifTool",
|
||||
"ExportDB",
|
||||
"ExportDBInMemory",
|
||||
"ExportDBNoOp",
|
||||
"ExportDBTemp",
|
||||
"ExportOptions",
|
||||
"ExportResults",
|
||||
"FileUtil",
|
||||
|
||||
@@ -103,6 +103,8 @@ _TESTED_OS_VERSIONS = [
|
||||
("11", "6"),
|
||||
("12", "0"),
|
||||
("12", "1"),
|
||||
("12", "2"),
|
||||
("12", "3"),
|
||||
]
|
||||
|
||||
# Photos 5 has persons who are empty string if unidentified face
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.45.10"
|
||||
__version__ = "0.46.6"
|
||||
|
||||
362
osxphotos/cli.py
362
osxphotos/cli.py
@@ -61,9 +61,20 @@ from .configoptions import (
|
||||
ConfigOptionsInvalidError,
|
||||
ConfigOptionsLoadError,
|
||||
)
|
||||
from .crash_reporter import crash_reporter
|
||||
from .datetime_formatter import DateTimeFormatter
|
||||
from .exiftool import get_exiftool_path
|
||||
from .export_db import ExportDB, ExportDBInMemory
|
||||
from .export_db_utils import (
|
||||
OSXPHOTOS_EXPORTDB_VERSION,
|
||||
export_db_check_signatures,
|
||||
export_db_get_last_run,
|
||||
export_db_get_version,
|
||||
export_db_save_config_to_file,
|
||||
export_db_touch_files,
|
||||
export_db_update_signatures,
|
||||
export_db_vacuum,
|
||||
)
|
||||
from .fileutil import FileUtil, FileUtilNoOp
|
||||
from .path_utils import is_valid_filepath, sanitize_filename, sanitize_filepath
|
||||
from .photoexporter import ExportOptions, ExportResults, PhotoExporter
|
||||
@@ -135,12 +146,19 @@ __all__ = [
|
||||
VERBOSE = False
|
||||
VERBOSE_TIMESTAMP = False
|
||||
|
||||
# global variable to control debug output
|
||||
# set via --debug
|
||||
DEBUG = False
|
||||
|
||||
# used to show/hide hidden commands
|
||||
OSXPHOTOS_HIDDEN = not bool(os.getenv("OSXPHOTOS_SHOW_HIDDEN", default=False))
|
||||
|
||||
# used by snap and diff commands
|
||||
OSXPHOTOS_SNAPSHOT_DIR = "/private/tmp/osxphotos_snapshots"
|
||||
|
||||
# where to write the crash report if osxphotos crashes
|
||||
OSXPHOTOS_CRASH_LOG = os.getcwd() + "/osxphotos_crash.log"
|
||||
|
||||
rich.traceback.install()
|
||||
|
||||
|
||||
@@ -266,6 +284,24 @@ class FunctionCall(click.ParamType):
|
||||
return (function, value)
|
||||
|
||||
|
||||
class ExportDBType(click.ParamType):
|
||||
|
||||
name = "EXPORTDB"
|
||||
|
||||
def convert(self, value, param, ctx):
|
||||
try:
|
||||
export_db_name = pathlib.Path(value)
|
||||
if export_db_name.is_dir():
|
||||
raise click.BadParameter(f"{value} is a directory")
|
||||
if export_db_name.is_file():
|
||||
# verify it's actually an osxphotos export_db
|
||||
# export_db_get_version will raise an error if it's not valid
|
||||
osxphotos_ver, export_db_ver = export_db_get_version(value)
|
||||
return value
|
||||
except Exception:
|
||||
self.fail(f"{value} exists but is not a valid osxphotos export database. ")
|
||||
|
||||
|
||||
class IncompatibleQueryOptions(Exception):
|
||||
pass
|
||||
|
||||
@@ -674,7 +710,7 @@ def QUERY_OPTIONS(f):
|
||||
@click.version_option(__version__, "--version", "-v")
|
||||
@click.pass_context
|
||||
def cli(ctx, db, json_, debug):
|
||||
ctx.obj = CLI_Obj(db=db, json=json_, debug=debug)
|
||||
ctx.obj = CLI_Obj(db=db, json=json_)
|
||||
|
||||
|
||||
@cli.command(cls=ExportCommand)
|
||||
@@ -1152,7 +1188,14 @@ def cli(ctx, db, json_, debug):
|
||||
f"If --exportdb is not specified, export database will be saved to '{OSXPHOTOS_EXPORT_DB}' "
|
||||
"in the export directory. If --exportdb is specified, it will be saved to the specified file. "
|
||||
),
|
||||
type=click.Path(),
|
||||
type=ExportDBType(),
|
||||
)
|
||||
@click.option(
|
||||
"--ramdb",
|
||||
is_flag=True,
|
||||
help="Copy export database to memory during export; "
|
||||
"may improve performance when exporting over a network or slow disk but could result in "
|
||||
"losing update state information if the program is interrupted or crashes.",
|
||||
)
|
||||
@click.option(
|
||||
"--load-config",
|
||||
@@ -1174,9 +1217,15 @@ def cli(ctx, db, json_, debug):
|
||||
required=False,
|
||||
metavar="<config file path>",
|
||||
default=None,
|
||||
help=("Save options to file for use with --load-config. File format is TOML."),
|
||||
help="Save options to file for use with --load-config. File format is TOML. "
|
||||
"See also --config-only.",
|
||||
type=click.Path(),
|
||||
)
|
||||
@click.option(
|
||||
"--config-only",
|
||||
is_flag=True,
|
||||
help="If specified, saves the config file but does not export any files; must be used with --save-config.",
|
||||
)
|
||||
@click.option(
|
||||
"--beta",
|
||||
is_flag=True,
|
||||
@@ -1205,10 +1254,25 @@ def cli(ctx, db, json_, debug):
|
||||
f"Can be specified multiple times. Valid options are: {PROFILE_SORT_KEYS}. "
|
||||
"Default = 'cumulative'.",
|
||||
)
|
||||
@click.option(
|
||||
"--debug",
|
||||
required=False,
|
||||
is_flag=True,
|
||||
default=False,
|
||||
hidden=OSXPHOTOS_HIDDEN,
|
||||
help="Enable debug output.",
|
||||
)
|
||||
@DB_ARGUMENT
|
||||
@click.argument("dest", nargs=1, type=click.Path(exists=True))
|
||||
@click.pass_obj
|
||||
@click.pass_context
|
||||
@crash_reporter(
|
||||
OSXPHOTOS_CRASH_LOG,
|
||||
"[red]Something went wrong and osxphotos encountered an error:[/red]",
|
||||
"osxphotos crash log",
|
||||
"Please file a bug report at https://github.com/RhetTbull/osxphotos/issues with the crash log attached.",
|
||||
f"osxphotos version: {__version__}",
|
||||
)
|
||||
def export(
|
||||
ctx,
|
||||
cli_obj,
|
||||
@@ -1326,8 +1390,10 @@ def export(
|
||||
add_skipped_to_album,
|
||||
add_missing_to_album,
|
||||
exportdb,
|
||||
ramdb,
|
||||
load_config,
|
||||
save_config,
|
||||
config_only,
|
||||
is_reference,
|
||||
beta,
|
||||
in_album,
|
||||
@@ -1347,6 +1413,7 @@ def export(
|
||||
preview_if_missing,
|
||||
profile,
|
||||
profile_sort,
|
||||
debug,
|
||||
):
|
||||
"""Export photos from the Photos database.
|
||||
Export path DEST is required.
|
||||
@@ -1360,6 +1427,11 @@ def export(
|
||||
to modify this behavior.
|
||||
"""
|
||||
|
||||
global DEBUG
|
||||
if debug:
|
||||
DEBUG = True
|
||||
osxphotos._set_debug(True)
|
||||
|
||||
if profile:
|
||||
click.echo("Profiling...")
|
||||
profile_sort = profile_sort or ["cumulative"]
|
||||
@@ -1384,7 +1456,7 @@ def export(
|
||||
cfg = ConfigOptions(
|
||||
"export",
|
||||
locals(),
|
||||
ignore=["ctx", "cli_obj", "dest", "load_config", "save_config"],
|
||||
ignore=["ctx", "cli_obj", "dest", "load_config", "save_config", "config_only"],
|
||||
)
|
||||
|
||||
global VERBOSE
|
||||
@@ -1403,7 +1475,7 @@ def export(
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
# re-set the local vars to the corresponding config value
|
||||
# this isn't elegant but avoids having to rewrite this function to use cfg.varname for every parameter
|
||||
@@ -1437,6 +1509,7 @@ def export(
|
||||
export_as_hardlink = cfg.export_as_hardlink
|
||||
export_by_date = cfg.export_by_date
|
||||
exportdb = cfg.exportdb
|
||||
ramdb = cfg.ramdb
|
||||
external_edit = cfg.external_edit
|
||||
favorite = cfg.favorite
|
||||
filename_template = cfg.filename_template
|
||||
@@ -1589,7 +1662,15 @@ def export(
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
if config_only and not save_config:
|
||||
click.secho(
|
||||
"--config-only must be used with --save-config",
|
||||
fg=CLI_COLOR_ERROR,
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
if all(x in [s.lower() for s in sidecar] for x in ["json", "exiftool"]):
|
||||
click.echo(
|
||||
@@ -1599,7 +1680,7 @@ def export(
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
if xattr_template:
|
||||
for attr, _ in xattr_template:
|
||||
@@ -1612,11 +1693,14 @@ def export(
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
if save_config:
|
||||
verbose_(f"Saving options to file {save_config}")
|
||||
verbose_(f"Saving options to config file '{save_config}'")
|
||||
cfg.write_to_file(save_config)
|
||||
if config_only:
|
||||
click.echo(f"Saved config file to '{save_config}'")
|
||||
sys.exit(0)
|
||||
|
||||
# set defaults for options that need them
|
||||
jpeg_quality = DEFAULT_JPEG_QUALITY if jpeg_quality is None else jpeg_quality
|
||||
@@ -1633,7 +1717,7 @@ def export(
|
||||
click.echo(
|
||||
click.style(f"DEST {dest} must be valid path", fg=CLI_COLOR_ERROR), err=True
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
dest = str(pathlib.Path(dest).resolve())
|
||||
|
||||
@@ -1644,7 +1728,7 @@ def export(
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
# if use_photokit and not check_photokit_authorization():
|
||||
# click.echo(
|
||||
@@ -1727,7 +1811,7 @@ def export(
|
||||
)
|
||||
)
|
||||
|
||||
# open export database and assign copy/link/unlink functions
|
||||
# open export database
|
||||
export_db_path = exportdb or os.path.join(dest, OSXPHOTOS_EXPORT_DB)
|
||||
|
||||
# check that export isn't in the parent or child of a previously exported library
|
||||
@@ -1754,7 +1838,11 @@ def export(
|
||||
export_db = ExportDBInMemory(dbfile=export_db_path, export_dir=dest)
|
||||
fileutil = FileUtilNoOp
|
||||
else:
|
||||
export_db = ExportDB(dbfile=export_db_path, export_dir=dest)
|
||||
export_db = (
|
||||
ExportDBInMemory(dbfile=export_db_path, export_dir=dest)
|
||||
if ramdb
|
||||
else ExportDB(dbfile=export_db_path, export_dir=dest)
|
||||
)
|
||||
fileutil = FileUtil
|
||||
|
||||
if verbose_:
|
||||
@@ -1768,6 +1856,9 @@ def export(
|
||||
f"Upgraded export database {export_db_path} from version {upgraded[0]} to {upgraded[1]}"
|
||||
)
|
||||
|
||||
# save config to export_db
|
||||
export_db.set_config(cfg.write_to_str())
|
||||
|
||||
photosdb = osxphotos.PhotosDB(dbfile=db, verbose=verbose_, exiftool=exiftool_path)
|
||||
|
||||
# enable beta features if requested
|
||||
@@ -2134,6 +2225,10 @@ def export(
|
||||
verbose_(f"Writing export report to {report}")
|
||||
write_export_report(report, results)
|
||||
|
||||
# close export_db and write changes if needed
|
||||
if ramdb and not dry_run:
|
||||
verbose_(f"Writing export database changes back to {export_db.path}")
|
||||
export_db.write_to_disk()
|
||||
export_db.close()
|
||||
|
||||
|
||||
@@ -2203,6 +2298,9 @@ def help(ctx, topic, **kw):
|
||||
"This only works if the Photos library being queried is the last-opened (default) library in Photos. "
|
||||
"This feature is currently experimental. I don't know how well it will work on large query sets.",
|
||||
)
|
||||
@click.option(
|
||||
"--debug", required=False, is_flag=True, default=False, hidden=OSXPHOTOS_HIDDEN
|
||||
)
|
||||
@DB_ARGUMENT
|
||||
@click.pass_obj
|
||||
@click.pass_context
|
||||
@@ -2287,12 +2385,18 @@ def query(
|
||||
query_eval,
|
||||
query_function,
|
||||
add_to_album,
|
||||
debug,
|
||||
):
|
||||
"""Query the Photos database using 1 or more search options;
|
||||
if more than one option is provided, they are treated as "AND"
|
||||
(e.g. search for photos matching all options).
|
||||
"""
|
||||
|
||||
global DEBUG
|
||||
if debug:
|
||||
DEBUG = True
|
||||
osxphotos._set_debug(True)
|
||||
|
||||
# if no query terms, show help and return
|
||||
# sanity check input args
|
||||
nonexclusive = [
|
||||
@@ -3148,6 +3252,9 @@ def export_photo_to_directory(
|
||||
f"Retrying export for photo ({photo.uuid}: {photo.original_filename})"
|
||||
)
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
# if debug mode, don't swallow the exceptions
|
||||
raise e
|
||||
click.echo(
|
||||
click.style(
|
||||
f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {filename}: {e}",
|
||||
@@ -3516,7 +3623,7 @@ def write_export_report(report_file, results):
|
||||
click.style("Could not open output file for writing", fg=CLI_COLOR_ERROR),
|
||||
err=True,
|
||||
)
|
||||
raise click.Abort()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cleanup_files(dest_path, files_to_keep, fileutil):
|
||||
@@ -4671,6 +4778,233 @@ def run(python_file):
|
||||
run_path(python_file, run_name="__main__")
|
||||
|
||||
|
||||
@cli.command(name="exportdb", hidden=OSXPHOTOS_HIDDEN)
|
||||
@click.option("--version", is_flag=True, help="Print export database version and exit.")
|
||||
@click.option("--vacuum", is_flag=True, help="Run VACUUM to defragment the database.")
|
||||
@click.option(
|
||||
"--check-signatures",
|
||||
is_flag=True,
|
||||
help="Check signatures for all exported photos in the database to find signatures that don't match.",
|
||||
)
|
||||
@click.option(
|
||||
"--update-signatures",
|
||||
is_flag=True,
|
||||
help="Update signatures for all exported photos in the database to match on-disk signatures.",
|
||||
)
|
||||
@click.option(
|
||||
"--touch-file",
|
||||
is_flag=True,
|
||||
help="Touch files on disk to match created date in Photos library and update export database signatures",
|
||||
)
|
||||
@click.option(
|
||||
"--last-run",
|
||||
is_flag=True,
|
||||
help="Show last run osxphotos commands used with this database.",
|
||||
)
|
||||
@click.option(
|
||||
"--save-config",
|
||||
metavar="CONFIG_FILE",
|
||||
help="Save last run configuration to TOML file for use by --load-config.",
|
||||
)
|
||||
@click.option(
|
||||
"--info",
|
||||
metavar="FILE_PATH",
|
||||
nargs=1,
|
||||
help="Print information about FILE_PATH contained in the database.",
|
||||
)
|
||||
@click.option(
|
||||
"--migrate",
|
||||
is_flag=True,
|
||||
help="Migrate (if needed) export database to current version.",
|
||||
)
|
||||
@click.option(
|
||||
"--sql",
|
||||
metavar="SQL_STATEMENT",
|
||||
help="Execute SQL_STATEMENT against export database and print results.",
|
||||
)
|
||||
@click.option(
|
||||
"--export-dir",
|
||||
help="Optional path to export directory (if not parent of export database).",
|
||||
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
||||
)
|
||||
@click.option("--verbose", "-V", is_flag=True, help="Print verbose output.")
|
||||
@click.option(
|
||||
"--dry-run",
|
||||
is_flag=True,
|
||||
help="Run in dry-run mode (don't actually update files), e.g. for use with --update-signatures.",
|
||||
)
|
||||
@click.argument("export_db", metavar="EXPORT_DATABASE", type=click.Path(exists=True))
|
||||
def exportdb(
|
||||
version,
|
||||
vacuum,
|
||||
check_signatures,
|
||||
update_signatures,
|
||||
touch_file,
|
||||
last_run,
|
||||
save_config,
|
||||
info,
|
||||
migrate,
|
||||
sql,
|
||||
export_dir,
|
||||
verbose,
|
||||
dry_run,
|
||||
export_db,
|
||||
):
|
||||
"""Utilities for working with the osxphotos export database"""
|
||||
export_db = pathlib.Path(export_db)
|
||||
if export_db.is_dir():
|
||||
# assume it's the export folder
|
||||
export_db = export_db / OSXPHOTOS_EXPORT_DB
|
||||
if not export_db.is_file():
|
||||
print(
|
||||
f"[red]Error: {OSXPHOTOS_EXPORT_DB} missing from {export_db.parent}[/red]"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
export_dir = export_dir or export_db.parent
|
||||
|
||||
sub_commands = [
|
||||
version,
|
||||
check_signatures,
|
||||
update_signatures,
|
||||
touch_file,
|
||||
last_run,
|
||||
bool(save_config),
|
||||
bool(info),
|
||||
migrate,
|
||||
bool(sql),
|
||||
]
|
||||
if sum(sub_commands) > 1:
|
||||
print(f"[red]Only a single sub-command may be specified at a time[/red]")
|
||||
sys.exit(1)
|
||||
|
||||
if version:
|
||||
try:
|
||||
osxphotos_ver, export_db_ver = export_db_get_version(export_db)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: could not read version from {export_db}: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(
|
||||
f"osxphotos version: {osxphotos_ver}, export database version: {export_db_ver}"
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
if vacuum:
|
||||
try:
|
||||
start_size = pathlib.Path(export_db).stat().st_size
|
||||
export_db_vacuum(export_db)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(
|
||||
f"Vacuumed {export_db}! {start_size} bytes -> {pathlib.Path(export_db).stat().st_size} bytes"
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
if update_signatures:
|
||||
try:
|
||||
updated, skipped = export_db_update_signatures(
|
||||
export_db, export_dir, verbose, dry_run
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"Done. Updated {updated} files, skipped {skipped} files.")
|
||||
sys.exit(0)
|
||||
|
||||
if last_run:
|
||||
try:
|
||||
last_run_info = export_db_get_last_run(export_db)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"last run at {last_run_info[0]}:")
|
||||
print(f"osxphotos {last_run_info[1]}")
|
||||
sys.exit(0)
|
||||
|
||||
if save_config:
|
||||
try:
|
||||
export_db_save_config_to_file(export_db, save_config)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"Saved configuration to {save_config}")
|
||||
sys.exit(0)
|
||||
|
||||
if check_signatures:
|
||||
try:
|
||||
matched, notmatched, skipped = export_db_check_signatures(
|
||||
export_db, export_dir, verbose=verbose
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(
|
||||
f"Done. Found {matched} matching signatures and {notmatched} signatures that don't match. Skipped {skipped} missing files."
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
if touch_file:
|
||||
try:
|
||||
touched, not_touched, skipped = export_db_touch_files(
|
||||
export_db, export_dir, verbose=verbose, dry_run=dry_run
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(
|
||||
f"Done. Touched {touched} files, skipped {not_touched} up to date files, skipped {skipped} missing files."
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
if info:
|
||||
exportdb = ExportDB(export_db, export_dir)
|
||||
try:
|
||||
info_rec = exportdb.get_file_record(info)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
if info_rec:
|
||||
print(info_rec.asdict())
|
||||
else:
|
||||
print(f"[red]File '{info}' not found in export database[/red]")
|
||||
sys.exit(0)
|
||||
|
||||
if migrate:
|
||||
exportdb = ExportDB(export_db, export_dir)
|
||||
upgraded = exportdb.was_upgraded
|
||||
if upgraded:
|
||||
print(
|
||||
f"Migrated export database {export_db} from version {upgraded[0]} to {upgraded[1]}"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"Export database {export_db} is already at latest version {OSXPHOTOS_EXPORTDB_VERSION}"
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
if sql:
|
||||
exportdb = ExportDB(export_db, export_dir)
|
||||
try:
|
||||
c = exportdb._conn.cursor()
|
||||
results = c.execute(sql)
|
||||
except Exception as e:
|
||||
print(f"[red]Error: {e}[/red]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
for row in results:
|
||||
print(row)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def _query_options_from_kwargs(**kwargs) -> QueryOptions:
|
||||
"""Validate query options and create a QueryOptions instance"""
|
||||
# sanity check input args
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
""" ConfigOptions class to load/save config settings for osxphotos CLI """
|
||||
import bitmath
|
||||
import toml
|
||||
|
||||
__all__ = [
|
||||
@@ -134,18 +135,12 @@ class ConfigOptions:
|
||||
filename: full path to TOML file to write; filename will be overwritten if it exists
|
||||
"""
|
||||
# todo: add overwrite and option to merge contents already in TOML file (under different [section] with new content)
|
||||
data = {}
|
||||
for attr in sorted(self._attrs.keys()):
|
||||
val = getattr(self, attr)
|
||||
if val in [False, ()]:
|
||||
val = None
|
||||
else:
|
||||
val = list(val) if type(val) == tuple else val
|
||||
|
||||
data[attr] = val
|
||||
|
||||
with open(filename, "w") as fd:
|
||||
toml.dump({self._name: data}, fd)
|
||||
toml.dump(self._get_toml_dict(), fd)
|
||||
|
||||
def write_to_str(self) -> str:
|
||||
"""Write self to TOML str"""
|
||||
return toml.dumps(self._get_toml_dict())
|
||||
|
||||
def load_from_file(self, filename, override=False):
|
||||
"""Load options from a TOML file.
|
||||
@@ -178,3 +173,21 @@ class ConfigOptions:
|
||||
|
||||
def asdict(self):
|
||||
return {attr: getattr(self, attr) for attr in sorted(self._attrs.keys())}
|
||||
|
||||
def _get_toml_dict(self):
|
||||
"""Return dict for writing to TOML file"""
|
||||
data = {}
|
||||
for attr in sorted(self._attrs.keys()):
|
||||
val = getattr(self, attr)
|
||||
|
||||
if isinstance(val, bitmath.Bitmath):
|
||||
val = int(val.to_Byte())
|
||||
|
||||
if val in [False, ()]:
|
||||
val = None
|
||||
else:
|
||||
val = list(val) if type(val) == tuple else val
|
||||
|
||||
data[attr] = val
|
||||
|
||||
return {self._name: data}
|
||||
|
||||
46
osxphotos/crash_reporter.py
Normal file
46
osxphotos/crash_reporter.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Error logger/crash reporter decorator"""
|
||||
|
||||
import datetime
|
||||
import functools
|
||||
import platform
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from rich import print
|
||||
|
||||
|
||||
def crash_reporter(filename, message, title, postamble, *extra_args):
|
||||
"""Create a crash dump file on error named filename
|
||||
|
||||
On error, create a crash dump file named filename with exception and stack trace.
|
||||
message is printed to stderr
|
||||
title is printed at beginning of crash dump file
|
||||
postamble is printed to stderr after crash dump file is created
|
||||
If extra_args is not None, any additional arguments to the function will be printed to the file.
|
||||
"""
|
||||
|
||||
def decorated(func):
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
print(message, file=sys.stderr)
|
||||
print(f"[red]{e}[/red]", file=sys.stderr)
|
||||
with open(filename, "w") as f:
|
||||
f.write(f"{title}\n")
|
||||
f.write(f"Created: {datetime.datetime.now()}\n")
|
||||
f.write(f"Python version: {sys.version}\n")
|
||||
f.write(f"Platform: {platform.platform()}\n")
|
||||
f.write(f"sys.argv: {sys.argv}\n")
|
||||
for arg in extra_args:
|
||||
f.write(f"{arg}\n")
|
||||
f.write(f"Error: {e}\n")
|
||||
traceback.print_exc(file=f)
|
||||
print(f"Crash log written to '{filename}'", file=sys.stderr)
|
||||
print(f"{postamble}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
return wrapped
|
||||
|
||||
return decorated
|
||||
@@ -69,6 +69,8 @@ def unescape_str(s):
|
||||
"""unescape an HTML string returned by exiftool -E"""
|
||||
if type(s) != str:
|
||||
return s
|
||||
# avoid " in values which result in json.loads() throwing an exception, #636
|
||||
s = s.replace(""", '\\"')
|
||||
return html.unescape(s)
|
||||
|
||||
|
||||
@@ -105,7 +107,8 @@ class _ExifToolProc:
|
||||
|
||||
def __init__(self, exiftool=None):
|
||||
"""construct _ExifToolProc singleton object or return instance of already created object
|
||||
exiftool: optional path to exiftool binary (if not provided, will search path to find it)"""
|
||||
exiftool: optional path to exiftool binary (if not provided, will search path to find it)
|
||||
"""
|
||||
|
||||
if hasattr(self, "_process_running") and self._process_running:
|
||||
# already running
|
||||
@@ -115,7 +118,6 @@ class _ExifToolProc:
|
||||
f"ignoring exiftool={exiftool}"
|
||||
)
|
||||
return
|
||||
|
||||
self._process_running = False
|
||||
self._exiftool = exiftool or get_exiftool_path()
|
||||
self._start_proc()
|
||||
@@ -147,6 +149,9 @@ class _ExifToolProc:
|
||||
return
|
||||
|
||||
# open exiftool process
|
||||
# make sure /usr/bin at start of path so exiftool can find xattr (see #636)
|
||||
env = os.environ.copy()
|
||||
env["PATH"] = f'/usr/bin/:{env["PATH"]}'
|
||||
self._process = subprocess.Popen(
|
||||
[
|
||||
self._exiftool,
|
||||
@@ -163,6 +168,7 @@ class _ExifToolProc:
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
env=env,
|
||||
)
|
||||
self._process_running = True
|
||||
|
||||
@@ -362,6 +368,7 @@ class ExifTool:
|
||||
error = "" if error == b"" else error.decode("utf-8")
|
||||
self.warning = warning
|
||||
self.error = error
|
||||
|
||||
return output[:-EXIFTOOL_STAYOPEN_EOF_LEN], warning, error
|
||||
|
||||
@property
|
||||
@@ -393,6 +400,7 @@ class ExifTool:
|
||||
except Exception as e:
|
||||
# will fail with some commands, e.g --ext AVI which produces
|
||||
# 'No file with specified extension' instead of json
|
||||
logging.warning(f"error loading json returned by exiftool: {e} {json_str}")
|
||||
return dict()
|
||||
exifdict = exifdict[0]
|
||||
if not tag_groups:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
264
osxphotos/export_db_utils.py
Normal file
264
osxphotos/export_db_utils.py
Normal file
@@ -0,0 +1,264 @@
|
||||
""" Utility functions for working with export_db """
|
||||
|
||||
|
||||
import pathlib
|
||||
import sqlite3
|
||||
from typing import Optional, Tuple, Union
|
||||
import datetime
|
||||
import os
|
||||
|
||||
import toml
|
||||
from rich import print
|
||||
|
||||
from ._constants import OSXPHOTOS_EXPORT_DB
|
||||
from ._version import __version__
|
||||
from .export_db import OSXPHOTOS_EXPORTDB_VERSION, ExportDB
|
||||
from .fileutil import FileUtil
|
||||
from .photosdb import PhotosDB
|
||||
|
||||
__all__ = [
|
||||
"export_db_check_signatures",
|
||||
"export_db_get_last_run",
|
||||
"export_db_get_version",
|
||||
"export_db_save_config_to_file",
|
||||
"export_db_touch_files",
|
||||
"export_db_update_signatures",
|
||||
"export_db_vacuum",
|
||||
]
|
||||
|
||||
|
||||
def isotime_from_ts(ts: int) -> str:
|
||||
"""Convert timestamp to ISO 8601 time string"""
|
||||
return datetime.datetime.fromtimestamp(ts).isoformat()
|
||||
|
||||
|
||||
def export_db_get_version(
|
||||
dbfile: Union[str, pathlib.Path]
|
||||
) -> Tuple[Optional[int], Optional[int]]:
|
||||
"""returns version from export database as tuple of (osxphotos version, export_db version)"""
|
||||
conn = sqlite3.connect(str(dbfile))
|
||||
c = conn.cursor()
|
||||
row = c.execute(
|
||||
"SELECT osxphotos, exportdb FROM version ORDER BY id DESC LIMIT 1;"
|
||||
).fetchone()
|
||||
if row:
|
||||
return (row[0], row[1])
|
||||
return (None, None)
|
||||
|
||||
|
||||
def export_db_vacuum(dbfile: Union[str, pathlib.Path]) -> None:
|
||||
"""Vacuum export database"""
|
||||
conn = sqlite3.connect(str(dbfile))
|
||||
c = conn.cursor()
|
||||
c.execute("VACUUM;")
|
||||
conn.commit()
|
||||
|
||||
|
||||
def export_db_update_signatures(
|
||||
dbfile: Union[str, pathlib.Path],
|
||||
export_dir: Union[str, pathlib.Path],
|
||||
verbose: bool = False,
|
||||
dry_run: bool = False,
|
||||
) -> Tuple[int, int]:
|
||||
"""Update signatures for all files found in the export database to match what's on disk
|
||||
|
||||
Returns: tuple of (updated, skipped)
|
||||
"""
|
||||
export_dir = pathlib.Path(export_dir)
|
||||
fileutil = FileUtil
|
||||
conn = sqlite3.connect(str(dbfile))
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT filepath_normalized, filepath FROM export_data;")
|
||||
rows = c.fetchall()
|
||||
updated = 0
|
||||
skipped = 0
|
||||
for row in rows:
|
||||
filepath_normalized = row[0]
|
||||
filepath = row[1]
|
||||
filepath = export_dir / filepath
|
||||
if not os.path.exists(filepath):
|
||||
skipped += 1
|
||||
if verbose:
|
||||
print(f"[dark_orange]Skipping missing file[/dark_orange]: '{filepath}'")
|
||||
continue
|
||||
updated += 1
|
||||
file_sig = fileutil.file_sig(filepath)
|
||||
if verbose:
|
||||
print(f"[green]Updating signature for[/green]: '{filepath}'")
|
||||
if not dry_run:
|
||||
c.execute(
|
||||
"UPDATE export_data SET dest_mode = ?, dest_size = ?, dest_mtime = ? WHERE filepath_normalized = ?;",
|
||||
(file_sig[0], file_sig[1], file_sig[2], filepath_normalized),
|
||||
)
|
||||
|
||||
if not dry_run:
|
||||
conn.commit()
|
||||
|
||||
return (updated, skipped)
|
||||
|
||||
|
||||
def export_db_get_last_run(
|
||||
export_db: Union[str, pathlib.Path]
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""Get last run from export database"""
|
||||
conn = sqlite3.connect(str(export_db))
|
||||
c = conn.cursor()
|
||||
row = c.execute(
|
||||
"SELECT datetime, args FROM runs ORDER BY id DESC LIMIT 1;"
|
||||
).fetchone()
|
||||
if row:
|
||||
return row[0], row[1]
|
||||
return None, None
|
||||
|
||||
|
||||
def export_db_save_config_to_file(
|
||||
export_db: Union[str, pathlib.Path], config_file: Union[str, pathlib.Path]
|
||||
) -> None:
|
||||
"""Save export_db last run config to file"""
|
||||
export_db = pathlib.Path(export_db)
|
||||
config_file = pathlib.Path(config_file)
|
||||
conn = sqlite3.connect(str(export_db))
|
||||
c = conn.cursor()
|
||||
row = c.execute("SELECT config FROM config ORDER BY id DESC LIMIT 1;").fetchone()
|
||||
if not row:
|
||||
return ValueError("No config found in export_db")
|
||||
with config_file.open("w") as f:
|
||||
f.write(row[0])
|
||||
|
||||
|
||||
def export_db_check_signatures(
|
||||
dbfile: Union[str, pathlib.Path],
|
||||
export_dir: Union[str, pathlib.Path],
|
||||
verbose: bool = False,
|
||||
) -> Tuple[int, int, int]:
|
||||
"""Check signatures for all files found in the export database to verify what matches the on disk files
|
||||
|
||||
Returns: tuple of (updated, skipped)
|
||||
"""
|
||||
export_dir = pathlib.Path(export_dir)
|
||||
fileutil = FileUtil
|
||||
conn = sqlite3.connect(str(dbfile))
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT filepath_normalized, filepath FROM export_data;")
|
||||
rows = c.fetchall()
|
||||
exportdb = ExportDB(dbfile, export_dir)
|
||||
matched = 0
|
||||
notmatched = 0
|
||||
skipped = 0
|
||||
for row in rows:
|
||||
filepath_normalized = row[0]
|
||||
filepath = row[1]
|
||||
filepath = export_dir / filepath
|
||||
if not filepath.exists():
|
||||
skipped += 1
|
||||
if verbose:
|
||||
print(f"[dark_orange]Skipping missing file[/dark_orange]: '{filepath}'")
|
||||
continue
|
||||
file_sig = fileutil.file_sig(filepath)
|
||||
file_rec = exportdb.get_file_record(filepath)
|
||||
if file_rec.dest_sig == file_sig:
|
||||
matched += 1
|
||||
if verbose:
|
||||
print(f"[green]Signatures matched[/green]: '{filepath}'")
|
||||
else:
|
||||
notmatched += 1
|
||||
if verbose:
|
||||
print(f"[deep_pink3]Signatures do not match[/deep_pink3]: '{filepath}'")
|
||||
|
||||
return (matched, notmatched, skipped)
|
||||
|
||||
|
||||
def export_db_touch_files(
|
||||
dbfile: Union[str, pathlib.Path],
|
||||
export_dir: Union[str, pathlib.Path],
|
||||
verbose: bool = False,
|
||||
dry_run: bool = False,
|
||||
) -> Tuple[int, int, int]:
|
||||
"""Touch files on disk to match the Photos library created date
|
||||
|
||||
Returns: tuple of (touched, not_touched, skipped)
|
||||
"""
|
||||
export_dir = pathlib.Path(export_dir)
|
||||
|
||||
# open and close exportdb to ensure it gets migrated
|
||||
exportdb = ExportDB(dbfile, export_dir)
|
||||
upgraded = exportdb.was_upgraded
|
||||
if upgraded and verbose:
|
||||
print(
|
||||
f"Upgraded export database {dbfile} from version {upgraded[0]} to {upgraded[1]}"
|
||||
)
|
||||
exportdb.close()
|
||||
|
||||
conn = sqlite3.connect(str(dbfile))
|
||||
c = conn.cursor()
|
||||
# get most recent config
|
||||
row = c.execute("SELECT config FROM config ORDER BY id DESC LIMIT 1;").fetchone()
|
||||
if row:
|
||||
config = toml.loads(row[0])
|
||||
try:
|
||||
photos_db_path = config["export"].get("db", None)
|
||||
except KeyError:
|
||||
photos_db_path = None
|
||||
else:
|
||||
# TODO: parse the runs table to get the last --db
|
||||
# in the mean time, photos_db_path = None will use the default library
|
||||
photos_db_path = None
|
||||
|
||||
verbose_ = print if verbose else lambda *args, **kwargs: None
|
||||
photosdb = PhotosDB(dbfile=photos_db_path, verbose=verbose_)
|
||||
exportdb = ExportDB(dbfile, export_dir)
|
||||
c.execute(
|
||||
"SELECT filepath_normalized, filepath, uuid, dest_mode, dest_size FROM export_data;"
|
||||
)
|
||||
rows = c.fetchall()
|
||||
touched = 0
|
||||
not_touched = 0
|
||||
skipped = 0
|
||||
for row in rows:
|
||||
filepath_normalized = row[0]
|
||||
filepath = row[1]
|
||||
filepath = export_dir / filepath
|
||||
uuid = row[2]
|
||||
dest_mode = row[3]
|
||||
dest_size = row[4]
|
||||
if not filepath.exists():
|
||||
skipped += 1
|
||||
if verbose:
|
||||
print(
|
||||
f"[dark_orange]Skipping missing file (not in export directory)[/dark_orange]: '{filepath}'"
|
||||
)
|
||||
continue
|
||||
|
||||
photo = photosdb.get_photo(uuid)
|
||||
if not photo:
|
||||
skipped += 1
|
||||
if verbose:
|
||||
print(
|
||||
f"[dark_orange]Skipping missing photo (did not find in Photos Library)[/dark_orange]: '{filepath}' ({uuid})"
|
||||
)
|
||||
continue
|
||||
|
||||
ts = int(photo.date.timestamp())
|
||||
stat = os.stat(str(filepath))
|
||||
mtime = stat.st_mtime
|
||||
if mtime == ts:
|
||||
not_touched += 1
|
||||
if verbose:
|
||||
print(
|
||||
f"[green]Skipping file (timestamp matches)[/green]: '{filepath}' [dodger_blue1]{isotime_from_ts(ts)} ({ts})[/dodger_blue1]"
|
||||
)
|
||||
continue
|
||||
|
||||
touched += 1
|
||||
if verbose:
|
||||
print(
|
||||
f"[deep_pink3]Touching file[/deep_pink3]: '{filepath}' "
|
||||
f"[dodger_blue1]{isotime_from_ts(mtime)} ({mtime}) -> {isotime_from_ts(ts)} ({ts})[/dodger_blue1]"
|
||||
)
|
||||
|
||||
if not dry_run:
|
||||
os.utime(str(filepath), (ts, ts))
|
||||
rec = exportdb.get_file_record(filepath)
|
||||
rec.dest_sig = (dest_mode, dest_size, ts)
|
||||
|
||||
return (touched, not_touched, skipped)
|
||||
@@ -143,7 +143,7 @@ class FileUtilMacOS(FileUtilABC):
|
||||
@classmethod
|
||||
def utime(cls, path, times):
|
||||
"""Set the access and modified time of path."""
|
||||
os.utime(path, times)
|
||||
os.utime(path, times=times)
|
||||
|
||||
@classmethod
|
||||
def cmp(cls, f1, f2, mtime1=None):
|
||||
@@ -187,7 +187,7 @@ class FileUtilMacOS(FileUtilABC):
|
||||
|
||||
@classmethod
|
||||
def file_sig(cls, f1):
|
||||
"""return os.stat signature for file f1"""
|
||||
"""return os.stat signature for file f1 as tuple of (mode, size, mtime)"""
|
||||
return cls._sig(os.stat(f1))
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -33,7 +33,7 @@ from ._constants import (
|
||||
from ._version import __version__
|
||||
from .datetime_utils import datetime_tz_to_utc
|
||||
from .exiftool import ExifTool, exiftool_can_write
|
||||
from .export_db import ExportDB_ABC, ExportDBNoOp
|
||||
from .export_db import ExportDB, ExportDBTemp
|
||||
from .fileutil import FileUtil
|
||||
from .photokit import (
|
||||
PHOTOS_VERSION_CURRENT,
|
||||
@@ -81,7 +81,8 @@ class ExportOptions:
|
||||
exiftool_flags (list of str): optional list of flags to pass to exiftool when using exiftool option, e.g ["-m", "-F"]
|
||||
exiftool: (bool, default = False): if True, will use exiftool to write metadata to export file
|
||||
export_as_hardlink: (bool, default=False): if True, will hardlink files instead of copying them
|
||||
export_db: (ExportDB_ABC): instance of a class that conforms to ExportDB_ABC with methods for getting/setting data related to exported files to compare update state
|
||||
export_db: (ExportDB): instance of a class that conforms to ExportDB with methods for getting/setting data related to exported files to compare update state
|
||||
face_regions: (bool, default=True): if True, will export face regions
|
||||
fileutil: (FileUtilABC): class that conforms to FileUtilABC with various file utilities
|
||||
force_update: (bool, default=False): if True, will export photo if any metadata has changed but export otherwise would not be triggered (e.g. metadata changed but not using exiftool)
|
||||
ignore_date_modified (bool): for use with sidecar and exiftool; if True, sets EXIF:ModifyDate to EXIF:DateTimeOriginal even if date_modified is set
|
||||
@@ -127,7 +128,8 @@ class ExportOptions:
|
||||
exiftool_flags: Optional[List] = None
|
||||
exiftool: bool = False
|
||||
export_as_hardlink: bool = False
|
||||
export_db: Optional[ExportDB_ABC] = None
|
||||
export_db: Optional[ExportDB] = None
|
||||
face_regions: bool = True
|
||||
fileutil: Optional[FileUtil] = None
|
||||
force_update: bool = False
|
||||
ignore_date_modified: bool = False
|
||||
@@ -162,6 +164,12 @@ class ExportOptions:
|
||||
def asdict(self):
|
||||
return asdict(self)
|
||||
|
||||
@property
|
||||
def bit_flags(self):
|
||||
"""Return bit flags representing options that affect export"""
|
||||
# currently only exiftool makes a difference
|
||||
return self.exiftool << 1
|
||||
|
||||
|
||||
class StagedFiles:
|
||||
"""Represents files staged for export"""
|
||||
@@ -401,8 +409,8 @@ class PhotoExporter:
|
||||
"Cannot use export_as_hardlink with download_missing or use_photos_export"
|
||||
)
|
||||
|
||||
# when called from export(), won't get an export_db, so use no-op version
|
||||
options.export_db = options.export_db or ExportDBNoOp()
|
||||
# when called from export(), won't get an export_db, so use temp version
|
||||
options.export_db = options.export_db or ExportDBTemp()
|
||||
|
||||
# ensure there's a FileUtil class to use
|
||||
options.fileutil = options.fileutil or FileUtil
|
||||
@@ -441,6 +449,7 @@ class PhotoExporter:
|
||||
|
||||
# get the right destination path depending on options.update, etc.
|
||||
dest = self._get_dest_path(src, dest, options)
|
||||
|
||||
self._render_options.filepath = str(dest)
|
||||
all_results = ExportResults()
|
||||
|
||||
@@ -543,23 +552,24 @@ class PhotoExporter:
|
||||
|
||||
all_results += self._write_sidecar_files(dest=dest, options=options)
|
||||
|
||||
if options.touch_file:
|
||||
all_results += self._touch_files(all_results, options)
|
||||
|
||||
return all_results
|
||||
|
||||
def _touch_files(
|
||||
self, results: ExportResults, options: ExportOptions
|
||||
) -> ExportResults:
|
||||
"""touch file date/time to match photo creation date/time"""
|
||||
def _touch_files(self, touch_files: List, options: ExportOptions) -> ExportResults:
|
||||
"""touch file date/time to match photo creation date/time; only touches files if needed"""
|
||||
fileutil = options.fileutil
|
||||
touch_files = set(results.to_touch)
|
||||
touch_results = ExportResults()
|
||||
for touch_file in touch_files:
|
||||
touch_results = []
|
||||
for touch_file in set(touch_files):
|
||||
ts = int(self.photo.date.timestamp())
|
||||
fileutil.utime(touch_file, (ts, ts))
|
||||
touch_results.touched.append(touch_file)
|
||||
return touch_results
|
||||
try:
|
||||
stat = os.stat(touch_file)
|
||||
if stat.st_mtime != ts:
|
||||
fileutil.utime(touch_file, (ts, ts))
|
||||
touch_results.append(touch_file)
|
||||
except FileNotFoundError as e:
|
||||
# ignore errors if in dry_run as file may not be present
|
||||
if not options.dry_run:
|
||||
raise e from e
|
||||
return ExportResults(touched=touch_results)
|
||||
|
||||
def _get_edited_filename(self, original_filename):
|
||||
"""Return the filename for the exported edited photo
|
||||
@@ -608,21 +618,11 @@ class PhotoExporter:
|
||||
):
|
||||
return pathlib.Path(increment_filename(dest))
|
||||
|
||||
# if update and file exists, need to check to see if it's the write file by checking export db
|
||||
# if update and file exists, need to check to see if it's the right file by checking export db
|
||||
if (options.update or options.force_update) and dest.exists() and src:
|
||||
export_db = options.export_db
|
||||
fileutil = options.fileutil
|
||||
# destination exists, check to see if destination is the right UUID
|
||||
dest_uuid = export_db.get_uuid_for_file(dest)
|
||||
if dest_uuid is None and fileutil.cmp(src, dest):
|
||||
# might be exporting into a pre-ExportDB folder or the DB got deleted
|
||||
dest_uuid = self.photo.uuid
|
||||
export_db.set_data(
|
||||
filename=dest,
|
||||
uuid=self.photo.uuid,
|
||||
orig_stat=fileutil.file_sig(dest),
|
||||
info_json=self.photo.json(),
|
||||
)
|
||||
if dest_uuid != self.photo.uuid:
|
||||
# not the right file, find the right one
|
||||
# find files that match "dest_name (*.ext" (e.g. "dest_name (1).jpg", "dest_name (2).jpg)", ...)
|
||||
@@ -637,16 +637,6 @@ class PhotoExporter:
|
||||
if dest_uuid == self.photo.uuid:
|
||||
dest = pathlib.Path(file_)
|
||||
break
|
||||
elif dest_uuid is None and fileutil.cmp(src, file_):
|
||||
# files match, update the UUID
|
||||
dest = pathlib.Path(file_)
|
||||
export_db.set_data(
|
||||
filename=dest,
|
||||
uuid=self.photo.uuid,
|
||||
orig_stat=fileutil.file_sig(dest),
|
||||
info_json=self.photo.json(),
|
||||
)
|
||||
break
|
||||
else:
|
||||
# increment the destination file
|
||||
dest = pathlib.Path(increment_filename(dest))
|
||||
@@ -654,6 +644,57 @@ class PhotoExporter:
|
||||
# either dest was updated in the if clause above or not updated at all
|
||||
return dest
|
||||
|
||||
def _should_update_photo(
|
||||
self, src: pathlib.Path, dest: pathlib.Path, options: ExportOptions
|
||||
) -> bool:
|
||||
"""Return True if photo should be updated, else False"""
|
||||
export_db = options.export_db
|
||||
fileutil = options.fileutil
|
||||
|
||||
file_record = export_db.get_file_record(dest)
|
||||
|
||||
if not file_record:
|
||||
# photo doesn't exist in database, should update
|
||||
return True
|
||||
|
||||
if options.export_as_hardlink and not dest.samefile(src):
|
||||
# different files, should update
|
||||
return True
|
||||
|
||||
if not options.export_as_hardlink and dest.samefile(src):
|
||||
# same file but not exporting as hardlink, should update
|
||||
return True
|
||||
|
||||
if not options.ignore_signature and not fileutil.cmp_file_sig(
|
||||
dest, file_record.dest_sig
|
||||
):
|
||||
# destination file doesn't match what was last exported
|
||||
return True
|
||||
|
||||
if file_record.export_options != options.bit_flags:
|
||||
# exporting with different set of options (e.g. exiftool), should update
|
||||
# need to check this before exiftool in case exiftool options are different
|
||||
# and export database is missing; this will always be True if database is missing
|
||||
# as it'll be None and bit_flags will be an int
|
||||
return True
|
||||
|
||||
if options.exiftool:
|
||||
current_exifdata = self._exiftool_json_sidecar(options=options)
|
||||
return current_exifdata != file_record.exifdata
|
||||
|
||||
if options.edited and not fileutil.cmp_file_sig(src, file_record.src_sig):
|
||||
# edited file in Photos doesn't match what was last exported
|
||||
return True
|
||||
|
||||
if options.force_update:
|
||||
current_digest = hexdigest(self.photo.json())
|
||||
if current_digest != file_record.digest:
|
||||
# metadata in Photos changed, force update
|
||||
return True
|
||||
|
||||
# photo should not be updated
|
||||
return False
|
||||
|
||||
def _stage_photos_for_export(self, options: ExportOptions) -> StagedFiles:
|
||||
"""Stages photos for export
|
||||
|
||||
@@ -987,11 +1028,8 @@ class PhotoExporter:
|
||||
update_updated_files = []
|
||||
update_new_files = []
|
||||
update_skipped_files = [] # skip files that are already up to date
|
||||
touched_files = []
|
||||
converted_to_jpeg_files = []
|
||||
exif_results = ExportResults()
|
||||
converted_stat = None
|
||||
edited_stat = None
|
||||
|
||||
dest_str = str(dest)
|
||||
dest_exists = dest.exists()
|
||||
@@ -1000,98 +1038,25 @@ class PhotoExporter:
|
||||
export_db = options.export_db
|
||||
|
||||
if options.update or options.force_update: # updating
|
||||
cmp_touch, cmp_orig = False, False
|
||||
if dest_exists:
|
||||
# update, destination exists, but we might not need to replace it...
|
||||
if options.exiftool:
|
||||
sig_exif = export_db.get_stat_exif_for_file(dest_str)
|
||||
cmp_orig = fileutil.cmp_file_sig(dest_str, sig_exif)
|
||||
if cmp_orig:
|
||||
# if signatures match also need to compare exifdata to see if metadata changed
|
||||
cmp_orig = not self._should_run_exiftool(dest_str, options)
|
||||
sig_exif = (
|
||||
sig_exif[0],
|
||||
sig_exif[1],
|
||||
int(self.photo.date.timestamp()),
|
||||
)
|
||||
cmp_touch = fileutil.cmp_file_sig(dest_str, sig_exif)
|
||||
elif options.convert_to_jpeg:
|
||||
sig_converted = export_db.get_stat_converted_for_file(dest_str)
|
||||
cmp_orig = fileutil.cmp_file_sig(dest_str, sig_converted)
|
||||
sig_converted = (
|
||||
sig_converted[0],
|
||||
sig_converted[1],
|
||||
int(self.photo.date.timestamp()),
|
||||
)
|
||||
cmp_touch = fileutil.cmp_file_sig(dest_str, sig_converted)
|
||||
else:
|
||||
cmp_orig = options.ignore_signature or fileutil.cmp(src, dest)
|
||||
cmp_touch = fileutil.cmp(
|
||||
src, dest, mtime1=int(self.photo.date.timestamp())
|
||||
)
|
||||
if options.force_update:
|
||||
# need to also check the photo's metadata to that in the database
|
||||
# and if anything changed, we need to update the file
|
||||
# ony the hex digest of the metadata is stored in the database
|
||||
photo_digest = hexdigest(self.photo.json())
|
||||
db_digest = export_db.get_metadata_for_file(dest_str)
|
||||
cmp_orig = photo_digest == db_digest
|
||||
|
||||
sig_cmp = cmp_touch if options.touch_file else cmp_orig
|
||||
|
||||
if options.edited:
|
||||
# requested edited version of photo
|
||||
# need to see if edited version in Photos library has changed
|
||||
# (e.g. it's been edited again)
|
||||
sig_edited = export_db.get_stat_edited_for_file(dest_str)
|
||||
cmp_edited = (
|
||||
fileutil.cmp_file_sig(src, sig_edited)
|
||||
if sig_edited != (None, None, None)
|
||||
else False
|
||||
)
|
||||
sig_cmp = sig_cmp and (options.force_update or cmp_edited)
|
||||
|
||||
if (options.export_as_hardlink and dest.samefile(src)) or (
|
||||
not options.export_as_hardlink
|
||||
and not dest.samefile(src)
|
||||
and sig_cmp
|
||||
):
|
||||
# destination exists and signatures match, skip it
|
||||
update_skipped_files.append(dest_str)
|
||||
elif options.touch_file and cmp_orig and not cmp_touch:
|
||||
# destination exists, signature matches original but does not match expected touch time
|
||||
# skip exporting but update touch time
|
||||
update_skipped_files.append(dest_str)
|
||||
touched_files.append(dest_str)
|
||||
elif not options.touch_file and cmp_touch and not cmp_orig:
|
||||
# destination exists, signature matches expected touch but not original
|
||||
# user likely exported with touch_file and is now exporting without touch_file
|
||||
# don't update the file because it's same but leave touch time
|
||||
update_skipped_files.append(dest_str)
|
||||
else:
|
||||
# destination exists but is different
|
||||
if self._should_update_photo(src, dest, options):
|
||||
update_updated_files.append(dest_str)
|
||||
if options.touch_file:
|
||||
touched_files.append(dest_str)
|
||||
else:
|
||||
update_skipped_files.append(dest_str)
|
||||
else:
|
||||
# update, destination doesn't exist (new file)
|
||||
update_new_files.append(dest_str)
|
||||
if options.touch_file:
|
||||
touched_files.append(dest_str)
|
||||
else:
|
||||
# not update, export the file
|
||||
exported_files.append(dest_str)
|
||||
if options.touch_file:
|
||||
sig = fileutil.file_sig(src)
|
||||
sig = (sig[0], sig[1], int(self.photo.date.timestamp()))
|
||||
if not fileutil.cmp_file_sig(src, sig):
|
||||
touched_files.append(dest_str)
|
||||
|
||||
if not update_skipped_files:
|
||||
# have file to export
|
||||
edited_stat = (
|
||||
fileutil.file_sig(src) if options.edited else (None, None, None)
|
||||
export_files = update_new_files + update_updated_files + exported_files
|
||||
for export_dest in export_files:
|
||||
# set src_sig before any modifications by convert_to_jpeg or exiftool
|
||||
export_record = export_db.create_or_get_file_record(
|
||||
export_dest, self.photo.uuid
|
||||
)
|
||||
export_record.src_sig = fileutil.file_sig(src)
|
||||
if dest_exists and any(
|
||||
[options.overwrite, options.update, options.force_update]
|
||||
):
|
||||
@@ -1121,7 +1086,6 @@ class PhotoExporter:
|
||||
src, tmp_file, compression_quality=options.jpeg_quality
|
||||
)
|
||||
src = tmp_file
|
||||
converted_stat = fileutil.file_sig(tmp_file)
|
||||
converted_to_jpeg_files.append(dest_str)
|
||||
|
||||
if options.exiftool:
|
||||
@@ -1137,20 +1101,7 @@ class PhotoExporter:
|
||||
f"Error copying file {src} to {dest_str}: {e} ({lineno(__file__)})"
|
||||
) from e
|
||||
|
||||
json_info = self.photo.json()
|
||||
# don't set the metadata digest if not force_update so that future use of force_update catches metadata change
|
||||
metadata_digest = hexdigest(json_info) if options.force_update else None
|
||||
export_db.set_data(
|
||||
filename=dest_str,
|
||||
uuid=self.photo.uuid,
|
||||
orig_stat=fileutil.file_sig(dest_str),
|
||||
converted_stat=converted_stat,
|
||||
edited_stat=edited_stat,
|
||||
info_json=json_info,
|
||||
metadata=metadata_digest,
|
||||
)
|
||||
|
||||
return ExportResults(
|
||||
results = ExportResults(
|
||||
converted_to_jpeg=converted_to_jpeg_files,
|
||||
error=exif_results.error,
|
||||
exif_updated=exif_results.exif_updated,
|
||||
@@ -1159,10 +1110,34 @@ class PhotoExporter:
|
||||
exported=exported_files + update_new_files + update_updated_files,
|
||||
new=update_new_files,
|
||||
skipped=update_skipped_files,
|
||||
to_touch=touched_files,
|
||||
updated=update_updated_files,
|
||||
)
|
||||
|
||||
# touch files if needed
|
||||
if options.touch_file:
|
||||
results += self._touch_files(
|
||||
exported_files
|
||||
+ update_new_files
|
||||
+ update_updated_files
|
||||
+ update_skipped_files,
|
||||
options,
|
||||
)
|
||||
|
||||
# set data in the database
|
||||
with export_db.create_or_get_file_record(dest_str, self.photo.uuid) as rec:
|
||||
photoinfo = self.photo.json()
|
||||
rec.photoinfo = photoinfo
|
||||
rec.export_options = options.bit_flags
|
||||
# don't set src_sig as that is set above before any modifications by convert_to_jpeg or exiftool
|
||||
if not options.ignore_signature:
|
||||
rec.dest_sig = fileutil.file_sig(dest)
|
||||
if options.exiftool:
|
||||
rec.exifdata = self._exiftool_json_sidecar(options)
|
||||
if options.force_update:
|
||||
rec.digest = hexdigest(photoinfo)
|
||||
|
||||
return results
|
||||
|
||||
def _write_sidecar_files(
|
||||
self,
|
||||
dest: pathlib.Path,
|
||||
@@ -1243,8 +1218,8 @@ class PhotoExporter:
|
||||
sidecar_type = data[4]
|
||||
|
||||
sidecar_digest = hexdigest(sidecar_str)
|
||||
old_sidecar_digest, sidecar_sig = export_db.get_sidecar_for_file(
|
||||
sidecar_filename
|
||||
sidecar_record = export_db.create_or_get_file_record(
|
||||
sidecar_filename, self.photo.uuid
|
||||
)
|
||||
write_sidecar = (
|
||||
not (options.update or options.force_update)
|
||||
@@ -1254,8 +1229,10 @@ class PhotoExporter:
|
||||
)
|
||||
or (
|
||||
(options.update or options.force_update)
|
||||
and (sidecar_digest != old_sidecar_digest)
|
||||
or not fileutil.cmp_file_sig(sidecar_filename, sidecar_sig)
|
||||
and (sidecar_digest != sidecar_record.digest)
|
||||
or not fileutil.cmp_file_sig(
|
||||
sidecar_filename, sidecar_record.dest_sig
|
||||
)
|
||||
)
|
||||
)
|
||||
if write_sidecar:
|
||||
@@ -1263,16 +1240,13 @@ class PhotoExporter:
|
||||
files_written.append(str(sidecar_filename))
|
||||
if not options.dry_run:
|
||||
self._write_sidecar(sidecar_filename, sidecar_str)
|
||||
export_db.set_sidecar_for_file(
|
||||
sidecar_filename,
|
||||
sidecar_digest,
|
||||
fileutil.file_sig(sidecar_filename),
|
||||
)
|
||||
sidecar_record.digest = sidecar_digest
|
||||
sidecar_record.dest_sig = fileutil.file_sig(sidecar_filename)
|
||||
else:
|
||||
verbose(f"Skipped up to date {sidecar_type} sidecar {sidecar_filename}")
|
||||
files_skipped.append(str(sidecar_filename))
|
||||
|
||||
return ExportResults(
|
||||
results = ExportResults(
|
||||
sidecar_json_written=sidecar_json_files_written,
|
||||
sidecar_json_skipped=sidecar_json_files_skipped,
|
||||
sidecar_exiftool_written=sidecar_exiftool_files_written,
|
||||
@@ -1281,6 +1255,26 @@ class PhotoExporter:
|
||||
sidecar_xmp_skipped=sidecar_xmp_files_skipped,
|
||||
)
|
||||
|
||||
if options.touch_file:
|
||||
all_sidecars = (
|
||||
sidecar_json_files_written
|
||||
+ sidecar_exiftool_files_written
|
||||
+ sidecar_xmp_files_written
|
||||
+ sidecar_json_files_skipped
|
||||
+ sidecar_exiftool_files_skipped
|
||||
+ sidecar_xmp_files_skipped
|
||||
)
|
||||
results += self._touch_files(all_sidecars, options)
|
||||
|
||||
# update destination signatures in database
|
||||
for sidecar_filename in all_sidecars:
|
||||
sidecar_record = export_db.create_or_get_file_record(
|
||||
sidecar_filename, self.photo.uuid
|
||||
)
|
||||
sidecar_record.dest_sig = fileutil.file_sig(sidecar_filename)
|
||||
|
||||
return results
|
||||
|
||||
def _write_exif_metadata_to_file(
|
||||
self,
|
||||
src,
|
||||
@@ -1295,10 +1289,7 @@ class PhotoExporter:
|
||||
local machine prior to being copied to the export destination which may be on a
|
||||
network drive or other slower external storage."""
|
||||
|
||||
export_db = options.export_db
|
||||
fileutil = options.fileutil
|
||||
verbose = options.verbose or self._verbose
|
||||
|
||||
exiftool_results = ExportResults()
|
||||
|
||||
# don't try to write if unsupported file type for exiftool
|
||||
@@ -1310,53 +1301,35 @@ class PhotoExporter:
|
||||
)
|
||||
)
|
||||
# set file signature so the file doesn't get re-exported with --update
|
||||
export_db.set_data(
|
||||
dest,
|
||||
uuid=self.photo.uuid,
|
||||
exif_stat=fileutil.file_sig(src),
|
||||
exif_json=self._exiftool_json_sidecar(options=options),
|
||||
)
|
||||
return exiftool_results
|
||||
|
||||
# determine if we need to write the exif metadata
|
||||
# if we are not updating, we always write
|
||||
# else, need to check the database to determine if we need to write
|
||||
run_exiftool = self._should_run_exiftool(dest, options)
|
||||
if run_exiftool:
|
||||
verbose(f"Writing metadata with exiftool for {pathlib.Path(dest).name}")
|
||||
if not options.dry_run:
|
||||
warning_, error_ = self._write_exif_data(src, options=options)
|
||||
if warning_:
|
||||
exiftool_results.exiftool_warning.append((dest, warning_))
|
||||
if error_:
|
||||
exiftool_results.exiftool_error.append((dest, error_))
|
||||
exiftool_results.error.append((dest, error_))
|
||||
verbose(f"Writing metadata with exiftool for {pathlib.Path(dest).name}")
|
||||
if not options.dry_run:
|
||||
warning_, error_ = self._write_exif_data(src, options=options)
|
||||
if warning_:
|
||||
exiftool_results.exiftool_warning.append((dest, warning_))
|
||||
if error_:
|
||||
exiftool_results.exiftool_error.append((dest, error_))
|
||||
exiftool_results.error.append((dest, error_))
|
||||
|
||||
export_db.set_data(
|
||||
dest,
|
||||
uuid=self.photo.uuid,
|
||||
exif_stat=fileutil.file_sig(src),
|
||||
exif_json=self._exiftool_json_sidecar(options=options),
|
||||
)
|
||||
exiftool_results.exif_updated.append(dest)
|
||||
exiftool_results.to_touch.append(dest)
|
||||
else:
|
||||
verbose(
|
||||
f"Skipped up to date exiftool metadata for {pathlib.Path(dest).name}"
|
||||
)
|
||||
exiftool_results.exif_updated.append(dest)
|
||||
exiftool_results.to_touch.append(dest)
|
||||
return exiftool_results
|
||||
|
||||
def _should_run_exiftool(self, dest, options: ExportOptions) -> bool:
|
||||
"""Return True if exiftool should be run to update metadata"""
|
||||
run_exiftool = not (options.update or options.force_update)
|
||||
run_exiftool = not options.update and not options.force_update
|
||||
if options.update or options.force_update:
|
||||
files_are_different = False
|
||||
old_data = options.export_db.get_exifdata_for_file(dest)
|
||||
exif_record = options.export_db.get_file_record(dest)
|
||||
old_data = exif_record.exifdata if exif_record else None
|
||||
if old_data is not None:
|
||||
old_data = json.loads(old_data)[0]
|
||||
current_data = json.loads(self._exiftool_json_sidecar(options=options))[
|
||||
0
|
||||
]
|
||||
current_data = json.loads(self._exiftool_json_sidecar(options=options))
|
||||
current_data = current_data[0]
|
||||
if old_data != current_data:
|
||||
files_are_different = True
|
||||
|
||||
@@ -1539,6 +1512,9 @@ class PhotoExporter:
|
||||
person_list = sorted(list(set(person_list)))
|
||||
exif["XMP:PersonInImage"] = person_list.copy()
|
||||
|
||||
if options.face_regions and self.photo.face_info:
|
||||
exif.update(self._get_mwg_face_regions_exiftool())
|
||||
|
||||
# if self.favorite():
|
||||
# exif["Rating"] = 5
|
||||
|
||||
@@ -1621,6 +1597,42 @@ class PhotoExporter:
|
||||
|
||||
return exif
|
||||
|
||||
def _get_mwg_face_regions_exiftool(self):
|
||||
"""Return a dict with MWG face regions for use by exiftool"""
|
||||
if self.photo.orientation in [5, 6, 7, 8]:
|
||||
w = self.photo.height
|
||||
h = self.photo.width
|
||||
else:
|
||||
w = self.photo.width
|
||||
h = self.photo.height
|
||||
exif = {}
|
||||
exif["XMP:RegionAppliedToDimensionsW"] = w
|
||||
exif["XMP:RegionAppliedToDimensionsH"] = h
|
||||
exif["XMP:RegionAppliedToDimensionsUnit"] = "pixel"
|
||||
exif["XMP:RegionName"] = []
|
||||
exif["XMP:RegionType"] = []
|
||||
exif["XMP:RegionAreaX"] = []
|
||||
exif["XMP:RegionAreaY"] = []
|
||||
exif["XMP:RegionAreaW"] = []
|
||||
exif["XMP:RegionAreaH"] = []
|
||||
exif["XMP:RegionAreaUnit"] = []
|
||||
exif["XMP:RegionPersonDisplayName"] = []
|
||||
# exif["XMP:RegionRectangle"] = []
|
||||
for face in self.photo.face_info:
|
||||
if not face.name:
|
||||
continue
|
||||
area = face.mwg_rs_area
|
||||
exif["XMP:RegionName"].append(face.name)
|
||||
exif["XMP:RegionType"].append("Face")
|
||||
exif["XMP:RegionAreaX"].append(area.x)
|
||||
exif["XMP:RegionAreaY"].append(area.y)
|
||||
exif["XMP:RegionAreaW"].append(area.w)
|
||||
exif["XMP:RegionAreaH"].append(area.h)
|
||||
exif["XMP:RegionAreaUnit"].append("normalized")
|
||||
exif["XMP:RegionPersonDisplayName"].append(face.name)
|
||||
# exif["XMP:RegionRectangle"].append(f"{area.x},{area.y},{area.h},{area.w}")
|
||||
return exif
|
||||
|
||||
def _get_exif_keywords(self):
|
||||
"""returns list of keywords found in the file's exif metadata"""
|
||||
keywords = []
|
||||
|
||||
@@ -54,7 +54,7 @@ from .scoreinfo import ScoreInfo
|
||||
from .searchinfo import SearchInfo
|
||||
from .text_detection import detect_text
|
||||
from .uti import get_preferred_uti_extension, get_uti_for_extension
|
||||
from .utils import _debug, _get_resource_loc, list_directory
|
||||
from .utils import _debug, _get_resource_loc, list_directory, _debug
|
||||
|
||||
__all__ = ["PhotoInfo", "PhotoInfoNone"]
|
||||
|
||||
@@ -588,6 +588,7 @@ class PhotoInfo:
|
||||
@property
|
||||
def ismissing(self):
|
||||
"""returns true if photo is missing from disk (which means it's not been downloaded from iCloud)
|
||||
|
||||
NOTE: the photos.db database uses an asynchrounous write-ahead log so changes in Photos
|
||||
do not immediately get written to disk. In particular, I've noticed that downloading
|
||||
an image from the cloud does not force the database to be updated until something else
|
||||
@@ -1488,7 +1489,8 @@ class PhotoInfo:
|
||||
description_template: string; optional template string that will be rendered for use as photo description
|
||||
render_options: an optional osxphotos.phototemplate.RenderOptions instance with options to pass to template renderer
|
||||
|
||||
Returns: list of photos exported
|
||||
Returns:
|
||||
list of photos exported
|
||||
"""
|
||||
|
||||
exporter = PhotoExporter(self)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import logging
|
||||
|
||||
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
|
||||
from ..utils import _db_is_locked, _debug, _open_sql_file
|
||||
from ..utils import _db_is_locked, _open_sql_file
|
||||
from .photosdb_utils import get_db_version
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import uuid as uuidlib
|
||||
from pprint import pformat
|
||||
|
||||
from .._constants import _PHOTOS_4_VERSION, SEARCH_CATEGORY_LABEL
|
||||
from ..utils import _db_is_locked, _debug, _open_sql_file, normalize_unicode
|
||||
from ..utils import _db_is_locked, _open_sql_file, normalize_unicode
|
||||
|
||||
"""
|
||||
This module should be imported in the class defintion of PhotosDB in photosdb.py
|
||||
@@ -139,17 +139,6 @@ def _process_searchinfo(self):
|
||||
_db_searchinfo_labels[label] = [uuid]
|
||||
_db_searchinfo_labels_normalized[label_norm] = [uuid]
|
||||
|
||||
if _debug():
|
||||
logging.debug(
|
||||
"_db_searchinfo_categories: \n" + pformat(self._db_searchinfo_categories)
|
||||
)
|
||||
logging.debug("_db_searchinfo_uuid: \n" + pformat(self._db_searchinfo_uuid))
|
||||
logging.debug("_db_searchinfo_labels: \n" + pformat(self._db_searchinfo_labels))
|
||||
logging.debug(
|
||||
"_db_searchinfo_labels_normalized: \n"
|
||||
+ pformat(self._db_searchinfo_labels_normalized)
|
||||
)
|
||||
|
||||
conn.close()
|
||||
|
||||
|
||||
|
||||
@@ -2456,7 +2456,6 @@ class PhotosDB:
|
||||
verbose("Processing moments.")
|
||||
self._process_moments()
|
||||
|
||||
# done processing, dump debug data if requested
|
||||
verbose("Done processing details from Photos library.")
|
||||
|
||||
def _process_moments(self):
|
||||
@@ -3280,27 +3279,6 @@ class PhotosDB:
|
||||
if options.to_time:
|
||||
photos = [p for p in photos if p.date.time() <= options.to_time]
|
||||
|
||||
if options.burst_photos:
|
||||
# add the burst_photos to the export set
|
||||
photos_burst = [p for p in photos if p.burst]
|
||||
for burst in photos_burst:
|
||||
if options.missing_bursts:
|
||||
# include burst photos that are missing
|
||||
photos.extend(burst.burst_photos)
|
||||
else:
|
||||
# don't include missing burst images (these can't be downloaded with AppleScript)
|
||||
photos.extend([p for p in burst.burst_photos if not p.ismissing])
|
||||
|
||||
# remove duplicates as each burst photo in the set that's selected would
|
||||
# result in the entire set being added above
|
||||
# can't use set() because PhotoInfo not hashable
|
||||
seen_uuids = {}
|
||||
for p in photos:
|
||||
if p.uuid in seen_uuids:
|
||||
continue
|
||||
seen_uuids[p.uuid] = p
|
||||
photos = list(seen_uuids.values())
|
||||
|
||||
if name:
|
||||
# search filename fields for text
|
||||
# if more than one, find photos with all title values in filename
|
||||
@@ -3451,6 +3429,28 @@ class PhotosDB:
|
||||
for function in options.function:
|
||||
photos = function[0](photos)
|
||||
|
||||
# burst should be checked last, ref #640
|
||||
if options.burst_photos:
|
||||
# add the burst_photos to the export set
|
||||
photos_burst = [p for p in photos if p.burst]
|
||||
for burst in photos_burst:
|
||||
if options.missing_bursts:
|
||||
# include burst photos that are missing
|
||||
photos.extend(burst.burst_photos)
|
||||
else:
|
||||
# don't include missing burst images (these can't be downloaded with AppleScript)
|
||||
photos.extend([p for p in burst.burst_photos if not p.ismissing])
|
||||
|
||||
# remove duplicates as each burst photo in the set that's selected would
|
||||
# result in the entire set being added above
|
||||
# can't use set() because PhotoInfo not hashable
|
||||
seen_uuids = {}
|
||||
for p in photos:
|
||||
if p.uuid in seen_uuids:
|
||||
continue
|
||||
seen_uuids[p.uuid] = p
|
||||
photos = list(seen_uuids.values())
|
||||
|
||||
return photos
|
||||
|
||||
def execute(self, sql):
|
||||
|
||||
@@ -99,7 +99,7 @@ OPERATOR:
|
||||
PathSep:
|
||||
(
|
||||
"("
|
||||
(value=/[^\(\)\{\}]{0,1}/)?
|
||||
(value=/[^\(\)\{\}]+/)?
|
||||
")"
|
||||
)?
|
||||
;
|
||||
|
||||
@@ -103,6 +103,8 @@
|
||||
% if photo.face_info:
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>${photo.width if photo.orientation in [5, 6, 7, 8] else photo.height}</stDim:h>
|
||||
<stDim:w>${photo.height if photo.orientation in [5, 6, 7, 8] else photo.width}</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -103,6 +103,8 @@
|
||||
% if photo.face_info:
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>${photo.width if photo.orientation in [5, 6, 7, 8] else photo.height}</stDim:h>
|
||||
<stDim:w>${photo.height if photo.orientation in [5, 6, 7, 8] else photo.width}</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
# Tests for osxphotos #
|
||||
|
||||
## Running Tests ##
|
||||
Tests require pytest and pytest-mock:
|
||||
`pip install pytest`
|
||||
`pip install pytest-mock`
|
||||
To set up a dev environment to work on osxphotos code or run tests follow these steps. This assumes you have python 3.7 or later installed. If you need to install python, you can do so with the XCode command lines tools (`xcode-select --install`) or from [python.org](https://www.python.org/downloads/macos/).
|
||||
|
||||
- `git clone git@github.com:RhetTbull/osxphotos.git`
|
||||
- `cd osxphotos`
|
||||
- `python3 -m venv venv`
|
||||
- `source venv/bin/activate`
|
||||
- `python3 -m pip install -r dev_requirements.txt`
|
||||
- `python3 -m pip install -e .`
|
||||
|
||||
To run the tests, do the following from the main source folder:
|
||||
`python -m pytest tests/`
|
||||
`python3 -m pytest tests/`
|
||||
|
||||
Running the tests this way allows the library to be tested without installing it.
|
||||
|
||||
## Skipped Tests ##
|
||||
A few tests will look for certain environment variables to determine if they should run.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import pathlib
|
||||
|
||||
import osxphotos
|
||||
from osxphotos.photoexporter import PhotoExporter, ExportOptions
|
||||
|
||||
PHOTOS_DB_15_7 = "./tests/Test-10.15.7.photoslibrary/database/photos.db"
|
||||
PHOTOS_DB_14_6 = "./tests/Test-10.14.6.photoslibrary/database/photos.db"
|
||||
@@ -31,7 +32,7 @@ SIDECAR_DIR = "tests/sidecars"
|
||||
|
||||
|
||||
def generate_sidecars(dbname, uuid_dict):
|
||||
""" generate XMP and JSON sidecars for testing """
|
||||
"""generate XMP and JSON sidecars for testing"""
|
||||
photosdb = osxphotos.PhotosDB(dbname)
|
||||
|
||||
for _, uuid in uuid_dict.items():
|
||||
@@ -39,7 +40,8 @@ def generate_sidecars(dbname, uuid_dict):
|
||||
|
||||
# plain xmp
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.xmp")
|
||||
xmp = photo._xmp_sidecar()
|
||||
exporter = PhotoExporter(photo)
|
||||
xmp = exporter._xmp_sidecar()
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(xmp)
|
||||
|
||||
@@ -47,63 +49,76 @@ def generate_sidecars(dbname, uuid_dict):
|
||||
ext = osxphotos.uti.get_preferred_uti_extension(photo.uti)
|
||||
ext = "jpg" if ext == "jpeg" else ext
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_ext.xmp")
|
||||
xmp = photo._xmp_sidecar(extension=ext)
|
||||
xmp = exporter._xmp_sidecar(extension=ext)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(xmp)
|
||||
|
||||
# persons_as_keywords
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_persons_as_keywords.xmp")
|
||||
xmp = photo._xmp_sidecar(use_persons_as_keywords=True, extension=ext)
|
||||
xmp = exporter._xmp_sidecar(
|
||||
ExportOptions(use_persons_as_keywords=True), extension=ext
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(xmp)
|
||||
|
||||
# albums_as_keywords
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_albums_as_keywords.xmp")
|
||||
xmp = photo._xmp_sidecar(use_albums_as_keywords=True, extension=ext)
|
||||
xmp = exporter._xmp_sidecar(
|
||||
ExportOptions(use_albums_as_keywords=True), extension=ext
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(xmp)
|
||||
|
||||
# keyword_template
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_keyword_template.xmp")
|
||||
xmp = photo._xmp_sidecar(
|
||||
keyword_template=["{created.year}", "{folder_album}"], extension=ext
|
||||
xmp = exporter._xmp_sidecar(
|
||||
ExportOptions(keyword_template=["{created.year}", "{folder_album}"]),
|
||||
extension=ext,
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(xmp)
|
||||
|
||||
# generate JSON files
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json")
|
||||
json_ = photo._exiftool_json_sidecar()
|
||||
json_ = exporter._exiftool_json_sidecar()
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(json_)
|
||||
|
||||
# no tag groups
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_no_tag_groups.json")
|
||||
json_ = photo._exiftool_json_sidecar(tag_groups=False)
|
||||
json_ = exporter._exiftool_json_sidecar(tag_groups=False)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(json_)
|
||||
|
||||
# ignore_date_modified
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_ignore_date_modified.json")
|
||||
json_ = photo._exiftool_json_sidecar(ignore_date_modified=True)
|
||||
json_ = exporter._exiftool_json_sidecar(
|
||||
ExportOptions(ignore_date_modified=True)
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(json_)
|
||||
|
||||
# keyword_template
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_keyword_template.json")
|
||||
json_ = photo._exiftool_json_sidecar(keyword_template=["{folder_album}"])
|
||||
json_ = exporter._exiftool_json_sidecar(
|
||||
ExportOptions(keyword_template=["{folder_album}"])
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(json_)
|
||||
|
||||
# persons_as_keywords
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_persons_as_keywords.json")
|
||||
json_ = photo._exiftool_json_sidecar(use_persons_as_keywords=True)
|
||||
json_ = exporter._exiftool_json_sidecar(
|
||||
ExportOptions(use_persons_as_keywords=True)
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(json_)
|
||||
|
||||
# albums_as_keywords
|
||||
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_albums_as_keywords.json")
|
||||
json_ = photo._exiftool_json_sidecar(use_albums_as_keywords=True)
|
||||
json_ = exporter._exiftool_json_sidecar(
|
||||
ExportOptions(use_albums_as_keywords=True)
|
||||
)
|
||||
with open(sidecar, "w") as file:
|
||||
file.write(json_)
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5832663178443909], "XMP:RegionAreaY": [0.27730926126241684], "XMP:RegionAreaW": [0.24365156888961792], "XMP:RegionAreaH": [0.16239472242887132], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -52,6 +52,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:Subject": ["AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:TagsList": ["AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:PersonInImage": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:Subject": ["AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:TagsList": ["AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5832663178443909], "XMP:RegionAreaY": [0.27730926126241684], "XMP:RegionAreaW": [0.24365156888961792], "XMP:RegionAreaH": [0.16239472242887132], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -58,6 +58,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5832663178443909], "XMP:RegionAreaY": [0.27730926126241684], "XMP:RegionAreaW": [0.24365156888961792], "XMP:RegionAreaH": [0.16239472242887132], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Folder1/SubFolder2/AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:Subject": ["Folder1/SubFolder2/AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:TagsList": ["Folder1/SubFolder2/AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:PersonInImage": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Folder1/SubFolder2/AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:Subject": ["Folder1/SubFolder2/AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:TagsList": ["Folder1/SubFolder2/AlbumInFolder", "Kids", "Pumpkin Farm", "Test Album (1)"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5832663178443909], "XMP:RegionAreaY": [0.27730926126241684], "XMP:RegionAreaW": [0.24365156888961792], "XMP:RegionAreaH": [0.16239472242887132], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -60,6 +60,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"ImageDescription": "Girl holding pumpkin", "Description": "Girl holding pumpkin", "Caption-Abstract": "Girl holding pumpkin", "Title": "I found one!", "ObjectName": "I found one!", "Keywords": ["Kids"], "Subject": ["Kids"], "TagsList": ["Kids"], "PersonInImage": ["Katie"], "DateTimeOriginal": "2018:09:28 16:07:07", "CreateDate": "2018:09:28 16:07:07", "OffsetTimeOriginal": "-04:00", "DateCreated": "2018:09:28", "TimeCreated": "16:07:07-04:00", "ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"ImageDescription": "Girl holding pumpkin", "Description": "Girl holding pumpkin", "Caption-Abstract": "Girl holding pumpkin", "Title": "I found one!", "ObjectName": "I found one!", "Keywords": ["Kids"], "Subject": ["Kids"], "TagsList": ["Kids"], "PersonInImage": ["Katie"], "RegionAppliedToDimensionsW": 1365, "RegionAppliedToDimensionsH": 2048, "RegionAppliedToDimensionsUnit": "pixel", "RegionName": ["Katie"], "RegionType": ["Face"], "RegionAreaX": [0.5832663178443909], "RegionAreaY": [0.27730926126241684], "RegionAreaW": [0.24365156888961792], "RegionAreaH": [0.16239472242887132], "RegionAreaUnit": ["normalized"], "RegionPersonDisplayName": ["Katie"], "DateTimeOriginal": "2018:09:28 16:07:07", "CreateDate": "2018:09:28 16:07:07", "OffsetTimeOriginal": "-04:00", "DateCreated": "2018:09:28", "TimeCreated": "16:07:07-04:00", "ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Katie", "Kids"], "XMP:Subject": ["Katie", "Kids"], "XMP:TagsList": ["Katie", "Kids"], "XMP:PersonInImage": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Katie", "Kids"], "XMP:Subject": ["Katie", "Kids"], "XMP:TagsList": ["Katie", "Kids"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5832663178443909], "XMP:RegionAreaY": [0.27730926126241684], "XMP:RegionAreaW": [0.24365156888961792], "XMP:RegionAreaH": [0.16239472242887132], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.40229974687099457], "XMP:RegionAreaY": [0.41379398107528687], "XMP:RegionAreaW": [0.3420099108278517], "XMP:RegionAreaH": [0.39389216899871826], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
@@ -52,6 +52,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.40229974687099457], "XMP:RegionAreaY": [0.41379398107528687], "XMP:RegionAreaW": [0.3420099108278517], "XMP:RegionAreaH": [0.39389216899871826], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
@@ -52,6 +52,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:04:15 14:40:24"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.40229974687099457], "XMP:RegionAreaY": [0.41379398107528687], "XMP:RegionAreaW": [0.3420099108278517], "XMP:RegionAreaH": [0.39389216899871826], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:04:15 14:40:24"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["wedding"], "XMP:Subject": ["wedding"], "XMP:TagsList": ["wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.40229974687099457], "XMP:RegionAreaY": [0.41379398107528687], "XMP:RegionAreaW": [0.3420099108278517], "XMP:RegionAreaH": [0.39389216899871826], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"ImageDescription": "Bride Wedding day", "Description": "Bride Wedding day", "Caption-Abstract": "Bride Wedding day", "Keywords": ["wedding"], "Subject": ["wedding"], "TagsList": ["wedding"], "PersonInImage": ["Maria"], "DateTimeOriginal": "2019:04:15 14:40:24", "CreateDate": "2019:04:15 14:40:24", "OffsetTimeOriginal": "-04:00", "DateCreated": "2019:04:15", "TimeCreated": "14:40:24-04:00", "ModifyDate": "2019:11:27 01:30:16"}]
|
||||
[{"ImageDescription": "Bride Wedding day", "Description": "Bride Wedding day", "Caption-Abstract": "Bride Wedding day", "Keywords": ["wedding"], "Subject": ["wedding"], "TagsList": ["wedding"], "PersonInImage": ["Maria"], "RegionAppliedToDimensionsW": 1526, "RegionAppliedToDimensionsH": 1325, "RegionAppliedToDimensionsUnit": "pixel", "RegionName": ["Maria"], "RegionType": ["Face"], "RegionAreaX": [0.40229974687099457], "RegionAreaY": [0.41379398107528687], "RegionAreaW": [0.3420099108278517], "RegionAreaH": [0.39389216899871826], "RegionAreaUnit": ["normalized"], "RegionPersonDisplayName": ["Maria"], "DateTimeOriginal": "2019:04:15 14:40:24", "CreateDate": "2019:04:15 14:40:24", "OffsetTimeOriginal": "-04:00", "DateCreated": "2019:04:15", "TimeCreated": "14:40:24-04:00", "ModifyDate": "2019:11:27 01:30:16"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.40229974687099457], "XMP:RegionAreaY": [0.41379398107528687], "XMP:RegionAreaW": [0.3420099108278517], "XMP:RegionAreaH": [0.39389216899871826], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:11:27 01:30:16"}]
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3097837567329407, 0.7126731872558595], "XMP:RegionAreaY": [0.33553561195731163, 0.4239872685185184], "XMP:RegionAreaW": [0.07461518356649322, 0.05], "XMP:RegionAreaH": [0.1119501069188118, 0.07501831501831502], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -53,6 +53,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3097837567329407, 0.7126731872558595], "XMP:RegionAreaY": [0.33553561195731163, 0.4239872685185184], "XMP:RegionAreaW": [0.07461518356649322, 0.05], "XMP:RegionAreaH": [0.1119501069188118, 0.07501831501831502], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -57,6 +57,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3097837567329407, 0.7126731872558595], "XMP:RegionAreaY": [0.33553561195731163, 0.4239872685185184], "XMP:RegionAreaW": [0.07461518356649322, 0.05], "XMP:RegionAreaH": [0.1119501069188118, 0.07501831501831502], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3097837567329407, 0.7126731872558595], "XMP:RegionAreaY": [0.33553561195731163, 0.4239872685185184], "XMP:RegionAreaW": [0.07461518356649322, 0.05], "XMP:RegionAreaH": [0.1119501069188118, 0.07501831501831502], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -59,6 +59,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"ImageDescription": "Girls with pumpkins", "Description": "Girls with pumpkins", "Caption-Abstract": "Girls with pumpkins", "Title": "Can we carry this?", "ObjectName": "Can we carry this?", "Keywords": ["Kids"], "Subject": ["Kids"], "TagsList": ["Kids"], "PersonInImage": ["Katie", "Suzy"], "DateTimeOriginal": "2018:09:28 15:35:49", "CreateDate": "2018:09:28 15:35:49", "OffsetTimeOriginal": "-04:00", "DateCreated": "2018:09:28", "TimeCreated": "15:35:49-04:00", "ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"ImageDescription": "Girls with pumpkins", "Description": "Girls with pumpkins", "Caption-Abstract": "Girls with pumpkins", "Title": "Can we carry this?", "ObjectName": "Can we carry this?", "Keywords": ["Kids"], "Subject": ["Kids"], "TagsList": ["Kids"], "PersonInImage": ["Katie", "Suzy"], "RegionAppliedToDimensionsW": 2048, "RegionAppliedToDimensionsH": 1365, "RegionAppliedToDimensionsUnit": "pixel", "RegionName": ["Suzy", "Katie"], "RegionType": ["Face", "Face"], "RegionAreaX": [0.3097837567329407, 0.7126731872558595], "RegionAreaY": [0.33553561195731163, 0.4239872685185184], "RegionAreaW": [0.07461518356649322, 0.05], "RegionAreaH": [0.1119501069188118, 0.07501831501831502], "RegionAreaUnit": ["normalized", "normalized"], "RegionPersonDisplayName": ["Suzy", "Katie"], "DateTimeOriginal": "2018:09:28 15:35:49", "CreateDate": "2018:09:28 15:35:49", "OffsetTimeOriginal": "-04:00", "DateCreated": "2018:09:28", "TimeCreated": "15:35:49-04:00", "ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Katie", "Kids", "Suzy"], "XMP:Subject": ["Katie", "Kids", "Suzy"], "XMP:TagsList": ["Katie", "Kids", "Suzy"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Katie", "Kids", "Suzy"], "XMP:Subject": ["Katie", "Kids", "Suzy"], "XMP:TagsList": ["Katie", "Kids", "Suzy"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3097837567329407, 0.7126731872558595], "XMP:RegionAreaY": [0.33553561195731163, 0.4239872685185184], "XMP:RegionAreaW": [0.07461518356649322, 0.05], "XMP:RegionAreaH": [0.1119501069188118, 0.07501831501831502], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -57,6 +57,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5898191407322884], "XMP:RegionAreaY": [0.28164292871952057], "XMP:RegionAreaW": [0.22411711513996124], "XMP:RegionAreaH": [0.14937493269826518], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5898191407322884], "XMP:RegionAreaY": [0.28164292871952057], "XMP:RegionAreaW": [0.22411711513996124], "XMP:RegionAreaH": [0.14937493269826518], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -60,6 +60,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5898191407322884], "XMP:RegionAreaY": [0.28164292871952057], "XMP:RegionAreaW": [0.22411711513996124], "XMP:RegionAreaH": [0.14937493269826518], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:Subject": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:TagsList": ["Kids", "Multi Keyword", "Pumpkin Farm", "Test Album"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5898191407322884], "XMP:RegionAreaY": [0.28164292871952057], "XMP:RegionAreaW": [0.22411711513996124], "XMP:RegionAreaH": [0.14937493269826518], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -62,6 +62,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"ImageDescription": "Girl holding pumpkin", "Description": "Girl holding pumpkin", "Caption-Abstract": "Girl holding pumpkin", "Title": "I found one!", "ObjectName": "I found one!", "Keywords": ["Kids"], "Subject": ["Kids"], "TagsList": ["Kids"], "PersonInImage": ["Katie"], "GPSLatitude": 41.256566, "GPSLongitude": -95.940257, "GPSLatitudeRef": "N", "GPSLongitudeRef": "W", "DateTimeOriginal": "2018:09:28 16:07:07", "CreateDate": "2018:09:28 16:07:07", "OffsetTimeOriginal": "-04:00", "DateCreated": "2018:09:28", "TimeCreated": "16:07:07-04:00", "ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"ImageDescription": "Girl holding pumpkin", "Description": "Girl holding pumpkin", "Caption-Abstract": "Girl holding pumpkin", "Title": "I found one!", "ObjectName": "I found one!", "Keywords": ["Kids"], "Subject": ["Kids"], "TagsList": ["Kids"], "PersonInImage": ["Katie"], "RegionAppliedToDimensionsW": 1365, "RegionAppliedToDimensionsH": 2048, "RegionAppliedToDimensionsUnit": "pixel", "RegionName": ["Katie"], "RegionType": ["Face"], "RegionAreaX": [0.5898191407322884], "RegionAreaY": [0.28164292871952057], "RegionAreaW": [0.22411711513996124], "RegionAreaH": [0.14937493269826518], "RegionAreaUnit": ["normalized"], "RegionPersonDisplayName": ["Katie"], "GPSLatitude": 41.256566, "GPSLongitude": -95.940257, "GPSLatitudeRef": "N", "GPSLongitudeRef": "W", "DateTimeOriginal": "2018:09:28 16:07:07", "CreateDate": "2018:09:28 16:07:07", "OffsetTimeOriginal": "-04:00", "DateCreated": "2018:09:28", "TimeCreated": "16:07:07-04:00", "ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Katie", "Kids"], "XMP:Subject": ["Katie", "Kids"], "XMP:TagsList": ["Katie", "Kids"], "XMP:PersonInImage": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
[{"EXIF:ImageDescription": "Girl holding pumpkin", "XMP:Description": "Girl holding pumpkin", "IPTC:Caption-Abstract": "Girl holding pumpkin", "XMP:Title": "I found one!", "IPTC:ObjectName": "I found one!", "IPTC:Keywords": ["Katie", "Kids"], "XMP:Subject": ["Katie", "Kids"], "XMP:TagsList": ["Katie", "Kids"], "XMP:PersonInImage": ["Katie"], "XMP:RegionAppliedToDimensionsW": 1365, "XMP:RegionAppliedToDimensionsH": 2048, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Katie"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.5898191407322884], "XMP:RegionAreaY": [0.28164292871952057], "XMP:RegionAreaW": [0.22411711513996124], "XMP:RegionAreaH": [0.14937493269826518], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Katie"], "EXIF:GPSLatitude": 41.256566, "EXIF:GPSLongitude": -95.940257, "EXIF:GPSLatitudeRef": "N", "EXIF:GPSLongitudeRef": "W", "EXIF:DateTimeOriginal": "2018:09:28 16:07:07", "EXIF:CreateDate": "2018:09:28 16:07:07", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "16:07:07-04:00", "EXIF:ModifyDate": "2018:09:28 16:07:07"}]
|
||||
@@ -56,6 +56,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>2048</stDim:h>
|
||||
<stDim:w>1365</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.41222959756851196], "XMP:RegionAreaY": [0.4221687614917755], "XMP:RegionAreaW": [0.3333342373371124], "XMP:RegionAreaH": [0.3839004122086291], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:Subject": ["AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:TagsList": ["AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:Subject": ["AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:TagsList": ["AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.41222959756851196], "XMP:RegionAreaY": [0.4221687614917755], "XMP:RegionAreaW": [0.3333342373371124], "XMP:RegionAreaH": [0.3839004122086291], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
@@ -60,6 +60,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:04:15 14:40:24"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.41222959756851196], "XMP:RegionAreaY": [0.4221687614917755], "XMP:RegionAreaW": [0.3333342373371124], "XMP:RegionAreaH": [0.3839004122086291], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:04:15 14:40:24"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Folder1/SubFolder2/AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:Subject": ["Folder1/SubFolder2/AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:TagsList": ["Folder1/SubFolder2/AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Folder1/SubFolder2/AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:Subject": ["Folder1/SubFolder2/AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:TagsList": ["Folder1/SubFolder2/AlbumInFolder", "I have a deleted twin", "Maria", "Multi Keyword", "wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.41222959756851196], "XMP:RegionAreaY": [0.4221687614917755], "XMP:RegionAreaW": [0.3333342373371124], "XMP:RegionAreaH": [0.3839004122086291], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
@@ -62,6 +62,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"ImageDescription": "Bride Wedding day", "Description": "Bride Wedding day", "Caption-Abstract": "Bride Wedding day", "Keywords": ["Maria", "wedding"], "Subject": ["Maria", "wedding"], "TagsList": ["Maria", "wedding"], "PersonInImage": ["Maria"], "DateTimeOriginal": "2019:04:15 14:40:24", "CreateDate": "2019:04:15 14:40:24", "OffsetTimeOriginal": "-04:00", "DateCreated": "2019:04:15", "TimeCreated": "14:40:24-04:00", "ModifyDate": "2019:07:27 17:33:28"}]
|
||||
[{"ImageDescription": "Bride Wedding day", "Description": "Bride Wedding day", "Caption-Abstract": "Bride Wedding day", "Keywords": ["Maria", "wedding"], "Subject": ["Maria", "wedding"], "TagsList": ["Maria", "wedding"], "PersonInImage": ["Maria"], "RegionAppliedToDimensionsW": 1526, "RegionAppliedToDimensionsH": 1325, "RegionAppliedToDimensionsUnit": "pixel", "RegionName": ["Maria"], "RegionType": ["Face"], "RegionAreaX": [0.41222959756851196], "RegionAreaY": [0.4221687614917755], "RegionAreaW": [0.3333342373371124], "RegionAreaH": [0.3839004122086291], "RegionAreaUnit": ["normalized"], "RegionPersonDisplayName": ["Maria"], "DateTimeOriginal": "2019:04:15 14:40:24", "CreateDate": "2019:04:15 14:40:24", "OffsetTimeOriginal": "-04:00", "DateCreated": "2019:04:15", "TimeCreated": "14:40:24-04:00", "ModifyDate": "2019:07:27 17:33:28"}]
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
[{"EXIF:ImageDescription": "Bride Wedding day", "XMP:Description": "Bride Wedding day", "IPTC:Caption-Abstract": "Bride Wedding day", "IPTC:Keywords": ["Maria", "wedding"], "XMP:Subject": ["Maria", "wedding"], "XMP:TagsList": ["Maria", "wedding"], "XMP:PersonInImage": ["Maria"], "XMP:RegionAppliedToDimensionsW": 1526, "XMP:RegionAppliedToDimensionsH": 1325, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Maria"], "XMP:RegionType": ["Face"], "XMP:RegionAreaX": [0.41222959756851196], "XMP:RegionAreaY": [0.4221687614917755], "XMP:RegionAreaW": [0.3333342373371124], "XMP:RegionAreaH": [0.3839004122086291], "XMP:RegionAreaUnit": ["normalized"], "XMP:RegionPersonDisplayName": ["Maria"], "EXIF:DateTimeOriginal": "2019:04:15 14:40:24", "EXIF:CreateDate": "2019:04:15 14:40:24", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2019:04:15", "IPTC:TimeCreated": "14:40:24-04:00", "EXIF:ModifyDate": "2019:07:27 17:33:28"}]
|
||||
@@ -54,6 +54,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1325</stDim:h>
|
||||
<stDim:w>1526</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3205035626888275, 0.7158178221434355], "XMP:RegionAreaY": [0.33566537871956825, 0.4209024980664253], "XMP:RegionAreaW": [0.07409769326841342, 0.06201007632625988], "XMP:RegionAreaH": [0.11117368191480637, 0.09303782880306244], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -53,6 +53,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids", "Pumpkin Farm", "Sorted Manual", "Sorted Newest First", "Sorted Oldest First", "Sorted Title", "Test Album"], "XMP:Subject": ["Kids", "Pumpkin Farm", "Sorted Manual", "Sorted Newest First", "Sorted Oldest First", "Sorted Title", "Test Album"], "XMP:TagsList": ["Kids", "Pumpkin Farm", "Sorted Manual", "Sorted Newest First", "Sorted Oldest First", "Sorted Title", "Test Album"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids", "Pumpkin Farm", "Sorted Manual", "Sorted Newest First", "Sorted Oldest First", "Sorted Title", "Test Album"], "XMP:Subject": ["Kids", "Pumpkin Farm", "Sorted Manual", "Sorted Newest First", "Sorted Oldest First", "Sorted Title", "Test Album"], "XMP:TagsList": ["Kids", "Pumpkin Farm", "Sorted Manual", "Sorted Newest First", "Sorted Oldest First", "Sorted Title", "Test Album"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3205035626888275, 0.7158178221434355], "XMP:RegionAreaY": [0.33566537871956825, 0.4209024980664253], "XMP:RegionAreaW": [0.07409769326841342, 0.06201007632625988], "XMP:RegionAreaH": [0.11117368191480637, 0.09303782880306244], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
@@ -65,6 +65,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#">
|
||||
<mwg-rs:Regions rdf:parseType="Resource">
|
||||
<mwg-rs:AppliedToDimensions rdf:parseType="Resource">
|
||||
<stDim:h>1365</stDim:h>
|
||||
<stDim:w>2048</stDim:w>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
</mwg-rs:AppliedToDimensions>
|
||||
<mwg-rs:RegionList>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
[{"EXIF:ImageDescription": "Girls with pumpkins", "XMP:Description": "Girls with pumpkins", "IPTC:Caption-Abstract": "Girls with pumpkins", "XMP:Title": "Can we carry this?", "IPTC:ObjectName": "Can we carry this?", "IPTC:Keywords": ["Kids"], "XMP:Subject": ["Kids"], "XMP:TagsList": ["Kids"], "XMP:PersonInImage": ["Katie", "Suzy"], "XMP:RegionAppliedToDimensionsW": 2048, "XMP:RegionAppliedToDimensionsH": 1365, "XMP:RegionAppliedToDimensionsUnit": "pixel", "XMP:RegionName": ["Suzy", "Katie"], "XMP:RegionType": ["Face", "Face"], "XMP:RegionAreaX": [0.3205035626888275, 0.7158178221434355], "XMP:RegionAreaY": [0.33566537871956825, 0.4209024980664253], "XMP:RegionAreaW": [0.07409769326841342, 0.06201007632625988], "XMP:RegionAreaH": [0.11117368191480637, 0.09303782880306244], "XMP:RegionAreaUnit": ["normalized", "normalized"], "XMP:RegionPersonDisplayName": ["Suzy", "Katie"], "EXIF:DateTimeOriginal": "2018:09:28 15:35:49", "EXIF:CreateDate": "2018:09:28 15:35:49", "EXIF:OffsetTimeOriginal": "-04:00", "IPTC:DateCreated": "2018:09:28", "IPTC:TimeCreated": "15:35:49-04:00", "EXIF:ModifyDate": "2018:09:28 15:35:49"}]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user