Added support for projects, implements #559
46
README.md
@ -14,7 +14,7 @@ OSXPhotos provides the ability to interact with and query Apple's Photos.app lib
|
||||
|
||||
# Table of Contents
|
||||
* [Supported operating systems](#supported-operating-systems)
|
||||
* [Installation instructions](#installation-instructions)
|
||||
* [Installation](#installation)
|
||||
* [Command Line Usage](#command-line-usage)
|
||||
+ [Command line examples](#command-line-examples)
|
||||
+ [Tutorial](#tutorial)
|
||||
@ -25,6 +25,7 @@ OSXPhotos provides the ability to interact with and query Apple's Photos.app lib
|
||||
+ [ExifInfo](#exifinfo)
|
||||
+ [AlbumInfo](#albuminfo)
|
||||
+ [ImportInfo](#importinfo)
|
||||
+ [ProjectInfo](#projectinfo)
|
||||
+ [FolderInfo](#folderinfo)
|
||||
+ [PlaceInfo](#placeinfo)
|
||||
+ [ScoreInfo](#scoreinfo)
|
||||
@ -1714,7 +1715,7 @@ Substitution Description
|
||||
{lf} A line feed: '\n', alias for {newline}
|
||||
{cr} A carriage return: '\r'
|
||||
{crlf} a carriage return + line feed: '\r\n'
|
||||
{osxphotos_version} The osxphotos version, e.g. '0.43.9'
|
||||
{osxphotos_version} The osxphotos version, e.g. '0.44.0'
|
||||
{osxphotos_cmd_line} The full command line used to run osxphotos
|
||||
|
||||
The following substitutions may result in multiple values. Thus if specified for
|
||||
@ -1729,6 +1730,13 @@ Substitution Description
|
||||
{folder_album} Folder path + album photo is contained in. e.g.
|
||||
'Folder/Subfolder/Album' or just 'Album' if no
|
||||
enclosing folder
|
||||
{project} Project(s) photo is contained in (such as greeting
|
||||
cards, calendars, slideshows)
|
||||
{album_project} Album(s) and project(s) photo is contained in; treats
|
||||
projects as regular albums
|
||||
{folder_album_project} Folder path + album (includes projects as albums)
|
||||
photo is contained in. e.g. 'Folder/Subfolder/Album'
|
||||
or just 'Album' if no enclosing folder
|
||||
{keyword} Keyword(s) assigned to photo
|
||||
{person} Person(s) / face(s) in a photo
|
||||
{label} Image categorization label associated with a photo
|
||||
@ -2103,7 +2111,7 @@ keywords = photosdb.keywords
|
||||
|
||||
Returns a list of the keywords found in the Photos library
|
||||
|
||||
#### `album_info`
|
||||
#### <a name="photosdbalbuminfo">`album_info`</a>
|
||||
```python
|
||||
# assumes photosdb is a PhotosDB object (see above)
|
||||
albums = photosdb.album_info
|
||||
@ -2133,6 +2141,10 @@ Returns list of shared album names found in photos database (e.g. albums shared
|
||||
|
||||
Returns a list of [ImportInfo](#importinfo) objects representing the import sessions for the database.
|
||||
|
||||
#### `project_info`
|
||||
|
||||
Returns a list of [ProjectInfo](#projectinfo) objects representing the projects/creations (cards, calendars, etc.) in the database.
|
||||
|
||||
#### `folder_info`
|
||||
```python
|
||||
# assumes photosdb is a PhotosDB object (see above)
|
||||
@ -2422,11 +2434,15 @@ Returns a list of keywords (e.g. tags) applied to the photo
|
||||
Returns a list of albums the photo is contained in. See also [album_info](#album_info).
|
||||
|
||||
#### `album_info`
|
||||
Returns a list of [AlbumInfo](#AlbumInfo) objects representing the albums the photo is contained in. See also [albums](#albums).
|
||||
Returns a list of [AlbumInfo](#AlbumInfo) objects representing the albums the photo is contained in or empty list of the photo is not in any albums. See also [albums](#albums).
|
||||
|
||||
#### `import_info`
|
||||
Returns an [ImportInfo](#importinfo) object representing the import session associated with the photo or `None` if there is no associated import session.
|
||||
|
||||
#### `project_info`
|
||||
Returns a list of [ProjectInfo](#projectinfo) objects representing projects/creations (cards, calendars, etc.) the photo is contained in or empty list if there are no projects associated with the photo.
|
||||
|
||||
|
||||
#### `persons`
|
||||
Returns a list of the names of the persons in the photo
|
||||
|
||||
@ -2934,6 +2950,23 @@ Returns the start date as a timezone aware datetime.datetime object for when the
|
||||
#### `end_date`
|
||||
Returns the end date as a timezone aware datetime.datetime object for when the import session completed.
|
||||
|
||||
### ProjectInfo
|
||||
PhotosDB.projcet_info returns a list of ProjectInfo objects. Each ProjectInfo object represents a project in the library. PhotoInfo.project_info returns a list of ProjectInfo objects for each project the photo is contained in.
|
||||
|
||||
Projects (found under "My Projects" in Photos) are projects or creations such as cards, calendars, and slideshows created in Photos. osxphotos provides only very basic information about projects and projects created with third party plugins may not accessible to osxphotos.
|
||||
|
||||
#### `uuid`
|
||||
Returns the universally unique identifier (uuid) of the project. This is how Photos keeps track of individual objects within the database.
|
||||
|
||||
#### `title`
|
||||
Returns the title or name of the project.
|
||||
|
||||
#### <a name="projectphotos">`photos`</a>
|
||||
Returns a list of [PhotoInfo](#PhotoInfo) objects representing each photo contained in the project.
|
||||
|
||||
#### `creation_date`
|
||||
Returns the creation date as a timezone aware datetime.datetime object of the project.
|
||||
|
||||
### FolderInfo
|
||||
PhotosDB.folder_info returns a list of FolderInfo objects representing the top level folders in the library. Each FolderInfo object represents a single folder in the Photos library.
|
||||
|
||||
@ -3584,10 +3617,13 @@ The following template field substitutions are availabe for use the templating s
|
||||
|{lf}|A line feed: '\n', alias for {newline}|
|
||||
|{cr}|A carriage return: '\r'|
|
||||
|{crlf}|a carriage return + line feed: '\r\n'|
|
||||
|{osxphotos_version}|The osxphotos version, e.g. '0.43.9'|
|
||||
|{osxphotos_version}|The osxphotos version, e.g. '0.44.0'|
|
||||
|{osxphotos_cmd_line}|The full command line used to run osxphotos|
|
||||
|{album}|Album(s) photo is contained in|
|
||||
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
||||
|{project}|Project(s) photo is contained in (such as greeting cards, calendars, slideshows)|
|
||||
|{album_project}|Album(s) and project(s) photo is contained in; treats projects as regular albums|
|
||||
|{folder_album_project}|Folder path + album (includes projects as albums) photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
||||
|{keyword}|Keyword(s) assigned to photo|
|
||||
|{person}|Person(s) / face(s) in a photo|
|
||||
|{label}|Image categorization label associated with a photo (Photos 5+ only). Labels are added automatically by Photos using machine learning algorithms to categorize images. These are not the same as {keyword} which refers to the user-defined keywords/tags applied in Photos.|
|
||||
|
||||
@ -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: 6a7b21011951131043e717993112beb1
|
||||
config: 4b8efce5e11b970d619d6d5988967d84
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
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.43.9',
|
||||
VERSION: '0.44.0',
|
||||
LANGUAGE: 'None',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
6
docs/_static/pygments.css
vendored
@ -1,7 +1,7 @@
|
||||
pre { line-height: 125%; }
|
||||
td.linenos pre { color: #000000; background-color: #f0f0f0; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos { color: #000000; background-color: #f0f0f0; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight { background: #f8f8f8; }
|
||||
|
||||
1648
docs/cli.html
2416
docs/genindex.html
106
docs/index.html
@ -4,8 +4,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.43.9 documentation</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.44.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
@ -31,30 +32,30 @@
|
||||
|
||||
<div class="body" role="main">
|
||||
|
||||
<div class="section" id="welcome-to-osxphotos-s-documentation">
|
||||
<section id="welcome-to-osxphotos-s-documentation">
|
||||
<h1>Welcome to osxphotos’s documentation!<a class="headerlink" href="#welcome-to-osxphotos-s-documentation" title="Permalink to this headline">¶</a></h1>
|
||||
</div>
|
||||
<div class="section" id="osxphotos">
|
||||
</section>
|
||||
<section id="osxphotos">
|
||||
<h1>OSXPhotos<a class="headerlink" href="#osxphotos" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="section" id="what-is-osxphotos">
|
||||
<section id="what-is-osxphotos">
|
||||
<h2>What is osxphotos?<a class="headerlink" href="#what-is-osxphotos" title="Permalink to this headline">¶</a></h2>
|
||||
<p>OSXPhotos provides both the ability to interact with and query Apple’s Photos.app library on macOS directly from your python code
|
||||
as well as a very flexible command line interface (CLI) app for exporting photos.
|
||||
You can query the Photos library database – for example, file name, file path, and metadata such as keywords/tags, persons/faces, albums, etc.
|
||||
You can also easily export both the original and edited photos.</p>
|
||||
</div>
|
||||
<div class="section" id="supported-operating-systems">
|
||||
</section>
|
||||
<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) 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>
|
||||
</div>
|
||||
<div class="section" id="installation">
|
||||
</section>
|
||||
<section id="installation">
|
||||
<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2>
|
||||
<p>If you are new to python and just want to use the command line application, I recommend you to install using pipx. See other advanced options below.</p>
|
||||
<div class="section" id="installation-using-pipx">
|
||||
<section id="installation-using-pipx">
|
||||
<h3>Installation using pipx<a class="headerlink" href="#installation-using-pipx" title="Permalink to this headline">¶</a></h3>
|
||||
<p>If you aren’t familiar with installing python applications, I recommend you install <code class="docutils literal notranslate"><span class="pre">osxphotos</span></code> with <a class="reference external" href="https://github.com/pipxproject/pipx">pipx</a>. If you use <code class="docutils literal notranslate"><span class="pre">pipx</span></code>, you will not need to create a virtual environment as <code class="docutils literal notranslate"><span class="pre">pipx</span></code> takes care of this. The easiest way to do this on a Mac is to use <a class="reference external" href="https://brew.sh/">homebrew</a>:</p>
|
||||
<ul class="simple">
|
||||
@ -64,15 +65,15 @@ E.g. you can read a database created with Photos 5.0 on MacOS 10.15 on a machine
|
||||
<li><p>Then type this: <code class="docutils literal notranslate"><span class="pre">pipx</span> <span class="pre">install</span> <span class="pre">osxphotos</span></code></p></li>
|
||||
<li><p>Now you should be able to run <code class="docutils literal notranslate"><span class="pre">osxphotos</span></code> by typing: <code class="docutils literal notranslate"><span class="pre">osxphotos</span></code></p></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="installation-using-pip">
|
||||
</section>
|
||||
<section id="installation-using-pip">
|
||||
<h3>Installation using pip<a class="headerlink" href="#installation-using-pip" title="Permalink to this headline">¶</a></h3>
|
||||
<p>You can also install directly from <a class="reference external" href="https://pypi.org/project/osxphotos/">pypi</a>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">osxphotos</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="installation-from-git-repository">
|
||||
</section>
|
||||
<section id="installation-from-git-repository">
|
||||
<h3>Installation from git repository<a class="headerlink" href="#installation-from-git-repository" title="Permalink to this headline">¶</a></h3>
|
||||
<p>OSXPhotos uses setuptools, thus simply run:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">git</span> <span class="n">clone</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">RhetTbull</span><span class="o">/</span><span class="n">osxphotos</span><span class="o">.</span><span class="n">git</span>
|
||||
@ -87,9 +88,9 @@ I recommend you install the latest version from <a class="reference external" hr
|
||||
libraries. If you just want to use the command line utility, you can download a pre-built executable of the latest
|
||||
<a class="reference external" href="https://github.com/RhetTbull/osxphotos/releases">release</a> or you can install via <code class="docutils literal notranslate"><span class="pre">pip</span></code> which also installs the command line app.
|
||||
If you aren’t comfortable with running python on your Mac, start with the pre-built executable or <code class="docutils literal notranslate"><span class="pre">pipx</span></code> as described above.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="command-line-usage">
|
||||
</section>
|
||||
</section>
|
||||
<section id="command-line-usage">
|
||||
<h2>Command Line Usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This package will install a command line utility called <code class="docutils literal notranslate"><span class="pre">osxphotos</span></code> that allows you to query the Photos database and export photos.
|
||||
Alternatively, you can also run the command line utility like this: <code class="docutils literal notranslate"><span class="pre">python3</span> <span class="pre">-m</span> <span class="pre">osxphotos</span></code></p>
|
||||
@ -127,38 +128,38 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
</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>
|
||||
<div class="section" id="command-line-examples">
|
||||
<section id="command-line-examples">
|
||||
<h3>Command line examples<a class="headerlink" href="#command-line-examples" title="Permalink to this headline">¶</a></h3>
|
||||
<div class="section" id="export-all-photos-to-desktop-export-group-in-folders-by-date-created">
|
||||
<section id="export-all-photos-to-desktop-export-group-in-folders-by-date-created">
|
||||
<h4>export all photos to ~/Desktop/export group in folders by date created<a class="headerlink" href="#export-all-photos-to-desktop-export-group-in-folders-by-date-created" title="Permalink to this headline">¶</a></h4>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">export</span> <span class="pre">--export-by-date</span> <span class="pre">~/Pictures/Photos\</span> <span class="pre">Library.photoslibrary</span> <span class="pre">~/Desktop/export</span></code></p>
|
||||
<p><strong>Note</strong>: Photos library/database path can also be specified using <code class="docutils literal notranslate"><span class="pre">--db</span></code> option:</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">export</span> <span class="pre">--export-by-date</span> <span class="pre">--db</span> <span class="pre">~/Pictures/Photos\</span> <span class="pre">Library.photoslibrary</span> <span class="pre">~/Desktop/export</span></code></p>
|
||||
</div>
|
||||
<div class="section" id="find-all-photos-with-keyword-kids-and-output-results-to-json-file-named-results-json">
|
||||
</section>
|
||||
<section id="find-all-photos-with-keyword-kids-and-output-results-to-json-file-named-results-json">
|
||||
<h4>find all photos with keyword “Kids” and output results to json file named results.json:<a class="headerlink" href="#find-all-photos-with-keyword-kids-and-output-results-to-json-file-named-results-json" title="Permalink to this headline">¶</a></h4>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">query</span> <span class="pre">--keyword</span> <span class="pre">Kids</span> <span class="pre">--json</span> <span class="pre">~/Pictures/Photos\</span> <span class="pre">Library.photoslibrary</span> <span class="pre">>results.json</span></code></p>
|
||||
</div>
|
||||
<div class="section" id="export-photos-to-file-structure-based-on-4-digit-year-and-full-name-of-month-of-photo-s-creation-date">
|
||||
</section>
|
||||
<section id="export-photos-to-file-structure-based-on-4-digit-year-and-full-name-of-month-of-photo-s-creation-date">
|
||||
<h4>export photos to file structure based on 4-digit year and full name of month of photo’s creation date:<a class="headerlink" href="#export-photos-to-file-structure-based-on-4-digit-year-and-full-name-of-month-of-photo-s-creation-date" title="Permalink to this headline">¶</a></h4>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">export</span> <span class="pre">~/Desktop/export</span> <span class="pre">--directory</span> <span class="pre">"{created.year}/{created.month}"</span></code></p>
|
||||
<p>(by default, it will attempt to use the system library)</p>
|
||||
</div>
|
||||
<div class="section" id="export-photos-to-file-structure-based-on-4-digit-year-of-photo-s-creation-date-and-add-keywords-for-media-type-and-labels-labels-are-only-awailable-on-photos-5-and-higher">
|
||||
</section>
|
||||
<section id="export-photos-to-file-structure-based-on-4-digit-year-of-photo-s-creation-date-and-add-keywords-for-media-type-and-labels-labels-are-only-awailable-on-photos-5-and-higher">
|
||||
<h4>export photos to file structure based on 4-digit year of photo’s creation date and add keywords for media type and labels (labels are only awailable on Photos 5 and higher):<a class="headerlink" href="#export-photos-to-file-structure-based-on-4-digit-year-of-photo-s-creation-date-and-add-keywords-for-media-type-and-labels-labels-are-only-awailable-on-photos-5-and-higher" title="Permalink to this headline">¶</a></h4>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">export</span> <span class="pre">~/Desktop/export</span> <span class="pre">--directory</span> <span class="pre">"{created.year}"</span> <span class="pre">--keyword-template</span> <span class="pre">"{label}"</span> <span class="pre">--keyword-template</span> <span class="pre">"{media_type}"</span></code></p>
|
||||
</div>
|
||||
<div class="section" id="export-default-library-using-country-name-year-as-output-directory-but-use-nocountry-year-if-country-not-specified-add-persons-album-names-and-year-as-keywords-write-exif-metadata-to-files-when-exporting-update-only-changed-files-print-verbose-ouput">
|
||||
</section>
|
||||
<section id="export-default-library-using-country-name-year-as-output-directory-but-use-nocountry-year-if-country-not-specified-add-persons-album-names-and-year-as-keywords-write-exif-metadata-to-files-when-exporting-update-only-changed-files-print-verbose-ouput">
|
||||
<h4>export default library using ‘country name/year’ as output directory (but use “NoCountry/year” if country not specified), add persons, album names, and year as keywords, write exif metadata to files when exporting, update only changed files, print verbose ouput<a class="headerlink" href="#export-default-library-using-country-name-year-as-output-directory-but-use-nocountry-year-if-country-not-specified-add-persons-album-names-and-year-as-keywords-write-exif-metadata-to-files-when-exporting-update-only-changed-files-print-verbose-ouput" title="Permalink to this headline">¶</a></h4>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">export</span> <span class="pre">~/Desktop/export</span> <span class="pre">--directory</span> <span class="pre">"{place.name.country,NoCountry}/{created.year}"</span>  <span class="pre">--person-keyword</span> <span class="pre">--album-keyword</span> <span class="pre">--keyword-template</span> <span class="pre">"{created.year}"</span> <span class="pre">--exiftool</span> <span class="pre">--update</span> <span class="pre">--verbose</span></code></p>
|
||||
</div>
|
||||
<div class="section" id="find-all-videos-larger-than-200mb-and-add-them-to-photos-album-big-videos-creating-the-album-if-necessary">
|
||||
</section>
|
||||
<section id="find-all-videos-larger-than-200mb-and-add-them-to-photos-album-big-videos-creating-the-album-if-necessary">
|
||||
<h4>find all videos larger than 200MB and add them to Photos album “Big Videos” creating the album if necessary<a class="headerlink" href="#find-all-videos-larger-than-200mb-and-add-them-to-photos-album-big-videos-creating-the-album-if-necessary" title="Permalink to this headline">¶</a></h4>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">osxphotos</span> <span class="pre">query</span> <span class="pre">--only-movies</span> <span class="pre">--min-size</span> <span class="pre">200MB</span> <span class="pre">--add-to-album</span> <span class="pre">"Big</span> <span class="pre">Videos"</span></code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="example-uses-of-the-package">
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="example-uses-of-the-package">
|
||||
<h2>Example uses of the package<a class="headerlink" href="#example-uses-of-the-package" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="sd">""" Simple usage of the package """</span>
|
||||
<span class="kn">import</span> <span class="nn">osxphotos</span>
|
||||
@ -274,50 +275,29 @@ Alternatively, you can also run the command line utility like this: <code class=
|
||||
<span class="n">export</span><span class="p">()</span> <span class="c1"># pylint: disable=no-value-for-parameter</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="package-interface">
|
||||
</section>
|
||||
<section id="package-interface">
|
||||
<h2>Package Interface<a class="headerlink" href="#package-interface" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Reference full documentation on <a class="reference external" href="https://github.com/RhetTbull/osxphotos/blob/master/README.md">GitHub</a></p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="cli.html">osxphotos command line interface (CLI)</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="cli.html#osxphotos">osxphotos</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-about">about</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-albums">albums</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-dump">dump</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-export">export</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-help">help</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-info">info</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-install">install</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-keywords">keywords</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-labels">labels</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-list">list</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-persons">persons</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-places">places</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-query">query</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-repl">repl</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-tutorial">tutorial</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-uninstall">uninstall</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="cli.html">osxphotos command line interface (CLI)</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="reference.html">osxphotos package</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos-module">osxphotos module</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="indices-and-tables">
|
||||
</section>
|
||||
</section>
|
||||
<section id="indices-and-tables">
|
||||
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h1>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></p></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
@ -375,7 +355,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 4.3.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.1</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
|
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos — osxphotos 0.43.9 documentation</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>osxphotos — osxphotos 0.44.0 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>
|
||||
@ -30,11 +31,11 @@
|
||||
|
||||
<div class="body" role="main">
|
||||
|
||||
<div class="section" id="osxphotos">
|
||||
<section id="osxphotos">
|
||||
<h1>osxphotos<a class="headerlink" href="#osxphotos" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="toctree-wrapper compound">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
@ -91,7 +92,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.1</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
|
|
||||
|
||||
BIN
docs/objects.inv
1355
docs/reference.html
@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — osxphotos 0.43.9 documentation</title>
|
||||
<title>Search — osxphotos 0.44.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
|
||||
@ -111,7 +111,7 @@
|
||||
©2021, Rhet Turnbull.
|
||||
|
||||
|
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.2</a>
|
||||
Powered by <a href="http://sphinx-doc.org/">Sphinx 4.3.1</a>
|
||||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||||
|
||||
</div>
|
||||
|
||||
@ -123,12 +123,20 @@ _XMP_TEMPLATE_NAME_BETA = "xmp_sidecar_beta.mako"
|
||||
# Constants used for processing folders and albums
|
||||
_PHOTOS_5_ALBUM_KIND = 2 # normal user album
|
||||
_PHOTOS_5_SHARED_ALBUM_KIND = 1505 # shared album
|
||||
_PHOTOS_5_PROJECT_ALBUM_KIND = 1508 # My Projects (e.g. Calendar, Card, Slideshow)
|
||||
_PHOTOS_5_FOLDER_KIND = 4000 # user folder
|
||||
_PHOTOS_5_ROOT_FOLDER_KIND = 3999 # root folder
|
||||
_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND = 1506 # import session
|
||||
|
||||
_PHOTOS_4_ALBUM_KIND = 3 # RKAlbum.albumSubclass
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUM = "TopLevelAlbums"
|
||||
_PHOTOS_4_ALBUM_TYPE_ALBUM = 1 # RKAlbum.albumType
|
||||
_PHOTOS_4_ALBUM_TYPE_PROJECT = 9 # RKAlbum.albumType
|
||||
_PHOTOS_4_ALBUM_TYPE_SLIDESHOW = 8 # RKAlbum.albumType
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUMS = [
|
||||
"TopLevelAlbums",
|
||||
"TopLevelKeepsakes",
|
||||
"TopLevelSlideshows",
|
||||
]
|
||||
_PHOTOS_4_ROOT_FOLDER = "LibraryFolder"
|
||||
|
||||
# EXIF related constants
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.43.9"
|
||||
__version__ = "0.44.0"
|
||||
|
||||
@ -14,7 +14,7 @@ from datetime import datetime, timedelta, timezone
|
||||
|
||||
from ._constants import (
|
||||
_PHOTOS_4_ALBUM_KIND,
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUM,
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUMS,
|
||||
_PHOTOS_4_VERSION,
|
||||
_PHOTOS_5_ALBUM_KIND,
|
||||
_PHOTOS_5_FOLDER_KIND,
|
||||
@ -161,7 +161,6 @@ class AlbumInfoBaseClass:
|
||||
|
||||
class AlbumInfo(AlbumInfoBaseClass):
|
||||
"""
|
||||
Base class for AlbumInfo, ImportInfo
|
||||
Info about a specific Album, contains all the details about the album
|
||||
including folders, photos, etc.
|
||||
"""
|
||||
@ -231,7 +230,7 @@ class AlbumInfo(AlbumInfoBaseClass):
|
||||
parent_uuid = self._db._dbalbum_details[self._uuid]["folderUuid"]
|
||||
self._parent = (
|
||||
FolderInfo(db=self._db, uuid=parent_uuid)
|
||||
if parent_uuid != _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
if parent_uuid not in _PHOTOS_4_TOP_LEVEL_ALBUMS
|
||||
else None
|
||||
)
|
||||
else:
|
||||
@ -266,18 +265,17 @@ class AlbumInfo(AlbumInfoBaseClass):
|
||||
|
||||
def photo_index(self, photo):
|
||||
"""return index of photo in album (based on album sort order)"""
|
||||
index = 0
|
||||
for p in self.photos:
|
||||
for index, p in enumerate(self.photos):
|
||||
if p.uuid == photo.uuid:
|
||||
return index
|
||||
index += 1
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Photo with uuid {photo.uuid} does not appear to be in this album"
|
||||
)
|
||||
raise ValueError(
|
||||
f"Photo with uuid {photo.uuid} does not appear to be in this album"
|
||||
)
|
||||
|
||||
|
||||
class ImportInfo(AlbumInfoBaseClass):
|
||||
"""Information about import sessions"""
|
||||
|
||||
@property
|
||||
def photos(self):
|
||||
"""return list of photos contained in import session"""
|
||||
@ -296,6 +294,15 @@ class ImportInfo(AlbumInfoBaseClass):
|
||||
return self._photos
|
||||
|
||||
|
||||
class ProjectInfo(AlbumInfo):
|
||||
"""
|
||||
ProjectInfo with info about projects
|
||||
Projects are cards, calendars, slideshows, etc.
|
||||
"""
|
||||
|
||||
...
|
||||
|
||||
|
||||
class FolderInfo:
|
||||
"""
|
||||
Info about a specific folder, contains all the details about the folder
|
||||
@ -357,7 +364,7 @@ class FolderInfo:
|
||||
parent_uuid = self._db._dbfolder_details[self._uuid]["parentFolderUuid"]
|
||||
self._parent = (
|
||||
FolderInfo(db=self._db, uuid=parent_uuid)
|
||||
if parent_uuid != _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
if parent_uuid not in _PHOTOS_4_TOP_LEVEL_ALBUMS
|
||||
else None
|
||||
)
|
||||
else:
|
||||
|
||||
@ -4159,6 +4159,7 @@ def _spotlight_photo(photo: PhotoInfo):
|
||||
)
|
||||
def repl(ctx, cli_obj, db, emacs):
|
||||
"""Run interactive osxphotos REPL shell (useful for debugging, prototyping, and inspecting your Photos library)"""
|
||||
import logging
|
||||
|
||||
from objexplore import explore
|
||||
from photoscript import Album, Photo, PhotosLibrary
|
||||
@ -4169,6 +4170,9 @@ def repl(ctx, cli_obj, db, emacs):
|
||||
from osxphotos.placeinfo import PlaceInfo
|
||||
from osxphotos.queryoptions import QueryOptions
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.disabled = True
|
||||
|
||||
pretty.install()
|
||||
print(f"python version: {sys.version}")
|
||||
print(f"osxphotos version: {osxphotos._version.__version__}")
|
||||
|
||||
@ -20,10 +20,14 @@ from .._constants import (
|
||||
_MOVIE_TYPE,
|
||||
_PHOTO_TYPE,
|
||||
_PHOTOS_4_ALBUM_KIND,
|
||||
_PHOTOS_4_ALBUM_TYPE_ALBUM,
|
||||
_PHOTOS_4_ALBUM_TYPE_PROJECT,
|
||||
_PHOTOS_4_ALBUM_TYPE_SLIDESHOW,
|
||||
_PHOTOS_4_ROOT_FOLDER,
|
||||
_PHOTOS_4_VERSION,
|
||||
_PHOTOS_5_ALBUM_KIND,
|
||||
_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND,
|
||||
_PHOTOS_5_PROJECT_ALBUM_KIND,
|
||||
_PHOTOS_5_SHARED_ALBUM_KIND,
|
||||
_PHOTOS_5_SHARED_PHOTO_PATH,
|
||||
_PHOTOS_5_VERSION,
|
||||
@ -34,7 +38,7 @@ from .._constants import (
|
||||
TEXT_DETECTION_CONFIDENCE_THRESHOLD,
|
||||
)
|
||||
from ..adjustmentsinfo import AdjustmentsInfo
|
||||
from ..albuminfo import AlbumInfo, ImportInfo
|
||||
from ..albuminfo import AlbumInfo, ImportInfo, ProjectInfo
|
||||
from ..momentinfo import MomentInfo
|
||||
from ..personinfo import FaceInfo, PersonInfo
|
||||
from ..phototemplate import PhotoTemplate, RenderOptions
|
||||
@ -570,6 +574,18 @@ class PhotoInfo:
|
||||
)
|
||||
return self._import_info
|
||||
|
||||
@property
|
||||
def project_info(self):
|
||||
"""list of AlbumInfo objects representing projects for the photo or None if no projects"""
|
||||
try:
|
||||
return self._project_info
|
||||
except AttributeError:
|
||||
project_uuids = self._get_album_uuids(project=True)
|
||||
self._project_info = [
|
||||
ProjectInfo(db=self._db, uuid=album) for album in project_uuids
|
||||
]
|
||||
return self._project_info
|
||||
|
||||
@property
|
||||
def keywords(self):
|
||||
"""list of keywords for picture"""
|
||||
@ -1197,34 +1213,48 @@ class PhotoInfo:
|
||||
"""Returns latitude, in degrees"""
|
||||
return self._info["latitude"]
|
||||
|
||||
def _get_album_uuids(self):
|
||||
def _get_album_uuids(self, project=False):
|
||||
"""Return list of album UUIDs this photo is found in
|
||||
|
||||
Filters out albums in the trash and any special album types
|
||||
|
||||
if project is True, returns special "My Project" albums (e.g. cards, calendars, slideshows)
|
||||
|
||||
Returns: list of album UUIDs
|
||||
"""
|
||||
if self._db._db_version <= _PHOTOS_4_VERSION:
|
||||
version4 = True
|
||||
album_kind = [_PHOTOS_4_ALBUM_KIND]
|
||||
else:
|
||||
version4 = False
|
||||
album_kind = [_PHOTOS_5_SHARED_ALBUM_KIND, _PHOTOS_5_ALBUM_KIND]
|
||||
album_type = (
|
||||
[_PHOTOS_4_ALBUM_TYPE_PROJECT, _PHOTOS_4_ALBUM_TYPE_SLIDESHOW]
|
||||
if project
|
||||
else [_PHOTOS_4_ALBUM_TYPE_ALBUM]
|
||||
)
|
||||
album_list = []
|
||||
for album in self._info["albums"]:
|
||||
detail = self._db._dbalbum_details[album]
|
||||
if (
|
||||
detail["kind"] in album_kind
|
||||
and detail["albumType"] in album_type
|
||||
and not detail["intrash"]
|
||||
and detail["folderUuid"] != _PHOTOS_4_ROOT_FOLDER
|
||||
# in Photos <= 4, special albums like "printAlbum" have kind _PHOTOS_4_ALBUM_KIND
|
||||
# but should not be listed here; they can be distinguished by looking
|
||||
# for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
):
|
||||
album_list.append(album)
|
||||
return album_list
|
||||
|
||||
# Photos 5+
|
||||
album_kind = (
|
||||
[_PHOTOS_5_PROJECT_ALBUM_KIND]
|
||||
if project
|
||||
else [_PHOTOS_5_SHARED_ALBUM_KIND, _PHOTOS_5_ALBUM_KIND]
|
||||
)
|
||||
|
||||
album_list = []
|
||||
for album in self._info["albums"]:
|
||||
detail = self._db._dbalbum_details[album]
|
||||
if (
|
||||
detail["kind"] in album_kind
|
||||
and not detail["intrash"]
|
||||
and (
|
||||
not version4
|
||||
# in Photos <= 4, special albums like "printAlbum" have kind _PHOTOS_4_ALBUM_KIND
|
||||
# but should not be listed here; they can be distinguished by looking
|
||||
# for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
or (version4 and detail["folderUuid"] != _PHOTOS_4_ROOT_FOLDER)
|
||||
)
|
||||
):
|
||||
if detail["kind"] in album_kind and not detail["intrash"]:
|
||||
album_list.append(album)
|
||||
return album_list
|
||||
|
||||
|
||||
@ -28,11 +28,15 @@ from .._constants import (
|
||||
_PHOTOS_3_VERSION,
|
||||
_PHOTOS_4_ALBUM_KIND,
|
||||
_PHOTOS_4_ROOT_FOLDER,
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUM,
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUMS,
|
||||
_PHOTOS_4_ALBUM_TYPE_ALBUM,
|
||||
_PHOTOS_4_ALBUM_TYPE_PROJECT,
|
||||
_PHOTOS_4_ALBUM_TYPE_SLIDESHOW,
|
||||
_PHOTOS_4_VERSION,
|
||||
_PHOTOS_5_ALBUM_KIND,
|
||||
_PHOTOS_5_FOLDER_KIND,
|
||||
_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND,
|
||||
_PHOTOS_5_PROJECT_ALBUM_KIND,
|
||||
_PHOTOS_5_ROOT_FOLDER_KIND,
|
||||
_PHOTOS_5_SHARED_ALBUM_KIND,
|
||||
_TESTED_OS_VERSIONS,
|
||||
@ -42,7 +46,7 @@ from .._constants import (
|
||||
TIME_DELTA,
|
||||
)
|
||||
from .._version import __version__
|
||||
from ..albuminfo import AlbumInfo, FolderInfo, ImportInfo
|
||||
from ..albuminfo import AlbumInfo, FolderInfo, ImportInfo, ProjectInfo
|
||||
from ..datetime_utils import datetime_has_tz, datetime_naive_to_local
|
||||
from ..fileutil import FileUtil
|
||||
from ..personinfo import PersonInfo
|
||||
@ -429,7 +433,7 @@ class PhotosDB:
|
||||
for folder, detail in self._dbfolder_details.items()
|
||||
if not detail["intrash"]
|
||||
and not detail["isMagic"]
|
||||
and detail["parentFolderUuid"] == _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
and detail["parentFolderUuid"] in _PHOTOS_4_TOP_LEVEL_ALBUMS
|
||||
]
|
||||
else:
|
||||
folders = [
|
||||
@ -450,7 +454,7 @@ class PhotosDB:
|
||||
for folder in self._dbfolder_details.values()
|
||||
if not folder["intrash"]
|
||||
and not folder["isMagic"]
|
||||
and folder["parentFolderUuid"] == _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
and folder["parentFolderUuid"] in _PHOTOS_4_TOP_LEVEL_ALBUMS
|
||||
]
|
||||
else:
|
||||
folder_names = [
|
||||
@ -529,6 +533,18 @@ class PhotosDB:
|
||||
]
|
||||
return self._import_info
|
||||
|
||||
@property
|
||||
def project_info(self):
|
||||
"""return list of AlbumInfo projects for each project in the database"""
|
||||
try:
|
||||
return self._project_info
|
||||
except AttributeError:
|
||||
self._project_info = [
|
||||
ProjectInfo(db=self, uuid=album)
|
||||
for album in self._get_album_uuids(project=True)
|
||||
]
|
||||
return self._project_info
|
||||
|
||||
@property
|
||||
def db_version(self):
|
||||
"""return the database version as stored in LiGlobals table"""
|
||||
@ -848,11 +864,10 @@ class PhotosDB:
|
||||
# build folder hierarchy
|
||||
for album, details in self._dbalbum_details.items():
|
||||
parent_folder = details["folderUuid"]
|
||||
if details[
|
||||
"albumSubclass"
|
||||
] == _PHOTOS_4_ALBUM_KIND and parent_folder not in [
|
||||
_PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
]:
|
||||
if (
|
||||
details["albumSubclass"] == _PHOTOS_4_ALBUM_KIND
|
||||
and parent_folder not in _PHOTOS_4_TOP_LEVEL_ALBUMS
|
||||
):
|
||||
folder_hierarchy = self._build_album_folder_hierarchy_4(parent_folder)
|
||||
self._dbalbum_folders[album] = folder_hierarchy
|
||||
else:
|
||||
@ -1582,7 +1597,7 @@ class PhotosDB:
|
||||
if parent_uuid is None:
|
||||
return folders
|
||||
|
||||
if parent_uuid == _PHOTOS_4_TOP_LEVEL_ALBUM:
|
||||
if parent_uuid in _PHOTOS_4_TOP_LEVEL_ALBUMS:
|
||||
if not folders:
|
||||
# this is a top-level folder with no sub-folders
|
||||
folders = {uuid: None}
|
||||
@ -2825,7 +2840,7 @@ class PhotosDB:
|
||||
hierarchy = _recurse_folder_hierarchy(folders)
|
||||
return hierarchy
|
||||
|
||||
def _get_album_uuids(self, shared=False, import_session=False):
|
||||
def _get_album_uuids(self, shared=False, import_session=False, project=False):
|
||||
"""Return list of album UUIDs found in photos database
|
||||
|
||||
Filters out albums in the trash and any special album types
|
||||
@ -2833,20 +2848,21 @@ class PhotosDB:
|
||||
Args:
|
||||
shared: boolean; if True, returns shared albums, else normal albums
|
||||
import_session: boolean, if True, returns import session albums, else normal or shared albums
|
||||
project: boolean, if True, returns albums that are part of My Projects
|
||||
Note: flags (shared, import_session) are mutually exclusive
|
||||
|
||||
|
||||
Raises:
|
||||
ValueError: raised if mutually exclusive flags passed
|
||||
|
||||
Returns: list of album UUIDs
|
||||
"""
|
||||
if shared and import_session:
|
||||
if sum(bool(x) for x in [shared, import_session, project]) > 1:
|
||||
raise ValueError(
|
||||
"flags are mutually exclusive: pass zero or one of shared, import_session"
|
||||
"flags are mutually exclusive: pass zero or one of shared, import_session, projects"
|
||||
)
|
||||
|
||||
if self._db_version <= _PHOTOS_4_VERSION:
|
||||
version4 = True
|
||||
if shared:
|
||||
logging.warning(
|
||||
f"Shared albums not implemented for Photos library version {self._db_version}"
|
||||
@ -2857,16 +2873,44 @@ class PhotosDB:
|
||||
f"Import sessions not implemented for Photos library version {self._db_version}"
|
||||
)
|
||||
return [] # not implemented for _PHOTOS_4_VERSION
|
||||
else:
|
||||
elif project:
|
||||
album_type = [
|
||||
_PHOTOS_4_ALBUM_TYPE_PROJECT,
|
||||
_PHOTOS_4_ALBUM_TYPE_SLIDESHOW,
|
||||
]
|
||||
album_kind = _PHOTOS_4_ALBUM_KIND
|
||||
else:
|
||||
version4 = False
|
||||
if shared:
|
||||
album_kind = _PHOTOS_5_SHARED_ALBUM_KIND
|
||||
elif import_session:
|
||||
album_kind = _PHOTOS_5_IMPORT_SESSION_ALBUM_KIND
|
||||
else:
|
||||
album_kind = _PHOTOS_5_ALBUM_KIND
|
||||
album_type = [_PHOTOS_4_ALBUM_TYPE_ALBUM]
|
||||
album_kind = _PHOTOS_4_ALBUM_KIND
|
||||
|
||||
album_list = []
|
||||
# look through _dbalbum_details because _dbalbums_album won't have empty albums it
|
||||
for album, detail in self._dbalbum_details.items():
|
||||
if (
|
||||
detail["kind"] == album_kind
|
||||
and detail["albumType"] in album_type
|
||||
and not detail["intrash"]
|
||||
and (
|
||||
(shared and detail["cloudownerhashedpersonid"] is not None)
|
||||
or (not shared and detail["cloudownerhashedpersonid"] is None)
|
||||
)
|
||||
and detail["folderUuid"] != _PHOTOS_4_ROOT_FOLDER
|
||||
# in Photos <= 4, special albums like "printAlbum" have kind _PHOTOS_4_ALBUM_KIND
|
||||
# but should not be listed here; they can be distinguished by looking
|
||||
# for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
):
|
||||
album_list.append(album)
|
||||
return album_list
|
||||
|
||||
# Photos version 5+
|
||||
if shared:
|
||||
album_kind = _PHOTOS_5_SHARED_ALBUM_KIND
|
||||
elif import_session:
|
||||
album_kind = _PHOTOS_5_IMPORT_SESSION_ALBUM_KIND
|
||||
elif project:
|
||||
album_kind = _PHOTOS_5_PROJECT_ALBUM_KIND
|
||||
else:
|
||||
album_kind = _PHOTOS_5_ALBUM_KIND
|
||||
|
||||
album_list = []
|
||||
# look through _dbalbum_details because _dbalbums_album won't have empty albums it
|
||||
@ -2878,13 +2922,6 @@ class PhotosDB:
|
||||
(shared and detail["cloudownerhashedpersonid"] is not None)
|
||||
or (not shared and detail["cloudownerhashedpersonid"] is None)
|
||||
)
|
||||
and (
|
||||
not version4
|
||||
# in Photos 4, special albums like "printAlbum" have kind _PHOTOS_4_ALBUM_KIND
|
||||
# but should not be listed here; they can be distinguished by looking
|
||||
# for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM
|
||||
or (version4 and detail["folderUuid"] != _PHOTOS_4_ROOT_FOLDER)
|
||||
)
|
||||
):
|
||||
album_list.append(album)
|
||||
return album_list
|
||||
|
||||
@ -181,6 +181,9 @@ TEMPLATE_SUBSTITUTIONS_PATHLIB = {
|
||||
TEMPLATE_SUBSTITUTIONS_MULTI_VALUED = {
|
||||
"{album}": "Album(s) photo is contained in",
|
||||
"{folder_album}": "Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder",
|
||||
"{project}": "Project(s) photo is contained in (such as greeting cards, calendars, slideshows)",
|
||||
"{album_project}": "Album(s) and project(s) photo is contained in; treats projects as regular albums",
|
||||
"{folder_album_project}": "Folder path + album (includes projects as albums) photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder",
|
||||
"{keyword}": "Keyword(s) assigned to photo",
|
||||
"{person}": "Person(s) / face(s) in a photo",
|
||||
"{label}": "Image categorization label associated with a photo (Photos 5+ only). "
|
||||
@ -1116,6 +1119,11 @@ class PhotoTemplate:
|
||||
values = []
|
||||
if field == "album":
|
||||
values = self.photo.burst_albums if self.photo.burst else self.photo.albums
|
||||
elif field == "project":
|
||||
values = [p.title for p in self.photo.project_info]
|
||||
elif field == "album_project":
|
||||
values = self.photo.burst_albums if self.photo.burst else self.photo.albums
|
||||
values += [p.title for p in self.photo.project_info]
|
||||
elif field == "keyword":
|
||||
values = self.photo.keywords
|
||||
elif field == "person":
|
||||
@ -1126,13 +1134,15 @@ class PhotoTemplate:
|
||||
values = self.photo.labels
|
||||
elif field == "label_normalized":
|
||||
values = self.photo.labels_normalized
|
||||
elif field == "folder_album":
|
||||
elif field in ["folder_album", "folder_album_project"]:
|
||||
values = []
|
||||
# photos must be in an album to be in a folder
|
||||
if self.photo.burst:
|
||||
album_info = self.photo.burst_album_info
|
||||
else:
|
||||
album_info = self.photo.album_info
|
||||
if field == "folder_album_project":
|
||||
album_info += self.photo.project_info
|
||||
for album in album_info:
|
||||
if album.folder_names:
|
||||
# album in folder
|
||||
@ -1193,7 +1203,7 @@ class PhotoTemplate:
|
||||
elif isinstance(obj, (str, int, float)):
|
||||
values = [str(obj)]
|
||||
else:
|
||||
values = [val for val in obj]
|
||||
values = list(obj)
|
||||
elif field == "detected_text":
|
||||
values = _get_detected_text(self.photo, self.exportdb, confidence=subfield)
|
||||
else:
|
||||
|
||||
|
After Width: | Height: | Size: 545 KiB |
|
After Width: | Height: | Size: 532 KiB |
|
After Width: | Height: | Size: 578 KiB |
|
After Width: | Height: | Size: 504 KiB |
|
After Width: | Height: | Size: 524 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>MajorVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>MinorVersion</key>
|
||||
<integer>34</integer>
|
||||
<key>createDate</key>
|
||||
<date>2021-12-30T03:56:43Z</date>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
tests/Test-iPhoto-Projects-10.12.6.photoslibrary/Projects.db
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>DatabaseMinorVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>DatabaseVersion</key>
|
||||
<integer>112</integer>
|
||||
<key>LastOpenMode</key>
|
||||
<integer>2</integer>
|
||||
<key>LibrarySchemaVersion</key>
|
||||
<integer>2622</integer>
|
||||
<key>MetaSchemaVersion</key>
|
||||
<integer>2</integer>
|
||||
<key>createDate</key>
|
||||
<date>2021-12-29T18:15:21Z</date>
|
||||
<key>databaseUuid</key>
|
||||
<string>Nm7MKBmoSRygMmA9WlEaGw</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1 @@
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LithiumMessageTracer</key>
|
||||
<dict>
|
||||
<key>LastReportedDate</key>
|
||||
<date>2021-12-30T03:56:48Z</date>
|
||||
</dict>
|
||||
<key>PXPeopleScreenUnlocked</key>
|
||||
<true/>
|
||||
<key>Photos</key>
|
||||
<dict>
|
||||
<key>IPXWorkspaceControllerZoomLevelsKey</key>
|
||||
<dict>
|
||||
<key>kZoomLevelIdentifierAlbums</key>
|
||||
<integer>7</integer>
|
||||
<key>kZoomLevelIdentifierVersions</key>
|
||||
<integer>7</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>RDLegacyProxyMediaRelocationCleanupCompletedKey</key>
|
||||
<true/>
|
||||
<key>ShowHiddenPhotosAlbumUserDefault</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
|
||||
<date>2021-12-31T04:32:23Z</date>
|
||||
<key>PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate</key>
|
||||
<date>2021-12-31T04:32:23Z</date>
|
||||
</dict>
|
||||
</plist>
|
||||
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PLLanguageAndLocaleKey</key>
|
||||
<string>en-US:en_US</string>
|
||||
<key>PLLastGeoProviderIdKey</key>
|
||||
<string>7618</string>
|
||||
<key>PLLastLocationInfoFormatVer</key>
|
||||
<integer>12</integer>
|
||||
<key>PLLastRevGeoForcedProviderOutOfDateCheckVersionKey</key>
|
||||
<integer>1</integer>
|
||||
<key>PLLastRevGeoVerFileFetchDateKey</key>
|
||||
<date>2021-12-30T03:56:45Z</date>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LastHistoryRowId</key>
|
||||
<integer>164</integer>
|
||||
<key>LibraryBuildTag</key>
|
||||
<string>E371079C-71D9-4C33-91F6-54B17B4B3066</string>
|
||||
<key>LibrarySchemaVersion</key>
|
||||
<integer>2622</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>FileVersion</key>
|
||||
<integer>11</integer>
|
||||
<key>Source</key>
|
||||
<dict>
|
||||
<key>35230</key>
|
||||
<dict>
|
||||
<key>CountryMinVersions</key>
|
||||
<dict>
|
||||
<key>OTHER</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>CurrentVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>NoResultErrorIsSuccess</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>57879</key>
|
||||
<dict>
|
||||
<key>CountryMinVersions</key>
|
||||
<dict>
|
||||
<key>OTHER</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>CurrentVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>NoResultErrorIsSuccess</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>7618</key>
|
||||
<dict>
|
||||
<key>AddCountyIfNeeded</key>
|
||||
<true/>
|
||||
<key>CountryMinVersions</key>
|
||||
<dict>
|
||||
<key>OTHER</key>
|
||||
<integer>10</integer>
|
||||
</dict>
|
||||
<key>CurrentVersion</key>
|
||||
<integer>10</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>MajorVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>MinorVersion</key>
|
||||
<integer>34</integer>
|
||||
<key>createDate</key>
|
||||
<date>2021-12-30T03:56:43Z</date>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>creationDate</key>
|
||||
<date>2021-12-30T03:56:00Z</date>
|
||||
<key>name</key>
|
||||
<string>Photos</string>
|
||||
<key>previewImageHash</key>
|
||||
<integer>0</integer>
|
||||
<key>previewImageName</key>
|
||||
<string>Calendar</string>
|
||||
<key>themeIdentifier</key>
|
||||
<string>Picture-Calendar</string>
|
||||
<key>type</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>MajorVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>MinorVersion</key>
|
||||
<integer>34</integer>
|
||||
<key>createDate</key>
|
||||
<date>2021-12-30T03:56:43Z</date>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>creationDate</key>
|
||||
<date>2021-12-30T03:55:08Z</date>
|
||||
<key>name</key>
|
||||
<string>Photos</string>
|
||||
<key>previewImageHash</key>
|
||||
<integer>0</integer>
|
||||
<key>previewImageName</key>
|
||||
<string>Card_Landscape</string>
|
||||
<key>themeIdentifier</key>
|
||||
<string>PremiumClassic-FoldedCard</string>
|
||||
<key>type</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 380 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 378 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 371 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 311 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 330 KiB |
@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>DatabaseMinorVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>DatabaseVersion</key>
|
||||
<integer>112</integer>
|
||||
<key>HistoricalMarker</key>
|
||||
<dict>
|
||||
<key>LastHistoryRowId</key>
|
||||
<integer>164</integer>
|
||||
<key>LibraryBuildTag</key>
|
||||
<string>E371079C-71D9-4C33-91F6-54B17B4B3066</string>
|
||||
<key>LibrarySchemaVersion</key>
|
||||
<integer>2622</integer>
|
||||
</dict>
|
||||
<key>LibrarySchemaVersion</key>
|
||||
<integer>2622</integer>
|
||||
<key>MetaSchemaVersion</key>
|
||||
<integer>2</integer>
|
||||
<key>SnapshotComplete</key>
|
||||
<true/>
|
||||
<key>SnapshotCompletedDate</key>
|
||||
<date>2021-12-30T03:56:44Z</date>
|
||||
<key>SnapshotLastAttemptStartDate</key>
|
||||
<date>2021-12-30T03:56:44Z</date>
|
||||
<key>SnapshotTables</key>
|
||||
<dict>
|
||||
<key>RKAdminData</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>33ba9a656c3588b4bdc1e44575e794e1d256d625</string>
|
||||
</dict>
|
||||
<key>RKAlbum</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>3b09c246d3a74e7f57265e6ab6abb0d333665215</string>
|
||||
</dict>
|
||||
<key>RKAlbumVersion</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>fc7c9baa656623406304fcc10474e561dff5a53a</string>
|
||||
</dict>
|
||||
<key>RKBookmark</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>33e3f9220c22909667ab63c0070757b8ffe1aeac</string>
|
||||
</dict>
|
||||
<key>RKCustomSortOrder</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>d65281f0c3f9e519cc5a00e21bb5ece35aa03cbd</string>
|
||||
</dict>
|
||||
<key>RKFace</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>dd0f12962d72c2e53f483bd3e02e18f3bbf423ac</string>
|
||||
</dict>
|
||||
<key>RKFolder</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>8712074c0728e02c777705031c0e16882eda9bff</string>
|
||||
</dict>
|
||||
<key>RKImageProxyState</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>5b0f369a4df955c63b1a636980e76e3d30d99fa9</string>
|
||||
</dict>
|
||||
<key>RKImportGroup</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>0ad244b52516a1cac3ea5532af1e60b3f74b4af7</string>
|
||||
</dict>
|
||||
<key>RKKeyword</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>85669e2bf25048d655ed8042d1607d50587de1fc</string>
|
||||
</dict>
|
||||
<key>RKKeywordForVersion</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>cf61584fa6191e45a64311ae4617418fde4d5263</string>
|
||||
</dict>
|
||||
<key>RKMaster</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>a609e1942bd9e5d69f3532e1e3e091156f5c3469</string>
|
||||
</dict>
|
||||
<key>RKModelResource</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>c677e8613d841620d96ed750d1a720bd283a0df7</string>
|
||||
</dict>
|
||||
<key>RKVersion</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>b2d209286b8f7b68a5fba0fb84e364ce55d83608</string>
|
||||
</dict>
|
||||
<key>RKVersionAnalysisState</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>2a36598c306df54e303c14ccb19bcdeae2d85bf5</string>
|
||||
</dict>
|
||||
<key>RKVolume</key>
|
||||
<dict>
|
||||
<key>0000000000.lisj</key>
|
||||
<string>5d16bc7903a060b2e879d148100441b1ac5c1629</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||