Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
062d8eb206 | ||
|
|
f0d7496bc6 | ||
|
|
8e2b768236 | ||
|
|
48bf326994 | ||
|
|
159d1102aa | ||
|
|
dbb4dbc0a7 | ||
|
|
777e768243 | ||
|
|
70999a70b8 | ||
|
|
3a6b2c2c35 | ||
|
|
dfb80ba8d6 | ||
|
|
94b818b156 | ||
|
|
f1cea1498b | ||
|
|
345678577a | ||
|
|
fb4138cfe6 | ||
|
|
db5b34d589 | ||
|
|
8963af9229 | ||
|
|
2041789ff4 | ||
|
|
aec86f93ea | ||
|
|
57bfb03e05 | ||
|
|
c2b2476e38 | ||
|
|
fa2027d453 | ||
|
|
9d980e4917 | ||
|
|
673243c6cd | ||
|
|
7376223eb8 | ||
|
|
ecd0b8e22f | ||
|
|
c4a608b5bd | ||
|
|
4d9e21ea16 | ||
|
|
1ee3e035c4 | ||
|
|
b1c0fb3e82 | ||
|
|
de715d2afd | ||
|
|
607cf80dda | ||
|
|
0c8fbd69af | ||
|
|
c2335236be | ||
|
|
123340eada | ||
|
|
852a06f99b | ||
|
|
9f8da5c623 | ||
|
|
077d577c98 | ||
|
|
12f39dbaf5 | ||
|
|
6e9f709279 | ||
|
|
666b6cac33 | ||
|
|
e95c096784 | ||
|
|
745161fbd1 | ||
|
|
8216c33b59 |
@@ -241,6 +241,15 @@
|
||||
"contributions": [
|
||||
"data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dssinger",
|
||||
"name": "David Singer",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1817903?v=4",
|
||||
"profile": "https://github.com/dssinger",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
83
CHANGELOG.md
83
CHANGELOG.md
@@ -4,6 +4,89 @@ 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.42.78](https://github.com/RhetTbull/osxphotos/compare/v0.42.77...v0.42.78)
|
||||
|
||||
> 29 August 2021
|
||||
|
||||
- docs: add dssinger as a contributor for bug [`#514`](https://github.com/RhetTbull/osxphotos/pull/514)
|
||||
- Fix for newlines in exif tags, #513 [`f0d7496`](https://github.com/RhetTbull/osxphotos/commit/f0d7496bc66aae291337efc570a2e2c4b9b5529c)
|
||||
|
||||
#### [v0.42.77](https://github.com/RhetTbull/osxphotos/compare/v0.42.74...v0.42.77)
|
||||
|
||||
> 28 August 2021
|
||||
|
||||
- Fixed --strip behavior, #511 [`dbb4dbc`](https://github.com/RhetTbull/osxphotos/commit/dbb4dbc0a7f7cb590ab3b2ce532c5c618c7fc249)
|
||||
- Update test for #506 [`f1cea14`](https://github.com/RhetTbull/osxphotos/commit/f1cea1498b3b973aa500d874126b9668a8743f1f)
|
||||
- Added {strip} template [`159d110`](https://github.com/RhetTbull/osxphotos/commit/159d1102aabd56def2caf6754747f7a4caa7d374)
|
||||
|
||||
#### [v0.42.74](https://github.com/RhetTbull/osxphotos/compare/v0.42.73...v0.42.74)
|
||||
|
||||
> 23 August 2021
|
||||
|
||||
- Fix for #506 [`db5b34d`](https://github.com/RhetTbull/osxphotos/commit/db5b34d58950c65f95d22a0e81390b9d4fb7ccd7)
|
||||
- Updated README [skip ci] [`fb4138c`](https://github.com/RhetTbull/osxphotos/commit/fb4138cfe6cfad02fead821b70b4b84d11b027e9)
|
||||
|
||||
#### [v0.42.73](https://github.com/RhetTbull/osxphotos/compare/v0.42.72...v0.42.73)
|
||||
|
||||
> 15 August 2021
|
||||
|
||||
- Added inspect() to repl, closes #501 [`#501`](https://github.com/RhetTbull/osxphotos/issues/501)
|
||||
- Updated docs for Text Detection [skip ci] [`c2b2476`](https://github.com/RhetTbull/osxphotos/commit/c2b2476e385fcd3773bd8abb942e788be2af8169)
|
||||
- Updated README.md [skip ci] [`2041789`](https://github.com/RhetTbull/osxphotos/commit/2041789ff4a3979a73712b27a51a77e8a880efb8)
|
||||
|
||||
#### [v0.42.72](https://github.com/RhetTbull/osxphotos/compare/v0.42.71...v0.42.72)
|
||||
|
||||
> 2 August 2021
|
||||
|
||||
- Improved caching of detected_text results [`fa2027d`](https://github.com/RhetTbull/osxphotos/commit/fa2027d45308738d2335d4b5a72c3ef5c478491a)
|
||||
|
||||
#### [v0.42.71](https://github.com/RhetTbull/osxphotos/compare/v0.42.70...v0.42.71)
|
||||
|
||||
> 29 July 2021
|
||||
|
||||
- Updated text_detection to detect macOS version [`7376223`](https://github.com/RhetTbull/osxphotos/commit/7376223eb87a4919fd54cc685a3f263e83626879)
|
||||
- Updated detected_text docs to make it clear this only works on Catalina+ [`ecd0b8e`](https://github.com/RhetTbull/osxphotos/commit/ecd0b8e22f8bf1f8d1e98d64834bebf0394dd903)
|
||||
- Fix for #500, check for macOS version before loading Vision [`673243c`](https://github.com/RhetTbull/osxphotos/commit/673243c6cd1c267b6b741b5429cdb63c062648d1)
|
||||
|
||||
#### [v0.42.70](https://github.com/RhetTbull/osxphotos/compare/v0.42.69...v0.42.70)
|
||||
|
||||
> 29 July 2021
|
||||
|
||||
- Added error logging to {detected_text} processing, #499 [`b1c0fb3`](https://github.com/RhetTbull/osxphotos/commit/b1c0fb3e8284600394ddbfdd7dfa94916a843c81)
|
||||
- Updated README.md [skip ci] [`1ee3e03`](https://github.com/RhetTbull/osxphotos/commit/1ee3e035c42d687158f7cf73382f0f263516dc37)
|
||||
- Removed unneeded test file [skip ci] [`607cf80`](https://github.com/RhetTbull/osxphotos/commit/607cf80dda37ad529edd91fe92af3885b04b9a37)
|
||||
|
||||
#### [v0.42.69](https://github.com/RhetTbull/osxphotos/compare/v0.42.67...v0.42.69)
|
||||
|
||||
> 28 July 2021
|
||||
|
||||
- Added {detected_text} template [`c233523`](https://github.com/RhetTbull/osxphotos/commit/c2335236be7a1eecf4f25a9dcb844df4d6372b5c)
|
||||
- Added PhotoInfo.detected_text() [`123340e`](https://github.com/RhetTbull/osxphotos/commit/123340eadabb0fb07209c4207ccad13a53de3619)
|
||||
- Updated dependencies [`0c8fbd6`](https://github.com/RhetTbull/osxphotos/commit/0c8fbd69af7a0d696de5224bf3c302e0c240905f)
|
||||
|
||||
#### [v0.42.67](https://github.com/RhetTbull/osxphotos/compare/v0.42.66...v0.42.67)
|
||||
|
||||
> 24 July 2021
|
||||
|
||||
- Added {album_seq} and {folder_album_seq}, #496 [`12f39db`](https://github.com/RhetTbull/osxphotos/commit/12f39dbaf520ad767e3da667257ce00af60fdd7e)
|
||||
- Fixed {album_seq} and {folder_album_seq} help text [`077d577`](https://github.com/RhetTbull/osxphotos/commit/077d577c9890c4840a60c3e450dcd4167aa669ea)
|
||||
|
||||
#### [v0.42.66](https://github.com/RhetTbull/osxphotos/compare/v0.42.65...v0.42.66)
|
||||
|
||||
> 23 July 2021
|
||||
|
||||
- Updated docs [`666b6ca`](https://github.com/RhetTbull/osxphotos/commit/666b6cac33fb8a2d0fc602609f11e190e11c538f)
|
||||
- Added {id} sequence number template, #154 [`e95c096`](https://github.com/RhetTbull/osxphotos/commit/e95c0967846106f6da2adaa0b85520df8b351bb0)
|
||||
- Updated example [skip ci] [`8216c33`](https://github.com/RhetTbull/osxphotos/commit/8216c33b596dba35007168cda4e8de34d9f4b2ea)
|
||||
|
||||
#### [v0.42.65](https://github.com/RhetTbull/osxphotos/compare/v0.42.64...v0.42.65)
|
||||
|
||||
> 20 July 2021
|
||||
|
||||
- Fixed album sort order for custom sort, #497 [`e27c40c`](https://github.com/RhetTbull/osxphotos/commit/e27c40c7724dc47a7c95d1a417808c2b1f13adb0)
|
||||
- Updated test data [`a05e7be`](https://github.com/RhetTbull/osxphotos/commit/a05e7be14e080af0cef80831c3ff7fa0a897a1b2)
|
||||
- Updated example [skip ci] [`6f4cab6`](https://github.com/RhetTbull/osxphotos/commit/6f4cab6721ca3091031d8010e29d959e3afdecb2)
|
||||
|
||||
#### [v0.42.64](https://github.com/RhetTbull/osxphotos/compare/v0.42.63...v0.42.64)
|
||||
|
||||
> 18 July 2021
|
||||
|
||||
@@ -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: 210ecd9d654dea5d4c21627449ca1d63
|
||||
config: 23e7c9cd300c96ffa7fce04034b83f61
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Overview: module code — osxphotos 0.42.20 documentation</title>
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||||
<title>Overview: module code — osxphotos 0.42.69 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>
|
||||
<script src="../_static/jquery.js"></script>
|
||||
<script src="../_static/underscore.js"></script>
|
||||
<script src="../_static/doctools.js"></script>
|
||||
@@ -31,7 +31,11 @@
|
||||
<div class="body" role="main">
|
||||
|
||||
<h1>All modules for which code is available</h1>
|
||||
<ul><li><a href="osxphotos/photoinfo/photoinfo.html">osxphotos.photoinfo.photoinfo</a></li>
|
||||
<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>
|
||||
<li><a href="osxphotos/photosdb/photosdb.html">osxphotos.photosdb.photosdb</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -89,7 +93,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.42.20 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.42.69 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>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
@@ -36,7 +36,6 @@
|
||||
<span class="sd">Represents a single photo in the Photos library and provides access to the photo's attributes</span>
|
||||
<span class="sd">PhotosDB.photos() returns a list of PhotoInfo objects</span>
|
||||
<span class="sd">"""</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">dataclasses</span>
|
||||
<span class="kn">import</span> <span class="nn">datetime</span>
|
||||
<span class="kn">import</span> <span class="nn">json</span>
|
||||
@@ -45,6 +44,7 @@
|
||||
<span class="kn">import</span> <span class="nn">os.path</span>
|
||||
<span class="kn">import</span> <span class="nn">pathlib</span>
|
||||
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span>
|
||||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">yaml</span>
|
||||
|
||||
@@ -63,13 +63,16 @@
|
||||
<span class="n">BURST_KEY</span><span class="p">,</span>
|
||||
<span class="n">BURST_NOT_SELECTED</span><span class="p">,</span>
|
||||
<span class="n">BURST_SELECTED</span><span class="p">,</span>
|
||||
<span class="n">TEXT_DETECTION_CONFIDENCE_THRESHOLD</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">..adjustmentsinfo</span> <span class="kn">import</span> <span class="n">AdjustmentsInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..albuminfo</span> <span class="kn">import</span> <span class="n">AlbumInfo</span><span class="p">,</span> <span class="n">ImportInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..personinfo</span> <span class="kn">import</span> <span class="n">FaceInfo</span><span class="p">,</span> <span class="n">PersonInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..phototemplate</span> <span class="kn">import</span> <span class="n">PhotoTemplate</span>
|
||||
<span class="kn">from</span> <span class="nn">..phototemplate</span> <span class="kn">import</span> <span class="n">PhotoTemplate</span><span class="p">,</span> <span class="n">RenderOptions</span>
|
||||
<span class="kn">from</span> <span class="nn">..placeinfo</span> <span class="kn">import</span> <span class="n">PlaceInfo4</span><span class="p">,</span> <span class="n">PlaceInfo5</span>
|
||||
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="n">_debug</span><span class="p">,</span> <span class="n">_get_resource_loc</span><span class="p">,</span> <span class="n">findfiles</span><span class="p">,</span> <span class="n">get_preferred_uti_extension</span>
|
||||
<span class="kn">from</span> <span class="nn">..text_detection</span> <span class="kn">import</span> <span class="n">detect_text</span>
|
||||
<span class="kn">from</span> <span class="nn">..uti</span> <span class="kn">import</span> <span class="n">get_preferred_uti_extension</span><span class="p">,</span> <span class="n">get_uti_for_extension</span>
|
||||
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="n">_debug</span><span class="p">,</span> <span class="n">_get_resource_loc</span><span class="p">,</span> <span class="n">findfiles</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="PhotoInfo"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotoInfo">[docs]</a><span class="k">class</span> <span class="nc">PhotoInfo</span><span class="p">:</span>
|
||||
@@ -79,30 +82,31 @@
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="c1"># import additional methods</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_searchinfo</span> <span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="n">search_info</span><span class="p">,</span>
|
||||
<span class="n">search_info_normalized</span><span class="p">,</span>
|
||||
<span class="n">labels</span><span class="p">,</span>
|
||||
<span class="n">labels_normalized</span><span class="p">,</span>
|
||||
<span class="n">SearchInfo</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_exifinfo</span> <span class="kn">import</span> <span class="n">exif_info</span><span class="p">,</span> <span class="n">ExifInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_comments</span> <span class="kn">import</span> <span class="n">comments</span><span class="p">,</span> <span class="n">likes</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_exifinfo</span> <span class="kn">import</span> <span class="n">ExifInfo</span><span class="p">,</span> <span class="n">exif_info</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_exiftool</span> <span class="kn">import</span> <span class="n">exiftool</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_export</span> <span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="n">export</span><span class="p">,</span>
|
||||
<span class="n">export2</span><span class="p">,</span>
|
||||
<span class="n">_export_photo</span><span class="p">,</span>
|
||||
<span class="n">ExportResults</span><span class="p">,</span>
|
||||
<span class="n">_exiftool_dict</span><span class="p">,</span>
|
||||
<span class="n">_exiftool_json_sidecar</span><span class="p">,</span>
|
||||
<span class="n">_export_photo</span><span class="p">,</span>
|
||||
<span class="n">_export_photo_with_photos_export</span><span class="p">,</span>
|
||||
<span class="n">_get_exif_keywords</span><span class="p">,</span>
|
||||
<span class="n">_get_exif_persons</span><span class="p">,</span>
|
||||
<span class="n">_write_exif_data</span><span class="p">,</span>
|
||||
<span class="n">_write_sidecar</span><span class="p">,</span>
|
||||
<span class="n">_xmp_sidecar</span><span class="p">,</span>
|
||||
<span class="n">ExportResults</span><span class="p">,</span>
|
||||
<span class="n">export</span><span class="p">,</span>
|
||||
<span class="n">export2</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_scoreinfo</span> <span class="kn">import</span> <span class="n">ScoreInfo</span><span class="p">,</span> <span class="n">score</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_searchinfo</span> <span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="n">SearchInfo</span><span class="p">,</span>
|
||||
<span class="n">labels</span><span class="p">,</span>
|
||||
<span class="n">labels_normalized</span><span class="p">,</span>
|
||||
<span class="n">search_info</span><span class="p">,</span>
|
||||
<span class="n">search_info_normalized</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_scoreinfo</span> <span class="kn">import</span> <span class="n">score</span><span class="p">,</span> <span class="n">ScoreInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">._photoinfo_comments</span> <span class="kn">import</span> <span class="n">comments</span><span class="p">,</span> <span class="n">likes</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">db</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span> <span class="o">=</span> <span class="n">uuid</span>
|
||||
@@ -110,9 +114,12 @@
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_verbose</span>
|
||||
|
||||
<span class="c1"># TODO: remove this once refactor of PhotoExporter is done</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_render_options</span> <span class="o">=</span> <span class="n">RenderOptions</span><span class="p">()</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">filename</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" filename of the picture """</span>
|
||||
<span class="sd">"""filename of the picture"""</span>
|
||||
<span class="k">if</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span>
|
||||
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_raw</span>
|
||||
@@ -140,7 +147,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">date</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" image creation date as timezone aware datetime object """</span>
|
||||
<span class="sd">"""image creation date as timezone aware datetime object"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"imageDate"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
@@ -166,52 +173,22 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">tzoffset</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" timezone offset from UTC in seconds """</span>
|
||||
<span class="sd">"""timezone offset from UTC in seconds"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"imageTimeZoneOffsetSeconds"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">path</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" absolute path on disk of the original picture """</span>
|
||||
<span class="sd">"""absolute path on disk of the original picture"""</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">_path</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">_path</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="c1"># TODO: should path try to return path even if ismissing?</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</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="mi">1</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">photopath</span> <span class="c1"># path would be meaningless until downloaded</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"has_raw"</span><span class="p">]:</span>
|
||||
<span class="c1"># return the path to JPEG even if RAW is original</span>
|
||||
<span class="n">vol</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"volumeId"</span><span class="p">]]</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"volumeId"</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="kc">None</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">vol</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="s2">"/Volumes"</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">],</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">vol</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">vol</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="s2">"/Volumes"</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">photopath</span><span class="p">):</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_path</span> <span class="o">=</span> <span class="n">photopath</span>
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_4</span><span class="p">()</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"shared"</span><span class="p">]:</span>
|
||||
<span class="c1"># shared photo</span>
|
||||
@@ -241,9 +218,40 @@
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_path</span> <span class="o">=</span> <span class="n">photopath</span>
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_path_4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return path for photo on Photos <= version 4"""</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"has_raw"</span><span class="p">]:</span>
|
||||
<span class="c1"># return the path to JPEG even if RAW is original</span>
|
||||
<span class="n">vol</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"volumeId"</span><span class="p">]]</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"volumeId"</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="kc">None</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">vol</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="s2">"/Volumes"</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">],</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">vol</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">vol</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"/Volumes"</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"imagePath"</span><span class="p">])</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">photopath</span><span class="p">):</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_path</span> <span class="o">=</span> <span class="n">photopath</span>
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">path_edited</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" absolute path on disk of the edited picture """</span>
|
||||
<span class="sd">"""absolute path on disk of the edited picture"""</span>
|
||||
<span class="sd">""" None if photo has not been edited """</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
@@ -257,7 +265,7 @@
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_edited</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_path_edited_5</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return path_edited for Photos >= 5 """</span>
|
||||
<span class="sd">"""return path_edited for Photos >= 5"""</span>
|
||||
<span class="c1"># In Photos 5.0 / Catalina / MacOS 10.15:</span>
|
||||
<span class="c1"># edited photos appear to always be converted to .jpeg and stored in</span>
|
||||
<span class="c1"># library_name/resources/renders/X/UUID_1_201_a.jpeg</span>
|
||||
@@ -280,14 +288,10 @@
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"type"</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTO_TYPE</span><span class="p">:</span>
|
||||
<span class="c1"># it's a photo</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">==</span> <span class="mi">5</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_1_201_a.jpeg"</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">!=</span> <span class="mi">5</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span> <span class="o">==</span> <span class="s2">"public.heic"</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_1_201_a.heic"</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># could be a heic or a jpeg</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span> <span class="o">==</span> <span class="s2">"public.heic"</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_1_201_a.heic"</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_1_201_a.jpeg"</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_1_201_a.jpeg"</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"type"</span><span class="p">]</span> <span class="o">==</span> <span class="n">_MOVIE_TYPE</span><span class="p">:</span>
|
||||
<span class="c1"># it's a movie</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_2_0_a.mov"</span>
|
||||
@@ -315,7 +319,7 @@
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_path_edited_4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return path_edited for Photos <= 4 """</span>
|
||||
<span class="sd">"""return path_edited for Photos <= 4"""</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">></span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Wrong database format!"</span><span class="p">)</span>
|
||||
@@ -373,9 +377,40 @@
|
||||
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">path_edited_live_photo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return path to edited version of live photo movie; only valid for Photos 5+"""</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><</span> <span class="n">_PHOTOS_5_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</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">_path_edited_live_photo</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">_path_edited_live_photo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_edited_5_live_photo</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_edited_live_photo</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_path_edited_5_live_photo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return path_edited_live_photo for Photos >= 5"""</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><</span> <span class="n">_PHOTOS_5_VERSION</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Wrong database format!"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">live_photo</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"hasAdjustments"</span><span class="p">]:</span>
|
||||
<span class="n">library</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span>
|
||||
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">_2_100_a.mov"</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="n">library</span><span class="p">,</span> <span class="s2">"resources"</span><span class="p">,</span> <span class="s2">"renders"</span><span class="p">,</span> <span class="n">directory</span><span class="p">,</span> <span class="n">filename</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">photopath</span><span class="p">):</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">path_raw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" absolute path of associated RAW image or None if there is not one """</span>
|
||||
<span class="sd">"""absolute path of associated RAW image or None if there is not one"""</span>
|
||||
|
||||
<span class="c1"># In Photos 5, raw is in same folder as original but with _4.ext</span>
|
||||
<span class="c1"># Unless "Copy Items to the Photos Library" is not checked</span>
|
||||
@@ -402,60 +437,72 @@
|
||||
<span class="c1"># return photopath</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="n">vol</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_info"</span><span class="p">][</span><span class="s2">"volume"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">vol</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="s2">"/Volumes"</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">photopath</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">"MISSING PATH: RAW photo for UUID </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2"> should be at </span><span class="si">{</span><span class="n">photopath</span><span class="si">}</span><span class="s2"> but does not appear to exist"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_raw_4</span><span class="p">()</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">isreference</span><span class="p">:</span>
|
||||
<span class="n">filestem</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"filename"</span><span class="p">])</span><span class="o">.</span><span class="n">stem</span>
|
||||
<span class="n">raw_ext</span> <span class="o">=</span> <span class="n">get_preferred_uti_extension</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"UTI_raw"</span><span class="p">])</span>
|
||||
<span class="c1"># raw_ext = get_preferred_uti_extension(self._info["UTI_raw"])</span>
|
||||
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</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">startswith</span><span class="p">(</span><span class="s2">"/"</span><span class="p">):</span>
|
||||
<span class="n">filepath</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"directory"</span><span class="p">]</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">filepath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"directory"</span><span class="p">])</span>
|
||||
|
||||
<span class="n">glob_str</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">filestem</span><span class="si">}</span><span class="s2">*.</span><span class="si">{</span><span class="n">raw_ext</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="c1"># raw files have same name as original but with _4.raw_ext appended</span>
|
||||
<span class="c1"># I believe the _4 maps to PHAssetResourceTypeAlternatePhoto = 4</span>
|
||||
<span class="c1"># see: https://developer.apple.com/documentation/photokit/phassetresourcetype/phassetresourcetypealternatephoto?language=objc</span>
|
||||
<span class="n">glob_str</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">filestem</span><span class="si">}</span><span class="s2">_4*"</span>
|
||||
<span class="n">raw_file</span> <span class="o">=</span> <span class="n">findfiles</span><span class="p">(</span><span class="n">glob_str</span><span class="p">,</span> <span class="n">filepath</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">raw_file</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="c1"># Note: In Photos Version 5.0 (141.19.150), images not copied to Photos Library</span>
|
||||
<span class="c1"># that are missing do not always trigger is_missing = True as happens</span>
|
||||
<span class="c1"># in earlier version so it's possible for this check to fail, if so, return None</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">"Error getting path to RAW file: </span><span class="si">{</span><span class="n">filepath</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">glob_str</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">raw_file</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="n">raw_file</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">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">photopath</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">"MISSING PATH: RAW photo for UUID </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2"> should be at </span><span class="si">{</span><span class="n">photopath</span><span class="si">}</span><span class="s2"> but does not appear to exist"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span> <span class="o">/</span> <span class="n">raw_file</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">photopath</span><span class="p">)</span> <span class="k">if</span> <span class="n">photopath</span><span class="o">.</span><span class="n">is_file</span><span class="p">()</span> <span class="k">else</span> <span class="kc">None</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># is a reference</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">"/Volumes"</span><span class="p">)</span>
|
||||
<span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_volume"</span><span class="p">]</span>
|
||||
<span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_relative_path"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">photopath</span><span class="p">)</span> <span class="k">if</span> <span class="n">photopath</span><span class="o">.</span><span class="n">is_file</span><span class="p">()</span> <span class="k">else</span> <span class="kc">None</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="c1"># don't have the path details</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">photopath</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_path_raw_4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Return path_raw for Photos <= version 4"""</span>
|
||||
<span class="n">vol</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_info"</span><span class="p">][</span><span class="s2">"volume"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">vol</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="s2">"/Volumes"</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_info"</span><span class="p">][</span><span class="s2">"imagePath"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">photopath</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">"MISSING PATH: RAW photo for UUID </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2"> should be at </span><span class="si">{</span><span class="n">photopath</span><span class="si">}</span><span class="s2"> but does not appear to exist"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">description</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" long / extended description of picture """</span>
|
||||
<span class="sd">"""long / extended description of picture"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"extendedDescription"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">persons</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" list of persons in picture """</span>
|
||||
<span class="sd">"""list of persons in picture"""</span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</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="s2">"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">_info</span><span class="p">[</span><span class="s2">"persons"</span><span class="p">]]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">person_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" list of PersonInfo objects for person in picture """</span>
|
||||
<span class="sd">"""list of PersonInfo objects for person in picture"""</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">_personinfo</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -466,7 +513,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">face_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" list of FaceInfo objects for faces in picture """</span>
|
||||
<span class="sd">"""list of FaceInfo objects for faces in picture"""</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">_faceinfo</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -480,7 +527,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">albums</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" list of albums picture is contained in """</span>
|
||||
<span class="sd">"""list of albums picture is contained in"""</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">_albums</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -492,7 +539,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">burst_albums</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""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 """</span>
|
||||
<span class="sd">"""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"""</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">_burst_albums</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -505,7 +552,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" list of AlbumInfo objects representing albums the photo is contained in """</span>
|
||||
<span class="sd">"""list of AlbumInfo objects representing albums the photo is contained in"""</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">_album_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -517,7 +564,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">burst_album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" 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. """</span>
|
||||
<span class="sd">"""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."""</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">_burst_album_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -530,7 +577,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">import_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" ImportInfo object representing import session for the photo or None if no import session """</span>
|
||||
<span class="sd">"""ImportInfo object representing import session for the photo or None if no import session"""</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">_import_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -543,17 +590,17 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">keywords</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" list of keywords for picture """</span>
|
||||
<span class="sd">"""list of keywords for picture"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"keywords"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" name / title of picture """</span>
|
||||
<span class="sd">"""name / title of picture"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" UUID of picture """</span>
|
||||
<span class="sd">"""UUID of picture"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
@@ -571,12 +618,12 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">hasadjustments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" True if picture has adjustments / edits """</span>
|
||||
<span class="sd">"""True if picture has adjustments / edits"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"hasAdjustments"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">adjustments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only """</span>
|
||||
<span class="sd">"""Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only"""</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
|
||||
@@ -600,32 +647,32 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">external_edit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if picture was edited outside of Photos using external editor """</span>
|
||||
<span class="sd">"""Returns True if picture was edited outside of Photos using external editor"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"adjustmentFormatID"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"com.apple.Photos.externalEdit"</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">favorite</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" True if picture is marked as favorite """</span>
|
||||
<span class="sd">"""True if picture is marked as favorite"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"favorite"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">hidden</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" True if picture is hidden """</span>
|
||||
<span class="sd">"""True if picture is hidden"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"hidden"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">visible</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" True if picture is visble """</span>
|
||||
<span class="sd">"""True if picture is visble"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"visible"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">intrash</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" True if picture is in trash ('Recently Deleted' folder)"""</span>
|
||||
<span class="sd">"""True if picture is in trash ('Recently Deleted' folder)"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"intrash"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">date_trashed</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Date asset was placed in the trash or None """</span>
|
||||
<span class="sd">"""Date asset was placed in the trash or None"""</span>
|
||||
<span class="c1"># TODO: add add_timezone(dt, offset_seconds) to datetime_utils</span>
|
||||
<span class="c1"># also update date_modified</span>
|
||||
<span class="n">trasheddate</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"trasheddate"</span><span class="p">]</span>
|
||||
@@ -639,7 +686,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">date_added</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Date photo was added to the database """</span>
|
||||
<span class="sd">"""Date photo was added to 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">_date_added</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -656,7 +703,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">location</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns (latitude, longitude) as float in degrees or None """</span>
|
||||
<span class="sd">"""returns (latitude, longitude) as float in degrees or None"""</span>
|
||||
<span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_latitude</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_longitude</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
@@ -690,13 +737,23 @@
|
||||
<span class="sd">"""Returns Uniform Type Identifier (UTI) for the original image</span>
|
||||
<span class="sd"> for example: public.jpeg or com.apple.quicktime-movie</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"has_raw"</span><span class="p">]:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"UTI"</span><span class="p">]</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared</span><span class="p">:</span>
|
||||
<span class="c1"># TODO: need reliable way to get original UTI for shared</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"UTI_original"</span><span class="p">]</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uti_original</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"has_raw"</span><span class="p">]:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_uti_original</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"raw_pair_info"</span><span class="p">][</span><span class="s2">"UTI"</span><span class="p">]</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared</span><span class="p">:</span>
|
||||
<span class="c1"># TODO: need reliable way to get original UTI for shared</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_uti_original</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span>
|
||||
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">>=</span> <span class="mi">7</span><span class="p">:</span>
|
||||
<span class="c1"># Monterey+</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_uti_original</span> <span class="o">=</span> <span class="n">get_uti_for_extension</span><span class="p">(</span>
|
||||
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span><span class="p">)</span><span class="o">.</span><span class="n">suffix</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_uti_original</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"UTI_original"</span><span class="p">]</span>
|
||||
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uti_original</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">uti_edited</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
@@ -715,7 +772,14 @@
|
||||
<span class="sd"> for example: com.canon.cr2-raw-image</span>
|
||||
<span class="sd"> Returns None if no associated RAW image</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"UTI_raw"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o"><</span> <span class="mi">7</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"UTI_raw"</span><span class="p">]</span>
|
||||
|
||||
<span class="n">rawpath</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_raw</span>
|
||||
<span class="k">if</span> <span class="n">rawpath</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">get_uti_for_extension</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">rawpath</span><span class="p">)</span><span class="o">.</span><span class="n">suffix</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">ismovie</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
@@ -752,27 +816,27 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">isreference</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a reference (not copied to the Photos library), otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a reference (not copied to the Photos library), otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"isreference"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">burst</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is part of a Burst photo set, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is part of a Burst photo set, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"burst"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">burst_selected</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a burst photo and has been selected from the burst set by the user, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a burst photo and has been selected from the burst set by the user, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</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="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">burst_key</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" 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 """</span>
|
||||
<span class="sd">"""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"""</span>
|
||||
<span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</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="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">burst_default_pick</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" 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 """</span>
|
||||
<span class="sd">"""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"""</span>
|
||||
<span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"burstPickType"</span><span class="p">]</span> <span class="o">&</span> <span class="n">BURST_DEFAULT_PICK</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
@@ -792,7 +856,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">live_photo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a live photo, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a live photo, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"live_photo"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
@@ -853,25 +917,40 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">path_derivatives</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Return any derivative (preview) images associated with the photo as a list of paths, sorted by file size (largest first) """</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives_4</span><span class="p">()</span>
|
||||
<span class="sd">"""Return any derivative (preview) images associated with the photo as a list of paths, sorted by file size (largest first)"""</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">_path_derivatives</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives_4</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives</span>
|
||||
|
||||
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
|
||||
<span class="n">derivative_path</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span>
|
||||
<span class="o">/</span> <span class="s2">"resources"</span>
|
||||
<span class="o">/</span> <span class="s2">"derivatives"</span>
|
||||
<span class="o">/</span> <span class="n">directory</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">files</span> <span class="o">=</span> <span class="n">derivative_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">*.*"</span><span class="p">)</span>
|
||||
<span class="n">files</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">files</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span><span class="o">.</span><span class="n">st_size</span><span class="p">)</span>
|
||||
<span class="c1"># return list of filename but skip .THM files (these are actually low-res thumbnails in JPEG format but with .THM extension)</span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">files</span> <span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">suffix</span> <span class="o">!=</span> <span class="s2">".THM"</span><span class="p">]</span>
|
||||
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
|
||||
<span class="n">derivative_path</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span>
|
||||
<span class="o">/</span> <span class="s2">"resources"</span>
|
||||
<span class="o">/</span> <span class="s2">"derivatives"</span>
|
||||
<span class="o">/</span> <span class="n">directory</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">files</span> <span class="o">=</span> <span class="n">derivative_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">*.*"</span><span class="p">)</span>
|
||||
<span class="n">files</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">files</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span><span class="o">.</span><span class="n">st_size</span><span class="p">)</span>
|
||||
<span class="c1"># return list of filename but skip .THM files (these are actually low-res thumbnails in JPEG format but with .THM extension)</span>
|
||||
<span class="n">derivatives</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nb">str</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">files</span> <span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">suffix</span> <span class="o">!=</span> <span class="s2">".THM"</span>
|
||||
<span class="p">]</span>
|
||||
<span class="k">if</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span>
|
||||
<span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">derivatives</span><span class="p">)</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="ow">and</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">".mov"</span><span class="p">)</span>
|
||||
<span class="p">):</span>
|
||||
<span class="n">derivatives</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">derivatives</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">_path_derivatives</span> <span class="o">=</span> <span class="n">derivatives</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_path_derivatives_4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Return paths to all derivative (preview) files for Photos <= 4"""</span>
|
||||
<span class="n">modelid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"masterModelID"</span><span class="p">]</span>
|
||||
<span class="sd">"""Return paths to all derivative (preview) files for Photos <= 4"""</span>
|
||||
<span class="n">modelid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"modelID"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">modelid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="p">[]</span>
|
||||
<span class="n">folder_id</span><span class="p">,</span> <span class="n">file_id</span> <span class="o">=</span> <span class="n">_get_resource_loc</span><span class="p">(</span><span class="n">modelid</span><span class="p">)</span>
|
||||
@@ -907,42 +986,42 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">panorama</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a panorama, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a panorama, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"panorama"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">slow_mo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a slow motion video, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a slow motion video, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"slow_mo"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">time_lapse</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a time lapse video, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a time lapse video, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"time_lapse"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">hdr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is an HDR photo, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is an HDR photo, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"hdr"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">screenshot</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is an HDR photo, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is an HDR photo, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"screenshot"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">portrait</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a portrait, otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a portrait, otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"portrait"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">selfie</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns True if photo is a selfie (front facing camera), otherwise False """</span>
|
||||
<span class="sd">"""Returns True if photo is a selfie (front facing camera), otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"selfie"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">place</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns PlaceInfo object containing reverse geolocation info """</span>
|
||||
<span class="sd">"""Returns PlaceInfo object containing reverse geolocation info"""</span>
|
||||
|
||||
<span class="c1"># implementation note: doesn't create the PlaceInfo object until requested</span>
|
||||
<span class="c1"># then memoizes the object in self._place to avoid recreating the object</span>
|
||||
@@ -970,12 +1049,12 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">has_raw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns True if photo has an associated raw image (that is, it's a RAW+JPEG pair), otherwise False """</span>
|
||||
<span class="sd">"""returns True if photo has an associated raw image (that is, it's a RAW+JPEG pair), otherwise False"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"has_raw"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">israw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns True if photo is a raw image. For images with an associated RAW+JPEG pair, see has_raw """</span>
|
||||
<span class="sd">"""returns True if photo is a raw image. For images with an associated RAW+JPEG pair, see has_raw"""</span>
|
||||
<span class="k">return</span> <span class="s2">"raw-image"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_original</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
@@ -987,17 +1066,17 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">height</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns height of the current photo version in pixels """</span>
|
||||
<span class="sd">"""returns height of the current photo version in pixels"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"height"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">width</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns width of the current photo version in pixels """</span>
|
||||
<span class="sd">"""returns width of the current photo version in pixels"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"width"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">orientation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns EXIF orientation of the current photo version as int or 0 if current orientation cannot be determined """</span>
|
||||
<span class="sd">"""returns EXIF orientation of the current photo version as int or 0 if current orientation cannot be determined"""</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"orientation"</span><span class="p">]</span>
|
||||
|
||||
@@ -1013,76 +1092,98 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">original_height</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns height of the original photo version in pixels """</span>
|
||||
<span class="sd">"""returns height of the original photo version in pixels"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"original_height"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">original_width</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns width of the original photo version in pixels """</span>
|
||||
<span class="sd">"""returns width of the original photo version in pixels"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"original_width"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">original_orientation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns EXIF orientation of the original photo version as int """</span>
|
||||
<span class="sd">"""returns EXIF orientation of the original photo version as int"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"original_orientation"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">original_filesize</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns filesize of original photo in bytes as int """</span>
|
||||
<span class="sd">"""returns filesize of original photo in bytes as int"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"original_filesize"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">duplicates</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return list of PhotoInfo objects for possible duplicates (matching signature of original size, date, height, width) or empty list if no matching duplicates"""</span>
|
||||
<span class="n">signature</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_duplicate_signature</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">)</span>
|
||||
<span class="n">duplicates</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]:</span>
|
||||
<span class="k">if</span> <span class="n">uuid</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">:</span>
|
||||
<span class="c1"># found a possible duplicate</span>
|
||||
<span class="n">duplicates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">get_photo</span><span class="p">(</span><span class="n">uuid</span><span class="p">))</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
<span class="c1"># don't expect this to happen as the signature should be in db</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">"Did not find signature for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2"> in _db_signatures"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">duplicates</span>
|
||||
|
||||
<div class="viewcode-block" id="PhotoInfo.render_template"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotoInfo.render_template">[docs]</a> <span class="k">def</span> <span class="nf">render_template</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="p">,</span>
|
||||
<span class="n">template_str</span><span class="p">,</span>
|
||||
<span class="n">none_str</span><span class="o">=</span><span class="s2">"_"</span><span class="p">,</span>
|
||||
<span class="n">path_sep</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">expand_inplace</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">inplace_sep</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">dirname</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">strip</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">edited</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="bp">self</span><span class="p">,</span> <span class="n">template_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">RenderOptions</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">"""Renders a template string for PhotoInfo instance using PhotoTemplate</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> template_str: a template string with fields to render</span>
|
||||
<span class="sd"> none_str: a str to use if template field renders to None, default is "_".</span>
|
||||
<span class="sd"> path_sep: a single character str to use as path separator when joining</span>
|
||||
<span class="sd"> fields like folder_album; if not provided, defaults to os.path.sep</span>
|
||||
<span class="sd"> expand_inplace: expand multi-valued substitutions in-place as a single string</span>
|
||||
<span class="sd"> instead of returning individual strings</span>
|
||||
<span class="sd"> inplace_sep: optional string to use as separator between multi-valued keywords</span>
|
||||
<span class="sd"> with expand_inplace; default is ','</span>
|
||||
<span class="sd"> filename: if True, template output will be sanitized to produce valid file name</span>
|
||||
<span class="sd"> dirname: if True, template output will be sanitized to produce valid directory name</span>
|
||||
<span class="sd"> strip: if True, strips leading/trailing white space from resulting template</span>
|
||||
<span class="sd"> edited: if True, sets {edited_version} field to True, otherwise it gets set to False; set if you want template evaluated for edited version</span>
|
||||
<span class="sd"> options: a RenderOptions instance</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> ([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">options</span> <span class="o">=</span> <span class="n">options</span> <span class="ow">or</span> <span class="n">RenderOptions</span><span class="p">()</span>
|
||||
<span class="n">template</span> <span class="o">=</span> <span class="n">PhotoTemplate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exiftool_path</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_exiftool_path</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span>
|
||||
<span class="n">template_str</span><span class="p">,</span>
|
||||
<span class="n">none_str</span><span class="o">=</span><span class="n">none_str</span><span class="p">,</span>
|
||||
<span class="n">path_sep</span><span class="o">=</span><span class="n">path_sep</span><span class="p">,</span>
|
||||
<span class="n">expand_inplace</span><span class="o">=</span><span class="n">expand_inplace</span><span class="p">,</span>
|
||||
<span class="n">inplace_sep</span><span class="o">=</span><span class="n">inplace_sep</span><span class="p">,</span>
|
||||
<span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">,</span>
|
||||
<span class="n">dirname</span><span class="o">=</span><span class="n">dirname</span><span class="p">,</span>
|
||||
<span class="n">strip</span><span class="o">=</span><span class="n">strip</span><span class="p">,</span>
|
||||
<span class="n">edited_version</span><span class="o">=</span><span class="n">edited</span><span class="p">,</span>
|
||||
<span class="p">)</span></div>
|
||||
<span class="k">return</span> <span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">template_str</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span></div>
|
||||
|
||||
<div class="viewcode-block" id="PhotoInfo.detected_text"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotoInfo.detected_text">[docs]</a> <span class="k">def</span> <span class="nf">detected_text</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">confidence_threshold</span><span class="o">=</span><span class="n">TEXT_DETECTION_CONFIDENCE_THRESHOLD</span><span class="p">):</span>
|
||||
<span class="sd">"""Detects text in photo and returns lists of results as (detected text, confidence)</span>
|
||||
|
||||
<span class="sd"> confidence_threshold: float between 0.0 and 1.0. If text detection confidence is below this threshold,</span>
|
||||
<span class="sd"> text will not be returned. Default is TEXT_DETECTION_CONFIDENCE_THRESHOLD</span>
|
||||
|
||||
<span class="sd"> If photo is edited, uses the edited photo, otherwise the original; falls back to the preview image if neither edited or original is available</span>
|
||||
|
||||
<span class="sd"> Returns: list of (detected text, confidence) tuples</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">path</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">path</span> <span class="o">=</span> <span class="n">path</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_derivatives</span> <span class="k">else</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">path</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_detected_text</span><span class="p">[(</span><span class="n">path</span><span class="p">,</span> <span class="n">confidence_threshold</span><span class="p">)]</span>
|
||||
<span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">KeyError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="ne">AttributeError</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_detected_text</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">detected_text</span> <span class="o">=</span> <span class="n">detect_text</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">detected_text</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_detected_text</span><span class="p">[(</span><span class="n">path</span><span class="p">,</span> <span class="n">confidence_threshold</span><span class="p">)]</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">confidence</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">text</span><span class="p">,</span> <span class="n">confidence</span> <span class="ow">in</span> <span class="n">detected_text</span>
|
||||
<span class="k">if</span> <span class="n">confidence</span> <span class="o">>=</span> <span class="n">confidence_threshold</span>
|
||||
<span class="p">]</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_detected_text</span><span class="p">[(</span><span class="n">path</span><span class="p">,</span> <span class="n">confidence_threshold</span><span class="p">)]</span></div>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">_longitude</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns longitude, in degrees """</span>
|
||||
<span class="sd">"""Returns longitude, in degrees"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"longitude"</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">_latitude</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns latitude, in degrees """</span>
|
||||
<span class="sd">"""Returns latitude, in degrees"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"latitude"</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>
|
||||
@@ -1120,7 +1221,7 @@
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s2">"osxphotos.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">(db=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="si">}</span><span class="s2">, uuid='</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">', info=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="si">}</span><span class="s2">)"</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" string representation of PhotoInfo object """</span>
|
||||
<span class="sd">"""string representation of PhotoInfo object"""</span>
|
||||
|
||||
<span class="n">date_iso</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
|
||||
<span class="n">date_modified_iso</span> <span class="o">=</span> <span class="p">(</span>
|
||||
@@ -1183,7 +1284,7 @@
|
||||
<span class="k">return</span> <span class="n">yaml</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">info</span><span class="p">,</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<div class="viewcode-block" id="PhotoInfo.asdict"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotoInfo.asdict">[docs]</a> <span class="k">def</span> <span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return dict representation """</span>
|
||||
<span class="sd">"""return dict representation"""</span>
|
||||
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">album</span><span class="o">.</span><span class="n">title</span><span class="p">:</span> <span class="n">album</span><span class="o">.</span><span class="n">folder_names</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">album_info</span><span class="p">}</span>
|
||||
<span class="n">exif</span> <span class="o">=</span> <span class="n">dataclasses</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exif_info</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">exif_info</span> <span class="k">else</span> <span class="p">{}</span>
|
||||
@@ -1259,7 +1360,7 @@
|
||||
<span class="p">}</span></div>
|
||||
|
||||
<div class="viewcode-block" id="PhotoInfo.json"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotoInfo.json">[docs]</a> <span class="k">def</span> <span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Return JSON representation """</span>
|
||||
<span class="sd">"""Return JSON representation"""</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="n">o</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">,</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">)):</span>
|
||||
@@ -1268,7 +1369,7 @@
|
||||
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">(),</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">default</span><span class="p">)</span></div>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="sd">""" Compare two PhotoInfo objects for equality """</span>
|
||||
<span class="sd">"""Compare two PhotoInfo objects for equality"""</span>
|
||||
<span class="c1"># Can't just compare the two __dicts__ because some methods (like albums)</span>
|
||||
<span class="c1"># memoize their value once called in an instance variable (e.g. self._albums)</span>
|
||||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">):</span>
|
||||
@@ -1280,8 +1381,22 @@
|
||||
<span class="k">return</span> <span class="kc">False</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="sd">""" Compare two PhotoInfo objects for inequality """</span>
|
||||
<span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="fm">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span></div>
|
||||
<span class="sd">"""Compare two PhotoInfo objects for inequality"""</span>
|
||||
<span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="fm">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Make PhotoInfo hashable"""</span>
|
||||
<span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">)</span></div>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">PhotoInfoNone</span><span class="p">:</span>
|
||||
<span class="sd">"""mock class that returns None for all attributes"""</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
@@ -1340,7 +1455,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.42.19 documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.42.66 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>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
@@ -44,11 +44,13 @@
|
||||
<span class="kn">import</span> <span class="nn">re</span>
|
||||
<span class="kn">import</span> <span class="nn">sys</span>
|
||||
<span class="kn">import</span> <span class="nn">tempfile</span>
|
||||
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span>
|
||||
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span>
|
||||
<span class="kn">from</span> <span class="nn">pprint</span> <span class="kn">import</span> <span class="n">pformat</span>
|
||||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">bitmath</span>
|
||||
<span class="kn">import</span> <span class="nn">photoscript</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.._constants</span> <span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="n">_DB_TABLE_NAMES</span><span class="p">,</span>
|
||||
@@ -76,6 +78,7 @@
|
||||
<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>
|
||||
<span class="kn">from</span> <span class="nn">..photoinfo</span> <span class="kn">import</span> <span class="n">PhotoInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..phototemplate</span> <span class="kn">import</span> <span class="n">RenderOptions</span>
|
||||
<span class="kn">from</span> <span class="nn">..queryoptions</span> <span class="kn">import</span> <span class="n">QueryOptions</span>
|
||||
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="n">_check_file_exists</span><span class="p">,</span>
|
||||
@@ -95,29 +98,29 @@
|
||||
|
||||
|
||||
<div class="viewcode-block" id="PhotosDB"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB">[docs]</a><span class="k">class</span> <span class="nc">PhotosDB</span><span class="p">:</span>
|
||||
<span class="sd">""" Processes a Photos.app library database to extract information about photos """</span>
|
||||
<span class="sd">"""Processes a Photos.app library database to extract information about photos"""</span>
|
||||
|
||||
<span class="c1"># import additional methods</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_comments</span> <span class="kn">import</span> <span class="n">_process_comments</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_exif</span> <span class="kn">import</span> <span class="n">_process_exifinfo</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_faceinfo</span> <span class="kn">import</span> <span class="n">_process_faceinfo</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_scoreinfo</span> <span class="kn">import</span> <span class="n">_process_scoreinfo</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_searchinfo</span> <span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="n">_process_searchinfo</span><span class="p">,</span>
|
||||
<span class="n">labels</span><span class="p">,</span>
|
||||
<span class="n">labels_normalized</span><span class="p">,</span>
|
||||
<span class="n">labels_as_dict</span><span class="p">,</span>
|
||||
<span class="n">labels_normalized</span><span class="p">,</span>
|
||||
<span class="n">labels_normalized_as_dict</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_scoreinfo</span> <span class="kn">import</span> <span class="n">_process_scoreinfo</span>
|
||||
<span class="kn">from</span> <span class="nn">._photosdb_process_comments</span> <span class="kn">import</span> <span class="n">_process_comments</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dbfile</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">exiftool</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="sd">""" Create a new PhotosDB object.</span>
|
||||
<span class="sd">"""Create a new PhotosDB object.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> dbfile: specify full path to photos library or photos.db; if None, will attempt to locate last library opened by Photos.</span>
|
||||
<span class="sd"> verbose: optional callable function to use for printing verbose text during processing; if None (default), does not print output.</span>
|
||||
<span class="sd"> exiftool: optional path to exiftool for methods that require this (e.g. PhotoInfo.exiftool); if not provided, will search PATH</span>
|
||||
<span class="sd"> </span>
|
||||
|
||||
<span class="sd"> Raises:</span>
|
||||
<span class="sd"> FileNotFoundError if dbfile is not a valid Photos library.</span>
|
||||
<span class="sd"> TypeError if verbose is not None and not callable.</span>
|
||||
@@ -273,6 +276,13 @@
|
||||
<span class="c1"># Will hold the primary key of root folder</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_folder_root_pk</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># Dict to hold signatures for finding possible duplicates</span>
|
||||
<span class="c1"># key is tuple of (original_filesize, date) and value is list of uuids that match that signature</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db_signatures</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="c1"># Dict to hold information on volume names (Photos 5+)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db_filesystem_volumes</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">"dbfile = </span><span class="si">{</span><span class="n">dbfile</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
@@ -355,7 +365,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">keywords_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return keywords as dict of keyword, count in reverse sorted order (descending) """</span>
|
||||
<span class="sd">"""return keywords as dict of keyword, count in reverse sorted order (descending)"""</span>
|
||||
<span class="n">keywords</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="n">k</span><span class="p">:</span> <span class="nb">len</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">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
|
||||
<span class="p">}</span>
|
||||
@@ -365,7 +375,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">persons_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return persons as dict of person, count in reverse sorted order (descending) """</span>
|
||||
<span class="sd">"""return persons as dict of person, count in reverse sorted order (descending)"""</span>
|
||||
<span class="n">persons</span> <span class="o">=</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">_dbfaces_pk</span><span class="p">:</span>
|
||||
<span class="n">fullname</span> <span class="o">=</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="s2">"fullname"</span><span class="p">]</span>
|
||||
@@ -378,7 +388,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">albums_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return albums as dict of albums, count in reverse sorted order (descending) """</span>
|
||||
<span class="sd">"""return albums as dict of albums, count in reverse sorted order (descending)"""</span>
|
||||
<span class="n">albums</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="n">album_keys</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</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="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">album_keys</span><span class="p">:</span>
|
||||
@@ -395,8 +405,8 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">albums_shared_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns shared albums as dict of albums, count in reverse sorted order (descending)</span>
|
||||
<span class="sd"> valid only on Photos 5; on Photos <= 4, prints warning and returns empty dict """</span>
|
||||
<span class="sd">"""returns shared albums as dict of albums, count in reverse sorted order (descending)</span>
|
||||
<span class="sd"> valid only on Photos 5; on Photos <= 4, prints warning and returns empty dict"""</span>
|
||||
|
||||
<span class="n">albums</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="n">album_keys</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
@@ -414,19 +424,19 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">keywords</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of keywords found in photos database """</span>
|
||||
<span class="sd">"""return list of keywords found in photos database"""</span>
|
||||
<span class="n">keywords</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">keywords</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">persons</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of persons found in photos database """</span>
|
||||
<span class="sd">"""return list of persons found in photos database"""</span>
|
||||
<span class="n">persons</span> <span class="o">=</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">k</span><span class="p">][</span><span class="s2">"fullname"</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">}</span>
|
||||
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">persons</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">person_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of PersonInfo objects for each person in the photos database """</span>
|
||||
<span class="sd">"""return list of PersonInfo objects for each person in the photos 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">_person_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -437,7 +447,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">folder_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list FolderInfo objects representing top-level folders in the photos database """</span>
|
||||
<span class="sd">"""return list FolderInfo objects representing top-level folders in the photos database"""</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">folders</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="n">FolderInfo</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">folder</span><span class="p">)</span>
|
||||
@@ -458,7 +468,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">folders</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of top-level folder names in the photos database """</span>
|
||||
<span class="sd">"""return list of top-level folder names in the photos database"""</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">folder_names</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="n">folder</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span>
|
||||
@@ -479,7 +489,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of AlbumInfo objects for each album in the photos database """</span>
|
||||
<span class="sd">"""return list of AlbumInfo objects for each album in the photos 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">_album_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -491,8 +501,8 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">album_info_shared</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of AlbumInfo objects for each shared album in the photos database</span>
|
||||
<span class="sd"> only valid for Photos 5; on Photos <= 4, prints warning and returns empty list """</span>
|
||||
<span class="sd">"""return list of AlbumInfo objects for each shared album in the photos database</span>
|
||||
<span class="sd"> only valid for Photos 5; on Photos <= 4, prints warning and returns empty list"""</span>
|
||||
<span class="c1"># if _dbalbum_details[key]["cloudownerhashedpersonid"] is not None, then it's a shared album</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">_album_info_shared</span>
|
||||
@@ -505,7 +515,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">albums</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of albums found in photos database """</span>
|
||||
<span class="sd">"""return list of albums found in photos database"""</span>
|
||||
|
||||
<span class="c1"># Could be more than one album with same name</span>
|
||||
<span class="c1"># Right now, they are treated as same album and photos are combined from albums with same name</span>
|
||||
@@ -518,8 +528,8 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">albums_shared</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of shared albums found in photos database</span>
|
||||
<span class="sd"> only valid for Photos 5; on Photos <= 4, prints warning and returns empty list """</span>
|
||||
<span class="sd">"""return list of shared albums found in photos database</span>
|
||||
<span class="sd"> only valid for Photos 5; on Photos <= 4, prints warning and returns empty list"""</span>
|
||||
|
||||
<span class="c1"># Could be more than one album with same name</span>
|
||||
<span class="c1"># Right now, they are treated as same album and photos are combined from albums with same name</span>
|
||||
@@ -534,7 +544,7 @@
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">import_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" return list of ImportInfo objects for each import session in the database """</span>
|
||||
<span class="sd">"""return list of ImportInfo objects for each import session 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">_import_info</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
@@ -546,21 +556,21 @@
|
||||
|
||||
<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>
|
||||
<span class="sd">"""return the database version as stored in LiGlobals table"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">db_path</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns path to the Photos library database PhotosDB was initialized with """</span>
|
||||
<span class="sd">"""returns path to the Photos library database PhotosDB was initialized with"""</span>
|
||||
<span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">library_path</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" returns path to the Photos library PhotosDB was initialized with """</span>
|
||||
<span class="sd">"""returns path to the Photos library PhotosDB was initialized with"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span>
|
||||
|
||||
<div class="viewcode-block" id="PhotosDB.get_db_connection"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.get_db_connection">[docs]</a> <span class="k">def</span> <span class="nf">get_db_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Get connection to the working copy of the Photos database </span>
|
||||
<span class="sd">"""Get connection to the working copy of the Photos database</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> tuple of (connection, cursor) to sqlite3 database</span>
|
||||
@@ -568,7 +578,7 @@
|
||||
<span class="k">return</span> <span class="n">_open_sql_file</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span></div>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_copy_db_file</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fname</span><span class="p">):</span>
|
||||
<span class="sd">""" copies the sqlite database file to a temp file """</span>
|
||||
<span class="sd">"""copies the sqlite database file to a temp file"""</span>
|
||||
<span class="sd">""" returns the name of the temp file """</span>
|
||||
<span class="sd">""" If sqlite shared memory and write-ahead log files exist, those are copied too """</span>
|
||||
<span class="c1"># required because python's sqlite3 implementation can't read a locked file</span>
|
||||
@@ -620,13 +630,15 @@
|
||||
<span class="c1"># return dest_path</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_process_database4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" process the Photos database to extract info</span>
|
||||
<span class="sd"> works on Photos version <= 4.0 """</span>
|
||||
<span class="sd">"""process the Photos database to extract info</span>
|
||||
<span class="sd"> works on Photos version <= 4.0"""</span>
|
||||
|
||||
<span class="n">verbose</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing database."</span><span class="p">)</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Database 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="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="mi">4</span> <span class="c1"># only used in Photos 5+</span>
|
||||
|
||||
<span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="o">=</span> <span class="n">_open_sql_file</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># get info to associate persons with photos</span>
|
||||
@@ -811,6 +823,8 @@
|
||||
<span class="s2">"creation_date"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span>
|
||||
<span class="s2">"start_date"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"end_date"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"customsortascending"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"customsortkey"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="c1"># get details about folders</span>
|
||||
@@ -1123,6 +1137,7 @@
|
||||
<span class="c1"># get info on special types</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">"specialType"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</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">"masterModelID"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">26</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">"pk"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span> <span class="c1"># same as masterModelID, to match Photos 5</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">"panorama"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</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">"slow_mo"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span> <span class="k">else</span> <span class="kc">False</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">"time_lapse"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span> <span class="k">else</span> <span class="kc">False</span>
|
||||
@@ -1213,6 +1228,13 @@
|
||||
<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">"import_uuid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">44</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">"fok_import_session"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># compute signatures for finding possible duplicates</span>
|
||||
<span class="n">signature</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_duplicate_signature</span><span class="p">(</span><span class="n">uuid</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">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">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">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># get additional details from RKMaster, needed for RAW processing</span>
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="s2">"Processing additional 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>
|
||||
@@ -1565,15 +1587,15 @@
|
||||
<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>
|
||||
<span class="sd"> uuid: parent uuid of the album being processed </span>
|
||||
<span class="sd"> (parent uuid is a folder in RKFolders)</span>
|
||||
<span class="sd"> folders: dict holding the folder hierarchy </span>
|
||||
<span class="sd"> NOTE: This implementation is different than _build_album_folder_hierarchy_5 </span>
|
||||
<span class="sd"> which takes the uuid of the album being processed. Here uuid is the parent uuid</span>
|
||||
<span class="sd"> of the parent folder album because in Photos <=4, folders are in RKFolders and </span>
|
||||
<span class="sd"> albums in RKAlbums. In Photos 5, folders are just special albums </span>
|
||||
<span class="sd"> with kind = _PHOTOS_5_FOLDER_KIND """</span>
|
||||
<span class="sd">"""recursively build folder/album hierarchy</span>
|
||||
<span class="sd"> uuid: parent uuid of the album being processed</span>
|
||||
<span class="sd"> (parent uuid is a folder in RKFolders)</span>
|
||||
<span class="sd"> folders: dict holding the folder hierarchy</span>
|
||||
<span class="sd"> NOTE: This implementation is different than _build_album_folder_hierarchy_5</span>
|
||||
<span class="sd"> which takes the uuid of the album being processed. Here uuid is the parent uuid</span>
|
||||
<span class="sd"> of the parent folder album because in Photos <=4, folders are in RKFolders and</span>
|
||||
<span class="sd"> albums in RKAlbums. In Photos 5, folders are just special albums</span>
|
||||
<span class="sd"> with kind = _PHOTOS_5_FOLDER_KIND"""</span>
|
||||
|
||||
<span class="n">parent_uuid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"parentFolderUuid"</span><span class="p">]</span>
|
||||
|
||||
@@ -1596,11 +1618,11 @@
|
||||
<span class="k">return</span> <span class="n">folders</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_process_database5</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" process the Photos database to extract info </span>
|
||||
<span class="sd"> works on Photos version 5 and version 6</span>
|
||||
<span class="sd">"""process the Photos database to extract info</span>
|
||||
<span class="sd"> works on Photos version 5 and version 6</span>
|
||||
|
||||
<span class="sd"> This is a big hairy 700 line function that should probably be refactored</span>
|
||||
<span class="sd"> but it works so don't touch it.</span>
|
||||
<span class="sd"> This is a big hairy 700 line function that should probably be refactored</span>
|
||||
<span class="sd"> but it works so don't touch it.</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
@@ -1615,10 +1637,14 @@
|
||||
<span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Database 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="si">{</span><span class="n">photos_ver</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||||
<span class="n">asset_table</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"ASSET"</span><span class="p">]</span>
|
||||
<span class="n">keyword_join</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"KEYWORD_JOIN"</span><span class="p">]</span>
|
||||
<span class="n">asset_album_table</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"ASSET_ALBUM_TABLE"</span><span class="p">]</span>
|
||||
<span class="n">album_join</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"ALBUM_JOIN"</span><span class="p">]</span>
|
||||
<span class="n">album_sort</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"ALBUM_SORT_ORDER"</span><span class="p">]</span>
|
||||
<span class="n">asset_album_join</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"ASSET_ALBUM_JOIN"</span><span class="p">]</span>
|
||||
<span class="n">import_fok</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"IMPORT_FOK"</span><span class="p">]</span>
|
||||
<span class="n">depth_state</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"DEPTH_STATE"</span><span class="p">]</span>
|
||||
<span class="n">uti_original_column</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"UTI_ORIGINAL"</span><span class="p">]</span>
|
||||
<span class="n">hdr_type_column</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">"HDR_TYPE"</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># Look for all combinations of persons and pictures</span>
|
||||
<span class="k">if</span> <span class="n">_debug</span><span class="p">():</span>
|
||||
@@ -1648,7 +1674,11 @@
|
||||
|
||||
<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="o">!=</span> <span class="s2">""</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">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>
|
||||
<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>
|
||||
@@ -1734,8 +1764,8 @@
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">album_sort</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"> </span>
|
||||
<span class="s2"> JOIN Z_26ASSETS ON </span><span class="si">{</span><span class="n">album_join</span><span class="si">}</span><span class="s2"> = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS</span>
|
||||
<span class="s2"> JOIN </span><span class="si">{</span><span class="n">asset_album_table</span><span class="si">}</span><span class="s2"> ON </span><span class="si">{</span><span class="n">album_join</span><span class="si">}</span><span class="s2"> = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = </span><span class="si">{</span><span class="n">asset_album_join</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2"> """</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@@ -1773,7 +1803,9 @@
|
||||
<span class="s2">"ZTRASHEDSTATE, "</span> <span class="c1"># 9</span>
|
||||
<span class="s2">"ZCREATIONDATE, "</span> <span class="c1"># 10</span>
|
||||
<span class="s2">"ZSTARTDATE, "</span> <span class="c1"># 11</span>
|
||||
<span class="s2">"ZENDDATE "</span> <span class="c1"># 12</span>
|
||||
<span class="s2">"ZENDDATE, "</span> <span class="c1"># 12</span>
|
||||
<span class="s2">"ZCUSTOMSORTASCENDING, "</span> <span class="c1"># 13</span>
|
||||
<span class="s2">"ZCUSTOMSORTKEY "</span> <span class="c1"># 14</span>
|
||||
<span class="s2">"FROM ZGENERICALBUM "</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
@@ -1793,6 +1825,8 @@
|
||||
<span class="s2">"creation_date"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">10</span><span class="p">],</span>
|
||||
<span class="s2">"start_date"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">11</span><span class="p">],</span>
|
||||
<span class="s2">"end_date"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">12</span><span class="p">],</span>
|
||||
<span class="s2">"customsortascending"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">13</span><span class="p">],</span>
|
||||
<span class="s2">"customsortkey"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">14</span><span class="p">],</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="c1"># add cross-reference by pk to uuid</span>
|
||||
@@ -1902,7 +1936,7 @@
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZAVALANCHEUUID,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZAVALANCHEPICKTYPE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZKINDSUBTYPE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZCUSTOMRENDEREDVALUE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">hdr_type_column</span><span class="si">}</span><span class="s2">,</span>
|
||||
<span class="s2"> ZADDITIONALASSETATTRIBUTES.ZCAMERACAPTUREDEVICE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZCLOUDASSETGUID,</span>
|
||||
<span class="s2"> ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA,</span>
|
||||
@@ -1921,7 +1955,8 @@
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZVISIBILITYSTATE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZTRASHEDDATE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZSAVEDASSETTYPE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZADDEDDATE</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZADDEDDATE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"> </span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> ORDER BY </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID """</span>
|
||||
@@ -1970,6 +2005,7 @@
|
||||
<span class="c1"># 39 ZGENERICASSET.ZTRASHEDDATE -- date item placed in the trash or null if not in trash</span>
|
||||
<span class="c1"># 40 ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported</span>
|
||||
<span class="c1"># 41 ZGENERICASSET.ZADDEDDATE -- date item added to the library</span>
|
||||
<span class="c1"># 42 ZGENERICASSET.Z_PK -- primary key</span>
|
||||
|
||||
<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>
|
||||
@@ -2154,6 +2190,8 @@
|
||||
<span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">):</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"added_date"</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">1970</span><span class="p">,</span> <span class="mi">1</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">"pk"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">42</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># initialize import session info which will be filled in later</span>
|
||||
<span class="c1"># not every photo has an import session so initialize all records now</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"import_session"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
@@ -2174,6 +2212,13 @@
|
||||
|
||||
<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="n">info</span>
|
||||
|
||||
<span class="c1"># compute signatures for finding possible duplicates</span>
|
||||
<span class="n">signature</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_duplicate_signature</span><span class="p">(</span><span class="n">uuid</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">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">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">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># # if row[19] is not None and ((row[20] == 2) or (row[20] == 4)):</span>
|
||||
<span class="c1"># # burst photo</span>
|
||||
<span class="c1"># if row[19] is not None:</span>
|
||||
@@ -2259,20 +2304,33 @@
|
||||
|
||||
<span class="c1"># Get info on remote/local availability for photos in shared albums</span>
|
||||
<span class="c1"># Also get UTI of original image (zdatastoresubtype = 1)</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">""" SELECT </span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">>=</span> <span class="mi">7</span><span class="p">:</span>
|
||||
<span class="n">sql_missing</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">""" SELECT </span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID, </span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZLOCALAVAILABILITY, </span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZREMOTEAVAILABILITY,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">uti_original_column</span><span class="si">}</span><span class="s2">,</span>
|
||||
<span class="s2"> null </span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET </span>
|
||||
<span class="s2"> WHERE ZDATASTORESUBTYPE = 1 OR ZDATASTORESUBTYPE = 3 """</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">sql_missing</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">""" SELECT </span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID, </span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZLOCALAVAILABILITY, </span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZREMOTEAVAILABILITY,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">uti_original_column</span><span class="si">}</span><span class="s2">,</span>
|
||||
<span class="s2"> ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER</span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET </span>
|
||||
<span class="s2"> JOIN ZUNIFORMTYPEIDENTIFIER ON ZUNIFORMTYPEIDENTIFIER.Z_PK = ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER </span>
|
||||
<span class="s2"> WHERE ZDATASTORESUBTYPE = 1 OR ZDATASTORESUBTYPE = 3 """</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql_missing</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Order of results:</span>
|
||||
<span class="c1"># 0 {asset_table}.ZUUID,</span>
|
||||
@@ -2332,20 +2390,36 @@
|
||||
|
||||
<span class="c1"># get information about associted RAW images</span>
|
||||
<span class="c1"># RAW images have ZDATASTORESUBTYPE = 17</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">""" SELECT</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">>=</span> <span class="mi">7</span><span class="p">:</span>
|
||||
<span class="n">sql_raw</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">""" SELECT</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZDATALENGTH, </span>
|
||||
<span class="s2"> null,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZRESOURCETYPE,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZFILESYSTEMBOOKMARK</span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2"> JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17</span>
|
||||
<span class="s2"> """</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">sql_raw</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">""" SELECT</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZDATALENGTH, </span>
|
||||
<span class="s2"> ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZRESOURCETYPE</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZRESOURCETYPE,</span>
|
||||
<span class="s2"> ZINTERNALRESOURCE.ZFILESYSTEMBOOKMARK</span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2"> JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> JOIN ZUNIFORMTYPEIDENTIFIER ON ZUNIFORMTYPEIDENTIFIER.Z_PK = ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER</span>
|
||||
<span class="s2"> WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17</span>
|
||||
<span class="s2"> """</span>
|
||||
<span class="p">)</span>
|
||||
<span class="s2"> """</span>
|
||||
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql_raw</span><span class="p">)</span>
|
||||
|
||||
<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">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
|
||||
@@ -2354,6 +2428,33 @@
|
||||
<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">"UTI_raw"</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">"datastore_subtype"</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">"resource_type"</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="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">"raw_bookmark"</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="c1"># get paths for the relative imports for RAW+JPEG images</span>
|
||||
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">""" SELECT</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
|
||||
<span class="s2"> ZFILESYSTEMVOLUME.ZNAME,</span>
|
||||
<span class="s2"> ZFILESYSTEMBOOKMARK.ZPATHRELATIVETOVOLUME</span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"> </span>
|
||||
<span class="s2"> JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> JOIN ZFILESYSTEMBOOKMARK ON ZFILESYSTEMBOOKMARK.ZRESOURCE = ZINTERNALRESOURCE.Z_PK</span>
|
||||
<span class="s2"> JOIN ZFILESYSTEMVOLUME ON ZFILESYSTEMVOLUME.Z_PK = ZINTERNALRESOURCE.ZFILESYSTEMVOLUME</span>
|
||||
<span class="s2"> WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17</span>
|
||||
<span class="s2"> """</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># path to the raw image will be /Volumes/ZFILESYSTEMVOLUME.ZNAME/ZFILESYSTEMBOOKMARK.ZPATHRELATIVETOVOLUME</span>
|
||||
<span class="c1"># 0: {asset_table}.ZUUID, -- UUID</span>
|
||||
<span class="c1"># 1: ZFILESYSTEMVOLUME.ZNAME, -- name of the volume</span>
|
||||
<span class="c1"># 2: ZFILESYSTEMBOOKMARK.ZPATHRELATIVETOVOLUME -- path to the raw image</span>
|
||||
|
||||
<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">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</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">"raw_volume"</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">"raw_relative_path"</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="c1"># add faces and keywords to photo data</span>
|
||||
<span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
|
||||
@@ -2459,9 +2560,9 @@
|
||||
<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_5</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>
|
||||
<span class="sd"> uuid: uuid of the album/folder being processed</span>
|
||||
<span class="sd"> folders: dict holding the folder hierarchy """</span>
|
||||
<span class="sd">"""recursively build folder/album hierarchy</span>
|
||||
<span class="sd"> uuid: uuid of the album/folder being processed</span>
|
||||
<span class="sd"> folders: dict holding the folder hierarchy"""</span>
|
||||
|
||||
<span class="c1"># get parent uuid</span>
|
||||
<span class="n">parent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"parentfolder"</span><span class="p">]</span>
|
||||
@@ -2482,17 +2583,17 @@
|
||||
<span class="k">return</span> <span class="n">folders</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_album_folder_hierarchy_list</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
|
||||
<span class="sd">""" return appropriate album_folder_hierarchy_list for the _db_version """</span>
|
||||
<span class="sd">"""return appropriate album_folder_hierarchy_list for the _db_version"""</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="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_list_4</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_list_5</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_album_folder_hierarchy_list_4</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
|
||||
<span class="sd">""" return hierarchical list of folder names album_uuid is contained in</span>
|
||||
<span class="sd"> the folder list is in form:</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders """</span>
|
||||
<span class="sd">"""return hierarchical list of folder names album_uuid is contained in</span>
|
||||
<span class="sd"> the folder list is in form:</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders"""</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
@@ -2500,7 +2601,7 @@
|
||||
<span class="k">return</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
|
||||
<span class="sd">""" recursively walk the folders dict to build list of folder hierarchy """</span>
|
||||
<span class="sd">"""recursively walk the folders dict to build list of folder hierarchy"""</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
|
||||
<span class="c1"># empty folder dict (album has no folder hierarchy)</span>
|
||||
<span class="k">return</span> <span class="p">[]</span>
|
||||
@@ -2526,10 +2627,10 @@
|
||||
<span class="k">return</span> <span class="n">hierarchy</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_album_folder_hierarchy_list_5</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
|
||||
<span class="sd">""" return hierarchical list of folder names album_uuid is contained in</span>
|
||||
<span class="sd"> the folder list is in form:</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders """</span>
|
||||
<span class="sd">"""return hierarchical list of folder names album_uuid is contained in</span>
|
||||
<span class="sd"> the folder list is in form:</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders"""</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||||
@@ -2537,7 +2638,7 @@
|
||||
<span class="k">return</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
|
||||
<span class="sd">""" recursively walk the folders dict to build list of folder hierarchy """</span>
|
||||
<span class="sd">"""recursively walk the folders dict to build list of folder hierarchy"""</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
|
||||
<span class="c1"># empty folder dict (album has no folder hierarchy)</span>
|
||||
@@ -2569,15 +2670,15 @@
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_folderinfo_5</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_album_folder_hierarchy_folderinfo_4</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
|
||||
<span class="sd">""" return hierarchical list of FolderInfo objects album_uuid is contained in</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders """</span>
|
||||
<span class="sd">"""return hierarchical list of FolderInfo objects album_uuid is contained in</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders"""</span>
|
||||
<span class="c1"># title = photosdb._dbalbum_details[album_uuid]["title"]</span>
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
|
||||
<span class="c1"># logging.warning(f"uuid = {album_uuid}, folder = {folders}")</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
|
||||
<span class="sd">""" recursively walk the folders dict to build list of folder hierarchy """</span>
|
||||
<span class="sd">"""recursively walk the folders dict to build list of folder hierarchy"""</span>
|
||||
<span class="c1"># logging.warning(f"folders={folders},hierarchy = {hierarchy}")</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
|
||||
<span class="c1"># empty folder dict (album has no folder hierarchy)</span>
|
||||
@@ -2603,14 +2704,14 @@
|
||||
<span class="k">return</span> <span class="n">hierarchy</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_album_folder_hierarchy_folderinfo_5</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
|
||||
<span class="sd">""" return hierarchical list of FolderInfo objects album_uuid is contained in</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders """</span>
|
||||
<span class="sd">"""return hierarchical list of FolderInfo objects album_uuid is contained in</span>
|
||||
<span class="sd"> ["Top level folder", "sub folder 1", "sub folder 2"]</span>
|
||||
<span class="sd"> returns empty list of album is not in any folders"""</span>
|
||||
<span class="c1"># title = photosdb._dbalbum_details[album_uuid]["title"]</span>
|
||||
<span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
|
||||
<span class="sd">""" recursively walk the folders dict to build list of folder hierarchy """</span>
|
||||
<span class="sd">"""recursively walk the folders dict to build list of folder hierarchy"""</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
|
||||
<span class="c1"># empty folder dict (album has no folder hierarchy)</span>
|
||||
@@ -2635,19 +2736,19 @@
|
||||
<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="sd">""" Return list of album UUIDs found in photos database</span>
|
||||
<span class="sd"> </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>
|
||||
<span class="sd"> </span>
|
||||
|
||||
<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"> Note: flags (shared, import_session) are mutually exclusive</span>
|
||||
<span class="sd"> </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"> 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">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
|
||||
@@ -2699,14 +2800,14 @@
|
||||
<span class="k">return</span> <span class="n">album_list</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_get_albums</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="sd">""" Return list of album titles found in photos database</span>
|
||||
<span class="sd">"""Return list of album titles found in photos database</span>
|
||||
<span class="sd"> Albums may have duplicate titles -- these will be treated as a single album.</span>
|
||||
<span class="sd"> </span>
|
||||
|
||||
<span class="sd"> Filters out albums in the trash and any special album types</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> shared: boolean; if True, returns shared albums, else normal albums</span>
|
||||
<span class="sd"> </span>
|
||||
|
||||
<span class="sd"> Returns: list of album names</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
@@ -2725,7 +2826,7 @@
|
||||
<span class="n">to_date</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">intrash</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">):</span>
|
||||
<span class="sd">""" Return a list of PhotoInfo objects</span>
|
||||
<span class="sd">"""Return a list of PhotoInfo objects</span>
|
||||
<span class="sd"> If called with no args, returns the entire database of photos</span>
|
||||
<span class="sd"> If called with args, returns photos matching the args (e.g. keywords, persons, etc.)</span>
|
||||
<span class="sd"> If more than one arg, returns photos matching all the criteria (e.g. keywords AND persons)</span>
|
||||
@@ -2740,10 +2841,10 @@
|
||||
<span class="sd"> persons: list of persons to search for</span>
|
||||
<span class="sd"> albums: list of album names to search for</span>
|
||||
<span class="sd"> images: if True, returns image files, if False, does not return images; default is True</span>
|
||||
<span class="sd"> movies: if True, returns movie files, if False, does not return movies; default is True </span>
|
||||
<span class="sd"> movies: if True, returns movie files, if False, does not return movies; default is True</span>
|
||||
<span class="sd"> from_date: return photos with creation date >= from_date (datetime.datetime object, default None)</span>
|
||||
<span class="sd"> to_date: return photos with creation date <= to_date (datetime.datetime object, default None)</span>
|
||||
<span class="sd"> intrash: if True, returns only images in "Recently deleted items" folder, </span>
|
||||
<span class="sd"> intrash: if True, returns only images in "Recently deleted items" folder,</span>
|
||||
<span class="sd"> if False returns only photos that aren't deleted; default is False</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
@@ -2850,7 +2951,7 @@
|
||||
<span class="k">return</span> <span class="n">photoinfo</span></div>
|
||||
|
||||
<div class="viewcode-block" id="PhotosDB.get_photo"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.get_photo">[docs]</a> <span class="k">def</span> <span class="nf">get_photo</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="sd">""" Returns a single photo matching uuid</span>
|
||||
<span class="sd">"""Returns a single photo matching uuid</span>
|
||||
|
||||
<span class="sd"> Arguments:</span>
|
||||
<span class="sd"> uuid: the UUID of photo to get</span>
|
||||
@@ -2865,7 +2966,7 @@
|
||||
|
||||
<span class="c1"># TODO: add to docs and test</span>
|
||||
<div class="viewcode-block" id="PhotosDB.photos_by_uuid"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.photos_by_uuid">[docs]</a> <span class="k">def</span> <span class="nf">photos_by_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuids</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns a list of photos with UUID in uuids.</span>
|
||||
<span class="sd">"""Returns a list of photos with UUID in uuids.</span>
|
||||
<span class="sd"> Does not generate error if invalid or missing UUID passed.</span>
|
||||
<span class="sd"> This is faster than using PhotosDB.photos if you have list of UUIDs.</span>
|
||||
<span class="sd"> Returns photos regardless of intrash state.</span>
|
||||
@@ -3217,11 +3318,12 @@
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">regex</span><span class="p">:</span>
|
||||
<span class="n">flags</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span> <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">ignore_case</span> <span class="k">else</span> <span class="mi">0</span>
|
||||
<span class="n">render_options</span> <span class="o">=</span> <span class="n">RenderOptions</span><span class="p">(</span><span class="n">none_str</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">regex</span><span class="p">,</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">regex</span><span class="p">:</span>
|
||||
<span class="n">regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">flags</span><span class="p">)</span>
|
||||
<span class="n">photo_list</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="n">rendered</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">render_template</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">none_str</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">rendered</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">render_template</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">render_options</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">rendered</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">regex</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
|
||||
<span class="n">photo_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
|
||||
@@ -3236,8 +3338,66 @@
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Invalid query_eval CRITERIA: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">duplicate</span><span class="p">:</span>
|
||||
<span class="n">no_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">1970</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">tz</span> <span class="o">=</span> <span class="n">timezone</span><span class="p">(</span><span class="n">timedelta</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
|
||||
<span class="n">no_date</span> <span class="o">=</span> <span class="n">no_date</span><span class="o">.</span><span class="n">astimezone</span><span class="p">(</span><span class="n">tz</span><span class="o">=</span><span class="n">tz</span><span class="p">)</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="nb">sorted</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">p</span><span class="o">.</span><span class="n">duplicates</span><span class="p">],</span>
|
||||
<span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">date_added</span> <span class="ow">or</span> <span class="n">no_date</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="c1"># gather all duplicates but ensure each uuid is only represented once</span>
|
||||
<span class="n">photodict</span> <span class="o">=</span> <span class="n">OrderedDict</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">not</span> <span class="ow">in</span> <span class="n">photodict</span><span class="p">:</span>
|
||||
<span class="n">photodict</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="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span>
|
||||
<span class="n">p</span><span class="o">.</span><span class="n">duplicates</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">date_added</span> <span class="ow">or</span> <span class="n">no_date</span>
|
||||
<span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">d</span><span class="o">.</span><span class="n">uuid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">photodict</span><span class="p">:</span>
|
||||
<span class="n">photodict</span><span class="p">[</span><span class="n">d</span><span class="o">.</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="n">d</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">photodict</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
|
||||
|
||||
<span class="c1"># filter for deleted as photo.duplicates will include photos in the trash</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">deleted</span> <span class="ow">or</span> <span class="n">options</span><span class="o">.</span><span class="n">deleted_only</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="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">intrash</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">deleted_only</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">intrash</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">location</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">location</span> <span class="o">!=</span> <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">)]</span>
|
||||
<span class="k">elif</span> <span class="n">options</span><span class="o">.</span><span class="n">no_location</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">location</span> <span class="o">==</span> <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">)]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">selected</span><span class="p">:</span>
|
||||
<span class="c1"># photos selected in Photos app</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="c1"># catch AppleScript errors as the scripting interfce to Photos is flaky</span>
|
||||
<span class="n">selected</span> <span class="o">=</span> <span class="n">photoscript</span><span class="o">.</span><span class="n">PhotosLibrary</span><span class="p">()</span><span class="o">.</span><span class="n">selection</span>
|
||||
<span class="n">selected_uuid</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">uuid</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">selected</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">uuid</span> <span class="ow">in</span> <span class="n">selected_uuid</span><span class="p">]</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||||
<span class="c1"># no photos selected or a selected photo was "open"</span>
|
||||
<span class="c1"># selection only works if photos selected in main media browser</span>
|
||||
<span class="n">photos</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">function</span><span class="p">:</span>
|
||||
<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="k">return</span> <span class="n">photos</span></div>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_duplicate_signature</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="sd">"""Compute a signature for finding possible duplicates"""</span>
|
||||
<span class="k">return</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">"original_filesize"</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">"imageDate"</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">"height"</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">"width"</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">"UTI"</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">"hasAdjustments"</span><span class="p">],</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s2">"osxphotos.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">(dbfile='</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">db_path</span><span class="si">}</span><span class="s2">')"</span>
|
||||
|
||||
@@ -3249,8 +3409,8 @@
|
||||
<span class="k">return</span> <span class="kc">False</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" Returns number of photos in the database</span>
|
||||
<span class="sd"> Includes recently deleted photos and non-selected burst images</span>
|
||||
<span class="sd">"""Returns number of photos in the database</span>
|
||||
<span class="sd"> Includes recently deleted photos and non-selected burst images</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">)</span></div>
|
||||
|
||||
@@ -3280,7 +3440,7 @@
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">values</span><span class="p">:</span>
|
||||
<span class="n">photos_search</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">photos</span> <span class="k">if</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">attribute</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">photos_search</span>
|
||||
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">photos_search</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
@@ -3339,7 +3499,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
106
docs/_static/basic.css
vendored
106
docs/_static/basic.css
vendored
@@ -130,7 +130,7 @@ ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li div.context {
|
||||
ul.search li p.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
@@ -277,25 +277,25 @@ p.rubric {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left {
|
||||
img.align-left, figure.align-left, .figure.align-left, object.align-left {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right {
|
||||
img.align-right, figure.align-right, .figure.align-right, object.align-right {
|
||||
clear: right;
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
img.align-center, figure.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
img.align-default, .figure.align-default {
|
||||
img.align-default, figure.align-default, .figure.align-default {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
@@ -319,7 +319,8 @@ img.align-default, .figure.align-default {
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
||||
div.sidebar {
|
||||
div.sidebar,
|
||||
aside.sidebar {
|
||||
margin: 0 0 0.5em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px;
|
||||
@@ -377,12 +378,14 @@ div.body p.centered {
|
||||
/* -- content of sidebars/topics/admonitions -------------------------------- */
|
||||
|
||||
div.sidebar > :last-child,
|
||||
aside.sidebar > :last-child,
|
||||
div.topic > :last-child,
|
||||
div.admonition > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sidebar::after,
|
||||
aside.sidebar::after,
|
||||
div.topic::after,
|
||||
div.admonition::after,
|
||||
blockquote::after {
|
||||
@@ -455,20 +458,22 @@ td > :last-child {
|
||||
|
||||
/* -- figures --------------------------------------------------------------- */
|
||||
|
||||
div.figure {
|
||||
div.figure, figure {
|
||||
margin: 0.5em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.figure p.caption {
|
||||
div.figure p.caption, figcaption {
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
div.figure p.caption span.caption-number {
|
||||
div.figure p.caption span.caption-number,
|
||||
figcaption span.caption-number {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.figure p.caption span.caption-text {
|
||||
div.figure p.caption span.caption-text,
|
||||
figcaption span.caption-text {
|
||||
}
|
||||
|
||||
/* -- field list styles ----------------------------------------------------- */
|
||||
@@ -503,6 +508,63 @@ table.hlist td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* -- object description styles --------------------------------------------- */
|
||||
|
||||
.sig {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
}
|
||||
|
||||
.sig-name, code.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sig-name {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
code.descname {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.sig-prename, code.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.sig-paren {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.sig-param.n {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* C++ specific styling */
|
||||
|
||||
.sig-inline.c-texpr,
|
||||
.sig-inline.cpp-texpr {
|
||||
font-family: unset;
|
||||
}
|
||||
|
||||
.sig.c .k, .sig.c .kt,
|
||||
.sig.cpp .k, .sig.cpp .kt {
|
||||
color: #0033B3;
|
||||
}
|
||||
|
||||
.sig.c .m,
|
||||
.sig.cpp .m {
|
||||
color: #1750EB;
|
||||
}
|
||||
|
||||
.sig.c .s, .sig.c .sc,
|
||||
.sig.cpp .s, .sig.cpp .sc {
|
||||
color: #067D17;
|
||||
}
|
||||
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
@@ -629,14 +691,6 @@ dl.glossary dt {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.sig-paren {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -766,7 +820,11 @@ div.code-block-caption code {
|
||||
table.highlighttable td.linenos,
|
||||
span.linenos,
|
||||
div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */
|
||||
user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: text; /* Safari fallback only */
|
||||
-webkit-user-select: none; /* Chrome/Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE10+ */
|
||||
}
|
||||
|
||||
div.code-block-caption span.caption-number {
|
||||
@@ -781,16 +839,6 @@ div.literal-block-wrapper {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
code.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
code.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
code.xref, a code {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
|
||||
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.42.20',
|
||||
VERSION: '0.42.69',
|
||||
LANGUAGE: 'None',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
2
docs/_static/searchtools.js
vendored
2
docs/_static/searchtools.js
vendored
@@ -509,7 +509,7 @@ var Search = {
|
||||
var excerpt = ((start > 0) ? '...' : '') +
|
||||
$.trim(text.substr(start, 240)) +
|
||||
((start + 240 - text.length) ? '...' : '');
|
||||
var rv = $('<div class="context"></div>').text(excerpt);
|
||||
var rv = $('<p class="context"></p>').text(excerpt);
|
||||
$.each(hlwords, function() {
|
||||
rv = rv.highlightText(this, 'highlighted');
|
||||
});
|
||||
|
||||
2042
docs/_static/underscore-1.13.1.js
vendored
Normal file
2042
docs/_static/underscore-1.13.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
docs/_static/underscore.js
vendored
8
docs/_static/underscore.js
vendored
File diff suppressed because one or more lines are too long
1004
docs/cli.html
1004
docs/cli.html
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Index — osxphotos 0.42.20 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
<title>Index — osxphotos 0.42.69 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>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
@@ -168,6 +168,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-places-db">osxphotos-places command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-db">osxphotos-query command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-repl-db">osxphotos-repl command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -227,6 +229,15 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-dry-run">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--duplicate
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-duplicate">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-duplicate">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -538,6 +549,15 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-load-config">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--location
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-location">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-location">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -585,8 +605,6 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-comment">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li>
|
||||
--no-description
|
||||
|
||||
@@ -603,6 +621,17 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-no-likes">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-likes">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li>
|
||||
--no-location
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-no-location">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-location">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -841,6 +870,41 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-portrait">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-portrait">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--post-command <CATEGORY COMMAND>
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-post-command">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--post-function <filename.py::function>
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-post-function">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--preview
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-preview">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--preview-if-missing
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-preview-if-missing">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--preview-suffix <SUFFIX>
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-preview-suffix">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -850,6 +914,15 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-query-eval">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-query-eval">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--query-function <filename.py::function>
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-query-function">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-query-function">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -896,6 +969,15 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-screenshot">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-screenshot">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--selected
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-selected">osxphotos-export command line option</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-selected">osxphotos-query command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -1122,19 +1204,19 @@
|
||||
<h2 id="A">A</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.activities">activities() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.activities">activities (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.adjustments">adjustments() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.adjustments">adjustments (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.album_info">album_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.album_info">album_info (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.album_info">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.album_info_shared">album_info_shared() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.album_info_shared">album_info_shared (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.albums">albums() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.albums">albums (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums">(osxphotos.PhotosDB property)</a>
|
||||
@@ -1142,13 +1224,13 @@
|
||||
</ul></li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_as_dict">albums_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_as_dict">albums_as_dict (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared">albums_shared() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared">albums_shared (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared_as_dict">albums_shared_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared_as_dict">albums_shared_as_dict (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.all">all() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.all">all (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExportResults.all_files">all_files() (osxphotos.PhotoInfo.ExportResults method)</a>
|
||||
</li>
|
||||
@@ -1170,23 +1252,23 @@
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.bit_rate">bit_rate (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.bodies_of_water">bodies_of_water() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.bodies_of_water">bodies_of_water (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst">burst() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst">burst (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_album_info">burst_album_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_album_info">burst_album_info (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_albums">burst_albums() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_albums">burst_albums (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_default_pick">burst_default_pick() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_default_pick">burst_default_pick (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_key">burst_key() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_key">burst_key (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_photos">burst_photos() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_photos">burst_photos (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_selected">burst_selected() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.burst_selected">burst_selected (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -1198,15 +1280,15 @@
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.camera_model">camera_model (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.city">city() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.city">city (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.codec">codec (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.comments">comments() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.comments">comments (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.country">country() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.country">country (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.curation">curation (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
@@ -1216,21 +1298,21 @@
|
||||
<h2 id="D">D</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date">date() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date">date (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date_added">date_added() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date_added">date_added (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date_modified">date_modified() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date_modified">date_modified (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date_trashed">date_trashed() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.date_trashed">date_trashed (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.db_path">db_path() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.db_path">db_path (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.db_version">db_version (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.db_version">db_version() (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.description">description() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.description">description (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li>
|
||||
DEST
|
||||
@@ -1239,6 +1321,10 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-arg-DEST">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.detected_text">detected_text() (osxphotos.PhotoInfo method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.duplicates">duplicates (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.duration">duration (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
@@ -1247,9 +1333,9 @@
|
||||
<h2 id="E">E</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.exif_info">exif_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.exif_info">exif_info (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.exiftool">exiftool() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.exiftool">exiftool (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.export">export() (osxphotos.PhotoInfo method)</a>
|
||||
</li>
|
||||
@@ -1259,7 +1345,7 @@
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.exposure_bias">exposure_bias (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.external_edit">external_edit() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.external_edit">external_edit (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -1267,13 +1353,13 @@
|
||||
<h2 id="F">F</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.face_info">face_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.face_info">face_info (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.failure">failure (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.favorite">favorite() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.favorite">favorite (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.filename">filename() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.filename">filename (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@@ -1281,9 +1367,9 @@
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.focal_length">focal_length (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.folder_info">folder_info() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.folder_info">folder_info (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.folders">folders() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.folders">folders (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.fps">fps (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
@@ -1307,21 +1393,21 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.harmonious_color">harmonious_color (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.has_raw">has_raw() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.has_raw">has_raw (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.hasadjustments">hasadjustments() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.hasadjustments">hasadjustments (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.hdr">hdr() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.hdr">hdr (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.height">height() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.height">height (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.hidden">hidden() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.hidden">hidden (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.highlight_visibility">highlight_visibility (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.holidays">holidays() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.holidays">holidays (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -1331,37 +1417,37 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.immersiveness">immersiveness (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.import_info">import_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.import_info">import_info (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.import_info">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.incloud">incloud() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.incloud">incloud (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.interaction">interaction (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.interesting_subject">interesting_subject (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.intrash">intrash() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.intrash">intrash (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.intrusive_object_presence">intrusive_object_presence (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.iscloudasset">iscloudasset() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.iscloudasset">iscloudasset (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ismissing">ismissing() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ismissing">ismissing (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ismovie">ismovie() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ismovie">ismovie (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.iso">iso (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.isphoto">isphoto() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.isphoto">isphoto (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.israw">israw() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.israw">israw (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.isreference">isreference() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.isreference">isreference (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -1377,7 +1463,7 @@
|
||||
<h2 id="K">K</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.keywords">keywords() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.keywords">keywords (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.keywords">(osxphotos.PhotosDB property)</a>
|
||||
@@ -1385,7 +1471,7 @@
|
||||
</ul></li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.keywords_as_dict">keywords_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.keywords_as_dict">keywords_as_dict (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -1393,7 +1479,7 @@
|
||||
<h2 id="L">L</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.labels">labels() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.labels">labels (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.labels">(osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
@@ -1401,15 +1487,15 @@
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.labels">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.labels_as_dict">labels_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.labels_as_dict">labels_as_dict (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.labels_normalized">labels_normalized() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.labels_normalized">labels_normalized (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.labels_normalized">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.labels_normalized_as_dict">labels_normalized_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.labels_normalized_as_dict">labels_normalized_as_dict (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.latitude">latitude (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
@@ -1417,17 +1503,17 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.lens_model">lens_model (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.library_path">library_path() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.library_path">library_path (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.likes">likes() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.likes">likes (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.live_photo">live_photo() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.live_photo">live_photo (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.lively_color">lively_color (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.locality_names">locality_names() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.locality_names">locality_names (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.location">location() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.location">location (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.longitude">longitude (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
@@ -1439,13 +1525,13 @@
|
||||
<h2 id="M">M</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.media_types">media_types() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.media_types">media_types (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.metering_mode">metering_mode (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.month">month() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.month">month (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -1453,7 +1539,7 @@
|
||||
<h2 id="N">N</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.neighborhoods">neighborhoods() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.neighborhoods">neighborhoods (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@@ -1465,17 +1551,17 @@
|
||||
<h2 id="O">O</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.orientation">orientation() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.orientation">orientation (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_filename">original_filename() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_filename">original_filename (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_filesize">original_filesize() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_filesize">original_filesize (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_height">original_height() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_height">original_height (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_orientation">original_orientation() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_orientation">original_orientation (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_width">original_width() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.original_width">original_width (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li>
|
||||
osxphotos command line option
|
||||
@@ -1553,6 +1639,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-download-missing">--download-missing</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-dry-run">--dry-run</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-duplicate">--duplicate</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-edited">--edited</a>
|
||||
</li>
|
||||
@@ -1623,6 +1711,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-live">--live</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-load-config">--load-config <config file path></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-location">--location</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-max-size">--max-size <SIZE></a>
|
||||
</li>
|
||||
@@ -1637,6 +1727,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-no-description">--no-description</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-no-likes">--no-likes</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-no-location">--no-location</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-no-place">--no-place</a>
|
||||
</li>
|
||||
@@ -1687,8 +1779,20 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-place">--place <PLACE></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-portrait">--portrait</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-post-command">--post-command <CATEGORY COMMAND></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-post-function">--post-function <filename.py::function></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-preview">--preview</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-preview-if-missing">--preview-if-missing</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-preview-suffix">--preview-suffix <SUFFIX></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-query-eval">--query-eval <CRITERIA></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-query-function">--query-function <filename.py::function></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-regex">--regex <REGEX TEMPLATE></a>
|
||||
</li>
|
||||
@@ -1701,6 +1805,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-save-config">--save-config <config file path></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-screenshot">--screenshot</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-selected">--selected</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-selfie">--selfie</a>
|
||||
</li>
|
||||
@@ -1849,6 +1955,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-deleted-only">--deleted-only</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-description">--description <DESC></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-duplicate">--duplicate</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-edited">--edited</a>
|
||||
</li>
|
||||
@@ -1887,6 +1995,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-label">--label <LABEL></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-live">--live</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-location">--location</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-max-size">--max-size <SIZE></a>
|
||||
</li>
|
||||
@@ -1901,6 +2011,8 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-description">--no-description</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-likes">--no-likes</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-location">--no-location</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-no-place">--no-place</a>
|
||||
</li>
|
||||
@@ -1951,10 +2063,14 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-portrait">--portrait</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-query-eval">--query-eval <CRITERIA></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-query-function">--query-function <filename.py::function></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-regex">--regex <REGEX TEMPLATE></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-screenshot">--screenshot</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-selected">--selected</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-selfie">--selfie</a>
|
||||
</li>
|
||||
@@ -1979,6 +2095,20 @@
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-i">-i</a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-query-arg-PHOTOS_LIBRARY">PHOTOS_LIBRARY</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
osxphotos-repl command line option
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-repl-db">--db <Photos database path></a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
osxphotos-tutorial command line option
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-tutorial-arg-WIDTH">WIDTH</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.overall">overall (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
@@ -1989,31 +2119,33 @@
|
||||
<h2 id="P">P</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.panorama">panorama() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.panorama">panorama (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path">path() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path">path (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_derivatives">path_derivatives() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_derivatives">path_derivatives (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_edited">path_edited() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_edited">path_edited (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_live_photo">path_live_photo() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_edited_live_photo">path_edited_live_photo (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_raw">path_raw() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_live_photo">path_live_photo (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.person_info">person_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.path_raw">path_raw (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.person_info">person_info (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.person_info">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.persons">persons() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.persons">persons (osxphotos.PhotoInfo property)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.persons">(osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.persons_as_dict">persons_as_dict() (osxphotos.PhotosDB property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.persons_as_dict">persons_as_dict (osxphotos.PhotosDB property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo">PhotoInfo (class in osxphotos)</a>
|
||||
</li>
|
||||
@@ -2056,9 +2188,9 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB">PhotosDB (class in osxphotos)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.place">place() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.place">place (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.place_names">place_names() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.place_names">place_names (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.pleasant_camera_tilt">pleasant_camera_tilt (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
@@ -2076,7 +2208,7 @@
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.pleasant_symmetry">pleasant_symmetry (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.portrait">portrait() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.portrait">portrait (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.promotion">promotion (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
@@ -2094,7 +2226,7 @@
|
||||
<h2 id="R">R</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.raw_original">raw_original() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.raw_original">raw_original (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@@ -2108,33 +2240,33 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.sample_rate">sample_rate (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.score">score() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.score">score (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.screenshot">screenshot() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.screenshot">screenshot (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.search_info">search_info() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.search_info">search_info (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.search_info_normalized">search_info_normalized() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.search_info_normalized">search_info_normalized (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.season">season() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.season">season (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.selfie">selfie() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.selfie">selfie (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.shared">shared() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.shared">shared (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.sharply_focused_subject">sharply_focused_subject (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.shutter_speed">shutter_speed (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.slow_mo">slow_mo() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.slow_mo">slow_mo (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.state">state() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.state">state (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.state_abbreviation">state_abbreviation() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.state_abbreviation">state_abbreviation (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.streets">streets() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.streets">streets (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -2144,9 +2276,9 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.tastefully_blurred">tastefully_blurred (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.time_lapse">time_lapse() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.time_lapse">time_lapse (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.title">title() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.title">title (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@@ -2159,7 +2291,7 @@
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.track_format">track_format (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.tzoffset">tzoffset() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.tzoffset">tzoffset (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -2167,17 +2299,17 @@
|
||||
<h2 id="U">U</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti">uti() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti">uti (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti_edited">uti_edited() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti_edited">uti_edited (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti_original">uti_original() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti_original">uti_original (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti_raw">uti_raw() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uti_raw">uti_raw (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uuid">uuid() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.uuid">uuid (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -2185,13 +2317,13 @@
|
||||
<h2 id="V">V</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.venue_types">venue_types() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.venue_types">venue_types (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.venues">venues() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.venues">venues (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.visible">visible() (osxphotos.PhotoInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.visible">visible (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -2203,13 +2335,20 @@
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.well_framed_subject">well_framed_subject (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.well_timed_shot">well_timed_shot (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.white_balance">white_balance (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.width">width() (osxphotos.PhotoInfo property)</a>
|
||||
<li>
|
||||
WIDTH
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-tutorial-arg-WIDTH">osxphotos-tutorial command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.width">width (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -2217,7 +2356,7 @@
|
||||
<h2 id="Y">Y</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.year">year() (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.SearchInfo.year">year (osxphotos.PhotoInfo.SearchInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -2278,7 +2417,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.42.20 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.42.69 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>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
@@ -45,8 +45,8 @@ You can also easily export both the original and edited photos.</p>
|
||||
</div>
|
||||
<div class="section" id="supported-operating-systems">
|
||||
<h2>Supported operating systems<a class="headerlink" href="#supported-operating-systems" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Only works on macOS (aka Mac OS X). Tested on macOS Sierra (10.12.6) until macOS Catalina (10.15.7).
|
||||
Beta support for macOS Big Sur (10.16.01/11.01).</p>
|
||||
<p>Only works on macOS (aka Mac OS X). Tested on macOS Sierra (10.12.6) through macOS Big Sur (11.3).</p>
|
||||
<p>If you have access to macOS 12 / Monterey beta and would like to help ensure osxphotos is compatible, please contact me via GitHub.</p>
|
||||
<p>This package will read Photos databases for any supported version on any supported macOS version.
|
||||
E.g. you can read a database created with Photos 5.0 on MacOS 10.15 on a machine running macOS 10.12 and vice versa.</p>
|
||||
<p>Requires python >= <code class="docutils literal notranslate"><span class="pre">3.7</span></code>.</p>
|
||||
@@ -122,6 +122,8 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
<span class="n">persons</span> <span class="n">Print</span> <span class="n">out</span> <span class="n">persons</span> <span class="p">(</span><span class="n">faces</span><span class="p">)</span> <span class="n">found</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">Photos</span> <span class="n">library</span><span class="o">.</span>
|
||||
<span class="n">places</span> <span class="n">Print</span> <span class="n">out</span> <span class="n">places</span> <span class="n">found</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">Photos</span> <span class="n">library</span><span class="o">.</span>
|
||||
<span class="n">query</span> <span class="n">Query</span> <span class="n">the</span> <span class="n">Photos</span> <span class="n">database</span> <span class="n">using</span> <span class="mi">1</span> <span class="ow">or</span> <span class="n">more</span> <span class="n">search</span> <span class="n">options</span><span class="p">;</span> <span class="k">if</span><span class="o">...</span>
|
||||
<span class="n">repl</span> <span class="n">Run</span> <span class="n">interactive</span> <span class="n">osxphotos</span> <span class="n">shell</span>
|
||||
<span class="n">tutorial</span> <span class="n">Display</span> <span class="n">osxphotos</span> <span class="n">tutorial</span><span class="o">.</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To get help on a specific command, use <code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">help</span> <span class="pre"><command_name></span></code></p>
|
||||
@@ -292,6 +294,8 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
<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-tutorial">tutorial</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -369,7 +373,7 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
|
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos — osxphotos 0.42.20 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
<title>osxphotos — osxphotos 0.42.69 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>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
@@ -91,7 +91,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
|
|
||||
|
||||
BIN
docs/objects.inv
BIN
docs/objects.inv
Binary file not shown.
1026
docs/reference.html
1026
docs/reference.html
File diff suppressed because one or more lines are too long
@@ -5,11 +5,11 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — osxphotos 0.42.20 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
|
||||
<title>Search — osxphotos 0.42.69 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
|
||||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
@@ -37,6 +37,7 @@
|
||||
<div class="body" role="main">
|
||||
|
||||
<h1 id="search-documentation">Search</h1>
|
||||
|
||||
<div id="fallback" class="admonition warning">
|
||||
<script>$('#fallback').hide();</script>
|
||||
<p>
|
||||
@@ -44,19 +45,26 @@
|
||||
functionality.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
Searching for multiple words only shows matches that contain
|
||||
all words.
|
||||
</p>
|
||||
|
||||
|
||||
<form action="" method="get">
|
||||
<input type="text" name="q" aria-labelledby="search-documentation" value="" />
|
||||
<input type="submit" value="search" />
|
||||
<span id="search-progress" style="padding-left: 10px"></span>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
<div id="search-results">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -102,7 +110,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 3.5.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.0.2</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,24 +10,6 @@ from osxphotos.path_utils import sanitize_dirname
|
||||
from osxphotos.phototemplate import RenderOptions
|
||||
|
||||
|
||||
def _get_album_sort_order(album: AlbumInfo, photo: PhotoInfo) -> Optional[int]:
|
||||
"""Get the sort order of photo in album
|
||||
|
||||
Returns: sort order as int or None if photo not found in album
|
||||
"""
|
||||
# get the album sort order from the album_info
|
||||
sort_order = 0 # change this to 1 if you want counting to start at 1
|
||||
for album_photo in album.photos:
|
||||
if album_photo.uuid == photo.uuid:
|
||||
# found the photo we're processing
|
||||
break
|
||||
sort_order += 1
|
||||
else:
|
||||
# didn't find the photo, so skip this file
|
||||
return None
|
||||
return sort_order
|
||||
|
||||
|
||||
def album_sequence(photo: PhotoInfo, options: RenderOptions, **kwargs) -> str:
|
||||
"""Call this with {function} template to get album sequence (sort order) when exporting with {folder_album} template
|
||||
|
||||
@@ -59,7 +41,7 @@ def album_sequence(photo: PhotoInfo, options: RenderOptions, **kwargs) -> str:
|
||||
def album_sort_order(
|
||||
photo: PhotoInfo, results: ExportResults, verbose: callable, **kwargs
|
||||
):
|
||||
"""Call this with osxphotos export /path/to/export --post-function post_function.py::post_function
|
||||
"""Call this with osxphotos export /path/to/export --post-function album_sort_order.py::album_sort_order
|
||||
This will get called immediately after the photo has been exported
|
||||
|
||||
Args:
|
||||
@@ -119,9 +101,10 @@ def album_sort_order(
|
||||
# didn't find the album, so skip this file
|
||||
return
|
||||
|
||||
sort_order = _get_album_sort_order(album_info, photo)
|
||||
if sort_order is None:
|
||||
# didn't find the photo, so skip this file
|
||||
try:
|
||||
sort_order = album_info.photo_index(photo)
|
||||
except ValueError:
|
||||
# photo not in album, so skip this file
|
||||
return
|
||||
|
||||
verbose(f"Sort order for {filepath} in album {album_dir} is {sort_order}")
|
||||
|
||||
@@ -282,3 +282,5 @@ class AlbumSortOrder(Enum):
|
||||
NEWEST_FIRST = 2
|
||||
OLDEST_FIRST = 3
|
||||
TITLE = 5
|
||||
|
||||
TEXT_DETECTION_CONFIDENCE_THRESHOLD = 0.75
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.42.65"
|
||||
__version__ = "0.42.78"
|
||||
|
||||
145
osxphotos/cli.py
145
osxphotos/cli.py
@@ -1796,6 +1796,7 @@ def export(
|
||||
export_dir=dest,
|
||||
dry_run=dry_run,
|
||||
exiftool_path=exiftool_path,
|
||||
export_db=export_db,
|
||||
)
|
||||
|
||||
if album_export and export_results.exported:
|
||||
@@ -1865,6 +1866,7 @@ def export(
|
||||
finder_tag_template=finder_tag_template,
|
||||
strip=strip,
|
||||
export_dir=dest,
|
||||
export_db=export_db,
|
||||
)
|
||||
results.xattr_written.extend(tags_written)
|
||||
results.xattr_skipped.extend(tags_skipped)
|
||||
@@ -1876,6 +1878,7 @@ def export(
|
||||
xattr_template,
|
||||
strip=strip,
|
||||
export_dir=dest,
|
||||
export_db=export_db,
|
||||
)
|
||||
results.xattr_written.extend(xattr_written)
|
||||
results.xattr_skipped.extend(xattr_skipped)
|
||||
@@ -2538,10 +2541,22 @@ def export_photo(
|
||||
sidecar_flags |= SIDECAR_EXIFTOOL
|
||||
|
||||
rendered_suffix = _render_suffix_template(
|
||||
original_suffix, "original_suffix", "--original-suffix", strip, dest, photo
|
||||
original_suffix,
|
||||
"original_suffix",
|
||||
"--original-suffix",
|
||||
strip,
|
||||
dest,
|
||||
photo,
|
||||
export_db,
|
||||
)
|
||||
rendered_preview_suffix = _render_suffix_template(
|
||||
preview_suffix, "preview_suffix", "--preview-suffix", strip, dest, photo
|
||||
preview_suffix,
|
||||
"preview_suffix",
|
||||
"--preview-suffix",
|
||||
strip,
|
||||
dest,
|
||||
photo,
|
||||
export_db,
|
||||
)
|
||||
|
||||
# if download_missing and the photo is missing or path doesn't exist,
|
||||
@@ -2557,11 +2572,24 @@ def export_photo(
|
||||
|
||||
results = ExportResults()
|
||||
dest_paths = get_dirnames_from_template(
|
||||
photo, directory, export_by_date, dest, dry_run, strip=strip, edited=False
|
||||
photo,
|
||||
directory,
|
||||
export_by_date,
|
||||
dest,
|
||||
dry_run,
|
||||
strip=strip,
|
||||
edited=False,
|
||||
export_db=export_db,
|
||||
)
|
||||
for dest_path in dest_paths:
|
||||
filenames = get_filenames_from_template(
|
||||
photo, filename_template, dest, dest_path, original_name, strip=strip
|
||||
photo,
|
||||
filename_template,
|
||||
dest,
|
||||
dest_path,
|
||||
original_name,
|
||||
strip=strip,
|
||||
export_db=export_db,
|
||||
)
|
||||
|
||||
for filename in filenames:
|
||||
@@ -2632,12 +2660,26 @@ def export_photo(
|
||||
|
||||
if export_edited and photo.hasadjustments:
|
||||
dest_paths = get_dirnames_from_template(
|
||||
photo, directory, export_by_date, dest, dry_run, strip=strip, edited=True
|
||||
photo,
|
||||
directory,
|
||||
export_by_date,
|
||||
dest,
|
||||
dry_run,
|
||||
strip=strip,
|
||||
edited=True,
|
||||
export_db=export_db,
|
||||
)
|
||||
for dest_path in dest_paths:
|
||||
# if export-edited, also export the edited version
|
||||
edited_filenames = get_filenames_from_template(
|
||||
photo, filename_template, dest, dest_path, original_name, strip=strip, edited=True
|
||||
photo,
|
||||
filename_template,
|
||||
dest,
|
||||
dest_path,
|
||||
original_name,
|
||||
strip=strip,
|
||||
edited=True,
|
||||
export_db=export_db,
|
||||
)
|
||||
for edited_filename in edited_filenames:
|
||||
edited_filename = pathlib.Path(edited_filename)
|
||||
@@ -2674,6 +2716,7 @@ def export_photo(
|
||||
strip,
|
||||
dest,
|
||||
photo,
|
||||
export_db,
|
||||
)
|
||||
edited_filename = (
|
||||
f"{edited_filename.stem}{rendered_edited_suffix}{edited_ext}"
|
||||
@@ -2729,7 +2772,9 @@ def export_photo(
|
||||
return results
|
||||
|
||||
|
||||
def _render_suffix_template(suffix_template, var_name, option_name, strip, dest, photo):
|
||||
def _render_suffix_template(
|
||||
suffix_template, var_name, option_name, strip, dest, photo, export_db
|
||||
):
|
||||
"""render suffix template
|
||||
|
||||
Returns:
|
||||
@@ -2739,7 +2784,7 @@ def _render_suffix_template(suffix_template, var_name, option_name, strip, dest,
|
||||
return ""
|
||||
|
||||
try:
|
||||
options = RenderOptions(filename=True, strip=strip, export_dir=dest)
|
||||
options = RenderOptions(filename=True, export_dir=dest, exportdb=export_db)
|
||||
rendered_suffix, unmatched = photo.render_template(suffix_template, options)
|
||||
except ValueError as e:
|
||||
raise click.BadOptionUsage(
|
||||
@@ -2756,6 +2801,10 @@ def _render_suffix_template(suffix_template, var_name, option_name, strip, dest,
|
||||
var_name,
|
||||
f"Invalid template for {option_name}: may not use multi-valued templates: '{suffix_template}': results={rendered_suffix}",
|
||||
)
|
||||
|
||||
if strip:
|
||||
rendered_suffix[0] = rendered_suffix[0].strip()
|
||||
|
||||
return rendered_suffix[0]
|
||||
|
||||
|
||||
@@ -2848,7 +2897,9 @@ def export_photo_to_directory(
|
||||
results.missing.append(str(pathlib.Path(dest_path) / filename))
|
||||
return results
|
||||
|
||||
render_options = RenderOptions(export_dir=export_dir, dest_path=dest_path)
|
||||
render_options = RenderOptions(
|
||||
export_dir=export_dir, dest_path=dest_path, exportdb=export_db
|
||||
)
|
||||
|
||||
tries = 0
|
||||
while tries <= retry:
|
||||
@@ -2960,6 +3011,7 @@ def get_filenames_from_template(
|
||||
original_name,
|
||||
strip=False,
|
||||
edited=False,
|
||||
export_db=None,
|
||||
):
|
||||
"""get list of export filenames for a photo
|
||||
|
||||
@@ -2983,10 +3035,10 @@ def get_filenames_from_template(
|
||||
options = RenderOptions(
|
||||
path_sep="_",
|
||||
filename=True,
|
||||
strip=strip,
|
||||
edited_version=edited,
|
||||
export_dir=export_dir,
|
||||
dest_path=dest_path,
|
||||
exportdb=export_db,
|
||||
)
|
||||
filenames, unmatched = photo.render_template(filename_template, options)
|
||||
except ValueError as e:
|
||||
@@ -3006,12 +3058,22 @@ def get_filenames_from_template(
|
||||
else [photo.filename]
|
||||
)
|
||||
|
||||
if strip:
|
||||
filenames = [filename.strip() for filename in filenames]
|
||||
filenames = [sanitize_filename(filename) for filename in filenames]
|
||||
|
||||
return filenames
|
||||
|
||||
|
||||
def get_dirnames_from_template(
|
||||
photo, directory, export_by_date, dest, dry_run, strip=False, edited=False
|
||||
photo,
|
||||
directory,
|
||||
export_by_date,
|
||||
dest,
|
||||
dry_run,
|
||||
strip=False,
|
||||
edited=False,
|
||||
export_db=None,
|
||||
):
|
||||
"""get list of directories to export a photo into, creates directories if they don't exist
|
||||
|
||||
@@ -3042,7 +3104,9 @@ def get_dirnames_from_template(
|
||||
elif directory:
|
||||
# got a directory template, render it and check results are valid
|
||||
try:
|
||||
options = RenderOptions(dirname=True, strip=strip, edited_version=edited)
|
||||
options = RenderOptions(
|
||||
dirname=True, edited_version=edited, exportdb=export_db
|
||||
)
|
||||
dirnames, unmatched = photo.render_template(directory, options)
|
||||
except ValueError as e:
|
||||
raise click.BadOptionUsage(
|
||||
@@ -3056,6 +3120,8 @@ def get_dirnames_from_template(
|
||||
|
||||
dest_paths = []
|
||||
for dirname in dirnames:
|
||||
if strip:
|
||||
dirname = dirname.strip()
|
||||
dirname = sanitize_filepath(dirname)
|
||||
dest_path = os.path.join(dest, dirname)
|
||||
if not is_valid_filepath(dest_path):
|
||||
@@ -3325,6 +3391,7 @@ def write_finder_tags(
|
||||
finder_tag_template=None,
|
||||
strip=False,
|
||||
export_dir=None,
|
||||
export_db=None,
|
||||
):
|
||||
"""Write Finder tags (extended attributes) to files; only writes attributes if attributes on file differ from what would be written
|
||||
|
||||
@@ -3338,6 +3405,7 @@ def write_finder_tags(
|
||||
exiftool_merge_keywords: if True, include any keywords in the exif data of the source image as keywords
|
||||
finder_tag_template: list of templates to evaluate for determining Finder tags
|
||||
export_dir: value to use for {export_dir} template
|
||||
export_db: an ExportDB object
|
||||
|
||||
Returns:
|
||||
(list of file paths that were updated with new Finder tags, list of file paths skipped because Finder tags didn't need updating)
|
||||
@@ -3367,8 +3435,8 @@ def write_finder_tags(
|
||||
options = RenderOptions(
|
||||
none_str=_OSXPHOTOS_NONE_SENTINEL,
|
||||
path_sep="/",
|
||||
strip=strip,
|
||||
export_dir=export_dir,
|
||||
exportdb=export_db,
|
||||
)
|
||||
rendered, unmatched = photo.render_template(template_str, options)
|
||||
except ValueError as e:
|
||||
@@ -3388,6 +3456,9 @@ def write_finder_tags(
|
||||
rendered_tags.extend(rendered)
|
||||
|
||||
# filter out any template values that didn't match by looking for sentinel
|
||||
if strip:
|
||||
rendered_tags = [value.strip() for value in rendered_tags]
|
||||
|
||||
rendered_tags = [
|
||||
value.replace(_OSXPHOTOS_NONE_SENTINEL, "") for value in rendered_tags
|
||||
]
|
||||
@@ -3408,7 +3479,12 @@ def write_finder_tags(
|
||||
|
||||
|
||||
def write_extended_attributes(
|
||||
photo, files, xattr_template, strip=False, export_dir=None
|
||||
photo,
|
||||
files,
|
||||
xattr_template,
|
||||
strip=False,
|
||||
export_dir=None,
|
||||
export_db=None,
|
||||
):
|
||||
"""Writes extended attributes to exported files
|
||||
|
||||
@@ -3416,6 +3492,7 @@ def write_extended_attributes(
|
||||
photo: a PhotoInfo object
|
||||
strip: xattr_template: list of tuples: (attribute name, attribute template)
|
||||
export_dir: value to use for {export_dir} template
|
||||
exportdb: an ExportDB object
|
||||
|
||||
Returns:
|
||||
tuple(list of file paths that were updated with new attributes, list of file paths skipped because attributes didn't need updating)
|
||||
@@ -3427,8 +3504,8 @@ def write_extended_attributes(
|
||||
options = RenderOptions(
|
||||
none_str=_OSXPHOTOS_NONE_SENTINEL,
|
||||
path_sep="/",
|
||||
strip=strip,
|
||||
export_dir=export_dir,
|
||||
exportdb=export_db,
|
||||
)
|
||||
rendered, unmatched = photo.render_template(template_str, options)
|
||||
except ValueError as e:
|
||||
@@ -3446,6 +3523,9 @@ def write_extended_attributes(
|
||||
)
|
||||
|
||||
# filter out any template values that didn't match by looking for sentinel
|
||||
if strip:
|
||||
rendered = [value.strip() for value in rendered]
|
||||
|
||||
rendered = [value.replace(_OSXPHOTOS_NONE_SENTINEL, "") for value in rendered]
|
||||
|
||||
try:
|
||||
@@ -3480,7 +3560,7 @@ def write_extended_attributes(
|
||||
|
||||
|
||||
def run_post_command(
|
||||
photo, post_command, export_results, export_dir, dry_run, exiftool_path
|
||||
photo, post_command, export_results, export_dir, dry_run, exiftool_path, export_db
|
||||
):
|
||||
# todo: pass in RenderOptions from export? (e.g. so it contains strip, etc?)
|
||||
# todo: need a shell_quote template type:
|
||||
@@ -3492,7 +3572,9 @@ def run_post_command(
|
||||
# some categories, like error, return a tuple of (file, error str)
|
||||
if isinstance(f, tuple):
|
||||
f = f[0]
|
||||
render_options = RenderOptions(export_dir=export_dir, filepath=f)
|
||||
render_options = RenderOptions(
|
||||
export_dir=export_dir, filepath=f, exportdb=export_db
|
||||
)
|
||||
template = PhotoTemplate(photo, exiftool_path=exiftool_path)
|
||||
command, _ = template.render(command_template, options=render_options)
|
||||
command = command[0] if command else None
|
||||
@@ -4002,6 +4084,10 @@ def _get_selected(photosdb):
|
||||
@click.pass_context
|
||||
def repl(ctx, cli_obj, db):
|
||||
"""Run interactive osxphotos shell"""
|
||||
|
||||
from osxphotos import PhotosDB, PhotoInfo, ExifTool
|
||||
from rich import inspect as _inspect
|
||||
|
||||
pretty.install()
|
||||
print(f"python version: {sys.version}")
|
||||
print(f"osxphotos version: {osxphotos._version.__version__}")
|
||||
@@ -4017,12 +4103,30 @@ def repl(ctx, cli_obj, db):
|
||||
get_photo = photosdb.get_photo
|
||||
show = _show_photo
|
||||
get_selected = _get_selected(photosdb)
|
||||
selected = get_selected()
|
||||
|
||||
def inspect(obj):
|
||||
"""inspect object"""
|
||||
return _inspect(obj, methods=True)
|
||||
|
||||
class ReprQuit:
|
||||
def __repr__(self):
|
||||
sys.exit(0)
|
||||
|
||||
def __call__(self):
|
||||
sys.exit(0)
|
||||
|
||||
quit = ReprQuit()
|
||||
q = ReprQuit()
|
||||
|
||||
print(f"Found {len(photos)} photos in {tictoc:0.2f} seconds")
|
||||
print("The following variables are defined:")
|
||||
print(f"- photosdb: PhotosDB() instance for {photosdb.library_path}")
|
||||
print(
|
||||
f"- photos: list of PhotoInfo objects for all photos in photosdb, including those in the trash"
|
||||
f"- photos: list of PhotoInfo objects for all photos in photosdb, including those in the trash (len={len(photos)})"
|
||||
)
|
||||
print(
|
||||
f"- selected: list of PhotoInfo objects for any photos selected in Photos (len={len(selected)})"
|
||||
)
|
||||
print(f"\nThe following functions may be helpful:")
|
||||
print(f"- get_photo(uuid): return a PhotoInfo object for photo with uuid")
|
||||
@@ -4033,5 +4137,8 @@ def repl(ctx, cli_obj, db):
|
||||
print(
|
||||
f"- help(object): print help text including list of methods for object; for example, help(PhotosDB)"
|
||||
)
|
||||
print(f"- quit(): exit this interactive shell\n")
|
||||
print(
|
||||
f"- inspect(object): print information about an object; for example inspect(photosdb)"
|
||||
)
|
||||
print(f"- q, quit, or quit(): exit this interactive shell\n")
|
||||
code.interact(banner="", local=locals())
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
pyexiftool: https://github.com/smarnach/pyexiftool which provides more functionality """
|
||||
|
||||
import atexit
|
||||
import html
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@@ -24,16 +25,34 @@ EXIFTOOL_STAYOPEN_EOF_LEN = len(EXIFTOOL_STAYOPEN_EOF)
|
||||
EXIFTOOL_PROCESSES = []
|
||||
|
||||
|
||||
def escape_str(s):
|
||||
"""escape string for use with exiftool -E"""
|
||||
if type(s) != str:
|
||||
return s
|
||||
s = html.escape(s)
|
||||
s = s.replace("\n", "
")
|
||||
s = s.replace("\t", "	")
|
||||
s = s.replace("\r", "
")
|
||||
return s
|
||||
|
||||
|
||||
def unescape_str(s):
|
||||
"""unescape an HTML string returned by exiftool -E"""
|
||||
if type(s) != str:
|
||||
return s
|
||||
return html.unescape(s)
|
||||
|
||||
|
||||
@atexit.register
|
||||
def terminate_exiftool():
|
||||
"""Terminate any running ExifTool subprocesses; call this to cleanup when done using ExifTool """
|
||||
"""Terminate any running ExifTool subprocesses; call this to cleanup when done using ExifTool"""
|
||||
for proc in EXIFTOOL_PROCESSES:
|
||||
proc._stop_proc()
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_exiftool_path():
|
||||
""" return path of exiftool, cache result """
|
||||
"""return path of exiftool, cache result"""
|
||||
exiftool_path = shutil.which("exiftool")
|
||||
if exiftool_path:
|
||||
return exiftool_path.rstrip()
|
||||
@@ -49,7 +68,7 @@ class _ExifToolProc:
|
||||
Creates a singleton object"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
""" create new object or return instance of already created singleton """
|
||||
"""create new object or return instance of already created singleton"""
|
||||
if not hasattr(cls, "instance") or not cls.instance:
|
||||
cls.instance = super().__new__(cls)
|
||||
|
||||
@@ -74,7 +93,7 @@ class _ExifToolProc:
|
||||
|
||||
@property
|
||||
def process(self):
|
||||
""" return the exiftool subprocess """
|
||||
"""return the exiftool subprocess"""
|
||||
if self._process_running:
|
||||
return self._process
|
||||
else:
|
||||
@@ -83,16 +102,16 @@ class _ExifToolProc:
|
||||
|
||||
@property
|
||||
def pid(self):
|
||||
""" return process id (PID) of the exiftool process """
|
||||
"""return process id (PID) of the exiftool process"""
|
||||
return self._process.pid
|
||||
|
||||
@property
|
||||
def exiftool(self):
|
||||
""" return path to exiftool process """
|
||||
"""return path to exiftool process"""
|
||||
return self._exiftool
|
||||
|
||||
def _start_proc(self):
|
||||
""" start exiftool in batch mode """
|
||||
"""start exiftool in batch mode"""
|
||||
|
||||
if self._process_running:
|
||||
logging.warning("exiftool already running: {self._process}")
|
||||
@@ -110,6 +129,7 @@ class _ExifToolProc:
|
||||
"-n", # no print conversion (e.g. print tag values in machine readable format)
|
||||
"-P", # Preserve file modification date/time
|
||||
"-G", # print group name for each tag
|
||||
"-E", # escape tag values for HTML (allows use of HTML 
 for newlines)
|
||||
],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
@@ -120,7 +140,7 @@ class _ExifToolProc:
|
||||
EXIFTOOL_PROCESSES.append(self)
|
||||
|
||||
def _stop_proc(self):
|
||||
""" stop the exiftool process if it's running, otherwise, do nothing """
|
||||
"""stop the exiftool process if it's running, otherwise, do nothing"""
|
||||
|
||||
if not self._process_running:
|
||||
return
|
||||
@@ -143,7 +163,7 @@ class _ExifToolProc:
|
||||
|
||||
|
||||
class ExifTool:
|
||||
""" Basic exiftool interface for reading and writing EXIF tags """
|
||||
"""Basic exiftool interface for reading and writing EXIF tags"""
|
||||
|
||||
def __init__(self, filepath, exiftool=None, overwrite=True, flags=None):
|
||||
"""Create ExifTool object
|
||||
@@ -189,6 +209,7 @@ class ExifTool:
|
||||
|
||||
if value is None:
|
||||
value = ""
|
||||
value = escape_str(value)
|
||||
command = [f"-{tag}={value}"]
|
||||
if self.overwrite and not self._context_mgr:
|
||||
command.append("-overwrite_original")
|
||||
@@ -233,6 +254,7 @@ class ExifTool:
|
||||
for value in values:
|
||||
if value is None:
|
||||
raise ValueError("Can't add None value to tag")
|
||||
value = escape_str(value)
|
||||
command.append(f"-{tag}+={value}")
|
||||
|
||||
if self.overwrite and not self._context_mgr:
|
||||
@@ -315,12 +337,12 @@ class ExifTool:
|
||||
|
||||
@property
|
||||
def pid(self):
|
||||
""" return process id (PID) of the exiftool process """
|
||||
"""return process id (PID) of the exiftool process"""
|
||||
return self._process.pid
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
""" returns exiftool version """
|
||||
"""returns exiftool version"""
|
||||
ver, _, _ = self.run_commands("-ver", no_file=True)
|
||||
return ver.decode("utf-8")
|
||||
|
||||
@@ -335,6 +357,7 @@ class ExifTool:
|
||||
json_str, _, _ = self.run_commands("-json")
|
||||
if not json_str:
|
||||
return dict()
|
||||
json_str = unescape_str(json_str.decode("utf-8"))
|
||||
|
||||
try:
|
||||
exifdict = json.loads(json_str)
|
||||
@@ -342,7 +365,6 @@ class ExifTool:
|
||||
# will fail with some commands, e.g --ext AVI which produces
|
||||
# 'No file with specified extension' instead of json
|
||||
return dict()
|
||||
|
||||
exifdict = exifdict[0]
|
||||
if not tag_groups:
|
||||
# strip tag groups
|
||||
@@ -358,12 +380,13 @@ class ExifTool:
|
||||
return exifdict
|
||||
|
||||
def json(self):
|
||||
""" returns JSON string containing all EXIF tags and values from exiftool """
|
||||
"""returns JSON string containing all EXIF tags and values from exiftool"""
|
||||
json, _, _ = self.run_commands("-json")
|
||||
json = unescape_str(json.decode("utf-8"))
|
||||
return json
|
||||
|
||||
def _read_exif(self):
|
||||
""" read exif data from file """
|
||||
"""read exif data from file"""
|
||||
data = self.asdict()
|
||||
self.data = {k: v for k, v in data.items()}
|
||||
|
||||
@@ -384,15 +407,15 @@ class ExifTool:
|
||||
|
||||
|
||||
class ExifToolCaching(ExifTool):
|
||||
""" Basic exiftool interface for reading and writing EXIF tags, with caching.
|
||||
Use this only when you know the file's EXIF data will not be changed by any external process.
|
||||
|
||||
Creates a singleton cached ExifTool instance """
|
||||
"""Basic exiftool interface for reading and writing EXIF tags, with caching.
|
||||
Use this only when you know the file's EXIF data will not be changed by any external process.
|
||||
|
||||
Creates a singleton cached ExifTool instance"""
|
||||
|
||||
_singletons = {}
|
||||
|
||||
def __new__(cls, filepath, exiftool=None):
|
||||
""" create new object or return instance of already created singleton """
|
||||
"""create new object or return instance of already created singleton"""
|
||||
if filepath not in cls._singletons:
|
||||
cls._singletons[filepath] = _ExifToolCaching(filepath, exiftool=exiftool)
|
||||
return cls._singletons[filepath]
|
||||
@@ -448,7 +471,6 @@ class _ExifToolCaching(ExifTool):
|
||||
return self._asdict_cache[tag_groups][normalized]
|
||||
|
||||
def flush_cache(self):
|
||||
""" Clear cached data so that calls to json or asdict return fresh data """
|
||||
"""Clear cached data so that calls to json or asdict return fresh data"""
|
||||
self._json_cache = None
|
||||
self._asdict_cache = {}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
""" Helper class for managing a database used by
|
||||
PhotoInfo.export for tracking state of exports and updates
|
||||
"""
|
||||
""" Helper class for managing a database used by PhotoInfo.export for tracking state of exports and updates """
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
@@ -12,13 +10,15 @@ from abc import ABC, abstractmethod
|
||||
from io import StringIO
|
||||
from sqlite3 import Error
|
||||
|
||||
from ._constants import OSXPHOTOS_EXPORT_DB
|
||||
from ._version import __version__
|
||||
|
||||
OSXPHOTOS_EXPORTDB_VERSION = "3.2"
|
||||
OSXPHOTOS_EXPORTDB_VERSION = "4.0"
|
||||
OSXPHOTOS_ABOUT_STRING = f"Created by osxphotos version {__version__} (https://github.com/RhetTbull/osxphotos) on {str(datetime.datetime.now())}"
|
||||
|
||||
|
||||
class ExportDB_ABC(ABC):
|
||||
""" abstract base class for ExportDB """
|
||||
"""abstract base class for ExportDB"""
|
||||
|
||||
@abstractmethod
|
||||
def get_uuid_for_file(self, filename):
|
||||
@@ -88,6 +88,14 @@ class ExportDB_ABC(ABC):
|
||||
def get_previous_uuids(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_detected_text_for_uuid(self, uuid):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_detected_text_for_uuid(self, uuid, json_text):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_data(
|
||||
self,
|
||||
@@ -104,7 +112,7 @@ class ExportDB_ABC(ABC):
|
||||
|
||||
|
||||
class ExportDBNoOp(ExportDB_ABC):
|
||||
""" An ExportDB with NoOp methods """
|
||||
"""An ExportDB with NoOp methods"""
|
||||
|
||||
def __init__(self):
|
||||
self.was_created = True
|
||||
@@ -162,6 +170,12 @@ class ExportDBNoOp(ExportDB_ABC):
|
||||
def get_previous_uuids(self):
|
||||
return []
|
||||
|
||||
def get_detected_text_for_uuid(self, uuid):
|
||||
return None
|
||||
|
||||
def set_detected_text_for_uuid(self, uuid, json_text):
|
||||
pass
|
||||
|
||||
def set_data(
|
||||
self,
|
||||
filename,
|
||||
@@ -177,23 +191,23 @@ class ExportDBNoOp(ExportDB_ABC):
|
||||
|
||||
|
||||
class ExportDB(ExportDB_ABC):
|
||||
""" Interface to sqlite3 database used to store state information for osxphotos export command """
|
||||
"""Interface to sqlite3 database used to store state information for osxphotos export command"""
|
||||
|
||||
def __init__(self, dbfile):
|
||||
""" dbfile: path to osxphotos export database file """
|
||||
"""dbfile: path to osxphotos export database file"""
|
||||
self._dbfile = dbfile
|
||||
# _path is parent of the database
|
||||
# all files referenced by get_/set_uuid_for_file will be converted to
|
||||
# relative paths to this parent _path
|
||||
# this allows the entire export tree to be moved to a new disk/location
|
||||
# whilst preserving the UUID to filename mappping
|
||||
# whilst preserving the UUID to filename mapping
|
||||
self._path = pathlib.Path(dbfile).parent
|
||||
self._conn = self._open_export_db(dbfile)
|
||||
self._insert_run_info()
|
||||
|
||||
def get_uuid_for_file(self, filename):
|
||||
""" query database for filename and return UUID
|
||||
returns None if filename not found in database
|
||||
"""query database for filename and return UUID
|
||||
returns None if filename not found in database
|
||||
"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
@@ -211,7 +225,7 @@ class ExportDB(ExportDB_ABC):
|
||||
return uuid
|
||||
|
||||
def set_uuid_for_file(self, filename, uuid):
|
||||
""" set UUID of filename to uuid in the database """
|
||||
"""set UUID of filename to uuid in the database"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path))
|
||||
filename_normalized = filename.lower()
|
||||
conn = self._conn
|
||||
@@ -226,9 +240,9 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def set_stat_orig_for_file(self, filename, stats):
|
||||
""" set stat info for filename
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime """
|
||||
"""set stat info for filename
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
if len(stats) != 3:
|
||||
raise ValueError(f"expected 3 elements for stat, got {len(stats)}")
|
||||
@@ -247,8 +261,8 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def get_stat_orig_for_file(self, filename):
|
||||
""" get stat info for filename
|
||||
returns: tuple of (mode, size, mtime)
|
||||
"""get stat info for filename
|
||||
returns: tuple of (mode, size, mtime)
|
||||
"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
@@ -272,21 +286,21 @@ class ExportDB(ExportDB_ABC):
|
||||
return stats
|
||||
|
||||
def set_stat_edited_for_file(self, filename, stats):
|
||||
""" set stat info for edited version of image (in Photos' library)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime """
|
||||
"""set stat info for edited version of image (in Photos' library)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime"""
|
||||
return self._set_stat_for_file("edited", filename, stats)
|
||||
|
||||
def get_stat_edited_for_file(self, filename):
|
||||
""" get stat info for edited version of image (in Photos' library)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime """
|
||||
"""get stat info for edited version of image (in Photos' library)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime"""
|
||||
return self._get_stat_for_file("edited", filename)
|
||||
|
||||
def set_stat_exif_for_file(self, filename, stats):
|
||||
""" set stat info for filename (after exiftool has updated it)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime """
|
||||
"""set stat info for filename (after exiftool has updated it)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
if len(stats) != 3:
|
||||
raise ValueError(f"expected 3 elements for stat, got {len(stats)}")
|
||||
@@ -305,8 +319,8 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def get_stat_exif_for_file(self, filename):
|
||||
""" get stat info for filename (after exiftool has updated it)
|
||||
returns: tuple of (mode, size, mtime)
|
||||
"""get stat info for filename (after exiftool has updated it)
|
||||
returns: tuple of (mode, size, mtime)
|
||||
"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
@@ -330,19 +344,19 @@ class ExportDB(ExportDB_ABC):
|
||||
return stats
|
||||
|
||||
def set_stat_converted_for_file(self, filename, stats):
|
||||
""" set stat info for filename (after image converted to jpeg)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime """
|
||||
"""set stat info for filename (after image converted to jpeg)
|
||||
filename: filename to set the stat info for
|
||||
stat: a tuple of length 3: mode, size, mtime"""
|
||||
return self._set_stat_for_file("converted", filename, stats)
|
||||
|
||||
def get_stat_converted_for_file(self, filename):
|
||||
""" get stat info for filename (after jpeg conversion)
|
||||
returns: tuple of (mode, size, mtime)
|
||||
"""get stat info for filename (after jpeg conversion)
|
||||
returns: tuple of (mode, size, mtime)
|
||||
"""
|
||||
return self._get_stat_for_file("converted", filename)
|
||||
|
||||
def get_info_for_uuid(self, uuid):
|
||||
""" returns the info JSON struct for a UUID """
|
||||
"""returns the info JSON struct for a UUID"""
|
||||
conn = self._conn
|
||||
try:
|
||||
c = conn.cursor()
|
||||
@@ -356,7 +370,7 @@ class ExportDB(ExportDB_ABC):
|
||||
return info
|
||||
|
||||
def set_info_for_uuid(self, uuid, info):
|
||||
""" sets the info JSON struct for a UUID """
|
||||
"""sets the info JSON struct for a UUID"""
|
||||
conn = self._conn
|
||||
try:
|
||||
c = conn.cursor()
|
||||
@@ -369,7 +383,7 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def get_exifdata_for_file(self, filename):
|
||||
""" returns the exifdata JSON struct for a file """
|
||||
"""returns the exifdata JSON struct for a file"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
try:
|
||||
@@ -387,7 +401,7 @@ class ExportDB(ExportDB_ABC):
|
||||
return exifdata
|
||||
|
||||
def set_exifdata_for_file(self, filename, exifdata):
|
||||
""" sets the exifdata JSON struct for a file """
|
||||
"""sets the exifdata JSON struct for a file"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
try:
|
||||
@@ -401,7 +415,7 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def get_sidecar_for_file(self, filename):
|
||||
""" returns the sidecar data and signature for a file """
|
||||
"""returns the sidecar data and signature for a file"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
try:
|
||||
@@ -429,7 +443,7 @@ class ExportDB(ExportDB_ABC):
|
||||
return sidecar_data, sidecar_sig
|
||||
|
||||
def set_sidecar_for_file(self, filename, sidecar_data, sidecar_sig):
|
||||
""" sets the sidecar data and signature for a file """
|
||||
"""sets the sidecar data and signature for a file"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path)).lower()
|
||||
conn = self._conn
|
||||
try:
|
||||
@@ -443,7 +457,7 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def get_previous_uuids(self):
|
||||
"""returns list of UUIDs of previously exported photos found in export database """
|
||||
"""returns list of UUIDs of previously exported photos found in export database"""
|
||||
conn = self._conn
|
||||
previous_uuids = []
|
||||
try:
|
||||
@@ -455,6 +469,36 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
return previous_uuids
|
||||
|
||||
def get_detected_text_for_uuid(self, uuid):
|
||||
"""Get the detected_text for a uuid"""
|
||||
conn = self._conn
|
||||
try:
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
"SELECT text_data FROM detected_text WHERE uuid = ?",
|
||||
(uuid,),
|
||||
)
|
||||
results = c.fetchone()
|
||||
detected_text = results[0] if results else None
|
||||
except Error as e:
|
||||
logging.warning(e)
|
||||
detected_text = None
|
||||
|
||||
return detected_text
|
||||
|
||||
def set_detected_text_for_uuid(self, uuid, text_json):
|
||||
"""Set the detected text for uuid"""
|
||||
conn = self._conn
|
||||
try:
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
"INSERT OR REPLACE INTO detected_text(uuid, text_data) VALUES (?, ?);",
|
||||
(uuid, text_json,),
|
||||
)
|
||||
conn.commit()
|
||||
except Error as e:
|
||||
logging.warning(e)
|
||||
|
||||
def set_data(
|
||||
self,
|
||||
filename,
|
||||
@@ -466,8 +510,7 @@ class ExportDB(ExportDB_ABC):
|
||||
info_json,
|
||||
exif_json,
|
||||
):
|
||||
""" sets all the data for file and uuid at once
|
||||
"""
|
||||
"""sets all the data for file and uuid at once"""
|
||||
filename = str(pathlib.Path(filename).relative_to(self._path))
|
||||
filename_normalized = filename.lower()
|
||||
conn = self._conn
|
||||
@@ -510,7 +553,7 @@ class ExportDB(ExportDB_ABC):
|
||||
logging.warning(e)
|
||||
|
||||
def close(self):
|
||||
""" close the database connection """
|
||||
"""close the database connection"""
|
||||
try:
|
||||
self._conn.close()
|
||||
except Error as e:
|
||||
@@ -548,9 +591,9 @@ class ExportDB(ExportDB_ABC):
|
||||
return stats
|
||||
|
||||
def _open_export_db(self, dbfile):
|
||||
""" open export database and return a db connection
|
||||
if dbfile does not exist, will create and initialize the database
|
||||
returns: connection to the database
|
||||
"""open export database and return a db connection
|
||||
if dbfile does not exist, will create and initialize the database
|
||||
returns: connection to the database
|
||||
"""
|
||||
|
||||
if not os.path.isfile(dbfile):
|
||||
@@ -573,7 +616,7 @@ class ExportDB(ExportDB_ABC):
|
||||
return conn
|
||||
|
||||
def _get_db_connection(self, dbfile):
|
||||
""" return db connection to dbname """
|
||||
"""return db connection to dbname"""
|
||||
try:
|
||||
conn = sqlite3.connect(dbfile)
|
||||
except Error as e:
|
||||
@@ -583,15 +626,15 @@ class ExportDB(ExportDB_ABC):
|
||||
return conn
|
||||
|
||||
def _get_database_version(self, conn):
|
||||
""" return tuple of (osxphotos, exportdb) versions for database connection conn """
|
||||
"""return tuple of (osxphotos, exportdb) versions for database connection conn"""
|
||||
version_info = conn.execute(
|
||||
"SELECT osxphotos, exportdb, max(id) FROM version"
|
||||
).fetchone()
|
||||
return (version_info[0], version_info[1])
|
||||
|
||||
def _create_db_tables(self, conn):
|
||||
""" create (if not already created) the necessary db tables for the export database
|
||||
conn: sqlite3 db connection
|
||||
"""create (if not already created) the necessary db tables for the export database
|
||||
conn: sqlite3 db connection
|
||||
"""
|
||||
sql_commands = {
|
||||
"sql_version_table": """ CREATE TABLE IF NOT EXISTS version (
|
||||
@@ -599,6 +642,10 @@ class ExportDB(ExportDB_ABC):
|
||||
osxphotos TEXT,
|
||||
exportdb TEXT
|
||||
); """,
|
||||
"sql_about_table": """ CREATE TABLE IF NOT EXISTS about (
|
||||
id INTEGER PRIMARY KEY,
|
||||
about TEXT
|
||||
);""",
|
||||
"sql_files_table": """ CREATE TABLE IF NOT EXISTS files (
|
||||
id INTEGER PRIMARY KEY,
|
||||
filepath TEXT NOT NULL,
|
||||
@@ -651,12 +698,18 @@ class ExportDB(ExportDB_ABC):
|
||||
size INTEGER,
|
||||
mtime REAL
|
||||
); """,
|
||||
"sql_detected_text_table": """ CREATE TABLE IF NOT EXISTS detected_text (
|
||||
id INTEGER PRIMARY KEY,
|
||||
uuid TEXT NOT NULL,
|
||||
text_data JSON
|
||||
); """,
|
||||
"sql_files_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_files_filepath_normalized on files (filepath_normalized); """,
|
||||
"sql_info_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_info_uuid on info (uuid); """,
|
||||
"sql_exifdata_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_exifdata_filename on exifdata (filepath_normalized); """,
|
||||
"sql_edited_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_edited_filename on edited (filepath_normalized);""",
|
||||
"sql_converted_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_converted_filename on converted (filepath_normalized);""",
|
||||
"sql_sidecar_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_sidecar_filename on sidecar (filepath_normalized);""",
|
||||
"sql_detected_text_idx": """ CREATE UNIQUE INDEX IF NOT EXISTS idx_detected_text on detected_text (uuid);""",
|
||||
}
|
||||
try:
|
||||
c = conn.cursor()
|
||||
@@ -666,12 +719,13 @@ class ExportDB(ExportDB_ABC):
|
||||
"INSERT INTO version(osxphotos, exportdb) VALUES (?, ?);",
|
||||
(__version__, OSXPHOTOS_EXPORTDB_VERSION),
|
||||
)
|
||||
c.execute("INSERT INTO about(about) VALUES (?);", (OSXPHOTOS_ABOUT_STRING,))
|
||||
conn.commit()
|
||||
except Error as e:
|
||||
logging.warning(e)
|
||||
|
||||
def __del__(self):
|
||||
""" ensure the database connection is closed """
|
||||
"""ensure the database connection is closed"""
|
||||
try:
|
||||
self._conn.close()
|
||||
except:
|
||||
@@ -696,35 +750,33 @@ class ExportDB(ExportDB_ABC):
|
||||
|
||||
|
||||
class ExportDBInMemory(ExportDB):
|
||||
""" In memory version of ExportDB
|
||||
Copies the on-disk database into memory so it may be operated on without
|
||||
modifying the on-disk verison
|
||||
"""In memory version of ExportDB
|
||||
Copies the on-disk database into memory so it may be operated on without
|
||||
modifying the on-disk version
|
||||
"""
|
||||
|
||||
def init(self, dbfile):
|
||||
self._dbfile = dbfile
|
||||
def __init__(self, dbfile):
|
||||
self._dbfile = dbfile or f"./{OSXPHOTOS_EXPORT_DB}"
|
||||
# _path is parent of the database
|
||||
# all files referenced by get_/set_uuid_for_file will be converted to
|
||||
# relative paths to this parent _path
|
||||
# this allows the entire export tree to be moved to a new disk/location
|
||||
# whilst preserving the UUID to filename mappping
|
||||
self._path = pathlib.Path(dbfile).parent
|
||||
self._conn = self._open_export_db(dbfile)
|
||||
# whilst preserving the UUID to filename mapping
|
||||
self._path = pathlib.Path(self._dbfile).parent
|
||||
self._conn = self._open_export_db(self._dbfile)
|
||||
self._insert_run_info()
|
||||
|
||||
def _open_export_db(self, dbfile):
|
||||
""" open export database and return a db connection
|
||||
returns: connection to the database
|
||||
"""open export database and return a db connection
|
||||
returns: connection to the database
|
||||
"""
|
||||
if not os.path.isfile(dbfile):
|
||||
conn = self._get_db_connection()
|
||||
if conn:
|
||||
self._create_db_tables(conn)
|
||||
self.was_created = True
|
||||
self.was_upgraded = ()
|
||||
self.version = OSXPHOTOS_EXPORTDB_VERSION
|
||||
else:
|
||||
if not conn:
|
||||
raise Exception("Error getting connection to in-memory database")
|
||||
self._create_db_tables(conn)
|
||||
self.was_created = True
|
||||
self.was_upgraded = ()
|
||||
else:
|
||||
try:
|
||||
conn = sqlite3.connect(dbfile)
|
||||
@@ -749,12 +801,11 @@ class ExportDBInMemory(ExportDB):
|
||||
self.was_upgraded = (exportdb_ver, OSXPHOTOS_EXPORTDB_VERSION)
|
||||
else:
|
||||
self.was_upgraded = ()
|
||||
self.version = OSXPHOTOS_EXPORTDB_VERSION
|
||||
|
||||
self.version = OSXPHOTOS_EXPORTDB_VERSION
|
||||
return conn
|
||||
|
||||
def _get_db_connection(self):
|
||||
""" return db connection to in memory database """
|
||||
"""return db connection to in memory database"""
|
||||
try:
|
||||
conn = sqlite3.connect(":memory:")
|
||||
except Error as e:
|
||||
|
||||
@@ -530,6 +530,7 @@ def export2(
|
||||
preview=False,
|
||||
preview_suffix=DEFAULT_PREVIEW_SUFFIX,
|
||||
render_options: Optional[RenderOptions] = None,
|
||||
strip=False,
|
||||
):
|
||||
"""export photo, like export but with update and dry_run options
|
||||
dest: must be valid destination path or exception raised
|
||||
@@ -588,6 +589,7 @@ def export2(
|
||||
preview: if True, also exports preview image
|
||||
preview_suffix: optional string to append to end of filename for preview images
|
||||
render_options: optional osxphotos.phototemplate.RenderOptions instance to specify options for rendering templates
|
||||
strip: if True, strip whitespace from rendered templates
|
||||
|
||||
Returns: ExportResults class
|
||||
ExportResults has attributes:
|
||||
@@ -969,6 +971,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
sidecars.append(
|
||||
(
|
||||
@@ -995,6 +998,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
sidecars.append(
|
||||
(
|
||||
@@ -1017,6 +1021,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
sidecars.append(
|
||||
(
|
||||
@@ -1087,6 +1092,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
)[0]
|
||||
if old_data != current_data:
|
||||
@@ -1110,6 +1116,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
if warning_:
|
||||
all_results.exiftool_warning.append((exported_file, warning_))
|
||||
@@ -1130,6 +1137,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
),
|
||||
)
|
||||
export_db.set_stat_exif_for_file(
|
||||
@@ -1155,6 +1163,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
if warning_:
|
||||
all_results.exiftool_warning.append((exported_file, warning_))
|
||||
@@ -1175,6 +1184,7 @@ def export2(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
),
|
||||
)
|
||||
export_db.set_stat_exif_for_file(
|
||||
@@ -1580,6 +1590,7 @@ def _write_exif_data(
|
||||
persons=True,
|
||||
location=True,
|
||||
replace_keywords=False,
|
||||
strip=False,
|
||||
):
|
||||
"""write exif data to image file at filepath
|
||||
|
||||
@@ -1593,6 +1604,7 @@ def _write_exif_data(
|
||||
persons: if True, write person data to metadata
|
||||
location: if True, write location data to metadata
|
||||
replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive
|
||||
strip: if True, strip any leading or trailing whitespace from rendered templates
|
||||
|
||||
Returns:
|
||||
(warning, error) of warning and error strings if exiftool produces warnings or errors
|
||||
@@ -1610,6 +1622,7 @@ def _write_exif_data(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
|
||||
with ExifTool(filepath, flags=flags, exiftool=self._db._exiftool_path) as exiftool:
|
||||
@@ -1635,6 +1648,7 @@ def _exiftool_dict(
|
||||
persons=True,
|
||||
location=True,
|
||||
replace_keywords=False,
|
||||
strip=False,
|
||||
):
|
||||
"""Return dict of EXIF details for building exiftool JSON sidecar or sending commands to ExifTool.
|
||||
Does not include all the EXIF fields as those are likely already in the image.
|
||||
@@ -1651,6 +1665,7 @@ def _exiftool_dict(
|
||||
persons: if True, include person data
|
||||
location: if True, include location data
|
||||
replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive
|
||||
strip: if True, strip any rendered templates
|
||||
|
||||
Returns: dict with exiftool tags / values
|
||||
|
||||
@@ -1698,6 +1713,8 @@ def _exiftool_dict(
|
||||
)
|
||||
rendered = self.render_template(description_template, options)[0]
|
||||
description = " ".join(rendered) if rendered else ""
|
||||
if strip:
|
||||
description = description.strip()
|
||||
exif["EXIF:ImageDescription"] = description
|
||||
exif["XMP:Description"] = description
|
||||
exif["IPTC:Caption-Abstract"] = description
|
||||
@@ -1745,6 +1762,9 @@ def _exiftool_dict(
|
||||
)
|
||||
rendered_keywords.extend(rendered)
|
||||
|
||||
if strip:
|
||||
rendered_keywords = [keyword.strip() for keyword in rendered_keywords]
|
||||
|
||||
# filter out any template values that didn't match by looking for sentinel
|
||||
rendered_keywords = [
|
||||
keyword
|
||||
@@ -1851,12 +1871,6 @@ def _exiftool_dict(
|
||||
self.date_modified
|
||||
).strftime("%Y:%m:%d %H:%M:%S")
|
||||
|
||||
# remove any new lines in any fields
|
||||
for field, val in exif.items():
|
||||
if type(val) == str:
|
||||
exif[field] = val.replace("\n", " ")
|
||||
elif type(val) == list:
|
||||
exif[field] = [str(v).replace("\n", " ") for v in val if v is not None]
|
||||
return exif
|
||||
|
||||
|
||||
@@ -1909,6 +1923,7 @@ def _exiftool_json_sidecar(
|
||||
persons=True,
|
||||
location=True,
|
||||
replace_keywords=False,
|
||||
strip=False,
|
||||
):
|
||||
"""Return dict of EXIF details for building exiftool JSON sidecar or sending commands to ExifTool.
|
||||
Does not include all the EXIF fields as those are likely already in the image.
|
||||
@@ -1926,6 +1941,7 @@ def _exiftool_json_sidecar(
|
||||
persons: if True, include person data
|
||||
location: if True, include location data
|
||||
replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive
|
||||
strip: if True, strip whitespace from rendered templates
|
||||
|
||||
Returns: dict with exiftool tags / values
|
||||
|
||||
@@ -1965,6 +1981,7 @@ def _exiftool_json_sidecar(
|
||||
persons=persons,
|
||||
location=location,
|
||||
replace_keywords=replace_keywords,
|
||||
strip=strip,
|
||||
)
|
||||
|
||||
if not tag_groups:
|
||||
@@ -1990,6 +2007,7 @@ def _xmp_sidecar(
|
||||
persons=True,
|
||||
location=True,
|
||||
replace_keywords=False,
|
||||
strip=False,
|
||||
):
|
||||
"""returns string for XMP sidecar
|
||||
use_albums_as_keywords: treat album names as keywords
|
||||
@@ -2002,6 +2020,7 @@ def _xmp_sidecar(
|
||||
persons: if True, include person data
|
||||
location: if True, include location data
|
||||
replace_keywords: if True, keyword_template replaces any keywords, otherwise it's additive
|
||||
strip: if True, strip whitespace from rendered templates
|
||||
"""
|
||||
|
||||
xmp_template_file = (
|
||||
@@ -2019,6 +2038,8 @@ def _xmp_sidecar(
|
||||
)
|
||||
rendered = self.render_template(description_template, options)[0]
|
||||
description = " ".join(rendered) if rendered else ""
|
||||
if strip:
|
||||
description = description.strip()
|
||||
else:
|
||||
description = self.description if self.description is not None else ""
|
||||
|
||||
@@ -2060,6 +2081,9 @@ def _xmp_sidecar(
|
||||
)
|
||||
rendered_keywords.extend(rendered)
|
||||
|
||||
if strip:
|
||||
rendered_keywords = [keyword.strip() for keyword in rendered_keywords]
|
||||
|
||||
# filter out any template values that didn't match by looking for sentinel
|
||||
rendered_keywords = [
|
||||
keyword
|
||||
|
||||
@@ -14,6 +14,7 @@ from datetime import timedelta, timezone
|
||||
from typing import Optional
|
||||
|
||||
import yaml
|
||||
from osxmetadata import OSXMetaData
|
||||
|
||||
from .._constants import (
|
||||
_MOVIE_TYPE,
|
||||
@@ -30,12 +31,14 @@ from .._constants import (
|
||||
BURST_KEY,
|
||||
BURST_NOT_SELECTED,
|
||||
BURST_SELECTED,
|
||||
TEXT_DETECTION_CONFIDENCE_THRESHOLD,
|
||||
)
|
||||
from ..adjustmentsinfo import AdjustmentsInfo
|
||||
from ..albuminfo import AlbumInfo, ImportInfo
|
||||
from ..personinfo import FaceInfo, PersonInfo
|
||||
from ..phototemplate import PhotoTemplate, RenderOptions
|
||||
from ..placeinfo import PlaceInfo4, PlaceInfo5
|
||||
from ..text_detection import detect_text
|
||||
from ..uti import get_preferred_uti_extension, get_uti_for_extension
|
||||
from ..utils import _debug, _get_resource_loc, findfiles
|
||||
|
||||
@@ -1106,6 +1109,52 @@ class PhotoInfo:
|
||||
template = PhotoTemplate(self, exiftool_path=self._db._exiftool_path)
|
||||
return template.render(template_str, options)
|
||||
|
||||
def detected_text(self, confidence_threshold=TEXT_DETECTION_CONFIDENCE_THRESHOLD):
|
||||
"""Detects text in photo and returns lists of results as (detected text, confidence)
|
||||
|
||||
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
|
||||
|
||||
If photo is edited, uses the edited photo, otherwise the original; falls back to the preview image if neither edited or original is available
|
||||
|
||||
Returns: list of (detected text, confidence) tuples
|
||||
"""
|
||||
|
||||
try:
|
||||
return self._detected_text_cache[confidence_threshold]
|
||||
except (AttributeError, KeyError) as e:
|
||||
if isinstance(e, AttributeError):
|
||||
self._detected_text_cache = {}
|
||||
|
||||
try:
|
||||
detected_text = self._detected_text()
|
||||
except Exception as e:
|
||||
logging.warning(f"Error detecting text in photo {self.uuid}: {e}")
|
||||
detected_text = []
|
||||
|
||||
self._detected_text_cache[confidence_threshold] = [
|
||||
(text, confidence)
|
||||
for text, confidence in detected_text
|
||||
if confidence >= confidence_threshold
|
||||
]
|
||||
return self._detected_text_cache[confidence_threshold]
|
||||
|
||||
def _detected_text(self):
|
||||
"""detect text in photo, either from cached extended attribute or by attempting text detection"""
|
||||
path = (
|
||||
self.path_edited if self.hasadjustments and self.path_edited else self.path
|
||||
)
|
||||
path = path or self.path_derivatives[0] if self.path_derivatives else None
|
||||
if not path:
|
||||
return []
|
||||
|
||||
md = OSXMetaData(path)
|
||||
detected_text = md.get_attribute("osxphotos_detected_text")
|
||||
if detected_text is None:
|
||||
detected_text = detect_text(path)
|
||||
md.set_attribute("osxphotos_detected_text", detected_text)
|
||||
return detected_text
|
||||
|
||||
@property
|
||||
def _longitude(self):
|
||||
"""Returns longitude, in degrees"""
|
||||
|
||||
@@ -1104,6 +1104,7 @@ class PhotosDB:
|
||||
# get info on special types
|
||||
self._dbphotos[uuid]["specialType"] = row[25]
|
||||
self._dbphotos[uuid]["masterModelID"] = row[26]
|
||||
self._dbphotos[uuid]["pk"] = row[26] # same as masterModelID, to match Photos 5
|
||||
self._dbphotos[uuid]["panorama"] = True if row[25] == 1 else False
|
||||
self._dbphotos[uuid]["slow_mo"] = True if row[25] == 2 else False
|
||||
self._dbphotos[uuid]["time_lapse"] = True if row[25] == 3 else False
|
||||
@@ -1921,7 +1922,8 @@ class PhotosDB:
|
||||
{asset_table}.ZVISIBILITYSTATE,
|
||||
{asset_table}.ZTRASHEDDATE,
|
||||
{asset_table}.ZSAVEDASSETTYPE,
|
||||
{asset_table}.ZADDEDDATE
|
||||
{asset_table}.ZADDEDDATE,
|
||||
{asset_table}.Z_PK
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
ORDER BY {asset_table}.ZUUID """
|
||||
@@ -1970,6 +1972,7 @@ class PhotosDB:
|
||||
# 39 ZGENERICASSET.ZTRASHEDDATE -- date item placed in the trash or null if not in trash
|
||||
# 40 ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported
|
||||
# 41 ZGENERICASSET.ZADDEDDATE -- date item added to the library
|
||||
# 42 ZGENERICASSET.Z_PK -- primary key
|
||||
|
||||
for row in c:
|
||||
uuid = row[0]
|
||||
@@ -2154,6 +2157,8 @@ class PhotosDB:
|
||||
except (ValueError, TypeError):
|
||||
info["added_date"] = datetime(1970, 1, 1)
|
||||
|
||||
info["pk"] = row[42]
|
||||
|
||||
# initialize import session info which will be filled in later
|
||||
# not every photo has an import session so initialize all records now
|
||||
info["import_session"] = None
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
""" Custom template system for osxphotos, implements osxphotos template language (OTL) """
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import shlex
|
||||
@@ -11,11 +13,13 @@ from typing import Optional
|
||||
|
||||
from textx import TextXSyntaxError, metamodel_from_file
|
||||
|
||||
from ._constants import _UNKNOWN_PERSON
|
||||
from ._constants import _UNKNOWN_PERSON, TEXT_DETECTION_CONFIDENCE_THRESHOLD
|
||||
from ._version import __version__
|
||||
from .datetime_formatter import DateTimeFormatter
|
||||
from .exiftool import ExifToolCaching
|
||||
from .export_db import ExportDB_ABC, ExportDBInMemory
|
||||
from .path_utils import sanitize_dirname, sanitize_filename, sanitize_pathpart
|
||||
from .text_detection import detect_text
|
||||
from .utils import expand_and_validate_filepath, load_function
|
||||
|
||||
# TODO: a lot of values are passed from function to function like path_sep--make these all class properties
|
||||
@@ -127,6 +131,29 @@ TEMPLATE_SUBSTITUTIONS = {
|
||||
"{exif.camera_model}": "Camera model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s'",
|
||||
"{exif.lens_model}": "Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'",
|
||||
"{uuid}": "Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'",
|
||||
"{id}": "A unique number for the photo based on its primary key in the Photos database. "
|
||||
+ "A sequential integer, e.g. 1, 2, 3...etc. Each asset associated with a photo (e.g. an image and Live Photo preview) will share the same id. "
|
||||
+ "May be formatted using a python string format code. "
|
||||
+ "For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in "
|
||||
+ "00001, 00002, 00003...etc. ",
|
||||
"{album_seq}": "An integer, starting at 0, indicating the photo's index (sequence) in the containing album. "
|
||||
+ "Only valid when used in a '--filename' template and only when '{album}' or '{folder_album}' is used in the '--directory' template. "
|
||||
+ 'For example \'--directory "{folder_album}" --filename "{album_seq}_{original_name}"\'. '
|
||||
+ "To start counting at a value other than 0, append append a period and the starting value to the field name. "
|
||||
+ "For example, to start counting at 1 instead of 0: '{album_seq.1}'. "
|
||||
+ "May be formatted using a python string format code. "
|
||||
+ "For example, to format as a 5-digit integer and pad with zeros, use '{album_seq:05d}' which results in "
|
||||
+ "00000, 00001, 00002...etc. "
|
||||
+ "This may result in incorrect sequences if you have duplicate albums with the same name; see also '{folder_album_seq}'.",
|
||||
"{folder_album_seq}": "An integer, starting at 0, indicating the photo's index (sequence) in the containing album and folder path. "
|
||||
+ "Only valid when used in a '--filename' template and only when '{folder_album}' is used in the '--directory' template. "
|
||||
+ 'For example \'--directory "{folder_album}" --filename "{folder_album_seq}_{original_name}"\'. '
|
||||
+ "To start counting at a value other than 0, append append a period and the starting value to the field name. "
|
||||
+ "For example, to start counting at 1 instead of 0: '{folder_album_seq.1}' "
|
||||
+ "May be formatted using a python string format code. "
|
||||
+ "For example, to format as a 5-digit integer and pad with zeros, use '{folder_album_seq:05d}' which results in "
|
||||
+ "00000, 00001, 00002...etc. "
|
||||
+ "This may result in incorrect sequences if you have duplicate albums with the same name in the same folder; see also '{album_seq}'.",
|
||||
"{comma}": "A comma: ','",
|
||||
"{semicolon}": "A semicolon: ';'",
|
||||
"{questionmark}": "A question mark: '?'",
|
||||
@@ -174,7 +201,15 @@ TEMPLATE_SUBSTITUTIONS_MULTI_VALUED = {
|
||||
+ "For example: '{photo.favorite}' is the same as '{favorite}' and '{photo.place.name}' is the same as '{place.name}'. "
|
||||
+ "'{photo}' provides access to properties that are not available as separate template fields but it assumes some knowledge of "
|
||||
+ "the underlying PhotoInfo class. See https://rhettbull.github.io/osxphotos/ for additional documentation on the PhotoInfo class.",
|
||||
"{detected_text}": "List of text strings found in the image after performing text detection. "
|
||||
+ "Using '{detected_text}' will cause osxphotos to perform text detection on your photos using the built-in macOS text detection algorithms which will slow down your export. "
|
||||
+ "The results for each photo will be cached in the export database so that future exports with '--update' do not need to reprocess each photo. "
|
||||
+ "You may pass a confidence threshold value between 0.0 and 1.0 after a colon as in '{detected_text:0.5}'; "
|
||||
+ f"The default confidence threshold is {TEXT_DETECTION_CONFIDENCE_THRESHOLD}. "
|
||||
+ "'{detected_text}' works only on macOS Catalina (10.15) or later. "
|
||||
+ "Note: this feature is not the same thing as Live Text in macOS Monterey, which osxphotos does not yet support.",
|
||||
"{shell_quote}": "Use in form '{shell_quote,TEMPLATE}'; quotes the rendered TEMPLATE value(s) for safe usage in the shell, e.g. My file.jpeg => 'My file.jpeg'; only adds quotes if needed.",
|
||||
"{strip}": "Use in form '{strip,TEMPLATE}'; strips whitespace from begining and end of rendered TEMPLATE value(s).",
|
||||
"{function}": "Execute a python function from an external file and use return value as template substitution. "
|
||||
+ "Use in format: {function:file.py::function_name} where 'file.py' is the name of the python file and 'function_name' is the name of the function to call. "
|
||||
+ "The function will be passed the PhotoInfo object for the photo. "
|
||||
@@ -253,6 +288,7 @@ class RenderOptions:
|
||||
dest_path: set to the destination path of the photo (for use by {function} template), only valid with --filename
|
||||
filepath: set to value for filepath of the exported photo if you want to evaluate {filepath} template
|
||||
quote: quote path templates for execution in the shell
|
||||
exportdb: ExportDB object
|
||||
"""
|
||||
|
||||
none_str: str = "_"
|
||||
@@ -267,6 +303,7 @@ class RenderOptions:
|
||||
dest_path: Optional[str] = None
|
||||
filepath: Optional[str] = None
|
||||
quote: bool = False
|
||||
exportdb: Optional[ExportDB_ABC] = None
|
||||
|
||||
|
||||
class PhotoTemplateParser:
|
||||
@@ -293,6 +330,11 @@ class PhotoTemplateParser:
|
||||
"""Parse a template_statement string"""
|
||||
return self.metamodel.model_from_str(template_statement)
|
||||
|
||||
def fields(self, template_statement):
|
||||
"""Return list of fields found in a template statement; does not verify that fields are valid"""
|
||||
model = self.parse(template_statement)
|
||||
return [ts.template.field for ts in model.template_strings if ts.template]
|
||||
|
||||
|
||||
class PhotoTemplate:
|
||||
"""PhotoTemplate class to render a template string from a PhotoInfo object"""
|
||||
@@ -317,6 +359,7 @@ class PhotoTemplate:
|
||||
# initialize render options
|
||||
# this will be done in render() but for testing, some of the lookup functions are called directly
|
||||
options = RenderOptions()
|
||||
self.options = options
|
||||
self.path_sep = options.path_sep
|
||||
self.inplace_sep = options.inplace_sep
|
||||
self.edited_version = options.edited_version
|
||||
@@ -328,6 +371,8 @@ class PhotoTemplate:
|
||||
self.export_dir = options.export_dir
|
||||
self.filepath = options.filepath
|
||||
self.quote = options.quote
|
||||
self.dest_path = options.dest_path
|
||||
self.exportdb = options.exportdb or ExportDBInMemory(None)
|
||||
|
||||
def render(
|
||||
self,
|
||||
@@ -347,6 +392,7 @@ class PhotoTemplate:
|
||||
if type(template) is not str:
|
||||
raise TypeError(f"template must be type str, not {type(template)}")
|
||||
|
||||
self.options = options
|
||||
self.path_sep = options.path_sep
|
||||
self.inplace_sep = options.inplace_sep
|
||||
self.edited_version = options.edited_version
|
||||
@@ -359,7 +405,8 @@ class PhotoTemplate:
|
||||
self.dest_path = options.dest_path
|
||||
self.filepath = options.filepath
|
||||
self.quote = options.quote
|
||||
self.options = options
|
||||
self.dest_path = options.dest_path
|
||||
self.exportdb = options.exportdb or self.exportdb
|
||||
|
||||
try:
|
||||
model = self.parser.parse(template)
|
||||
@@ -487,10 +534,14 @@ class PhotoTemplate:
|
||||
conditional_value = []
|
||||
|
||||
vals = []
|
||||
if field in SINGLE_VALUE_SUBSTITUTIONS:
|
||||
if (
|
||||
field in SINGLE_VALUE_SUBSTITUTIONS
|
||||
or field.split(".")[0] in SINGLE_VALUE_SUBSTITUTIONS
|
||||
):
|
||||
vals = self.get_template_value(
|
||||
field,
|
||||
default=default,
|
||||
subfield=subfield,
|
||||
# delim=delim or self.inplace_sep,
|
||||
# path_sep=path_sep,
|
||||
)
|
||||
@@ -512,7 +563,7 @@ class PhotoTemplate:
|
||||
)
|
||||
elif field in MULTI_VALUE_SUBSTITUTIONS or field.startswith("photo"):
|
||||
vals = self.get_template_value_multi(
|
||||
field, path_sep=path_sep, default=default
|
||||
field, subfield, path_sep=path_sep, default=default
|
||||
)
|
||||
elif field.split(".")[0] in PATHLIB_SUBSTITUTIONS:
|
||||
vals = self.get_template_value_pathlib(field)
|
||||
@@ -524,7 +575,7 @@ class PhotoTemplate:
|
||||
|
||||
if self.expand_inplace or delim is not None:
|
||||
sep = delim if delim is not None else self.inplace_sep
|
||||
vals = [sep.join(sorted(vals))]
|
||||
vals = [sep.join(sorted(vals))] if vals else []
|
||||
|
||||
for filter_ in filters:
|
||||
vals = self.get_template_value_filter(filter_, vals)
|
||||
@@ -565,12 +616,8 @@ class PhotoTemplate:
|
||||
f"comparison operators may only be used with a single value: {vals} {conditional_value}"
|
||||
)
|
||||
try:
|
||||
match = (
|
||||
True
|
||||
if test_function(
|
||||
float(vals[0]), float(conditional_value[0])
|
||||
)
|
||||
else False
|
||||
match = bool(
|
||||
test_function(float(vals[0]), float(conditional_value[0]))
|
||||
)
|
||||
if (match and not negation) or (negation and not match):
|
||||
return ["True"]
|
||||
@@ -645,6 +692,7 @@ class PhotoTemplate:
|
||||
self,
|
||||
field,
|
||||
default,
|
||||
subfield=None,
|
||||
# bool_val=None,
|
||||
# delim=None,
|
||||
# path_sep=None,
|
||||
@@ -657,6 +705,7 @@ class PhotoTemplate:
|
||||
bool_val: True value if expression is boolean
|
||||
delim: delimiter for expand in place
|
||||
path_sep: path separator for fields that are path-like
|
||||
subfield: subfield (value after : in field)
|
||||
|
||||
Returns:
|
||||
The matching template value (which may be None).
|
||||
@@ -668,9 +717,6 @@ class PhotoTemplate:
|
||||
if self.photo.uuid is None:
|
||||
return []
|
||||
|
||||
if field not in FIELD_NAMES:
|
||||
raise ValueError(f"SyntaxError: Unknown field: {field}")
|
||||
|
||||
# initialize today with current date/time if needed
|
||||
if self.today is None:
|
||||
self.today = datetime.datetime.now()
|
||||
@@ -923,6 +969,26 @@ class PhotoTemplate:
|
||||
value = self.photo.exif_info.lens_model if self.photo.exif_info else None
|
||||
elif field == "uuid":
|
||||
value = self.photo.uuid
|
||||
elif field == "id":
|
||||
value = format_str_value(self.photo._info["pk"], subfield)
|
||||
elif field.startswith("album_seq") or field.startswith("folder_album_seq"):
|
||||
dest_path = self.dest_path
|
||||
if not dest_path:
|
||||
value = None
|
||||
else:
|
||||
if field.startswith("album_seq"):
|
||||
album = pathlib.Path(dest_path).name
|
||||
album_info = _get_album_by_name(self.photo, album)
|
||||
else:
|
||||
album_info = _get_album_by_path(self.photo, dest_path)
|
||||
value = album_info.photo_index(self.photo) if album_info else None
|
||||
if value is not None:
|
||||
try:
|
||||
start_id = field.split(".", 1)
|
||||
value = int(value) + int(start_id[1])
|
||||
except IndexError:
|
||||
pass
|
||||
value = format_str_value(value, subfield)
|
||||
elif field in PUNCTUATION:
|
||||
value = PUNCTUATION[field]
|
||||
elif field == "osxphotos_version":
|
||||
@@ -1023,11 +1089,12 @@ class PhotoTemplate:
|
||||
value = []
|
||||
return value
|
||||
|
||||
def get_template_value_multi(self, field, path_sep, default):
|
||||
def get_template_value_multi(self, field, subfield, path_sep, default):
|
||||
"""lookup value for template field (multi-value template substitutions)
|
||||
|
||||
Args:
|
||||
field: template field to find value for.
|
||||
subfield: the template subfield value
|
||||
path_sep: path separator to use for folder_album field
|
||||
default: value of default field
|
||||
|
||||
@@ -1076,12 +1143,10 @@ class PhotoTemplate:
|
||||
folder = path_sep.join(album.folder_names)
|
||||
folder += path_sep + album.title
|
||||
values.append(folder)
|
||||
elif self.dirname:
|
||||
values.append(sanitize_dirname(album.title))
|
||||
else:
|
||||
# album not in folder
|
||||
if self.dirname:
|
||||
values.append(sanitize_dirname(album.title))
|
||||
else:
|
||||
values.append(album.title)
|
||||
values.append(album.title)
|
||||
elif field == "comment":
|
||||
values = [
|
||||
f"{comment.user}: {comment.text}" for comment in self.photo.comments
|
||||
@@ -1098,6 +1163,8 @@ class PhotoTemplate:
|
||||
)
|
||||
elif field == "shell_quote":
|
||||
values = [shlex.quote(v) for v in default if v]
|
||||
elif field == "strip":
|
||||
values = [v.strip() for v in default]
|
||||
elif field.startswith("photo"):
|
||||
# provide access to PhotoInfo object
|
||||
properties = field.split(".")
|
||||
@@ -1124,6 +1191,8 @@ class PhotoTemplate:
|
||||
values = [str(obj)]
|
||||
else:
|
||||
values = [val for val in obj]
|
||||
elif field == "detected_text":
|
||||
values = _get_detected_text(self.photo, self.exportdb, confidence=subfield)
|
||||
else:
|
||||
raise ValueError(f"Unhandled template value: {field}")
|
||||
|
||||
@@ -1336,3 +1405,51 @@ def _get_pathlib_value(field, value, quote):
|
||||
return val_str
|
||||
except AttributeError:
|
||||
raise ValueError("Illegal value for path template: {attribute}")
|
||||
|
||||
|
||||
def format_str_value(value, format_str):
|
||||
"""Format value based on format code in field in format id:02d"""
|
||||
if not format_str:
|
||||
return str(value)
|
||||
format_str = "{0:" + f"{format_str}" + "}"
|
||||
return format_str.format(value)
|
||||
|
||||
|
||||
def _get_album_by_name(photo, album):
|
||||
"""Finds first album named album that photo is in and returns the AlbumInfo object, otherwise returns None"""
|
||||
for album_info in photo.album_info:
|
||||
if album_info.title == album:
|
||||
return album_info
|
||||
return None
|
||||
|
||||
|
||||
def _get_album_by_path(photo, folder_album_path):
|
||||
"""finds the first album whose folder_album path matches and folder_album_path and returns the AlbumInfo object, otherwise, returns None"""
|
||||
|
||||
for album_info in photo.album_info:
|
||||
# following code is how {folder_album} builds the folder path
|
||||
folder = "/".join(sanitize_dirname(f) for f in album_info.folder_names)
|
||||
folder += "/" + sanitize_dirname(album_info.title)
|
||||
if folder_album_path.endswith(folder):
|
||||
return album_info
|
||||
return None
|
||||
|
||||
|
||||
def _get_detected_text(photo, exportdb, confidence=TEXT_DETECTION_CONFIDENCE_THRESHOLD):
|
||||
"""Returns the detected text for a photo
|
||||
{detected_text} uses this instead of PhotoInfo.detected_text() to cache the text for all confidence values
|
||||
"""
|
||||
if not photo.isphoto:
|
||||
return []
|
||||
|
||||
confidence = (
|
||||
float(confidence)
|
||||
if confidence is not None
|
||||
else TEXT_DETECTION_CONFIDENCE_THRESHOLD
|
||||
)
|
||||
|
||||
# _detected_text caches the text detection results in an extended attribute
|
||||
# so the first time this gets called is slow but repeated accesses are fast
|
||||
detected_text = photo._detected_text()
|
||||
exportdb.set_detected_text_for_uuid(photo.uuid, json.dumps(detected_text))
|
||||
return [text for text, conf in detected_text if conf >= confidence]
|
||||
|
||||
75
osxphotos/text_detection.py
Normal file
75
osxphotos/text_detection.py
Normal file
@@ -0,0 +1,75 @@
|
||||
""" Use Apple's Vision Framework via PyObjC to perform text detection on images (macOS 10.15+ only) """
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
import objc
|
||||
import Quartz
|
||||
from Cocoa import NSURL
|
||||
from Foundation import NSDictionary
|
||||
|
||||
# needed to capture system-level stderr
|
||||
from wurlitzer import pipes
|
||||
|
||||
from .utils import _get_os_version
|
||||
|
||||
ver, major, minor = _get_os_version()
|
||||
if ver == "10" and int(major) < 15:
|
||||
vision = False
|
||||
else:
|
||||
import Vision
|
||||
|
||||
vision = True
|
||||
|
||||
|
||||
def detect_text(img_path: str) -> List:
|
||||
"""process image at img_path with VNRecognizeTextRequest and return list of results"""
|
||||
if not vision:
|
||||
logging.warning(f"detect_text not implemented for this version of macOS")
|
||||
return []
|
||||
|
||||
with objc.autorelease_pool():
|
||||
input_url = NSURL.fileURLWithPath_(img_path)
|
||||
|
||||
with pipes() as (out, err):
|
||||
# capture stdout and stderr from system calls
|
||||
# otherwise, Quartz.CIImage.imageWithContentsOfURL_
|
||||
# prints to stderr something like:
|
||||
# 2020-09-20 20:55:25.538 python[73042:5650492] Creating client/daemon connection: B8FE995E-3F27-47F4-9FA8-559C615FD774
|
||||
# 2020-09-20 20:55:25.652 python[73042:5650492] Got the query meta data reply for: com.apple.MobileAsset.RawCamera.Camera, response: 0
|
||||
input_image = Quartz.CIImage.imageWithContentsOfURL_(input_url)
|
||||
|
||||
vision_options = NSDictionary.dictionaryWithDictionary_({})
|
||||
vision_handler = Vision.VNImageRequestHandler.alloc().initWithCIImage_options_(
|
||||
input_image, vision_options
|
||||
)
|
||||
results = []
|
||||
handler = make_request_handler(results)
|
||||
vision_request = (
|
||||
Vision.VNRecognizeTextRequest.alloc().initWithCompletionHandler_(handler)
|
||||
)
|
||||
error = vision_handler.performRequests_error_([vision_request], None)
|
||||
vision_request.dealloc()
|
||||
vision_handler.dealloc()
|
||||
|
||||
for result in results:
|
||||
result[0] = str(result[0])
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def make_request_handler(results):
|
||||
"""results: list to store results"""
|
||||
if not isinstance(results, list):
|
||||
raise ValueError("results must be a list")
|
||||
|
||||
def handler(request, error):
|
||||
if error:
|
||||
print(f"Error! {error}")
|
||||
else:
|
||||
observations = request.results()
|
||||
for text_observation in observations:
|
||||
recognized_text = text_observation.topCandidates_(1)[0]
|
||||
results.append([recognized_text.string(), recognized_text.confidence()])
|
||||
|
||||
return handler
|
||||
@@ -278,15 +278,15 @@ For example, to set Finder comment to the photo's title and description:
|
||||
|
||||
In the template string above, `{newline}` instructs osxphotos to insert a new line character ("\n") between the title and description. In this example, if `{title}` or `{descr}` is empty, you'll get "title\n" or "\ndescription" which may not be desired so you can use more advanced features of the template system to handle these cases:
|
||||
|
||||
`osxphotos export /path/to/export --xattr-template findercomment "{title}{title?{descr?{newline},},}{descr}"`
|
||||
`osxphotos export /path/to/export --xattr-template findercomment "{title,}{title?{descr?{newline},},}{descr,}"`
|
||||
|
||||
Explanation of the template string:
|
||||
|
||||
```txt
|
||||
{title}{title?{descr?{newline},},}{descr}
|
||||
{title,}{title?{descr?{newline},},}{descr,}
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
└──> insert title │ │ │ │ │
|
||||
└──> insert title (or nothing if no title)
|
||||
│ │ │ │ │ │
|
||||
└───> is there a title?
|
||||
│ │ │ │ │
|
||||
@@ -298,7 +298,8 @@ Explanation of the template string:
|
||||
│ │
|
||||
└───> if title is blank, insert nothing
|
||||
│
|
||||
└───> finally, insert description
|
||||
└───> finally, insert description
|
||||
(or nothing if no description)
|
||||
```
|
||||
|
||||
In this example, `title?` demonstrates use of the boolean (True/False) feature of the template system. `title?` is read as "Is the title True (or not blank/empty)? If so, then the value immediately following the `?` is used in place of `title`. If `title` is blank, then the value immediately following the comma is used instead. The format for boolean fields is `field?value if true,value if false`. Either `value if true` or `value if false` may be blank, in which case a blank string ("") is used for the value and both may also be an entirely new template string as seen in the above example. Using this format, template strings may be nested inside each other to form complex `if-then-else` statements.
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
pyobjc-core==7.2
|
||||
pyobjc-framework-AppleScriptKit==7.2
|
||||
pyobjc-framework-AppleScriptObjC==7.2
|
||||
pyobjc-framework-Photos==7.2
|
||||
pyobjc-framework-Quartz==7.2
|
||||
pyobjc-framework-AVFoundation==7.2
|
||||
pyobjc-framework-CoreServices==7.2
|
||||
pyobjc-framework-Metal==7.2
|
||||
pyobjc-core>=7.2
|
||||
pyobjc-framework-AppleScriptKit>=7.2
|
||||
pyobjc-framework-AppleScriptObjC>=7.2
|
||||
pyobjc-framework-Photos>=7.2
|
||||
pyobjc-framework-Quartz>=7.2
|
||||
pyobjc-framework-AVFoundation>=7.2
|
||||
pyobjc-framework-CoreServices>=7.2
|
||||
pyobjc-framework-Metal>=7.2
|
||||
pyobjc-framework-Vision>=7.2
|
||||
Click==8.0.1
|
||||
PyYAML==5.4.1
|
||||
Mako==1.1.4
|
||||
@@ -13,10 +14,10 @@ bpylist2==3.0.2
|
||||
pathvalidate==2.4.1
|
||||
dataclasses==0.7;python_version<'3.7'
|
||||
wurlitzer==2.1.0
|
||||
photoscript==0.1.3
|
||||
photoscript==0.1.4
|
||||
toml==0.10.2
|
||||
osxmetadata==0.99.25
|
||||
osxmetadata==0.99.31
|
||||
textx==2.3.0
|
||||
rich==10.2.2
|
||||
rich==10.6.0
|
||||
bitmath==1.3.3.1
|
||||
more-itertools==8.8.0
|
||||
more-itertools==8.8.0
|
||||
|
||||
6
requirements_dev.txt
Normal file
6
requirements_dev.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
sphinx_click
|
||||
pytest==6.2.4
|
||||
pytest-mock
|
||||
m2r2
|
||||
pyinstaller==4.4
|
||||
|
||||
23
setup.py
23
setup.py
@@ -73,14 +73,15 @@ setup(
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
],
|
||||
install_requires=[
|
||||
"pyobjc-core==7.2",
|
||||
"pyobjc-framework-AppleScriptKit==7.2",
|
||||
"pyobjc-framework-AppleScriptObjC==7.2",
|
||||
"pyobjc-framework-Photos==7.2",
|
||||
"pyobjc-framework-Quartz==7.2",
|
||||
"pyobjc-framework-AVFoundation==7.2",
|
||||
"pyobjc-framework-CoreServices==7.2",
|
||||
"pyobjc-framework-Metal==7.2",
|
||||
"pyobjc-core",
|
||||
"pyobjc-framework-AppleScriptKit",
|
||||
"pyobjc-framework-AppleScriptObjC",
|
||||
"pyobjc-framework-Photos",
|
||||
"pyobjc-framework-Quartz",
|
||||
"pyobjc-framework-AVFoundation",
|
||||
"pyobjc-framework-CoreServices",
|
||||
"pyobjc-framework-Metal",
|
||||
"pyobjc-framework-Vision",
|
||||
"Click==8.0.1",
|
||||
"PyYAML==5.4.1",
|
||||
"Mako==1.1.4",
|
||||
@@ -88,11 +89,11 @@ setup(
|
||||
"pathvalidate==2.4.1",
|
||||
"dataclasses==0.7;python_version<'3.7'",
|
||||
"wurlitzer==2.1.0",
|
||||
"photoscript==0.1.3",
|
||||
"photoscript==0.1.4",
|
||||
"toml==0.10.2",
|
||||
"osxmetadata==0.99.25",
|
||||
"osxmetadata==0.99.31",
|
||||
"textx==2.3.0",
|
||||
"rich==10.2.2",
|
||||
"rich==10.6.0",
|
||||
"bitmath==1.3.3.1",
|
||||
"more-itertools==8.8.0",
|
||||
],
|
||||
|
||||
@@ -234,6 +234,11 @@ UUID_NOT_REFERENCE = "F12384F6-CD17-4151-ACBA-AE0E3688539E"
|
||||
|
||||
UUID_DUPLICATE = ""
|
||||
|
||||
UUID_DETECTED_TEXT = {
|
||||
"E2078879-A29C-4D6F-BACB-E3BBE6C3EB91": "osxphotos",
|
||||
"A92D9C26-3A50-4197-9388-CB5F7DB9FA91": None,
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def photosdb():
|
||||
@@ -1371,12 +1376,12 @@ def test_no_adjustments(photosdb):
|
||||
|
||||
|
||||
def test_exiftool_newlines_in_description(photosdb):
|
||||
"""Test that exiftool code removes newlines embedded in description, issue #393"""
|
||||
"""Test that exiftool handles newlines embedded in description, issue #393"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["description_newlines"])
|
||||
exif = photo._exiftool_dict()
|
||||
assert photo.description.find("\n") > 0
|
||||
assert exif["EXIF:ImageDescription"].find("\n") == -1
|
||||
assert exif["EXIF:ImageDescription"].find("\n") > 0
|
||||
|
||||
|
||||
@pytest.mark.skip(SKIP_TEST, reason="Not yet implemented")
|
||||
@@ -1423,3 +1428,14 @@ def test_multi_uuid(photosdb):
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["favorite"], UUID_DICT["not_favorite"]])
|
||||
|
||||
assert len(photos) == 2
|
||||
|
||||
|
||||
def test_detected_text(photosdb):
|
||||
"""test PhotoInfo.detected_text"""
|
||||
for uuid, expected_text in UUID_DETECTED_TEXT.items():
|
||||
photo = photosdb.get_photo(uuid=uuid)
|
||||
detected_text = " ".join(text for text, conf in photo.detected_text())
|
||||
if expected_text is not None:
|
||||
assert expected_text in detected_text
|
||||
else:
|
||||
assert not detected_text
|
||||
|
||||
@@ -778,6 +778,27 @@ UUID_DICT_MISSING = {
|
||||
"D79B8D77-BFFC-460B-9312-034F2877D35B": "Pumkins2.jpg", # not missing
|
||||
}
|
||||
|
||||
UUID_DICT_FOLDER_ALBUM_SEQ = {
|
||||
"7783E8E6-9CAC-40F3-BE22-81FB7051C266": {
|
||||
"directory": "{folder_album}",
|
||||
"album": "Sorted Oldest First",
|
||||
"filename": "{album?{folder_album_seq.1}_,}{original_name}",
|
||||
"result": "3_IMG_3092.heic",
|
||||
},
|
||||
"3DD2C897-F19E-4CA6-8C22-B027D5A71907": {
|
||||
"directory": "{album}",
|
||||
"album": "Sorted Oldest First",
|
||||
"filename": "{album?{album_seq}_,}{original_name}",
|
||||
"result": "0_IMG_4547.jpg",
|
||||
},
|
||||
}
|
||||
|
||||
UUID_EMPTY_TITLE = "7783E8E6-9CAC-40F3-BE22-81FB7051C266" # IMG_3092.heic
|
||||
FILENAME_EMPTY_TITLE = "IMG_3092.heic"
|
||||
DESCRIPTION_TEMPLATE_EMPTY_TITLE = "{title,No Title} and {descr,No Descr}"
|
||||
DESCRIPTION_VALUE_EMPTY_TITLE = "No Title and No Descr"
|
||||
DESCRIPTION_TEMPLATE_TITLE_CONDITIONAL = "{title?true,false}"
|
||||
DESCRIPTION_VALUE_TITLE_CONDITIONAL = "false"
|
||||
|
||||
def modify_file(filename):
|
||||
"""appends data to a file to modify it"""
|
||||
@@ -7070,3 +7091,112 @@ def test_export_query_function():
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "exported: 1" in result.output
|
||||
|
||||
|
||||
def test_export_album_seq():
|
||||
"""Test {album_seq} template"""
|
||||
import glob
|
||||
from osxphotos.cli import cli
|
||||
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
# pylint: disable=not-context-manager
|
||||
with runner.isolated_filesystem():
|
||||
for uuid in UUID_DICT_FOLDER_ALBUM_SEQ:
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"export",
|
||||
"--db",
|
||||
os.path.join(cwd, PHOTOS_DB_15_7),
|
||||
".",
|
||||
"-V",
|
||||
"--album",
|
||||
UUID_DICT_FOLDER_ALBUM_SEQ[uuid]["album"],
|
||||
"--directory",
|
||||
UUID_DICT_FOLDER_ALBUM_SEQ[uuid]["directory"],
|
||||
"--filename",
|
||||
UUID_DICT_FOLDER_ALBUM_SEQ[uuid]["filename"],
|
||||
"--uuid",
|
||||
uuid,
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
files = glob.glob(f"{UUID_DICT_FOLDER_ALBUM_SEQ[uuid]['album']}/*")
|
||||
assert (
|
||||
f"{UUID_DICT_FOLDER_ALBUM_SEQ[uuid]['album']}/{UUID_DICT_FOLDER_ALBUM_SEQ[uuid]['result']}"
|
||||
in files
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(exiftool is None, reason="exiftool not installed")
|
||||
def test_export_description_template():
|
||||
"""Test for issue #506"""
|
||||
import json
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import osxphotos
|
||||
from osxphotos.cli import cli
|
||||
from osxphotos.exiftool import ExifTool
|
||||
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
# pylint: disable=not-context-manager
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"export",
|
||||
"--db",
|
||||
os.path.join(cwd, PHOTOS_DB_15_7),
|
||||
".",
|
||||
"--sidecar=json",
|
||||
f"--uuid={UUID_EMPTY_TITLE}",
|
||||
"-V",
|
||||
"--description-template",
|
||||
DESCRIPTION_TEMPLATE_EMPTY_TITLE,
|
||||
"--exiftool"
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
exif = ExifTool(FILENAME_EMPTY_TITLE).asdict()
|
||||
assert exif["EXIF:ImageDescription"] == DESCRIPTION_VALUE_EMPTY_TITLE
|
||||
|
||||
def test_export_description_template_conditional():
|
||||
"""Test for issue #506"""
|
||||
import json
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import osxphotos
|
||||
from osxphotos.cli import cli
|
||||
from osxphotos.exiftool import ExifTool
|
||||
import json
|
||||
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
# pylint: disable=not-context-manager
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"export",
|
||||
"--db",
|
||||
os.path.join(cwd, PHOTOS_DB_15_7),
|
||||
".",
|
||||
"--sidecar=json",
|
||||
f"--uuid={UUID_EMPTY_TITLE}",
|
||||
"-V",
|
||||
"--description-template",
|
||||
DESCRIPTION_TEMPLATE_TITLE_CONDITIONAL,
|
||||
"--sidecar",
|
||||
"JSON"
|
||||
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
with open(f"{FILENAME_EMPTY_TITLE}.json","r") as fp:
|
||||
json_got = json.load(fp)[0]
|
||||
assert json_got["EXIF:ImageDescription"] == DESCRIPTION_VALUE_TITLE_CONDITIONAL
|
||||
|
||||
|
||||
@@ -141,6 +141,44 @@ def test_setvalue_1():
|
||||
assert exif.data["IPTC:Keywords"] == "test"
|
||||
|
||||
|
||||
def test_setvalue_multiline():
|
||||
# test setting a tag value with embedded newline
|
||||
import os.path
|
||||
import tempfile
|
||||
import osxphotos.exiftool
|
||||
from osxphotos.fileutil import FileUtil
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
tempfile = os.path.join(tempdir.name, os.path.basename(TEST_FILE_ONE_KEYWORD))
|
||||
FileUtil.copy(TEST_FILE_ONE_KEYWORD, tempfile)
|
||||
|
||||
exif = osxphotos.exiftool.ExifTool(tempfile)
|
||||
exif.setvalue("EXIF:ImageDescription", "multi\nline")
|
||||
assert not exif.error
|
||||
|
||||
exif._read_exif()
|
||||
assert exif.data["EXIF:ImageDescription"] == "multi\nline"
|
||||
|
||||
|
||||
def test_setvalue_non_alphanumeric_chars():
|
||||
# test setting a tag value non-alphanumeric characters
|
||||
import os.path
|
||||
import tempfile
|
||||
import osxphotos.exiftool
|
||||
from osxphotos.fileutil import FileUtil
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
tempfile = os.path.join(tempdir.name, os.path.basename(TEST_FILE_ONE_KEYWORD))
|
||||
FileUtil.copy(TEST_FILE_ONE_KEYWORD, tempfile)
|
||||
|
||||
exif = osxphotos.exiftool.ExifTool(tempfile)
|
||||
exif.setvalue("EXIF:ImageDescription", "<hello>{world}$bye#foo%bar")
|
||||
assert not exif.error
|
||||
|
||||
exif._read_exif()
|
||||
assert exif.data["EXIF:ImageDescription"] == "<hello>{world}$bye#foo%bar"
|
||||
|
||||
|
||||
def test_setvalue_warning():
|
||||
# test setting illegal tag value generates warning
|
||||
import os.path
|
||||
@@ -311,6 +349,45 @@ def test_addvalues_2():
|
||||
assert sorted(exif.data["IPTC:Keywords"]) == sorted(test_multi)
|
||||
|
||||
|
||||
def test_addvalues_non_alphanumeric_multiline():
|
||||
# test setting a tag value
|
||||
import os.path
|
||||
import tempfile
|
||||
import osxphotos.exiftool
|
||||
from osxphotos.fileutil import FileUtil
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
tempfile = os.path.join(tempdir.name, os.path.basename(TEST_FILE_ONE_KEYWORD))
|
||||
FileUtil.copy(TEST_FILE_ONE_KEYWORD, tempfile)
|
||||
|
||||
exif = osxphotos.exiftool.ExifTool(tempfile)
|
||||
exif.addvalues("IPTC:Keywords", "multi\nline", "<Foo>\t{bar}")
|
||||
assert not exif.error
|
||||
exif._read_exif()
|
||||
assert sorted(exif.data["IPTC:Keywords"]) == sorted(
|
||||
["wedding", "multi\nline", "<Foo>\t{bar}"]
|
||||
)
|
||||
|
||||
|
||||
def test_addvalues_unicode():
|
||||
# test setting a tag value with unicode
|
||||
import os.path
|
||||
import tempfile
|
||||
import osxphotos.exiftool
|
||||
from osxphotos.fileutil import FileUtil
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
tempfile = os.path.join(tempdir.name, os.path.basename(TEST_FILE_ONE_KEYWORD))
|
||||
FileUtil.copy(TEST_FILE_ONE_KEYWORD, tempfile)
|
||||
|
||||
exif = osxphotos.exiftool.ExifTool(tempfile)
|
||||
exif.setvalue("IPTC:Keywords", None)
|
||||
exif.addvalues("IPTC:Keywords", "ǂ", "Ƕ")
|
||||
assert not exif.error
|
||||
exif._read_exif()
|
||||
assert sorted(exif.data["IPTC:Keywords"]) == sorted(["ǂ", "Ƕ"])
|
||||
|
||||
|
||||
def test_singleton():
|
||||
import osxphotos.exiftool
|
||||
|
||||
@@ -384,7 +461,7 @@ def test_str():
|
||||
|
||||
|
||||
def test_photoinfo_exiftool():
|
||||
""" test PhotoInfo.exiftool which returns ExifTool object for photo """
|
||||
"""test PhotoInfo.exiftool which returns ExifTool object for photo"""
|
||||
import osxphotos
|
||||
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
@@ -397,7 +474,7 @@ def test_photoinfo_exiftool():
|
||||
|
||||
|
||||
def test_photoinfo_exiftool_no_groups():
|
||||
""" test PhotoInfo.exiftool which returns ExifTool object for photo without tag group names"""
|
||||
"""test PhotoInfo.exiftool which returns ExifTool object for photo without tag group names"""
|
||||
import osxphotos
|
||||
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
@@ -420,7 +497,7 @@ def test_photoinfo_exiftool_none():
|
||||
|
||||
|
||||
def test_exiftool_terminate():
|
||||
""" Test that exiftool process is terminated when exiftool.terminate() is called """
|
||||
"""Test that exiftool process is terminated when exiftool.terminate() is called"""
|
||||
import osxphotos.exiftool
|
||||
import subprocess
|
||||
|
||||
@@ -435,7 +512,7 @@ def test_exiftool_terminate():
|
||||
ps = subprocess.run(["ps"], capture_output=True)
|
||||
stdout = ps.stdout.decode("utf-8")
|
||||
assert "exiftool -stay_open" not in stdout
|
||||
|
||||
|
||||
# verify we can create a new instance after termination
|
||||
exif2 = osxphotos.exiftool.ExifTool(TEST_FILE_ONE_KEYWORD)
|
||||
assert exif2.asdict()["IPTC:Keywords"] == "wedding"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
""" Test ExportDB """
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
EXIF_DATA = """[{"_CreatedBy": "osxphotos, https://github.com/RhetTbull/osxphotos", "EXIF:ImageDescription": "\u2068Elder Park\u2069, \u2068Adelaide\u2069, \u2068Australia\u2069", "XMP:Description": "\u2068Elder Park\u2069, \u2068Adelaide\u2069, \u2068Australia\u2069", "XMP:Title": "Elder Park", "EXIF:GPSLatitude": "34 deg 55' 8.01\" S", "EXIF:GPSLongitude": "138 deg 35' 48.70\" E", "Composite:GPSPosition": "34 deg 55' 8.01\" S, 138 deg 35' 48.70\" E", "EXIF:GPSLatitudeRef": "South", "EXIF:GPSLongitudeRef": "East", "EXIF:DateTimeOriginal": "2017:06:20 17:18:56", "EXIF:OffsetTimeOriginal": "+09:30", "EXIF:ModifyDate": "2020:05:18 14:42:04"}]"""
|
||||
@@ -12,10 +14,11 @@ DATABASE_VERSION1 = "tests/export_db_version1.db"
|
||||
|
||||
|
||||
def test_export_db():
|
||||
""" test ExportDB """
|
||||
"""test ExportDB"""
|
||||
import os
|
||||
import tempfile
|
||||
from osxphotos.export_db import ExportDB, OSXPHOTOS_EXPORTDB_VERSION
|
||||
|
||||
from osxphotos.export_db import OSXPHOTOS_EXPORTDB_VERSION, ExportDB
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
dbname = os.path.join(tempdir.name, ".osxphotos_export.db")
|
||||
@@ -47,6 +50,9 @@ def test_export_db():
|
||||
assert db.get_sidecar_for_file(filepath) == (SIDECAR_DATA, (13, 14, 15))
|
||||
assert db.get_previous_uuids() == ["FOO-BAR"]
|
||||
|
||||
db.set_detected_text_for_uuid("FOO-BAR", json.dumps([["foo", 0.5]]))
|
||||
assert json.loads(db.get_detected_text_for_uuid("FOO-BAR")) == [["foo", 0.5]]
|
||||
|
||||
# test set_data which sets all at the same time
|
||||
filepath2 = os.path.join(tempdir.name, "test2.jpg")
|
||||
db.set_data(
|
||||
@@ -80,6 +86,7 @@ def test_export_db():
|
||||
assert db.get_stat_converted_for_file(filepath2) == (7, 8, 9)
|
||||
assert db.get_stat_edited_for_file(filepath2) == (10, 11, 12)
|
||||
assert sorted(db.get_previous_uuids()) == (["BAR-FOO", "FOO-BAR"])
|
||||
assert json.loads(db.get_detected_text_for_uuid("FOO-BAR")) == [["foo", 0.5]]
|
||||
|
||||
# update data
|
||||
db.set_uuid_for_file(filepath, "FUBAR")
|
||||
@@ -88,10 +95,11 @@ def test_export_db():
|
||||
|
||||
|
||||
def test_export_db_no_op():
|
||||
""" test ExportDBNoOp """
|
||||
"""test ExportDBNoOp"""
|
||||
import os
|
||||
import tempfile
|
||||
from osxphotos.export_db import ExportDBNoOp, OSXPHOTOS_EXPORTDB_VERSION
|
||||
|
||||
from osxphotos.export_db import OSXPHOTOS_EXPORTDB_VERSION, ExportDBNoOp
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
db = ExportDBNoOp()
|
||||
@@ -121,6 +129,9 @@ def test_export_db_no_op():
|
||||
assert db.get_sidecar_for_file(filepath) == (None, (None, None, None))
|
||||
assert db.get_previous_uuids() == []
|
||||
|
||||
db.set_detected_text_for_uuid("FOO-BAR", json.dumps([["foo", 0.5]]))
|
||||
assert db.get_detected_text_for_uuid("FOO-BAR") is None
|
||||
|
||||
# test set_data which sets all at the same time
|
||||
filepath2 = os.path.join(tempdir.name, "test2.jpg")
|
||||
db.set_data(
|
||||
@@ -148,13 +159,14 @@ def test_export_db_no_op():
|
||||
|
||||
|
||||
def test_export_db_in_memory():
|
||||
""" test ExportDBInMemory """
|
||||
"""test ExportDBInMemory"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from osxphotos.export_db import (
|
||||
OSXPHOTOS_EXPORTDB_VERSION,
|
||||
ExportDB,
|
||||
ExportDBInMemory,
|
||||
OSXPHOTOS_EXPORTDB_VERSION,
|
||||
)
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
@@ -174,6 +186,7 @@ def test_export_db_in_memory():
|
||||
db.set_stat_edited_for_file(filepath, (10, 11, 12))
|
||||
db.set_sidecar_for_file(filepath, SIDECAR_DATA, (13, 14, 15))
|
||||
assert db.get_previous_uuids() == ["FOO-BAR"]
|
||||
db.set_detected_text_for_uuid("FOO-BAR", json.dumps([["foo", 0.5]]))
|
||||
|
||||
db.close()
|
||||
|
||||
@@ -192,6 +205,7 @@ def test_export_db_in_memory():
|
||||
assert dbram.get_stat_edited_for_file(filepath) == (10, 11, 12)
|
||||
assert dbram.get_sidecar_for_file(filepath) == (SIDECAR_DATA, (13, 14, 15))
|
||||
assert dbram.get_previous_uuids() == ["FOO-BAR"]
|
||||
assert json.loads(dbram.get_detected_text_for_uuid("FOO-BAR")) == [["foo", 0.5]]
|
||||
|
||||
# change a value
|
||||
dbram.set_uuid_for_file(filepath, "FUBAR")
|
||||
@@ -202,6 +216,7 @@ def test_export_db_in_memory():
|
||||
dbram.set_stat_converted_for_file(filepath, (1, 2, 3))
|
||||
dbram.set_stat_edited_for_file(filepath, (4, 5, 6))
|
||||
dbram.set_sidecar_for_file(filepath, "FUBAR", (20, 21, 22))
|
||||
dbram.set_detected_text_for_uuid("FUBAR", json.dumps([["bar", 0.5]]))
|
||||
|
||||
assert dbram.get_uuid_for_file(filepath_lower) == "FUBAR"
|
||||
assert dbram.get_info_for_uuid("FUBAR") == INFO_DATA2
|
||||
@@ -212,6 +227,7 @@ def test_export_db_in_memory():
|
||||
assert dbram.get_stat_edited_for_file(filepath) == (4, 5, 6)
|
||||
assert dbram.get_sidecar_for_file(filepath) == ("FUBAR", (20, 21, 22))
|
||||
assert dbram.get_previous_uuids() == ["FUBAR"]
|
||||
assert json.loads(dbram.get_detected_text_for_uuid("FUBAR")) == [["bar", 0.5]]
|
||||
|
||||
dbram.close()
|
||||
|
||||
@@ -228,13 +244,15 @@ def test_export_db_in_memory():
|
||||
assert db.get_previous_uuids() == ["FOO-BAR"]
|
||||
|
||||
assert db.get_info_for_uuid("FUBAR") is None
|
||||
assert db.get_detected_text_for_uuid("FUBAR") is None
|
||||
|
||||
|
||||
def test_export_db_in_memory_nofile():
|
||||
""" test ExportDBInMemory with no dbfile """
|
||||
"""test ExportDBInMemory with no dbfile"""
|
||||
import os
|
||||
import tempfile
|
||||
from osxphotos.export_db import ExportDBInMemory, OSXPHOTOS_EXPORTDB_VERSION
|
||||
|
||||
from osxphotos.export_db import OSXPHOTOS_EXPORTDB_VERSION, ExportDBInMemory
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
|
||||
filepath = os.path.join(tempdir.name, "test.JPG")
|
||||
@@ -254,6 +272,7 @@ def test_export_db_in_memory_nofile():
|
||||
dbram.set_stat_converted_for_file(filepath, (1, 2, 3))
|
||||
dbram.set_stat_edited_for_file(filepath, (4, 5, 6))
|
||||
dbram.set_sidecar_for_file(filepath, "FUBAR", (20, 21, 22))
|
||||
dbram.set_detected_text_for_uuid("FUBAR", json.dumps([["bar", 0.5]]))
|
||||
|
||||
assert dbram.get_uuid_for_file(filepath_lower) == "FUBAR"
|
||||
assert dbram.get_info_for_uuid("FUBAR") == INFO_DATA2
|
||||
@@ -264,5 +283,6 @@ def test_export_db_in_memory_nofile():
|
||||
assert dbram.get_stat_edited_for_file(filepath) == (4, 5, 6)
|
||||
assert dbram.get_sidecar_for_file(filepath) == ("FUBAR", (20, 21, 22))
|
||||
assert dbram.get_previous_uuids() == ["FUBAR"]
|
||||
|
||||
assert json.loads(dbram.get_detected_text_for_uuid("FUBAR")) == [["bar", 0.5]]
|
||||
|
||||
dbram.close()
|
||||
|
||||
@@ -1346,12 +1346,12 @@ def test_no_adjustments(photosdb):
|
||||
|
||||
|
||||
def test_exiftool_newlines_in_description(photosdb):
|
||||
"""Test that exiftool code removes newlines embedded in description, issue #393"""
|
||||
"""Test that exiftool handles newlines embedded in description, issue #393"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["description_newlines"])
|
||||
exif = photo._exiftool_dict()
|
||||
assert photo.description.find("\n") > 0
|
||||
assert exif["EXIF:ImageDescription"].find("\n") == -1
|
||||
assert exif["EXIF:ImageDescription"].find("\n") > 0
|
||||
|
||||
|
||||
@pytest.mark.skip(SKIP_TEST, reason="Not yet implemented")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
""" Test template.py """
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -7,6 +8,7 @@ from photoinfo_mock import PhotoInfoMock
|
||||
|
||||
import osxphotos
|
||||
from osxphotos.exiftool import get_exiftool_path
|
||||
from osxphotos.export_db import ExportDBInMemory
|
||||
from osxphotos.phototemplate import (
|
||||
TEMPLATE_SUBSTITUTIONS,
|
||||
TEMPLATE_SUBSTITUTIONS_MULTI_VALUED,
|
||||
@@ -262,6 +264,11 @@ TEMPLATE_VALUES_DATE_NOT_MODIFIED = {
|
||||
"{modified.strftime,%Y-%m-%d-%H%M%S}": "2020-02-04-190738",
|
||||
}
|
||||
|
||||
UUID_DETECTED_TEXT = "E2078879-A29C-4D6F-BACB-E3BBE6C3EB91"
|
||||
TEMPLATE_VALUES_DETECTED_TEXT = {
|
||||
"{detected_text}": "osxphotos",
|
||||
"{;+detected_text:0.5}": "osxphotos;",
|
||||
}
|
||||
|
||||
COMMENT_UUID_DICT = {
|
||||
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||
@@ -343,6 +350,62 @@ UUID_CONDITIONAL = {
|
||||
},
|
||||
}
|
||||
|
||||
UUID_ALBUM_SEQ = {
|
||||
"7783E8E6-9CAC-40F3-BE22-81FB7051C266": {
|
||||
"album": "/Sorted Manual",
|
||||
"templates": {
|
||||
"{album_seq}": "0",
|
||||
"{album_seq:02d}": "00",
|
||||
"{album_seq.1}": "1",
|
||||
"{album_seq.1:03d}": "001",
|
||||
"{folder_album_seq}": "0",
|
||||
"{folder_album_seq:02d}": "00",
|
||||
"{folder_album_seq.1}": "1",
|
||||
"{folder_album_seq.1:03d}": "001",
|
||||
},
|
||||
},
|
||||
"F12384F6-CD17-4151-ACBA-AE0E3688539E": {
|
||||
"album": "/Sorted Manual",
|
||||
"templates": {
|
||||
"{album_seq}": "2",
|
||||
"{album_seq:02d}": "02",
|
||||
"{album_seq.1}": "3",
|
||||
"{album_seq.1:03d}": "003",
|
||||
"{folder_album_seq}": "2",
|
||||
"{folder_album_seq:02d}": "02",
|
||||
"{folder_album_seq.1}": "3",
|
||||
"{folder_album_seq.1:03d}": "003",
|
||||
},
|
||||
},
|
||||
"E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51": {
|
||||
"album": "/Folder1/SubFolder2/AlbumInFolder",
|
||||
"templates": {
|
||||
"{album_seq}": "1",
|
||||
"{album_seq:02d}": "01",
|
||||
"{album_seq.1}": "2",
|
||||
"{album_seq.1:03d}": "002",
|
||||
"{folder_album_seq}": "1",
|
||||
"{folder_album_seq:02d}": "01",
|
||||
"{folder_album_seq.1}": "2",
|
||||
"{folder_album_seq.0}": "1",
|
||||
"{folder_album_seq.1:03d}": "002",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
UUID_EMPTY_TITLE = "7783E8E6-9CAC-40F3-BE22-81FB7051C266" # IMG_3092.heic
|
||||
UUID_EMPTY_TITLE_HAS_DESCRIPTION = "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51" # wedding.jpg
|
||||
|
||||
TEMPLATE_VALUES_EMPTY_TITLE = {
|
||||
"{title,No Title} and {descr,No Descr}": "No Title and No Descr",
|
||||
"{title?true,false}": "false",
|
||||
}
|
||||
|
||||
TEMPLATE_VALUES_EMPTY_TITLE_HAS_DESCRIPTION = {
|
||||
"{title,} {descr} ": " Bride Wedding day ",
|
||||
"{strip,{title,} {descr} }": "Bride Wedding day",
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def photosdb_places():
|
||||
@@ -391,7 +454,10 @@ def test_lookup_multi(photosdb_places):
|
||||
if subst in ["{exiftool}", "{photo}", "{function}"]:
|
||||
continue
|
||||
lookup = template.get_template_value_multi(
|
||||
lookup_str, path_sep=os.path.sep, default=[]
|
||||
lookup_str,
|
||||
path_sep=os.path.sep,
|
||||
default=[],
|
||||
subfield=None,
|
||||
)
|
||||
assert isinstance(lookup, list)
|
||||
|
||||
@@ -1095,3 +1161,50 @@ def test_filepath():
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
rendered, _ = template.render("{filepath.foo}", options)
|
||||
|
||||
|
||||
def test_id(photosdb):
|
||||
"""Test {id} template"""
|
||||
photo = photosdb.get_photo(UUID_MULTI_KEYWORDS)
|
||||
rendered, _ = photo.render_template("{id}")
|
||||
assert rendered[0] == "7"
|
||||
|
||||
rendered, _ = photo.render_template("{id:03d}")
|
||||
assert rendered[0] == "007"
|
||||
|
||||
|
||||
def test_album_seq(photosdb):
|
||||
"""Test {album_seq} and {folder_album_seq} templates"""
|
||||
from osxphotos.phototemplate import RenderOptions
|
||||
|
||||
for uuid in UUID_ALBUM_SEQ:
|
||||
photo = photosdb.get_photo(uuid)
|
||||
album = UUID_ALBUM_SEQ[uuid]["album"]
|
||||
options = RenderOptions(dest_path=album)
|
||||
for template, value in UUID_ALBUM_SEQ[uuid]["templates"].items():
|
||||
rendered, _ = photo.render_template(template, options=options)
|
||||
assert rendered[0] == value
|
||||
|
||||
|
||||
def test_detected_text(photosdb):
|
||||
"""Test {detected_text} template"""
|
||||
photo = photosdb.get_photo(UUID_DETECTED_TEXT)
|
||||
for template, value in TEMPLATE_VALUES_DETECTED_TEXT.items():
|
||||
rendered, _ = photo.render_template(template)
|
||||
assert value in "".join(rendered)
|
||||
|
||||
|
||||
def test_empty_title(photosdb):
|
||||
"""Test for issue #506"""
|
||||
photo = photosdb.get_photo(UUID_EMPTY_TITLE)
|
||||
for template, value in TEMPLATE_VALUES_EMPTY_TITLE.items():
|
||||
rendered, _ = photo.render_template(template)
|
||||
assert value in "".join(rendered)
|
||||
|
||||
|
||||
def test_strip(photosdb):
|
||||
"""Test {strip} template"""
|
||||
photo = photosdb.get_photo(UUID_EMPTY_TITLE_HAS_DESCRIPTION)
|
||||
for template, value in TEMPLATE_VALUES_EMPTY_TITLE_HAS_DESCRIPTION.items():
|
||||
rendered, _ = photo.render_template(template)
|
||||
assert value in "".join(rendered)
|
||||
|
||||
Reference in New Issue
Block a user