From a36eb416b19284477922b6a5f837f4040327138b Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Mon, 31 Aug 2020 05:24:54 -0700 Subject: [PATCH] Normalize unicode for issue #208 --- osxphotos/__main__.py | 24 ++++++++++++++- osxphotos/_constants.py | 3 ++ osxphotos/_version.py | 2 +- .../photosdb/_photosdb_process_faceinfo.py | 6 ++-- .../photosdb/_photosdb_process_searchinfo.py | 9 +++--- osxphotos/photosdb/photosdb.py | 20 ++++++------ osxphotos/placeinfo.py | 29 ++++++++++-------- osxphotos/utils.py | 12 ++++++++ .../database/Photos.sqlite-shm | Bin 32768 -> 32768 bytes .../database/Photos.sqlite-wal | Bin 580952 -> 1174232 bytes .../database/Photos.sqlite.lock | 2 +- .../caches/graph/CLSLocationCache.sqlite-shm | Bin 32768 -> 32768 bytes .../caches/graph/changetoken.plist | Bin 606 -> 606 bytes .../87554DE2-780A-4ED2-83B2-324CCE3DEE45 | Bin 0 -> 8 bytes .../resources/journals/Album-change.plj | Bin 1833 -> 2345 bytes .../resources/journals/Folder-change.plj | Bin 1214 -> 1478 bytes .../resources/journals/HistoryToken.plist | Bin 553 -> 553 bytes tests/test_catalina_10_15_6.py | 2 ++ tests/test_cli.py | 23 +++++++++++++- 19 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 tests/Test-10.15.6.photoslibrary/private/com.apple.photolibraryd/caches/clientservertransaction/87554DE2-780A-4ED2-83B2-324CCE3DEE45 diff --git a/osxphotos/__main__.py b/osxphotos/__main__.py index 8e4749f4..023c401a 100644 --- a/osxphotos/__main__.py +++ b/osxphotos/__main__.py @@ -10,6 +10,7 @@ import pathlib import pprint import sys import time +import unicodedata import click import yaml @@ -22,7 +23,7 @@ from pathvalidate import ( import osxphotos -from ._constants import _EXIF_TOOL_URL, _PHOTOS_4_VERSION, _UNKNOWN_PLACE +from ._constants import _EXIF_TOOL_URL, _PHOTOS_4_VERSION, _UNKNOWN_PLACE, UNICODE_FORMAT from ._export_db import ExportDB, ExportDBInMemory from ._version import __version__ from .datetime_formatter import DateTimeFormatter @@ -40,9 +41,21 @@ OSXPHOTOS_EXPORT_DB = ".osxphotos_export.db" def verbose(*args, **kwargs): + """ print output if verbose flag set """ if VERBOSE: click.echo(*args, **kwargs) +def normalize_unicode(value): + """ normalize unicode data """ + if value is not None: + if isinstance(value, tuple): + return tuple(unicodedata.normalize(UNICODE_FORMAT, v) for v in value) + elif isinstance(value, str): + return unicodedata.normalize(UNICODE_FORMAT, value) + else: + return value + else: + return None def get_photos_db(*db_options): """ Return path to photos db, select first non-None db_options @@ -1863,6 +1876,15 @@ def _query( to_date=to_date, ) + person = normalize_unicode(person) + keyword = normalize_unicode(keyword) + album = normalize_unicode(album) + folder = normalize_unicode(folder) + title = normalize_unicode(title) + description = normalize_unicode(description) + place = normalize_unicode(place) + label = normalize_unicode(label) + if album: photos = get_photos_by_attribute(photos, "albums", album, ignore_case) diff --git a/osxphotos/_constants.py b/osxphotos/_constants.py index 82b0c578..fde74c14 100644 --- a/osxphotos/_constants.py +++ b/osxphotos/_constants.py @@ -9,6 +9,9 @@ from datetime import datetime # 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 diff --git a/osxphotos/_version.py b/osxphotos/_version.py index 80d20f8d..22cb5725 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.33.6" +__version__ = "0.33.7" diff --git a/osxphotos/photosdb/_photosdb_process_faceinfo.py b/osxphotos/photosdb/_photosdb_process_faceinfo.py index 53212ce5..7f386f64 100644 --- a/osxphotos/photosdb/_photosdb_process_faceinfo.py +++ b/osxphotos/photosdb/_photosdb_process_faceinfo.py @@ -4,7 +4,7 @@ import logging from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION -from ..utils import _open_sql_file +from ..utils import _open_sql_file, normalize_unicode from .photosdb_utils import get_db_version @@ -121,7 +121,7 @@ def _process_faceinfo_4(photosdb): face["asset_uuid"] = asset_uuid face["uuid"] = row[2] face["person"] = person_id - face["fullname"] = row[3] + face["fullname"] = normalize_unicode(row[3]) face["sourcewidth"] = row[7] face["sourceheight"] = row[8] face["centerx"] = row[9] @@ -282,7 +282,7 @@ def _process_faceinfo_5(photosdb): face["asset_uuid"] = asset_uuid face["uuid"] = row[2] face["person"] = person_pk - face["fullname"] = row[4] + face["fullname"] = normalize_unicode(row[4]) face["agetype"] = row[5] face["baldtype"] = row[6] face["eyemakeuptype"] = row[7] diff --git a/osxphotos/photosdb/_photosdb_process_searchinfo.py b/osxphotos/photosdb/_photosdb_process_searchinfo.py index fd948c87..6f5aec08 100644 --- a/osxphotos/photosdb/_photosdb_process_searchinfo.py +++ b/osxphotos/photosdb/_photosdb_process_searchinfo.py @@ -10,7 +10,7 @@ import uuid as uuidlib from pprint import pformat from .._constants import _PHOTOS_4_VERSION, SEARCH_CATEGORY_LABEL -from ..utils import _db_is_locked, _debug, _open_sql_file +from ..utils import _db_is_locked, _debug, _open_sql_file, normalize_unicode """ This module should be imported in the class defintion of PhotosDB in photosdb.py @@ -112,8 +112,8 @@ def _process_searchinfo(self): record["groupid"] = row[3] record["category"] = row[4] record["owning_groupid"] = row[5] - record["content_string"] = row[6].replace("\x00", "") - record["normalized_string"] = row[7].replace("\x00", "") + record["content_string"] = normalize_unicode(row[6].replace("\x00", "")) + record["normalized_string"] = normalize_unicode(row[7].replace("\x00", "")) record["lookup_identifier"] = row[8] try: @@ -147,9 +147,10 @@ def _process_searchinfo(self): "_db_searchinfo_labels_normalized: \n" + pformat(self._db_searchinfo_labels_normalized) ) - + conn.close() + @property def labels(self): """ return list of all search info labels found in the library """ diff --git a/osxphotos/photosdb/photosdb.py b/osxphotos/photosdb/photosdb.py index ed178b50..144898ae 100644 --- a/osxphotos/photosdb/photosdb.py +++ b/osxphotos/photosdb/photosdb.py @@ -44,6 +44,7 @@ from ..utils import ( _get_os_version, _open_sql_file, get_last_library_path, + normalize_unicode, ) from .photosdb_utils import get_db_model_version, get_db_version @@ -713,7 +714,7 @@ class PhotosDB: for album in c: self._dbalbum_details[album[0]] = { "_uuid": album[0], - "title": album[1], + "title": normalize_unicode(album[1]), "cloudlibrarystate": album[2], "cloudidentifier": album[3], "intrash": False if album[4] == 0 else True, @@ -760,7 +761,7 @@ class PhotosDB: self._dbfolder_details[uuid] = { "_uuid": row[0], "modelId": row[1], - "name": row[2], + "name": normalize_unicode(row[2]), "isMagic": row[3], "intrash": row[4], "folderType": row[5], @@ -963,7 +964,7 @@ class PhotosDB: self._dbphotos[uuid]["volumeId"] = row[10] self._dbphotos[uuid]["imagePath"] = row[11] self._dbphotos[uuid]["extendedDescription"] = row[12] - self._dbphotos[uuid]["name"] = row[13] + self._dbphotos[uuid]["name"] = normalize_unicode(row[13]) self._dbphotos[uuid]["isMissing"] = row[14] self._dbphotos[uuid]["originalFilename"] = row[15] self._dbphotos[uuid]["favorite"] = row[16] @@ -1608,7 +1609,7 @@ class PhotosDB: for album in c: self._dbalbum_details[album[0]] = { "_uuid": album[0], - "title": album[1], + "title": normalize_unicode(album[1]), "cloudlocalstate": album[2], "cloudownerfirstname": album[3], "cloudownderlastname": album[4], @@ -1683,12 +1684,13 @@ class PhotosDB: JOIN ZKEYWORD ON ZKEYWORD.Z_PK = {keyword_join} """ ) for keyword in c: + keyword_title = normalize_unicode(keyword[0]) if not keyword[1] in self._dbkeywords_uuid: self._dbkeywords_uuid[keyword[1]] = [] - if not keyword[0] in self._dbkeywords_keyword: - self._dbkeywords_keyword[keyword[0]] = [] + if not keyword_title in self._dbkeywords_keyword: + self._dbkeywords_keyword[keyword_title] = [] self._dbkeywords_uuid[keyword[1]].append(keyword[0]) - self._dbkeywords_keyword[keyword[0]].append(keyword[1]) + self._dbkeywords_keyword[keyword_title].append(keyword[1]) if _debug(): logging.debug(f"Finished walking through keywords") @@ -1795,7 +1797,7 @@ class PhotosDB: info["modelID"] = None info["masterUuid"] = None info["masterFingerprint"] = row[1] - info["name"] = row[2] + info["name"] = normalize_unicode(row[2]) # There are sometimes negative values for lastmodifieddate in the database # I don't know what these mean but they will raise exception in datetime if @@ -2027,7 +2029,7 @@ class PhotosDB: for row in c: uuid = row[0] if uuid in self._dbphotos: - self._dbphotos[uuid]["extendedDescription"] = row[1] + self._dbphotos[uuid]["extendedDescription"] = normalize_unicode(row[1]) else: if _debug(): logging.debug( diff --git a/osxphotos/placeinfo.py b/osxphotos/placeinfo.py index 7c52d987..18de2a0c 100644 --- a/osxphotos/placeinfo.py +++ b/osxphotos/placeinfo.py @@ -11,6 +11,9 @@ from collections import namedtuple # pylint: disable=syntax-error import yaml from bpylist import archiver +from ._constants import UNICODE_FORMAT +from .utils import normalize_unicode + # postal address information, returned by PlaceInfo.address PostalAddress = namedtuple( "PostalAddress", @@ -76,12 +79,12 @@ class PLRevGeoLocationInfo: geoServiceProvider, postalAddress, ): - self.addressString = addressString + self.addressString = normalize_unicode(addressString) self.countryCode = countryCode self.mapItem = mapItem self.isHome = isHome - self.compoundNames = compoundNames - self.compoundSecondaryNames = compoundSecondaryNames + self.compoundNames = normalize_unicode(compoundNames) + self.compoundSecondaryNames = normalize_unicode(compoundSecondaryNames) self.version = version self.geoServiceProvider = geoServiceProvider self.postalAddress = postalAddress @@ -183,7 +186,7 @@ class PLRevGeoMapItemAdditionalPlaceInfo: def __init__(self, area, name, placeType, dominantOrderType): self.area = area - self.name = name + self.name = normalize_unicode(name) self.placeType = placeType self.dominantOrderType = dominantOrderType @@ -232,13 +235,13 @@ class CNPostalAddress: _subLocality, ): self._ISOCountryCode = _ISOCountryCode - self._city = _city - self._country = _country - self._postalCode = _postalCode - self._state = _state - self._street = _street - self._subAdministrativeArea = _subAdministrativeArea - self._subLocality = _subLocality + self._city = normalize_unicode(_city) + self._country = normalize_unicode(_country) + self._postalCode = normalize_unicode(_postalCode) + self._state = normalize_unicode(_state) + self._street = normalize_unicode(_street) + self._subAdministrativeArea = normalize_unicode(_subAdministrativeArea) + self._subLocality = normalize_unicode(_subLocality) def __eq__(self, other): return all( @@ -414,9 +417,9 @@ class PlaceInfo4(PlaceInfo): # 2: type # 3: area try: - places_dict[p[2]].append((p[1], p[3])) + places_dict[p[2]].append((normalize_unicode(p[1]), p[3])) except KeyError: - places_dict[p[2]] = [(p[1], p[3])] + places_dict[p[2]] = [(normalize_unicode(p[1]), p[3])] # build list to populate PlaceNames tuple # initialize with empty lists for each field in PlaceNames diff --git a/osxphotos/utils.py b/osxphotos/utils.py index 28f7bb83..2ec3f4bb 100644 --- a/osxphotos/utils.py +++ b/osxphotos/utils.py @@ -10,6 +10,7 @@ import sqlite3 import subprocess import sys import tempfile +import unicodedata import urllib.parse from plistlib import load as plistload @@ -18,6 +19,7 @@ import CoreServices import objc from Foundation import * +from ._constants import UNICODE_FORMAT from .fileutil import FileUtil _DEBUG = False @@ -352,3 +354,13 @@ def _db_is_locked(dbname): # attr = xattr.xattr(filepath) # uuid_bytes = bytes(uuid, 'utf-8') # attr.set(OSXPHOTOS_XATTR_UUID, uuid_bytes) + + +def normalize_unicode(value): + """ normalize unicode data """ + if value is not None: + if not isinstance(value, str): + raise ValueError("value must be str") + return unicodedata.normalize(UNICODE_FORMAT, value) + else: + return None diff --git a/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite-shm b/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite-shm index 49f2dac9ef31b2780e238fb467d14953e4a22381..a5e29bd3ca58eeab60b58beced2b310884d374e1 100644 GIT binary patch literal 32768 zcmeI5cXU)$5XQe3APGGX2%%XJ?AQ@SK!hkFb^)WgbWy9|GX6AnH?(WGS%uUa242eYI0V(zQqkjU> zDPddt&Y3w4n+zJl;Qq@eZZQu8U`}=f`yz=nAo~&7LvsIKB}2$i@)~)ayg}Y1 zZ;`jjJ7gG%wY~-{(44d;ZAb=bM~0ITWF*NVqsVA7hKwcS$ape=OeB-YWHN&XVPk!&KH zNo3FVq=(Voim$Q!kbCjZYvex4`>hdqHyXvsV>3pWnPj57<317kHJ)A)4Y zBwVAsq9W?zFr0~7@H;95^og-ZS-YglI;s~oPOS`+ungLum&1lz<633)vv8|Ysh7!| zKDRN*ZFzO|@oJ?^(j4qVZBkbb$W&Xm(GNG8vxUZii5gL! z=4l^Vx6*Q`i34#muE+hH%e)0YqO4avu-)Z$Z3S1CN#+(B2PSDmd74Ie#)sOaG!bby z2&bS6`fwuo=lBWbywp;&`(=i|g~ox&8d08Re?03$?NXYAS~wVOaRVOUEdH(d8Hrwv zQnUM46pHn7j)BW)kFJ52pW-9qb3U|grO8OgAvhH`qAyRO_yWHm$*URn?tjAVqSVz_ zs+D09o{nyTw>#BG#^-%#3qyJwn&FbdNUY5Hq*CWvw#sz_p{YO3N2f3N(3V7LD!vQF zvQ~$p%i_>vwvQ%W^r0<@((NHx)S8g=>AubBK3aImhc+xyIgid=e2BAg8@}cVf|b4W zxc@GRtYdBDmlE}OMj@AiSunwGq+k;KWY;rQCg~oxII1yKA zgw)6xktHq8!yOKnR2BQ;D4dH-bVm<7gpaTdJ5j}}9oP53I)^LTQ@RDNaM(jV{GqHq z3$1XqQY)w0h9kZIrNyj>5>*5aHn!fBa}M#vJLKA2uTNXocFm4N9a+7 delta 503 zcmb7;-7CXk6vxkbem%=rnxvK@$x9m&c`1YxW|Cq3h8AJ6v|M;;Ugt-0p|<4QDpxL) z8|~H~Fn5$(xOC&f&6G5aah}bETc@6$=X{^f_j`_E2*VJ&wx>E!h1p|`@O>x%+@X%5 z*W2fp=3{D2Tt`z=GnV`QkNt}O@+w=E%KiRR84*Ch_SIgyh-q@9J!X~t!ki1mPzNqp zB9v#c04CumhVlz3-D8RgnH2Qd8z!p^Q?k!OLas^+ltMkz=Tz?0IV6nqKAmgMkNH9!s-BM-&X$1tq*HTgM8{yP%~BHR05p4`t8*Uf5u0 zNKnwHQk?=TGt}brZ(EgV1GCwg)ZzE28F@KigBox`5DwUXgVeU5J}#*(VDRv?z(UrC zO`024_)(42xZ*Jbv_L2LV2-5_l4;GuY%OYC;3t$RItWF1w>Ukn8+<#oZkT8Nj>b1L VJD+T+EnJ8t?6)HsI}Y~i;s?0nl^g&7 diff --git a/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite-wal b/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite-wal index 0bf6febbb612c80198aac6bfdc3714752ccd5501..a7b9270293e8f39c32043fd0391ccfec6432d5ab 100644 GIT binary patch delta 49087 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 delta 25 gcmca{)&0gU<%Sl<7N!>F7M2#)7Pc1lEgTVd0ghP-(*OVf diff --git a/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite.lock b/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite.lock index 5b4d48b7..5b9b78f5 100644 --- a/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite.lock +++ b/tests/Test-10.15.6.photoslibrary/database/Photos.sqlite.lock @@ -7,7 +7,7 @@ hostuuid 9575E48B-8D5F-5654-ABAC-4431B1167324 pid - 1847 + 1942 processname photolibraryd uid diff --git a/tests/Test-10.15.6.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm b/tests/Test-10.15.6.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm index 8f27ed5ef816dfda3362eeb1ac1f56f1deabc3be..eb0386c29202af47f189447fa24b2a936a19c47d 100644 GIT binary patch delta 205 zcmZo@U}|V!VwQNMJNYA1>&6ZX#?4=tw%KlC?qHt$&q-wSC#F|SlmEE#02!Z{n6(%@ zH-BWRW|~~#Eim~LQ^DjP-VhmX4hB&MMFt%Pdj@ZyiqA~koD58u)yRG;UK+5Oq27Xx`2!?Osp&n3Jlgj$+IlX(hNpGhB7;|6ocX9k4(!q m_ho4@ZerG8+58~?3Xt)Kb@GOC7NE9YOqut-M$ delta 725 zcmb7>OH7kd5QWcN+Z1RuK=Bb8q^O9rg~Z3s7{tgzi&3cpA}Zn=m7<6sKKSv8AP8RM zVHd2}NMa;SOjwyNUAQo~H8Cda-Kp_;?yV$ly~&rEIdkUzH}gA=avasO>QfmOj{w;T z7C|!c=J`T(-(XE;dq>lUs@;Lc$u?K`^{bix^)KFS?*0AG`Kv1=W_v3{4~wg88MOde zO$ten6p;5FNGPh0Q3^ApD?a1>spb?jF2Sa$KQ!*eu>DG@bpXUfJ<1QXk z9+x^RdqdcTqiDxH3{#$xddl;nyQ0~0Xe1}DzeatYW4MC*7-1(R-orS98+e3CBq$V$ zKLg9Ti3lnXMH4#k08gw__A``_Ia+ z@erfw@w0YZf3EX+PM{0@cxuPmtn9AAIozZ$ty>%VGxy>ou3-RU*3xS&60^bM;=kI8 z+brJ7k^>lI@?E(D*o1>jzqqBv`n>tv_dc9LH^wzLksN9XiJWKer;=ONlKdEdFLJ@= ja-CsbCcBD**KP)R4hA8CE_(?*g)2S=>;KNae(r!wsREw5PkzIc z%~ls~y`JgldKn3z7DlXEW-}UWUe`aJKdB%mv$({-;36YaXh~*CPHMh@5rYwf z0fQlf1%ob-G+