Add exif metadata to json

main
bashrc 2026-01-26 11:53:20 +00:00
parent 477ca609a8
commit b9d9accb14
6 changed files with 101 additions and 14 deletions

View File

@ -2959,9 +2959,10 @@ def profile_edit(self, calling_domain: str, cookie: str,
if self.server.low_bandwidth: if self.server.low_bandwidth:
convert_image_to_low_bandwidth(filename) convert_image_to_low_bandwidth(filename)
exif_json: list[dict] = []
process_meta_data(base_dir, nickname, domain, process_meta_data(base_dir, nickname, domain,
filename, post_image_filename, city, filename, post_image_filename, city,
content_license_url) content_license_url, exif_json)
if os.path.isfile(post_image_filename): if os.path.isfile(post_image_filename):
print('profile update POST ' + m_type + print('profile update POST ' + m_type +
' image, zip or font saved to ' + ' image, zip or font saved to ' +

View File

@ -64,6 +64,7 @@ from cache import remove_person_from_cache
from cache import get_person_from_cache from cache import get_person_from_cache
from shares import add_shares_to_actor from shares import add_shares_to_actor
from person import get_actor_update_json from person import get_actor_update_json
from maps import geocoords_to_osm_link
NEW_POST_SUCCESS = 1 NEW_POST_SUCCESS = 1
NEW_POST_FAILED = -1 NEW_POST_FAILED = -1
@ -1860,6 +1861,7 @@ def _receive_new_post_process(self, post_type: str, path: str, headers: {},
else: else:
print('DEBUG: no media filename in POST') print('DEBUG: no media filename in POST')
exif_json: list[dict] = []
if filename: if filename:
if is_image_file(filename): if is_image_file(filename):
# convert to low bandwidth if needed # convert to low bandwidth if needed
@ -1875,10 +1877,11 @@ def _receive_new_post_process(self, post_type: str, path: str, headers: {},
city = get_spoofed_city(city, base_dir, nickname, domain) city = get_spoofed_city(city, base_dir, nickname, domain)
process_meta_data(base_dir, nickname, domain, process_meta_data(base_dir, nickname, domain,
filename, post_image_filename, city, filename, post_image_filename, city,
content_license_url) content_license_url, exif_json)
if os.path.isfile(post_image_filename): if os.path.isfile(post_image_filename):
print('POST media saved to ' + post_image_filename) print('POST media saved to ' + post_image_filename)
else: else:
exif_json = []
print('ERROR: POST media could not be saved to ' + print('ERROR: POST media could not be saved to ' +
post_image_filename) post_image_filename)
else: else:
@ -1953,6 +1956,33 @@ def _receive_new_post_process(self, post_type: str, path: str, headers: {},
fields['eventEndTime'] = None fields['eventEndTime'] = None
if not fields.get('location'): if not fields.get('location'):
fields['location'] = None fields['location'] = None
if exif_json:
# convert the exif geolocation into an OSM link
latitude = None
longitude = None
for property_dict in exif_json:
if not isinstance(property_dict, dict):
continue
if not property_dict.get('name') or \
not property_dict.get('value'):
continue
if not isinstance(property_dict['name'], str):
continue
if property_dict['name'] == "GPSLongitude":
longitude = property_dict['value']
if not isinstance(longitude, float):
longitude = float(longitude)
if property_dict['name'] == "GPSLatitude":
latitude = property_dict['value']
if not isinstance(latitude, float):
longitude = float(latitude)
if latitude is not None and \
longitude is not None:
osm_domain = 'osm.org'
zoom = 17
fields['location'] = \
geocoords_to_osm_link(osm_domain, zoom,
latitude, longitude)
if not fields.get('locationAddress'): if not fields.get('locationAddress'):
fields['locationAddress'] = None fields['locationAddress'] = None
if not fields.get('languagesDropdown'): if not fields.get('languagesDropdown'):

12
maps.py
View File

@ -25,8 +25,8 @@ from timeFunctions import date_utcnow
from session import get_resolved_url from session import get_resolved_url
def _geocoords_to_osm_link(osm_domain: str, zoom: int, def geocoords_to_osm_link(osm_domain: str, zoom: int,
latitude: float, longitude: float) -> str: latitude: float, longitude: float) -> str:
"""Returns an OSM link for the given geocoordinates """Returns an OSM link for the given geocoordinates
""" """
return 'https://www.' + osm_domain + '/#map=' + \ return 'https://www.' + osm_domain + '/#map=' + \
@ -280,9 +280,9 @@ def get_location_from_post(post_json_object: {}) -> str:
# location geocoordinate # location geocoordinate
osm_domain = 'osm.org' osm_domain = 'osm.org'
zoom = 17 zoom = 17
locn = _geocoords_to_osm_link(osm_domain, zoom, locn = geocoords_to_osm_link(osm_domain, zoom,
locn2['latitude'], locn2['latitude'],
locn2['longitude']) locn2['longitude'])
elif locn_url: elif locn_url:
# location name and link # location name and link
if locn: if locn:
@ -814,7 +814,7 @@ def html_open_street_map(url: str,
return '' return ''
if not zoom: if not zoom:
return '' return ''
osm_url = _geocoords_to_osm_link(osm_domain, zoom, latitude, longitude) osm_url = geocoords_to_osm_link(osm_domain, zoom, latitude, longitude)
html_str = \ html_str = \
'<iframe width="' + width + '" height="' + height + \ '<iframe width="' + width + '" height="' + height + \
'" frameborder="0" ' + \ '" frameborder="0" ' + \

View File

@ -318,7 +318,8 @@ def _remove_meta_data(image_filename: str, output_filename: str) -> None:
def _spoof_meta_data(base_dir: str, nickname: str, domain: str, def _spoof_meta_data(base_dir: str, nickname: str, domain: str,
output_filename: str, spoof_city: str, output_filename: str, spoof_city: str,
content_license_url: str) -> None: content_license_url: str,
exif_json: list[dict]) -> None:
"""Spoof image metadata using a decoy model for a given city """Spoof image metadata using a decoy model for a given city
""" """
if not os.path.isfile(output_filename): if not os.path.isfile(output_filename):
@ -372,6 +373,52 @@ def _spoof_meta_data(base_dir: str, nickname: str, domain: str,
'-Comment="" ' + '-Comment="" ' +
output_filename) != 0: # nosec output_filename) != 0: # nosec
print('ERROR: exiftool failed to run') print('ERROR: exiftool failed to run')
else:
# FEP-ee3a
# https://codeberg.org/fediverse/fep/src/branch/main/
# fep/ee3a/fep-ee3a.md
exif_json += [
{
"@type": "PropertyValue",
"name": "DateTime",
"value": published
},
{
"@type": "PropertyValue",
"name": "GPSLongitudeRef",
"value": longitude_ref
},
{
"@type": "PropertyValue",
"name": "GPSLongitude",
"value": str(longitude)
},
{
"@type": "PropertyValue",
"name": "GPSLatitudeRef",
"value": latitude_ref
},
{
"@type": "PropertyValue",
"name": "GPSLatitude",
"value": str(latitude)
},
{
"@type": "PropertyValue",
"name": "Make",
"value": cam_make
},
{
"@type": "PropertyValue",
"name": "Model",
"value": cam_model
},
{
"@type": "PropertyValue",
"name": "PhotographicSensitivity",
"value": "400"
}
]
else: else:
print('ERROR: exiftool is not installed') print('ERROR: exiftool is not installed')
return return
@ -469,7 +516,8 @@ def convert_image_to_low_bandwidth(image_filename: str) -> None:
def process_meta_data(base_dir: str, nickname: str, domain: str, def process_meta_data(base_dir: str, nickname: str, domain: str,
image_filename: str, output_filename: str, image_filename: str, output_filename: str,
city: str, content_license_url: str) -> None: city: str, content_license_url: str,
exif_json: list[dict]) -> None:
"""Handles image metadata. This tries to spoof the metadata """Handles image metadata. This tries to spoof the metadata
if possible, but otherwise just removes it if possible, but otherwise just removes it
""" """
@ -478,7 +526,7 @@ def process_meta_data(base_dir: str, nickname: str, domain: str,
# now add some spoofed data to misdirect surveillance capitalists # now add some spoofed data to misdirect surveillance capitalists
_spoof_meta_data(base_dir, nickname, domain, output_filename, city, _spoof_meta_data(base_dir, nickname, domain, output_filename, city,
content_license_url) content_license_url, exif_json)
def _is_media(image_filename: str) -> bool: def _is_media(image_filename: str) -> bool:
@ -707,9 +755,15 @@ def attach_media(base_dir: str, http_prefix: str,
if media_type.startswith('image/'): if media_type.startswith('image/'):
if low_bandwidth: if low_bandwidth:
convert_image_to_low_bandwidth(image_filename) convert_image_to_low_bandwidth(image_filename)
exif_json: list[dict] = []
process_meta_data(base_dir, nickname, domain, process_meta_data(base_dir, nickname, domain,
image_filename, media_filename, city, image_filename, media_filename, city,
content_license_url) content_license_url, exif_json)
if exif_json:
# FEP-ee3a
# https://codeberg.org/fediverse/fep/src/branch/main/
# fep/ee3a/fep-ee3a.md
attachment_json['exifData'] = exif_json
else: else:
copyfile(image_filename, media_filename) copyfile(image_filename, media_filename)
_log_uploaded_media(base_dir, nickname, domain, media_filename) _log_uploaded_media(base_dir, nickname, domain, media_filename)

View File

@ -172,9 +172,10 @@ def set_profile_image(base_dir: str, http_prefix: str,
' -size ' + resolution + ' -quality 50 ' + \ ' -size ' + resolution + ' -quality 50 ' + \
safe_system_string(profile_filename) safe_system_string(profile_filename)
subprocess.call(cmd, shell=True) subprocess.call(cmd, shell=True)
exif_json: list[dict] = []
process_meta_data(base_dir, nickname, domain, process_meta_data(base_dir, nickname, domain,
profile_filename, profile_filename, city, profile_filename, profile_filename, city,
content_license_url) content_license_url, exif_json)
return True return True
return False return False

View File

@ -393,9 +393,10 @@ def add_share(base_dir: str,
continue continue
if low_bandwidth: if low_bandwidth:
convert_image_to_low_bandwidth(image_filename) convert_image_to_low_bandwidth(image_filename)
exif_json: list[dict] = []
process_meta_data(base_dir, nickname, domain, process_meta_data(base_dir, nickname, domain,
image_filename, item_idfile + '.' + ext, image_filename, item_idfile + '.' + ext,
city, content_license_url) city, content_license_url, exif_json)
if move_image: if move_image:
try: try:
os.remove(image_filename) os.remove(image_filename)