Initial support for Ventura developer preview (#715)
This commit is contained in:
@@ -44,10 +44,8 @@ _PHOTOS_5_VERSION = "5000" # I've seen both 5001 and 6000. 6000 is most common
|
||||
# Ranges for model version by Photos version
|
||||
_PHOTOS_5_MODEL_VERSION = [13000, 13999]
|
||||
_PHOTOS_6_MODEL_VERSION = [14000, 14999]
|
||||
_PHOTOS_7_MODEL_VERSION = [
|
||||
15000,
|
||||
15999,
|
||||
] # Monterey developer preview is 15134, 12.1 is 15331
|
||||
_PHOTOS_7_MODEL_VERSION = [15000, 15999] # Dev preview: 15134, 12.1: 15331
|
||||
_PHOTOS_8_MODEL_VERSION = [16000, 16999] # Ventura dev preview: 16119
|
||||
|
||||
# some table names differ between Photos 5 and Photos 6
|
||||
_DB_TABLE_NAMES = {
|
||||
@@ -87,6 +85,18 @@ _DB_TABLE_NAMES = {
|
||||
"ASSET_ALBUM_TABLE": "Z_27ASSETS",
|
||||
"HDR_TYPE": "ZHDRTYPE",
|
||||
},
|
||||
8: {
|
||||
"ASSET": "ZASSET",
|
||||
"KEYWORD_JOIN": "Z_1KEYWORDS.Z_40KEYWORDS",
|
||||
"ALBUM_JOIN": "Z_28ASSETS.Z_3ASSETS",
|
||||
"ALBUM_SORT_ORDER": "Z_28ASSETS.Z_FOK_3ASSETS",
|
||||
"IMPORT_FOK": "null",
|
||||
"DEPTH_STATE": "ZASSET.ZDEPTHTYPE",
|
||||
"UTI_ORIGINAL": "ZINTERNALRESOURCE.ZCOMPACTUTI",
|
||||
"ASSET_ALBUM_JOIN": "Z_28ASSETS.Z_28ALBUMS",
|
||||
"ASSET_ALBUM_TABLE": "Z_28ASSETS",
|
||||
"HDR_TYPE": "ZHDRTYPE",
|
||||
},
|
||||
}
|
||||
|
||||
# which version operating systems have been tested
|
||||
@@ -107,6 +117,7 @@ _TESTED_OS_VERSIONS = [
|
||||
("12", "1"),
|
||||
("12", "2"),
|
||||
("12", "3"),
|
||||
("12", "4"),
|
||||
]
|
||||
|
||||
# Photos 5 has persons who are empty string if unidentified face
|
||||
|
||||
Binary file not shown.
@@ -92,11 +92,13 @@ class PersonInfo:
|
||||
return f"PersonInfo(name={self.name}, display_name={self.display_name}, uuid={self.uuid}, facecount={self.facecount})"
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, type(self)):
|
||||
return False
|
||||
|
||||
return all(
|
||||
getattr(self, field) == getattr(other, field) for field in ["_db", "_pk"]
|
||||
return (
|
||||
all(
|
||||
getattr(self, field) == getattr(other, field)
|
||||
for field in ["_db", "_pk"]
|
||||
)
|
||||
if isinstance(other, type(self))
|
||||
else False
|
||||
)
|
||||
|
||||
def __ne__(self, other):
|
||||
@@ -127,23 +129,14 @@ class FaceInfo:
|
||||
self._person_pk = face["person"]
|
||||
self.center_x = face["centerx"]
|
||||
self.center_y = face["centery"]
|
||||
self.mouth_x = face["mouthx"]
|
||||
self.mouth_y = face["mouthy"]
|
||||
self.left_eye_x = face["lefteyex"]
|
||||
self.left_eye_y = face["lefteyey"]
|
||||
self.right_eye_x = face["righteyex"]
|
||||
self.right_eye_y = face["righteyey"]
|
||||
self.size = face["size"]
|
||||
self.quality = face["quality"]
|
||||
self.source_width = face["sourcewidth"]
|
||||
self.source_height = face["sourceheight"]
|
||||
self.has_smile = face["has_smile"]
|
||||
self.left_eye_closed = face["left_eye_closed"]
|
||||
self.right_eye_closed = face["right_eye_closed"]
|
||||
self.manual = face["manual"]
|
||||
self.face_type = face["facetype"]
|
||||
self.age_type = face["agetype"]
|
||||
# self.bald_type = face["baldtype"]
|
||||
self.eye_makeup_type = face["eyemakeuptype"]
|
||||
self.eye_state = face["eyestate"]
|
||||
self.facial_hair_type = face["facialhairtype"]
|
||||
@@ -174,33 +167,6 @@ class FaceInfo:
|
||||
size_reference = photo.width if photo.width > photo.height else photo.height
|
||||
return self.size * size_reference
|
||||
|
||||
@property
|
||||
def mouth(self):
|
||||
"""Coordinates, in PIL format, for mouth position
|
||||
|
||||
Returns:
|
||||
tuple of coordinates in form (x, y)
|
||||
"""
|
||||
return self._make_point_with_rotation((self.mouth_x, self.mouth_y))
|
||||
|
||||
@property
|
||||
def left_eye(self):
|
||||
"""Coordinates, in PIL format, for left eye position
|
||||
|
||||
Returns:
|
||||
tuple of coordinates in form (x, y)
|
||||
"""
|
||||
return self._make_point_with_rotation((self.left_eye_x, self.left_eye_y))
|
||||
|
||||
@property
|
||||
def right_eye(self):
|
||||
"""Coordinates, in PIL format, for right eye position
|
||||
|
||||
Returns:
|
||||
tuple of coordinates in form (x, y)
|
||||
"""
|
||||
return self._make_point_with_rotation((self.right_eye_x, self.right_eye_y))
|
||||
|
||||
@property
|
||||
def person_info(self):
|
||||
"""PersonInfo instance for person associated with this face"""
|
||||
@@ -415,15 +381,6 @@ class FaceInfo:
|
||||
"center_x": self.center_x,
|
||||
"center_y": self.center_y,
|
||||
"center": self.center,
|
||||
"mouth_x": self.mouth_x,
|
||||
"mouth_y": self.mouth_y,
|
||||
"mouth": self.mouth,
|
||||
"left_eye_x": self.left_eye_x,
|
||||
"left_eye_y": self.left_eye_y,
|
||||
"left_eye": self.left_eye,
|
||||
"right_eye_x": self.right_eye_x,
|
||||
"right_eye_y": self.right_eye_y,
|
||||
"right_eye": self.right_eye,
|
||||
"size": self.size,
|
||||
"face_rect": self.face_rect(),
|
||||
"mpri_reg_rect": self.mpri_reg_rect._asdict(),
|
||||
@@ -435,12 +392,9 @@ class FaceInfo:
|
||||
"source_width": self.source_width,
|
||||
"source_height": self.source_height,
|
||||
"has_smile": self.has_smile,
|
||||
"left_eye_closed": self.left_eye_closed,
|
||||
"right_eye_closed": self.right_eye_closed,
|
||||
"manual": self.manual,
|
||||
"face_type": self.face_type,
|
||||
"age_type": self.age_type,
|
||||
# "bald_type": self.bald_type,
|
||||
"eye_makeup_type": self.eye_makeup_type,
|
||||
"eye_state": self.eye_state,
|
||||
"facial_hair_type": self.facial_hair_type,
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
""" Methods for PhotosDB to add Photos face info
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
|
||||
from ..utils import _open_sql_file, normalize_unicode
|
||||
from .photosdb_utils import get_db_version
|
||||
|
||||
|
||||
"""
|
||||
This module should be imported in the class defintion of PhotosDB in photosdb.py
|
||||
Do not import this module directly
|
||||
@@ -202,8 +200,8 @@ def _process_faceinfo_5(photosdb):
|
||||
ZDETECTEDFACE.ZHASSMILE,
|
||||
ZDETECTEDFACE.ZHIDDEN,
|
||||
ZDETECTEDFACE.ZISINTRASH,
|
||||
ZDETECTEDFACE.ZISLEFTEYECLOSED,
|
||||
ZDETECTEDFACE.ZISRIGHTEYECLOSED,
|
||||
NULL, -- ZDETECTEDFACE.ZISLEFTEYECLOSED
|
||||
NULL, -- ZDETECTEDFACE.ZISRIGHTEYECLOSED
|
||||
ZDETECTEDFACE.ZLIPMAKEUPTYPE,
|
||||
ZDETECTEDFACE.ZMANUAL,
|
||||
ZDETECTEDFACE.ZQUALITYMEASURE,
|
||||
@@ -213,17 +211,17 @@ def _process_faceinfo_5(photosdb):
|
||||
ZDETECTEDFACE.ZBLURSCORE,
|
||||
ZDETECTEDFACE.ZCENTERX,
|
||||
ZDETECTEDFACE.ZCENTERY,
|
||||
ZDETECTEDFACE.ZLEFTEYEX,
|
||||
ZDETECTEDFACE.ZLEFTEYEY,
|
||||
ZDETECTEDFACE.ZMOUTHX,
|
||||
ZDETECTEDFACE.ZMOUTHY,
|
||||
NULL, -- ZDETECTEDFACE.ZLEFTEYEX,
|
||||
NULL, -- ZDETECTEDFACE.ZLEFTEYEY,
|
||||
NULL, -- ZDETECTEDFACE.ZMOUTHX,
|
||||
NULL, -- ZDETECTEDFACE.ZMOUTHY,
|
||||
ZDETECTEDFACE.ZPOSEYAW,
|
||||
ZDETECTEDFACE.ZQUALITY,
|
||||
ZDETECTEDFACE.ZRIGHTEYEX,
|
||||
ZDETECTEDFACE.ZRIGHTEYEY,
|
||||
NULL, -- ZDETECTEDFACE.ZRIGHTEYEX,
|
||||
NULL, -- ZDETECTEDFACE.ZRIGHTEYEY,
|
||||
ZDETECTEDFACE.ZROLL,
|
||||
ZDETECTEDFACE.ZSIZE,
|
||||
ZDETECTEDFACE.ZYAW,
|
||||
NULL, -- ZDETECTEDFACE.ZYAW,
|
||||
ZDETECTEDFACE.ZMASTERIDENTIFIER
|
||||
FROM ZDETECTEDFACE
|
||||
JOIN {asset_table} ON {asset_table}.Z_PK = ZDETECTEDFACE.ZASSET
|
||||
@@ -237,7 +235,7 @@ def _process_faceinfo_5(photosdb):
|
||||
# 3 ZDETECTEDFACE.ZPERSON,
|
||||
# 4 ZPERSON.ZFULLNAME,
|
||||
# 5 ZDETECTEDFACE.ZAGETYPE,
|
||||
# 6 ZDETECTEDFACE.ZBALDTYPE, (Not available on Monterey)
|
||||
# 6 NULL -- ZDETECTEDFACE.ZBALDTYPE, (Not available on Monterey)
|
||||
# 7 ZDETECTEDFACE.ZEYEMAKEUPTYPE,
|
||||
# 8 ZDETECTEDFACE.ZEYESSTATE,
|
||||
# 9 ZDETECTEDFACE.ZFACIALHAIRTYPE,
|
||||
@@ -247,8 +245,8 @@ def _process_faceinfo_5(photosdb):
|
||||
# 13 ZDETECTEDFACE.ZHASSMILE,
|
||||
# 14 ZDETECTEDFACE.ZHIDDEN,
|
||||
# 15 ZDETECTEDFACE.ZISINTRASH,
|
||||
# 16 ZDETECTEDFACE.ZISLEFTEYECLOSED,
|
||||
# 17 ZDETECTEDFACE.ZISRIGHTEYECLOSED,
|
||||
# 16 NULL -- ZDETECTEDFACE.ZISLEFTEYECLOSED,
|
||||
# 17 NULL -- ZDETECTEDFACE.ZISRIGHTEYECLOSED,
|
||||
# 18 ZDETECTEDFACE.ZLIPMAKEUPTYPE,
|
||||
# 19 ZDETECTEDFACE.ZMANUAL,
|
||||
# 20 ZDETECTEDFACE.ZQUALITYMEASURE,
|
||||
@@ -258,17 +256,17 @@ def _process_faceinfo_5(photosdb):
|
||||
# 24 ZDETECTEDFACE.ZBLURSCORE,
|
||||
# 25 ZDETECTEDFACE.ZCENTERX,
|
||||
# 26 ZDETECTEDFACE.ZCENTERY,
|
||||
# 27 ZDETECTEDFACE.ZLEFTEYEX,
|
||||
# 28 ZDETECTEDFACE.ZLEFTEYEY,
|
||||
# 29 ZDETECTEDFACE.ZMOUTHX,
|
||||
# 30 ZDETECTEDFACE.ZMOUTHY,
|
||||
# 27 NULL -- ZDETECTEDFACE.ZLEFTEYEX, (Not available on Ventura)
|
||||
# 28 NULL -- ZDETECTEDFACE.ZLEFTEYEY, (Not available on Ventura)
|
||||
# 29 NULL -- ZDETECTEDFACE.ZMOUTHX, (Not available on Ventura)
|
||||
# 30 NULL -- ZDETECTEDFACE.ZMOUTHY, (Not available on Ventura)
|
||||
# 31 ZDETECTEDFACE.ZPOSEYAW,
|
||||
# 32 ZDETECTEDFACE.ZQUALITY,
|
||||
# 33 ZDETECTEDFACE.ZRIGHTEYEX,
|
||||
# 34 ZDETECTEDFACE.ZRIGHTEYEY,
|
||||
# 33 NULL -- ZDETECTEDFACE.ZRIGHTEYEX, (Not available on Ventura)
|
||||
# 34 NULL -- ZDETECTEDFACE.ZRIGHTEYEY, (Not available on Ventura)
|
||||
# 35 ZDETECTEDFACE.ZROLL,
|
||||
# 36 ZDETECTEDFACE.ZSIZE,
|
||||
# 37 ZDETECTEDFACE.ZYAW,
|
||||
# 37 NULL -- ZDETECTEDFACE.ZYAW, (Not available on Ventura)
|
||||
# 38 ZDETECTEDFACE.ZMASTERIDENTIFIER
|
||||
|
||||
for row in result:
|
||||
@@ -310,8 +308,8 @@ def _process_faceinfo_5(photosdb):
|
||||
face["righteyey"] = row[34]
|
||||
face["roll"] = row[35]
|
||||
face["size"] = row[36]
|
||||
face["yaw"] = row[37]
|
||||
face["pitch"] = 0.0 # not defined in Photos 5
|
||||
face["yaw"] = 0 # Photos 4 only (this is in Photos 5-7, but dropped in Ventura so just don't support it)
|
||||
face["pitch"] = 0 # not defined in Photos 5
|
||||
|
||||
photosdb._db_faceinfo_pk[pk] = face
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import tempfile
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Iterable
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
from unicodedata import normalize
|
||||
|
||||
import bitmath
|
||||
@@ -2858,16 +2858,16 @@ class PhotosDB:
|
||||
|
||||
def photos(
|
||||
self,
|
||||
keywords=None,
|
||||
uuid=None,
|
||||
persons=None,
|
||||
albums=None,
|
||||
images=True,
|
||||
movies=True,
|
||||
from_date=None,
|
||||
to_date=None,
|
||||
intrash=False,
|
||||
):
|
||||
keywords: Optional[List[str]] = None,
|
||||
uuid: Optional[List[str]] = None,
|
||||
persons: Optional[List[str]] = None,
|
||||
albums: Optional[List[str]] = None,
|
||||
images: bool = True,
|
||||
movies: bool = True,
|
||||
from_date: Optional[datetime] = None,
|
||||
to_date: Optional[datetime] = None,
|
||||
intrash: bool = False,
|
||||
) -> List[PhotoInfo]:
|
||||
"""Return a list of PhotoInfo objects
|
||||
If called with no args, returns the entire database of photos
|
||||
If called with args, returns photos matching the args (e.g. keywords, persons, etc.)
|
||||
|
||||
@@ -12,6 +12,7 @@ from .._constants import (
|
||||
_PHOTOS_5_VERSION,
|
||||
_PHOTOS_6_MODEL_VERSION,
|
||||
_PHOTOS_7_MODEL_VERSION,
|
||||
_PHOTOS_8_MODEL_VERSION,
|
||||
_TESTED_DB_VERSIONS,
|
||||
)
|
||||
from ..utils import _open_sql_file
|
||||
@@ -92,10 +93,12 @@ def get_db_model_version(db_file):
|
||||
return 6
|
||||
elif _PHOTOS_7_MODEL_VERSION[0] <= model_ver <= _PHOTOS_7_MODEL_VERSION[1]:
|
||||
return 7
|
||||
elif _PHOTOS_8_MODEL_VERSION[0] <= model_ver <= _PHOTOS_8_MODEL_VERSION[1]:
|
||||
return 8
|
||||
else:
|
||||
logging.warning(f"Unknown model version: {model_ver}")
|
||||
# cross our fingers and try latest version
|
||||
return 7
|
||||
return 8
|
||||
|
||||
|
||||
class UnknownLibraryVersion(Exception):
|
||||
|
||||
Reference in New Issue
Block a user