Compare commits

..

3 Commits

Author SHA1 Message Date
Rhet Turnbull
6070616717 Updated docs 2022-05-01 22:30:21 -07:00
Rhet Turnbull
70d3247e8c Feature timewarp function (#678)
* Added constraints, fixed themes for timewarp

* Updated progress to use rich_progress

* Added --function to timewarp, #676
2022-05-01 22:22:01 -07:00
Rhet Turnbull
25f35699d8 Updated CHANGELOG.md [skip ci] 2022-05-01 16:25:23 -07:00
30 changed files with 388 additions and 80 deletions

View File

@@ -1942,7 +1942,7 @@ cog.out(get_template_field_table())
|{lf}|A line feed: '\n', alias for {newline}|
|{cr}|A carriage return: '\r'|
|{crlf}|a carriage return + line feed: '\r\n'|
|{osxphotos_version}|The osxphotos version, e.g. '0.48.0'|
|{osxphotos_version}|The osxphotos version, e.g. '0.48.1'|
|{osxphotos_cmd_line}|The full command line used to run osxphotos|
|{album}|Album(s) photo is contained in|
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|

View File

@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [v0.48.0](https://github.com/RhetTbull/osxphotos/compare/v0.47.13...v0.48.0)
> 1 May 2022
- Feature timewarp [`#675`](https://github.com/RhetTbull/osxphotos/pull/675)
- Version bump [`d07aab5`](https://github.com/RhetTbull/osxphotos/commit/d07aab58d1b0ef8e8769740db089235bbc938a4e)
- Updated dependencies for rich_theme_manager [`8a3dc9b`](https://github.com/RhetTbull/osxphotos/commit/8a3dc9b3938f2363baba6dbf1f832ee55d57eb28)
#### [v0.47.13](https://github.com/RhetTbull/osxphotos/compare/v0.47.12...v0.47.13)
> 24 April 2022

View File

@@ -1808,7 +1808,7 @@ Substitution Description
{lf} A line feed: '\n', alias for {newline}
{cr} A carriage return: '\r'
{crlf} a carriage return + line feed: '\r\n'
{osxphotos_version} The osxphotos version, e.g. '0.48.0'
{osxphotos_version} The osxphotos version, e.g. '0.48.1'
{osxphotos_cmd_line} The full command line used to run osxphotos
The following substitutions may result in multiple values. Thus if specified
@@ -3721,7 +3721,7 @@ The following template field substitutions are availabe for use the templating s
|{lf}|A line feed: '\n', alias for {newline}|
|{cr}|A carriage return: '\r'|
|{crlf}|a carriage return + line feed: '\r\n'|
|{osxphotos_version}|The osxphotos version, e.g. '0.48.0'|
|{osxphotos_version}|The osxphotos version, e.g. '0.48.1'|
|{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

@@ -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: 35181f6d3f1c86b23a5a5b12b47bc6b1
config: bea67f756056dcbf51004e51b5dc2067
tags: 645f666f9bcd5a90fca523b33c5a78b7

View File

@@ -5,7 +5,7 @@
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../genindex.html" /><link rel="search" title="Search" href="../search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>Overview: module code - osxphotos 0.48.0 documentation</title>
<title>Overview: module code - osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css" />
@@ -123,7 +123,7 @@
</label>
</div>
<div class="header-center">
<a href="../index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="../index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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

@@ -318,7 +318,7 @@ Template Substitutions
* - {crlf}
- a carriage return + line feed: '\r\n'
* - {osxphotos_version}
- The osxphotos version, e.g. '0.48.0'
- The osxphotos version, e.g. '0.48.1'
* - {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.48.0',
VERSION: '0.48.1',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
BUILDER: 'html',

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Template System" href="template_help.html" /><link rel="prev" title="OSXPhotos Tutorial" href="tutorial.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Command Line Interface (CLI) - osxphotos 0.48.0 documentation</title>
<title>OSXPhotos Command Line Interface (CLI) - osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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">
@@ -2167,13 +2167,18 @@ See Timewarp Overview below for additional information.</p>
<dd><p>Pull date/time and timezone for selected photos from EXIF metadata in the original file into Photos and update the associated data in Photos to match the EXIF data. pull-exif will be executed before any other updates are performed on the photo. It is possible for images to have missing EXIF data, for example the date/time could be set but there might be no timezone set in the EXIF metadata. Missing data will be handled thusly: if date/time/timezone are all present in the EXIF data, the photos date/time/timezone will be updated. If timezone is missing but date/time is present, only the photos date/time will be updated. If date/time is missing but the timezone is present, only the photos timezone will be updated unless use-file-time is set in which case, the photos file modification date/time will be used in place of EXIF date/time. If the date is present but the time is missing, the time will be set to 00:00:00. Requires the third-party exiftool utility be installed (see <a class="reference external" href="https://exiftool.org/">https://exiftool.org/</a>). See also push-exif.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-timewarp-F">
<span id="cmdoption-osxphotos-timewarp-f"></span><span id="cmdoption-osxphotos-timewarp-function"></span><span class="sig-name descname"><span class="pre">-F</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">--function</span></span><span class="sig-prename descclassname"> <span class="pre">&lt;filename.py::function&gt;</span></span><a class="headerlink" href="#cmdoption-osxphotos-timewarp-F" title="Permalink to this definition">#</a></dt>
<dd><p>Run python function to determine the date/time/timezone to apply to a photo. Use this in format: function filename.py::function where filename.py is a python file youve created and function is the name of the function in the python file you want to call. The function will be passed information about the photo being processed and is expected to return a naive datetime.datetime object with time in local time and UTC timezone offset in seconds. See example function at https://github.com/RhetTbull/osxphotos/blob/master/examples/timewarp_function_example.py</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-timewarp-m">
<span id="cmdoption-osxphotos-timewarp-match-time"></span><span class="sig-name descname"><span class="pre">-m</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">--match-time</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-timewarp-m" title="Permalink to this definition">#</a></dt>
<dd><p>When used with timezone, adjusts the photo time so that the timestamp in the new timezone matches the timestamp in the old timezone. For example, if photo has time of 12:00 and timezone of GMT+01:00 and new timezone is specified as timezone +02:00 (one hour ahead of current GMT+01:00 timezone), the photos new time will be 12:00 GMT+02:00. That is, the timezone will have changed but the timestamp of the photo will match the previous timestamp. Use match-time when the cameras time was correct for the time the photo was taken but the timezone was missing or wrong and you want to adjust the timezone while preserving the photos time. See also timezone.</p>
</dd></dl>
<dl class="std option">
<dt class="sig sig-object std" id="cmdoption-osxphotos-timewarp-f">
<span id="cmdoption-osxphotos-timewarp-use-file-time"></span><span class="sig-name descname"><span class="pre">-f</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">--use-file-time</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-timewarp-f" title="Permalink to this definition">#</a></dt>
<dt class="sig sig-object std" id="cmdoption-osxphotos-timewarp-0">
<span id="cmdoption-osxphotos-timewarp-use-file-time"></span><span class="sig-name descname"><span class="pre">-f</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">--use-file-time</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-timewarp-0" title="Permalink to this definition">#</a></dt>
<dd><p>When used with pull-exif, the file modification date/time will be used if date/time is missing from the EXIF data.</p>
</dd></dl>
<dl class="std option">

View File

@@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Index - osxphotos 0.48.0 documentation</title>
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Index - osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -122,7 +122,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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">
@@ -637,6 +637,13 @@
<li><a href="cli.html#cmdoption-osxphotos-query-from-time">osxphotos-query command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-from-time">osxphotos-repl command line option</a>
</li>
</ul></li>
<li>
--function
<ul>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-F">osxphotos-timewarp command line option</a>
</li>
</ul></li>
<li>
@@ -1652,7 +1659,7 @@
--use-file-time
<ul>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-f">osxphotos-timewarp command line option</a>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-0">osxphotos-timewarp command line option</a>
</li>
</ul></li>
<li>
@@ -1778,13 +1785,20 @@
<ul>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-e">osxphotos-timewarp command line option</a>
</li>
</ul></li>
<li>
-F
<ul>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-F">osxphotos-timewarp command line option</a>
</li>
</ul></li>
<li>
-f
<ul>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-f">osxphotos-timewarp command line option</a>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-0">osxphotos-timewarp command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-uuid-f">osxphotos-uuid command line option</a>
</li>
@@ -3361,6 +3375,8 @@
<li><a href="cli.html#cmdoption-osxphotos-timewarp-D">--date-delta</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-e">--exiftool-path</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-F">--function</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-i">--inspect</a>
</li>
@@ -3386,7 +3402,7 @@
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-z">--timezone</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-f">--use-file-time</a>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-0">--use-file-time</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-V">--verbose</a>
</li>
@@ -3400,7 +3416,9 @@
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-e">-e</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-f">-f</a>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-F">-F</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-0">-f</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-timewarp-i">-i</a>
</li>

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos" href="overview.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>osxphotos 0.48.0 documentation</title>
<title>osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="#"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="#"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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">

Binary file not shown.

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="OSXPhotos Python Package Overview" href="package_overview.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos python API - osxphotos 0.48.0 documentation</title>
<title>OSXPhotos python API - osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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="#" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Search - osxphotos 0.48.0 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/><title>Search - osxphotos 0.48.1 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
@@ -121,7 +121,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 documentation</span>
</a><form class="sidebar-search-container" method="get" action="#" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Python Package Overview" href="package_overview.html" /><link rel="prev" title="OSXPhotos Command Line Interface (CLI)" href="cli.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Template System - osxphotos 0.48.0 documentation</title>
<title>OSXPhotos Template System - osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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">
@@ -564,7 +564,7 @@
<td><p>a carriage return + line feed: rn</p></td>
</tr>
<tr class="row-even"><td><p>{osxphotos_version}</p></td>
<td><p>The osxphotos version, e.g. 0.48.0</p></td>
<td><p>The osxphotos version, e.g. 0.48.1</p></td>
</tr>
<tr class="row-odd"><td><p>{osxphotos_cmd_line}</p></td>
<td><p>The full command line used to run osxphotos</p></td>

View File

@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="OSXPhotos Command Line Interface (CLI)" href="cli.html" /><link rel="prev" title="OSXPhotos" href="overview.html" />
<meta name="generator" content="sphinx-4.4.0, furo 2022.04.07"/>
<title>OSXPhotos Tutorial - osxphotos 0.48.0 documentation</title>
<title>OSXPhotos Tutorial - osxphotos 0.48.1 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=68f4518137b9aefe99b631505a2064c3c42c9852" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -124,7 +124,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">osxphotos 0.48.0 documentation</div></a>
<a href="index.html"><div class="brand">osxphotos 0.48.1 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.48.0 documentation</span>
<span class="sidebar-brand-text">osxphotos 0.48.1 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

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

View File

@@ -0,0 +1,46 @@
"""Example function for use with `osxphotos timewarp --function`
Call this as: `osxphotos timewarp --function timewarp_function_example.py::get_date_time_timezone`
"""
from datetime import datetime, timedelta
from typing import Callable, Optional, Tuple
from photoscript import Photo
def get_date_time_timezone(
photo: Photo, path: Optional[str], tz_sec: int, tz_name: str, verbose: Callable
) -> Tuple[datetime, int]:
"""Example function for use with `osxphotos timewarp --function`
Args:
photo: Photo object
path: path to photo, which may be None if photo is not on disk
tz_sec: timezone offset from UTC in seconds
tz_name: timezone name
verbose: function to print verbose messages
Returns:
tuple of (new date/time as datetime.datetime, and new timezone offset from UTC in seconds as int)
"""
# this example adds 3 hours to the date/time and subtracts 1 hour from the timezone
# the photo's date/time can be accessed as photo.date
# photo.date is a datetime.datetime object
# the date/time is naive (timezone unaware) as will be in local timezone
date = photo.date
# add 3 hours
date = date + timedelta(hours=3)
# subtract 1 hour from timezone
timezone = tz_sec - 3600
# verbose(msg) prints a message to the console if user used --verbose option
# otherwise it does nothing
# photo's filename can be access as photo.filename
verbose(f"Updating {photo.filename} date/time: {date} and timezone: {timezone}")
return date, timezone

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.48.0"
__version__ = "0.48.1"

View File

@@ -5,7 +5,7 @@ import os
import sys
from functools import partial
from textwrap import dedent
from typing import Callable
from typing import Callable, Optional
import click
from photoscript import Photo, PhotosLibrary
@@ -20,7 +20,7 @@ from osxphotos.photosalbum import PhotosAlbumPhotoScript
from osxphotos.phototz import PhotoTimeZone, PhotoTimeZoneUpdater
from osxphotos.timeutils import update_datetime
from osxphotos.timezones import Timezone
from osxphotos.utils import pluralize
from osxphotos.utils import noop, pluralize
from .click_rich_echo import (
rich_click_echo,
@@ -34,7 +34,15 @@ from .color_themes import get_theme
from .common import THEME_OPTION
from .darkmode import is_dark_mode
from .help import HELP_WIDTH, rich_text
from .param_types import DateOffset, DateTimeISO8601, TimeOffset, TimeString, UTCOffset
from .param_types import (
DateOffset,
DateTimeISO8601,
FunctionCall,
TimeOffset,
TimeString,
UTCOffset,
)
from .rich_progress import rich_progress
from .verbose import get_verbose_console, verbose_print
# format for pretty printing date/times
@@ -103,6 +111,48 @@ def update_photo_time_for_new_timezone(
)
def update_photo_from_function(
library_path: str,
function: Callable,
verbose_print: Callable,
photo: Photo,
path: Optional[str],
):
"""Update photo from function call"""
photo_tz_sec, _, photo_tz_name = PhotoTimeZone(
library_path=library_path
).get_timezone(photo)
dt_new, tz_new = function(
photo=photo,
path=path,
tz_sec=photo_tz_sec,
tz_name=photo_tz_name,
verbose=verbose_print,
)
if dt_new != photo.date:
old_date = photo.date
photo.date = dt_new
verbose_print(
f"Updated date/time for photo [filename]{photo.filename}[/filename] "
f"([uuid]{photo.uuid}[/uuid]) from: [time]{old_date}[/time] to [time]{dt_new}[/time]"
)
else:
verbose_print(
f"Skipped date/time update for photo [filename]{photo.filename}[/filename] "
f"([uuid]{photo.uuid}[/uuid]): nothing to do"
)
if tz_new != photo_tz_sec:
tz_updater = PhotoTimeZoneUpdater(
timezone=Timezone(tz_new), verbose=verbose_print, library_path=library_path
)
tz_updater.update_photo(photo)
else:
verbose_print(
f"Skipped timezone update for photo [filename]{photo.filename}[/filename] "
f"([uuid]{photo.uuid}[/uuid]): nothing to do"
)
class TimeWarpCommand(click.Command):
"""Custom click.Command that overrides get_help() to show additional help info for export"""
@@ -267,9 +317,20 @@ For this to work, you'll need to install the third-party exiftool (https://exift
"Requires the third-party exiftool utility be installed (see https://exiftool.org/). "
"See also --push-exif.",
)
# constraint=RequireAtLeast(1),
# @constraint(mutually_exclusive, ["date", "date_delta"])
# @constraint(mutually_exclusive, ["time", "time_delta"])
@click.option(
"--function",
"-F",
metavar="filename.py::function",
nargs=1,
type=FunctionCall(),
multiple=False,
help="Run python function to determine the date/time/timezone to apply to a photo. "
"Use this in format: --function filename.py::function where filename.py is a python "
"file you've created and function is the name of the function in the python file you want to call. The function will be "
"passed information about the photo being processed and is expected to return "
"a naive datetime.datetime object with time in local time and UTC timezone offset in seconds. "
"See example function at https://github.com/RhetTbull/osxphotos/blob/master/examples/timewarp_function_example.py",
)
@click.option(
"--match-time",
"-m",
@@ -326,9 +387,6 @@ For this to work, you'll need to install the third-party exiftool (https://exift
help="Terminal width in characters.",
hidden=True,
)
# @constraint(mutually_exclusive, ["plain", "mono", "dark", "light"])
# @constraint(If("match_time", then=requires_one), ["timezone"])
# @constraint(If("add_to_album", then=requires_one), ["compare_exif"])
@click.option("--timestamp", is_flag=True, help="Add time stamp to verbose output")
@THEME_OPTION
@click.option(
@@ -346,6 +404,7 @@ def timewarp(
compare_exif,
push_exif,
pull_exif,
function,
match_time,
use_file_time,
add_to_album,
@@ -362,10 +421,43 @@ def timewarp(
Changes will be applied to all photos currently selected in Photos.
timewarp cannot operate on photos selected in a Smart Album;
select photos in a regular album or in the 'All Photos' view.
select photos in a regular album or in the 'All Photos' view.
See Timewarp Overview below for additional information.
"""
# check constraints
if not any(
[
date,
date_delta,
time,
time_delta,
timezone,
inspect,
compare_exif,
push_exif,
pull_exif,
function,
]
):
raise click.UsageError(
"At least one of --date, --date-delta, --time, --time-delta, "
"--timezone, --inspect, --compare-exif, --push-exif, --pull-exif, --function "
"must be specified."
)
if date and date_delta:
raise click.UsageError("--date and --date-delta are mutually exclusive.")
if time and time_delta:
raise click.UsageError("--time and --time-delta are mutually exclusive.")
if match_time and not timezone:
raise click.UsageError("--match-time must be used with --timezone.")
if add_to_album and not compare_exif:
raise click.UsageError("--add-to-album must be used with --compare-exif.")
color_theme = get_theme(theme)
verbose_ = verbose_print(
verbose,
@@ -376,15 +468,21 @@ def timewarp(
file=output_file,
)
# set console for rich_echo to be same as for verbose_
# TODO: this is a hack, find a better way to do this
terminal_width = terminal_width or (1000 if output_file else None)
if output_file:
set_rich_console(Console(file=output_file, width=terminal_width))
elif terminal_width:
set_rich_console(
Console(file=sys.stdout, force_terminal=True, width=terminal_width)
Console(
file=sys.stdout,
theme=color_theme,
force_terminal=True,
width=terminal_width,
)
)
else:
set_rich_console(get_verbose_console())
set_rich_console(get_verbose_console(theme=color_theme))
set_rich_theme(color_theme)
if any([compare_exif, push_exif, pull_exif]):
@@ -426,6 +524,16 @@ def timewarp(
verbose_print=verbose_,
)
if function:
update_photo_from_function_ = partial(
update_photo_from_function,
library_path=library,
function=function[0],
verbose_print=verbose_,
)
else:
update_photo_from_function_ = noop
if inspect:
tzinfo = PhotoTimeZone(library_path=library)
if photos:
@@ -456,10 +564,11 @@ def timewarp(
)
for photo in photos:
diff_results = (
photocomp.compare_exif_with_markup(photo)
if not plain
else photocomp.compare_exif_no_markup(photo)
photocomp.compare_exif_no_markup(photo)
if plain
else photocomp.compare_exif_with_markup(photo)
)
if not plain:
filename = (
f"[change]{photo.filename}[/change]"
@@ -497,7 +606,8 @@ def timewarp(
timezone, verbose=verbose_, library_path=library
)
if any([push_exif, pull_exif]):
if any([push_exif, pull_exif, function]):
# ExifDateTimeUpdater used to get photo path for --function
exif_updater = ExifDateTimeUpdater(
library_path=library,
verbose=verbose_,
@@ -505,11 +615,13 @@ def timewarp(
plain=plain,
)
rich_echo(f"Processing {len(photos)} {pluralize(len(photos), 'photo', 'photos')}")
# send progress bar output to /dev/null if verbose to hide the progress bar
fp = open(os.devnull, "w") if verbose else None
with click.progressbar(photos, file=fp) as bar:
for p in bar:
num_photos = len(photos)
with rich_progress(console=get_verbose_console(), mock=verbose) as progress:
task = progress.add_task(
f"Processing [num]{num_photos}[/] {pluralize(len(photos), 'photo', 'photos')}",
total=num_photos,
)
for p in photos:
if pull_exif:
exif_updater.update_photos_from_exif(
p, use_file_modify_date=use_file_time
@@ -522,6 +634,10 @@ def timewarp(
update_photo_time_for_new_timezone_(photo=p, new_timezone=timezone)
if timezone:
tz_updater.update_photo(p)
if function:
verbose_(f"Calling function [bold]{function[1]}")
photo_path = exif_updater.get_photo_path(p)
update_photo_from_function_(photo=p, path=photo_path)
if push_exif:
# this should be the last step in the if chain to ensure all Photos data is updated
# before exiftool is run
@@ -533,8 +649,7 @@ def timewarp(
if exif_error:
rich_echo_error(f"[error]Error running exiftool: {exif_error}[/]")
if fp is not None:
fp.close()
progress.advance(task)
rich_echo("Done.")

View File

@@ -43,15 +43,18 @@ def noop(*args, **kwargs):
pass
def get_verbose_console() -> Console:
"""Get console object
def get_verbose_console(theme: t.Optional[Theme] = None) -> Console:
"""Get console object or create one if not already created
Args:
theme: optional rich.theme.Theme object to use for formatting
Returns:
Console object
"""
global _console
if _console.console is None:
_console.console = Console(force_terminal=True)
_console.console = Console(force_terminal=True, theme=theme)
return _console.console

Binary file not shown.

View File

@@ -247,6 +247,18 @@ class ExifDateTimeUpdater:
exif, use_file_modify_date=use_file_modify_date
)
def get_photo_path(self, photo: Photo) -> Optional[str]:
"""Get the path to a photo
Args:
photo: photoscript.Photo object to act on
Returns:
str: path to photo or None if not found
"""
_photo = self.db.get_photo(photo.uuid)
return _photo.path if _photo else None
def get_exif_date_time_offset(
exif: Dict, use_file_modify_date: bool = False

View File

@@ -149,7 +149,7 @@ class PhotoTimeZoneUpdater:
conn.commit()
self.verbose(
f"Updated timezone for photo [filename]{photo.filename}[/filename] ([uuid]{photo.uuid}[/uuid]) "
+ f"from [tz]{[tz_name]}[/tz], offset=[tz]{tz_offset}[/tz] "
+ f"from [tz]{tz_name}[/tz], offset=[tz]{tz_offset}[/tz] "
+ f"to [tz]{self.tz_name}[/tz], offset=[tz]{self.tz_offset}[/tz]"
)
except Exception as e:

View File

@@ -1,11 +1,20 @@
""" Test data for timewarp command on Catalina/Photos 5 """
import datetime
import pathlib
from tests.parse_timewarp_output import CompareValues, InspectValues
TEST_LIBRARY_TIMEWARP = "tests/TestTimeWarp-10.15.7.photoslibrary"
def get_file_timestamp(file: str) -> str:
"""Get timestamp of file"""
return datetime.datetime.fromtimestamp(pathlib.Path(file).stat().st_mtime).strftime(
"%Y-%m-%d %H:%M:%S"
)
CATALINA_PHOTOS_5 = {
"filenames": {
"pumpkins": "IMG_6522.jpeg",
@@ -258,7 +267,9 @@ CATALINA_PHOTOS_5 = {
"post": CompareValues(
"IMG_6506.jpeg",
"7E9DF2EE-A5B0-4077-80EC-30565221A3B9",
"2021-10-08 16:11:09",
get_file_timestamp(
f"{TEST_LIBRARY_TIMEWARP}/originals/7/7E9DF2EE-A5B0-4077-80EC-30565221A3B9.jpeg"
),
"",
"-0700",
"",
@@ -302,7 +313,7 @@ CATALINA_PHOTOS_5 = {
"parameters": [("-0200", "2021-10-04 23:00:00-0200")]
},
"video_push_exif": {
# IMG_6501.jpeg
# IMG_6551.mov
"pre": CompareValues(
"IMG_6551.mov",
"16BEC0BE-4188-44F1-A8F1-7250E978AD12",
@@ -321,7 +332,7 @@ CATALINA_PHOTOS_5 = {
),
},
"video_pull_exif": {
# IMG_6501.jpeg
# IMG_6551.jpeg
"pre": CompareValues(
"IMG_6551.mov",
"16BEC0BE-4188-44F1-A8F1-7250E978AD12",
@@ -339,4 +350,16 @@ CATALINA_PHOTOS_5 = {
"-0200",
),
},
"function": {
# IMG_6501.jpeg
"uuid": "2F00448D-3C0D-477A-9B10-5F21DCAB405A",
"expected": InspectValues(
"IMG_6501.jpeg",
"2F00448D-3C0D-477A-9B10-5F21DCAB405A",
"2020-09-01 18:53:02-0700",
"2020-09-01 18:53:02-0700",
"-0700",
"GMT-0700",
),
},
}

View File

@@ -46,7 +46,7 @@ def ask_user_to_make_selection(
video: set to True if asking for a video instead of a photo
"""
# needs to be called with a suspend_capture fixture
photo_or_video = "photo" if not video else "video"
photo_or_video = "video" if video else "photo"
tries = 0
while tries < retry:
with suspend_capture:
@@ -935,3 +935,35 @@ def test_video_pull_exif(photoslib, suspend_capture, output_file):
)
output_values = parse_compare_exif(output_file)
assert output_values[0] == post_test
@pytest.mark.timewarp
def test_select_pears_3(photoslib, suspend_capture):
"""Force user to select the right photo for following tests"""
assert ask_user_to_make_selection(photoslib, suspend_capture, "pears")
@pytest.mark.timewarp
def test_function(photoslib, suspend_capture, output_file):
"""Test timewarp function"""
from osxphotos.cli.timewarp import timewarp
expected = TEST_DATA["function"]["expected"]
runner = CliRunner()
result = runner.invoke(
timewarp,
[
"--function",
"tests/timewarp_function_example.py::get_date_time_timezone",
],
terminal_width=TERMINAL_WIDTH,
)
assert result.exit_code == 0
result = runner.invoke(
timewarp,
["--inspect", "--plain", "-o", output_file],
terminal_width=TERMINAL_WIDTH,
)
output_values = parse_inspect_output(output_file)
assert output_values[0] == expected

View File

@@ -0,0 +1,46 @@
"""Example function for use with `osxphotos timewarp --function`
Call this as: `osxphotos timewarp --function timewarp_function_example.py::get_date_time_timezone`
"""
from datetime import datetime, timedelta
from typing import Callable, Optional, Tuple
from photoscript import Photo
def get_date_time_timezone(
photo: Photo, path: Optional[str], tz_sec: int, tz_name: str, verbose: Callable
) -> Tuple[datetime, int]:
"""Example function for use with `osxphotos timewarp --function`
Args:
photo: Photo object
path: path to photo, which may be None if photo is not on disk
tz_sec: timezone offset from UTC in seconds
tz_name: timezone name
verbose: function to print verbose messages
Returns:
tuple of (new date/time as datetime.datetime, and new timezone offset from UTC in seconds as int)
"""
# this example adds 3 hours to the date/time and subtracts 1 hour from the timezone
# the photo's date/time can be accessed as photo.date
# photo.date is a datetime.datetime object
# the date/time is naive (timezone unaware) as will be in local timezone
date = photo.date
# add 3 hours
date = date + timedelta(hours=3)
# subtract 1 hour from timezone
timezone = tz_sec - 3600
# verbose(msg) prints a message to the console if user used --verbose option
# otherwise it does nothing
# photo's filename can be access as photo.filename
verbose(f"Updating {photo.filename} date/time: {date} and timezone: {timezone}")
return date, timezone