diff --git a/osxphotos/_version.py b/osxphotos/_version.py index 3017c9d8..942d62c8 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.42.9" +__version__ = "0.42.10" diff --git a/osxphotos/cli.py b/osxphotos/cli.py index 7b49e659..3564c5cc 100644 --- a/osxphotos/cli.py +++ b/osxphotos/cli.py @@ -2163,8 +2163,6 @@ def export_photo( global VERBOSE VERBOSE = bool(verbose) - results = ExportResults() - export_original = not (skip_original_if_edited and photo.hasadjustments) # can't export edited if photo doesn't have edited versions @@ -2206,33 +2204,54 @@ def export_photo( if photo.hasadjustments and photo.path_edited is None: missing_edited = True + sidecar = [s.lower() for s in sidecar] + sidecar_flags = 0 + if "json" in sidecar: + sidecar_flags |= SIDECAR_JSON + if "xmp" in sidecar: + sidecar_flags |= SIDECAR_XMP + if "exiftool" in sidecar: + sidecar_flags |= SIDECAR_EXIFTOOL + + rendered_suffix = "" + if original_suffix: + try: + rendered_suffix, unmatched = photo.render_template( + original_suffix, filename=True, strip=strip + ) + except ValueError as e: + raise click.BadOptionUsage( + "original_suffix", + f"Invalid template for --original-suffix '{original_suffix}': {e}", + ) + if not rendered_suffix or unmatched: + raise click.BadOptionUsage( + "original_suffix", + f"Invalid template for --original-suffix '{original_suffix}': results={rendered_suffix} unknown field={unmatched}", + ) + if len(rendered_suffix) > 1: + raise click.BadOptionUsage( + "original_suffix", + f"Invalid template for --original-suffix: may not use multi-valued templates: '{original_suffix}': results={rendered_suffix}", + ) + rendered_suffix = rendered_suffix[0] + + # if download_missing and the photo is missing or path doesn't exist, + # try to download with Photos + use_photos_export = use_photos_export or ( + download_missing + and ( + photo.ismissing + or photo.path is None + or (export_edited and photo.path_edited is None) + ) + ) + + results = ExportResults() filenames = get_filenames_from_template( photo, filename_template, original_name, strip=strip ) for filename in filenames: - rendered_suffix = "" - if original_suffix: - try: - rendered_suffix, unmatched = photo.render_template( - original_suffix, filename=True, strip=strip - ) - except ValueError as e: - raise click.BadOptionUsage( - "original_suffix", - f"Invalid template for --original-suffix '{original_suffix}': {e}", - ) - if not rendered_suffix or unmatched: - raise click.BadOptionUsage( - "original_suffix", - f"Invalid template for --original-suffix '{original_suffix}': results={rendered_suffix} unknown field={unmatched}", - ) - if len(rendered_suffix) > 1: - raise click.BadOptionUsage( - "original_suffix", - f"Invalid template for --original-suffix: may not use multi-valued templates: '{original_suffix}': results={rendered_suffix}", - ) - rendered_suffix = rendered_suffix[0] - original_filename = pathlib.Path(filename) file_ext = original_filename.suffix if photo.isphoto and (jpeg_ext or convert_to_jpeg): @@ -2254,314 +2273,331 @@ def export_photo( f"Exporting {photo.original_filename} ({photo.filename}) as {original_filename}" ) - dest_paths = get_dirnames_from_template( - photo, directory, export_by_date, dest, dry_run, strip=strip + results += export_photo_with_template( + photo=photo, + filename=original_filename, + directory=directory, + edited=False, + use_photos_export=use_photos_export, + export_by_date=export_by_date, + dest=dest, + dry_run=dry_run, + strip=strip, + export_original=export_original, + missing=missing_original, + verbose=verbose, + sidecar_flags=sidecar_flags, + sidecar_drop_ext=sidecar_drop_ext, + export_live=export_live, + export_raw=export_raw, + export_as_hardlink=export_as_hardlink, + overwrite=overwrite, + exiftool=exiftool, + exiftool_merge_keywords=exiftool_merge_keywords, + exiftool_merge_persons=exiftool_merge_persons, + album_keyword=album_keyword, + person_keyword=person_keyword, + keyword_template=keyword_template, + description_template=description_template, + update=update, + ignore_signature=ignore_signature, + export_db=export_db, + fileutil=fileutil, + touch_file=touch_file, + convert_to_jpeg=convert_to_jpeg, + jpeg_quality=jpeg_quality, + ignore_date_modified=ignore_date_modified, + use_photokit=use_photokit, + exiftool_option=exiftool_option, + jpeg_ext=jpeg_ext, + replace_keywords=replace_keywords, + retry=retry, ) - sidecar = [s.lower() for s in sidecar] - sidecar_flags = 0 - if "json" in sidecar: - sidecar_flags |= SIDECAR_JSON - if "xmp" in sidecar: - sidecar_flags |= SIDECAR_XMP - if "exiftool" in sidecar: - sidecar_flags |= SIDECAR_EXIFTOOL - - # if download_missing and the photo is missing or path doesn't exist, - # try to download with Photos - use_photos_export = use_photos_export or ( - download_missing - and ( - photo.ismissing - or photo.path is None - or (export_edited and photo.path_edited is None) - ) + if export_edited and photo.hasadjustments: + # if export-edited, also export the edited version + edited_filenames = get_filenames_from_template( + photo, filename_template, original_name, strip=strip ) - - # export the photo to each path in dest_paths - for dest_path in dest_paths: - # TODO: if --skip-original-if-edited, it's possible edited version is on disk but - # original is missing, in which case we should download the edited version - if export_original: - if missing_original: - space = " " if not verbose else "" - verbose_( - f"{space}Skipping missing photo {photo.original_filename} ({photo.uuid})" - ) - results.missing.append( - str(pathlib.Path(dest_path) / original_filename) - ) - elif photo.intrash and (not photo.path or use_photos_export): - # skip deleted files if they're missing or using use_photos_export - # as AppleScript/PhotoKit cannot export deleted photos - space = " " if not verbose else "" - verbose_( - f"{space}Skipping missing deleted photo {photo.original_filename} ({photo.uuid})" - ) - results.missing.append( - str(pathlib.Path(dest_path) / original_filename) - ) - else: - tries = 0 - while tries <= retry: - tries += 1 - error = 0 - try: - export_results = photo.export2( - dest_path, - original_filename, - sidecar=sidecar_flags, - sidecar_drop_ext=sidecar_drop_ext, - live_photo=export_live, - raw_photo=export_raw, - export_as_hardlink=export_as_hardlink, - overwrite=overwrite, - use_photos_export=use_photos_export, - exiftool=exiftool, - merge_exif_keywords=exiftool_merge_keywords, - merge_exif_persons=exiftool_merge_persons, - use_albums_as_keywords=album_keyword, - use_persons_as_keywords=person_keyword, - keyword_template=keyword_template, - description_template=description_template, - update=update, - ignore_signature=ignore_signature, - export_db=export_db, - fileutil=fileutil, - dry_run=dry_run, - touch_file=touch_file, - convert_to_jpeg=convert_to_jpeg, - jpeg_quality=jpeg_quality, - ignore_date_modified=ignore_date_modified, - use_photokit=use_photokit, - verbose=verbose_, - exiftool_flags=exiftool_option, - jpeg_ext=jpeg_ext, - replace_keywords=replace_keywords, - ) - for warning_ in export_results.exiftool_warning: - verbose_( - f"exiftool warning for file {warning_[0]}: {warning_[1]}" - ) - for error_ in export_results.exiftool_error: - click.echo( - click.style( - f"exiftool error for file {error_[0]}: {error_[1]}", - fg=CLI_COLOR_ERROR, - ), - err=True, - ) - for error_ in export_results.error: - click.echo( - click.style( - f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {error_[0]}: {error_[1]}", - fg=CLI_COLOR_ERROR, - ), - err=True, - ) - error += 1 - if not error or tries > retry: - results += export_results - break - else: - click.echo( - "Retrying export for photo ({photo.uuid}: {photo.original_filename})" - ) - except Exception as e: - click.echo( - click.style( - f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {original_filename}: {e}", - fg=CLI_COLOR_ERROR, - ), - err=True, - ) - if tries > retry: - results.error.append( - (str(pathlib.Path(dest) / original_filename), e) - ) - break - else: - click.echo( - f"Retrying export for photo ({photo.uuid}: {photo.original_filename})" - ) - else: - verbose_(f"Skipping original version of {photo.original_filename}") - - # if export-edited, also export the edited version + for edited_filename in edited_filenames: + edited_filename = pathlib.Path(edited_filename) # verify the photo has adjustments and valid path to avoid raising an exception - if export_edited and photo.hasadjustments: - edited_filename = pathlib.Path(filename) - edited_ext = ( - # rare cases on Photos <= 4 that uti_edited is None - "." + get_preferred_uti_extension(photo.uti_edited) - if photo.uti_edited - else pathlib.Path(photo.path_edited).suffix - if photo.path_edited - else pathlib.Path(photo.filename).suffix - ) + edited_ext = ( + # rare cases on Photos <= 4 that uti_edited is None + "." + get_preferred_uti_extension(photo.uti_edited) + if photo.uti_edited + else pathlib.Path(photo.path_edited).suffix + if photo.path_edited + else pathlib.Path(photo.filename).suffix + ) - if ( - photo.isphoto - and jpeg_ext - and edited_ext.lower() in [".jpg", ".jpeg"] - ): - edited_ext = "." + jpeg_ext + if photo.isphoto and jpeg_ext and edited_ext.lower() in [".jpg", ".jpeg"]: + edited_ext = "." + jpeg_ext - # Big Sur uses .heic for some edited photos so need to check - # if extension isn't jpeg/jpg and using --convert-to-jpeg - if ( - photo.isphoto - and convert_to_jpeg - and edited_ext.lower() not in [".jpg", ".jpeg"] - ): - edited_ext = "." + jpeg_ext if jpeg_ext else ".jpeg" + # Big Sur uses .heic for some edited photos so need to check + # if extension isn't jpeg/jpg and using --convert-to-jpeg + if ( + photo.isphoto + and convert_to_jpeg + and edited_ext.lower() not in [".jpg", ".jpeg"] + ): + edited_ext = "." + jpeg_ext if jpeg_ext else ".jpeg" - if edited_suffix: - try: - rendered_suffix, unmatched = photo.render_template( - edited_suffix, filename=True, strip=strip - ) - except ValueError as e: - raise click.BadOptionUsage( - "edited_suffix", - f"Invalid template for --edited-suffix '{edited_suffix}': {e}", - ) - if not rendered_suffix or unmatched: - raise click.BadOptionUsage( - "edited_suffix", - f"Invalid template for --edited-suffix '{edited_suffix}': unknown field={unmatched}", - ) - if len(rendered_suffix) > 1: - raise click.BadOptionUsage( - "edited_suffix", - f"Invalid template for --edited-suffix: may not use multi-valued templates: '{edited_suffix}': results={rendered_suffix}", - ) - rendered_suffix = rendered_suffix[0] - - edited_filename = ( - f"{edited_filename.stem}{rendered_suffix}{edited_ext}" + if edited_suffix: + try: + rendered_suffix, unmatched = photo.render_template( + edited_suffix, filename=True, strip=strip ) - else: - edited_filename = f"{edited_filename.stem}{edited_ext}" + except ValueError as e: + raise click.BadOptionUsage( + "edited_suffix", + f"Invalid template for --edited-suffix '{edited_suffix}': {e}", + ) + if not rendered_suffix or unmatched: + raise click.BadOptionUsage( + "edited_suffix", + f"Invalid template for --edited-suffix '{edited_suffix}': unknown field={unmatched}", + ) + if len(rendered_suffix) > 1: + raise click.BadOptionUsage( + "edited_suffix", + f"Invalid template for --edited-suffix: may not use multi-valued templates: '{edited_suffix}': results={rendered_suffix}", + ) + rendered_suffix = rendered_suffix[0] + edited_filename = f"{edited_filename.stem}{rendered_suffix}{edited_ext}" + else: + edited_filename = f"{edited_filename.stem}{edited_ext}" + verbose_( + f"Exporting edited version of {photo.original_filename} ({photo.filename}) as {edited_filename}" + ) + + results += export_photo_with_template( + photo=photo, + filename=edited_filename, + directory=directory, + edited=True, + use_photos_export=use_photos_export, + export_by_date=export_by_date, + dest=dest, + dry_run=dry_run, + strip=strip, + export_original=export_original, + missing=missing_edited, + verbose=verbose, + sidecar_flags=sidecar_flags, + sidecar_drop_ext=sidecar_drop_ext, + export_live=export_live, + export_raw=export_raw, + export_as_hardlink=export_as_hardlink, + overwrite=overwrite, + exiftool=exiftool, + exiftool_merge_keywords=exiftool_merge_keywords, + exiftool_merge_persons=exiftool_merge_persons, + album_keyword=album_keyword, + person_keyword=person_keyword, + keyword_template=keyword_template, + description_template=description_template, + update=update, + ignore_signature=ignore_signature, + export_db=export_db, + fileutil=fileutil, + touch_file=touch_file, + convert_to_jpeg=convert_to_jpeg, + jpeg_quality=jpeg_quality, + ignore_date_modified=ignore_date_modified, + use_photokit=use_photokit, + exiftool_option=exiftool_option, + jpeg_ext=jpeg_ext, + replace_keywords=replace_keywords, + retry=retry, + ) + + return results + + +def export_photo_with_template( + photo, + filename, + directory, + edited, + use_photos_export, + export_by_date, + dest, + dry_run, + strip, + export_original, + missing, + verbose, + sidecar_flags, + sidecar_drop_ext, + export_live, + export_raw, + export_as_hardlink, + overwrite, + exiftool, + exiftool_merge_keywords, + exiftool_merge_persons, + album_keyword, + person_keyword, + keyword_template, + description_template, + update, + ignore_signature, + export_db, + fileutil, + touch_file, + convert_to_jpeg, + jpeg_quality, + ignore_date_modified, + use_photokit, + exiftool_option, + jpeg_ext, + replace_keywords, + retry, +): + """ Evaluate directory template then export photo to each directory """ + + results = ExportResults() + + dest_paths = get_dirnames_from_template( + photo, directory, export_by_date, dest, dry_run, strip=strip + ) + + # export the photo to each path in dest_paths + for dest_path in dest_paths: + # TODO: if --skip-original-if-edited, it's possible edited version is on disk but + # original is missing, in which case we should download the edited version + if export_original: + if missing: + space = " " if not verbose else "" verbose_( - f"Exporting edited version of {photo.original_filename} ({photo.filename}) as {edited_filename}" + f"{space}Skipping missing photo {photo.original_filename} ({photo.uuid})" ) - if missing_edited: - space = " " if not verbose else "" - verbose_( - f"{space}Skipping missing edited photo for {edited_filename}" + results.missing.append(str(pathlib.Path(dest_path) / filename)) + continue + elif photo.intrash and (not photo.path or use_photos_export): + # skip deleted files if they're missing or using use_photos_export + # as AppleScript/PhotoKit cannot export deleted photos + space = " " if not verbose else "" + verbose_( + f"{space}Skipping missing deleted photo {photo.original_filename} ({photo.uuid})" + ) + results.missing.append(str(pathlib.Path(dest_path) / filename)) + continue + elif not edited: + verbose_(f"Skipping original version of {photo.original_filename}") + continue + else: + # exporting the edited version + if missing: + space = " " if not verbose else "" + verbose_(f"{space}Skipping missing edited photo for {filename}") + results.missing.append(str(pathlib.Path(dest_path) / filename)) + continue + elif photo.intrash and (not photo.path_edited or use_photos_export): + # skip deleted files if they're missing or using use_photos_export + # as AppleScript/PhotoKit cannot export deleted photos + space = " " if not verbose else "" + verbose_( + f"{space}Skipping missing deleted photo {photo.original_filename} ({photo.uuid})" + ) + results.missing.append(str(pathlib.Path(dest_path) / filename)) + continue + + tries = 0 + while tries <= retry: + tries += 1 + error = 0 + try: + export_results = photo.export2( + dest_path, + filename, + edited=edited, + sidecar=sidecar_flags, + sidecar_drop_ext=sidecar_drop_ext, + live_photo=export_live, + raw_photo=export_raw, + export_as_hardlink=export_as_hardlink, + overwrite=overwrite, + use_photos_export=use_photos_export, + exiftool=exiftool, + merge_exif_keywords=exiftool_merge_keywords, + merge_exif_persons=exiftool_merge_persons, + use_albums_as_keywords=album_keyword, + use_persons_as_keywords=person_keyword, + keyword_template=keyword_template, + description_template=description_template, + update=update, + ignore_signature=ignore_signature, + export_db=export_db, + fileutil=fileutil, + dry_run=dry_run, + touch_file=touch_file, + convert_to_jpeg=convert_to_jpeg, + jpeg_quality=jpeg_quality, + ignore_date_modified=ignore_date_modified, + use_photokit=use_photokit, + verbose=verbose_, + exiftool_flags=exiftool_option, + jpeg_ext=jpeg_ext, + replace_keywords=replace_keywords, + ) + for warning_ in export_results.exiftool_warning: + verbose_(f"exiftool warning for file {warning_[0]}: {warning_[1]}") + for error_ in export_results.exiftool_error: + click.echo( + click.style( + f"exiftool error for file {error_[0]}: {error_[1]}", + fg=CLI_COLOR_ERROR, + ), + err=True, ) - results.missing.append( - str(pathlib.Path(dest_path) / edited_filename) + for error_ in export_results.error: + click.echo( + click.style( + f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {error_[0]}: {error_[1]}", + fg=CLI_COLOR_ERROR, + ), + err=True, ) - elif photo.intrash and (not photo.path_edited or use_photos_export): - # skip deleted files if they're missing or using use_photos_export - # as AppleScript/PhotoKit cannot export deleted photos - space = " " if not verbose else "" - verbose_( - f"{space}Skipping missing deleted photo {photo.original_filename} ({photo.uuid})" + error += 1 + if not error or tries > retry: + results += export_results + break + else: + click.echo( + "Retrying export for photo ({photo.uuid}: {photo.original_filename})" ) - results.missing.append( - str(pathlib.Path(dest_path) / edited_filename) + except Exception as e: + click.echo( + click.style( + f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {filename}: {e}", + fg=CLI_COLOR_ERROR, + ), + err=True, + ) + if tries > retry: + results.error.append((str(pathlib.Path(dest) / filename), e)) + break + else: + click.echo( + f"Retrying export for photo ({photo.uuid}: {photo.original_filename})" ) - else: - tries = 0 - while tries <= retry: - tries += 1 - error = 0 - try: - export_results_edited = photo.export2( - dest_path, - edited_filename, - sidecar=sidecar_flags, - sidecar_drop_ext=sidecar_drop_ext, - export_as_hardlink=export_as_hardlink, - overwrite=overwrite, - edited=True, - use_photos_export=use_photos_export, - exiftool=exiftool, - merge_exif_keywords=exiftool_merge_keywords, - merge_exif_persons=exiftool_merge_persons, - use_albums_as_keywords=album_keyword, - use_persons_as_keywords=person_keyword, - keyword_template=keyword_template, - description_template=description_template, - update=update, - ignore_signature=ignore_signature, - export_db=export_db, - fileutil=fileutil, - dry_run=dry_run, - touch_file=touch_file, - convert_to_jpeg=convert_to_jpeg, - jpeg_quality=jpeg_quality, - ignore_date_modified=ignore_date_modified, - use_photokit=use_photokit, - verbose=verbose_, - exiftool_flags=exiftool_option, - jpeg_ext=jpeg_ext, - replace_keywords=replace_keywords, - ) - for warning_ in export_results_edited.exiftool_warning: - verbose_( - f"exiftool warning for file {warning_[0]}: {warning_[1]}" - ) - for error_ in export_results_edited.exiftool_error: - click.echo( - click.style( - f"exiftool error for file {error_[0]}: {error_[1]}", - fg=CLI_COLOR_ERROR, - ), - err=True, - ) - for error_ in export_results_edited.error: - click.echo( - click.style( - f"Error exporting edited photo ({photo.uuid}: {photo.original_filename}) as {error_[0]}: {error_[1]}", - fg=CLI_COLOR_ERROR, - ), - err=True, - ) - error += 1 - if not error or tries > retry: - results += export_results_edited - break - else: - click.echo( - "Retrying export for photo ({photo.uuid}: {photo.original_filename})" - ) - except Exception as e: - click.echo( - click.style( - f"Error exporting edited photo ({photo.uuid}: {photo.original_filename}) {filename} as {edited_filename}: {e}", - fg=CLI_COLOR_ERROR, - ), - err=True, - ) - if tries > retry: - results.error.append( - (str(pathlib.Path(dest) / edited_filename), e) - ) - break - else: - click.echo( - f"Retrying export for photo ({photo.uuid}: {photo.original_filename})" - ) - - if verbose: - if update: - for new in results.new: - verbose_(f"Exported new file {new}") - for updated in results.updated: - verbose_(f"Exported updated file {updated}") - for skipped in results.skipped: - verbose_(f"Skipped up to date file {skipped}") - else: - for exported in results.exported: - verbose_(f"Exported {exported}") - for touched in results.touched: - verbose_(f"Touched date on file {touched}") + if verbose: + if update: + for new in results.new: + verbose_(f"Exported new file {new}") + for updated in results.updated: + verbose_(f"Exported updated file {updated}") + for skipped in results.skipped: + verbose_(f"Skipped up to date file {skipped}") + else: + for exported in results.exported: + verbose_(f"Exported {exported}") + for touched in results.touched: + verbose_(f"Touched date on file {touched}") return results diff --git a/tests/search_info_test_data_10_15_7.json b/tests/search_info_test_data_10_15_7.json index fcf110cd..4df4c84a 100644 --- a/tests/search_info_test_data_10_15_7.json +++ b/tests/search_info_test_data_10_15_7.json @@ -1 +1 @@ -{"UUID_SEARCH_INFO": {"C8EAF50A-D891-4E0C-8086-C417E1284153": {"labels": ["Food", "Butter"], "place_names": ["Durham Bulls Athletic Park"], "streets": ["Blackwell St"], "neighborhoods": ["American Tobacco District", "Downtown Durham"], "city": "Durham", "locality_names": ["Durham"], "state": "North Carolina", "state_abbreviation": "NC", "country": "United States", "bodies_of_water": [], "month": "October", "year": "2018", "holidays": [], "activities": ["Dinner", "Travel", "Entertainment", "Dining", "Trip"], "season": "Fall", "venues": ["The Pinhook", "Copa", "Luna Rotisserie and Empanadas", "Pie Pushers"], "venue_types": ["Cocktail Bar", "Restaurant", "Pizza", "Music Venue", "Bar", "Tapas & Small Plates", "Food", "Empanadas", "Chicken Wings", "Arts & Entertainment", "Latin American", "Cuban", "Nightlife"], "media_types": []}, "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": {"labels": ["Sunset Sunrise", "Sky", "Outdoor", "Land", "Desert"], "place_names": ["Royal Palms State Beach"], "streets": [], "neighborhoods": ["San Pedro"], "city": "Los Angeles", "locality_names": [], "state": "California", "state_abbreviation": "", "country": "United States", "bodies_of_water": ["Catalina Channel"], "month": "November", "year": "2017", "holidays": [], "activities": ["Beach Activity", "Activity"], "season": "Fall", "venues": [], "venue_types": [], "media_types": ["Live Photos"]}, "2C151013-5BBA-4D00-B70F-1C9420418B86": {"labels": ["Bench", "Vegetation", "Forest", "Outdoor", "Land", "People", "Furniture", "Water", "Water Body"], "place_names": [], "streets": [], "neighborhoods": [], "city": "", "locality_names": [], "state": "", "state_abbreviation": "", "country": "", "bodies_of_water": [], "month": "December", "year": "2014", "holidays": ["Christmas Day"], "activities": ["Celebration", "Holiday"], "season": "Winter", "venues": [], "venue_types": [], "media_types": []}}, "UUID_SEARCH_INFO_NORMALIZED": {"C8EAF50A-D891-4E0C-8086-C417E1284153": {"labels": ["food", "butter"], "place_names": ["durham bulls athletic park"], "streets": ["blackwell st"], "neighborhoods": ["american tobacco district", "downtown durham"], "city": "durham", "locality_names": ["durham"], "state": "north carolina", "state_abbreviation": "nc", "country": "united states", "bodies_of_water": [], "month": "october", "year": "2018", "holidays": [], "activities": ["dinner", "travel", "entertainment", "dining", "trip"], "season": "fall", "venues": ["the pinhook", "copa", "luna rotisserie and empanadas", "pie pushers"], "venue_types": ["cocktail bar", "restaurant", "pizza", "music venue", "bar", "tapas & small plates", "food", "empanadas", "chicken wings", "arts & entertainment", "latin american", "cuban", "nightlife"], "media_types": []}, "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": {"labels": ["sunset sunrise", "sky", "outdoor", "land", "desert"], "place_names": ["royal palms state beach"], "streets": [], "neighborhoods": ["san pedro"], "city": "los angeles", "locality_names": [], "state": "california", "state_abbreviation": "", "country": "united states", "bodies_of_water": ["catalina channel"], "month": "november", "year": "2017", "holidays": [], "activities": ["beach activity", "activity"], "season": "fall", "venues": [], "venue_types": [], "media_types": ["live photos"]}, "2C151013-5BBA-4D00-B70F-1C9420418B86": {"labels": ["bench", "vegetation", "forest", "outdoor", "land", "people", "furniture", "water", "water body"], "place_names": [], "streets": [], "neighborhoods": [], "city": "", "locality_names": [], "state": "", "state_abbreviation": "", "country": "", "bodies_of_water": [], "month": "december", "year": "2014", "holidays": ["christmas day"], "activities": ["celebration", "holiday"], "season": "winter", "venues": [], "venue_types": [], "media_types": []}}, "UUID_SEARCH_INFO_ALL": {"C8EAF50A-D891-4E0C-8086-C417E1284153": ["Food", "Butter", "Durham Bulls Athletic Park", "Blackwell St", "American Tobacco District", "Downtown Durham", "Durham", "Dinner", "Travel", "Entertainment", "Dining", "Trip", "The Pinhook", "Copa", "Luna Rotisserie and Empanadas", "Pie Pushers", "Cocktail Bar", "Restaurant", "Pizza", "Music Venue", "Bar", "Tapas & Small Plates", "Food", "Empanadas", "Chicken Wings", "Arts & Entertainment", "Latin American", "Cuban", "Nightlife", "Durham", "North Carolina", "NC", "United States", "October", "2018", "Fall"], "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": ["Sunset Sunrise", "Sky", "Outdoor", "Land", "Desert", "Royal Palms State Beach", "San Pedro", "Catalina Channel", "Beach Activity", "Activity", "Live Photos", "Los Angeles", "California", "United States", "November", "2017", "Fall"], "2C151013-5BBA-4D00-B70F-1C9420418B86": ["Bench", "Vegetation", "Forest", "Outdoor", "Land", "People", "Furniture", "Water", "Water Body", "Christmas Day", "Celebration", "Holiday", "December", "2014", "Winter"]}, "UUID_SEARCH_INFO_ALL_NORMALIZED": {"C8EAF50A-D891-4E0C-8086-C417E1284153": ["food", "butter", "durham bulls athletic park", "blackwell st", "american tobacco district", "downtown durham", "durham", "dinner", "travel", "entertainment", "dining", "trip", "the pinhook", "copa", "luna rotisserie and empanadas", "pie pushers", "cocktail bar", "restaurant", "pizza", "music venue", "bar", "tapas & small plates", "food", "empanadas", "chicken wings", "arts & entertainment", "latin american", "cuban", "nightlife", "durham", "north carolina", "nc", "united states", "october", "2018", "fall"], "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": ["sunset sunrise", "sky", "outdoor", "land", "desert", "royal palms state beach", "san pedro", "catalina channel", "beach activity", "activity", "live photos", "los angeles", "california", "united states", "november", "2017", "fall"], "2C151013-5BBA-4D00-B70F-1C9420418B86": ["bench", "vegetation", "forest", "outdoor", "land", "people", "furniture", "water", "water body", "christmas day", "celebration", "holiday", "december", "2014", "winter"]}} +{"UUID_SEARCH_INFO": {"C8EAF50A-D891-4E0C-8086-C417E1284153": {"labels": ["Food", "Butter"], "place_names": ["Durham Bulls Athletic Park"], "streets": ["Blackwell St"], "neighborhoods": ["American Tobacco District", "Downtown Durham"], "city": "Durham", "locality_names": ["Durham"], "state": "North Carolina", "state_abbreviation": "NC", "country": "United States", "bodies_of_water": [], "month": "October", "year": "2018", "holidays": [], "activities": ["Dinner", "Travel", "Entertainment", "Dining", "Trip"], "season": "Fall", "venues": ["Copa", "The Pinhook", "Luna Rotisserie and Empanadas", "Pie Pushers"], "venue_types": ["Cocktail Bar", "Restaurant", "Pizza", "Music Venue", "Bar", "Tapas & Small Plates", "Food", "Empanadas", "Chicken Wings", "Arts & Entertainment", "Latin American", "Cuban", "Nightlife"], "media_types": []}, "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": {"labels": ["Desert", "Sky", "Sunset Sunrise", "Outdoor", "Land"], "place_names": ["Royal Palms State Beach"], "streets": [], "neighborhoods": ["San Pedro"], "city": "Los Angeles", "locality_names": [], "state": "California", "state_abbreviation": "", "country": "United States", "bodies_of_water": ["Catalina Channel"], "month": "November", "year": "2017", "holidays": [], "activities": ["Beach Activity", "Activity"], "season": "Fall", "venues": [], "venue_types": [], "media_types": ["Live Photos"]}, "2C151013-5BBA-4D00-B70F-1C9420418B86": {"labels": ["Forest", "Bench", "Land", "Furniture", "Water", "Water Body", "People", "Plant", "Outdoor", "Vegetation"], "place_names": [], "streets": [], "neighborhoods": [], "city": "", "locality_names": [], "state": "", "state_abbreviation": "", "country": "", "bodies_of_water": [], "month": "December", "year": "2014", "holidays": ["Christmas Day"], "activities": ["Celebration", "Holiday"], "season": "Winter", "venues": [], "venue_types": [], "media_types": []}}, "UUID_SEARCH_INFO_NORMALIZED": {"C8EAF50A-D891-4E0C-8086-C417E1284153": {"labels": ["food", "butter"], "place_names": ["durham bulls athletic park"], "streets": ["blackwell st"], "neighborhoods": ["american tobacco district", "downtown durham"], "city": "durham", "locality_names": ["durham"], "state": "north carolina", "state_abbreviation": "nc", "country": "united states", "bodies_of_water": [], "month": "october", "year": "2018", "holidays": [], "activities": ["dinner", "travel", "entertainment", "dining", "trip"], "season": "fall", "venues": ["copa", "the pinhook", "luna rotisserie and empanadas", "pie pushers"], "venue_types": ["cocktail bar", "restaurant", "pizza", "music venue", "bar", "tapas & small plates", "food", "empanadas", "chicken wings", "arts & entertainment", "latin american", "cuban", "nightlife"], "media_types": []}, "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": {"labels": ["desert", "sky", "sunset sunrise", "outdoor", "land"], "place_names": ["royal palms state beach"], "streets": [], "neighborhoods": ["san pedro"], "city": "los angeles", "locality_names": [], "state": "california", "state_abbreviation": "", "country": "united states", "bodies_of_water": ["catalina channel"], "month": "november", "year": "2017", "holidays": [], "activities": ["beach activity", "activity"], "season": "fall", "venues": [], "venue_types": [], "media_types": ["live photos"]}, "2C151013-5BBA-4D00-B70F-1C9420418B86": {"labels": ["forest", "bench", "land", "furniture", "water", "water body", "people", "plant", "outdoor", "vegetation"], "place_names": [], "streets": [], "neighborhoods": [], "city": "", "locality_names": [], "state": "", "state_abbreviation": "", "country": "", "bodies_of_water": [], "month": "december", "year": "2014", "holidays": ["christmas day"], "activities": ["celebration", "holiday"], "season": "winter", "venues": [], "venue_types": [], "media_types": []}}, "UUID_SEARCH_INFO_ALL": {"C8EAF50A-D891-4E0C-8086-C417E1284153": ["Food", "Butter", "Durham Bulls Athletic Park", "Blackwell St", "American Tobacco District", "Downtown Durham", "Durham", "Dinner", "Travel", "Entertainment", "Dining", "Trip", "Copa", "The Pinhook", "Luna Rotisserie and Empanadas", "Pie Pushers", "Cocktail Bar", "Restaurant", "Pizza", "Music Venue", "Bar", "Tapas & Small Plates", "Food", "Empanadas", "Chicken Wings", "Arts & Entertainment", "Latin American", "Cuban", "Nightlife", "Durham", "North Carolina", "NC", "United States", "October", "2018", "Fall"], "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": ["Desert", "Sky", "Sunset Sunrise", "Outdoor", "Land", "Royal Palms State Beach", "San Pedro", "Catalina Channel", "Beach Activity", "Activity", "Live Photos", "Los Angeles", "California", "United States", "November", "2017", "Fall"], "2C151013-5BBA-4D00-B70F-1C9420418B86": ["Forest", "Bench", "Land", "Furniture", "Water", "Water Body", "People", "Plant", "Outdoor", "Vegetation", "Christmas Day", "Celebration", "Holiday", "December", "2014", "Winter"]}, "UUID_SEARCH_INFO_ALL_NORMALIZED": {"C8EAF50A-D891-4E0C-8086-C417E1284153": ["food", "butter", "durham bulls athletic park", "blackwell st", "american tobacco district", "downtown durham", "durham", "dinner", "travel", "entertainment", "dining", "trip", "copa", "the pinhook", "luna rotisserie and empanadas", "pie pushers", "cocktail bar", "restaurant", "pizza", "music venue", "bar", "tapas & small plates", "food", "empanadas", "chicken wings", "arts & entertainment", "latin american", "cuban", "nightlife", "durham", "north carolina", "nc", "united states", "october", "2018", "fall"], "71DFB4C3-E868-4BE4-906E-D96BD8692D7E": ["desert", "sky", "sunset sunrise", "outdoor", "land", "royal palms state beach", "san pedro", "catalina channel", "beach activity", "activity", "live photos", "los angeles", "california", "united states", "november", "2017", "fall"], "2C151013-5BBA-4D00-B70F-1C9420418B86": ["forest", "bench", "land", "furniture", "water", "water body", "people", "plant", "outdoor", "vegetation", "christmas day", "celebration", "holiday", "december", "2014", "winter"]}}