Alpha support for MacOS Big Sur/10.16, see issue #187
This commit is contained in:
@@ -10,18 +10,42 @@ import os.path
|
||||
# Photos 4.0 (10.14.5) == 4016
|
||||
# Photos 4.0 (10.14.6) == 4025
|
||||
# Photos 5.0 (10.15.0) == 6000
|
||||
# TODO: Should this also use compatibleBackToVersion from LiGlobals?
|
||||
_TESTED_DB_VERSIONS = ["6000", "4025", "4016", "3301", "2622"]
|
||||
|
||||
# database model versions (applies to Photos 5, Photos 6)
|
||||
# these come from PLModelVersion key in binary plist in Z_METADATA.Z_PLIST
|
||||
# Photos 5 (10.15.1) == 13537
|
||||
# Photos 5 (10.15.4, 10.15.5, 10.15.6) == 13703
|
||||
# Photos 6 (10.16.0 Beta) == 14104
|
||||
_TEST_MODEL_VERSIONS = ["13537", "13703", "14104"]
|
||||
|
||||
# only version 3 - 4 have RKVersion.selfPortrait
|
||||
_PHOTOS_3_VERSION = "3301"
|
||||
|
||||
# versions 5.0 and later have a different database structure
|
||||
_PHOTOS_4_VERSION = "4025" # latest Mojove version on 10.14.6
|
||||
_PHOTOS_5_VERSION = "6000" # seems to be current on 10.15.1 through 10.15.5
|
||||
_PHOTOS_5_VERSION = "6000" # seems to be current on 10.15.1 through 10.15.6
|
||||
|
||||
# Ranges for model version by Photos version
|
||||
_PHOTOS_5_MODEL_VERSION = [13000, 13999]
|
||||
_PHOTOS_6_MODEL_VERSION = [14000, 14999]
|
||||
|
||||
# some table names differ between Photos 5 and Photos 6
|
||||
_DB_TABLE_NAMES = {
|
||||
5: {
|
||||
"ASSET": "ZGENERICASSET",
|
||||
"KEYWORD_JOIN": "Z_1KEYWORDS.Z_37KEYWORDS",
|
||||
"ALBUM_JOIN": "Z_26ASSETS.Z_34ASSETS",
|
||||
},
|
||||
6: {
|
||||
"ASSET": "ZASSET",
|
||||
"KEYWORD_JOIN": "Z_1KEYWORDS.Z_36KEYWORDS",
|
||||
"ALBUM_JOIN": "Z_26ASSETS.Z_3ASSETS",
|
||||
},
|
||||
}
|
||||
|
||||
# which major version operating systems have been tested
|
||||
_TESTED_OS_VERSIONS = ["12", "13", "14", "15"]
|
||||
_TESTED_OS_VERSIONS = ["12", "13", "14", "15", "16"]
|
||||
|
||||
# Photos 5 has persons who are empty string if unidentified face
|
||||
_UNKNOWN_PERSON = "_UNKNOWN_"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.31.2"
|
||||
__version__ = "0.32.0"
|
||||
|
||||
@@ -4,3 +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
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
import logging
|
||||
|
||||
from .._constants import _PHOTOS_4_VERSION
|
||||
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
|
||||
from ..utils import _db_is_locked, _debug, _open_sql_file
|
||||
|
||||
from .photosdb_utils import get_db_version
|
||||
|
||||
def _process_exifinfo(self):
|
||||
""" load the exif data from the database
|
||||
@@ -35,14 +35,16 @@ def _process_exifinfo_5(photosdb):
|
||||
|
||||
db = photosdb._tmp_db
|
||||
|
||||
asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
|
||||
|
||||
(conn, cursor) = _open_sql_file(db)
|
||||
|
||||
result = conn.execute(
|
||||
"""
|
||||
SELECT ZGENERICASSET.ZUUID, ZEXTENDEDATTRIBUTES.*
|
||||
FROM ZGENERICASSET
|
||||
f"""
|
||||
SELECT {asset_table}.ZUUID, ZEXTENDEDATTRIBUTES.*
|
||||
FROM {asset_table}
|
||||
JOIN ZEXTENDEDATTRIBUTES
|
||||
ON ZEXTENDEDATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
|
||||
ON ZEXTENDEDATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
import logging
|
||||
|
||||
from .._constants import _PHOTOS_4_VERSION
|
||||
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
|
||||
from ..utils import _open_sql_file
|
||||
from .photosdb_utils import get_db_version
|
||||
|
||||
|
||||
"""
|
||||
@@ -180,13 +181,15 @@ def _process_faceinfo_5(photosdb):
|
||||
|
||||
db = photosdb._tmp_db
|
||||
|
||||
asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
|
||||
|
||||
(conn, cursor) = _open_sql_file(db)
|
||||
|
||||
result = cursor.execute(
|
||||
"""
|
||||
f"""
|
||||
SELECT
|
||||
ZDETECTEDFACE.Z_PK,
|
||||
ZGENERICASSET.ZUUID,
|
||||
{asset_table}.ZUUID,
|
||||
ZDETECTEDFACE.ZUUID,
|
||||
ZDETECTEDFACE.ZPERSON,
|
||||
ZPERSON.ZFULLNAME,
|
||||
@@ -225,7 +228,7 @@ def _process_faceinfo_5(photosdb):
|
||||
ZDETECTEDFACE.ZYAW,
|
||||
ZDETECTEDFACE.ZMASTERIDENTIFIER
|
||||
FROM ZDETECTEDFACE
|
||||
JOIN ZGENERICASSET ON ZGENERICASSET.Z_PK = ZDETECTEDFACE.ZASSET
|
||||
JOIN {asset_table} ON {asset_table}.Z_PK = ZDETECTEDFACE.ZASSET
|
||||
JOIN ZPERSON ON ZPERSON.Z_PK = ZDETECTEDFACE.ZPERSON;
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
import logging
|
||||
|
||||
from .._constants import _PHOTOS_4_VERSION
|
||||
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
|
||||
from ..utils import _open_sql_file
|
||||
from .photosdb_utils import get_db_version
|
||||
|
||||
"""
|
||||
This module should be imported in the class defintion of PhotosDB in photosdb.py
|
||||
@@ -45,16 +46,18 @@ def _process_scoreinfo_5(photosdb):
|
||||
|
||||
db = photosdb._tmp_db
|
||||
|
||||
asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
|
||||
|
||||
(conn, cursor) = _open_sql_file(db)
|
||||
|
||||
result = cursor.execute(
|
||||
"""
|
||||
f"""
|
||||
SELECT
|
||||
ZGENERICASSET.ZUUID,
|
||||
ZGENERICASSET.ZOVERALLAESTHETICSCORE,
|
||||
ZGENERICASSET.ZCURATIONSCORE,
|
||||
ZGENERICASSET.ZPROMOTIONSCORE,
|
||||
ZGENERICASSET.ZHIGHLIGHTVISIBILITYSCORE,
|
||||
{asset_table}.ZUUID,
|
||||
{asset_table}.ZOVERALLAESTHETICSCORE,
|
||||
{asset_table}.ZCURATIONSCORE,
|
||||
{asset_table}.ZPROMOTIONSCORE,
|
||||
{asset_table}.ZHIGHLIGHTVISIBILITYSCORE,
|
||||
ZCOMPUTEDASSETATTRIBUTES.ZBEHAVIORALSCORE,
|
||||
ZCOMPUTEDASSETATTRIBUTES.ZFAILURESCORE,
|
||||
ZCOMPUTEDASSETATTRIBUTES.ZHARMONIOUSCOLORSCORE,
|
||||
@@ -78,8 +81,8 @@ def _process_scoreinfo_5(photosdb):
|
||||
ZCOMPUTEDASSETATTRIBUTES.ZWELLCHOSENSUBJECTSCORE,
|
||||
ZCOMPUTEDASSETATTRIBUTES.ZWELLFRAMEDSUBJECTSCORE,
|
||||
ZCOMPUTEDASSETATTRIBUTES.ZWELLTIMEDSHOTSCORE
|
||||
FROM ZGENERICASSET
|
||||
JOIN ZCOMPUTEDASSETATTRIBUTES ON ZCOMPUTEDASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
|
||||
FROM {asset_table}
|
||||
JOIN ZCOMPUTEDASSETATTRIBUTES ON ZCOMPUTEDASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ from pprint import pformat
|
||||
from shutil import copyfile
|
||||
|
||||
from .._constants import (
|
||||
_DB_TABLE_NAMES,
|
||||
_MOVIE_TYPE,
|
||||
_PHOTO_TYPE,
|
||||
_PHOTOS_3_VERSION,
|
||||
@@ -45,6 +46,7 @@ from ..utils import (
|
||||
_open_sql_file,
|
||||
get_last_library_path,
|
||||
)
|
||||
from .photosdb_utils import get_db_version, get_db_model_version
|
||||
|
||||
# TODO: Add test for imageTimeZoneOffsetSeconds = None
|
||||
# TODO: Add test for __str__
|
||||
@@ -267,7 +269,7 @@ class PhotosDB:
|
||||
if _db_is_locked(self._dbfile):
|
||||
self._tmp_db = self._copy_db_file(self._dbfile)
|
||||
|
||||
self._db_version = self._get_db_version(self._tmp_db)
|
||||
self._db_version = get_db_version(self._tmp_db)
|
||||
|
||||
# If Photos >= 5, actual data isn't in photos.db but in Photos.sqlite
|
||||
if int(self._db_version) > int(_PHOTOS_4_VERSION):
|
||||
@@ -530,34 +532,6 @@ class PhotosDB:
|
||||
|
||||
return dest_path
|
||||
|
||||
def _get_db_version(self, db_file):
|
||||
""" Gets the Photos DB version from LiGlobals table
|
||||
|
||||
Args:
|
||||
db_file: path to database file containing LiGlobals table
|
||||
|
||||
Returns: version as str
|
||||
"""
|
||||
|
||||
version = None
|
||||
|
||||
(conn, c) = _open_sql_file(db_file)
|
||||
|
||||
# get database version
|
||||
c.execute(
|
||||
"SELECT value from LiGlobals where LiGlobals.keyPath is 'libraryVersion'"
|
||||
)
|
||||
version = c.fetchone()[0]
|
||||
conn.close()
|
||||
|
||||
if version not in _TESTED_DB_VERSIONS:
|
||||
print(
|
||||
f"WARNING: Only tested on database versions [{', '.join(_TESTED_DB_VERSIONS)}]"
|
||||
+ f" You have database version={version} which has not been tested"
|
||||
)
|
||||
|
||||
return version
|
||||
|
||||
def _process_database4(self):
|
||||
""" process the Photos database to extract info
|
||||
works on Photos version <= 4.0 """
|
||||
@@ -1436,7 +1410,7 @@ class PhotosDB:
|
||||
|
||||
def _process_database5(self):
|
||||
""" process the Photos database to extract info
|
||||
works on Photos version >= 5.0
|
||||
works on Photos version 5 and version 6
|
||||
|
||||
This is a big hairy 700 line function that should probably be refactored
|
||||
but it works so don't touch it.
|
||||
@@ -1448,6 +1422,12 @@ class PhotosDB:
|
||||
# Epoch is Jan 1, 2001
|
||||
td = (datetime(2001, 1, 1, 0, 0) - datetime(1970, 1, 1, 0, 0)).total_seconds()
|
||||
|
||||
photos_ver = get_db_model_version(self._tmp_db)
|
||||
self._photos_ver = photos_ver
|
||||
asset_table = _DB_TABLE_NAMES[photos_ver]["ASSET"]
|
||||
keyword_join = _DB_TABLE_NAMES[photos_ver]["KEYWORD_JOIN"]
|
||||
album_join = _DB_TABLE_NAMES[photos_ver]["ALBUM_JOIN"]
|
||||
|
||||
(conn, c) = _open_sql_file(self._tmp_db)
|
||||
|
||||
# Look for all combinations of persons and pictures
|
||||
@@ -1496,14 +1476,14 @@ class PhotosDB:
|
||||
# get info on keyface -- some photos have null keyface so can't do a single query
|
||||
# (at least not with my SQL skills)
|
||||
c.execute(
|
||||
""" SELECT
|
||||
f""" SELECT
|
||||
ZPERSON.Z_PK,
|
||||
ZPERSON.ZKEYFACE,
|
||||
ZGENERICASSET.ZUUID,
|
||||
{asset_table}.ZUUID,
|
||||
ZDETECTEDFACE.ZUUID
|
||||
FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET
|
||||
FROM ZPERSON, ZDETECTEDFACE, {asset_table}
|
||||
WHERE ZDETECTEDFACE.Z_PK = ZPERSON.ZKEYFACE AND
|
||||
ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK
|
||||
ZDETECTEDFACE.ZASSET = {asset_table}.Z_PK
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -1522,12 +1502,12 @@ class PhotosDB:
|
||||
|
||||
# get information on detected faces
|
||||
c.execute(
|
||||
""" SELECT
|
||||
f""" SELECT
|
||||
ZPERSON.Z_PK,
|
||||
ZGENERICASSET.ZUUID
|
||||
FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET
|
||||
{asset_table}.ZUUID
|
||||
FROM ZPERSON, ZDETECTEDFACE, {asset_table}
|
||||
WHERE ZDETECTEDFACE.ZPERSON = ZPERSON.Z_PK AND
|
||||
ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK
|
||||
ZDETECTEDFACE.ZASSET = {asset_table}.Z_PK
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -1556,12 +1536,12 @@ class PhotosDB:
|
||||
|
||||
# get details about albums
|
||||
c.execute(
|
||||
""" SELECT
|
||||
f""" SELECT
|
||||
ZGENERICALBUM.ZUUID,
|
||||
ZGENERICASSET.ZUUID,
|
||||
Z_26ASSETS.Z_FOK_34ASSETS
|
||||
FROM ZGENERICASSET
|
||||
JOIN Z_26ASSETS ON Z_26ASSETS.Z_34ASSETS = ZGENERICASSET.Z_PK
|
||||
{asset_table}.ZUUID,
|
||||
{album_join}
|
||||
FROM {asset_table}
|
||||
JOIN Z_26ASSETS ON {album_join} = {asset_table}.Z_PK
|
||||
JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS
|
||||
"""
|
||||
)
|
||||
@@ -1668,11 +1648,11 @@ class PhotosDB:
|
||||
|
||||
# get details on keywords
|
||||
c.execute(
|
||||
"SELECT ZKEYWORD.ZTITLE, ZGENERICASSET.ZUUID "
|
||||
"FROM ZGENERICASSET "
|
||||
"JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK "
|
||||
"JOIN Z_1KEYWORDS ON Z_1KEYWORDS.Z_1ASSETATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK "
|
||||
"JOIN ZKEYWORD ON ZKEYWORD.Z_PK = Z_1KEYWORDS.Z_37KEYWORDS "
|
||||
f"""SELECT ZKEYWORD.ZTITLE, {asset_table}.ZUUID
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
JOIN Z_1KEYWORDS ON Z_1KEYWORDS.Z_1ASSETATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK
|
||||
JOIN ZKEYWORD ON ZKEYWORD.Z_PK = {keyword_join} """
|
||||
)
|
||||
for keyword in c:
|
||||
if not keyword[1] in self._dbkeywords_uuid:
|
||||
@@ -1699,45 +1679,45 @@ class PhotosDB:
|
||||
# get details about photos
|
||||
logging.debug(f"Getting information about photos")
|
||||
c.execute(
|
||||
"""SELECT ZGENERICASSET.ZUUID,
|
||||
f"""SELECT {asset_table}.ZUUID,
|
||||
ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT,
|
||||
ZADDITIONALASSETATTRIBUTES.ZTITLE,
|
||||
ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME,
|
||||
ZGENERICASSET.ZMODIFICATIONDATE,
|
||||
ZGENERICASSET.ZDATECREATED,
|
||||
{asset_table}.ZMODIFICATIONDATE,
|
||||
{asset_table}.ZDATECREATED,
|
||||
ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET,
|
||||
ZADDITIONALASSETATTRIBUTES.ZINFERREDTIMEZONEOFFSET,
|
||||
ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME,
|
||||
ZGENERICASSET.ZHIDDEN,
|
||||
ZGENERICASSET.ZFAVORITE,
|
||||
ZGENERICASSET.ZDIRECTORY,
|
||||
ZGENERICASSET.ZFILENAME,
|
||||
ZGENERICASSET.ZLATITUDE,
|
||||
ZGENERICASSET.ZLONGITUDE,
|
||||
ZGENERICASSET.ZHASADJUSTMENTS,
|
||||
ZGENERICASSET.ZCLOUDBATCHPUBLISHDATE,
|
||||
ZGENERICASSET.ZKIND,
|
||||
ZGENERICASSET.ZUNIFORMTYPEIDENTIFIER,
|
||||
ZGENERICASSET.ZAVALANCHEUUID,
|
||||
ZGENERICASSET.ZAVALANCHEPICKTYPE,
|
||||
ZGENERICASSET.ZKINDSUBTYPE,
|
||||
ZGENERICASSET.ZCUSTOMRENDEREDVALUE,
|
||||
{asset_table}.ZHIDDEN,
|
||||
{asset_table}.ZFAVORITE,
|
||||
{asset_table}.ZDIRECTORY,
|
||||
{asset_table}.ZFILENAME,
|
||||
{asset_table}.ZLATITUDE,
|
||||
{asset_table}.ZLONGITUDE,
|
||||
{asset_table}.ZHASADJUSTMENTS,
|
||||
{asset_table}.ZCLOUDBATCHPUBLISHDATE,
|
||||
{asset_table}.ZKIND,
|
||||
{asset_table}.ZUNIFORMTYPEIDENTIFIER,
|
||||
{asset_table}.ZAVALANCHEUUID,
|
||||
{asset_table}.ZAVALANCHEPICKTYPE,
|
||||
{asset_table}.ZKINDSUBTYPE,
|
||||
{asset_table}.ZCUSTOMRENDEREDVALUE,
|
||||
ZADDITIONALASSETATTRIBUTES.ZCAMERACAPTUREDEVICE,
|
||||
ZGENERICASSET.ZCLOUDASSETGUID,
|
||||
{asset_table}.ZCLOUDASSETGUID,
|
||||
ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA,
|
||||
ZGENERICASSET.ZMOMENT,
|
||||
{asset_table}.ZMOMENT,
|
||||
ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE,
|
||||
ZGENERICASSET.ZTRASHEDSTATE,
|
||||
ZGENERICASSET.ZHEIGHT,
|
||||
ZGENERICASSET.ZWIDTH,
|
||||
ZGENERICASSET.ZORIENTATION,
|
||||
{asset_table}.ZTRASHEDSTATE,
|
||||
{asset_table}.ZHEIGHT,
|
||||
{asset_table}.ZWIDTH,
|
||||
{asset_table}.ZORIENTATION,
|
||||
ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT,
|
||||
ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH,
|
||||
ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION,
|
||||
ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE
|
||||
FROM ZGENERICASSET
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
|
||||
ORDER BY ZGENERICASSET.ZUUID """
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
ORDER BY {asset_table}.ZUUID """
|
||||
)
|
||||
# Order of results
|
||||
# 0 SELECT ZGENERICASSET.ZUUID,
|
||||
@@ -1973,12 +1953,12 @@ class PhotosDB:
|
||||
|
||||
# Get extended description
|
||||
c.execute(
|
||||
"SELECT ZGENERICASSET.ZUUID, "
|
||||
"ZASSETDESCRIPTION.ZLONGDESCRIPTION "
|
||||
"FROM ZGENERICASSET "
|
||||
"JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK "
|
||||
"JOIN ZASSETDESCRIPTION ON ZASSETDESCRIPTION.Z_PK = ZADDITIONALASSETATTRIBUTES.ZASSETDESCRIPTION "
|
||||
"ORDER BY ZGENERICASSET.ZUUID "
|
||||
f"""SELECT {asset_table}.ZUUID,
|
||||
ZASSETDESCRIPTION.ZLONGDESCRIPTION
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
JOIN ZASSETDESCRIPTION ON ZASSETDESCRIPTION.Z_PK = ZADDITIONALASSETATTRIBUTES.ZASSETDESCRIPTION
|
||||
ORDER BY {asset_table}.ZUUID """
|
||||
)
|
||||
for row in c:
|
||||
uuid = row[0]
|
||||
@@ -1992,12 +1972,12 @@ class PhotosDB:
|
||||
|
||||
# get information about adjusted/edited photos
|
||||
c.execute(
|
||||
"SELECT ZGENERICASSET.ZUUID, "
|
||||
"ZGENERICASSET.ZHASADJUSTMENTS, "
|
||||
"ZUNMANAGEDADJUSTMENT.ZADJUSTMENTFORMATIDENTIFIER "
|
||||
"FROM ZGENERICASSET, ZUNMANAGEDADJUSTMENT "
|
||||
"JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK "
|
||||
"WHERE ZADDITIONALASSETATTRIBUTES.ZUNMANAGEDADJUSTMENT = ZUNMANAGEDADJUSTMENT.Z_PK "
|
||||
f"""SELECT {asset_table}.ZUUID,
|
||||
{asset_table}.ZHASADJUSTMENTS,
|
||||
ZUNMANAGEDADJUSTMENT.ZADJUSTMENTFORMATIDENTIFIER
|
||||
FROM {asset_table}, ZUNMANAGEDADJUSTMENT
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
WHERE ZADDITIONALASSETATTRIBUTES.ZUNMANAGEDADJUSTMENT = ZUNMANAGEDADJUSTMENT.Z_PK """
|
||||
)
|
||||
for row in c:
|
||||
uuid = row[0]
|
||||
@@ -2016,12 +1996,12 @@ class PhotosDB:
|
||||
|
||||
# Get info on remote/local availability for photos in shared albums
|
||||
c.execute(
|
||||
""" SELECT
|
||||
ZGENERICASSET.ZUUID,
|
||||
f""" SELECT
|
||||
{asset_table}.ZUUID,
|
||||
ZINTERNALRESOURCE.ZLOCALAVAILABILITY,
|
||||
ZINTERNALRESOURCE.ZREMOTEAVAILABILITY
|
||||
FROM ZGENERICASSET
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET
|
||||
WHERE ZDATASTORESUBTYPE = 1 OR ZDATASTORESUBTYPE = 3 """
|
||||
)
|
||||
@@ -2047,11 +2027,11 @@ class PhotosDB:
|
||||
|
||||
# get information on local/remote availability
|
||||
c.execute(
|
||||
""" SELECT ZGENERICASSET.ZUUID,
|
||||
f""" SELECT {asset_table}.ZUUID,
|
||||
ZINTERNALRESOURCE.ZLOCALAVAILABILITY,
|
||||
ZINTERNALRESOURCE.ZREMOTEAVAILABILITY
|
||||
FROM ZGENERICASSET
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZFINGERPRINT = ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT """
|
||||
)
|
||||
|
||||
@@ -2075,11 +2055,11 @@ class PhotosDB:
|
||||
|
||||
# get information about cloud sync state
|
||||
c.execute(
|
||||
""" SELECT
|
||||
ZGENERICASSET.ZUUID,
|
||||
f""" SELECT
|
||||
{asset_table}.ZUUID,
|
||||
ZCLOUDMASTER.ZCLOUDLOCALSTATE
|
||||
FROM ZCLOUDMASTER, ZGENERICASSET
|
||||
WHERE ZGENERICASSET.ZMASTER = ZCLOUDMASTER.Z_PK """
|
||||
FROM ZCLOUDMASTER, {asset_table}
|
||||
WHERE {asset_table}.ZMASTER = ZCLOUDMASTER.Z_PK """
|
||||
)
|
||||
for row in c:
|
||||
uuid = row[0]
|
||||
@@ -2090,15 +2070,15 @@ class PhotosDB:
|
||||
# get information about associted RAW images
|
||||
# RAW images have ZDATASTORESUBTYPE = 17
|
||||
c.execute(
|
||||
""" SELECT
|
||||
ZGENERICASSET.ZUUID,
|
||||
f""" SELECT
|
||||
{asset_table}.ZUUID,
|
||||
ZINTERNALRESOURCE.ZDATALENGTH,
|
||||
ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER,
|
||||
ZINTERNALRESOURCE.ZDATASTORESUBTYPE,
|
||||
ZINTERNALRESOURCE.ZRESOURCETYPE
|
||||
FROM ZGENERICASSET
|
||||
FROM {asset_table}
|
||||
JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
JOIN ZUNIFORMTYPEIDENTIFIER ON ZUNIFORMTYPEIDENTIFIER.Z_PK = ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER
|
||||
WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17
|
||||
"""
|
||||
|
||||
84
osxphotos/photosdb/photosdb_utils.py
Normal file
84
osxphotos/photosdb/photosdb_utils.py
Normal file
@@ -0,0 +1,84 @@
|
||||
""" utility functions used by PhotosDB """
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
|
||||
from .._constants import (
|
||||
_PHOTOS_5_MODEL_VERSION,
|
||||
_PHOTOS_6_MODEL_VERSION,
|
||||
_TESTED_DB_VERSIONS,
|
||||
)
|
||||
from ..utils import _open_sql_file
|
||||
|
||||
|
||||
def get_db_version(db_file):
|
||||
""" Gets the Photos DB version from LiGlobals table
|
||||
|
||||
Args:
|
||||
db_file: path to photos.db database file containing LiGlobals table
|
||||
|
||||
Returns: version as str
|
||||
"""
|
||||
|
||||
version = None
|
||||
|
||||
(conn, c) = _open_sql_file(db_file)
|
||||
|
||||
# get database version
|
||||
c.execute("SELECT value from LiGlobals where LiGlobals.keyPath is 'libraryVersion'")
|
||||
version = c.fetchone()[0]
|
||||
conn.close()
|
||||
|
||||
if version not in _TESTED_DB_VERSIONS:
|
||||
print(
|
||||
f"WARNING: Only tested on database versions [{', '.join(_TESTED_DB_VERSIONS)}]"
|
||||
+ f" You have database version={version} which has not been tested"
|
||||
)
|
||||
|
||||
return version
|
||||
|
||||
|
||||
def get_model_version(db_file):
|
||||
""" Returns the database model version from Z_METADATA
|
||||
|
||||
Args:
|
||||
db_file: path to Photos.sqlite database file containing Z_METADATA table
|
||||
|
||||
Returns: model version as str
|
||||
"""
|
||||
|
||||
version = None
|
||||
|
||||
(conn, c) = _open_sql_file(db_file)
|
||||
|
||||
# get database version
|
||||
c.execute("SELECT MAX(Z_VERSION), Z_PLIST FROM Z_METADATA")
|
||||
results = c.fetchone()
|
||||
|
||||
conn.close()
|
||||
|
||||
plist = plistlib.loads(results[1])
|
||||
return plist["PLModelVersion"]
|
||||
|
||||
|
||||
def get_db_model_version(db_file):
|
||||
""" Returns Photos version based on model version found in db_file
|
||||
|
||||
Args:
|
||||
db_file: path to Photos.sqlite file
|
||||
|
||||
Returns: int of major Photos version number (e.g. 5 or 6).
|
||||
If unknown model version found, logs warning and returns most current Photos version.
|
||||
"""
|
||||
|
||||
model_ver = get_model_version(db_file)
|
||||
if _PHOTOS_5_MODEL_VERSION[0] <= model_ver <= _PHOTOS_5_MODEL_VERSION[1]:
|
||||
db_ver = 5
|
||||
elif _PHOTOS_6_MODEL_VERSION[0] <= model_ver <= _PHOTOS_6_MODEL_VERSION[1]:
|
||||
db_ver = 6
|
||||
else:
|
||||
logging.warning(f"Unknown model version: {model_ver}")
|
||||
# cross our fingers and try latest version
|
||||
db_ver = 6
|
||||
|
||||
return db_ver
|
||||
Reference in New Issue
Block a user