Compare commits

...

23 Commits

Author SHA1 Message Date
Rhet Turnbull
bf9961e203 Release v0.60.7 (#1114) 2023-07-15 08:11:06 -07:00
dvdkon
c63b08694e Add .AAE adjustment export (fix #97) (#1113)
Implements #97, export of adjustments data
2023-07-15 07:16:56 -07:00
Rhet Turnbull
30b0c13b33 Added docs for PlaceInfo.asdict() 2023-07-03 00:45:37 -07:00
Rhet Turnbull
1977578cfd Updated CHANGELOG.md [skip ci] 2023-07-02 13:27:51 -07:00
Rhet Turnbull
44a46cb652 Release v0.60.6, for real this time (#1112) 2023-07-02 09:42:57 -07:00
Rhet Turnbull
7ed8c7e583 Release v0.60.6 (#1110) 2023-07-02 09:34:29 -07:00
Rhet Turnbull
0064304574 Updated PlaceInfo to work with docs, #1100 (#1109) 2023-07-02 09:32:26 -07:00
Rhet Turnbull
179997aa96 Removed --library/--db from import command, #1105 (#1107) 2023-07-02 09:03:00 -07:00
allcontributors[bot]
889c878138 add msolo as a contributor for bug (#1106)
* update README.md [skip ci]

* update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-06-30 20:51:08 -05:00
Rhet Turnbull
2bac3a9c3e Updated CHANGELOG.md [skip ci] 2023-06-24 11:19:53 -07:00
Rhet Turnbull
3a1a4ad991 Release v0.60.5 (#1103) 2023-06-24 10:53:28 -07:00
Rhet Turnbull
2190628e82 Implemented --count, #1098 (#1102) 2023-06-24 10:50:34 -07:00
Rhet Turnbull
bb8e164f21 Unicode refactor (#1101)
* Began refactoring for improving unicode handling

* Added platform and unicode modules

* Added tests for unicode utilities

* Added tests for unicode utilities

* Added tests for unicode utilities

* Added tests for unicode utilities

* Fixed unicode tests for linux

* Fixed unicode tests for linux

* Fixed duplicate alubm name with --add-to-album

* Fixed test for linux

* Fix for duplicate unicode kewyords, see #907, #1085
2023-06-24 10:50:10 -07:00
Rhet Turnbull
7ccfe26e37 Added note on pipx reinstall: 2023-06-18 16:26:39 -07:00
Rhet Turnbull
2c80226ec8 fixed formatting (#1096) 2023-06-18 16:22:46 -07:00
Rhet Turnbull
492e1edb7f Updated CHANGELOG.md [skip ci] 2023-06-18 16:18:37 -07:00
Rhet Turnbull
72c6a165c7 Release v0.60.4 (#1095)
* Updated tested OS versions

* Version bump

* Release v0.60.4
2023-06-18 16:13:29 -07:00
Rhet Turnbull
e9aa289e8a Updated CHANGELOG.md [skip ci] 2023-06-18 10:03:57 -07:00
Rhet Turnbull
1fd73e5351 Release v0.60.3 (#1094) 2023-06-18 09:56:07 -07:00
Rhet Turnbull
8de871ccf1 Feature syndicated photos 1054 (#1093)
* Added find() to repl

* Added find() to repl

* Added support for syndicated photos #1054
2023-06-18 09:54:04 -07:00
allcontributors[bot]
0473b45631 add ces3001 as a contributor for bug (#1091)
* update README.md [skip ci]

* update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-06-17 07:38:06 -07:00
allcontributors[bot]
6b541b83ad add MaxLyt as a contributor for bug (#1090)
* update README.md [skip ci]

* update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-06-17 07:30:28 -07:00
Rhet Turnbull
633f3a92fa Updated CHANGELOG.md [skip ci] 2023-06-17 07:29:32 -07:00
158 changed files with 2523 additions and 617 deletions

View File

@@ -570,8 +570,36 @@
"bug",
"doc"
]
},
{
"login": "MaxLyt",
"name": "MaxLyt",
"avatar_url": "https://avatars.githubusercontent.com/u/136200430?v=4",
"profile": "https://github.com/MaxLyt",
"contributions": [
"bug"
]
},
{
"login": "ces3001",
"name": "ces3001",
"avatar_url": "https://avatars.githubusercontent.com/u/23762610?v=4",
"profile": "https://github.com/ces3001",
"contributions": [
"bug"
]
},
{
"login": "msolo",
"name": "msolo",
"avatar_url": "https://avatars.githubusercontent.com/u/5078276?v=4",
"profile": "https://github.com/msolo",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,
"skipCi": true
"skipCi": true,
"commitType": "docs"
}

View File

@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.60.2
current_version = 0.60.7
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
serialize = {major}.{minor}.{patch}

View File

@@ -339,10 +339,7 @@ to your function. You can then do whatever you want with the photos.
from __future__ import annotations
import osxphotos
from osxphotos.cli import (
selection_command,
verbose,
)
from osxphotos.cli import selection_command, verbose
@selection_command
@@ -390,7 +387,6 @@ Python < 3.11.
For example, the following code will work on Python >= 3.11. This code is available in the `examples` directory as
[concurrent_export.py](https://github.com/RhetTbull/osxphotos/blob/main/examples/concurrent_export.py).
```python
"""Example for concurrent export of photos using osxphotos.PhotoExporter.export()
@@ -1183,6 +1179,15 @@ Returns True if photo is a [cloud asset](#iscloudasset) and is synched to iCloud
**Note**: Applies to master (original) photo only. It's possible for the master to be in iCloud but a local edited version is not yet synched to iCloud. `incloud` provides status of only the master photo. osxphotos does not yet provide a means to determine if the edited version is in iCloud. If you need this feature, please open an [issue](https://github.com/RhetTbull/osxphotos/issues).
#### `syndicated`
Return true if photo was shared via syndication (e.g. via Messages, etc.); these are photos that appear in "Shared with you" album. Photos 8+ only; returns None if not Photos 8+.
#### `saved_to_library`
Return True if syndicated photo has been saved to library; returns False if photo is not syndicated or has not been saved to the library.
Syndicated photos are photos that appear in "Shared with you" album. Photos 8+ only; returns None if not Photos 8+.
#### `uti`
Returns Uniform Type Identifier (UTI) for the current version of the image, for example: 'public.jpeg' or 'com.apple. quicktime-movie'. If the image has been edited, `uti` will return the UTI for the edited image, otherwise it will return the UTI for the original image.
@@ -2494,7 +2499,7 @@ cog.out(get_template_field_table())
|{cr}|A carriage return: '\r'|
|{crlf}|A carriage return + line feed: '\r\n'|
|{tab}|:A tab: '\t'|
|{osxphotos_version}|The osxphotos version, e.g. '0.60.2'|
|{osxphotos_version}|The osxphotos version, e.g. '0.60.7'|
|{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

@@ -2,6 +2,110 @@
All notable changes to this project will be documented in this file.
## [v0.60.6](https://github.com/RhetTbull/osxphotos/compare/v0.60.5...v0.60.6)
Remove --library/--db from import command
### [v0.60.6] - 2023-07-02
#### Added
#### Removed
- Removed `--library/--db` options from `osxphotos import` as import does not allow user to specify a library; the last used library is always used for import
#### Changed
#### Contributors
- [@RhetTbull](https://github.com/RhetTbull) - Code and documentation
- [@msolo](https://github.com/msolo) - Bug report for `osxphotos import`
## [v0.60.5](https://github.com/RhetTbull/osxphotos/compare/v0.60.4...v0.60.5)
Unicode Fixes
### [v0.60.5] - 2023-06-24
#### Added
- Added `--count`to query to print count of query results and exit (#1098)
#### Removed
#### Changed
#### Fixed
- Normalize unicode for `osxphotos import` to avoid duplicate keywords and albums (#1087)
#### Contributors
- [@RhetTbull](https://github.com/RhetTbull/osxphotos) - code & testing
- [@oPromessa](https://github.com/oPromessa) - for finding and documenting the unicode bugs
## [v0.60.4](https://github.com/RhetTbull/osxphotos/compare/v0.60.3...v0.60.4)
Updated testing / compatibility matrix to include macOS 13.4.
### [v0.60.4] - 2023-06-18
#### Fixed
#### Added
#### Removed
#### Changed
#### Contributors
- [@RhetTbull](https://github.com/RhetTbull/osxphotos) - code & testing
## [v0.60.3](https://github.com/RhetTbull/osxphotos/compare/v0.60.2...v0.60.3)
Ventura introduced a "shared with you" album which shows photos shared via Messages (and possible other apps). These show up in the Photos library in the
"Shared with you" album but the images are stored in a different location that regular images so osxphotos could not previously access the images.
It can now do so.
### [v0.60.3] 2023-06-18
#### Fixed
#### Added
- `PhotoInfo.syndicated` property to identify syndicated photos.
- `PhotoInfo.saved_to_library` property to identify syndicated photos that have been saved to the library.
- `--syndicated`/`--not-syndicated`, `--saved-to-library`/`--not-saved-to-library` query options.
- `find()` function in `osxphotos repl` to search for files in the active Photos library directory.
#### Removed
#### Changed
#### Contributors
- [@RhetTbull](https://github.com/RhetTbull) for code.
## [v0.60.2](https://github.com/RhetTbull/osxphotos/compare/v0.60.1...v0.60.2)
Performance Improvements for --download-missing
### [v0.60.2] - 2023-06-17
#### Fixed
- Performance improvements for `osxphotos export` when used with `--download-missing` or `--sidecar XMP` options. (#1086)
#### Added
#### Changed
#### Contributors
- [@RhetTbull](https://github.com/RhetTbull) for code changes.
- [@MaxLyt](https://github.com/MaxLyt) for finding the issue.
## [v0.60.1](https://github.com/RhetTbull/osxphotos/compare/v0.60.0...v0.60.1)
Hot fix for a bug with in-memory database and --dry-run.
@@ -95,7 +199,8 @@ Performance Boost
- Removed lock files from export code (speed boost for NAS export, see #999); will need to eventually add this back for multithreaded export
- Optimized some code in export CLI to speed export
- Some linting fixed for move to ruff
-
-
#### Contributors
- [@RhetTbull](https://github.com/RhetTbull) for code changes.
@@ -195,15 +300,15 @@ See example code in [concurrent_export.py](https://github.com/RhetTbull/osxphoto
#### Added
- `--migrate-photos-library` option added to `osxphotos exportdb` to migrate the export database from one Photos library to another. This is useful when moving to a new computer but maintaining the existing osxphotos export. Thanks to @swduncan for the idea. (#990)
- `--migrate-photos-library` option added to `osxphotos exportdb` to migrate the export database from one Photos library to another. This is useful when moving to a new computer but maintaining the existing osxphotos export. Thanks to @swduncan for the idea. (#990)
#### Fixed
- Fixed a bug in `osxphotos export --cleanup` to handle files which could not be deleted. Thanks to @oPromessa for finding this and suggesting the fix. (#987)
- Fixed a bug in `osxphotos export --cleanup` to handle files which could not be deleted. Thanks to @oPromessa for finding this and suggesting the fix. (#987)
#### Internal
- Fixed a bug that caused `rich_echo()` to not display rich text if `--verbose` wasn't specified.
- Fixed a bug that caused `rich_echo()` to not display rich text if `--verbose` wasn't specified.
#### Contributors To This Release
@@ -211,10 +316,10 @@ See example code in [concurrent_export.py](https://github.com/RhetTbull/osxphoto
- [@Promessa](https://github.com/promessa) who found the cleanup bug and suggested a code fix.
- [@swduncan](https://github.com/swduncan) who suggested the library migrate use case.
## [v0.57.1](https://github.com/RhetTbull/osxphotos/compare/v0.57.0...v0.57.1)
### 12 February 2023
### Added show command, bug fix, refactoring
A bug fix and some refactoring to prepare for adding a parallel export mode. Also added `osxphotos show` command.
@@ -237,7 +342,6 @@ A bug fix and some refactoring to prepare for adding a parallel export mode. Als
- [@RhetTbull](https://github.com/RhetTbull)
- [@aa599](https://github.com/aa599) for reporting the timezone bug and suggesting change to `--uuid-from-file`
## [v0.57.0](https://github.com/RhetTbull/osxphotos/compare/v0.56.7...v0.57.0)
### 5 February 2023
@@ -269,7 +373,7 @@ for building simple command line tools.
#### Contributors
- @RhetTbull
- @RhetTbull
## [v0.56.7](https://github.com/RhetTbull/osxphotos/compare/v0.56.6...v0.56.7)
@@ -296,7 +400,6 @@ for building simple command line tools.
- @pweaver - thanks for finding the bug with `--dry-run` and `--finder-tag-keywords`
- @eecue for providing testing data
## [v0.56.6](https://github.com/RhetTbull/osxphotos/compare/v0.56.5...v0.56.6)
### 22 January 2023
@@ -345,7 +448,6 @@ for building simple command line tools.
- Thanks to @djbeadle for idea of adding SearchInfo.source
- Thanks for @oPromessa for testing `import` speed-ups and providing test data
### [v0.56.3](https://github.com/RhetTbull/osxphotos/compare/v0.56.2...v0.56.3)
### 16 January 2023
@@ -382,7 +484,7 @@ for building simple command line tools.
#### Contributors to this release
- @RhetTbull - Added AI scores to `osxphotos inspect`
- @RhetTbull - Added AI scores to `osxphotos inspect`
- @mave2k - Documentation fixes
- @oPromessa - Bug fix for metadata in `osxphotos import`
@@ -396,7 +498,6 @@ for building simple command line tools.
- Added new `osxphotos sync` command to sync metadata between libraries (#887)
## [v0.56.0](https://github.com/RhetTbull/osxphotos/compare/v0.55.7...v0.56.0)
### 13 January 2023
@@ -409,6 +510,7 @@ for building simple command line tools.
- Added PhotoInfo.fingerprint (#900)
#### Changed
- Added --profile, --watch, --breakpoint, --debug as global options; previously these worked only with export
#### New Contributors
@@ -416,6 +518,7 @@ for building simple command line tools.
- Added @oPromessa as a contributor for code
- Added @johnsturgeon as a contributor for bug, and doc
- Added @qkeddy as a contributor for ideas, and data
## [v0.55.7](https://github.com/RhetTbull/osxphotos/compare/v0.55.6...v0.55.7)
### 1 January 2023
@@ -434,6 +537,7 @@ for building simple command line tools.
### Updates for timewarp and export when reading/writing QuickTime dates
#### Changed
- Added QuickTime:ContentCreateDate as a source for `osxphotos timewarp`
- Write QuickTime:ContentCreateDate when exporting with --exiftool for `osxphotos export`
@@ -2223,7 +2327,7 @@ Thanks to @PetrochukM for identifying this and providing code!
- doc: start with examples before the export reference [`7c7bf1b`](https://github.com/RhetTbull/osxphotos/commit/7c7bf1be6b6382a995a4e17906adfd8720d0a1c3)
- Updated dependencies in README.md [`b1cab32`](https://github.com/RhetTbull/osxphotos/commit/b1cab32ff4c7b65ae4c9a5a9a11c175dbd487c0a)
- remove extra spaces [`a59bb5b`](https://github.com/RhetTbull/osxphotos/commit/a59bb5b02f10fa554dae346a7271be37f50d8bcc)
- Adding back dependency https://github.com/RhetTbull/PhotoScript) [`7c8bfc8`](https://github.com/RhetTbull/osxphotos/commit/7c8bfc811ab3a93dabadf1655f7d0e217d6c7b01)
- Adding back dependency <https://github.com/RhetTbull/PhotoScript>) [`7c8bfc8`](https://github.com/RhetTbull/osxphotos/commit/7c8bfc811ab3a93dabadf1655f7d0e217d6c7b01)
## [v0.39.6](https://github.com/RhetTbull/osxphotos/compare/v0.39.5...v0.39.6)

View File

@@ -7,7 +7,7 @@
[![Downloads](https://static.pepy.tech/personalized-badge/osxphotos?period=month&units=international_system&left_color=black&right_color=brightgreen&left_text=downloads/month)](https://pepy.tech/project/osxphotos)
[![subreddit](https://img.shields.io/reddit/subreddit-subscribers/osxphotos?style=social)](https://www.reddit.com/r/osxphotos/)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-59-orange.svg?style=flat)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-62-orange.svg?style=flat)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
OSXPhotos provides the ability to interact with and query Apple's Photos.app library on macOS and Linux. You can query the Photos library database — for example, file name, file path, and metadata such as keywords/tags, persons/faces, albums, etc. You can also easily export both the original and edited photos.
@@ -43,7 +43,7 @@ Tested on macOS Sierra (10.12.6) through macOS Ventura (13.3). Tested on both x8
| macOS Version | macOS name | Photos.app version |
| ----------------- |------------|:-------------------|
| 13.0 - 13.3 | Ventura | 8.0 ✅ |
| 13.0 - 13.4 | Ventura | 8.0 ✅ |
| 12.0 - 12.6 | Monterey | 7.0 ✅ |
| 10.16, 11.0-11.4 | Big Sur | 6.0 ✅ |
| 10.15.1 - 10.15.7 | Catalina | 5.0 ✅ |
@@ -74,6 +74,14 @@ Once you've installed osxphotos with pipx, to upgrade to the latest version:
pipx upgrade osxphotos
**Note**: When installing other packages with homebrew, homebrew may update the version of Python installed which would then cause any app (including osxphotos) installed with `pipx` to fail. If this happens, the easiest fix is to reinstall osxphotos with:
pipx reinstall osxphotos
Alternatively, you can reinstall all apps installed with `pipx` with:
pipx reinstall-all
### Installation using pip
You can also install directly from [pypi](https://pypi.org/project/osxphotos/):
@@ -132,15 +140,8 @@ Usage: osxphotos [OPTIONS] COMMAND [ARGS]...
osxphotos: the multi-tool for your Photos library
Options:
-v, --version Show the version and exit.
--library, --db PHOTOS_LIBRARY_PATH
Specify path to Photos library. If not
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.
-h, --help Show this message and exit.
-v, --version Show the version and exit.
-h, --help Show this message and exit.
Commands:
about Print information about osxphotos including license.
@@ -869,6 +870,16 @@ Options:
been synched)
--not-incloud Search for photos that are not in iCloud (have
not been synched)
--syndicated Search for photos that have been shared via
syndication ('Shared with You' album via
Messages, etc.)
--not-syndicated Search for photos that have not been shared
via syndication ('Shared with You' album via
Messages, etc.)
--saved-to-library Search for syndicated photos that have saved
to the library
--not-saved-to-library Search for syndicated photos that have not
saved to the library
--regex REGEX TEMPLATE Search for photos where TEMPLATE matches
regular expression REGEX. For example, to find
photos in an album that begins with 'Beach': '
@@ -1055,6 +1066,14 @@ Options:
export all burst images; only the primary
photo will be exported--associated burst
images will be skipped.
--export-aae Also export an adjustments file detailing
edits made to the original. The resulting file
is named photoname.AAE. Note that to import
these files back to Photos succesfully, you
also need to export the edited photo and match
the filename format Photos.app expects:
--filename 'IMG_{edited_version?E,}{id:04d}'
--edited-suffix ''
--sidecar FORMAT Create sidecar for each photo exported; valid
FORMAT values: xmp, json, exiftool; --sidecar
xmp: create XMP sidecar used by Digikam, Adobe
@@ -2099,7 +2118,7 @@ Substitution Description
{cr} A carriage return: '\r'
{crlf} A carriage return + line feed: '\r\n'
{tab} :A tab: '\t'
{osxphotos_version} The osxphotos version, e.g. '0.60.2'
{osxphotos_version} The osxphotos version, e.g. '0.60.7'
{osxphotos_cmd_line} The full command line used to run osxphotos
The following substitutions may result in multiple values. Thus if specified
@@ -2586,7 +2605,7 @@ The following template field substitutions are availabe for use the templating s
|{cr}|A carriage return: '\r'|
|{crlf}|A carriage return + line feed: '\r\n'|
|{tab}|:A tab: '\t'|
|{osxphotos_version}|The osxphotos version, e.g. '0.60.2'|
|{osxphotos_version}|The osxphotos version, e.g. '0.60.7'|
|{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|
@@ -2713,6 +2732,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dvdkon"><img src="https://avatars.githubusercontent.com/u/3526303?v=4?s=75" width="75px;" alt="dvdkon"/><br /><sub><b>dvdkon</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/commits?author=dvdkon" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wernerzj"><img src="https://avatars.githubusercontent.com/u/130370930?v=4?s=75" width="75px;" alt="wernerzj"/><br /><sub><b>wernerzj</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Awernerzj" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rajscode"><img src="https://avatars.githubusercontent.com/u/99123253?v=4?s=75" width="75px;" alt="rajscode"/><br /><sub><b>rajscode</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Arajscode" title="Bug reports">🐛</a> <a href="https://github.com/RhetTbull/osxphotos/commits?author=rajscode" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MaxLyt"><img src="https://avatars.githubusercontent.com/u/136200430?v=4?s=75" width="75px;" alt="MaxLyt"/><br /><sub><b>MaxLyt</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3AMaxLyt" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ces3001"><img src="https://avatars.githubusercontent.com/u/23762610?v=4?s=75" width="75px;" alt="ces3001"/><br /><sub><b>ces3001</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Aces3001" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/msolo"><img src="https://avatars.githubusercontent.com/u/5078276?v=4?s=75" width="75px;" alt="msolo"/><br /><sub><b>msolo</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Amsolo" title="Bug reports">🐛</a></td>
</tr>
</tbody>
</table>

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: c65b2fa3d733cf8df20a933bdfcfebb7
config: b4797f5f0cba9ef01218a6f2b8eb0959
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-5.3.0, furo 2022.09.29"/>
<title>Overview: module code - osxphotos 0.60.2 documentation</title>
<title>Overview: module code - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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-5.3.0, furo 2022.09.29"/>
<title>osxphotos._constants - osxphotos 0.60.1 documentation</title>
<title>osxphotos._constants - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.1 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.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.60.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -215,9 +215,6 @@
<span class="c1"># Apple Epoch is Jan 1, 2001</span>
<span class="n">TIME_DELTA</span> <span class="o">=</span> <span class="p">(</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2001</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">1970</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">()</span>
<span class="c1"># Unicode format to use for comparing strings</span>
<span class="n">UNICODE_FORMAT</span> <span class="o">=</span> <span class="s2">&quot;NFC&quot;</span>
<span class="c1"># which Photos library database versions have been tested</span>
<span class="c1"># Photos 2.0 (10.12.6) == 2622</span>
<span class="c1"># Photos 3.0 (10.13.6) == 3301</span>
@@ -326,6 +323,7 @@
<span class="p">(</span><span class="s2">&quot;13&quot;</span><span class="p">,</span> <span class="s2">&quot;1&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;13&quot;</span><span class="p">,</span> <span class="s2">&quot;2&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;13&quot;</span><span class="p">,</span> <span class="s2">&quot;3&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;13&quot;</span><span class="p">,</span> <span class="s2">&quot;4&quot;</span><span class="p">),</span>
<span class="p">]</span>
<span class="c1"># Photos 5 has persons who are empty string if unidentified face</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.export_db - osxphotos 0.60.2 documentation</title>
<title>osxphotos.export_db - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -224,7 +224,7 @@
<span class="kn">from</span> <span class="nn">._constants</span> <span class="kn">import</span> <span class="n">OSXPHOTOS_EXPORT_DB</span><span class="p">,</span> <span class="n">SQLITE_CHECK_SAME_THREAD</span>
<span class="kn">from</span> <span class="nn">._version</span> <span class="kn">import</span> <span class="n">__version__</span>
<span class="kn">from</span> <span class="nn">.fileutil</span> <span class="kn">import</span> <span class="n">FileUtil</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">normalize_fs_path</span>
<span class="kn">from</span> <span class="nn">.unicode</span> <span class="kn">import</span> <span class="n">normalize_fs_path</span>
<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;ExportDB&quot;</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.fileutil - osxphotos 0.60.0 documentation</title>
<title>osxphotos.fileutil - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.0 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.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.60.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -207,7 +207,8 @@
<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">.imageconverter</span> <span class="kn">import</span> <span class="n">ImageConverter</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">is_macos</span><span class="p">,</span> <span class="n">normalize_fs_path</span>
<span class="kn">from</span> <span class="nn">.platform</span> <span class="kn">import</span> <span class="n">is_macos</span>
<span class="kn">from</span> <span class="nn">.unicode</span> <span class="kn">import</span> <span class="n">normalize_fs_path</span>
<span class="k">if</span> <span class="n">is_macos</span><span class="p">:</span>
<span class="kn">import</span> <span class="nn">Foundation</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.photoexporter - osxphotos 0.60.2 documentation</title>
<title>osxphotos.photoexporter - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">
@@ -233,17 +233,17 @@
<span class="kn">from</span> <span class="nn">.export_db</span> <span class="kn">import</span> <span class="n">ExportDB</span><span class="p">,</span> <span class="n">ExportDBTemp</span>
<span class="kn">from</span> <span class="nn">.fileutil</span> <span class="kn">import</span> <span class="n">FileUtil</span>
<span class="kn">from</span> <span class="nn">.phototemplate</span> <span class="kn">import</span> <span class="n">RenderOptions</span>
<span class="kn">from</span> <span class="nn">.platform</span> <span class="kn">import</span> <span class="n">is_macos</span>
<span class="kn">from</span> <span class="nn">.rich_utils</span> <span class="kn">import</span> <span class="n">add_rich_markup_tag</span>
<span class="kn">from</span> <span class="nn">.unicode</span> <span class="kn">import</span> <span class="n">normalize_fs_path</span>
<span class="kn">from</span> <span class="nn">.uti</span> <span class="kn">import</span> <span class="n">get_preferred_uti_extension</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">hexdigest</span><span class="p">,</span>
<span class="n">increment_filename</span><span class="p">,</span>
<span class="n">increment_filename_with_count</span><span class="p">,</span>
<span class="n">is_macos</span><span class="p">,</span>
<span class="n">lineno</span><span class="p">,</span>
<span class="n">list_directory</span><span class="p">,</span>
<span class="n">lock_filename</span><span class="p">,</span>
<span class="n">normalize_fs_path</span><span class="p">,</span>
<span class="n">unlock_filename</span><span class="p">,</span>
<span class="p">)</span>
@@ -332,6 +332,7 @@
<span class="sd"> render_options (RenderOptions): t.Optional osxphotos.phototemplate.RenderOptions instance to specify options for rendering templates</span>
<span class="sd"> replace_keywords (bool): if True, keyword_template replaces any keywords, otherwise it&#39;s additive</span>
<span class="sd"> rich (bool): if True, will use rich markup with verbose output</span>
<span class="sd"> export_aae (bool): if True, also exports adjustments as .AAE file</span>
<span class="sd"> sidecar_drop_ext (bool, default=False): if True, drops the photo&#39;s extension from sidecar filename (e.g. &#39;IMG_1234.json&#39; instead of &#39;IMG_1234.JPG.json&#39;)</span>
<span class="sd"> sidecar: bit field (int): set to one or more of `SIDECAR_XMP`, `SIDECAR_JSON`, `SIDECAR_EXIFTOOL`</span>
<span class="sd"> - SIDECAR_JSON: if set will write a json sidecar with data in format readable by exiftool sidecar filename will be dest/filename.json;</span>
@@ -384,6 +385,7 @@
<span class="n">render_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">RenderOptions</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">replace_keywords</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">rich</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">export_aae</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">sidecar_drop_ext</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">sidecar</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">strip</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
@@ -478,6 +480,7 @@
<span class="s2">&quot;missing&quot;</span><span class="p">,</span>
<span class="s2">&quot;missing_album&quot;</span><span class="p">,</span>
<span class="s2">&quot;new&quot;</span><span class="p">,</span>
<span class="s2">&quot;aae_written&quot;</span><span class="p">,</span>
<span class="s2">&quot;sidecar_exiftool_skipped&quot;</span><span class="p">,</span>
<span class="s2">&quot;sidecar_exiftool_written&quot;</span><span class="p">,</span>
<span class="s2">&quot;sidecar_json_skipped&quot;</span><span class="p">,</span>
@@ -508,6 +511,7 @@
<span class="n">missing</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">missing_album</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">new</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">aae_written</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">sidecar_exiftool_skipped</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">sidecar_exiftool_written</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">sidecar_json_skipped</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
@@ -547,6 +551,7 @@
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">exif_updated</span>
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">touched</span>
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">converted_to_jpeg</span>
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">aae_written</span>
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">sidecar_json_written</span>
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">sidecar_json_skipped</span>
<span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">sidecar_exiftool_written</span>
@@ -802,6 +807,8 @@
<span class="sa">f</span><span class="s2">&quot;Skipping missing preview photo for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filename</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">original_filename</span><span class="p">)</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">uuid</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">export_aae</span><span class="p">:</span>
<span class="n">all_results</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_write_aae_file</span><span class="p">(</span><span class="n">dest</span><span class="o">=</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>
<span class="n">all_results</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_write_sidecar_files</span><span class="p">(</span><span class="n">dest</span><span class="o">=</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>
<span class="k">return</span> <span class="n">all_results</span></div>
@@ -1601,6 +1608,53 @@
<span class="n">exported_paths</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">dest_new</span><span class="p">))</span>
<span class="k">return</span> <span class="n">exported_paths</span>
<span class="k">def</span> <span class="nf">_write_aae_file</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">pathlib</span><span class="o">.</span><span class="n">Path</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">&quot;&quot;&quot;Write AAE file for the photo.&quot;&quot;&quot;</span>
<span class="c1"># AAE files describe adjustments to originals, so they don&#39;t make sense</span>
<span class="c1"># for edited files</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">edited</span><span class="p">:</span>
<span class="k">return</span> <span class="n">ExportResults</span><span class="p">()</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">aae_src</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">adjustments_path</span>
<span class="k">if</span> <span class="n">aae_src</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">ExportResults</span><span class="p">()</span>
<span class="n">aae_dest</span> <span class="o">=</span> <span class="n">dest</span><span class="o">.</span><span class="n">with_suffix</span><span class="p">(</span><span class="s2">&quot;.AAE&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">export_as_hardlink</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">aae_dest</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span> <span class="ow">and</span> <span class="nb">any</span><span class="p">(</span>
<span class="p">[</span><span class="n">options</span><span class="o">.</span><span class="n">overwrite</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">force_update</span><span class="p">]):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">options</span><span class="o">.</span><span class="n">fileutil</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="n">aae_dest</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">ExportError</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Error removing file </span><span class="si">{</span><span class="n">aae_dest</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2"> ((</span><span class="si">{</span><span class="n">lineno</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="p">)</span> <span class="kn">from</span> <span class="nn">e</span>
<span class="n">options</span><span class="o">.</span><span class="n">fileutil</span><span class="o">.</span><span class="n">hardlink</span><span class="p">(</span><span class="n">aae_src</span><span class="p">,</span> <span class="n">aae_dest</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">ExportError</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Error hardlinking </span><span class="si">{</span><span class="n">aae_src</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">aae_dest</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">lineno</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="p">)</span> <span class="kn">from</span> <span class="nn">e</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">options</span><span class="o">.</span><span class="n">fileutil</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">aae_src</span><span class="p">,</span> <span class="n">aae_dest</span><span class="p">)</span>
<span class="n">verbose</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Exported adjustments of </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filename</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">original_filename</span><span class="p">)</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath</span><span class="p">(</span><span class="n">normalize_fs_path</span><span class="p">(</span><span class="n">aae_dest</span><span class="p">))</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">ExportError</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Error copying file </span><span class="si">{</span><span class="n">aae_src</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">aae_dest</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">lineno</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="p">)</span> <span class="kn">from</span> <span class="nn">e</span>
<span class="k">return</span> <span class="n">ExportResults</span><span class="p">(</span><span class="n">aae_written</span><span class="o">=</span><span class="p">[</span><span class="n">aae_dest</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">_write_sidecar_files</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">pathlib</span><span class="o">.</span><span class="n">Path</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.photoinfo - osxphotos 0.60.2 documentation</title>
<title>osxphotos.photoinfo - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">
@@ -258,14 +258,16 @@
<span class="kn">from</span> <span class="nn">.phototables</span> <span class="kn">import</span> <span class="n">PhotoTables</span>
<span class="kn">from</span> <span class="nn">.phototemplate</span> <span class="kn">import</span> <span class="n">PhotoTemplate</span><span class="p">,</span> <span class="n">RenderOptions</span>
<span class="kn">from</span> <span class="nn">.placeinfo</span> <span class="kn">import</span> <span class="n">PlaceInfo4</span><span class="p">,</span> <span class="n">PlaceInfo5</span>
<span class="kn">from</span> <span class="nn">.platform</span> <span class="kn">import</span> <span class="n">assert_macos</span><span class="p">,</span> <span class="n">is_macos</span>
<span class="kn">from</span> <span class="nn">.query_builder</span> <span class="kn">import</span> <span class="n">get_query</span>
<span class="kn">from</span> <span class="nn">.scoreinfo</span> <span class="kn">import</span> <span class="n">ScoreInfo</span>
<span class="kn">from</span> <span class="nn">.searchinfo</span> <span class="kn">import</span> <span class="n">SearchInfo</span>
<span class="kn">from</span> <span class="nn">.uti</span> <span class="kn">import</span> <span class="n">get_preferred_uti_extension</span><span class="p">,</span> <span class="n">get_uti_for_extension</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">_get_resource_loc</span><span class="p">,</span> <span class="n">assert_macos</span><span class="p">,</span> <span class="n">is_macos</span><span class="p">,</span> <span class="n">hexdigest</span><span class="p">,</span> <span class="n">list_directory</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">_get_resource_loc</span><span class="p">,</span> <span class="n">hexdigest</span><span class="p">,</span> <span class="n">list_directory</span>
<span class="k">if</span> <span class="n">is_macos</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">osxmetadata</span> <span class="kn">import</span> <span class="n">OSXMetaData</span>
<span class="kn">from</span> <span class="nn">.text_detection</span> <span class="kn">import</span> <span class="n">detect_text</span>
<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;PhotoInfo&quot;</span><span class="p">,</span> <span class="s2">&quot;PhotoInfoNone&quot;</span><span class="p">,</span> <span class="s2">&quot;frozen_photoinfo_factory&quot;</span><span class="p">]</span>
@@ -331,8 +333,7 @@
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="n">imagedate</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;lastmodifieddate&quot;</span><span class="p">]</span>
<span class="k">if</span> <span class="n">imagedate</span><span class="p">:</span>
<span class="k">if</span> <span class="n">imagedate</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;lastmodifieddate&quot;</span><span class="p">]:</span>
<span class="n">seconds</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;imageTimeZoneOffsetSeconds&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="mi">0</span>
<span class="n">delta</span> <span class="o">=</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">seconds</span><span class="o">=</span><span class="n">seconds</span><span class="p">)</span>
<span class="n">tz</span> <span class="o">=</span> <span class="n">timezone</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span>
@@ -369,6 +370,9 @@
<span class="sd">&quot;&quot;&quot;Returns candidate path for original photo on Photos &gt;= version 5&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;shared&quot;</span><span class="p">]:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_5_shared</span><span class="p">()</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">syndicated</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">saved_to_library</span><span class="p">:</span>
<span class="c1"># path for &quot;shared with you&quot; syndicated photos that have not yet been saved to the library</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_syndication</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">_info</span><span class="p">[</span><span class="s2">&quot;directory&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;filename&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;directory&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span>
@@ -408,6 +412,21 @@
<span class="n">filename</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">_path_syndication</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return path for syndicated photo on Photos &gt;= version 8&quot;&quot;&quot;</span>
<span class="c1"># Photos 8+ stores syndicated photos in a separate directory</span>
<span class="c1"># in ~/Photos Library.photoslibrary/scopes/syndication/originals/X/UUID.ext</span>
<span class="c1"># where X is first digit of UUID</span>
<span class="n">syndication_path</span> <span class="o">=</span> <span class="s2">&quot;scopes/syndication/originals&quot;</span>
<span class="n">uuid_dir</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">,</span>
<span class="n">syndication_path</span><span class="p">,</span>
<span class="n">uuid_dir</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">path</span> <span class="k">if</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">path</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">_path_4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Returns candidate path for original photo on Photos &lt;= version 4&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;has_raw&quot;</span><span class="p">]:</span>
@@ -828,28 +847,38 @@
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;hasAdjustments&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">adjustments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only&quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">adjustments_path</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Returns path to adjustments file or none if file doesn&#39;t exist&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="n">library</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span>
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
<span class="n">plist_file</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">library</span><span class="p">)</span>
<span class="o">/</span> <span class="s2">&quot;resources&quot;</span>
<span class="o">/</span> <span class="s2">&quot;renders&quot;</span>
<span class="o">/</span> <span class="n">directory</span>
<span class="o">/</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">.plist&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">plist_file</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span> <span class="o">=</span> <span class="n">AdjustmentsInfo</span><span class="p">(</span><span class="n">plist_file</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="n">library</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span>
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
<span class="n">plist_file</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">library</span><span class="p">)</span>
<span class="o">/</span> <span class="s2">&quot;resources&quot;</span>
<span class="o">/</span> <span class="s2">&quot;renders&quot;</span>
<span class="o">/</span> <span class="n">directory</span>
<span class="o">/</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">.plist&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">plist_file</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">return</span> <span class="n">plist_file</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">adjustments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only&quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="n">plist_file</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">adjustments_path</span>
<span class="k">if</span> <span class="n">plist_file</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span> <span class="o">=</span> <span class="n">AdjustmentsInfo</span><span class="p">(</span><span class="n">plist_file</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adjustmentinfo</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">external_edit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
@@ -1078,6 +1107,10 @@
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">live_photo</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismissing</span><span class="p">:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_live_photo_shared_5</span><span class="p">()</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">syndicated</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">saved_to_library</span><span class="p">:</span>
<span class="c1"># syndicated (&quot;Shared with you&quot;) photos not yet saved to library</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_live_syndicated</span><span class="p">()</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">)</span>
<span class="n">photopath</span> <span class="o">=</span> <span class="n">filename</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">filename</span><span class="o">.</span><span class="n">stem</span><span class="si">}</span><span class="s2">_3.mov&quot;</span><span class="p">)</span>
<span class="n">photopath</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">photopath</span><span class="p">)</span>
@@ -1135,8 +1168,24 @@
<span class="n">photopath</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">return</span> <span class="n">photopath</span>
<span class="k">def</span> <span class="nf">_path_live_syndicated</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return path for live syndicated photo on Photos &gt;= version 8&quot;&quot;&quot;</span>
<span class="c1"># Photos 8+ stores live syndicated photos in a separate directory</span>
<span class="c1"># in ~/Photos Library.photoslibrary/scopes/syndication/originals/X/UUID_3.mov</span>
<span class="c1"># where X is first digit of UUID</span>
<span class="n">syndication_path</span> <span class="o">=</span> <span class="s2">&quot;scopes/syndication/originals&quot;</span>
<span class="n">uuid_dir</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">stem</span><span class="si">}</span><span class="s2">_3.mov&quot;</span>
<span class="n">live_photo</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">,</span>
<span class="n">syndication_path</span><span class="p">,</span>
<span class="n">uuid_dir</span><span class="p">,</span>
<span class="n">filename</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">live_photo</span> <span class="k">if</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">live_photo</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span>
<span class="nd">@cached_property</span>
<span class="k">def</span> <span class="nf">path_derivatives</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">path_derivatives</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="sd">&quot;&quot;&quot;Return any derivative (preview) images associated with the photo as a list of paths, sorted by file size (largest first)&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives_4</span><span class="p">()</span>
@@ -1145,24 +1194,36 @@
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path_derivatives_5_shared</span><span class="p">()</span>
<span class="n">directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first char of uuid</span>
<span class="n">derivative_path</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span> <span class="o">/</span> <span class="sa">f</span><span class="s2">&quot;resources/derivatives/</span><span class="si">{</span><span class="n">directory</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">syndicated</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">saved_to_library</span><span class="p">:</span>
<span class="c1"># syndicated (&quot;Shared with you&quot;) photos not yet saved to library</span>
<span class="n">derivative_path</span> <span class="o">=</span> <span class="s2">&quot;scopes/syndication/resources/derivatives&quot;</span>
<span class="n">thumb_path</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">derivative_path</span><span class="si">}</span><span class="s2">/masters/</span><span class="si">{</span><span class="n">directory</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">_4_5005_c.jpeg&quot;</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">derivative_path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;resources/derivatives/</span><span class="si">{</span><span class="n">directory</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">thumb_path</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;resources/derivatives/masters/</span><span class="si">{</span><span class="n">directory</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">_4_5005_c.jpeg&quot;</span>
<span class="p">)</span>
<span class="n">derivative_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="n">derivative_path</span><span class="p">)</span>
<span class="n">thumb_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="n">thumb_path</span><span class="p">)</span>
<span class="c1"># find all files that start with uuid in derivative path</span>
<span class="n">files</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">derivative_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">*.*&quot;</span><span class="p">))</span>
<span class="c1"># previews may be missing from derivatives path</span>
<span class="c1"># there are what appear to be low res thumbnails in the &quot;masters&quot; subfolder</span>
<span class="n">thumb_path</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span>
<span class="o">/</span> <span class="sa">f</span><span class="s2">&quot;resources/derivatives/masters/</span><span class="si">{</span><span class="n">directory</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">_4_5005_c.jpeg&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">thumb_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
<span class="n">files</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">thumb_path</span><span class="p">)</span>
<span class="c1"># sort by file size, largest first</span>
<span class="n">files</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">files</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span><span class="o">.</span><span class="n">st_size</span><span class="p">)</span>
<span class="c1"># return list of filename but skip .THM files (these are actually low-res thumbnails in JPEG format but with .THM extension)</span>
<span class="n">derivatives</span> <span class="o">=</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">files</span> <span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">suffix</span> <span class="o">!=</span> <span class="s2">&quot;.THM&quot;</span><span class="p">]</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">derivatives</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;.mov&quot;</span><span class="p">):</span>
<span class="c1"># ensure .mov is first in list as poster image could be larger than the movie preview</span>
<span class="n">derivatives</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">derivatives</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">return</span> <span class="n">derivatives</span>
@@ -1481,6 +1542,38 @@
<span class="bp">self</span><span class="o">.</span><span class="n">_search_info_normalized</span> <span class="o">=</span> <span class="n">SearchInfo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">normalized</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_search_info_normalized</span>
<span class="nd">@cached_property</span>
<span class="k">def</span> <span class="nf">syndicated</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Return true if photo was shared via syndication (e.g. via Messages, etc.);</span>
<span class="sd"> these are photos that appear in &quot;Shared with you&quot; album.</span>
<span class="sd"> Photos 8+ only; returns None if not Photos 8+.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">photos_version</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_syndication_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">&quot;syndication_identifier&quot;</span><span class="p">]</span>
<span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="nd">@cached_property</span>
<span class="k">def</span> <span class="nf">saved_to_library</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Return True if syndicated photo has been saved to library;</span>
<span class="sd"> returns False if photo is not syndicated or has not been saved to the library.</span>
<span class="sd"> Returns None if not Photos 8+.</span>
<span class="sd"> Syndicated photos are photos that appear in &quot;Shared with you&quot; album; Photos 8+ only.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">photos_version</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_syndication_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">&quot;syndication_history&quot;</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">labels</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;returns list of labels applied to photo by Photos image categorization</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.photosalbum - osxphotos 0.60.0 documentation</title>
<title>osxphotos.photosalbum - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.0 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.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.60.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -197,12 +197,16 @@
<h1>Source code for osxphotos.photosalbum</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot; PhotosAlbum class to create an album in default Photos library and add photos to it &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
<span class="kn">import</span> <span class="nn">unicodedata</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span>
<span class="kn">from</span> <span class="nn">more_itertools</span> <span class="kn">import</span> <span class="n">chunked</span>
<span class="kn">from</span> <span class="nn">.photoinfo</span> <span class="kn">import</span> <span class="n">PhotoInfo</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">assert_macos</span><span class="p">,</span> <span class="n">noop</span><span class="p">,</span> <span class="n">pluralize</span>
<span class="kn">from</span> <span class="nn">.platform</span> <span class="kn">import</span> <span class="n">assert_macos</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">noop</span><span class="p">,</span> <span class="n">pluralize</span>
<span class="n">assert_macos</span><span class="p">()</span>
@@ -212,19 +216,36 @@
<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;PhotosAlbum&quot;</span><span class="p">,</span> <span class="s2">&quot;PhotosAlbumPhotoScript&quot;</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">get_unicode_variants</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="sd">&quot;&quot;&quot;Get all unicode variants of string&quot;&quot;&quot;</span>
<span class="n">variants</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">form</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;NFC&quot;</span><span class="p">,</span> <span class="s2">&quot;NFD&quot;</span><span class="p">,</span> <span class="s2">&quot;NFKC&quot;</span><span class="p">,</span> <span class="s2">&quot;NFKD&quot;</span><span class="p">]:</span>
<span class="n">normalized</span> <span class="o">=</span> <span class="n">unicodedata</span><span class="o">.</span><span class="n">normalize</span><span class="p">(</span><span class="n">form</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
<span class="n">variants</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">normalized</span><span class="p">)</span>
<span class="k">return</span> <span class="n">variants</span>
<span class="k">def</span> <span class="nf">folder_by_path</span><span class="p">(</span><span class="n">folders</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">verbose</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">callable</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Folder</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Get (and create if necessary) a Photos Folder by path (passed as list of folder names)&quot;&quot;&quot;</span>
<span class="n">library</span> <span class="o">=</span> <span class="n">PhotosLibrary</span><span class="p">()</span>
<span class="n">verbose</span> <span class="o">=</span> <span class="n">verbose</span> <span class="ow">or</span> <span class="n">noop</span>
<span class="n">top_folder_name</span> <span class="o">=</span> <span class="n">folders</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">top_folder</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">folder</span><span class="p">(</span><span class="n">top_folder_name</span><span class="p">,</span> <span class="n">top_level</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">top_folder</span><span class="p">:</span>
<span class="k">for</span> <span class="n">folder_variant</span> <span class="ow">in</span> <span class="n">get_unicode_variants</span><span class="p">(</span><span class="n">top_folder_name</span><span class="p">):</span>
<span class="n">top_folder</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">folder</span><span class="p">(</span><span class="n">folder_variant</span><span class="p">,</span> <span class="n">top_level</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="n">top_folder</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Creating folder &#39;</span><span class="si">{</span><span class="n">top_folder_name</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
<span class="n">top_folder</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">create_folder</span><span class="p">(</span><span class="n">top_folder_name</span><span class="p">)</span>
<span class="n">current_folder</span> <span class="o">=</span> <span class="n">top_folder</span>
<span class="k">for</span> <span class="n">folder_name</span> <span class="ow">in</span> <span class="n">folders</span><span class="p">:</span>
<span class="n">folder</span> <span class="o">=</span> <span class="n">current_folder</span><span class="o">.</span><span class="n">folder</span><span class="p">(</span><span class="n">folder_name</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">folder</span><span class="p">:</span>
<span class="k">for</span> <span class="n">folder_variant</span> <span class="ow">in</span> <span class="n">get_unicode_variants</span><span class="p">(</span><span class="n">folder_name</span><span class="p">):</span>
<span class="n">folder</span> <span class="o">=</span> <span class="n">current_folder</span><span class="o">.</span><span class="n">folder</span><span class="p">(</span><span class="n">folder_variant</span><span class="p">)</span>
<span class="k">if</span> <span class="n">folder</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Creating folder &#39;</span><span class="si">{</span><span class="n">folder_name</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
<span class="n">folder</span> <span class="o">=</span> <span class="n">current_folder</span><span class="o">.</span><span class="n">create_folder</span><span class="p">(</span><span class="n">folder_name</span><span class="p">)</span>
<span class="n">current_folder</span> <span class="o">=</span> <span class="n">folder</span>
@@ -241,15 +262,24 @@
<span class="c1"># have folders</span>
<span class="n">album_name</span> <span class="o">=</span> <span class="n">folders_album</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="n">folder</span> <span class="o">=</span> <span class="n">folder_by_path</span><span class="p">(</span><span class="n">folders_album</span><span class="p">,</span> <span class="n">verbose</span><span class="p">)</span>
<span class="n">album</span> <span class="o">=</span> <span class="n">folder</span><span class="o">.</span><span class="n">album</span><span class="p">(</span><span class="n">album_name</span><span class="p">)</span>
<span class="k">if</span> <span class="n">album</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">for</span> <span class="n">album_variant</span> <span class="ow">in</span> <span class="n">get_unicode_variants</span><span class="p">(</span><span class="n">album_name</span><span class="p">):</span>
<span class="c1"># Get album if it exists</span>
<span class="c1"># need to check every unicode variant to avoid creating duplicate albums with same visual representation (#1085)</span>
<span class="n">album</span> <span class="o">=</span> <span class="n">folder</span><span class="o">.</span><span class="n">album</span><span class="p">(</span><span class="n">album_variant</span><span class="p">)</span>
<span class="k">if</span> <span class="n">album</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Creating album &#39;</span><span class="si">{</span><span class="n">album_name</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
<span class="n">album</span> <span class="o">=</span> <span class="n">folder</span><span class="o">.</span><span class="n">create_album</span><span class="p">(</span><span class="n">album_name</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># only have album name</span>
<span class="n">album_name</span> <span class="o">=</span> <span class="n">folders_album</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">album</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">album</span><span class="p">(</span><span class="n">album_name</span><span class="p">,</span> <span class="n">top_level</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="n">album</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">for</span> <span class="n">album_variant</span> <span class="ow">in</span> <span class="n">get_unicode_variants</span><span class="p">(</span><span class="n">album_name</span><span class="p">):</span>
<span class="n">album</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">album</span><span class="p">(</span><span class="n">album_variant</span><span class="p">,</span> <span class="n">top_level</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="n">album</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># album doesn&#39;t exist, create it</span>
<span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Creating album &#39;</span><span class="si">{</span><span class="n">album_name</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
<span class="n">album</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">create_album</span><span class="p">(</span><span class="n">album_name</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.photosdb._photosdb_process_comments - osxphotos 0.60.2 documentation</title>
<title>osxphotos.photosdb._photosdb_process_comments - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../../../index.html"><div class="brand">osxphotos 0.60.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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -203,8 +203,8 @@
<span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span> <span class="nn">.._constants</span> <span class="kn">import</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">,</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">,</span> <span class="n">TIME_DELTA</span>
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="kn">from</span> <span class="nn">..sqlite_utils</span> <span class="kn">import</span> <span class="n">sqlite_open_ro</span>
<span class="kn">from</span> <span class="nn">..unicode</span> <span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="k">def</span> <span class="nf">_process_comments</span><span class="p">(</span><span class="bp">self</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.photosdb.photosdb - osxphotos 0.60.2 documentation</title>
<title>osxphotos.photosdb.photosdb - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../../../index.html"><div class="brand">osxphotos 0.60.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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -253,17 +253,12 @@
<span class="kn">from</span> <span class="nn">..personinfo</span> <span class="kn">import</span> <span class="n">PersonInfo</span>
<span class="kn">from</span> <span class="nn">..photoinfo</span> <span class="kn">import</span> <span class="n">PhotoInfo</span>
<span class="kn">from</span> <span class="nn">..phototemplate</span> <span class="kn">import</span> <span class="n">RenderOptions</span>
<span class="kn">from</span> <span class="nn">..platform</span> <span class="kn">import</span> <span class="n">get_macos_version</span><span class="p">,</span> <span class="n">is_macos</span>
<span class="kn">from</span> <span class="nn">..queryoptions</span> <span class="kn">import</span> <span class="n">QueryOptions</span>
<span class="kn">from</span> <span class="nn">..rich_utils</span> <span class="kn">import</span> <span class="n">add_rich_markup_tag</span>
<span class="kn">from</span> <span class="nn">..sqlite_utils</span> <span class="kn">import</span> <span class="n">sqlite_db_is_locked</span><span class="p">,</span> <span class="n">sqlite_open_ro</span>
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">_check_file_exists</span><span class="p">,</span>
<span class="n">is_macos</span><span class="p">,</span>
<span class="n">get_macos_version</span><span class="p">,</span>
<span class="n">get_last_library_path</span><span class="p">,</span>
<span class="n">noop</span><span class="p">,</span>
<span class="n">normalize_unicode</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..unicode</span> <span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="n">_check_file_exists</span><span class="p">,</span> <span class="n">get_last_library_path</span><span class="p">,</span> <span class="n">noop</span>
<span class="kn">from</span> <span class="nn">.photosdb_utils</span> <span class="kn">import</span> <span class="n">get_db_model_version</span><span class="p">,</span> <span class="n">get_db_version</span>
<span class="k">if</span> <span class="n">is_macos</span><span class="p">:</span>
@@ -293,6 +288,7 @@
<span class="n">labels_normalized</span><span class="p">,</span>
<span class="n">labels_normalized_as_dict</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">._photosdb_process_syndicationinfo</span> <span class="kn">import</span> <span class="n">_process_syndicationinfo</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
@@ -487,6 +483,10 @@
<span class="c1"># Dict to hold data on imports for Photos &lt;= 4</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_db_import_group</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># Dict to hold syndication info for Photos &gt;= 8</span>
<span class="c1"># key is UUID and value is dict of syndication info</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_db_syndication_uuid</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;dbfile = </span><span class="si">{</span><span class="n">dbfile</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">dbfile</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
@@ -2714,6 +2714,10 @@
<span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing moments.&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_process_moments</span><span class="p">()</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photos_version</span> <span class="o">&gt;=</span> <span class="mi">8</span><span class="p">:</span>
<span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing syndication info.&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_process_syndicationinfo</span><span class="p">()</span>
<span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Done processing details from Photos library.&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_process_moments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
@@ -3713,6 +3717,16 @@
<span class="n">added_after</span> <span class="o">=</span> <span class="n">datetime_naive_to_local</span><span class="p">(</span><span class="n">added_after</span><span class="p">)</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date_added</span> <span class="ow">and</span> <span class="n">p</span><span class="o">.</span><span class="n">date_added</span> <span class="o">&gt;</span> <span class="n">added_after</span><span class="p">]</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">syndicated</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">syndicated</span><span class="p">]</span>
<span class="k">elif</span> <span class="n">options</span><span class="o">.</span><span class="n">not_syndicated</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">syndicated</span><span class="p">]</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">saved_to_library</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">syndicated</span> <span class="ow">and</span> <span class="n">p</span><span class="o">.</span><span class="n">saved_to_library</span><span class="p">]</span>
<span class="k">elif</span> <span class="n">options</span><span class="o">.</span><span class="n">not_saved_to_library</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">syndicated</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">saved_to_library</span><span class="p">]</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">function</span><span class="p">:</span>
<span class="k">for</span> <span class="n">function</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">function</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="n">function</span><span class="p">[</span><span class="mi">0</span><span class="p">](</span><span class="n">photos</span><span class="p">)</span>

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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.placeinfo - osxphotos 0.60.0 documentation</title>
<title>osxphotos.placeinfo - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.0 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.7 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.60.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">
@@ -202,14 +202,16 @@
<span class="sd"> See https://developer.apple.com/documentation/corelocation/clplacemark</span>
<span class="sd"> for additional documentation on reverse geolocation data</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
<span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">namedtuple</span> <span class="c1"># pylint: disable=syntax-error</span>
<span class="kn">import</span> <span class="nn">yaml</span>
<span class="kn">from</span> <span class="nn">bpylist2</span> <span class="kn">import</span> <span class="n">archiver</span>
<span class="kn">from</span> <span class="nn">._constants</span> <span class="kn">import</span> <span class="n">UNICODE_FORMAT</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="kn">from</span> <span class="nn">.unicode</span> <span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;PLRevGeoLocationInfo&quot;</span><span class="p">,</span>
@@ -529,36 +531,101 @@
<span class="n">archiver</span><span class="o">.</span><span class="n">update_class_map</span><span class="p">({</span><span class="s2">&quot;PLRevGeoLocationInfo&quot;</span><span class="p">:</span> <span class="n">PLRevGeoLocationInfo</span><span class="p">})</span>
<div class="viewcode-block" id="PlaceInfo"><a class="viewcode-back" href="../../reference.html#osxphotos.PlaceInfo">[docs]</a><span class="k">class</span> <span class="nc">PlaceInfo</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
<span class="c1"># PlaceInfo is really an abstract base class but defining it as such</span>
<span class="c1"># means it doesn&#39;t get picked up by the doc generation tools</span>
<span class="c1"># so we define it as a regular class and then subclass it</span>
<span class="c1"># TODO: right fix is probably have PlaceInfo as the only class that</span>
<span class="c1"># is used and then have PlaceInfo4 and PlaceInfo5 called by PlaceInfo</span>
<span class="c1"># as needed to return the properties (and make them private classes)</span>
<div class="viewcode-block" id="PlaceInfo"><a class="viewcode-back" href="../../reference.html#osxphotos.PlaceInfo">[docs]</a><span class="k">class</span> <span class="nc">PlaceInfo</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Reverse geolocation place info for a photo.&quot;&quot;&quot;</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">address_str</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">address_str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Returns the full postal address as a string if defined, otherwise `None`.&quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">country_code</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">country_code</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Returns the country_code of place, for example &quot;GB&quot;.</span>
<span class="sd"> Returns `None` if PhotoInfo contains no country code.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">ishome</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">ishome</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Returns `True` if photo place is user&#39;s home address, otherwise `False`.&quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Returns the name of the local place as str.</span>
<span class="sd"> This is what Photos displays in the Info window.</span>
<span class="sd"> **Note** Photos 5 uses a different algorithm to determine the name than earlier versions which means the same Photo may have a different place name in Photos 4 and Photos 5.</span>
<span class="sd"> `PhotoInfo.name` will return the name Photos would have shown depending on the version of the library being processed.</span>
<span class="sd"> Returns `None` if photo does not contain a name.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">names</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">names</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">PlaceNames</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;Returns a `PlaceNames` namedtuple with the following fields.</span>
<span class="sd"> Each field is a list with zero or more values, sorted by area in ascending order.</span>
<span class="sd"> E.g. `names.area_of_interest` could be [&#39;Gulf Islands National Seashore&#39;, &#39;Santa Rosa Island&#39;], [&quot;Knott&#39;s Berry Farm&quot;], or [] if `area_of_interest` not defined.</span>
<span class="sd"> The value shown in Photos is the first value in the list. With the exception of `body_of_water` each of these field corresponds to an attribute of</span>
<span class="sd"> a [CLPlacemark](https://developer.apple.com/documentation/corelocation/clplacemark) object.</span>
<span class="sd"> * `country`; the name of the country associated with the placemark.</span>
<span class="sd"> * `state_province`; administrativeArea, The state or province associated with the placemark.</span>
<span class="sd"> * `sub_administrative_area`; additional administrative area information for the placemark.</span>
<span class="sd"> * `city`; locality; the city associated with the placemark.</span>
<span class="sd"> * `additional_city_info`; subLocality, Additional city-level information for the placemark.</span>
<span class="sd"> * `ocean`; the name of the ocean associated with the placemark.</span>
<span class="sd"> * `area_of_interest`; areasOfInterest, The relevant areas of interest associated with the placemark.</span>
<span class="sd"> * `inland_water`; the name of the inland water body associated with the placemark.</span>
<span class="sd"> * `region`; the geographic region associated with the placemark.</span>
<span class="sd"> * `sub_throughfare`; additional street-level information for the placemark.</span>
<span class="sd"> * `postal_code`; the postal code associated with the placemark.</span>
<span class="sd"> * `street_address`; throughfare, The street address associated with the placemark.</span>
<span class="sd"> * `body_of_water`; in Photos 4, any body of water; in Photos 5 contains the union of ocean and inland_water</span>
<span class="sd"> **Note**: In Photos &lt;= 4.0, only the following fields are defined; all others are set to empty list:</span>
<span class="sd"> * `country`</span>
<span class="sd"> * `state_province`</span>
<span class="sd"> * `sub_administrative_area`</span>
<span class="sd"> * `city`</span>
<span class="sd"> * `additional_city_info`</span>
<span class="sd"> * `area_of_interest`</span>
<span class="sd"> * `body_of_water`</span>
<span class="sd"> Note:</span>
<span class="sd"> The `PlaceNames` namedtuple contains reserved fields not listed below (see implementation for details),</span>
<span class="sd"> thus it should be referenced only by name (e.g. `names.city`) and not by index.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">address</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">pass</span></div>
<span class="sd">&quot;&quot;&quot;Returns a `PostalAddress` namedtuple with details of the postal address containing the following fields:</span>
<span class="sd"> * `city`</span>
<span class="sd"> * `country`</span>
<span class="sd"> * `postal_code`</span>
<span class="sd"> * `state`</span>
<span class="sd"> * `street`</span>
<span class="sd"> * `sub_administrative_area`</span>
<span class="sd"> * `sub_locality`</span>
<span class="sd"> * `iso_country_code`</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span>
<div class="viewcode-block" id="PlaceInfo.asdict"><a class="viewcode-back" href="../../reference.html#osxphotos.PlaceInfo.asdict">[docs]</a> <span class="k">def</span> <span class="nf">asdict</span><span class="p">():</span>
<span class="sd">&quot;&quot;&quot;Returns a dictionary representation of the PlaceInfo object.&quot;&quot;&quot;</span>
<span class="k">pass</span></div></div>
<span class="k">class</span> <span class="nc">PlaceInfo4</span><span class="p">(</span><span class="n">PlaceInfo</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.queryoptions - osxphotos 0.58.1 documentation</title>
<title>osxphotos.queryoptions - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.58.1 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.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.58.1 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -305,6 +305,10 @@
<span class="sd"> uti: list of UTIs to search for</span>
<span class="sd"> uuid: list of uuids to search for</span>
<span class="sd"> year: search for photos taken in a given year</span>
<span class="sd"> syndicated: search for photos that have been shared via syndication (&quot;Shared with You&quot; album via Messages, etc.)</span>
<span class="sd"> not_syndicated: search for photos that have not been shared via syndication (&quot;Shared with You&quot; album via Messages, etc.)</span>
<span class="sd"> saved_to_library: search for syndicated photos that have been saved to the Photos library</span>
<span class="sd"> not_saved_to_library: search for syndicated photos that have not been saved to the Photos library</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">added_after</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
@@ -389,6 +393,10 @@
<span class="n">uti</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">uuid</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">year</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">syndicated</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">not_syndicated</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">saved_to_library</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">not_saved_to_library</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</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="k">return</span> <span class="n">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span></div>
@@ -458,6 +466,8 @@
<span class="p">(</span><span class="s2">&quot;deleted&quot;</span><span class="p">,</span> <span class="s2">&quot;not_deleted&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;deleted&quot;</span><span class="p">,</span> <span class="s2">&quot;deleted_only&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;deleted_only&quot;</span><span class="p">,</span> <span class="s2">&quot;not_deleted&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;syndicated&quot;</span><span class="p">,</span> <span class="s2">&quot;not_syndicated&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;saved_to_library&quot;</span><span class="p">,</span> <span class="s2">&quot;not_saved_to_library&quot;</span><span class="p">),</span>
<span class="p">]</span>
<span class="c1"># TODO: add option to validate requiring at least one query arg</span>
<span class="k">for</span> <span class="n">arg</span><span class="p">,</span> <span class="n">not_arg</span> <span class="ow">in</span> <span class="n">exclusive</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-5.3.0, furo 2022.09.29"/>
<title>osxphotos.scoreinfo - osxphotos 0.60.2 documentation</title>
<title>osxphotos.scoreinfo - osxphotos 0.60.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=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="../../index.html"><div class="brand">osxphotos 0.60.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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.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">
@@ -197,7 +197,7 @@
<h1>Source code for osxphotos.scoreinfo</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot; ScoreInfo class to expose computed score info from the library &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">asdict</span>
<span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">asdict</span><span class="p">,</span> <span class="n">dataclass</span>
<span class="kn">from</span> <span class="nn">._constants</span> <span class="kn">import</span> <span class="n">_PHOTOS_4_VERSION</span>

View File

@@ -361,7 +361,7 @@ Template Substitutions
* - {tab}
- :A tab: '\t'
* - {osxphotos_version}
- The osxphotos version, e.g. '0.60.2'
- The osxphotos version, e.g. '0.60.7'
* - {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.60.2',
VERSION: '0.60.7',
LANGUAGE: 'en',
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-5.3.0, furo 2022.09.29"/>
<title>OSXPhotos Command Line Interface (CLI) - osxphotos 0.60.2 documentation</title>
<title>OSXPhotos Command Line Interface (CLI) - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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,18 +211,6 @@
<dd><p>Show the version and exit.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-library">
<span id="cmdoption-osxphotos-db"></span><span class="sig-name descname"><span class="pre">--library</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">--db</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;PHOTOS_LIBRARY_PATH&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-library" title="Permalink to this definition">#</a></dt>
<dd><p>Specify path to Photos library. If not 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>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-json">
<span class="sig-name descname"><span class="pre">--json</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-json" title="Permalink to this definition">#</a></dt>
<dd><p>Print output in JSON format.</p>
</dd></dl>
<section id="osxphotos-about">
<h3>about<a class="headerlink" href="#osxphotos-about" title="Permalink to this heading">#</a></h3>
<p>Print information about osxphotos including license.</p>
@@ -728,6 +716,30 @@ See <cite>osxphotos help timewarp</cite> for more information.</p>
<dd><p>Search for photos that are not in iCloud (have not been synched)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-add-locations-syndicated">
<span class="sig-name descname"><span class="pre">--syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-add-locations-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-add-locations-not-syndicated">
<span class="sig-name descname"><span class="pre">--not-syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-add-locations-not-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have not been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-add-locations-saved-to-library">
<span class="sig-name descname"><span class="pre">--saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-add-locations-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-add-locations-not-saved-to-library">
<span class="sig-name descname"><span class="pre">--not-saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-add-locations-not-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have not saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-add-locations-regex">
<span class="sig-name descname"><span class="pre">--regex</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REGEX</span> <span class="pre">TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-add-locations-regex" title="Permalink to this definition">#</a></dt>
@@ -1659,6 +1671,30 @@ to modify this behavior.</p>
<dd><p>Search for photos that are not in iCloud (have not been synched)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-syndicated">
<span class="sig-name descname"><span class="pre">--syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-export-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-not-syndicated">
<span class="sig-name descname"><span class="pre">--not-syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-export-not-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have not been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-saved-to-library">
<span class="sig-name descname"><span class="pre">--saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-export-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-not-saved-to-library">
<span class="sig-name descname"><span class="pre">--not-saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-export-not-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have not saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-regex">
<span class="sig-name descname"><span class="pre">--regex</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REGEX</span> <span class="pre">TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-export-regex" title="Permalink to this definition">#</a></dt>
@@ -1857,6 +1893,12 @@ to modify this behavior.</p>
<dd><p>Attempt to download missing photos from iCloud. The current implementation uses Applescript to interact with Photos to export the photo which will force Photos to download from iCloud if the photo does not exist on disk. This will be slow and will require internet connection. This obviously only works if the Photos library is synched to iCloud. Note: download-missing does not currently export all burst images; only the primary photo will be exportedassociated burst images will be skipped.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-export-aae">
<span class="sig-name descname"><span class="pre">--export-aae</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-export-export-aae" title="Permalink to this definition">#</a></dt>
<dd><p>Also export an adjustments file detailing edits made to the original. The resulting file is named photoname.AAE. Note that to import these files back to Photos succesfully, you also need to export the edited photo and match the filename format Photos.app expects: filename IMG_{edited_version?E,}{id:04d} edited-suffix </p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-export-sidecar">
<span class="sig-name descname"><span class="pre">--sidecar</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;FORMAT&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-export-sidecar" title="Permalink to this definition">#</a></dt>
@@ -2332,7 +2374,11 @@ to modify this behavior.</p>
</section>
<section id="osxphotos-import">
<h3>import<a class="headerlink" href="#osxphotos-import" title="Permalink to this heading">#</a></h3>
<p>Import photos and videos into Photos.</p>
<p>Import photos and videos into Photos. Photos will be imported into the
most recently opened Photos library.</p>
<p>Photos are imported one at a time thus the “Imports” album in Photos will show
a new import group for each photo imported. Batch import into a single import
group will be added in a future release.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>osxphotos import <span class="o">[</span>OPTIONS<span class="o">]</span> <span class="o">[</span>FILES<span class="o">]</span>...
</pre></div>
</div>
@@ -2781,6 +2827,12 @@ If the same query option is provided multiple times, they are treated as
<dd><p>Print output in JSON format.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-count">
<span class="sig-name descname"><span class="pre">--count</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-query-count" title="Permalink to this definition">#</a></dt>
<dd><p>Print count of photos matching query and exit.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-keyword">
<span class="sig-name descname"><span class="pre">--keyword</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;KEYWORD&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-query-keyword" title="Permalink to this definition">#</a></dt>
@@ -3225,6 +3277,30 @@ If the same query option is provided multiple times, they are treated as
<dd><p>Search for photos that are not in iCloud (have not been synched)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-syndicated">
<span class="sig-name descname"><span class="pre">--syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-query-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-not-syndicated">
<span class="sig-name descname"><span class="pre">--not-syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-query-not-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have not been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-saved-to-library">
<span class="sig-name descname"><span class="pre">--saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-query-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-not-saved-to-library">
<span class="sig-name descname"><span class="pre">--not-saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-query-not-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have not saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-query-regex">
<span class="sig-name descname"><span class="pre">--regex</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REGEX</span> <span class="pre">TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-query-regex" title="Permalink to this definition">#</a></dt>
@@ -3762,6 +3838,30 @@ If the same query option is provided multiple times, they are treated as
<dd><p>Search for photos that are not in iCloud (have not been synched)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-repl-syndicated">
<span class="sig-name descname"><span class="pre">--syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-repl-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-repl-not-syndicated">
<span class="sig-name descname"><span class="pre">--not-syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-repl-not-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have not been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-repl-saved-to-library">
<span class="sig-name descname"><span class="pre">--saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-repl-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-repl-not-saved-to-library">
<span class="sig-name descname"><span class="pre">--not-saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-repl-not-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have not saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-repl-regex">
<span class="sig-name descname"><span class="pre">--regex</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REGEX</span> <span class="pre">TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-repl-regex" title="Permalink to this definition">#</a></dt>
@@ -4421,6 +4521,30 @@ two different computers, you can export the metadata to a shared folder.</p>
<dd><p>Search for photos that are not in iCloud (have not been synched)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-sync-syndicated">
<span class="sig-name descname"><span class="pre">--syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-sync-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-sync-not-syndicated">
<span class="sig-name descname"><span class="pre">--not-syndicated</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-sync-not-syndicated" title="Permalink to this definition">#</a></dt>
<dd><p>Search for photos that have not been shared via syndication (Shared with You album via Messages, etc.)</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-sync-saved-to-library">
<span class="sig-name descname"><span class="pre">--saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-sync-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-sync-not-saved-to-library">
<span class="sig-name descname"><span class="pre">--not-saved-to-library</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-sync-not-saved-to-library" title="Permalink to this definition">#</a></dt>
<dd><p>Search for syndicated photos that have not saved to the library</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-sync-regex">
<span class="sig-name descname"><span class="pre">--regex</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;REGEX</span> <span class="pre">TEMPLATE&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-sync-regex" title="Permalink to this definition">#</a></dt>

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-5.3.0, furo 2022.09.29"/><title>Index - osxphotos 0.60.2 documentation</title>
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29"/><title>Index - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">
@@ -423,6 +423,13 @@
<ul>
<li><a href="cli.html#cmdoption-osxphotos-export-convert-to-jpeg">osxphotos-export command line option</a>
</li>
</ul></li>
<li>
--count
<ul>
<li><a href="cli.html#cmdoption-osxphotos-query-count">osxphotos-query command line option</a>
</li>
</ul></li>
<li>
@@ -464,8 +471,6 @@
--db
<ul>
<li><a href="cli.html#cmdoption-osxphotos-library">osxphotos command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-albums-library">osxphotos-albums command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-batch-edit-library">osxphotos-batch-edit command line option</a>
@@ -766,6 +771,13 @@
<li><a href="cli.html#cmdoption-osxphotos-orphans-export">osxphotos-orphans command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-e">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
--export-aae
<ul>
<li><a href="cli.html#cmdoption-osxphotos-export-export-aae">osxphotos-export command line option</a>
</li>
</ul></li>
<li>
@@ -1137,8 +1149,6 @@
--json
<ul>
<li><a href="cli.html#cmdoption-osxphotos-json">osxphotos command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-albums-json">osxphotos-albums command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-dump-json">osxphotos-dump command line option</a>
@@ -1226,8 +1236,6 @@
--library
<ul>
<li><a href="cli.html#cmdoption-osxphotos-library">osxphotos command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-albums-library">osxphotos-albums command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-batch-edit-library">osxphotos-batch-edit command line option</a>
@@ -1563,8 +1571,6 @@
<li><a href="cli.html#cmdoption-osxphotos-sync-not-cloudasset">osxphotos-sync command line option</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
--not-edited
@@ -1595,6 +1601,8 @@
<li><a href="cli.html#cmdoption-osxphotos-sync-not-favorite">osxphotos-sync command line option</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
--not-hdr
@@ -1728,6 +1736,21 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-not-reference">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-reference">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
--not-saved-to-library
<ul>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-saved-to-library">osxphotos-add-locations command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-saved-to-library">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-saved-to-library">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-saved-to-library">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-saved-to-library">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
@@ -1786,6 +1809,21 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-not-slow-mo">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-slow-mo">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
--not-syndicated
<ul>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-syndicated">osxphotos-add-locations command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-syndicated">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-syndicated">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-syndicated">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-syndicated">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
@@ -2132,6 +2170,21 @@
<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>
</li>
</ul></li>
<li>
--saved-to-library
<ul>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-saved-to-library">osxphotos-add-locations command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-saved-to-library">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-saved-to-library">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-saved-to-library">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-saved-to-library">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
@@ -2303,6 +2356,21 @@
<ul>
<li><a href="cli.html#cmdoption-osxphotos-diff-s">osxphotos-diff command line option</a>
</li>
</ul></li>
<li>
--syndicated
<ul>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-syndicated">osxphotos-add-locations command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-syndicated">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-syndicated">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-syndicated">osxphotos-repl command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-syndicated">osxphotos-sync command line option</a>
</li>
</ul></li>
<li>
@@ -2966,10 +3034,16 @@
<li><a href="reference.html#osxphotos.QueryOptions.added_before">added_before (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.added_in_last">added_in_last (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.PlaceInfo.address">address (osxphotos.PlaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PlaceInfo.address_str">address_str (osxphotos.PlaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.ExifTool.addvalues">addvalues() (osxphotos.ExifTool method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.adjustments">adjustments (osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.adjustments_path">adjustments_path (osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.album">album (osxphotos.QueryOptions attribute)</a>
</li>
@@ -2992,11 +3066,11 @@
</li>
</ul></li>
<li><a href="reference.html#osxphotos.PhotosDB.albums_as_dict">albums_as_dict (osxphotos.PhotosDB property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared">albums_shared (osxphotos.PhotosDB property)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared">albums_shared (osxphotos.PhotosDB property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotosDB.albums_shared_as_dict">albums_shared_as_dict (osxphotos.PhotosDB property)</a>
</li>
<li><a href="reference.html#osxphotos.AlbumSortOrder">AlbumSortOrder (class in osxphotos)</a>
@@ -3016,6 +3090,8 @@
<ul>
<li><a href="reference.html#osxphotos.ExifTool.asdict">(osxphotos.ExifTool method)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.asdict">(osxphotos.FaceInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.FolderInfo.asdict">(osxphotos.FolderInfo method)</a>
</li>
@@ -3026,6 +3102,8 @@
<li><a href="reference.html#osxphotos.PersonInfo.asdict">(osxphotos.PersonInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.asdict">(osxphotos.PhotoInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.PlaceInfo.asdict">(osxphotos.PlaceInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.ScoreInfo.asdict">(osxphotos.ScoreInfo method)</a>
</li>
@@ -3079,6 +3157,8 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.SearchInfo.camera">camera (osxphotos.SearchInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.center">center (osxphotos.FaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.SearchInfo.city">city (osxphotos.SearchInfo property)</a>
</li>
@@ -3107,6 +3187,8 @@
<li><a href="reference.html#osxphotos.FileUtilNoOp.copy">copy() (osxphotos.FileUtilNoOp class method)</a>
</li>
<li><a href="reference.html#osxphotos.SearchInfo.country">country (osxphotos.SearchInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PlaceInfo.country_code">country_code (osxphotos.PlaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.ExportDB.create_file_record">create_file_record() (osxphotos.ExportDB method)</a>
</li>
@@ -3222,14 +3304,16 @@
</li>
<li><a href="reference.html#osxphotos.PhotoTemplate.expand_variables_to_str">expand_variables_to_str() (osxphotos.PhotoTemplate method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<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_aae">export_aae (osxphotos.ExportOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.ExportOptions.export_as_hardlink">export_as_hardlink (osxphotos.ExportOptions attribute)</a>
</li>
<li>
@@ -3278,7 +3362,11 @@
<li><a href="reference.html#osxphotos.PhotoInfo.face_info">(osxphotos.PhotoInfo property)</a>
</li>
</ul></li>
<li><a href="reference.html#osxphotos.FaceInfo.face_rect">face_rect() (osxphotos.FaceInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportOptions.face_regions">face_regions (osxphotos.ExportOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo">FaceInfo (class in osxphotos)</a>
</li>
<li><a href="reference.html#osxphotos.PersonInfo.favorite">favorite (osxphotos.PersonInfo property)</a>
@@ -3304,11 +3392,11 @@
</li>
</ul></li>
<li><a href="reference.html#osxphotos.FileUtil">FileUtil (class in osxphotos)</a>
</li>
<li><a href="reference.html#osxphotos.ExportOptions.fileutil">fileutil (osxphotos.ExportOptions attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.ExportOptions.fileutil">fileutil (osxphotos.ExportOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.FileUtilNoOp">FileUtilNoOp (class in osxphotos)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoTemplate.filter_predicate">filter_predicate() (osxphotos.PhotoTemplate method)</a>
@@ -3467,10 +3555,10 @@
<li><a href="reference.html#osxphotos.QueryOptions.incloud">(osxphotos.QueryOptions attribute)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.ExportOptions.increment">increment (osxphotos.ExportOptions attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotoInfo.intrash">intrash (osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.is_debug">is_debug() (in module osxphotos)</a>
@@ -3478,6 +3566,8 @@
<li><a href="reference.html#osxphotos.QueryOptions.is_reference">is_reference (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.iscloudasset">iscloudasset (osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PlaceInfo.ishome">ishome (osxphotos.PlaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.ismissing">ismissing (osxphotos.PhotoInfo property)</a>
</li>
@@ -3501,11 +3591,11 @@
</li>
<li><a href="reference.html#osxphotos.ExportOptions.jpeg_quality">jpeg_quality (osxphotos.ExportOptions attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.ExifTool.json">json() (osxphotos.ExifTool method)</a>
<ul>
<li><a href="reference.html#osxphotos.FaceInfo.json">(osxphotos.FaceInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.PersonInfo.json">(osxphotos.PersonInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.json">(osxphotos.PhotoInfo method)</a>
@@ -3611,10 +3701,10 @@
</li>
<li><a href="reference.html#osxphotos.QueryOptions.missing_bursts">missing_bursts (osxphotos.QueryOptions attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.MomentInfo.modification_date">modification_date (osxphotos.MomentInfo property)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
module
@@ -3629,6 +3719,10 @@
<li><a href="reference.html#osxphotos.SearchInfo.month">month (osxphotos.SearchInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.movies">movies (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.mpri_reg_rect">mpri_reg_rect (osxphotos.FaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.mwg_rs_area">mwg_rs_area (osxphotos.FaceInfo property)</a>
</li>
</ul></td>
</tr></table>
@@ -3638,7 +3732,13 @@
<h2>N</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.QueryOptions.name">name (osxphotos.QueryOptions attribute)</a>
<li><a href="reference.html#osxphotos.PlaceInfo.name">name (osxphotos.PlaceInfo property)</a>
<ul>
<li><a href="reference.html#osxphotos.QueryOptions.name">(osxphotos.QueryOptions attribute)</a>
</li>
</ul></li>
<li><a href="reference.html#osxphotos.PlaceInfo.names">names (osxphotos.PlaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.SearchInfo.neighborhoods">neighborhoods (osxphotos.SearchInfo property)</a>
</li>
@@ -3683,6 +3783,8 @@
<li><a href="reference.html#osxphotos.QueryOptions.not_portrait">not_portrait (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.not_reference">not_reference (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.not_saved_to_library">not_saved_to_library (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.not_screenshot">not_screenshot (osxphotos.QueryOptions attribute)</a>
</li>
@@ -3691,6 +3793,8 @@
<li><a href="reference.html#osxphotos.QueryOptions.not_shared">not_shared (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.not_slow_mo">not_slow_mo (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.not_syndicated">not_syndicated (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.QueryOptions.not_time_lapse">not_time_lapse (osxphotos.QueryOptions attribute)</a>
</li>
@@ -3725,12 +3829,6 @@
osxphotos command line option
<ul>
<li><a href="cli.html#cmdoption-osxphotos-library">--db</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-json">--json</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-library">--library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-v">--version</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-v">-v</a>
@@ -3845,6 +3943,8 @@
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-portrait">--not-portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-reference">--not-reference</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-saved-to-library">--not-saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-screenshot">--not-screenshot</a>
</li>
@@ -3853,6 +3953,8 @@
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-shared">--not-shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-slow-mo">--not-slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-syndicated">--not-syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-not-time-lapse">--not-time-lapse</a>
</li>
@@ -3873,6 +3975,8 @@
<li><a href="cli.html#cmdoption-osxphotos-add-locations-query-function">--query-function</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-regex">--regex</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-saved-to-library">--saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-screenshot">--screenshot</a>
</li>
@@ -3883,6 +3987,8 @@
<li><a href="cli.html#cmdoption-osxphotos-add-locations-shared">--shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-slow-mo">--slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-syndicated">--syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-add-locations-theme">--theme</a>
</li>
@@ -4129,6 +4235,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-exiftool-option">--exiftool-option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-exiftool-path">--exiftool-path</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-export-aae">--export-aae</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-export-as-hardlink">--export-as-hardlink</a>
</li>
@@ -4249,6 +4357,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-not-portrait">--not-portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-reference">--not-reference</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-saved-to-library">--not-saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-screenshot">--not-screenshot</a>
</li>
@@ -4257,6 +4367,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-not-shared">--not-shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-slow-mo">--not-slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-syndicated">--not-syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-not-time-lapse">--not-time-lapse</a>
</li>
@@ -4307,6 +4419,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-retry">--retry</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-save-config">--save-config</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-saved-to-library">--saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-screenshot">--screenshot</a>
</li>
@@ -4337,6 +4451,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-slow-mo">--slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-strip">--strip</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-syndicated">--syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-theme">--theme</a>
</li>
@@ -4542,8 +4658,6 @@
<li><a href="cli.html#cmdoption-osxphotos-import-arg-FILES">FILES</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
osxphotos-info command line option
@@ -4557,6 +4671,8 @@
<li><a href="cli.html#cmdoption-osxphotos-info-arg-PHOTOS_LIBRARY">PHOTOS_LIBRARY</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
osxphotos-inspect command line option
@@ -4682,6 +4798,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-burst">--burst</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-cloudasset">--cloudasset</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-count">--count</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-library">--db</a>
</li>
@@ -4786,6 +4904,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-not-portrait">--not-portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-reference">--not-reference</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-saved-to-library">--not-saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-screenshot">--not-screenshot</a>
</li>
@@ -4794,6 +4914,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-not-shared">--not-shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-slow-mo">--not-slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-syndicated">--not-syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-not-time-lapse">--not-time-lapse</a>
</li>
@@ -4818,6 +4940,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-quiet">--quiet</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-regex">--regex</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-saved-to-library">--saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-screenshot">--screenshot</a>
</li>
@@ -4828,6 +4952,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-shared">--shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-slow-mo">--slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-syndicated">--syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-time-lapse">--time-lapse</a>
</li>
@@ -4969,6 +5095,8 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-not-portrait">--not-portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-reference">--not-reference</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-saved-to-library">--not-saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-screenshot">--not-screenshot</a>
</li>
@@ -4977,6 +5105,8 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-not-shared">--not-shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-slow-mo">--not-slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-syndicated">--not-syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-not-time-lapse">--not-time-lapse</a>
</li>
@@ -4997,6 +5127,8 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-query-function">--query-function</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-regex">--regex</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-saved-to-library">--saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-screenshot">--screenshot</a>
</li>
@@ -5007,6 +5139,8 @@
<li><a href="cli.html#cmdoption-osxphotos-repl-shared">--shared</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-slow-mo">--slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-syndicated">--syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-time-lapse">--time-lapse</a>
</li>
@@ -5181,12 +5315,16 @@
<li><a href="cli.html#cmdoption-osxphotos-sync-not-portrait">--not-portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-reference">--not-reference</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-saved-to-library">--not-saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-screenshot">--not-screenshot</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-selfie">--not-selfie</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-slow-mo">--not-slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-syndicated">--not-syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-not-time-lapse">--not-time-lapse</a>
</li>
@@ -5209,6 +5347,8 @@
<li><a href="cli.html#cmdoption-osxphotos-sync-regex">--regex</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-R">--report</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-saved-to-library">--saved-to-library</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-screenshot">--screenshot</a>
</li>
@@ -5219,6 +5359,8 @@
<li><a href="cli.html#cmdoption-osxphotos-sync-s">--set</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-slow-mo">--slow-mo</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-syndicated">--syndicated</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-sync-theme">--theme</a>
</li>
@@ -5450,9 +5592,11 @@
</li>
<li><a href="reference.html#osxphotos.QueryOptions.person">person (osxphotos.QueryOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.person_info">person_info (osxphotos.PhotoInfo property)</a>
<li><a href="reference.html#osxphotos.FaceInfo.person_info">person_info (osxphotos.FaceInfo property)</a>
<ul>
<li><a href="reference.html#osxphotos.PhotoInfo.person_info">(osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotosDB.person_info">(osxphotos.PhotosDB property)</a>
</li>
</ul></li>
@@ -5467,6 +5611,8 @@
</li>
</ul></li>
<li><a href="reference.html#osxphotos.PhotosDB.persons_as_dict">persons_as_dict (osxphotos.PhotosDB property)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.photo">photo (osxphotos.FaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.AlbumInfo.photo_index">photo_index() (osxphotos.AlbumInfo method)</a>
</li>
@@ -5486,10 +5632,10 @@
<li><a href="reference.html#osxphotos.QueryOptions.photos">(osxphotos.QueryOptions attribute)</a>
</li>
</ul></li>
<li><a href="reference.html#osxphotos.PhotosDB.photos">photos() (osxphotos.PhotosDB method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotosDB.photos">photos() (osxphotos.PhotosDB method)</a>
</li>
<li><a href="reference.html#osxphotos.PhotosDB.photos_by_uuid">photos_by_uuid() (osxphotos.PhotosDB method)</a>
</li>
<li>
@@ -5526,6 +5672,8 @@
<li><a href="reference.html#osxphotos.PhotoTemplate">PhotoTemplate (class in osxphotos)</a>
</li>
<li><a href="reference.html#osxphotos.ExifTool.pid">pid (osxphotos.ExifTool property)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.pitch">pitch (osxphotos.FaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.MomentInfo.pk">pk (osxphotos.MomentInfo property)</a>
</li>
@@ -5598,10 +5746,10 @@
</li>
<li><a href="reference.html#osxphotos.PhotoTemplate.render">render() (osxphotos.PhotoTemplate method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.ExportOptions.render_options">render_options (osxphotos.ExportOptions attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotoInfo.render_template">render_template() (osxphotos.PhotoInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.ExportOptions.replace_keywords">replace_keywords (osxphotos.ExportOptions attribute)</a>
@@ -5609,6 +5757,10 @@
<li><a href="reference.html#osxphotos.ExportOptions.rich">rich (osxphotos.ExportOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.FileUtilNoOp.rmdir">rmdir() (osxphotos.FileUtilNoOp class method)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.roll">roll (osxphotos.FaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.roll_pitch_yaw">roll_pitch_yaw() (osxphotos.FaceInfo method)</a>
</li>
<li><a href="reference.html#osxphotos.ExifTool.run_commands">run_commands() (osxphotos.ExifTool method)</a>
</li>
@@ -5620,6 +5772,12 @@
<h2>S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.PhotoInfo.saved_to_library">saved_to_library (osxphotos.PhotoInfo property)</a>
<ul>
<li><a href="reference.html#osxphotos.QueryOptions.saved_to_library">(osxphotos.QueryOptions attribute)</a>
</li>
</ul></li>
<li><a href="reference.html#osxphotos.PhotoInfo.score">score (osxphotos.PhotoInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.ScoreInfo">ScoreInfo (class in osxphotos)</a>
@@ -5667,6 +5825,8 @@
<li><a href="reference.html#osxphotos.ExportOptions.sidecar">sidecar (osxphotos.ExportOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.ExportOptions.sidecar_drop_ext">sidecar_drop_ext (osxphotos.ExportOptions attribute)</a>
</li>
<li><a href="reference.html#osxphotos.FaceInfo.size_pixels">size_pixels (osxphotos.FaceInfo property)</a>
</li>
<li><a href="reference.html#osxphotos.PhotoInfo.slow_mo">slow_mo (osxphotos.PhotoInfo property)</a>
@@ -5701,6 +5861,12 @@
<ul>
<li><a href="cli.html#cmdoption-osxphotos-help-arg-SUBTOPIC">osxphotos-help command line option</a>
</li>
</ul></li>
<li><a href="reference.html#osxphotos.PhotoInfo.syndicated">syndicated (osxphotos.PhotoInfo property)</a>
<ul>
<li><a href="reference.html#osxphotos.QueryOptions.syndicated">(osxphotos.QueryOptions attribute)</a>
</li>
</ul></li>
</ul></td>
@@ -5857,6 +6023,10 @@
<section id="Y" class="genindex-section">
<h2>Y</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.FaceInfo.yaw">yaw (osxphotos.FaceInfo property)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#osxphotos.QueryOptions.year">year (osxphotos.QueryOptions attribute)</a>

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-5.3.0, furo 2022.09.29"/>
<title>osxphotos 0.60.2 documentation</title>
<title>osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="#"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">
@@ -361,6 +361,7 @@
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.render_options"><code class="docutils literal notranslate"><span class="pre">ExportOptions.render_options</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.replace_keywords"><code class="docutils literal notranslate"><span class="pre">ExportOptions.replace_keywords</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.rich"><code class="docutils literal notranslate"><span class="pre">ExportOptions.rich</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.export_aae"><code class="docutils literal notranslate"><span class="pre">ExportOptions.export_aae</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.sidecar_drop_ext"><code class="docutils literal notranslate"><span class="pre">ExportOptions.sidecar_drop_ext</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.sidecar"><code class="docutils literal notranslate"><span class="pre">ExportOptions.sidecar</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportOptions.strip"><code class="docutils literal notranslate"><span class="pre">ExportOptions.strip</span></code></a></li>
@@ -384,6 +385,22 @@
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ExportResults.datetime"><code class="docutils literal notranslate"><span class="pre">ExportResults.datetime</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.FaceInfo"><code class="docutils literal notranslate"><span class="pre">FaceInfo</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.asdict"><code class="docutils literal notranslate"><span class="pre">FaceInfo.asdict()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.center"><code class="docutils literal notranslate"><span class="pre">FaceInfo.center</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.face_rect"><code class="docutils literal notranslate"><span class="pre">FaceInfo.face_rect()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.json"><code class="docutils literal notranslate"><span class="pre">FaceInfo.json()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.mpri_reg_rect"><code class="docutils literal notranslate"><span class="pre">FaceInfo.mpri_reg_rect</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.mwg_rs_area"><code class="docutils literal notranslate"><span class="pre">FaceInfo.mwg_rs_area</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.person_info"><code class="docutils literal notranslate"><span class="pre">FaceInfo.person_info</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.photo"><code class="docutils literal notranslate"><span class="pre">FaceInfo.photo</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.pitch"><code class="docutils literal notranslate"><span class="pre">FaceInfo.pitch</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.roll"><code class="docutils literal notranslate"><span class="pre">FaceInfo.roll</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.roll_pitch_yaw"><code class="docutils literal notranslate"><span class="pre">FaceInfo.roll_pitch_yaw()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.size_pixels"><code class="docutils literal notranslate"><span class="pre">FaceInfo.size_pixels</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FaceInfo.yaw"><code class="docutils literal notranslate"><span class="pre">FaceInfo.yaw</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.FileUtil"><code class="docutils literal notranslate"><span class="pre">FileUtil</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.FileUtilNoOp"><code class="docutils literal notranslate"><span class="pre">FileUtilNoOp</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.FileUtilNoOp.convert_to_jpeg"><code class="docutils literal notranslate"><span class="pre">FileUtilNoOp.convert_to_jpeg()</span></code></a></li>
@@ -444,6 +461,7 @@
</li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo"><code class="docutils literal notranslate"><span class="pre">PhotoInfo</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.adjustments"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.adjustments</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.adjustments_path"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.adjustments_path</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.album_info"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.album_info</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.albums"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.albums</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.asdict"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.asdict()</span></code></a></li>
@@ -517,6 +535,7 @@
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.project_info"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.project_info</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.raw_original"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.raw_original</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.render_template"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.render_template()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.saved_to_library"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.saved_to_library</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.score"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.score</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.screenshot"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.screenshot</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.search_info"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.search_info</span></code></a></li>
@@ -524,6 +543,7 @@
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.selfie"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.selfie</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.shared"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.shared</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.slow_mo"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.slow_mo</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.syndicated"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.syndicated</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.tables"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.tables()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.time_lapse"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.time_lapse</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotoInfo.title"><code class="docutils literal notranslate"><span class="pre">PhotoInfo.title</span></code></a></li>
@@ -590,7 +610,16 @@
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PhotosDB.query"><code class="docutils literal notranslate"><span class="pre">PhotosDB.query()</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo"><code class="docutils literal notranslate"><span class="pre">PlaceInfo</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo"><code class="docutils literal notranslate"><span class="pre">PlaceInfo</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.address"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.address</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.address_str"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.address_str</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.asdict"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.asdict()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.country_code"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.country_code</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.ishome"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.ishome</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.name"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.name</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.PlaceInfo.names"><code class="docutils literal notranslate"><span class="pre">PlaceInfo.names</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.ProjectInfo"><code class="docutils literal notranslate"><span class="pre">ProjectInfo</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ProjectInfo.folder_list"><code class="docutils literal notranslate"><span class="pre">ProjectInfo.folder_list</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.ProjectInfo.folder_names"><code class="docutils literal notranslate"><span class="pre">ProjectInfo.folder_names</span></code></a></li>
@@ -677,6 +706,10 @@
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.uti"><code class="docutils literal notranslate"><span class="pre">QueryOptions.uti</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.uuid"><code class="docutils literal notranslate"><span class="pre">QueryOptions.uuid</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.year"><code class="docutils literal notranslate"><span class="pre">QueryOptions.year</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.syndicated"><code class="docutils literal notranslate"><span class="pre">QueryOptions.syndicated</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.not_syndicated"><code class="docutils literal notranslate"><span class="pre">QueryOptions.not_syndicated</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.saved_to_library"><code class="docutils literal notranslate"><span class="pre">QueryOptions.saved_to_library</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="reference.html#osxphotos.QueryOptions.not_saved_to_library"><code class="docutils literal notranslate"><span class="pre">QueryOptions.not_saved_to_library</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#osxphotos.ScoreInfo"><code class="docutils literal notranslate"><span class="pre">ScoreInfo</span></code></a><ul>

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-5.3.0, furo 2022.09.29"/>
<title>OSXPhotos - osxphotos 0.60.2 documentation</title>
<title>OSXPhotos - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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 Reference" href="reference.html" /><link rel="prev" title="OSXPhotos Template System" href="template_help.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29"/>
<title>OSXPhotos Python Package Overview - osxphotos 0.60.2 documentation</title>
<title>OSXPhotos Python Package Overview - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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-5.3.0, furo 2022.09.29"/><title>Python Module Index - osxphotos 0.60.2 documentation</title>
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29"/><title>Python Module Index - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">

File diff suppressed because one or more lines are too long

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-5.3.0, furo 2022.09.29"/><title>Search - osxphotos 0.60.2 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29"/><title>Search - osxphotos 0.60.7 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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-5.3.0, furo 2022.09.29"/>
<title>OSXPhotos Template System - osxphotos 0.60.2 documentation</title>
<title>OSXPhotos Template System - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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">
@@ -613,7 +613,7 @@
</td>
</tr>
<tr class="row-odd"><td><p>{osxphotos_version}</p></td>
<td><p>The osxphotos version, e.g. 0.60.2</p></td>
<td><p>The osxphotos version, e.g. 0.60.7</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-5.3.0, furo 2022.09.29"/>
<title>OSXPhotos Tutorial - osxphotos 0.60.2 documentation</title>
<title>OSXPhotos Tutorial - osxphotos 0.60.7 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<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.60.2 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.60.7 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.60.2 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.60.7 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

@@ -361,7 +361,7 @@ Template Substitutions
* - {tab}
- :A tab: '\t'
* - {osxphotos_version}
- The osxphotos version, e.g. '0.60.2'
- The osxphotos version, e.g. '0.60.7'
* - {osxphotos_cmd_line}
- The full command line used to run osxphotos
* - {album}

View File

@@ -21,7 +21,6 @@ from osxphotos.sqlitekvstore import SQLiteKVStore
class Latitude(click.ParamType):
name = "Latitude"
def convert(self, value, param, ctx):
@@ -37,7 +36,6 @@ class Latitude(click.ParamType):
class Longitude(click.ParamType):
name = "Longitude"
def convert(self, value, param, ctx):

View File

@@ -23,10 +23,7 @@ to your function. You can then do whatever you want with the photos.
from __future__ import annotations
import osxphotos
from osxphotos.cli import (
selection_command,
verbose,
)
from osxphotos.cli import selection_command, verbose
@selection_command

View File

@@ -2,9 +2,10 @@
import sys
import osxphotos
import click
import osxphotos
@click.command()
@click.argument("album1")

View File

@@ -1,6 +1,7 @@
import osxphotos
import os.path
import osxphotos
def main():
db = osxphotos.utils.get_system_library_path()

View File

@@ -32,7 +32,7 @@ import osxphotos
default=False,
)
def export(export_path, default_album, library_path, edited):
""" Export all photos, organized by album """
"""Export all photos, organized by album"""
export_path = os.path.expanduser(export_path)
library_path = os.path.expanduser(library_path) if library_path else None
@@ -66,11 +66,11 @@ def export(export_path, default_album, library_path, edited):
os.makedirs(dest_dir)
filename = p.original_filename
# export the photo but only if --edited, photo has adjustments, and
# export the photo but only if --edited, photo has adjustments, and
# path_edited is not None (can be None if edited photo is missing)
if edited and p.hasadjustments and p.path_edited:
# export edited version
# use original filename with _edited appended but make sure suffix is
# use original filename with _edited appended but make sure suffix is
# same as edited file
edited_filename = f"{pathlib.Path(filename).stem}_edited{pathlib.Path(p.path_edited).suffix}"
exported = p.export(dest_dir, edited_filename, edited=True)

View File

@@ -32,7 +32,7 @@ import osxphotos
default=None,
)
def export(export_path, library_path, uuid):
""" export photos to export_path and draw faces """
"""export photos to export_path and draw faces"""
library_path = os.path.expanduser(library_path) if library_path else None
if library_path is not None:
photosdb = osxphotos.PhotosDB(library_path)
@@ -61,7 +61,7 @@ def export(export_path, library_path, uuid):
def get_circle_points(xy, radius):
""" Returns tuples of (x0, y0), (x1, y1) for a circle centered at x, y with radius
"""Returns tuples of (x0, y0), (x1, y1) for a circle centered at x, y with radius
Arguments:
xy: tuple of x, y coordinates

View File

@@ -77,7 +77,9 @@ def place_folder(photo: osxphotos.PhotoInfo) -> str:
return ""
def photos_folders(photo: osxphotos.PhotoInfo, options: osxphotos.phototemplate.RenderOptions, **kwargs) -> Union[List, str]:
def photos_folders(
photo: osxphotos.PhotoInfo, options: osxphotos.phototemplate.RenderOptions, **kwargs
) -> Union[List, str]:
"""template function for use with --directory to export photos in a folder structure similar to Photos
Args:

View File

@@ -29,7 +29,9 @@ def main():
exported = photo.export(tempdir.name, use_photos_export=True, timeout=300)
if photo.hasadjustments:
exported.extend(
photo.export(tempdir.name, use_photos_export=True, edited=True, timeout=300)
photo.export(
tempdir.name, use_photos_export=True, edited=True, timeout=300
)
)
for filename in exported:
print(f"Removing temporary file {filename}")

View File

@@ -10,7 +10,7 @@ from osxphotos._constants import TIME_DELTA
@dataclass
class Comment:
""" Class for shared photo comments """
"""Class for shared photo comments"""
uuid: str
sort_fok: int
@@ -22,7 +22,7 @@ class Comment:
@dataclass
class Like:
""" Class for shared photo likes """
"""Class for shared photo likes"""
uuid: str
sort_fok: int
@@ -32,10 +32,10 @@ class Like:
def get_shared_person_info(photosdb, hashed_person_id):
""" returns tuple of (first name, last name, full name)
for person invited to shared album with
"""returns tuple of (first name, last name, full name)
for person invited to shared album with
ZINVITEEHASHEDPERSONID = hashed_person_id
Args:
photosdb: a osxphotos.PhotosDB object
hashed_person_id: str, value of ZINVITEEHASHEDPERSONID to lookup
@@ -66,12 +66,12 @@ def get_shared_person_info(photosdb, hashed_person_id):
def get_comments(photosdb, uuid):
""" return comments and likes, if any, for photo with uuid
"""return comments and likes, if any, for photo with uuid
Args:
photosdb: a osxphotos.PhotosDB object
uuid: uuid of the photo
Returns:
tuple of (list of comments as Comment objects or [] if no comments, list of likes as Like objects or [] if no likes)
"""

View File

@@ -15,14 +15,14 @@ import time
import click
import osxphotos
from osxphotos.cli import get_photos_db, _list_libraries
from osxphotos.cli import _list_libraries, get_photos_db
def show(photo):
""" open image with default image viewer
Note: This is for debugging only -- it will actually open any filetype which could
be very, very bad.
"""open image with default image viewer
Note: This is for debugging only -- it will actually open any filetype which could
be very, very bad.
Args:
photo: PhotoInfo object or a path to a photo on disk

View File

@@ -1,8 +1,10 @@
""" Example function for use with osxphotos import --post-function option """
import typing as t
import photoscript
import pathlib
import typing as t
import photoscript
from osxphotos.cli.import_cli import ReportRecord

View File

@@ -3,6 +3,7 @@ import os.path
import osxphotos
def main():
db = os.path.expanduser("~/Pictures/Photos Library.photoslibrary")
photosdb = osxphotos.PhotosDB(db)
@@ -15,11 +16,14 @@ def main():
print(photosdb.albums_as_dict)
# find all photos with Keyword = Foo and containing John Smith
photos = photosdb.photos(keywords=["Foo"],persons=["John Smith"])
photos = photosdb.photos(keywords=["Foo"], persons=["John Smith"])
# find all photos that include Alice Smith but do not contain the keyword Bar
photos = [p for p in photosdb.photos(persons=["Alice Smith"])
if p not in photosdb.photos(keywords=["Bar"]) ]
photos = [
p
for p in photosdb.photos(persons=["Alice Smith"])
if p not in photosdb.photos(keywords=["Bar"])
]
for p in photos:
print(
p.uuid,
@@ -34,5 +38,6 @@ def main():
p.path,
)
if __name__ == "__main__":
main()
main()

View File

@@ -10,8 +10,8 @@
from typing import List
def myfilter(values: List[str]) -> List[str]:
""" Custom filter to append "foo-" to template value """
"""Custom filter to append "foo-" to template value"""
values = ["foo-" + val for val in values]
return values

View File

@@ -7,7 +7,7 @@ from typing import Callable
from osxphotos import ExportResults, PhotoInfo
from osxphotos.exiftool import ExifTool
from osxphotos.utils import normalize_unicode
from osxphotos.unicode import normalize_unicode
# Update this for your custom keyword to rating mapping
RATINGS = {

View File

@@ -13,7 +13,7 @@ from .exiftool import ExifTool
from .export_db import ExportDB, ExportDBTemp
from .fileutil import FileUtil, FileUtilNoOp
from .momentinfo import MomentInfo
from .personinfo import PersonInfo
from .personinfo import FaceInfo, PersonInfo
from .photoexporter import ExportOptions, ExportResults, PhotoExporter
from .photoinfo import PhotoInfo
from .photosdb import PhotosDB
@@ -21,10 +21,10 @@ from .photosdb._photosdb_process_comments import CommentInfo, LikeInfo
from .phototables import PhotoTables
from .phototemplate import PhotoTemplate
from .placeinfo import PlaceInfo
from .platform import is_macos
from .queryoptions import QueryOptions
from .scoreinfo import ScoreInfo
from .searchinfo import SearchInfo
from .utils import is_macos
if is_macos:
from .photosalbum import PhotosAlbum, PhotosAlbumPhotoScript
@@ -48,6 +48,7 @@ __all__ = [
"ExportDBTemp",
"ExportOptions",
"ExportResults",
"FaceInfo",
"FileUtil",
"FileUtilNoOp",
"FolderInfo",

View File

@@ -18,9 +18,6 @@ OSXPHOTOS_URL = "https://github.com/RhetTbull/osxphotos"
# Apple Epoch is Jan 1, 2001
TIME_DELTA = (datetime(2001, 1, 1, 0, 0) - datetime(1970, 1, 1, 0, 0)).total_seconds()
# Unicode format to use for comparing strings
UNICODE_FORMAT = "NFC"
# which Photos library database versions have been tested
# Photos 2.0 (10.12.6) == 2622
# Photos 3.0 (10.13.6) == 3301
@@ -129,6 +126,7 @@ _TESTED_OS_VERSIONS = [
("13", "1"),
("13", "2"),
("13", "3"),
("13", "4"),
]
# Photos 5 has persons who are empty string if unidentified face

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.60.2"
__version__ = "0.60.7"

View File

@@ -5,7 +5,6 @@ import sys
from rich import print
from rich.traceback import install as install_traceback
from osxphotos.utils import is_macos
from osxphotos.debug import (
debug_breakpoint,
debug_watch,
@@ -14,6 +13,7 @@ from osxphotos.debug import (
set_debug,
wrap_function,
)
from osxphotos.platform import is_macos
# apply any debug functions
# need to do this before importing anything else so that the debug functions

View File

@@ -7,8 +7,9 @@ import datetime
import click
import osxphotos
from osxphotos.platform import assert_macos
from osxphotos.queryoptions import IncompatibleQueryOptions, query_options_from_kwargs
from osxphotos.utils import assert_macos, pluralize
from osxphotos.utils import pluralize
from .cli_params import QUERY_OPTIONS, THEME_OPTION, TIMESTAMP_OPTION, VERBOSE_OPTION
from .click_rich_echo import rich_click_echo as echo

View File

@@ -12,8 +12,8 @@ import click
import osxphotos
from osxphotos.phototemplate import RenderOptions
from osxphotos.platform import assert_macos
from osxphotos.sqlitekvstore import SQLiteKVStore
from osxphotos.utils import assert_macos
assert_macos()

View File

@@ -9,11 +9,11 @@ import click
from osxphotos._constants import PROFILE_SORT_KEYS
from osxphotos._version import __version__
from osxphotos.utils import is_macos
from osxphotos.platform import is_macos
from .about import about
from .albums import albums
from .cli_params import DB_OPTION, DEBUG_OPTIONS, JSON_OPTION, VERSION_OPTION
from .cli_params import DEBUG_OPTIONS, VERSION_OPTION
from .common import OSXPHOTOS_HIDDEN
from .debug_dump import debug_dump
from .docs import docs_command
@@ -62,8 +62,6 @@ CTX_SETTINGS = dict(help_option_names=["-h", "--help"])
@click.group(context_settings=CTX_SETTINGS)
@VERSION_OPTION
@DB_OPTION
@JSON_OPTION
@DEBUG_OPTIONS
@click.option(
"--profile", is_flag=True, hidden=OSXPHOTOS_HIDDEN, help="Enable profiling"
@@ -83,12 +81,12 @@ CTX_SETTINGS = dict(help_option_names=["-h", "--help"])
"Default = 'cumulative'.",
)
@click.pass_context
def cli_main(ctx, db, json_, profile, profile_sort, **kwargs):
def cli_main(ctx, profile, profile_sort, **kwargs):
"""osxphotos: the multi-tool for your Photos library"""
# Note: kwargs is used to catch any debug options passed in
# the debug options are handled in cli/__init__.py
# before this function is called
ctx.obj = CLI_Obj(db=db, json=json_, group=cli_main)
ctx.obj = CLI_Obj(group=cli_main)
if profile:
click.echo("Profiling...")
profile_sort = profile_sort or ["cumulative"]

View File

@@ -3,13 +3,14 @@
from __future__ import annotations
import functools
from typing import Any, Callable
import click
import contextlib
import functools
from textwrap import dedent
from typing import Any, Callable
from ..utils import is_macos
import click
from ..platform import is_macos
from .common import OSXPHOTOS_HIDDEN, print_version
from .param_types import *
@@ -590,6 +591,26 @@ _QUERY_PARAMETERS_DICT = {
is_flag=True,
help="Search for photos that are not in iCloud (have not been synched)",
),
"--syndicated": click.Option(
["--syndicated"],
is_flag=True,
help="Search for photos that have been shared via syndication ('Shared with You' album via Messages, etc.)",
),
"--not-syndicated": click.Option(
["--not-syndicated"],
is_flag=True,
help="Search for photos that have not been shared via syndication ('Shared with You' album via Messages, etc.)",
),
"--saved-to-library": click.Option(
["--saved-to-library"],
is_flag=True,
help="Search for syndicated photos that have saved to the library",
),
"--not-saved-to-library": click.Option(
["--not-saved-to-library"],
is_flag=True,
help="Search for syndicated photos that have not saved to the library",
),
"--regex": click.Option(
["--regex"],
metavar="REGEX TEMPLATE",

View File

@@ -15,7 +15,8 @@ from xdg import xdg_config_home, xdg_data_home
import osxphotos
from osxphotos._constants import APP_NAME
from osxphotos._version import __version__
from osxphotos.utils import get_latest_version, get_macos_version
from osxphotos.platform import get_macos_version
from osxphotos.utils import get_latest_version
# used to show/hide hidden commands
OSXPHOTOS_HIDDEN = not bool(os.getenv("OSXPHOTOS_SHOW_HIDDEN", default=False))

View File

@@ -1,11 +1,10 @@
"""Detect dark mode on MacOS >= 10.14 or fake it elsewhere"""
from osxphotos.utils import is_macos
from osxphotos.platform import is_macos
if is_macos:
import objc
import Foundation
import objc
def theme():
with objc.autorelease_pool():

View File

@@ -45,16 +45,11 @@ from osxphotos.path_utils import is_valid_filepath, sanitize_filename, sanitize_
from osxphotos.photoexporter import ExportOptions, ExportResults, PhotoExporter
from osxphotos.photoinfo import PhotoInfoNone
from osxphotos.phototemplate import PhotoTemplate, RenderOptions
from osxphotos.platform import get_macos_version, is_macos
from osxphotos.queryoptions import load_uuid_from_file, query_options_from_kwargs
from osxphotos.unicode import normalize_fs_path
from osxphotos.uti import get_preferred_uti_extension
from osxphotos.utils import (
format_sec_to_hhmmss,
get_macos_version,
is_macos,
normalize_fs_path,
pluralize,
under_test,
)
from osxphotos.utils import format_sec_to_hhmmss, pluralize, under_test
if is_macos:
from osxmetadata import (
@@ -302,6 +297,14 @@ from .verbose import get_verbose_console, verbose_print
"Note: --download-missing does not currently export all burst images; "
"only the primary photo will be exported--associated burst images will be skipped.",
)
@click.option(
"--export-aae",
is_flag=True,
help="Also export an adjustments file detailing edits made to the original. "
"The resulting file is named photoname.AAE. "
"Note that to import these files back to Photos succesfully, you also need to "
"export the edited photo and match the filename format Photos.app expects: "
"--filename 'IMG_{edited_version?E,}{id:04d}' --edited-suffix ''")
@click.option(
"--sidecar",
default=None,
@@ -857,6 +860,7 @@ def export(
screenshot,
selfie,
shared,
export_aae,
sidecar,
sidecar_drop_ext,
skip_bursts,
@@ -886,6 +890,10 @@ def export(
verbose_flag,
xattr_template,
year,
syndicated,
not_syndicated,
saved_to_library,
not_saved_to_library,
selected=False, # Isn't provided on unsupported platforms
# debug, # debug, watch, breakpoint handled in cli/__init__.py
# watch,
@@ -1077,6 +1085,7 @@ def export(
selected = cfg.selected
selfie = cfg.selfie
shared = cfg.shared
export_aae = cfg.export_aae
sidecar = cfg.sidecar
sidecar_drop_ext = cfg.sidecar_drop_ext
skip_bursts = cfg.skip_bursts
@@ -1107,6 +1116,11 @@ def export(
verbose_flag = cfg.verbose
xattr_template = cfg.xattr_template
year = cfg.year
syndicated = cfg.syndicated
not_syndicated = cfg.not_syndicated
saved_to_library = cfg.saved_to_library
not_saved_to_library = cfg.not_saved_to_library
# config file might have changed verbose
verbose = verbose_print(verbose=verbose_flag, timestamp=timestamp, theme=theme)
verbose(f"Loaded options from file [filepath]{load_config}")
@@ -1155,6 +1169,8 @@ def export(
("slow_mo", "not_slow_mo"),
("time_lapse", "not_time_lapse"),
("title", "no_title"),
("syndicated", "not_syndicated"),
("saved_to_library", "not_saved_to_library"),
]
dependent_options = [
("append", ("report")),
@@ -1639,6 +1655,7 @@ def export(
+ results.exif_updated
+ results.touched
+ results.converted_to_jpeg
+ results.aae_written
+ results.sidecar_json_written
+ results.sidecar_json_skipped
+ results.sidecar_exiftool_written
@@ -1696,6 +1713,7 @@ def export_photo(
dest=None,
verbose=None,
export_by_date=None,
export_aae=None,
sidecar=None,
sidecar_drop_ext=False,
update=None,
@@ -1784,6 +1802,7 @@ def export_photo(
preview_suffix: str, template to use as suffix for preview images
replace_keywords: if True, --keyword-template replaces keywords instead of adding keywords
retry: retry up to retry # of times if there's an error
export_aae: bool; if True, will also save adjustments
sidecar_drop_ext: bool; if True, drops photo extension from sidecar name
sidecar: list zero, 1 or 2 of ["json","xmp"] of sidecar variety to export
skip_original_if_edited: bool; if True does not export original if photo has been edited
@@ -1950,6 +1969,7 @@ def export_photo(
preview_suffix=rendered_preview_suffix,
replace_keywords=replace_keywords,
retry=retry,
export_aae=export_aae,
sidecar_drop_ext=sidecar_drop_ext,
sidecar_flags=sidecar_flags,
touch_file=touch_file,
@@ -2066,6 +2086,7 @@ def export_photo(
preview_suffix=rendered_preview_suffix,
replace_keywords=replace_keywords,
retry=retry,
export_aae=export_aae,
sidecar_drop_ext=sidecar_drop_ext,
sidecar_flags=sidecar_flags if not export_original else 0,
touch_file=touch_file,
@@ -2153,6 +2174,7 @@ def export_photo_to_directory(
preview_suffix,
replace_keywords,
retry,
export_aae,
sidecar_drop_ext,
sidecar_flags,
touch_file,
@@ -2217,6 +2239,7 @@ def export_photo_to_directory(
render_options=render_options,
replace_keywords=replace_keywords,
rich=True,
export_aae=export_aae,
sidecar=sidecar_flags,
sidecar_drop_ext=sidecar_drop_ext,
tmpdir=tmpdir,

View File

@@ -19,14 +19,14 @@ from osxphotos.export_db_utils import (
export_db_backup,
export_db_check_signatures,
export_db_get_errors,
export_db_get_last_library,
export_db_get_last_run,
export_db_get_version,
export_db_migrate_photos_library,
export_db_save_config_to_file,
export_db_touch_files,
export_db_update_signatures,
export_db_vacuum,
export_db_migrate_photos_library,
export_db_get_last_library,
)
from osxphotos.utils import pluralize

View File

@@ -20,7 +20,7 @@ from osxphotos.phototemplate import (
TEMPLATE_SUBSTITUTIONS_PATHLIB,
get_template_help,
)
from osxphotos.utils import is_macos
from osxphotos.platform import is_macos
if is_macos:
from osxmetadata import MDITEM_ATTRIBUTE_DATA, MDITEM_ATTRIBUTE_SHORT_NAMES

View File

@@ -41,8 +41,10 @@ from osxphotos.exiftool import ExifToolCaching, get_exiftool_path
from osxphotos.photoinfo import PhotoInfoNone
from osxphotos.photosalbum import PhotosAlbumPhotoScript
from osxphotos.phototemplate import PhotoTemplate, RenderOptions
from osxphotos.platform import assert_macos
from osxphotos.sqlitekvstore import SQLiteKVStore
from osxphotos.utils import assert_macos, pluralize
from osxphotos.unicode import normalize_unicode
from osxphotos.utils import pluralize
assert_macos()
@@ -357,11 +359,12 @@ def set_photo_metadata(
merge_keywords: bool,
) -> MetaData:
"""Set metadata (title, description, keywords) for a Photo object"""
photo.title = metadata.title
photo.description = metadata.description
photo.title = normalize_unicode(metadata.title)
photo.description = normalize_unicode(metadata.description)
keywords = metadata.keywords.copy()
keywords =normalize_unicode(keywords)
if merge_keywords:
if old_keywords := photo.keywords:
if old_keywords := normalize_unicode(photo.keywords):
keywords.extend(old_keywords)
keywords = list(set(keywords))
photo.keywords = keywords
@@ -420,7 +423,7 @@ def set_photo_title(
verbose(
f"Setting title of photo [filename]{filepath.name}[/] to '{title_text[0]}'"
)
photo.title = title_text[0]
photo.title = normalize_unicode(title_text[0])
return title_text[0]
else:
return ""
@@ -448,7 +451,7 @@ def set_photo_description(
verbose(
f"Setting description of photo [filename]{filepath.name}[/] to '{description_text[0]}'"
)
photo.description = description_text[0]
photo.description = normalize_unicode(description_text[0])
return description_text[0]
else:
return ""
@@ -469,8 +472,9 @@ def set_photo_keywords(
kw = render_photo_template(filepath, relative_filepath, keyword, exiftool_path)
keywords.extend(kw)
if keywords:
keywords = normalize_unicode(keywords)
if merge:
if old_keywords := photo.keywords:
if old_keywords := normalize_unicode(photo.keywords):
keywords.extend(old_keywords)
keywords = list(set(keywords))
verbose(f"Setting keywords of photo [filename]{filepath.name}[/] to {keywords}")
@@ -1418,7 +1422,13 @@ def import_cli(
verbose_flag,
walk,
):
"""Import photos and videos into Photos."""
"""Import photos and videos into Photos. Photos will be imported into the
most recently opened Photos library.
Photos are imported one at a time thus the "Imports" album in Photos will show
a new import group for each photo imported. Batch import into a single import
group will be added in a future release.
"""
verbose = verbose_print(verbose=verbose_flag, timestamp=timestamp, theme=theme)

View File

@@ -20,8 +20,9 @@ from rich.panel import Panel
from osxphotos import PhotoInfo, PhotosDB
from osxphotos._constants import _UNKNOWN_PERSON, search_category_factory
from osxphotos.platform import assert_macos
from osxphotos.rich_utils import add_rich_markup_tag
from osxphotos.utils import assert_macos, dd_to_dms_str
from osxphotos.utils import dd_to_dms_str
assert_macos()

View File

@@ -1,6 +1,7 @@
"""query command for osxphotos CLI"""
import sys
import click
import osxphotos
@@ -11,8 +12,8 @@ from osxphotos.cli.click_rich_echo import (
)
from osxphotos.debug import set_debug
from osxphotos.phototemplate import RenderOptions
from osxphotos.platform import assert_macos, is_macos
from osxphotos.queryoptions import query_options_from_kwargs
from osxphotos.utils import assert_macos, is_macos
if is_macos:
from osxphotos.photosalbum import PhotosAlbum
@@ -51,6 +52,7 @@ MACOS_OPTIONS = make_click_option_decorator(
@click.command()
@DB_OPTION
@JSON_OPTION
@click.option("--count", is_flag=True, help="Print count of photos matching query and exit.")
@QUERY_OPTIONS
@DELETED_OPTIONS
@MACOS_OPTIONS
@@ -81,6 +83,7 @@ def query(
db,
field,
json_,
count,
print_template,
quiet,
photos_library,
@@ -136,6 +139,10 @@ def query(
# below needed for to make CliRunner work for testing
cli_json = cli_obj.json if cli_obj is not None else None
if count:
click.echo(len(photos))
return
if add_to_album and photos:
assert_macos()

View File

@@ -5,8 +5,11 @@ import os
import os.path
import pathlib
import re
import shlex
import subprocess
import sys
import time
from functools import partial
from typing import List
import click
@@ -17,13 +20,13 @@ from osxphotos._constants import _PHOTOS_4_VERSION
from osxphotos.cli.click_rich_echo import rich_echo_error as echo_error
from osxphotos.photoinfo import PhotoInfo
from osxphotos.photosdb import PhotosDB
from osxphotos.platform import assert_macos, is_macos
from osxphotos.pyrepl import embed_repl
from osxphotos.queryoptions import (
IncompatibleQueryOptions,
QueryOptions,
query_options_from_kwargs,
)
from osxphotos.utils import assert_macos, is_macos
if is_macos:
import photoscript
@@ -100,6 +103,7 @@ def repl(ctx, cli_obj, db, emacs, beta, **kwargs):
get_photo = photosdb.get_photo
show = _show_photo
spotlight = _spotlight_photo
find = partial(_find_in_library, photosdb)
get_selected = _get_selected(photosdb)
try:
selected = get_selected()
@@ -129,28 +133,31 @@ def repl(ctx, cli_obj, db, emacs, beta, **kwargs):
)
print(f"\nThe following functions may be helpful:")
print(
f"- get_photo(uuid): return a PhotoInfo object for photo with uuid; e.g. get_photo('B13F4485-94E0-41CD-AF71-913095D62E31')"
"- get_photo(uuid): return a PhotoInfo object for photo with uuid; e.g. get_photo('B13F4485-94E0-41CD-AF71-913095D62E31')"
)
print(
f"- get_selected(); return list of PhotoInfo objects for photos selected in Photos"
"- get_selected(); return list of PhotoInfo objects for photos selected in Photos"
)
print(
f"- show(photo): open a photo object in the default viewer; e.g. show(selected[0])"
"- show(photo): open a photo object in the default viewer; e.g. show(selected[0])"
)
print(
f"- show(path): open a file at path in the default viewer; e.g. show('/path/to/photo.jpg')"
"- show(path): open a file at path in the default viewer; e.g. show('/path/to/photo.jpg')"
)
print(f"- spotlight(photo): open a photo and spotlight it in Photos")
print("- spotlight(photo): open a photo and spotlight it in Photos")
# print(
# f"- help(object): print help text including list of methods for object; for example, help(PhotosDB)"
# )
print(
f"- inspect(object): print information about an object; e.g. inspect(PhotoInfo)"
"- inspect(object): print information about an object; e.g. inspect(PhotoInfo)"
)
print(
f"- explore(object): interactively explore an object with objexplore; e.g. explore(PhotoInfo)"
"- explore(object): interactively explore an object with objexplore; e.g. explore(PhotoInfo)"
)
print(f"- q, quit, quit(), exit, exit(): exit this interactive shell\n")
print(
"- find(text): search for files matching text in Photos library; e.g. find('B13F4485')"
)
print("- q, quit, quit(), exit, exit(): exit this interactive shell\n")
embed_repl(
globals=globals(),
@@ -233,3 +240,20 @@ def _query_photos(photosdb: PhotosDB, query_options: QueryOptions) -> List:
) from e
return photos
def _find_in_library(photosdb: PhotosDB, search_str: str) -> list[str]:
"""Find files in Photos library matching search_str using find command"""
# this is a quick and dirty way to find files in the Photos library
# e.g. those matching a UUID or a filename
library_path = photosdb.library_path
if not library_path:
raise ValueError("Could not find Photos library")
search_str = shlex.quote(search_str)
library_path = shlex.quote(library_path)
cmd = f"find {library_path} | grep {search_str}"
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
# Split the output into lines and return as a list
return output.strip().split("\n")

View File

@@ -8,7 +8,8 @@ import click
from osxphotos._constants import UUID_PATTERN
from osxphotos.export_db_utils import get_uuid_for_filepath
from osxphotos.photosdb.photosdb_utils import get_photos_library_version
from osxphotos.utils import get_last_library_path, assert_macos
from osxphotos.platform import assert_macos
from osxphotos.utils import get_last_library_path
assert_macos()

View File

@@ -15,13 +15,14 @@ from osxphotos.photoinfo import PhotoInfoNone
from osxphotos.photosalbum import PhotosAlbum
from osxphotos.photosdb.photosdb_utils import get_db_version
from osxphotos.phototemplate import PhotoTemplate, RenderOptions
from osxphotos.platform import assert_macos
from osxphotos.queryoptions import (
IncompatibleQueryOptions,
QueryOptions,
query_options_from_kwargs,
)
from osxphotos.sqlitekvstore import SQLiteKVStore
from osxphotos.utils import assert_macos, pluralize
from osxphotos.utils import pluralize
assert_macos()

View File

@@ -25,11 +25,13 @@ from osxphotos.photodates import (
update_photo_time_for_new_timezone,
)
from osxphotos.phototz import PhotoTimeZone, PhotoTimeZoneUpdater
from osxphotos.utils import assert_macos, noop, pluralize
from osxphotos.platform import assert_macos
from osxphotos.utils import noop, pluralize
assert_macos()
from photoscript import PhotosLibrary
from osxphotos.photosalbum import PhotosAlbumPhotoScript
from .cli_params import THEME_OPTION, TIMESTAMP_OPTION, VERBOSE_OPTION

View File

@@ -2,7 +2,7 @@
import click
from osxphotos.utils import assert_macos
from osxphotos.platform import assert_macos
assert_macos()

View File

@@ -1,11 +1,14 @@
"""about command for osxphotos CLI"""
import click
import os
import click
import packaging
from osxphotos._constants import OSXPHOTOS_URL
from osxphotos._version import __version__
from .common import get_latest_version
import packaging
@click.command(name="version")

View File

@@ -7,11 +7,13 @@ from osxphotos import PhotosDB
from osxphotos.exiftool import ExifTool
from .datetime_utils import datetime_naive_to_local, datetime_to_new_tz
from .utils import assert_macos, noop
from .platform import assert_macos
from .utils import noop
assert_macos()
from photoscript import Photo
from .exif_datetime_updater import get_exif_date_time_offset
from .phototz import PhotoTimeZone

Binary file not shown.

View File

@@ -27,7 +27,7 @@ import osxphotos
from ._constants import OSXPHOTOS_EXPORT_DB, SQLITE_CHECK_SAME_THREAD
from ._version import __version__
from .fileutil import FileUtil
from .utils import normalize_fs_path
from .unicode import normalize_fs_path
__all__ = [
"ExportDB",

View File

@@ -10,7 +10,8 @@ from abc import ABC, abstractmethod
from tempfile import TemporaryDirectory
from .imageconverter import ImageConverter
from .utils import is_macos, normalize_fs_path
from .platform import is_macos
from .unicode import normalize_fs_path
if is_macos:
import Foundation

View File

@@ -10,11 +10,11 @@ import sys
# needed to capture system-level stderr
from wurlitzer import pipes
from .utils import is_macos
from .platform import is_macos
if is_macos:
import objc
import Metal
import objc
import Quartz
from Cocoa import NSURL
from Foundation import NSDictionary

View File

@@ -13,7 +13,7 @@ filename is needed.
import pathvalidate
from osxphotos.utils import normalize_unicode
from osxphotos.unicode import normalize_unicode
from ._constants import MAX_DIRNAME_LEN, MAX_FILENAME_LEN

View File

@@ -36,17 +36,17 @@ from .exiftool import ExifTool, ExifToolCaching, exiftool_can_write, get_exiftoo
from .export_db import ExportDB, ExportDBTemp
from .fileutil import FileUtil
from .phototemplate import RenderOptions
from .platform import is_macos
from .rich_utils import add_rich_markup_tag
from .unicode import normalize_fs_path
from .uti import get_preferred_uti_extension
from .utils import (
hexdigest,
increment_filename,
increment_filename_with_count,
is_macos,
lineno,
list_directory,
lock_filename,
normalize_fs_path,
unlock_filename,
)
@@ -135,6 +135,7 @@ class ExportOptions:
render_options (RenderOptions): t.Optional osxphotos.phototemplate.RenderOptions instance to specify options for rendering templates
replace_keywords (bool): if True, keyword_template replaces any keywords, otherwise it's additive
rich (bool): if True, will use rich markup with verbose output
export_aae (bool): if True, also exports adjustments as .AAE file
sidecar_drop_ext (bool, default=False): if True, drops the photo's extension from sidecar filename (e.g. 'IMG_1234.json' instead of 'IMG_1234.JPG.json')
sidecar: bit field (int): set to one or more of `SIDECAR_XMP`, `SIDECAR_JSON`, `SIDECAR_EXIFTOOL`
- SIDECAR_JSON: if set will write a json sidecar with data in format readable by exiftool sidecar filename will be dest/filename.json;
@@ -187,6 +188,7 @@ class ExportOptions:
render_options: t.Optional[RenderOptions] = None
replace_keywords: bool = False
rich: bool = False
export_aae: bool = False
sidecar_drop_ext: bool = False
sidecar: int = 0
strip: bool = False
@@ -281,6 +283,7 @@ class ExportResults:
"missing",
"missing_album",
"new",
"aae_written",
"sidecar_exiftool_skipped",
"sidecar_exiftool_written",
"sidecar_json_skipped",
@@ -311,6 +314,7 @@ class ExportResults:
missing=None,
missing_album=None,
new=None,
aae_written=None,
sidecar_exiftool_skipped=None,
sidecar_exiftool_written=None,
sidecar_json_skipped=None,
@@ -350,6 +354,7 @@ class ExportResults:
+ self.exif_updated
+ self.touched
+ self.converted_to_jpeg
+ self.aae_written
+ self.sidecar_json_written
+ self.sidecar_json_skipped
+ self.sidecar_exiftool_written
@@ -605,6 +610,8 @@ class PhotoExporter:
f"Skipping missing preview photo for {self._filename(self.photo.original_filename)} ({self._uuid(self.photo.uuid)})"
)
if options.export_aae:
all_results += self._write_aae_file(dest=dest, options=options)
all_results += self._write_sidecar_files(dest=dest, options=options)
return all_results
@@ -1404,6 +1411,53 @@ class PhotoExporter:
exported_paths.append(str(dest_new))
return exported_paths
def _write_aae_file(
self,
dest: pathlib.Path,
options: ExportOptions,
) -> ExportResults:
"""Write AAE file for the photo."""
# AAE files describe adjustments to originals, so they don't make sense
# for edited files
if options.edited:
return ExportResults()
verbose = options.verbose or self._verbose
aae_src = self.photo.adjustments_path
if aae_src is None:
return ExportResults()
aae_dest = dest.with_suffix(".AAE")
if options.export_as_hardlink:
try:
if aae_dest.exists() and any(
[options.overwrite, options.update, options.force_update]):
try:
options.fileutil.unlink(aae_dest)
except Exception as e:
raise ExportError(
f"Error removing file {aae_dest}: {e} (({lineno(__file__)})"
) from e
options.fileutil.hardlink(aae_src, aae_dest)
except Exception as e:
raise ExportError(
f"Error hardlinking {aae_src} to {aae_dest}: {e} ({lineno(__file__)})"
) from e
else:
try:
options.fileutil.copy(aae_src, aae_dest)
verbose(
f"Exported adjustments of {self._filename(self.photo.original_filename)} to {self._filepath(normalize_fs_path(aae_dest))}"
)
except Exception as e:
raise ExportError(
f"Error copying file {aae_src} to {aae_dest}: {e} ({lineno(__file__)})"
) from e
return ExportResults(aae_written=[aae_dest])
def _write_sidecar_files(
self,
dest: pathlib.Path,

View File

@@ -61,14 +61,16 @@ from .photoexporter import ExportOptions, PhotoExporter
from .phototables import PhotoTables
from .phototemplate import PhotoTemplate, RenderOptions
from .placeinfo import PlaceInfo4, PlaceInfo5
from .platform import assert_macos, is_macos
from .query_builder import get_query
from .scoreinfo import ScoreInfo
from .searchinfo import SearchInfo
from .uti import get_preferred_uti_extension, get_uti_for_extension
from .utils import _get_resource_loc, assert_macos, is_macos, hexdigest, list_directory
from .utils import _get_resource_loc, hexdigest, list_directory
if is_macos:
from osxmetadata import OSXMetaData
from .text_detection import detect_text
__all__ = ["PhotoInfo", "PhotoInfoNone", "frozen_photoinfo_factory"]
@@ -134,8 +136,7 @@ class PhotoInfo:
if not self.hasadjustments and self._db._db_version <= _PHOTOS_4_VERSION:
return None
imagedate = self._info["lastmodifieddate"]
if imagedate:
if imagedate := self._info["lastmodifieddate"]:
seconds = self._info["imageTimeZoneOffsetSeconds"] or 0
delta = timedelta(seconds=seconds)
tz = timezone(delta)
@@ -172,6 +173,9 @@ class PhotoInfo:
"""Returns candidate path for original photo on Photos >= version 5"""
if self._info["shared"]:
return self._path_5_shared()
if self.syndicated and not self.saved_to_library:
# path for "shared with you" syndicated photos that have not yet been saved to the library
return self._path_syndication()
return (
os.path.join(self._info["directory"], self._info["filename"])
if self._info["directory"].startswith("/")
@@ -211,6 +215,21 @@ class PhotoInfo:
filename,
)
def _path_syndication(self):
"""Return path for syndicated photo on Photos >= version 8"""
# Photos 8+ stores syndicated photos in a separate directory
# in ~/Photos Library.photoslibrary/scopes/syndication/originals/X/UUID.ext
# where X is first digit of UUID
syndication_path = "scopes/syndication/originals"
uuid_dir = self.uuid[0]
path = os.path.join(
self._db._library_path,
syndication_path,
uuid_dir,
self.filename,
)
return path if os.path.isfile(path) else None
def _path_4(self):
"""Returns candidate path for original photo on Photos <= version 4"""
if self._info["has_raw"]:
@@ -631,28 +650,38 @@ class PhotoInfo:
return self._info["hasAdjustments"] == 1
@property
def adjustments(self):
"""Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only"""
def adjustments_path(self):
"""Returns path to adjustments file or none if file doesn't exist"""
if self._db._db_version <= _PHOTOS_4_VERSION:
return None
if self.hasadjustments:
try:
return self._adjustmentinfo
except AttributeError:
library = self._db._library_path
directory = self._uuid[0] # first char of uuid
plist_file = (
pathlib.Path(library)
/ "resources"
/ "renders"
/ directory
/ f"{self._uuid}.plist"
)
if not plist_file.is_file():
return None
self._adjustmentinfo = AdjustmentsInfo(plist_file)
return self._adjustmentinfo
if not self.hasadjustments:
return None
library = self._db._library_path
directory = self._uuid[0] # first char of uuid
plist_file = (
pathlib.Path(library)
/ "resources"
/ "renders"
/ directory
/ f"{self._uuid}.plist"
)
if not plist_file.is_file():
return None
return plist_file
@property
def adjustments(self):
"""Returns AdjustmentsInfo class for adjustment data or None if no adjustments; Photos 5+ only"""
try:
return self._adjustmentinfo
except AttributeError:
plist_file = self.adjustments_path
if plist_file is None:
return None
self._adjustmentinfo = AdjustmentsInfo(plist_file)
return self._adjustmentinfo
@property
def external_edit(self):
@@ -881,6 +910,10 @@ class PhotoInfo:
elif self.live_photo and self.path and not self.ismissing:
if self.shared:
return self._path_live_photo_shared_5()
if self.syndicated and not self.saved_to_library:
# syndicated ("Shared with you") photos not yet saved to library
return self._path_live_syndicated()
filename = pathlib.Path(self.path)
photopath = filename.parent.joinpath(f"{filename.stem}_3.mov")
photopath = str(photopath)
@@ -938,8 +971,24 @@ class PhotoInfo:
photopath = None
return photopath
def _path_live_syndicated(self):
"""Return path for live syndicated photo on Photos >= version 8"""
# Photos 8+ stores live syndicated photos in a separate directory
# in ~/Photos Library.photoslibrary/scopes/syndication/originals/X/UUID_3.mov
# where X is first digit of UUID
syndication_path = "scopes/syndication/originals"
uuid_dir = self.uuid[0]
filename = f"{pathlib.Path(self.filename).stem}_3.mov"
live_photo = os.path.join(
self._db._library_path,
syndication_path,
uuid_dir,
filename,
)
return live_photo if os.path.isfile(live_photo) else None
@cached_property
def path_derivatives(self):
def path_derivatives(self) -> list[str]:
"""Return any derivative (preview) images associated with the photo as a list of paths, sorted by file size (largest first)"""
if self._db._db_version <= _PHOTOS_4_VERSION:
return self._path_derivatives_4()
@@ -948,24 +997,36 @@ class PhotoInfo:
return self._path_derivatives_5_shared()
directory = self._uuid[0] # first char of uuid
derivative_path = (
pathlib.Path(self._db._library_path) / f"resources/derivatives/{directory}"
)
if self.syndicated and not self.saved_to_library:
# syndicated ("Shared with you") photos not yet saved to library
derivative_path = "scopes/syndication/resources/derivatives"
thumb_path = (
f"{derivative_path}/masters/{directory}/{self.uuid}_4_5005_c.jpeg"
)
else:
derivative_path = f"resources/derivatives/{directory}"
thumb_path = (
f"resources/derivatives/masters/{directory}/{self.uuid}_4_5005_c.jpeg"
)
derivative_path = pathlib.Path(self._db._library_path).joinpath(derivative_path)
thumb_path = pathlib.Path(self._db._library_path).joinpath(thumb_path)
# find all files that start with uuid in derivative path
files = list(derivative_path.glob(f"{self.uuid}*.*"))
# previews may be missing from derivatives path
# there are what appear to be low res thumbnails in the "masters" subfolder
thumb_path = (
pathlib.Path(self._db._library_path)
/ f"resources/derivatives/masters/{directory}/{self.uuid}_4_5005_c.jpeg"
)
if thumb_path.exists():
files.append(thumb_path)
# sort by file size, largest first
files = sorted(files, reverse=True, key=lambda f: f.stat().st_size)
# return list of filename but skip .THM files (these are actually low-res thumbnails in JPEG format but with .THM extension)
derivatives = [str(filename) for filename in files if filename.suffix != ".THM"]
if self.isphoto and len(derivatives) > 1 and derivatives[0].endswith(".mov"):
# ensure .mov is first in list as poster image could be larger than the movie preview
derivatives[1], derivatives[0] = derivatives[0], derivatives[1]
return derivatives
@@ -1284,6 +1345,38 @@ class PhotoInfo:
self._search_info_normalized = SearchInfo(self, normalized=True)
return self._search_info_normalized
@cached_property
def syndicated(self) -> bool | None:
"""Return true if photo was shared via syndication (e.g. via Messages, etc.);
these are photos that appear in "Shared with you" album.
Photos 8+ only; returns None if not Photos 8+.
"""
if self._db.photos_version < 8:
return None
try:
return (
self._db._db_syndication_uuid[self.uuid]["syndication_identifier"]
is not None
)
except KeyError:
return False
@cached_property
def saved_to_library(self) -> bool | None:
"""Return True if syndicated photo has been saved to library;
returns False if photo is not syndicated or has not been saved to the library.
Returns None if not Photos 8+.
Syndicated photos are photos that appear in "Shared with you" album; Photos 8+ only.
"""
if self._db.photos_version < 8:
return None
try:
return self._db._db_syndication_uuid[self.uuid]["syndication_history"] != 0
except KeyError:
return False
@property
def labels(self):
"""returns list of labels applied to photo by Photos image categorization

View File

@@ -23,6 +23,8 @@ import sys
import threading
import time
from .platform import get_macos_version
assert sys.platform == "darwin"
import AVFoundation
@@ -37,7 +39,7 @@ from wurlitzer import pipes
from .fileutil import FileUtil
from .uti import get_preferred_uti_extension
from .utils import get_macos_version, increment_filename
from .utils import increment_filename
__all__ = [
"NSURL_to_path",

View File

@@ -1,11 +1,15 @@
""" PhotosAlbum class to create an album in default Photos library and add photos to it """
from __future__ import annotations
import unicodedata
from typing import List, Optional
from more_itertools import chunked
from .photoinfo import PhotoInfo
from .utils import assert_macos, noop, pluralize
from .platform import assert_macos
from .utils import noop, pluralize
assert_macos()
@@ -15,19 +19,36 @@ from photoscript import Album, Folder, Photo, PhotosLibrary
__all__ = ["PhotosAlbum", "PhotosAlbumPhotoScript"]
def get_unicode_variants(s: str) -> list[str]:
"""Get all unicode variants of string"""
variants = []
for form in ["NFC", "NFD", "NFKC", "NFKD"]:
normalized = unicodedata.normalize(form, s)
variants.append(normalized)
return variants
def folder_by_path(folders: List[str], verbose: Optional[callable] = None) -> Folder:
"""Get (and create if necessary) a Photos Folder by path (passed as list of folder names)"""
library = PhotosLibrary()
verbose = verbose or noop
top_folder_name = folders.pop(0)
top_folder = library.folder(top_folder_name, top_level=True)
if not top_folder:
for folder_variant in get_unicode_variants(top_folder_name):
top_folder = library.folder(folder_variant, top_level=True)
if top_folder is not None:
break
else:
verbose(f"Creating folder '{top_folder_name}'")
top_folder = library.create_folder(top_folder_name)
current_folder = top_folder
for folder_name in folders:
folder = current_folder.folder(folder_name)
if not folder:
for folder_variant in get_unicode_variants(folder_name):
folder = current_folder.folder(folder_variant)
if folder is not None:
break
else:
verbose(f"Creating folder '{folder_name}'")
folder = current_folder.create_folder(folder_name)
current_folder = folder
@@ -44,15 +65,24 @@ def album_by_path(
# have folders
album_name = folders_album.pop()
folder = folder_by_path(folders_album, verbose)
album = folder.album(album_name)
if album is None:
for album_variant in get_unicode_variants(album_name):
# Get album if it exists
# need to check every unicode variant to avoid creating duplicate albums with same visual representation (#1085)
album = folder.album(album_variant)
if album is not None:
break
else:
verbose(f"Creating album '{album_name}'")
album = folder.create_album(album_name)
else:
# only have album name
album_name = folders_album[0]
album = library.album(album_name, top_level=True)
if album is None:
for album_variant in get_unicode_variants(album_name):
album = library.album(album_variant, top_level=True)
if album is not None:
break
else:
# album doesn't exist, create it
verbose(f"Creating album '{album_name}'")
album = library.create_album(album_name)

View File

@@ -4,7 +4,7 @@ from __future__ import annotations
import sqlite3
from .utils import assert_macos
from .platform import assert_macos
assert_macos()

View File

@@ -4,4 +4,4 @@ Processes a Photos.app library database to extract information about photos
"""
from .photosdb import PhotosDB
from .photosdb_utils import get_db_version, get_db_model_version, get_model_version
from .photosdb_utils import get_db_model_version, get_db_version, get_model_version

View File

@@ -6,8 +6,8 @@ import datetime
from dataclasses import dataclass
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION, TIME_DELTA
from ..utils import normalize_unicode
from ..sqlite_utils import sqlite_open_ro
from ..unicode import normalize_unicode
def _process_comments(self):

View File

@@ -4,7 +4,7 @@
import logging
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
from ..sqlite_utils import sqlite_open_ro, sqlite_db_is_locked
from ..sqlite_utils import sqlite_db_is_locked, sqlite_open_ro
from .photosdb_utils import get_db_version

View File

@@ -4,7 +4,7 @@
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
from ..sqlite_utils import sqlite_open_ro
from ..utils import normalize_unicode
from ..unicode import normalize_unicode
from .photosdb_utils import get_db_version
"""

View File

@@ -7,11 +7,10 @@ import logging
import pathlib
import uuid as uuidlib
from functools import lru_cache
from pprint import pformat
from .._constants import _PHOTOS_4_VERSION, search_category_factory
from ..sqlite_utils import sqlite_db_is_locked, sqlite_open_ro
from ..utils import normalize_unicode
from ..unicode import normalize_unicode
"""
This module should be imported in the class defintion of PhotosDB in photosdb.py
@@ -154,7 +153,7 @@ def _process_searchinfo(self):
def labels(self):
"""return list of all search info labels found in the library"""
if self._db_version <= _PHOTOS_4_VERSION:
logging.warning(f"SearchInfo not implemented for this library version")
logging.warning("SearchInfo not implemented for this library version")
return []
return list(self._db_searchinfo_labels.keys())
@@ -164,7 +163,7 @@ def labels(self):
def labels_normalized(self):
"""return list of all normalized search info labels found in the library"""
if self._db_version <= _PHOTOS_4_VERSION:
logging.warning(f"SearchInfo not implemented for this library version")
logging.warning("SearchInfo not implemented for this library version")
return []
return list(self._db_searchinfo_labels_normalized.keys())
@@ -174,8 +173,8 @@ def labels_normalized(self):
def labels_as_dict(self):
"""return labels as dict of label: count in reverse sorted order (descending)"""
if self._db_version <= _PHOTOS_4_VERSION:
logging.warning(f"SearchInfo not implemented for this library version")
return dict()
logging.warning("SearchInfo not implemented for this library version")
return {}
labels = {k: len(v) for k, v in self._db_searchinfo_labels.items()}
labels = dict(sorted(labels.items(), key=lambda kv: kv[1], reverse=True))
@@ -186,8 +185,8 @@ def labels_as_dict(self):
def labels_normalized_as_dict(self):
"""return normalized labels as dict of label: count in reverse sorted order (descending)"""
if self._db_version <= _PHOTOS_4_VERSION:
logging.warning(f"SearchInfo not implemented for this library version")
return dict()
logging.warning("SearchInfo not implemented for this library version")
return {}
labels = {k: len(v) for k, v in self._db_searchinfo_labels_normalized.items()}
labels = dict(sorted(labels.items(), key=lambda kv: kv[1], reverse=True))
return labels

View File

@@ -0,0 +1,60 @@
""" Methods for PhotosDB to process Syndication info (#1054) """
from __future__ import annotations
from typing import TYPE_CHECKING
from .._constants import _DB_TABLE_NAMES
from ..sqlite_utils import sqlite_open_ro
if TYPE_CHECKING:
from osxphotos.photosdb import PhotosDB
def _process_syndicationinfo(self: PhotosDB):
"""Process syndication information"""
self._db_syndication_uuid = {}
if self.photos_version < 8:
raise NotImplementedError(
f"syndication info not implemented for this database version: {self.photos_version}"
)
else:
_process_syndicationinfo_8(self)
def _process_syndicationinfo_8(photosdb: PhotosDB):
"""Process Syndication info for Photos 8.0 and later
Args:
photosdb: an OSXPhotosDB instance
"""
db = photosdb._tmp_db
zasset = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
(conn, cursor) = sqlite_open_ro(db)
result = cursor.execute(
f"""
SELECT
{zasset}.ZUUID,
{zasset}.ZSYNDICATIONSTATE,
ZADDITIONALASSETATTRIBUTES.ZSYNDICATIONHISTORY,
ZADDITIONALASSETATTRIBUTES.ZSYNDICATIONIDENTIFIER
FROM {zasset}
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {zasset}.Z_PK
"""
)
for row in result:
uuid = row[0]
syndication_state = row[1]
syndication_history = row[2]
syndication_identifier = row[3]
photosdb._db_syndication_uuid[uuid] = {
"syndication_state": syndication_state,
"syndication_identifier": syndication_identifier,
"syndication_history": syndication_history,
}

View File

@@ -56,17 +56,12 @@ from ..fileutil import FileUtil
from ..personinfo import PersonInfo
from ..photoinfo import PhotoInfo
from ..phototemplate import RenderOptions
from ..platform import get_macos_version, is_macos
from ..queryoptions import QueryOptions
from ..rich_utils import add_rich_markup_tag
from ..sqlite_utils import sqlite_db_is_locked, sqlite_open_ro
from ..utils import (
_check_file_exists,
is_macos,
get_macos_version,
get_last_library_path,
noop,
normalize_unicode,
)
from ..unicode import normalize_unicode
from ..utils import _check_file_exists, get_last_library_path, noop
from .photosdb_utils import get_db_model_version, get_db_version
if is_macos:
@@ -96,6 +91,7 @@ class PhotosDB:
labels_normalized,
labels_normalized_as_dict,
)
from ._photosdb_process_syndicationinfo import _process_syndicationinfo
def __init__(
self,
@@ -290,6 +286,10 @@ class PhotosDB:
# Dict to hold data on imports for Photos <= 4
self._db_import_group = {}
# Dict to hold syndication info for Photos >= 8
# key is UUID and value is dict of syndication info
self._db_syndication_uuid = {}
logger.debug(f"dbfile = {dbfile}")
if dbfile is None:
@@ -2517,6 +2517,10 @@ class PhotosDB:
verbose("Processing moments.")
self._process_moments()
if self.photos_version >= 8:
verbose("Processing syndication info.")
self._process_syndicationinfo()
verbose("Done processing details from Photos library.")
def _process_moments(self):
@@ -3516,6 +3520,16 @@ class PhotosDB:
added_after = datetime_naive_to_local(added_after)
photos = [p for p in photos if p.date_added and p.date_added > added_after]
if options.syndicated:
photos = [p for p in photos if p.syndicated]
elif options.not_syndicated:
photos = [p for p in photos if not p.syndicated]
if options.saved_to_library:
photos = [p for p in photos if p.syndicated and p.saved_to_library]
elif options.not_saved_to_library:
photos = [p for p in photos if p.syndicated and not p.saved_to_library]
if options.function:
for function in options.function:
photos = function[0](photos)

View File

@@ -5,14 +5,16 @@
See https://developer.apple.com/documentation/corelocation/clplacemark
for additional documentation on reverse geolocation data
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from collections import namedtuple # pylint: disable=syntax-error
import yaml
from bpylist2 import archiver
from ._constants import UNICODE_FORMAT
from .utils import normalize_unicode
from .unicode import normalize_unicode
__all__ = [
"PLRevGeoLocationInfo",
@@ -332,35 +334,100 @@ archiver.update_class_map({"PLRevGeoMapItem": PLRevGeoMapItem})
archiver.update_class_map({"PLRevGeoLocationInfo": PLRevGeoLocationInfo})
class PlaceInfo(ABC):
# PlaceInfo is really an abstract base class but defining it as such
# means it doesn't get picked up by the doc generation tools
# so we define it as a regular class and then subclass it
# TODO: right fix is probably have PlaceInfo as the only class that
# is used and then have PlaceInfo4 and PlaceInfo5 called by PlaceInfo
# as needed to return the properties (and make them private classes)
class PlaceInfo:
"""Reverse geolocation place info for a photo."""
@property
@abstractmethod
def address_str(self):
def address_str(self) -> str | None:
"""Returns the full postal address as a string if defined, otherwise `None`."""
pass
@property
@abstractmethod
def country_code(self):
def country_code(self) -> str | None:
"""Returns the country_code of place, for example "GB".
Returns `None` if PhotoInfo contains no country code.
"""
pass
@property
@abstractmethod
def ishome(self):
def ishome(self) -> bool:
"""Returns `True` if photo place is user's home address, otherwise `False`."""
pass
@property
@abstractmethod
def name(self):
def name(self) -> str | None:
"""Returns the name of the local place as str.
This is what Photos displays in the Info window.
**Note** Photos 5 uses a different algorithm to determine the name than earlier versions which means the same Photo may have a different place name in Photos 4 and Photos 5.
`PhotoInfo.name` will return the name Photos would have shown depending on the version of the library being processed.
Returns `None` if photo does not contain a name.
"""
pass
@property
@abstractmethod
def names(self):
def names(self) -> PlaceNames | None:
"""Returns a `PlaceNames` namedtuple with the following fields.
Each field is a list with zero or more values, sorted by area in ascending order.
E.g. `names.area_of_interest` could be ['Gulf Islands National Seashore', 'Santa Rosa Island'], ["Knott's Berry Farm"], or [] if `area_of_interest` not defined.
The value shown in Photos is the first value in the list. With the exception of `body_of_water` each of these field corresponds to an attribute of
a [CLPlacemark](https://developer.apple.com/documentation/corelocation/clplacemark) object.
* `country`; the name of the country associated with the placemark.
* `state_province`; administrativeArea, The state or province associated with the placemark.
* `sub_administrative_area`; additional administrative area information for the placemark.
* `city`; locality; the city associated with the placemark.
* `additional_city_info`; subLocality, Additional city-level information for the placemark.
* `ocean`; the name of the ocean associated with the placemark.
* `area_of_interest`; areasOfInterest, The relevant areas of interest associated with the placemark.
* `inland_water`; the name of the inland water body associated with the placemark.
* `region`; the geographic region associated with the placemark.
* `sub_throughfare`; additional street-level information for the placemark.
* `postal_code`; the postal code associated with the placemark.
* `street_address`; throughfare, The street address associated with the placemark.
* `body_of_water`; in Photos 4, any body of water; in Photos 5 contains the union of ocean and inland_water
**Note**: In Photos <= 4.0, only the following fields are defined; all others are set to empty list:
* `country`
* `state_province`
* `sub_administrative_area`
* `city`
* `additional_city_info`
* `area_of_interest`
* `body_of_water`
Note:
The `PlaceNames` namedtuple contains reserved fields not listed below (see implementation for details),
thus it should be referenced only by name (e.g. `names.city`) and not by index.
"""
pass
@property
@abstractmethod
def address(self):
"""Returns a `PostalAddress` namedtuple with details of the postal address containing the following fields:
* `city`
* `country`
* `postal_code`
* `state`
* `street`
* `sub_administrative_area`
* `sub_locality`
* `iso_country_code`
"""
pass
def asdict():
"""Returns a dictionary representation of the PlaceInfo object."""
pass

29
osxphotos/platform.py Normal file
View File

@@ -0,0 +1,29 @@
"""Functions for multi-platform support"""
import platform
import sys
is_macos = sys.platform == "darwin"
def assert_macos():
assert is_macos, "This feature only runs on macOS"
def get_macos_version():
assert_macos()
# returns tuple of str containing OS version
# e.g. 10.13.6 = ("10", "13", "6")
version = platform.mac_ver()[0].split(".")
if len(version) == 2:
(ver, major) = version
minor = "0"
elif len(version) == 3:
(ver, major, minor) = version
else:
raise (
ValueError(
f"Could not parse version string: {platform.mac_ver()} {version}"
)
)
return (ver, major, minor)

View File

@@ -108,6 +108,10 @@ class QueryOptions:
uti: list of UTIs to search for
uuid: list of uuids to search for
year: search for photos taken in a given year
syndicated: search for photos that have been shared via syndication ("Shared with You" album via Messages, etc.)
not_syndicated: search for photos that have not been shared via syndication ("Shared with You" album via Messages, etc.)
saved_to_library: search for syndicated photos that have been saved to the Photos library
not_saved_to_library: search for syndicated photos that have not been saved to the Photos library
"""
added_after: Optional[datetime.datetime] = None
@@ -192,6 +196,10 @@ class QueryOptions:
uti: Optional[Iterable[str]] = None
uuid: Optional[Iterable[str]] = None
year: Optional[Iterable[int]] = None
syndicated: Optional[bool] = None
not_syndicated: Optional[bool] = None
saved_to_library: Optional[bool] = None
not_saved_to_library: Optional[bool] = None
def asdict(self):
return asdict(self)
@@ -261,6 +269,8 @@ def query_options_from_kwargs(**kwargs) -> QueryOptions:
("deleted", "not_deleted"),
("deleted", "deleted_only"),
("deleted_only", "not_deleted"),
("syndicated", "not_syndicated"),
("saved_to_library", "not_saved_to_library"),
]
# TODO: add option to validate requiring at least one query arg
for arg, not_arg in exclusive:

View File

@@ -1,6 +1,6 @@
""" ScoreInfo class to expose computed score info from the library """
from dataclasses import dataclass, asdict
from dataclasses import asdict, dataclass
from ._constants import _PHOTOS_4_VERSION

View File

@@ -4,7 +4,7 @@ import logging
import sys
from typing import List, Optional
from .utils import assert_macos, get_macos_version
from .platform import assert_macos, get_macos_version
assert_macos()

View File

@@ -1,9 +1,8 @@
"""Utilities for working with datetimes"""
import datetime
from typing import Optional
import re
from typing import Optional
def utc_offset_string_to_seconds(utc_offset: str) -> int:

View File

@@ -2,7 +2,7 @@
from typing import Union
from .utils import is_macos
from .platform import is_macos
def format_offset_time(offset: int) -> str:

90
osxphotos/unicode.py Normal file
View File

@@ -0,0 +1,90 @@
"""Utilities for working with unicode strings."""
from __future__ import annotations
import pathlib
import unicodedata
from typing import Literal, TypeVar, Union
from osxphotos.platform import is_macos
# Unicode format to use for comparing strings
DEFAULT_UNICODE_FORM = "NFC"
# global unicode format
_GLOBAL_UNICODE_FORM = DEFAULT_UNICODE_FORM
# global unicode format to use for filesystem paths
_GLOBAL_UNICODE_FS_FORM = "NFD" if is_macos else "NFC"
PathType = TypeVar("PathType", bound=Union[str, pathlib.Path])
UnicodeDataType = TypeVar(
"UnicodeDataType", bound=Union[str, list[str], tuple[str, ...], None]
)
__all__ = [
"get_unicode_form",
"set_unicode_form",
"get_unicode_fs_form",
"set_unicode_fs_form",
"normalize_fs_path",
"normalize_unicode",
"DEFAULT_UNICODE_FORM",
]
def get_unicode_form() -> Literal["NFC", "NFKC", "NFD", "NFKD"]:
"""Return the global unicode format"""
global _GLOBAL_UNICODE_FORM
return _GLOBAL_UNICODE_FORM
def set_unicode_form(format: Literal["NFC", "NFKC", "NFD", "NFKD"]) -> None:
"""Set the global unicode format"""
if format not in ["NFC", "NFKC", "NFD", "NFKD"]:
raise ValueError(f"Invalid unicode format: {format}")
global _GLOBAL_UNICODE_FORM
_GLOBAL_UNICODE_FORM = format
def get_unicode_fs_form() -> Literal["NFC", "NFKC", "NFD", "NFKD"]:
"""Return the global unicode filesystem format"""
global _GLOBAL_UNICODE_FS_FORM
return _GLOBAL_UNICODE_FS_FORM
def set_unicode_fs_form(format: str) -> Literal["NFC", "NFKC", "NFD", "NFKD"]:
"""Set the global unicode filesystem format"""
if format not in ["NFC", "NFKC", "NFD", "NFKD"]:
raise ValueError(f"Invalid unicode format: {format}")
global _GLOBAL_UNICODE_FS_FORM
_GLOBAL_UNICODE_FS_FORM = format
def normalize_fs_path(path: PathType) -> PathType:
"""Normalize filesystem paths with unicode in them"""
form = get_unicode_fs_form()
if isinstance(path, pathlib.Path):
return pathlib.Path(unicodedata.normalize(form, str(path)))
else:
return unicodedata.normalize(form, path)
def normalize_unicode(value: UnicodeDataType) -> UnicodeDataType:
"""normalize unicode data"""
form = get_unicode_form()
if value is None:
return None
if isinstance(value, tuple):
return tuple(unicodedata.normalize(form, v) for v in value)
elif isinstance(value, list):
return [unicodedata.normalize(form, v) for v in value]
elif isinstance(value, str):
return unicodedata.normalize(form, value)
else:
return value

View File

@@ -24,7 +24,7 @@ import subprocess
import sys
import tempfile
from .utils import assert_macos, is_macos, get_macos_version
from .platform import assert_macos, get_macos_version, is_macos
if is_macos:
import CoreServices

View File

@@ -1,5 +1,7 @@
""" Utility functions used in osxphotos """
from __future__ import annotations
import datetime
import fnmatch
import hashlib
@@ -9,30 +11,29 @@ import logging
import os
import os.path
import pathlib
import platform
import re
import subprocess
import sys
import unicodedata
import urllib.parse
from plistlib import load as plistload
from typing import Any, Callable, List, Optional, Tuple, TypeVar, Union
from typing import Callable, List, Optional, Tuple, TypeVar, Union
from uuid import UUID
import requests
import shortuuid
from ._constants import UNICODE_FORMAT
from osxphotos.platform import get_macos_version, is_macos
from osxphotos.unicode import normalize_fs_path
T = TypeVar("T", bound=Union[str, pathlib.Path])
logger = logging.getLogger("osxphotos")
__all__ = [
"is_macos",
"assert_macos",
"dd_to_dms_str",
"expand_and_validate_filepath",
"get_last_library_path",
"get_macos_version",
"get_system_library_path",
"hexdigest",
"increment_filename_with_count",
@@ -43,8 +44,6 @@ __all__ = [
"load_function",
"lock_filename",
"noop",
"normalize_fs_path",
"normalize_unicode",
"pluralize",
"shortuuid_to_uuid",
"uuid_to_shortuuid",
@@ -54,13 +53,6 @@ __all__ = [
VERSION_INFO_URL = "https://pypi.org/pypi/osxphotos/json"
is_macos = sys.platform == "darwin"
def assert_macos():
assert is_macos, "This feature only runs on macOS"
if is_macos:
import CoreFoundation
@@ -78,25 +70,6 @@ def lineno(filename):
return f"{filename}: {line}"
def get_macos_version():
assert_macos()
# returns tuple of str containing OS version
# e.g. 10.13.6 = ("10", "13", "6")
version = platform.mac_ver()[0].split(".")
if len(version) == 2:
(ver, major) = version
minor = "0"
elif len(version) == 3:
(ver, major, minor) = version
else:
raise (
ValueError(
f"Could not parse version string: {platform.mac_ver()} {version}"
)
)
return (ver, major, minor)
def _check_file_exists(filename):
"""returns true if file exists and is not a directory
otherwise returns false"""
@@ -280,16 +253,6 @@ def list_photo_libraries():
return lib_list
T = TypeVar("T", bound=Union[str, pathlib.Path])
def normalize_fs_path(path: T) -> T:
"""Normalize filesystem paths with unicode in them"""
form = "NFD" if is_macos else "NFC"
if isinstance(path, pathlib.Path):
return pathlib.Path(unicodedata.normalize(form, str(path)))
else:
return unicodedata.normalize(form, path)
# def findfiles(pattern, path):
@@ -378,18 +341,6 @@ def list_directory(
return files
def normalize_unicode(value) -> Any:
"""normalize unicode data"""
if value is None:
return None
if isinstance(value, (tuple, list)):
return tuple(unicodedata.normalize(UNICODE_FORMAT, v) for v in value)
elif isinstance(value, str):
return unicodedata.normalize(UNICODE_FORMAT, value)
else:
return value
def increment_filename_with_count(
filepath: Union[str, pathlib.Path], count: int = 0, lock: bool = False
) -> Tuple[str, int]:

View File

@@ -23,7 +23,7 @@ One test for locale does not run on GitHub's automated workflow and will look fo
A couple of tests require interaction with Photos and configuring a specific test library. Currently these run only on Catalina. The tests must be specified by using a pytest flag. Only one of these interactive tests can be run at a time. The current flags are:
--addalbum: test --add-to-album options
--addalbum: test --add-to-album options (pytest -vv tests/test_photosalbum_unicode.py tests/test_cli_add_to_album.py --addalbum)
--timewarp: test `osxphotos timewarp`
--test-import: test `osxphotos import`
--test-sync: test `osxphotos sync`

View File

@@ -7,7 +7,7 @@ import time
import pytest
from osxphotos.utils import is_macos
from osxphotos.platform import is_macos
if is_macos:
import photoscript
@@ -18,7 +18,6 @@ if is_macos:
from osxphotos.exiftool import _ExifToolProc
# run timewarp tests (configured with --timewarp)
TEST_TIMEWARP = False

View File

@@ -7,7 +7,7 @@
import pathlib
import osxphotos
from osxphotos.photoexporter import PhotoExporter, ExportOptions
from osxphotos.photoexporter import ExportOptions, PhotoExporter
PHOTOS_DB_15_7 = "./tests/Test-10.15.7.photoslibrary/database/photos.db"
PHOTOS_DB_14_6 = "./tests/Test-10.14.6.photoslibrary/database/photos.db"
@@ -92,9 +92,7 @@ def generate_sidecars(dbname, uuid_dict):
# ignore_date_modified
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_ignore_date_modified.json")
json_ = exporter.exiftool_json_sidecar(
ExportOptions(ignore_date_modified=True)
)
json_ = exporter.exiftool_json_sidecar(ExportOptions(ignore_date_modified=True))
with open(sidecar, "w") as file:
file.write(json_)

Some files were not shown because too many files have changed in this diff Show More