def get_iphoto_or_aperture_pictures(plistpath: Path, photo_class): # The structure of iPhoto and Aperture libraries for the base photo list are excactly the same. if not plistpath.exists(): return [] s = plistpath.open("rt", encoding="utf-8").read() # There was a case where a guy had 0x10 chars in his plist, causing expat errors on loading s = remove_invalid_xml(s, replace_with="") # It seems that iPhoto sometimes doesn't properly escape & chars. The regexp below is to find # any & char that is not a &-based entity (&, ", etc.). based on TextMate's XML # bundle's regexp s, count = re.subn(r"&(?![a-zA-Z0-9_-]+|#[0-9]+|#x[0-9a-fA-F]+;)", "", s) if count: logging.warning("%d invalid XML entities replacement made", count) parser = IPhotoPlistParser() try: plist = parser.parse(io.BytesIO(s.encode("utf-8"))) except Exception: logging.warning("iPhoto plist parsing choked on data: %r", parser.lastdata) raise result = [] for key, photo_data in plist["Master Image List"].items(): if photo_data["MediaType"] != "Image": continue photo_path = Path(photo_data["ImagePath"]) photo = photo_class(photo_path, key) result.append(photo) return result
def get_iphoto_or_aperture_pictures(plistpath: Path, photo_class): # The structure of iPhoto and Aperture libraries for the base photo list are excactly the same. if not plistpath.exists(): return [] s = plistpath.open('rt', encoding='utf-8').read() # There was a case where a guy had 0x10 chars in his plist, causing expat errors on loading s = remove_invalid_xml(s, replace_with='') # It seems that iPhoto sometimes doesn't properly escape & chars. The regexp below is to find # any & char that is not a &-based entity (&, ", etc.). based on TextMate's XML # bundle's regexp s, count = re.subn(r'&(?![a-zA-Z0-9_-]+|#[0-9]+|#x[0-9a-fA-F]+;)', '', s) if count: logging.warning("%d invalid XML entities replacement made", count) parser = IPhotoPlistParser() try: plist = parser.parse(io.BytesIO(s.encode('utf-8'))) except Exception: logging.warning("iPhoto plist parsing choked on data: %r", parser.lastdata) raise result = [] for key, photo_data in plist['Master Image List'].items(): if photo_data['MediaType'] != 'Image': continue photo_path = Path(photo_data['ImagePath']) photo = photo_class(photo_path, key) result.append(photo) return result
def get_iphoto_or_aperture_pictures(plistpath: Path, photo_class): # The structure of iPhoto and Aperture libraries for the base photo list are excactly the same. if not plistpath.exists(): return [] s = plistpath.open('rt', encoding='utf-8').read() # There was a case where a guy had 0x10 chars in his plist, causing expat errors on loading s = remove_invalid_xml(s, replace_with='') # It seems that iPhoto sometimes doesn't properly escape & chars. The regexp below is to find # any & char that is not a &-based entity (&, ", etc.). based on TextMate's XML # bundle's regexp s, count = re.subn(r'&(?![a-zA-Z0-9_-]+|#[0-9]+|#x[0-9a-fA-F]+;)', '', s) if count: logging.warning("%d invalid XML entities replacement made", count) plist = plistlib.readPlistFromBytes(s.encode('utf-8')) result = [] for key, photo_data in plist['Master Image List'].items(): if photo_data['MediaType'] != 'Image': continue photo_path = Path(photo_data['ImagePath']) photo = photo_class(photo_path, key) result.append(photo) return result