Exposed --use-photos-export and --use-photokit

This commit is contained in:
Rhet Turnbull
2020-11-25 09:15:16 -08:00
parent f7bd1376e1
commit e951e5361e
4 changed files with 82 additions and 38 deletions

View File

@@ -356,6 +356,16 @@ Options:
to a filesystem that doesn't support Mac OS
extended attributes. Only use this if you
get an error while exporting.
--use-photos-export Force the use of AppleScript or PhotoKit to
export even if not missing (see also '--
download-missing' and '--use-photokit').
--use-photokit Use with '--download-missing' or '--use-
photos-export' to use direct Photos
interface instead of AppleScript to export.
Highly experimental alpha feature; does not
work with iTerm2 (use with Terminal.app).
This is faster and more reliable than the
default AppleScript interface.
-h, --help Show this message and exit.
** Export **

View File

@@ -28,6 +28,7 @@ from .export_db import ExportDB, ExportDBInMemory
from .fileutil import FileUtil, FileUtilNoOp
from .path_utils import is_valid_filepath, sanitize_filename, sanitize_filepath
from .photoinfo import ExportResults
from .photokit import check_photokit_authorization, request_photokit_authorization
from .phototemplate import TEMPLATE_SUBSTITUTIONS, TEMPLATE_SUBSTITUTIONS_MULTI_VALUED
# global variable to control verbose output
@@ -1394,15 +1395,15 @@ def query(
"--use-photos-export",
is_flag=True,
default=False,
hidden=True,
help="Force the use of AppleScript to export even if not missing (see also --download-missing).",
help="Force the use of AppleScript or PhotoKit to export even if not missing (see also '--download-missing' and '--use-photokit').",
)
@click.option(
"--use-photokit",
is_flag=True,
default=False,
hidden=True,
help="Use PhotoKit interface instead of AppleScript to export. Highly experimental alpha feature.",
help="Use with '--download-missing' or '--use-photos-export' to use direct Photos interface instead of AppleScript to export. "
"Highly experimental alpha feature; does not work with iTerm2 (use with Terminal.app). "
"This is faster and more reliable than the default AppleScript interface.",
)
@DB_ARGUMENT
@click.argument("dest", nargs=1, type=click.Path(exists=True))
@@ -1545,6 +1546,18 @@ def export(
click.echo(cli.commands["export"].get_help(ctx), err=True)
return
if use_photokit and not check_photokit_authorization():
click.echo(
"Requesting access to use your Photos library. Click 'OK' on the dialog box to grant access."
)
request_photokit_authorization()
click.confirm("Have you granted access?")
if not check_photokit_authorization():
click.echo(
"Failed to get access to the Photos library which is needed with `--use-photokit`."
)
return
# initialize export flags
# by default, will export all versions of photos unless skip flag is set
(export_edited, export_bursts, export_live, export_raw) = [

View File

@@ -1,4 +1,4 @@
""" version info """
__version__ = "0.36.20"
__version__ = "0.36.21"

View File

@@ -80,6 +80,58 @@ def path_to_NSURL(path):
return url
def check_photokit_authorization():
""" Check authorization to use user's Photos Library
Returns:
True if user has authorized access to the Photos library, otherwise False
"""
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
return auth_status == Photos.PHAuthorizationStatusAuthorized
def request_photokit_authorization():
""" Request authorization to user's Photos Library
Returns:
authorization status
Note: In actual practice, the terminal process running the python code
will do the actual request.
"""
(_, major, _) = _get_os_version()
def handler(status):
pass
auth_status = 0
if int(major) < 16:
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status != Photos.PHAuthorizationStatusAuthorized:
# it seems the first try fails after Terminal prompts user for access so try again
for _ in range(2):
Photos.PHPhotoLibrary.requestAuthorization_(handler)
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status == Photos.PHAuthorizationStatusAuthorized:
break
else:
# requestAuthorization deprecated in 10.16/11.0
# but requestAuthorizationForAccessLevel not yet implemented in pyobjc (will be in ver 7.0)
# https://developer.apple.com/documentation/photokit/phphotolibrary/3616053-requestauthorizationforaccesslev?language=objc
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status != Photos.PHAuthorizationStatusAuthorized:
# it seems the first try fails after Terminal prompts user for access so try again
for _ in range(2):
Photos.PHPhotoLibrary.requestAuthorization_(handler)
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status == Photos.PHAuthorizationStatusAuthorized:
break
return auth_status
### exceptions
class PhotoKitError(Exception):
"""Base class for exceptions in this module. """
@@ -1051,12 +1103,6 @@ class PhotoLibrary:
# get image manager and request options
self._phimagemanager = Photos.PHCachingImageManager.defaultManager()
def _auth_status(self, status):
""" Handler for requestAuthorization_ """
# This doesn't actually get called but requestAuthorization needs a callable handler
# The Terminal will handle the actual authorization when called
pass
def request_authorization(self):
""" Request authorization to user's Photos Library
@@ -1064,33 +1110,8 @@ class PhotoLibrary:
authorization status
"""
(_, major, _) = _get_os_version()
auth_status = 0
if int(major) < 16:
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status != Photos.PHAuthorizationStatusAuthorized:
# it seems the first try fails after Terminal prompts user for access so try again
for _ in range(2):
Photos.PHPhotoLibrary.requestAuthorization_(self._auth_status)
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status == Photos.PHAuthorizationStatusAuthorized:
break
else:
# requestAuthorization deprecated in 10.16/11.0
# but requestAuthorizationForAccessLevel not yet implemented in pyobjc (will be in ver 7.0)
# https://developer.apple.com/documentation/photokit/phphotolibrary/3616053-requestauthorizationforaccesslev?language=objc
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status != Photos.PHAuthorizationStatusAuthorized:
# it seems the first try fails after Terminal prompts user for access so try again
for _ in range(2):
Photos.PHPhotoLibrary.requestAuthorization_(self._auth_status)
auth_status = Photos.PHPhotoLibrary.authorizationStatus()
if auth_status == Photos.PHAuthorizationStatusAuthorized:
break
self.auth_status = auth_status
return auth_status
self.auth_status = request_photokit_authorization()
return self.auth_status
def fetch_uuid_list(self, uuid_list):
""" fetch PHAssets with uuids in uuid_list