Compare commits

..

16 Commits

Author SHA1 Message Date
Rhet Turnbull
128e84c7a4 Added inspect command 2022-05-22 13:32:20 -07:00
Rhet Turnbull
4771207595 Feature inspect command (#701)
* Initial implementation of inspect command

* Updated help for inspect
2022-05-22 12:23:40 -07:00
Rhet Turnbull
0eca3b9c13 Initial implementation of inspect command (#700) 2022-05-22 12:18:40 -07:00
Rhet Turnbull
afec845e1b Updated CHANGELOG.md [skip ci] 2022-05-21 11:13:55 -07:00
Rhet Turnbull
64002044d2 Added timestamp to export_data in exportdb, #697 2022-05-21 11:00:52 -07:00
Rhet Turnbull
4e40d4b74e Added warning on hardlinks to exiftool command 2022-05-21 08:48:59 -07:00
Rhet Turnbull
63d515646b Updated CHANGELOG.md [skip ci] 2022-05-21 08:20:21 -07:00
Rhet Turnbull
0a7575b889 Updated docs 2022-05-21 08:12:32 -07:00
Rhet Turnbull
c776f3070d Added --uuid-info, --uuid-files to exportdb 2022-05-21 08:08:25 -07:00
Rhet Turnbull
3b789242aa Updated CHANGELOG.md [skip ci] 2022-05-21 07:29:12 -07:00
Rhet Turnbull
dfcb99f377 Updated test 2022-05-21 07:25:47 -07:00
Rhet Turnbull
8e9f27995b Added exiftool command 2022-05-20 22:19:26 -07:00
Rhet Turnbull
79e4b333e9 Initial implementation of exiftool command, #691 (#696)
* Initial implementation of exiftool command, #691

* updated comment [skip ci]
2022-05-20 22:12:48 -07:00
Rhet Turnbull
6d5af5c5e8 Added example [skip ci] 2022-05-18 23:07:33 -07:00
Rhet Turnbull
5a3e32a2b4 Updated CHANGELOG.md [skip ci] 2022-05-17 23:09:29 -07:00
Rhet Turnbull
3473c2ece2 Updated docs [skip ci] 2022-05-17 22:43:45 -07:00
43 changed files with 2083 additions and 149 deletions

View File

@@ -1943,7 +1943,7 @@ cog.out(get_template_field_table())
|{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.49.1'|
|{osxphotos_version}|The osxphotos version, e.g. '0.49.5'|
|{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|

View File

@@ -4,6 +4,38 @@ 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.49.4](https://github.com/RhetTbull/osxphotos/compare/v0.49.3...v0.49.4)
> 21 May 2022
- Added timestamp to export_data in exportdb, #697 [`6400204`](https://github.com/RhetTbull/osxphotos/commit/64002044d2cbbd6fb3c2f0ab69ff6cd5ee2e8e25)
- Added warning on hardlinks to exiftool command [`4e40d4b`](https://github.com/RhetTbull/osxphotos/commit/4e40d4b74e9b244b8eee602f839e595af4f99dfb)
#### [v0.49.3](https://github.com/RhetTbull/osxphotos/compare/v0.49.2...v0.49.3)
> 21 May 2022
- Updated docs [`0a7575b`](https://github.com/RhetTbull/osxphotos/commit/0a7575b889949f9e74ad716bc316e87f2599d4ad)
- Added --uuid-info, --uuid-files to exportdb [`c776f30`](https://github.com/RhetTbull/osxphotos/commit/c776f3070d40ed960eabe3c21c57c354108ff5e4)
#### [v0.49.2](https://github.com/RhetTbull/osxphotos/compare/v0.49.1...v0.49.2)
> 21 May 2022
- Initial implementation of exiftool command, #691 [`#696`](https://github.com/RhetTbull/osxphotos/pull/696)
- Added exiftool command [`8e9f279`](https://github.com/RhetTbull/osxphotos/commit/8e9f27995b56489da8968e77018a8a3d1bbe76bd)
- Added example [skip ci] [`6d5af5c`](https://github.com/RhetTbull/osxphotos/commit/6d5af5c5e87aa0699da7291376cbf05c4237f6ec)
- Updated docs [skip ci] [`3473c2e`](https://github.com/RhetTbull/osxphotos/commit/3473c2ece2b6eea9885893c85aa9eceb16921b94)
- Updated test [`dfcb99f`](https://github.com/RhetTbull/osxphotos/commit/dfcb99f3774cb519c30a9fcf403ca9fdc3fed993)
#### [v0.49.1](https://github.com/RhetTbull/osxphotos/compare/v0.49.0...v0.49.1)
> 17 May 2022
- Implemented #689 [`4ec9f6d`](https://github.com/RhetTbull/osxphotos/commit/4ec9f6d3e606f72962e351432a64a24ff9153d87)
- Unhid exportdb command [`5a9722b`](https://github.com/RhetTbull/osxphotos/commit/5a9722b37c8326bde7c6bde9870ce704aabb2a15)
- Added example [`72af96b`](https://github.com/RhetTbull/osxphotos/commit/72af96b48ee7552d5d35e6f5d619c5b7a55050ab)
#### [v0.49.0](https://github.com/RhetTbull/osxphotos/compare/v0.48.8...v0.49.0)
> 15 May 2022

View File

@@ -18,9 +18,10 @@ OSXPhotos provides the ability to interact with and query Apple's Photos.app lib
* [Supported operating systems](#supported-operating-systems)
* [Installation](#installation)
* [Command Line Usage](#command-line-usage)
* [Command line examples](#command-line-examples)
* [Command Line Examples](#command-line-examples)
* [Tutorial](#tutorial)
* [Command line reference: export](#command-line-reference-export)
* [Command Line Reference: export](#command-line-reference-export)
* [Files Created By OSXPhotos](#files-created-by-osxphotos)
* [Package Interface](#package-interface)
* [PhotosDB](#photosdb)
* [PhotoInfo](#photoinfo)
@@ -130,17 +131,17 @@ Usage: osxphotos [OPTIONS] COMMAND [ARGS]...
osxphotos: query and export your Photos library
Options:
--db <Photos database path> Specify Photos database path. Path to Photos
library/database can be specified using either
--db or directly as PHOTOS_LIBRARY positional
argument. If neither --db or PHOTOS_LIBRARY
provided, will attempt to find the library to
use in the following order: 1. last opened
library, 2. system library, 3.
~/Pictures/Photos Library.photoslibrary
--json Print output in JSON format.
-v, --version Show the version and exit.
-h, --help Show this message and exit.
--db PHOTOS_LIBRARY_PATH Specify Photos database path. Path to Photos
library/database can be specified using either
--db or directly as PHOTOS_LIBRARY positional
argument. If neither --db or PHOTOS_LIBRARY
provided, will attempt to find the library to use
in the following order: 1. last opened library, 2.
system library, 3. ~/Pictures/Photos
Library.photoslibrary
--json Print output in JSON format.
-v, --version Show the version and exit.
-h, --help Show this message and exit.
Commands:
about Print information about osxphotos including license.
@@ -148,9 +149,12 @@ Commands:
diff Compare two Photos databases and print out differences
docs Open osxphotos documentation in your browser.
dump Print list of all photos & associated info from the Photos...
exiftool Run exiftool on previously exported files to update metadata.
export Export photos from the Photos database.
exportdb Utilities for working with the osxphotos export database
help Print help; for help on commands: help <command>.
info Print out descriptive info of the Photos library database.
inspect Interactively inspect photos selected in Photos.
install Install Python packages into the same environment as osxphotos
keywords Print out keywords found in the Photos library.
labels Print out image classification labels found in the Photos...
@@ -159,7 +163,7 @@ Commands:
places Print out places found in the Photos library.
query Query the Photos database using 1 or more search options; if...
repl Run interactive osxphotos REPL shell (useful for debugging,...
run Run a python file using same environment as osxphotos
run Run a python file using same environment as osxphotos.
snap Create snapshot of Photos database to use with diff command
theme Manage osxphotos color themes.
timewarp Adjust date/time/timezone of photos in Apple Photos.
@@ -1846,7 +1850,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.49.1'
{osxphotos_version} The osxphotos version, e.g. '0.49.5'
{osxphotos_cmd_line} The full command line used to run osxphotos
The following substitutions may result in multiple values. Thus if specified
@@ -2052,6 +2056,16 @@ not be called if the --dry-run flag is set.
```
<!-- OSXPHOTOS-EXPORT-USAGE:END -->
### Files Created By OSXPhotos
The OSXPhotos command line tool creates a number of files during the course of its execution.
OSXPhotos adheres to the [XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) standard for file locations.
* `$XDG_CONFIG_HOME` or `$HOME/.config`: `osxphotos` directory containing configuration files, for example color themes for colorized output.
* `$XDG_DATA_HOME` or `$HOME/.local/share`: `osxphotos` directory containing local data files, for example, the help files displayed with `osxphotos docs`.
* Current working dir: `osxphotos_crash.log` file containing the stack trace of the last crash if OSXPhotos encounters a fatal error during execution.
* export directory (when running `osxphotos export` command): `.osxphotos_export.db` [SQLite](https://www.sqlite.org/index.html) database containing information needed to update an export and track metadata changes in exported photos. *Note*: This file may contain sensitive information such as locations and the names of persons in photos so if you are using `osxphotos export` to share with others, you may want to delete this file. You can also specify an alternate location for the export database using the `--exportdb` flag during export. See also `osxphotos help exportdb` for more information about built in utilities for working with the export database.
## Example uses of the package
```python
@@ -4012,7 +4026,7 @@ The following template field substitutions are availabe for use the templating s
|{lf}|A line feed: '\n', alias for {newline}|
|{cr}|A carriage return: '\r'|
|{crlf}|a carriage return + line feed: '\r\n'|
|{osxphotos_version}|The osxphotos version, e.g. '0.49.1'|
|{osxphotos_version}|The osxphotos version, e.g. '0.49.5'|
|{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|

View File

@@ -102,9 +102,12 @@ Alternatively, you can also run the command line utility like this: ``python3 -m
diff Compare two Photos databases and print out differences
docs Open osxphotos documentation in your browser.
dump Print list of all photos & associated info from the Photos...
exiftool Run exiftool on previously exported files to update metadata.
export Export photos from the Photos database.
exportdb Utilities for working with the osxphotos export database
help Print help; for help on commands: help <command>.
info Print out descriptive info of the Photos library database.
inspect Interactively inspect photos selected in Photos.
install Install Python packages into the same environment as osxphotos
keywords Print out keywords found in the Photos library.
labels Print out image classification labels found in the Photos...

View File

@@ -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: a77e6404d00931c687c8320621f91963
config: 453784a6da675ee114829e25c5e16bfc
tags: 645f666f9bcd5a90fca523b33c5a78b7

View File

@@ -5,7 +5,7 @@
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../genindex.html" /><link rel="search" title="Search" href="../search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>Overview: module code - osxphotos 0.49.1 documentation</title>
<title>Overview: module code - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css" />
@@ -123,7 +123,7 @@
</label>
</div>
<div class="header-center">
<a href="../index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="../index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -146,7 +146,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="../index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="../search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

View File

@@ -5,7 +5,7 @@
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../../genindex.html" /><link rel="search" title="Search" href="../../search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>osxphotos.export_db - osxphotos 0.49.1 documentation</title>
<title>osxphotos.export_db - osxphotos 0.49.4 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="../../_static/copybutton.css" />
@@ -123,7 +123,7 @@
</label>
</div>
<div class="header-center">
<a href="../../index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.49.4 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -146,7 +146,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="../../index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.4 documentation</span>
</a><form class="sidebar-search-container" method="get" action="../../search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -211,7 +211,7 @@
<span class="kn">from</span> <span class="nn">io</span> <span class="kn">import</span> <span class="n">StringIO</span>
<span class="kn">from</span> <span class="nn">sqlite3</span> <span class="kn">import</span> <span class="n">Error</span>
<span class="kn">from</span> <span class="nn">tempfile</span> <span class="kn">import</span> <span class="n">TemporaryDirectory</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">,</span> <span class="n">Union</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">,</span> <span class="n">Union</span><span class="p">,</span> <span class="n">List</span>
<span class="kn">from</span> <span class="nn">tenacity</span> <span class="kn">import</span> <span class="n">retry</span><span class="p">,</span> <span class="n">stop_after_attempt</span>
@@ -226,7 +226,7 @@
<span class="s2">"ExportDBTemp"</span><span class="p">,</span>
<span class="p">]</span>
<span class="n">OSXPHOTOS_EXPORTDB_VERSION</span> <span class="o">=</span> <span class="s2">"7.0"</span>
<span class="n">OSXPHOTOS_EXPORTDB_VERSION</span> <span class="o">=</span> <span class="s2">"7.1"</span>
<span class="n">OSXPHOTOS_ABOUT_STRING</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Created by osxphotos version </span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> (https://github.com/RhetTbull/osxphotos) on </span><span class="si">{</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="si">}</span><span class="s2">"</span>
<span class="c1"># max retry attempts for methods which use tenacity.retry</span>
@@ -367,6 +367,17 @@
<span class="n">uuid</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">return</span> <span class="n">uuid</span></div>
<div class="viewcode-block" id="ExportDB.get_files_for_uuid"><a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_files_for_uuid">[docs]</a> <span class="k">def</span> <span class="nf">get_files_for_uuid</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="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">:</span>
<span class="sd">"""query database for UUID and return list of files associated with UUID or empty list"""</span>
<span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</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="s2">"SELECT filepath FROM export_data WHERE uuid = ?"</span><span class="p">,</span>
<span class="p">(</span><span class="n">uuid</span><span class="p">,),</span>
<span class="p">)</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="k">return</span> <span class="p">[</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">export_dir</span><span class="p">,</span> <span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">]</span></div>
<div class="viewcode-block" id="ExportDB.get_photoinfo_for_uuid"><a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_photoinfo_for_uuid">[docs]</a> <span class="k">def</span> <span class="nf">get_photoinfo_for_uuid</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 the photoinfo JSON struct for a UUID"""</span>
<span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span>
@@ -478,6 +489,20 @@
<span class="n">results</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">return</span> <span class="n">results</span></div>
<div class="viewcode-block" id="ExportDB.get_exported_files"><a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_exported_files">[docs]</a> <span class="k">def</span> <span class="nf">get_exported_files</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Returns tuple of (uuid, filepath) for all paths of all exported files tracked in the database"""</span>
<span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</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="s2">"SELECT uuid, filepath FROM export_data"</span><span class="p">)</span>
<span class="k">except</span> <span class="n">Error</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">while</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
<span class="k">yield</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</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">export_dir</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">return</span></div>
<div class="viewcode-block" id="ExportDB.close"><a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.close">[docs]</a> <span class="k">def</span> <span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""close the database connection"""</span>
<span class="k">try</span><span class="p">:</span>
@@ -495,7 +520,7 @@
<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">dbfile</span><span class="p">):</span>
<span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_db_connection</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">conn</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">"Error getting connection to database </span><span class="si">{dbfile}</span><span class="s2">"</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Error getting connection to database </span><span class="si">{</span><span class="n">dbfile</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">_create_or_migrate_db_tables</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">()</span>
@@ -652,6 +677,10 @@
<span class="c1"># create report_data table</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_migrate_6_0_to_7_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="k">if</span> <span class="n">version</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="s2">"7.1"</span><span class="p">:</span>
<span class="c1"># add timestamp to export_data</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_migrate_7_0_to_7_1</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"VACUUM;"</span><span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
@@ -869,6 +898,32 @@
<span class="k">except</span> <span class="n">Error</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_migrate_7_0_to_7_1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</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="s2">"""ALTER TABLE export_data ADD COLUMN timestamp DATETIME;"""</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="sd">"""</span>
<span class="sd"> CREATE TRIGGER insert_timestamp_trigger</span>
<span class="sd"> AFTER INSERT ON export_data</span>
<span class="sd"> BEGIN</span>
<span class="sd"> UPDATE export_data SET timestamp = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') WHERE id = NEW.id;</span>
<span class="sd"> END;</span>
<span class="sd"> """</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="sd">"""</span>
<span class="sd"> CREATE TRIGGER update_timestamp_trigger</span>
<span class="sd"> AFTER UPDATE On export_data</span>
<span class="sd"> BEGIN</span>
<span class="sd"> UPDATE export_data SET timestamp = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') WHERE id = NEW.id;</span>
<span class="sd"> END;</span>
<span class="sd"> """</span>
<span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="k">except</span> <span class="n">Error</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_perform_db_maintenace</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">):</span>
<span class="sd">"""Perform database maintenance"""</span>
<span class="k">try</span><span class="p">:</span>
@@ -1230,6 +1285,21 @@
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
<span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">timestamp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""returns the timestamp value"""</span>
<span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="s2">"SELECT timestamp FROM export_data WHERE filepath_normalized = ?;"</span><span class="p">,</span>
<span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
<span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
<span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</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">"No timestamp found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">"</span>
<span class="p">)</span>
<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 of self"""</span>
<span class="n">exifdata</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exifdata</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">exifdata</span> <span class="k">else</span> <span class="kc">None</span>
@@ -1238,6 +1308,7 @@
<span class="s2">"filepath"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filepath</span><span class="p">,</span>
<span class="s2">"filepath_normalized"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filepath_normalized</span><span class="p">,</span>
<span class="s2">"uuid"</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="s2">"timestamp"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">timestamp</span><span class="p">,</span>
<span class="s2">"digest"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">digest</span><span class="p">,</span>
<span class="s2">"src_sig"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">src_sig</span><span class="p">,</span>
<span class="s2">"dest_sig"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">dest_sig</span><span class="p">,</span>

View File

@@ -5,7 +5,7 @@
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../../genindex.html" /><link rel="search" title="Search" href="../../search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>osxphotos.photoexporter - osxphotos 0.49.0 documentation</title>
<title>osxphotos.photoexporter - osxphotos 0.49.2 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="../../_static/copybutton.css" />
@@ -123,7 +123,7 @@
</label>
</div>
<div class="header-center">
<a href="../../index.html"><div class="brand">osxphotos 0.49.0 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.49.2 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -146,7 +146,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="../../index.html">
<span class="sidebar-brand-text">osxphotos 0.49.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.2 documentation</span>
</a><form class="sidebar-search-container" method="get" action="../../search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -931,7 +931,7 @@
<span class="k">return</span> <span class="n">ShouldUpdate</span><span class="o">.</span><span class="n">EXPORT_OPTIONS_DIFFERENT</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">exiftool</span><span class="p">:</span>
<span class="n">current_exifdata</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_json_sidecar</span><span class="p">(</span><span class="n">options</span><span class="o">=</span><span class="n">options</span><span class="p">)</span>
<span class="n">current_exifdata</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exiftool_json_sidecar</span><span class="p">(</span><span class="n">options</span><span class="o">=</span><span class="n">options</span><span class="p">)</span>
<span class="n">rv</span> <span class="o">=</span> <span class="n">current_exifdata</span> <span class="o">!=</span> <span class="n">file_record</span><span class="o">.</span><span class="n">exifdata</span>
<span class="c1"># if using exiftool, don't need to continue checking edited below</span>
<span class="c1"># as exiftool will be used to update edited file</span>
@@ -1339,7 +1339,7 @@
<span class="c1"># point src to the tmp_file so that the original source is not modified</span>
<span class="c1"># and the export grabs the new file</span>
<span class="n">src</span> <span class="o">=</span> <span class="n">tmp_file</span>
<span class="n">exif_results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_write_exif_metadata_to_file</span><span class="p">(</span>
<span class="n">exif_results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">write_exiftool_metadata_to_file</span><span class="p">(</span>
<span class="n">src</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="n">options</span>
<span class="p">)</span>
@@ -1381,7 +1381,7 @@
<span class="k">if</span> <span class="ow">not</span> <span class="n">options</span><span class="o">.</span><span class="n">ignore_signature</span><span class="p">:</span>
<span class="n">rec</span><span class="o">.</span><span class="n">dest_sig</span> <span class="o">=</span> <span class="n">fileutil</span><span class="o">.</span><span class="n">file_sig</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">exiftool</span><span class="p">:</span>
<span class="n">rec</span><span class="o">.</span><span class="n">exifdata</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_json_sidecar</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="n">rec</span><span class="o">.</span><span class="n">exifdata</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exiftool_json_sidecar</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">hexdigest</span> <span class="o">!=</span> <span class="n">rec</span><span class="o">.</span><span class="n">digest</span><span class="p">:</span>
<span class="n">results</span><span class="o">.</span><span class="n">metadata_changed</span> <span class="o">=</span> <span class="p">[</span><span class="n">dest_str</span><span class="p">]</span>
<span class="n">rec</span><span class="o">.</span><span class="n">digest</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">hexdigest</span>
@@ -1516,7 +1516,7 @@
<span class="n">sidecar_filename</span> <span class="o">=</span> <span class="n">dest</span><span class="o">.</span><span class="n">parent</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="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">dest</span><span class="o">.</span><span class="n">stem</span><span class="si">}{</span><span class="n">dest_suffix</span><span class="si">}</span><span class="s2">.json"</span>
<span class="p">)</span>
<span class="n">sidecar_str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_json_sidecar</span><span class="p">(</span>
<span class="n">sidecar_str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exiftool_json_sidecar</span><span class="p">(</span>
<span class="n">filename</span><span class="o">=</span><span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="n">options</span>
<span class="p">)</span>
<span class="n">sidecars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
@@ -1533,7 +1533,7 @@
<span class="n">sidecar_filename</span> <span class="o">=</span> <span class="n">dest</span><span class="o">.</span><span class="n">parent</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="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">dest</span><span class="o">.</span><span class="n">stem</span><span class="si">}{</span><span class="n">dest_suffix</span><span class="si">}</span><span class="s2">.json"</span>
<span class="p">)</span>
<span class="n">sidecar_str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_json_sidecar</span><span class="p">(</span>
<span class="n">sidecar_str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exiftool_json_sidecar</span><span class="p">(</span>
<span class="n">tag_groups</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="n">options</span>
<span class="p">)</span>
<span class="n">sidecars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
@@ -1632,19 +1632,20 @@
<span class="k">return</span> <span class="n">results</span>
<span class="k">def</span> <span class="nf">_write_exif_metadata_to_file</span><span class="p">(</span>
<div class="viewcode-block" id="PhotoExporter.write_exiftool_metadata_to_file"><a class="viewcode-back" href="../../reference.html#osxphotos.PhotoExporter.write_exiftool_metadata_to_file">[docs]</a> <span class="k">def</span> <span class="nf">write_exiftool_metadata_to_file</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">src</span><span class="p">,</span>
<span class="n">dest</span><span class="p">,</span>
<span class="n">options</span><span class="p">:</span> <span class="n">ExportOptions</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ExportResults</span><span class="p">:</span>
<span class="sd">"""Write exif metadata to file using exiftool</span>
<span class="sd">"""Write exif metadata to src file using exiftool</span>
<span class="sd"> Note: this method modifies src so src must be a copy of the original file;</span>
<span class="sd"> Caution: This method modifies *src*, not *dest*, </span>
<span class="sd"> so src must be a copy of the original file if you don't want the source modified;</span>
<span class="sd"> it also does not write to dest (dest is the intended destination for purposes of</span>
<span class="sd"> referencing the export database. This allows the exiftool update to be done on the</span>
<span class="sd"> local machine prior to being copied to the export destination which may be on a</span>
<span class="sd"> network drive or other slower external storage."""</span>
<span class="sd"> network drive or other slower external storage)."""</span>
<span class="n">verbose</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">verbose</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span>
<span class="n">exiftool_results</span> <span class="o">=</span> <span class="n">ExportResults</span><span class="p">()</span>
@@ -1676,7 +1677,7 @@
<span class="n">exiftool_results</span><span class="o">.</span><span class="n">exif_updated</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span>
<span class="n">exiftool_results</span><span class="o">.</span><span class="n">to_touch</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span>
<span class="k">return</span> <span class="n">exiftool_results</span>
<span class="k">return</span> <span class="n">exiftool_results</span></div>
<span class="k">def</span> <span class="nf">_should_run_exiftool</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">ExportOptions</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="sd">"""Return True if exiftool should be run to update metadata"""</span>
@@ -1687,7 +1688,7 @@
<span class="n">old_data</span> <span class="o">=</span> <span class="n">exif_record</span><span class="o">.</span><span class="n">exifdata</span> <span class="k">if</span> <span class="n">exif_record</span> <span class="k">else</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">old_data</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">old_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">old_data</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">current_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_json_sidecar</span><span class="p">(</span><span class="n">options</span><span class="o">=</span><span class="n">options</span><span class="p">))</span>
<span class="n">current_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exiftool_json_sidecar</span><span class="p">(</span><span class="n">options</span><span class="o">=</span><span class="n">options</span><span class="p">))</span>
<span class="n">current_data</span> <span class="o">=</span> <span class="n">current_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="n">old_data</span> <span class="o">!=</span> <span class="n">current_data</span><span class="p">:</span>
<span class="n">files_are_different</span> <span class="o">=</span> <span class="kc">True</span>
@@ -2027,7 +2028,7 @@
<span class="k">pass</span>
<span class="k">return</span> <span class="n">persons</span>
<span class="k">def</span> <span class="nf">_exiftool_json_sidecar</span><span class="p">(</span>
<div class="viewcode-block" id="PhotoExporter.exiftool_json_sidecar"><a class="viewcode-back" href="../../reference.html#osxphotos.PhotoExporter.exiftool_json_sidecar">[docs]</a> <span class="k">def</span> <span class="nf">exiftool_json_sidecar</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">options</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">ExportOptions</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">tag_groups</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
@@ -2079,7 +2080,7 @@
<span class="n">exif_new</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
<span class="n">exif</span> <span class="o">=</span> <span class="n">exif_new</span>
<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="n">exif</span><span class="p">])</span>
<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="n">exif</span><span class="p">])</span></div>
<span class="k">def</span> <span class="nf">_xmp_sidecar</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>

View File

@@ -320,7 +320,7 @@ Template Substitutions
* - {crlf}
- a carriage return + line feed: '\r\n'
* - {osxphotos_version}
- The osxphotos version, e.g. '0.49.1'
- The osxphotos version, e.g. '0.49.5'
* - {osxphotos_cmd_line}
- The full command line used to run osxphotos
* - {album}

View File

@@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.49.1',
VERSION: '0.49.5',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
BUILDER: 'html',

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Template System" href="template_help.html" /><link rel="prev" title="OSXPhotos Tutorial" href="tutorial.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Command Line Interface (CLI) - osxphotos 0.49.1 documentation</title>
<title>OSXPhotos Command Line Interface (CLI) - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -343,6 +343,138 @@ library specified by db to the database specified by DB2</p>
<dd><p>Optional argument(s)</p>
</dd></dl>
</section>
<section id="osxphotos-exiftool">
<h3>exiftool<a class="headerlink" href="#osxphotos-exiftool" title="Permalink to this headline">#</a></h3>
<p>Run exiftool on previously exported files to update metadata.</p>
<p>If you previously exported photos with <cite>osxphotos export</cite> but did not include the
<cite>exiftool</cite> option and you now want to update the metadata of the exported files with
exiftool, you can use this command to do so.</p>
<p>If you simply re-run the <cite>osxphotos export</cite> with <cite>update</cite> and <cite>exiftool</cite>, osxphotos will
re-export all photos because it will detect that the previously exported photos do not have the
exiftool metadata updates. This command will run exiftool on the previously exported photos
to update all metadata then will update the export database so that using <cite>exiftool update</cite>
with <cite>osxphotos export</cite> in the future will work correctly and not unnecessarily re-export photos.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>osxphotos exiftool <span class="o">[</span>OPTIONS<span class="o">]</span> EXPORT_DIRECTORY
</pre></div>
</div>
<p class="rubric">Options</p>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-db-config">
<span class="sig-name descname"><span class="pre">--db-config</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-db-config" title="Permalink to this definition">#</a></dt>
<dd><p>Load configuration options from the export database to match the last export; If any other command line options are used in conjunction with db-config, they will override the corresponding values loaded from the export database; see also load-config.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-load-config">
<span class="sig-name descname"><span class="pre">--load-config</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;CONFIG_FILE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-load-config" title="Permalink to this definition">#</a></dt>
<dd><p>Load options from file as written with save-config. If any other command line options are used in conjunction with load-config, they will override the corresponding values in the config file; see also db-config.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-save-config">
<span class="sig-name descname"><span class="pre">--save-config</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;CONFIG_FILE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-save-config" title="Permalink to this definition">#</a></dt>
<dd><p>Save options to file for use with load-config. File format is TOML.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-exiftool-path">
<span class="sig-name descname"><span class="pre">--exiftool-path</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;EXIFTOOL_PATH&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-exiftool-path" title="Permalink to this definition">#</a></dt>
<dd><p>Optionally specify path to exiftool; if not provided, will look for exiftool in $PATH.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-exiftool-option">
<span class="sig-name descname"><span class="pre">--exiftool-option</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;OPTION&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-exiftool-option" title="Permalink to this definition">#</a></dt>
<dd><p>Optional flag/option to pass to exiftool when using exiftool. For example, exiftool-option -m to ignore minor warnings. Specify these as you would on the exiftool command line. See exiftool docs at <a class="reference external" href="https://exiftool.org/exiftool_pod.html">https://exiftool.org/exiftool_pod.html</a> for full list of options. More than one option may be specified by repeating the option, e.g. exiftool-option -m exiftool-option -F.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-exiftool-merge-keywords">
<span class="sig-name descname"><span class="pre">--exiftool-merge-keywords</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-exiftool-merge-keywords" title="Permalink to this definition">#</a></dt>
<dd><p>Merge any keywords found in the original file with keywords used for exiftool and sidecar.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-exiftool-merge-persons">
<span class="sig-name descname"><span class="pre">--exiftool-merge-persons</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-exiftool-merge-persons" title="Permalink to this definition">#</a></dt>
<dd><p>Merge any persons found in the original file with persons used for exiftool and sidecar.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-ignore-date-modified">
<span class="sig-name descname"><span class="pre">--ignore-date-modified</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-ignore-date-modified" title="Permalink to this definition">#</a></dt>
<dd><p>If used with exiftool or sidecar, will ignore the photo modification date and set EXIF:ModifyDate to EXIF:DateTimeOriginal; this is consistent with how Photos handles the EXIF:ModifyDate tag.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-person-keyword">
<span class="sig-name descname"><span class="pre">--person-keyword</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-person-keyword" title="Permalink to this definition">#</a></dt>
<dd><p>Use person in image as keyword/tag when exporting metadata.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-album-keyword">
<span class="sig-name descname"><span class="pre">--album-keyword</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-album-keyword" title="Permalink to this definition">#</a></dt>
<dd><p>Use album name as keyword/tag when exporting metadata.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-keyword-template">
<span class="sig-name descname"><span class="pre">--keyword-template</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-keyword-template" title="Permalink to this definition">#</a></dt>
<dd><p>For use with exiftool, sidecar; specify a template string to use as keyword in the form {name,DEFAULT} This is the same format as directory. For example, if you wanted to add the full path to the folder and album photo is contained in as a keyword when exporting you could specify keyword-template “{folder_album}” You may specify more than one template, for example keyword-template “{folder_album}” keyword-template “{created.year}”. See replace-keywords and Templating System below.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-replace-keywords">
<span class="sig-name descname"><span class="pre">--replace-keywords</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-replace-keywords" title="Permalink to this definition">#</a></dt>
<dd><p>Replace keywords with any values specified with keyword-template. By default, keyword-template will add keywords to any keywords already associated with the photo. If replace-keywords is specified, values from keyword-template will replace any existing keywords instead of adding additional keywords.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-description-template">
<span class="sig-name descname"><span class="pre">--description-template</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-description-template" title="Permalink to this definition">#</a></dt>
<dd><p>For use with exiftool, sidecar; specify a template string to use as description in the form {name,DEFAULT} This is the same format as directory. For example, if you wanted to append exported with osxphotos on [todays date] to the description, you could specify description-template “{descr} exported with osxphotos on {today.date}” See Templating System below.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-exportdb">
<span class="sig-name descname"><span class="pre">--exportdb</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;exportdb&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-exportdb" title="Permalink to this definition">#</a></dt>
<dd><p>Optional path to export database (if not in the default location in the export directory).</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-report">
<span class="sig-name descname"><span class="pre">--report</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REPORT_FILE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-report" title="Permalink to this definition">#</a></dt>
<dd><p>Write a report of all files that were exported. The extension of the report filename will be used to determine the format. Valid extensions are: .csv (CSV file), .json (JSON), .db and .sqlite (SQLite database). REPORT_FILE may be a template string (see Templating System), for example, report export_{today.date}.csv will write a CSV report file named with todays date. See also append.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-append">
<span class="sig-name descname"><span class="pre">--append</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-append" title="Permalink to this definition">#</a></dt>
<dd><p>If used with report, add data to existing report file instead of overwriting it. See also report.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-V">
<span id="cmdoption-osxphotos-exiftool-v"></span><span id="cmdoption-osxphotos-exiftool-verbose"></span><span class="sig-name descname"><span class="pre">-V</span></span><span class="sig-prename descclassname"></span><span class="sig-prename descclassname"><span class="pre">,</span> </span><span class="sig-name descname"><span class="pre">--verbose</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-V" title="Permalink to this definition">#</a></dt>
<dd><p>Print verbose output.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-timestamp">
<span class="sig-name descname"><span class="pre">--timestamp</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-timestamp" title="Permalink to this definition">#</a></dt>
<dd><p>Add time stamp to verbose output</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-dry-run">
<span class="sig-name descname"><span class="pre">--dry-run</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-dry-run" title="Permalink to this definition">#</a></dt>
<dd><p>Run in dry-run mode (dont actually update files), e.g. for use with update-signatures.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-theme">
<span class="sig-name descname"><span class="pre">--theme</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;THEME&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-theme" title="Permalink to this definition">#</a></dt>
<dd><p>Specify the color theme to use for verbose output. Valid themes are dark, light, mono, and plain. Defaults to dark or light depending on system dark mode setting.</p>
<dl class="field-list simple">
<dt class="field-odd">Options</dt>
<dd class="field-odd"><p>dark | light | mono | plain</p>
</dd>
</dl>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-db">
<span class="sig-name descname"><span class="pre">--db</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;PHOTOS_LIBRARY_PATH&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-db" title="Permalink to this definition">#</a></dt>
<dd><p>Specify Photos database path. Path to Photos library/database can be specified using either db or directly as PHOTOS_LIBRARY positional argument. If neither db or PHOTOS_LIBRARY provided, will attempt to find the library to use in the following order: 1. last opened library, 2. system library, 3. ~/Pictures/Photos Library.photoslibrary</p>
</dd></dl>
<p class="rubric">Arguments</p>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exiftool-arg-EXPORT_DIRECTORY">
<span id="cmdoption-osxphotos-exiftool-arg-export-directory"></span><span class="sig-name descname"><span class="pre">EXPORT_DIRECTORY</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-exiftool-arg-EXPORT_DIRECTORY" title="Permalink to this definition">#</a></dt>
<dd><p>Required argument</p>
</dd></dl>
</section>
<section id="osxphotos-export">
<h3>export<a class="headerlink" href="#osxphotos-export" title="Permalink to this headline">#</a></h3>
<p>Export photos from the Photos database.
@@ -1146,6 +1278,16 @@ to modify this behavior.</p>
<dd><p>Print information about FILE_PATH contained in the database.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exportdb-uuid-files">
<span class="sig-name descname"><span class="pre">--uuid-files</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;UUID&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exportdb-uuid-files" title="Permalink to this definition">#</a></dt>
<dd><p>List exported files associated with UUID.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exportdb-uuid-info">
<span class="sig-name descname"><span class="pre">--uuid-info</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;UUID&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exportdb-uuid-info" title="Permalink to this definition">#</a></dt>
<dd><p>Print information about UUID contained in the database.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-exportdb-report">
<span class="sig-name descname"><span class="pre">--report</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REPORT_FILE</span> <span class="pre">RUN_ID&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-exportdb-report" title="Permalink to this definition">#</a></dt>
<dd><p>Generate an export report as <cite>osxphotos export … report REPORT_FILE</cite> would have done. This allows you to re-create an export report if you didnt use the report option when running <cite>osxphotos export</cite>. The extension of the report file is used to determine the format. Valid extensions are: .csv (CSV file), .json (JSON), .db and .sqlite (SQLite database). RUN_ID may be any integer from -10 to 0 specifying which run to use. For example, <cite>report report.csv 0</cite> will generate a CSV report for the last run and <cite>report report.json -1</cite> will generate a JSON report for the second-to-last run (one run prior to last run). REPORT_FILE may be a template string (see Templating System), for example, report export_{today.date}.csv will write a CSV report file named with todays date. See also append.</p>
@@ -1229,6 +1371,38 @@ to modify this behavior.</p>
<dd><p>Optional argument(s)</p>
</dd></dl>
</section>
<section id="osxphotos-inspect">
<h3>inspect<a class="headerlink" href="#osxphotos-inspect" title="Permalink to this headline">#</a></h3>
<p>Interactively inspect photos selected in Photos.</p>
<p>Open Photos then run <cite>osxphotos inspect</cite> in the terminal.
As you select a photo in Photos, inspect will display metadata about the photo.
Press Ctrl+C to exit when done.
Works best with a modern terminal like iTerm2 or Kitty.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>osxphotos inspect <span class="o">[</span>OPTIONS<span class="o">]</span>
</pre></div>
</div>
<p class="rubric">Options</p>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-inspect-t">
<span id="cmdoption-osxphotos-inspect-detect-text"></span><span class="sig-name descname"><span class="pre">-t</span></span><span class="sig-prename descclassname"></span><span class="sig-prename descclassname"><span class="pre">,</span> </span><span class="sig-name descname"><span class="pre">--detect-text</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-inspect-t" title="Permalink to this definition">#</a></dt>
<dd><p>Detect text in photos</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-inspect-theme">
<span class="sig-name descname"><span class="pre">--theme</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;THEME&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-inspect-theme" title="Permalink to this definition">#</a></dt>
<dd><p>Specify the color theme to use for verbose output. Valid themes are dark, light, mono, and plain. Defaults to dark or light depending on system dark mode setting.</p>
<dl class="field-list simple">
<dt class="field-odd">Options</dt>
<dd class="field-odd"><p>dark | light | mono | plain</p>
</dd>
</dl>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-inspect-db">
<span class="sig-name descname"><span class="pre">--db</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;PHOTOS_LIBRARY_PATH&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-inspect-db" title="Permalink to this definition">#</a></dt>
<dd><p>Specify Photos database path. Path to Photos library/database can be specified using either db or directly as PHOTOS_LIBRARY positional argument. If neither db or PHOTOS_LIBRARY provided, will attempt to find the library to use in the following order: 1. last opened library, 2. system library, 3. ~/Pictures/Photos Library.photoslibrary</p>
</dd></dl>
</section>
<section id="osxphotos-install">
<h3>install<a class="headerlink" href="#osxphotos-install" title="Permalink to this headline">#</a></h3>
<p>Install Python packages into the same environment as osxphotos</p>
@@ -2568,10 +2742,12 @@ Commands:
<li><a class="reference internal" href="#osxphotos-diff">diff</a></li>
<li><a class="reference internal" href="#osxphotos-docs">docs</a></li>
<li><a class="reference internal" href="#osxphotos-dump">dump</a></li>
<li><a class="reference internal" href="#osxphotos-exiftool">exiftool</a></li>
<li><a class="reference internal" href="#osxphotos-export">export</a></li>
<li><a class="reference internal" href="#osxphotos-exportdb">exportdb</a></li>
<li><a class="reference internal" href="#osxphotos-help">help</a></li>
<li><a class="reference internal" href="#osxphotos-info">info</a></li>
<li><a class="reference internal" href="#osxphotos-inspect">inspect</a></li>
<li><a class="reference internal" href="#osxphotos-install">install</a></li>
<li><a class="reference internal" href="#osxphotos-keywords">keywords</a></li>
<li><a class="reference internal" href="#osxphotos-labels">labels</a></li>

View File

@@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Index - osxphotos 0.49.1 documentation</title>
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Index - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -122,7 +122,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -145,7 +145,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -279,6 +279,8 @@
--album-keyword
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-album-keyword">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-album-keyword">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -286,6 +288,8 @@
--append
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-append">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-append">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-append">osxphotos-exportdb command line option</a>
@@ -392,10 +396,14 @@
<li><a href="cli.html#cmdoption-osxphotos-diff-db">osxphotos-diff command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-dump-db">osxphotos-dump command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-db">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-db">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-info-db">osxphotos-info command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-inspect-db">osxphotos-inspect command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-keywords-db">osxphotos-keywords command line option</a>
</li>
@@ -410,6 +418,13 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-db">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-snap-db">osxphotos-snap command line option</a>
</li>
</ul></li>
<li>
--db-config
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-db-config">osxphotos-exiftool command line option</a>
</li>
</ul></li>
<li>
@@ -467,7 +482,16 @@
--description-template
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-description-template">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-description-template">osxphotos-export command line option</a>
</li>
</ul></li>
<li>
--detect-text
<ul>
<li><a href="cli.html#cmdoption-osxphotos-inspect-t">osxphotos-inspect command line option</a>
</li>
</ul></li>
<li>
@@ -488,6 +512,8 @@
--dry-run
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-dry-run">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-dry-run">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-dry-run">osxphotos-exportdb command line option</a>
@@ -558,6 +584,8 @@
--exiftool-merge-keywords
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-merge-keywords">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-exiftool-merge-keywords">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -565,6 +593,8 @@
--exiftool-merge-persons
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-merge-persons">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-exiftool-merge-persons">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -572,6 +602,8 @@
--exiftool-option
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-option">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-exiftool-option">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -579,6 +611,8 @@
--exiftool-path
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-path">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-exiftool-path">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-e">osxphotos-timewarp command line option</a>
@@ -609,6 +643,8 @@
--exportdb
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exportdb">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-exportdb">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -788,6 +824,8 @@
--ignore-date-modified
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-ignore-date-modified">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-ignore-date-modified">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -897,6 +935,8 @@
--keyword-template
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-keyword-template">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-keyword-template">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -954,6 +994,8 @@
--load-config
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-load-config">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-load-config">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -1358,6 +1400,8 @@
--person-keyword
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-person-keyword">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-person-keyword">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -1492,6 +1536,8 @@
--replace-keywords
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-replace-keywords">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-replace-keywords">osxphotos-export command line option</a>
</li>
</ul></li>
@@ -1499,6 +1545,8 @@
--report
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-report">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-report">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-report">osxphotos-exportdb command line option</a>
@@ -1522,6 +1570,8 @@
--save-config
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-save-config">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-save-config">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-save-config">osxphotos-exportdb command line option</a>
@@ -1670,7 +1720,11 @@
--theme
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-theme">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-theme">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-inspect-theme">osxphotos-inspect command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-theme">osxphotos-timewarp command line option</a>
</li>
@@ -1704,6 +1758,8 @@
--timestamp
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-timestamp">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-timestamp">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-timestamp">osxphotos-timewarp command line option</a>
@@ -1827,6 +1883,13 @@
<li><a href="cli.html#cmdoption-osxphotos-query-uuid">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-uuid">osxphotos-repl command line option</a>
</li>
</ul></li>
<li>
--uuid-files
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-uuid-files">osxphotos-exportdb command line option</a>
</li>
</ul></li>
<li>
@@ -1838,6 +1901,13 @@
<li><a href="cli.html#cmdoption-osxphotos-query-uuid-from-file">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-uuid-from-file">osxphotos-repl command line option</a>
</li>
</ul></li>
<li>
--uuid-info
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-uuid-info">osxphotos-exportdb command line option</a>
</li>
</ul></li>
<li>
@@ -1852,6 +1922,8 @@
<ul>
<li><a href="cli.html#cmdoption-osxphotos-diff-V">osxphotos-diff command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-V">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-V">osxphotos-export command line option</a>
</li>
@@ -2025,6 +2097,8 @@
-t
<ul>
<li><a href="cli.html#cmdoption-osxphotos-inspect-t">osxphotos-inspect command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-t">osxphotos-timewarp command line option</a>
</li>
</ul></li>
@@ -2040,6 +2114,8 @@
<ul>
<li><a href="cli.html#cmdoption-osxphotos-diff-V">osxphotos-diff command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-V">osxphotos-exiftool command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-V">osxphotos-export command line option</a>
</li>
@@ -2306,14 +2382,16 @@
</ul></li>
<li><a href="reference.html#osxphotos.ExportOptions.exiftool_flags">exiftool_flags (osxphotos.ExportOptions attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotoExporter.exiftool_json_sidecar">exiftool_json_sidecar() (osxphotos.PhotoExporter method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoExporter.export">export() (osxphotos.PhotoExporter method)</a>
<ul>
<li><a href="reference.html#osxphotos.PhotoInfo.export">(osxphotos.PhotoInfo method)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.ExportOptions.export_as_hardlink">export_as_hardlink (osxphotos.ExportOptions attribute)</a>
</li>
<li>
@@ -2327,6 +2405,13 @@
</li>
<li><a href="reference.html#osxphotos.ExportDB.export_dir">export_dir (osxphotos.ExportDB property)</a>
</li>
<li>
EXPORT_DIRECTORY
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-arg-EXPORT_DIRECTORY">osxphotos-exiftool command line option</a>
</li>
</ul></li>
<li><a href="reference.html#osxphotos.ExportDB">ExportDB (class in osxphotos)</a>
</li>
<li><a href="reference.html#osxphotos.ExportOptions">ExportOptions (class in osxphotos)</a>
@@ -2402,19 +2487,23 @@
<li><a href="reference.html#osxphotos.PhotosDB.get_db_connection">get_db_connection() (osxphotos.PhotosDB method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.get_export_results">get_export_results() (osxphotos.ExportDB method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.get_exported_files">get_exported_files() (osxphotos.ExportDB method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.get_file_record">get_file_record() (osxphotos.ExportDB method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.get_files_for_uuid">get_files_for_uuid() (osxphotos.ExportDB method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoTemplate.get_media_type">get_media_type() (osxphotos.PhotoTemplate method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotosDB.get_photo">get_photo() (osxphotos.PhotosDB method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoTemplate.get_photo_video_type">get_photo_video_type() (osxphotos.PhotoTemplate method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.get_photoinfo_for_uuid">get_photoinfo_for_uuid() (osxphotos.ExportDB method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.ExportDB.get_photoinfo_for_uuid">get_photoinfo_for_uuid() (osxphotos.ExportDB method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.get_previous_uuids">get_previous_uuids() (osxphotos.ExportDB method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoTemplate.get_template_value">get_template_value() (osxphotos.PhotoTemplate method)</a>
@@ -2811,6 +2900,57 @@
<li><a href="cli.html#cmdoption-osxphotos-dump-json">--json</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-dump-arg-PHOTOS_LIBRARY">PHOTOS_LIBRARY</a>
</li>
</ul></li>
<li>
osxphotos-exiftool command line option
<ul>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-album-keyword">--album-keyword</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-append">--append</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-db">--db</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-db-config">--db-config</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-description-template">--description-template</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-dry-run">--dry-run</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-merge-keywords">--exiftool-merge-keywords</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-merge-persons">--exiftool-merge-persons</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-option">--exiftool-option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exiftool-path">--exiftool-path</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-exportdb">--exportdb</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-ignore-date-modified">--ignore-date-modified</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-keyword-template">--keyword-template</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-load-config">--load-config</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-person-keyword">--person-keyword</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-replace-keywords">--replace-keywords</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-report">--report</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-save-config">--save-config</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-theme">--theme</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-timestamp">--timestamp</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-V">--verbose</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-V">-V</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exiftool-arg-EXPORT_DIRECTORY">EXPORT_DIRECTORY</a>
</li>
</ul></li>
<li>
@@ -3137,6 +3277,10 @@
<li><a href="cli.html#cmdoption-osxphotos-exportdb-touch-file">--touch-file</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-update-signatures">--update-signatures</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-uuid-files">--uuid-files</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-uuid-info">--uuid-info</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-exportdb-vacuum">--vacuum</a>
</li>
@@ -3167,6 +3311,19 @@
<li><a href="cli.html#cmdoption-osxphotos-info-json">--json</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-info-arg-PHOTOS_LIBRARY">PHOTOS_LIBRARY</a>
</li>
</ul></li>
<li>
osxphotos-inspect command line option
<ul>
<li><a href="cli.html#cmdoption-osxphotos-inspect-db">--db</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-inspect-t">--detect-text</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-inspect-theme">--theme</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-inspect-t">-t</a>
</li>
</ul></li>
<li>
@@ -3202,6 +3359,8 @@
<li><a href="cli.html#cmdoption-osxphotos-labels-arg-PHOTOS_LIBRARY">PHOTOS_LIBRARY</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
osxphotos-list command line option
@@ -3404,8 +3563,6 @@
<li><a href="cli.html#cmdoption-osxphotos-query-arg-PHOTOS_LIBRARY">PHOTOS_LIBRARY</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
osxphotos-repl command line option
@@ -4150,6 +4307,8 @@
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotoInfo.width">width (osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoExporter.write_exiftool_metadata_to_file">write_exiftool_metadata_to_file() (osxphotos.PhotoExporter method)</a>
</li>
</ul></td>
</tr></table>

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos" href="overview.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>osxphotos 0.49.1 documentation</title>
<title>osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="#"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="#"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="#">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -237,10 +237,12 @@
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-diff">diff</a></li>
<li class="toctree-l3"><a class="reference internal" href="cli.html#osxphotos-docs">docs</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-exiftool">exiftool</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-exportdb">exportdb</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-inspect">inspect</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>

Binary file not shown.

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Tutorial" href="tutorial.html" /><link rel="prev" title="Welcome to OSXPhotoss documentation!" href="index.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos - osxphotos 0.49.1 documentation</title>
<title>OSXPhotos - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos python API" href="reference.html" /><link rel="prev" title="OSXPhotos Template System" href="template_help.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Python Package Overview - osxphotos 0.49.1 documentation</title>
<title>OSXPhotos Python Package Overview - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

View File

@@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Python Module Index - osxphotos 0.49.1 documentation</title>
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Python Module Index - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -122,7 +122,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -145,7 +145,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="OSXPhotos Python Package Overview" href="package_overview.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos python API - osxphotos 0.49.1 documentation</title>
<title>OSXPhotos python API - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -412,12 +412,22 @@ If called in context manager, returns True (execution is delayed until exiting c
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.ExportDB.get_exported_files">
<span class="sig-name descname"><span class="pre">get_exported_files</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/export_db.html#ExportDB.get_exported_files"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.ExportDB.get_exported_files" title="Permalink to this definition">#</a></dt>
<dd><p>Returns tuple of (uuid, filepath) for all paths of all exported files tracked in the database</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.ExportDB.get_file_record">
<span class="sig-name descname"><span class="pre">get_file_record</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">pathlib.Path</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon"></span> <span class="sig-return-typehint"><span class="pre">osxphotos.export_db.ExportRecord</span></span></span><a class="reference internal" href="_modules/osxphotos/export_db.html#ExportDB.get_file_record"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.ExportDB.get_file_record" title="Permalink to this definition">#</a></dt>
<dd><p>get info for filename and uuid</p>
<p>Returns: an ExportRecord object or None if filename not found</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.ExportDB.get_files_for_uuid">
<span class="sig-name descname"><span class="pre">get_files_for_uuid</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">uuid</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon"></span> <span class="sig-return-typehint"><span class="pre">List</span></span></span><a class="reference internal" href="_modules/osxphotos/export_db.html#ExportDB.get_files_for_uuid"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.ExportDB.get_files_for_uuid" title="Permalink to this definition">#</a></dt>
<dd><p>query database for UUID and return list of files associated with UUID or empty list</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.ExportDB.get_photoinfo_for_uuid">
<span class="sig-name descname"><span class="pre">get_photoinfo_for_uuid</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">uuid</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/export_db.html#ExportDB.get_photoinfo_for_uuid"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.ExportDB.get_photoinfo_for_uuid" title="Permalink to this definition">#</a></dt>
<dd><p>returns the photoinfo JSON struct for a UUID</p>
@@ -1137,6 +1147,49 @@ Highest quality face is result[0] and lowest quality face is result[n]</p>
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">osxphotos.</span></span><span class="sig-name descname"><span class="pre">PhotoExporter</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">photo</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#osxphotos.PhotoInfo" title="osxphotos.PhotoInfo"><span class="pre">PhotoInfo</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">tmpdir</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoexporter.html#PhotoExporter"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoExporter" title="Permalink to this definition">#</a></dt>
<dd><p>Export a photo</p>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.PhotoExporter.exiftool_json_sidecar">
<span class="sig-name descname"><span class="pre">exiftool_json_sidecar</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">options</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="#osxphotos.ExportOptions" title="osxphotos.photoexporter.ExportOptions"><span class="pre">osxphotos.photoexporter.ExportOptions</span></a><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">tag_groups</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photoexporter.html#PhotoExporter.exiftool_json_sidecar"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoExporter.exiftool_json_sidecar" title="Permalink to this definition">#</a></dt>
<dd><dl class="simple">
<dt>Return dict of EXIF details for building exiftool JSON sidecar or sending commands to ExifTool.</dt><dd><p>Does not include all the EXIF fields as those are likely already in the image.</p>
</dd>
</dl>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>options</strong> (<a class="reference internal" href="#osxphotos.ExportOptions" title="osxphotos.ExportOptions"><em>ExportOptions</em></a>) options for export</p></li>
<li><p><strong>tag_groups</strong> (<em>bool</em><em>, </em><em>default=True</em>) if True, include tag groups in the output</p></li>
<li><p><strong>filename</strong> (<em>str</em>) name of source image file (without path); if not None, exiftool JSON signature will be included; if None, signature will not be included</p></li>
</ul>
</dd>
</dl>
<p>Returns: dict with exiftool tags / values</p>
<dl class="simple">
<dt>Exports the following:</dt><dd><p>EXIF:ImageDescription
XMP:Description (may include template)
IPTC:CaptionAbstract
XMP:Title
IPTC:ObjectName
XMP:TagsList
IPTC:Keywords (may include album name, person name, or template)
XMP:Subject (set to keywords + person)
XMP:PersonInImage
EXIF:GPSLatitudeRef, EXIF:GPSLongitudeRef
EXIF:GPSLatitude, EXIF:GPSLongitude
EXIF:GPSPosition
EXIF:DateTimeOriginal
EXIF:OffsetTimeOriginal
EXIF:ModifyDate
IPTC:DigitalCreationDate
IPTC:DateCreated
QuickTime:CreationDate
QuickTime:CreateDate (UTC)
QuickTime:ModifyDate (UTC)
QuickTime:GPSCoordinates
UserData:GPSCoordinates</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.PhotoExporter.export">
<span class="sig-name descname"><span class="pre">export</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">dest</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">options</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="#osxphotos.ExportOptions" title="osxphotos.photoexporter.ExportOptions"><span class="pre">osxphotos.photoexporter.ExportOptions</span></a><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon"></span> <span class="sig-return-typehint"><a class="reference internal" href="#osxphotos.ExportResults" title="osxphotos.photoexporter.ExportResults"><span class="pre">osxphotos.photoexporter.ExportResults</span></a></span></span><a class="reference internal" href="_modules/osxphotos/photoexporter.html#PhotoExporter.export"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoExporter.export" title="Permalink to this definition">#</a></dt>
<dd><p>Export photo</p>
@@ -1167,6 +1220,17 @@ reference PhotoInfo.path_edited</p></li>
</dl>
</div>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="osxphotos.PhotoExporter.write_exiftool_metadata_to_file">
<span class="sig-name descname"><span class="pre">write_exiftool_metadata_to_file</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">src</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">dest</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">options</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#osxphotos.ExportOptions" title="osxphotos.photoexporter.ExportOptions"><span class="pre">osxphotos.photoexporter.ExportOptions</span></a></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon"></span> <span class="sig-return-typehint"><a class="reference internal" href="#osxphotos.ExportResults" title="osxphotos.photoexporter.ExportResults"><span class="pre">osxphotos.photoexporter.ExportResults</span></a></span></span><a class="reference internal" href="_modules/osxphotos/photoexporter.html#PhotoExporter.write_exiftool_metadata_to_file"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotoExporter.write_exiftool_metadata_to_file" title="Permalink to this definition">#</a></dt>
<dd><p>Write exif metadata to src file using exiftool</p>
<p>Caution: This method modifies <em>src</em>, not <em>dest</em>,
so src must be a copy of the original file if you dont want the source modified;
it also does not write to dest (dest is the intended destination for purposes of
referencing the export database. This allows the exiftool update to be done on the
local machine prior to being copied to the export destination which may be on a
network drive or other slower external storage).</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="osxphotos.PhotoInfo">

View File

@@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Search - osxphotos 0.49.1 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Search - osxphotos 0.49.5 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
@@ -121,7 +121,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -144,7 +144,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="#" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Python Package Overview" href="package_overview.html" /><link rel="prev" title="OSXPhotos Command Line Interface (CLI)" href="cli.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Template System - osxphotos 0.49.1 documentation</title>
<title>OSXPhotos Template System - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -567,7 +567,7 @@
<td><p>a carriage return + line feed: rn</p></td>
</tr>
<tr class="row-odd"><td><p>{osxphotos_version}</p></td>
<td><p>The osxphotos version, e.g. 0.49.1</p></td>
<td><p>The osxphotos version, e.g. 0.49.5</p></td>
</tr>
<tr class="row-even"><td><p>{osxphotos_cmd_line}</p></td>
<td><p>The full command line used to run osxphotos</p></td>

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Command Line Interface (CLI)" href="cli.html" /><link rel="prev" title="OSXPhotos" href="overview.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Tutorial - osxphotos 0.49.1 documentation</title>
<title>OSXPhotos Tutorial - osxphotos 0.49.5 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.49.1 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.49.5 documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -147,7 +147,7 @@
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">osxphotos 0.49.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.49.5 documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

View File

@@ -320,7 +320,7 @@ Template Substitutions
* - {crlf}
- a carriage return + line feed: '\r\n'
* - {osxphotos_version}
- The osxphotos version, e.g. '0.49.1'
- The osxphotos version, e.g. '0.49.5'
* - {osxphotos_cmd_line}
- The full command line used to run osxphotos
* - {album}

90
examples/photo_inspect.py Normal file
View File

@@ -0,0 +1,90 @@
"""Print information about one or more items selected in Photos; run with `osxphotos run photo_inspect.py`"""
from time import sleep
import bitmath
from photoscript import PhotosLibrary
from rich import print
from osxphotos import PhotoInfo, PhotosDB
from osxphotos.utils import dd_to_dms_str
def get_photo_type(photo: PhotoInfo):
"""Return a string describing the type of photo"""
if photo.ismovie:
photo_type = "video"
else:
raw = "RAW+JPEG " if photo.has_raw else "RAW " if photo.israw else ""
photo_type = f"{raw}photo"
if photo.burst:
photo_type += " burst"
if photo.live_photo:
photo_type += " live"
if photo.selfie:
photo_type += " selfie"
if photo.panorama:
photo_type += " panorama"
if photo.hdr:
photo_type += " HDR"
if photo.screenshot:
photo_type += " screenshot"
if photo.slow_mo:
photo_type += " slow-mo"
if photo.time_lapse:
photo_type += " time-lapse"
if photo.portrait:
photo_type += " portrait"
return photo_type
def inspect_photo(photo: PhotoInfo):
"""Print info about an osxphotos PhotoInfo object"""
properties = [
f"filename: {photo.original_filename}",
f"type: {get_photo_type(photo)}",
f"uuid: {photo.uuid}",
f"date: {photo.date.isoformat()}",
f"dimensions: {photo.height} x {photo.width}",
f"file size: {bitmath.Byte(photo.original_filesize).to_MB()}",
f"title: {photo.title or '-'}",
f"description: {photo.description or '-'}",
f"edited: {'' if photo.hasadjustments else '-'}",
f"keywords: {', '.join(photo.keywords) or '-'}",
f"persons: {', '.join(photo.persons) or '-'}",
f"location: {', '.join(dd_to_dms_str(*photo.location)) if photo.location[0] else '-'}",
f"place: {photo.place.name if photo.place else '-'}",
f"categories: {', '.join(photo.labels) or '-'}",
f"albums: {', '.join(photo.albums) or '-'}",
f"favorite: {'' if photo.favorite else '-'}",
]
if photo.exif_info:
properties.extend(
[
f"camera: {photo.exif_info.camera_make or '-'} {photo.exif_info.camera_model or '-'}",
f"lens: {photo.exif_info.lens_model or '-'}",
]
)
for property in properties:
print(property)
print("-" * 20)
if __name__ == "__main__":
print("Loading Photos Library...")
photosdb = PhotosDB()
photoslib = PhotosLibrary()
# keep track of last seen UUIDs so we don't print duplicates
last_uuids = []
print("Select one or more photos in Photos (press Ctrl+C to quit)")
while True:
if photos := photoslib.selection:
uuids = sorted([photo.uuid for photo in photos])
if uuids != last_uuids:
for photo in photos:
photoinfo = photosdb.get_photo(photo.uuid)
inspect_photo(photoinfo)
last_uuids = uuids
sleep(0.200)

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.49.1"
__version__ = "0.49.5"

View File

@@ -48,6 +48,7 @@ from .cli import cli_main
from .common import get_photos_db, load_uuid_from_file
from .debug_dump import debug_dump
from .dump import dump
from .exiftool_cli import exiftool
from .export import export
from .exportdb import exportdb
from .grep import grep
@@ -58,6 +59,7 @@ from .keywords import keywords
from .labels import labels
from .list import _list_libraries, list_libraries
from .persons import persons
from .photo_inspect import photo_inspect
from .places import places
from .query import query
from .repl import repl
@@ -74,6 +76,7 @@ __all__ = [
"debug_dump",
"diff",
"dump",
"exiftool_cli",
"export",
"exportdb",
"grep",
@@ -86,6 +89,7 @@ __all__ = [
"list_libraries",
"load_uuid_from_file",
"persons",
"photo_inspect",
"places",
"query",
"repl",

View File

@@ -10,6 +10,7 @@ from .common import DB_OPTION, JSON_OPTION, OSXPHOTOS_HIDDEN
from .debug_dump import debug_dump
from .docs import docs
from .dump import dump
from .exiftool_cli import exiftool
from .export import export
from .exportdb import exportdb
from .grep import grep
@@ -20,6 +21,7 @@ from .keywords import keywords
from .labels import labels
from .list import list_libraries
from .persons import persons
from .photo_inspect import photo_inspect
from .places import places
from .query import query
from .repl import repl
@@ -67,6 +69,7 @@ for command in [
diff,
docs,
dump,
exiftool,
export,
exportdb,
grep,
@@ -77,6 +80,7 @@ for command in [
labels,
list_libraries,
persons,
photo_inspect,
places,
query,
repl,

View File

@@ -0,0 +1,417 @@
"""exiftool command for osxphotos CLI to update an previous export with exiftool metadata"""
import os
import pathlib
import sys
from typing import Callable
import click
from osxphotos import PhotosDB
from osxphotos._constants import OSXPHOTOS_EXPORT_DB
from osxphotos._version import __version__
from osxphotos.configoptions import ConfigOptions, ConfigOptionsLoadError
from osxphotos.export_db import ExportDB, ExportDBInMemory
from osxphotos.export_db_utils import export_db_get_config
from osxphotos.fileutil import FileUtil, FileUtilNoOp
from osxphotos.photoexporter import ExportOptions, ExportResults, PhotoExporter
from osxphotos.utils import pluralize
from .click_rich_echo import (
rich_click_echo,
rich_echo_error,
set_rich_console,
set_rich_theme,
set_rich_timestamp,
)
from .color_themes import get_theme
from .common import DB_OPTION, THEME_OPTION, get_photos_db
from .export import export, render_and_validate_report
from .param_types import ExportDBType, TemplateString
from .report_writer import ReportWriterNoOp, report_writer_factory
from .rich_progress import rich_progress
from .verbose import get_verbose_console, verbose_print
@click.command(name="exiftool")
@click.option(
"--db-config",
is_flag=True,
help="Load configuration options from the export database to match the last export; "
"If any other command line options are used in conjunction with --db-config, "
"they will override the corresponding values loaded from the export database; "
"see also --load-config.",
)
@click.option(
"--load-config",
required=False,
metavar="CONFIG_FILE",
default=None,
help=(
"Load options from file as written with --save-config. "
"If any other command line options are used in conjunction with --load-config, "
"they will override the corresponding values in the config file; "
"see also --db-config."
),
type=click.Path(exists=True),
)
@click.option(
"--save-config",
required=False,
metavar="CONFIG_FILE",
default=None,
help="Save options to file for use with --load-config. File format is TOML. ",
type=click.Path(),
)
@click.option(
"--exiftool-path",
metavar="EXIFTOOL_PATH",
type=click.Path(exists=True),
help="Optionally specify path to exiftool; if not provided, will look for exiftool in $PATH.",
)
@click.option(
"--exiftool-option",
multiple=True,
metavar="OPTION",
help="Optional flag/option to pass to exiftool when using --exiftool. "
"For example, --exiftool-option '-m' to ignore minor warnings. "
"Specify these as you would on the exiftool command line. "
"See exiftool docs at https://exiftool.org/exiftool_pod.html for full list of options. "
"More than one option may be specified by repeating the option, e.g. "
"--exiftool-option '-m' --exiftool-option '-F'. ",
)
@click.option(
"--exiftool-merge-keywords",
is_flag=True,
help="Merge any keywords found in the original file with keywords used for '--exiftool' and '--sidecar'.",
)
@click.option(
"--exiftool-merge-persons",
is_flag=True,
help="Merge any persons found in the original file with persons used for '--exiftool' and '--sidecar'.",
)
@click.option(
"--ignore-date-modified",
is_flag=True,
help="If used with --exiftool or --sidecar, will ignore the photo "
"modification date and set EXIF:ModifyDate to EXIF:DateTimeOriginal; "
"this is consistent with how Photos handles the EXIF:ModifyDate tag.",
)
@click.option(
"--person-keyword",
is_flag=True,
help="Use person in image as keyword/tag when exporting metadata.",
)
@click.option(
"--album-keyword",
is_flag=True,
help="Use album name as keyword/tag when exporting metadata.",
)
@click.option(
"--keyword-template",
metavar="TEMPLATE",
multiple=True,
default=None,
help="For use with --exiftool, --sidecar; specify a template string to use as "
"keyword in the form '{name,DEFAULT}' "
"This is the same format as --directory. For example, if you wanted to add "
"the full path to the folder and album photo is contained in as a keyword when exporting "
'you could specify --keyword-template "{folder_album}" '
'You may specify more than one template, for example --keyword-template "{folder_album}" '
'--keyword-template "{created.year}". '
"See '--replace-keywords' and Templating System below.",
type=TemplateString(),
)
@click.option(
"--replace-keywords",
is_flag=True,
help="Replace keywords with any values specified with --keyword-template. "
"By default, --keyword-template will add keywords to any keywords already associated "
"with the photo. If --replace-keywords is specified, values from --keyword-template "
"will replace any existing keywords instead of adding additional keywords.",
)
@click.option(
"--description-template",
metavar="TEMPLATE",
multiple=False,
default=None,
help="For use with --exiftool, --sidecar; specify a template string to use as "
"description in the form '{name,DEFAULT}' "
"This is the same format as --directory. For example, if you wanted to append "
"'exported with osxphotos on [today's date]' to the description, you could specify "
'--description-template "{descr} exported with osxphotos on {today.date}" '
"See Templating System below.",
type=TemplateString(),
)
@click.option(
"--exportdb",
help="Optional path to export database (if not in the default location in the export directory).",
type=ExportDBType(),
)
@click.option(
"--report",
metavar="REPORT_FILE",
help="Write a report of all files that were exported. "
"The extension of the report filename will be used to determine the format. "
"Valid extensions are: "
".csv (CSV file), .json (JSON), .db and .sqlite (SQLite database). "
"REPORT_FILE may be a template string (see Templating System), for example, "
"--report 'export_{today.date}.csv' will write a CSV report file named with today's date. "
"See also --append.",
type=TemplateString(),
)
@click.option(
"--append",
is_flag=True,
help="If used with --report, add data to existing report file instead of overwriting it. "
"See also --report.",
)
@click.option("--verbose", "-V", is_flag=True, help="Print verbose output.")
@click.option("--timestamp", is_flag=True, help="Add time stamp to verbose output")
@click.option(
"--dry-run",
is_flag=True,
help="Run in dry-run mode (don't actually update files), e.g. for use with --update-signatures.",
)
@THEME_OPTION
@DB_OPTION
@click.argument(
"export_dir",
metavar="EXPORT_DIRECTORY",
nargs=1,
type=click.Path(exists=True, file_okay=False),
)
def exiftool(
album_keyword,
append,
db_config,
db,
description_template,
dry_run,
exiftool_merge_keywords,
exiftool_merge_persons,
exiftool_option,
exiftool_path,
export_dir,
exportdb,
ignore_date_modified,
keyword_template,
load_config,
person_keyword,
replace_keywords,
report,
save_config,
theme,
timestamp,
verbose,
):
"""Run exiftool on previously exported files to update metadata.
If you previously exported photos with `osxphotos export` but did not include the
`--exiftool` option and you now want to update the metadata of the exported files with
exiftool, you can use this command to do so.
If you simply re-run the `osxphotos export` with `--update` and `--exiftool`, osxphotos will
re-export all photos because it will detect that the previously exported photos do not have the
exiftool metadata updates. This command will run exiftool on the previously exported photos
to update all metadata then will update the export database so that using `--exiftool --update`
with `osxphotos export` in the future will work correctly and not unnecessarily re-export photos.
"""
# save locals for initializing config options
locals_ = locals()
if load_config and db_config:
raise click.UsageError("Cannot specify both --load-config and --db-config")
exportdb = exportdb or pathlib.Path(export_dir) / OSXPHOTOS_EXPORT_DB
if not exportdb.exists():
raise click.UsageError(f"Export database {exportdb} does not exist")
# grab all the variables we need from the export command
# export is a click Command so can walk through it's params to get the option names
for param in export.params:
if param.name not in locals_:
locals_[param.name] = None
# need to ensure --exiftool is true in the config options
locals_["exiftool"] = True
config = ConfigOptions(
"export",
locals_,
ignore=[
"cli_obj",
"config_only",
"ctx",
"db_config",
"dest",
"export_dir",
"load_config",
"save_config",
],
)
color_theme = get_theme(theme)
verbose_ = verbose_print(
verbose, timestamp, rich=True, theme=color_theme, highlight=False
)
# set console for rich_echo to be same as for verbose_
set_rich_console(get_verbose_console())
set_rich_theme(color_theme)
set_rich_timestamp(timestamp)
# load config options from either file or export database
# values already set in config will take precedence over any values
# in the config file or database
if load_config:
try:
config.load_from_file(load_config)
except ConfigOptionsLoadError as e:
rich_click_echo(
f"[error]Error parsing {load_config} config file: {e.message}", err=True
)
sys.exit(1)
verbose_(f"Loaded options from file [filepath]{load_config}")
elif db_config:
config = export_db_get_config(exportdb, config)
verbose_("Loaded options from export database")
# from here on out, use config.param_name instead of using the params passed into the function
# as the values may have been updated from config file or database
if load_config or db_config:
# config file might have changed verbose
color_theme = get_theme(config.theme)
verbose_ = verbose_print(
config.verbose,
config.timestamp,
rich=True,
theme=color_theme,
highlight=False,
)
# set console for rich_echo to be same as for verbose_
set_rich_console(get_verbose_console())
set_rich_timestamp(config.timestamp)
# validate options
if append and not report:
raise click.UsageError("--append requires --report")
# need to ensure we have a photos database
config.db = get_photos_db(config.db)
if save_config:
verbose_(f"Saving options to config file '[filepath]{save_config}'")
config.write_to_file(save_config)
process_files(exportdb, export_dir, verbose=verbose_, options=config)
def process_files(
exportdb: str, export_dir: str, verbose: Callable, options: ConfigOptions
):
"""Process files in the export database.
Args:
exportdb: Path to export database.
export_dir: Path to export directory.
verbose: Callable for verbose output.
options: ConfigOptions
"""
if options.report:
report = render_and_validate_report(
options.report, options.exiftool_path, export_dir
)
report_writer = report_writer_factory(report, options.append)
else:
report_writer = ReportWriterNoOp()
photosdb = PhotosDB(options.db, verbose=verbose)
if options.dry_run:
export_db = ExportDBInMemory(exportdb, export_dir)
fileutil = FileUtilNoOp
else:
export_db = ExportDB(exportdb, export_dir)
fileutil = FileUtil
# get_exported_files is a generator which returns tuple of (uuid, filepath)
files = list(export_db.get_exported_files())
# filter out sidecar files
files = [
(u, f)
for u, f in files
if pathlib.Path(f).suffix.lower() not in [".json", ".xmp"]
]
total = len(files)
count = 1
all_results = ExportResults()
# process files that are hardlinked? Requires user confirmation
hardlink_ok = False
with rich_progress(console=get_verbose_console(), mock=options.verbose) as progress:
task = progress.add_task("Processing files", total=total)
for uuid, file in files:
if not pathlib.Path(file).exists():
verbose(f"Skipping missing file [filepath]{file}[/]")
report_writer.write(ExportResults(missing=[file]))
continue
if not hardlink_ok and os.stat(file).st_nlink > 1:
rich_click_echo(
f"[warning]:warning-emoji: Warning: file [filepath]{file}[/] is hardlinked.\n"
"You may be modifying linked original files in your Photos library. "
"This is inadvisable.[/]",
)
click.confirm("Continue processing hardlinks?", abort=True)
hardlink_ok = True
verbose(f"Processing file [filepath]{file}[/] ([num]{count}/{total}[/num])")
photo = photosdb.get_photo(uuid)
export_options = ExportOptions(
description_template=options.description_template,
dry_run=options.dry_run,
exiftool_flags=options.exiftool_option,
exiftool=True,
export_db=export_db,
ignore_date_modified=options.ignore_date_modified,
keyword_template=options.keyword_template,
merge_exif_keywords=options.exiftool_merge_keywords,
merge_exif_persons=options.exiftool_merge_persons,
replace_keywords=options.replace_keywords,
use_albums_as_keywords=options.album_keyword,
use_persons_as_keywords=options.person_keyword,
verbose=verbose,
)
exporter = PhotoExporter(photo)
results = exporter.write_exiftool_metadata_to_file(
src=file, dest=file, options=export_options
)
all_results += results
for warning_ in results.exiftool_warning:
verbose(
f"[warning]exiftool warning for file {warning_[0]}: {warning_[1]}"
)
for error_ in results.exiftool_error:
rich_echo_error(
f"[error]exiftool error for file {error_[0]}: {error_[1]}"
)
for result in results.exif_updated:
verbose(f"Updated EXIF metadata for [filepath]{result}")
# update the database
with export_db.get_file_record(file) as rec:
rec.dest_sig = fileutil.file_sig(file)
rec.export_options = export_options.bit_flags
rec.exifdata = exporter.exiftool_json_sidecar(export_options)
report_writer.write(results)
count += 1
progress.advance(task)
photo_str_total = pluralize(total, "photo", "photos")
summary = (
f"Processed: [num]{total}[/] {photo_str_total}, "
f"skipped: [num]{len(all_results.skipped)}[/], "
f"updated EXIF data: [num]{len(all_results.exif_updated)}[/], "
)
verbose(summary)
if options.report:
verbose(f"Wrote export report to [filepath]{report}")
report_writer.close()

View File

@@ -2729,14 +2729,3 @@ def render_and_validate_report(report: str, exiftool_path: str, export_dir: str)
return report
# def _export_with_profiler(args: Dict):
# """ "Run export with cProfile"""
# try:
# args.pop("profile")
# except KeyError:
# pass
# cProfile.runctx(
# "_export(**args)", globals=globals(), locals=locals(), sort="tottime"
# )

View File

@@ -1,5 +1,6 @@
"""exportdb command for osxphotos CLI"""
import json
import pathlib
import sys
@@ -63,6 +64,18 @@ from .verbose import verbose_print
nargs=1,
help="Print information about FILE_PATH contained in the database.",
)
@click.option(
"--uuid-files",
metavar="UUID",
nargs=1,
help="List exported files associated with UUID.",
)
@click.option(
"--uuid-info",
metavar="UUID",
nargs=1,
help="Print information about UUID contained in the database.",
)
@click.option(
"--report",
metavar="REPORT_FILE RUN_ID",
@@ -110,22 +123,24 @@ from .verbose import verbose_print
)
@click.argument("export_db", metavar="EXPORT_DATABASE", type=click.Path(exists=True))
def exportdb(
version,
vacuum,
check_signatures,
update_signatures,
touch_file,
last_run,
save_config,
info,
report,
migrate,
sql,
export_dir,
append,
verbose,
check_signatures,
dry_run,
export_db,
export_dir,
info,
last_run,
migrate,
report,
save_config,
sql,
touch_file,
update_signatures,
uuid_files,
uuid_info,
vacuum,
verbose,
version,
):
"""Utilities for working with the osxphotos export database"""
@@ -163,6 +178,8 @@ def exportdb(
sql,
touch_file,
update_signatures,
uuid_files,
uuid_info,
vacuum,
version,
]
@@ -273,6 +290,37 @@ def exportdb(
print(f"[red]File '{info}' not found in export database[/red]")
sys.exit(0)
if uuid_info:
# get photoinfo record for a uuid
exportdb = ExportDB(export_db, export_dir)
try:
info_rec = exportdb.get_photoinfo_for_uuid(uuid_info)
except Exception as e:
print(f"[red]Error: {e}[/red]")
sys.exit(1)
else:
if info_rec:
print(json.dumps(json.loads(info_rec), sort_keys=True, indent=2))
else:
print(f"[red]UUID '{uuid_info}' not found in export database[/red]")
sys.exit(0)
if uuid_files:
# list files associated with a uuid
exportdb = ExportDB(export_db, export_dir)
try:
file_list = exportdb.get_files_for_uuid(uuid_files)
except Exception as e:
print(f"[red]Error: {e}[/red]")
sys.exit(1)
else:
if file_list:
for f in file_list:
print(f)
else:
print(f"[red]UUID '{uuid_files}' not found in export database[/red]")
sys.exit(0)
if report:
exportdb = ExportDB(export_db, export_dir)
report_template, run_id = report

View File

@@ -0,0 +1,474 @@
"""Inspect photos selected in Photos """
import functools
import re
from fractions import Fraction
from multiprocessing import Process, Queue
from queue import Empty
from time import gmtime, sleep, strftime
from typing import List, Optional, Tuple
import pathlib
import bitmath
import click
from applescript import ScriptError
from photoscript import PhotosLibrary
from rich.console import Console
from rich.layout import Layout
from rich.live import Live
from rich.panel import Panel
from osxphotos import PhotoInfo, PhotosDB
from osxphotos._constants import _UNKNOWN_PERSON
from osxphotos.rich_utils import add_rich_markup_tag
from osxphotos.text_detection import detect_text as detect_text_in_photo
from osxphotos.utils import dd_to_dms_str
from .color_themes import get_theme
from .common import DB_OPTION, THEME_OPTION, get_photos_db
# global that tracks UUID being inspected
CURRENT_UUID = None
# helpers for markup
bold = add_rich_markup_tag("bold")
dim = add_rich_markup_tag("dim")
def extract_uuid(text: str) -> str:
"""Extract a UUID from a string"""
if match := re.search(
r"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})",
text,
):
return match[1]
return None
def trim(text: str, pad: str = "") -> str:
"""Truncate a string to a fit in console, - len(pad) - 4; also removes new lines"""
width = Console().width - len(pad) - 4
text = text.replace("\n", " ")
return text if len(text) <= width else f"{text[: width- 3]}..."
def inspect_photo(photo: PhotoInfo, detected_text: Optional[str] = None) -> str:
"""Get info about an osxphotos PhotoInfo object formatted for printing"""
properties = [
bold("Filename: ") + f"[filename]{photo.original_filename}[/]",
bold("Type: ") + get_photo_type(photo),
bold("UUID: ") + f"[uuid]{photo.uuid}[/]",
bold("Date: ") + f"[time]{photo.date.isoformat()}[/]",
bold("Date added: ") + f"[time]{photo.date_added.isoformat()}[/]",
]
if photo.date_modified:
properties.append(
bold("Date modified: ") + f"[time]{photo.date_modified.isoformat()}[/]"
)
if photo.intrash and photo.date_trashed:
properties.append(
bold("Date deleted: ") + f"[time]{photo.date_trashed.isoformat()}[/]"
)
if photo.import_info and photo.import_info.creation_date:
properties.append(
bold("Date imported: ")
+ f"[time]{photo.import_info.creation_date.isoformat()}[/]"
)
properties.extend(
[
bold("Dimensions: ")
+ f"[num]{photo.width}[/] x [num]{photo.height}[/] "
+ bold("Orientation: ")
+ f"[num]{photo.orientation}[/]",
bold("File size: ")
+ f"[num]{float(bitmath.Byte(photo.original_filesize).to_MB()):.2f} MB[/]",
bold("Title: ") + f"{photo.title or '-'}",
bold("Description: ")
+ f"{trim(photo.description or '-', 'Description: ')}",
bold("Edited: ")
+ f"{'' if photo.hasadjustments else '-'} "
+ bold("External edits: ")
+ f"{'' if photo.external_edit else '-'}",
bold("Keywords: ") + f"{', '.join(photo.keywords) or '-'}",
bold("Persons: ")
+ f"{', '.join(p for p in photo.persons if p != _UNKNOWN_PERSON) or '-'}",
bold("Location: ")
+ f"{', '.join(dd_to_dms_str(*photo.location)) if photo.location[0] else '-'}",
bold("Place: ") + f"{photo.place.name if photo.place else '-'}",
bold("Categories: ") + f"{', '.join(photo.labels) or '-'}",
]
)
properties.append(format_flags(photo))
properties.append(format_albums(photo))
if photo.project_info:
properties.append(
bold("Projects: ")
+ f"{', '.join(p.title for p in photo.project_info) or '-'}"
)
if photo.moment_info:
properties.append(bold("Moment: ") + f"{photo.moment_info.title or '-'}")
if photo.comments:
comments = [f"{c.user}: {c.text}" for c in photo.comments]
properties.append(
bold("Comments: ") + trim(f"{', '.join(comments)}", "Comments: ")
)
if photo.likes:
properties.append(
bold("Likes: ")
+ trim(f"{', '.join(l.user for l in photo.likes)}", "Likes: ")
)
properties.append(format_exif_info(photo))
properties.append(format_score_info(photo))
if detected_text:
# have detected text for this photo
properties.append(
bold("Detected text: ") + trim(detected_text, "Detected text: ")
)
properties.append(format_paths(photo))
return "\n".join(properties)
def format_score_info(photo: PhotoInfo) -> str:
"""Format score_info"""
score_str = bold("Score: ")
if photo.score:
score_str += f"[num]{photo.score.overall}[/]" if photo.score else "-"
return score_str
def format_flags(photo: PhotoInfo) -> str:
"""Format special properties"""
flag_str = bold("Flags: ")
flags = []
if photo.favorite:
flags.append("favorite")
if photo.visible:
flags.append("visible")
if photo.hidden:
flags.append("hidden")
if photo.ismissing:
flags.append("missing")
if photo.intrash:
flags.append("in trash")
if photo.iscloudasset:
flags.append("cloud asset")
if photo.incloud:
flags.append("in cloud")
if photo.shared:
flags.append("shared")
flag_str += f"{', '.join(flags) or '-'}"
return flag_str
def format_albums(photo: PhotoInfo) -> str:
"""Format albums for inspect_photo"""
album_str = bold("Albums: ")
album_names = []
for album in photo.album_info:
if album.folder_names:
folder_str = "/".join(album.folder_names)
album_names.append(f"{folder_str}/{album.title}")
else:
album_names.append(album.title)
album_str += f"{', '.join(album_names) or '-'}"
return album_str
def format_path_link(path: str) -> str:
"""Format a path as URI for display in terminal"""
return f"[link={pathlib.Path(path).as_uri()}]{path}[/link]"
def format_paths(photo: PhotoInfo) -> str:
"""format photo paths for inspect_photo"""
path_str = bold("Path original: ")
path_str += f"[filepath]{format_path_link(photo.path)}[/]" if photo.path else "-"
if photo.path_edited:
path_str += "\n"
path_str += bold("Path edited: ")
path_str += f"[filepath]{format_path_link(photo.path_edited)}[/]"
if photo.path_raw:
path_str += "\n"
path_str += bold("Path raw: ")
path_str += f"[filepath]{format_path_link(photo.path_raw)}[/]"
if photo.path_derivatives:
path_str += "\n"
path_str += bold("Path preview: ")
path_str += f"[filepath]{format_path_link(photo.path_derivatives[0])}[/]"
return path_str
def format_exif_info(photo: PhotoInfo) -> str:
"""Format exif_info for inspect_photo"""
exif_str = bold("EXIF: ")
exif = photo.exif_info
if not exif:
return f"{exif_str}-"
if exif.camera_make:
exif_str += f"{exif.camera_make} "
if exif.camera_model:
exif_str += f"{exif.camera_model} "
if exif.focal_length:
exif_str += f"{exif.focal_length:.2f}mm "
if exif.iso:
exif_str += f"ISO {exif.iso} "
if exif.flash_fired:
exif_str += "Flash "
if exif.exposure_bias is not None:
exif_str += (
f"{int(exif.exposure_bias)} ev "
if exif.exposure_bias == int(exif.exposure_bias)
else f"{exif.exposure_bias} ev "
)
if exif.aperture:
exif_str += (
f"ƒ{int(exif.aperture)} "
if exif.aperture == int(exif.aperture)
else f"ƒ{exif.aperture:.1f} "
)
if exif.shutter_speed:
exif_str += f"{Fraction(exif.shutter_speed).limit_denominator(100_000)}s "
if exif.bit_rate:
exif_str += f"{exif.bit_rate} bit rate"
if exif.sample_rate:
exif_str += f"{exif.sample_rate} sample rate"
if exif.fps:
exif_str += f"{exif.fps or 0:.1f}FPS "
if exif.duration:
exif_str += f"{strftime('%H:%M:%S', gmtime(exif.duration or 0))} "
if exif.codec:
exif_str += f"{exif.codec}"
if exif.track_format:
exif_str += f"{exif.track_format}"
return exif_str
def get_photo_type(photo: PhotoInfo) -> str:
"""Return a string describing the type of photo"""
photo_type = "video" if photo.ismovie else "photo"
if photo.has_raw:
photo_type += " RAW+JPEG"
if photo.israw:
photo_type += " RAW"
if photo.burst:
photo_type += " burst"
if photo.live_photo:
photo_type += " live"
if photo.selfie:
photo_type += " selfie"
if photo.panorama:
photo_type += " panorama"
if photo.hdr:
photo_type += " HDR"
if photo.screenshot:
photo_type += " screenshot"
if photo.slow_mo:
photo_type += " slow-mo"
if photo.time_lapse:
photo_type += " time-lapse"
if photo.portrait:
photo_type += " portrait"
return photo_type
def start_text_detection(photo: PhotoInfo) -> Tuple[Process, Queue]:
"""Start text detection process for a photo"""
path_preview = photo.path_derivatives[0] if photo.path_derivatives else None
path = photo.path_edited or photo.path or path_preview
if not path:
raise ValueError("No path to photo")
queue = Queue()
p = Process(
target=_get_detected_text,
args=(photo.uuid, path, photo.orientation, queue),
)
p.start()
return (p, queue)
def _get_detected_text(uuid: str, path: str, orientation: int, queue: Queue) -> None:
"""Called by start_text_detection to run text detection in separate process"""
try:
if text := detect_text_in_photo(path, orientation):
queue.put([uuid, " ".join(t[0] for t in text if t[1] > 0.5)])
except Exception as e:
queue.put([uuid, str(e)])
def get_uuid_for_photos_selection() -> List[str]:
"""Get the uuid for the first photo selected in Photos
Returns: tuple of (uuid, total_selected_photos)"""
photoslib = PhotosLibrary()
try:
if photos := photoslib.selection:
return photos[0].uuid, len(photos)
except (ValueError, ScriptError) as e:
if uuid := extract_uuid(str(e)):
return uuid, 1
else:
raise e
return None, 0
def make_layout() -> Layout:
"""Define the layout."""
layout = Layout(name="root")
layout.split(
Layout(name="main", ratio=1),
Layout(name="status", size=1),
Layout(name="footer", size=1),
)
return layout
@click.command(name="inspect")
@click.option("--detect-text", "-t", is_flag=True, help="Detect text in photos")
@THEME_OPTION
@DB_OPTION
def photo_inspect(db, theme, detect_text):
"""Interactively inspect photos selected in Photos.
Open Photos then run `osxphotos inspect` in the terminal.
As you select a photo in Photos, inspect will display metadata about the photo.
Press Ctrl+C to exit when done.
Works best with a modern terminal like iTerm2 or Kitty.
"""
db = get_photos_db(db)
if not db:
raise click.UsageError(
"Did not locate Photos database. Try running with --db option."
)
theme = get_theme(theme)
console = Console(theme=theme)
layout = make_layout()
layout["footer"].update("Press Ctrl+C to quit")
layout["main"].update(
Panel("Loading Photos database, hold on...", title="Loading...")
)
def loading_status(status: str):
layout["status"].update(f"Loading database: {status}")
def update_status(status: str):
layout["status"].update(status)
def update_detected_text(photo: PhotoInfo, uuid: str, text: str):
global CURRENT_UUID
if uuid == CURRENT_UUID:
layout["main"].update(
Panel(
inspect_photo(photo, text),
title=photo.title or photo.original_filename,
)
)
with Live(layout, console=console, refresh_per_second=10, screen=True):
photosdb = PhotosDB(dbfile=db, verbose=loading_status)
layout["main"].update(
Panel("Select a photo in Photos to inspect", title="Select a photo")
)
processes = []
global CURRENT_UUID
detected_text_cache = {}
last_uuid = None
uuid = None
total = 0
while True:
try:
uuid, total = get_uuid_for_photos_selection()
except Exception as e:
layout["main"].update(Panel(f"Error: {e}", title="Error"))
except KeyboardInterrupt:
# allow Ctrl+C to quit
break
finally:
if uuid and uuid != last_uuid:
if total > 1:
update_status(
f"{total} photos selected; inspecting uuid={uuid}"
)
else:
update_status(f"Inspecting uuid={uuid}")
CURRENT_UUID = uuid
if photo := photosdb.get_photo(uuid):
layout["main"].update(
Panel(
inspect_photo(
photo,
detected_text=detected_text_cache.get(uuid, None),
),
title=photo.title or photo.original_filename,
)
)
# start text detection if requested
if (
detect_text
and (
photo.path
or photo.path_edited
or photo.path_derivatives
)
and uuid not in detected_text_cache
):
# can only detect text on photos if on disk
# start text detection in separate process as it can take a few seconds
update_detected_text_callback = functools.partial(
update_detected_text, photo
)
process, queue = start_text_detection(photo)
processes.append(
[True, process, queue, update_detected_text_callback]
)
else:
layout["main"].update(
Panel(
f"No photo found in database for uuid={uuid}",
title="Error",
)
)
last_uuid = uuid
if not uuid:
last_uuid = None
layout["main"].update(
Panel("Select a photo in Photos to inspect", title="Select a photo")
)
update_status("Select a photo in Photos to inspect")
if detect_text:
# check on text detection processes
for _, values in enumerate(processes):
alive, process, queue, update_detected_text_callback = values
if alive:
# process hasn't been marked as dead yet
try:
uuid, text = queue.get(False)
update_detected_text_callback(uuid, text)
detected_text_cache[uuid] = text
process.join()
# set alive = False
values[0] = False
except Empty:
if not process.is_alive():
# process has finished, nothing in the queue
process.join()
# set alive = False
values[0] = False
sleep(0.100)

View File

@@ -57,8 +57,8 @@ class ConfigOptions:
setattr(self, attr, self._attrs[attr])
else:
setattr(self, attr, arg)
except KeyError:
raise KeyError(f"Missing argument: {attr}")
except KeyError as e:
raise KeyError(f"Missing argument: {attr}") from e
def validate(self, exclusive=None, inclusive=None, dependent=None, cli=False):
"""validate combinations of otions
@@ -153,9 +153,26 @@ class ConfigOptions:
ConfigOptionsLoadError if there are any errors during the parsing of the TOML file
"""
loaded = toml.load(filename)
return self._load_from_toml_dict(loaded, override)
def load_from_str(self, str, override=False):
"""Load options from a TOML str.
Args:
str: TOML str
override: bool; if True, values in the TOML str will override values already set in the instance
Raises:
ConfigOptionsLoadError if there are any errors during the parsing of the TOML str
"""
loaded = toml.loads(str)
return self._load_from_toml_dict(loaded, override)
def _load_from_toml_dict(self, loaded, override):
"""Load options from a TOML dict (as returned by toml.load or toml.loads)"""
name = self._name
if name not in loaded:
raise ConfigOptionsLoadError(f"[{name}] section missing from {filename}")
raise ConfigOptionsLoadError(f"[{name}] section missing from config file")
for attr in loaded[name]:
if attr not in self._attrs:

Binary file not shown.

View File

@@ -15,7 +15,7 @@ from contextlib import suppress
from io import StringIO
from sqlite3 import Error
from tempfile import TemporaryDirectory
from typing import Any, Optional, Tuple, Union
from typing import Any, Optional, Tuple, Union, List
from tenacity import retry, stop_after_attempt
@@ -30,7 +30,7 @@ __all__ = [
"ExportDBTemp",
]
OSXPHOTOS_EXPORTDB_VERSION = "7.0"
OSXPHOTOS_EXPORTDB_VERSION = "7.1"
OSXPHOTOS_ABOUT_STRING = f"Created by osxphotos version {__version__} (https://github.com/RhetTbull/osxphotos) on {datetime.datetime.now()}"
# max retry attempts for methods which use tenacity.retry
@@ -171,6 +171,17 @@ class ExportDB:
uuid = None
return uuid
def get_files_for_uuid(self, uuid: str) -> List:
"""query database for UUID and return list of files associated with UUID or empty list"""
conn = self._conn
c = conn.cursor()
c.execute(
"SELECT filepath FROM export_data WHERE uuid = ?",
(uuid,),
)
results = c.fetchall()
return [os.path.join(self.export_dir, r[0]) for r in results]
def get_photoinfo_for_uuid(self, uuid):
"""returns the photoinfo JSON struct for a UUID"""
conn = self._conn
@@ -282,6 +293,20 @@ class ExportDB:
results = None
return results
def get_exported_files(self):
"""Returns tuple of (uuid, filepath) for all paths of all exported files tracked in the database"""
conn = self._conn
try:
c = conn.cursor()
c.execute("SELECT uuid, filepath FROM export_data")
except Error as e:
logging.warning(e)
return
while row := c.fetchone():
yield row[0], os.path.join(self.export_dir, row[1])
return
def close(self):
"""close the database connection"""
try:
@@ -299,7 +324,7 @@ class ExportDB:
if not os.path.isfile(dbfile):
conn = self._get_db_connection(dbfile)
if not conn:
raise Exception("Error getting connection to database {dbfile}")
raise Exception(f"Error getting connection to database {dbfile}")
self._create_or_migrate_db_tables(conn)
self.was_created = True
self.was_upgraded = ()
@@ -456,6 +481,10 @@ class ExportDB:
# create report_data table
self._migrate_6_0_to_7_0(conn)
if version[1] < "7.1":
# add timestamp to export_data
self._migrate_7_0_to_7_1(conn)
conn.execute("VACUUM;")
conn.commit()
@@ -673,6 +702,32 @@ class ExportDB:
except Error as e:
logging.warning(e)
def _migrate_7_0_to_7_1(self, conn):
try:
c = conn.cursor()
c.execute("""ALTER TABLE export_data ADD COLUMN timestamp DATETIME;""")
c.execute(
"""
CREATE TRIGGER insert_timestamp_trigger
AFTER INSERT ON export_data
BEGIN
UPDATE export_data SET timestamp = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') WHERE id = NEW.id;
END;
"""
)
c.execute(
"""
CREATE TRIGGER update_timestamp_trigger
AFTER UPDATE On export_data
BEGIN
UPDATE export_data SET timestamp = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') WHERE id = NEW.id;
END;
"""
)
conn.commit()
except Error as e:
logging.warning(e)
def _perform_db_maintenace(self, conn):
"""Perform database maintenance"""
try:
@@ -1034,6 +1089,21 @@ class ExportRecord:
if not self._context_manager:
conn.commit()
@property
def timestamp(self):
"""returns the timestamp value"""
conn = self._conn
c = conn.cursor()
if row := c.execute(
"SELECT timestamp FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,),
).fetchone():
return row[0]
raise ValueError(
f"No timestamp found in database for {self._filepath_normalized}"
)
def asdict(self):
"""Return dict of self"""
exifdata = json.loads(self.exifdata) if self.exifdata else None
@@ -1042,6 +1112,7 @@ class ExportRecord:
"filepath": self.filepath,
"filepath_normalized": self.filepath_normalized,
"uuid": self.uuid,
"timestamp": self.timestamp,
"digest": self.digest,
"src_sig": self.src_sig,
"dest_sig": self.dest_sig,

View File

@@ -12,10 +12,11 @@ from rich import print
from ._constants import OSXPHOTOS_EXPORT_DB
from ._version import __version__
from .utils import noop
from .configoptions import ConfigOptions
from .export_db import OSXPHOTOS_EXPORTDB_VERSION, ExportDB
from .fileutil import FileUtil
from .photosdb import PhotosDB
from .utils import noop
__all__ = [
"export_db_check_signatures",
@@ -125,6 +126,23 @@ def export_db_save_config_to_file(
f.write(row[0])
def export_db_get_config(
export_db: Union[str, pathlib.Path], config: ConfigOptions, override=False
) -> ConfigOptions:
"""Load last run config to config
Args:
export_db: path to export database
override: if True, any loaded config values will overwrite existing values in config
"""
conn = sqlite3.connect(str(export_db))
c = conn.cursor()
row = c.execute("SELECT config FROM config ORDER BY id DESC LIMIT 1;").fetchone()
if not row:
return ValueError("No config found in export_db")
return config.load_from_str(row[0], override=override)
def export_db_check_signatures(
dbfile: Union[str, pathlib.Path],
export_dir: Union[str, pathlib.Path],

View File

@@ -735,7 +735,7 @@ class PhotoExporter:
return ShouldUpdate.EXPORT_OPTIONS_DIFFERENT
if options.exiftool:
current_exifdata = self._exiftool_json_sidecar(options=options)
current_exifdata = self.exiftool_json_sidecar(options=options)
rv = current_exifdata != file_record.exifdata
# if using exiftool, don't need to continue checking edited below
# as exiftool will be used to update edited file
@@ -1143,7 +1143,7 @@ class PhotoExporter:
# point src to the tmp_file so that the original source is not modified
# and the export grabs the new file
src = tmp_file
exif_results = self._write_exif_metadata_to_file(
exif_results = self.write_exiftool_metadata_to_file(
src, dest, options=options
)
@@ -1185,7 +1185,7 @@ class PhotoExporter:
if not options.ignore_signature:
rec.dest_sig = fileutil.file_sig(dest)
if options.exiftool:
rec.exifdata = self._exiftool_json_sidecar(options)
rec.exifdata = self.exiftool_json_sidecar(options)
if self.photo.hexdigest != rec.digest:
results.metadata_changed = [dest_str]
rec.digest = self.photo.hexdigest
@@ -1320,7 +1320,7 @@ class PhotoExporter:
sidecar_filename = dest.parent / pathlib.Path(
f"{dest.stem}{dest_suffix}.json"
)
sidecar_str = self._exiftool_json_sidecar(
sidecar_str = self.exiftool_json_sidecar(
filename=dest.name, options=options
)
sidecars.append(
@@ -1337,7 +1337,7 @@ class PhotoExporter:
sidecar_filename = dest.parent / pathlib.Path(
f"{dest.stem}{dest_suffix}.json"
)
sidecar_str = self._exiftool_json_sidecar(
sidecar_str = self.exiftool_json_sidecar(
tag_groups=False, filename=dest.name, options=options
)
sidecars.append(
@@ -1436,19 +1436,20 @@ class PhotoExporter:
return results
def _write_exif_metadata_to_file(
def write_exiftool_metadata_to_file(
self,
src,
dest,
options: ExportOptions,
) -> ExportResults:
"""Write exif metadata to file using exiftool
"""Write exif metadata to src file using exiftool
Note: this method modifies src so src must be a copy of the original file;
Caution: This method modifies *src*, not *dest*,
so src must be a copy of the original file if you don't want the source modified;
it also does not write to dest (dest is the intended destination for purposes of
referencing the export database. This allows the exiftool update to be done on the
local machine prior to being copied to the export destination which may be on a
network drive or other slower external storage."""
network drive or other slower external storage)."""
verbose = options.verbose or self._verbose
exiftool_results = ExportResults()
@@ -1491,7 +1492,7 @@ class PhotoExporter:
old_data = exif_record.exifdata if exif_record else None
if old_data is not None:
old_data = json.loads(old_data)[0]
current_data = json.loads(self._exiftool_json_sidecar(options=options))
current_data = json.loads(self.exiftool_json_sidecar(options=options))
current_data = current_data[0]
if old_data != current_data:
files_are_different = True
@@ -1831,7 +1832,7 @@ class PhotoExporter:
pass
return persons
def _exiftool_json_sidecar(
def exiftool_json_sidecar(
self,
options: t.Optional[ExportOptions] = None,
tag_groups: bool = True,

View File

@@ -32,7 +32,7 @@ def detect_text(img_path: str, orientation: Optional[int] = None) -> List:
orientation: optional EXIF orientation (if known, passing orientation may improve quality of results)
"""
if not vision:
logging.warning(f"detect_text not implemented for this version of macOS")
logging.warning("detect_text not implemented for this version of macOS")
return []
with objc.autorelease_pool():
@@ -47,18 +47,18 @@ def detect_text(img_path: str, orientation: Optional[int] = None) -> List:
input_image = Quartz.CIImage.imageWithContentsOfURL_(input_url)
vision_options = NSDictionary.dictionaryWithDictionary_({})
if orientation is not None:
if not 1 <= orientation <= 8:
raise ValueError("orientation must be between 1 and 8")
vision_handler = Vision.VNImageRequestHandler.alloc().initWithCIImage_orientation_options_(
input_image, orientation, vision_options
)
else:
if orientation is None:
vision_handler = (
Vision.VNImageRequestHandler.alloc().initWithCIImage_options_(
input_image, vision_options
)
)
elif 1 <= orientation <= 8:
vision_handler = Vision.VNImageRequestHandler.alloc().initWithCIImage_orientation_options_(
input_image, orientation, vision_options
)
else:
raise ValueError("orientation must be between 1 and 8")
results = []
handler = make_request_handler(results)
vision_request = (

View File

@@ -80,19 +80,19 @@ def generate_sidecars(dbname, uuid_dict):
# generate JSON files
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json")
json_ = exporter._exiftool_json_sidecar()
json_ = exporter.exiftool_json_sidecar()
with open(sidecar, "w") as file:
file.write(json_)
# no tag groups
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_no_tag_groups.json")
json_ = exporter._exiftool_json_sidecar(tag_groups=False)
json_ = exporter.exiftool_json_sidecar(tag_groups=False)
with open(sidecar, "w") as file:
file.write(json_)
# ignore_date_modified
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_ignore_date_modified.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(ignore_date_modified=True)
)
with open(sidecar, "w") as file:
@@ -100,7 +100,7 @@ def generate_sidecars(dbname, uuid_dict):
# keyword_template
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_keyword_template.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(keyword_template=["{folder_album}"])
)
with open(sidecar, "w") as file:
@@ -108,7 +108,7 @@ def generate_sidecars(dbname, uuid_dict):
# persons_as_keywords
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_persons_as_keywords.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(use_persons_as_keywords=True)
)
with open(sidecar, "w") as file:
@@ -116,7 +116,7 @@ def generate_sidecars(dbname, uuid_dict):
# albums_as_keywords
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_albums_as_keywords.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(use_albums_as_keywords=True)
)
with open(sidecar, "w") as file:

266
tests/test_cli_exiftool.py Normal file
View File

@@ -0,0 +1,266 @@
"""Tests for `osxphotos exiftool` command."""
import glob
import json
import os
import pytest
from click.testing import CliRunner
from osxphotos.cli.exiftool_cli import exiftool
from osxphotos.cli.export import export
from osxphotos.exiftool import ExifTool, get_exiftool_path
from .test_cli import CLI_EXIFTOOL, PHOTOS_DB_15_7
# determine if exiftool installed so exiftool tests can be skipped
try:
exiftool_path = get_exiftool_path()
except FileNotFoundError:
exiftool_path = None
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool():
"""Test osxphotos exiftool"""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
uuid_option = []
for uuid in CLI_EXIFTOOL:
uuid_option.extend(("--uuid", uuid))
# first, export without --exiftool
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
*uuid_option,
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert sorted(files) == sorted(
[CLI_EXIFTOOL[uuid]["File:FileName"] for uuid in CLI_EXIFTOOL]
)
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
["--db", os.path.join(cwd, PHOTOS_DB_15_7), "-V", "--db-config", temp_dir],
)
assert result.exit_code == 0
exif = ExifTool(CLI_EXIFTOOL[uuid]["File:FileName"]).asdict()
for key in CLI_EXIFTOOL[uuid]:
if type(exif[key]) == list:
assert sorted(exif[key]) == sorted(CLI_EXIFTOOL[uuid][key])
else:
assert exif[key] == CLI_EXIFTOOL[uuid][key]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
"--exiftool",
"--update",
*uuid_option,
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: {len(CLI_EXIFTOOL)}" in result.output
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool_album_keyword():
"""Test osxphotos exiftool with --album-template."""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
# first, export without --exiftool
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
"--album",
"Pumpkin Farm",
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert len(files) == 3
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
"-V",
"--db-config",
"--report",
"exiftool.json",
"--album-keyword",
temp_dir,
],
)
assert result.exit_code == 0
report = json.load(open("exiftool.json", "r"))
assert len(report) == 3
# verify exiftool metadata was updated
for file in report:
exif = ExifTool(file["filename"]).asdict()
assert "Pumpkin Farm" in exif["IPTC:Keywords"]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
"--exiftool",
"--update",
"--album",
"Pumpkin Farm",
"--album-keyword",
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: 3" in result.output
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool_keyword_template():
"""Test osxphotos exiftool with --keyword-template."""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
uuid_option = []
for uuid in CLI_EXIFTOOL:
uuid_option.extend(("--uuid", uuid))
# first, export without --exiftool
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
*uuid_option,
],
)
assert result.exit_code == 0
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
"-V",
"--db-config",
"--keyword-template",
"FOO",
temp_dir,
"--report",
"exiftool.json",
],
)
assert result.exit_code == 0
report = json.load(open("exiftool.json", "r"))
for file in report:
exif = ExifTool(file["filename"]).asdict()
assert "FOO" in exif["IPTC:Keywords"]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
"--exiftool",
"--keyword-template",
"FOO",
"--update",
*uuid_option,
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: {len(CLI_EXIFTOOL)}" in result.output
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool_load_config():
"""Test osxphotos exiftool with --load-config"""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
uuid_option = []
for uuid in CLI_EXIFTOOL:
uuid_option.extend(("--uuid", uuid))
# first, export without --exiftool
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
"--save-config",
"config.toml",
*uuid_option,
],
)
assert result.exit_code == 0
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
["-V", "--load-config", "config.toml", temp_dir],
)
assert result.exit_code == 0
exif = ExifTool(CLI_EXIFTOOL[uuid]["File:FileName"]).asdict()
for key in CLI_EXIFTOOL[uuid]:
if type(exif[key]) == list:
assert sorted(exif[key]) == sorted(CLI_EXIFTOOL[uuid][key])
else:
assert exif[key] == CLI_EXIFTOOL[uuid][key]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
temp_dir,
"-V",
"--exiftool",
"--update",
*uuid_option,
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: {len(CLI_EXIFTOOL)}" in result.output

View File

@@ -1,6 +1,8 @@
""" test ConfigOptions class """
import pathlib
from io import StringIO
import pytest
import toml
@@ -43,6 +45,15 @@ def test_write_to_file_load_from_file(tmpdir):
assert cfg2.bar
def test_load_from_str(tmpdir):
cfg = ConfigOptions("test", VARS)
cfg.bar = True
cfg_str = cfg.write_to_str()
cfg2 = ConfigOptions("test", VARS).load_from_str(cfg_str)
assert cfg2.foo == "bar"
assert cfg2.bar
def test_load_from_file_error(tmpdir):
cfg_file = pathlib.Path(str(tmpdir)) / "test.toml"
cfg = ConfigOptions("test", VARS)

View File

@@ -404,7 +404,7 @@ def test_exiftool_json_sidecar(photosdb):
with open(str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json"), "r") as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar()
json_got = PhotoExporter(photo).exiftool_json_sidecar()
json_got = json.loads(json_got)[0]
assert json_got == json_expected
@@ -420,7 +420,7 @@ def test_exiftool_json_sidecar_ignore_date_modified(photosdb):
) as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(ignore_date_modified=True)
)
json_got = json.loads(json_got)[0]
@@ -453,7 +453,7 @@ def test_exiftool_json_sidecar_keyword_template_long(capsys, photosdb):
long_str = "x" * (_MAX_IPTC_KEYWORD_LEN + 1)
photos[0]._verbose = print
json_got = PhotoExporter(photos[0])._exiftool_json_sidecar(
json_got = PhotoExporter(photos[0]).exiftool_json_sidecar(
ExportOptions(keyword_template=[long_str])
)
json_got = json.loads(json_got)[0]
@@ -479,7 +479,7 @@ def test_exiftool_json_sidecar_keyword_template(photosdb):
str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_keyword_template.json"), "r"
) as fp:
json_expected = json.load(fp)
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(keyword_template=["{folder_album}"])
)
json_got = json.loads(json_got)
@@ -497,7 +497,7 @@ def test_exiftool_json_sidecar_use_persons_keyword(photosdb):
) as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(use_persons_as_keywords=True)
)
json_got = json.loads(json_got)[0]
@@ -515,7 +515,7 @@ def test_exiftool_json_sidecar_use_albums_keywords(photosdb):
) as fp:
json_expected = json.load(fp)
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(use_albums_as_keywords=True)
)
json_got = json.loads(json_got)
@@ -530,7 +530,7 @@ def test_exiftool_sidecar(photosdb):
with open(pathlib.Path(SIDECAR_DIR) / f"{uuid}_no_tag_groups.json", "r") as fp:
json_expected = fp.read()
json_got = PhotoExporter(photo)._exiftool_json_sidecar(tag_groups=False)
json_got = PhotoExporter(photo).exiftool_json_sidecar(tag_groups=False)
assert json_got == json_expected

View File

@@ -50,6 +50,7 @@ def test_export_db():
assert db.get_uuid_for_file(filepath) is None
db.create_file_record(filepath, uuid)
assert db.get_uuid_for_file(filepath) == uuid
assert db.get_files_for_uuid(uuid) == [filepath]
record = db.get_file_record(filepath)
assert record.uuid == uuid
@@ -142,6 +143,7 @@ def test_export_db_in_memory():
assert record2.digest == DIGEST_DATA
assert record2.src_sig == (7, 8, 9)
assert record2.dest_sig == (10, 11, 12)
assert dbram.get_files_for_uuid(uuid) == [filepath]
# change some values
record2.photoinfo = INFO_DATA2

View File

@@ -337,7 +337,7 @@ def test_exiftool_json_sidecar(photosdb):
with open(str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json"), "r") as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar()
json_got = PhotoExporter(photo).exiftool_json_sidecar()
json_got = json.loads(json_got)[0]
assert json_got == json_expected