diff --git a/daemon.py b/daemon.py index 671e2caec..5abe4bb91 100644 --- a/daemon.py +++ b/daemon.py @@ -403,7 +403,7 @@ from crawlers import blocked_user_agent from crawlers import load_known_web_bots from qrcode import save_domain_qrcode from importFollowing import run_import_following_watchdog -from maps import kml_from_tagmaps_path +from maps import map_format_from_tagmaps_path import os @@ -3853,7 +3853,10 @@ class PubServer(BaseHTTPRequestHandler): search_str = search_str.split('&')[0] search_str = \ urllib.parse.unquote_plus(search_str.strip()) - search_str = search_str.lower().strip() + search_str = search_str.strip() + # hashtags can be combined case + if not search_str.startswith('#'): + search_str = search_str.lower() print('search_str: ' + search_str) if search_for_emoji: search_str = ':' + search_str + ':' @@ -3898,7 +3901,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, timezone, bold_reading, - self.server.dogwhistles) + self.server.dogwhistles, + self.server.map_format) if hashtag_str: msg = hashtag_str.encode('utf-8') msglen = len(msg) @@ -8601,7 +8605,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, timezone, bold_reading, - self.server.dogwhistles) + self.server.dogwhistles, + self.server.map_format) if hashtag_str: msg = hashtag_str.encode('utf-8') msglen = len(msg) @@ -17091,12 +17096,18 @@ class PubServer(BaseHTTPRequestHandler): # hashtag map kml if self.path.startswith('/tagmaps/') or \ (authorized and '/tagmaps/' in self.path): - kml_str = kml_from_tagmaps_path(self.server.base_dir, self.path) - if kml_str: - msg = kml_str.encode('utf-8') + map_str = \ + map_format_from_tagmaps_path(self.server.base_dir, self.path, + self.server.map_format) + if map_str: + msg = map_str.encode('utf-8') msglen = len(msg) - header_type = \ - 'application/vnd.google-earth.kml+xml; charset=utf-8' + if self.server.map_format == 'gpx': + header_type = \ + 'application/gpx+xml; charset=utf-8' + else: + header_type = \ + 'application/vnd.google-earth.kml+xml; charset=utf-8' self._set_headers(header_type, msglen, None, calling_domain, True) self._write(msg) @@ -20823,7 +20834,8 @@ def load_tokens(base_dir: str, tokens_dict: {}, tokens_lookup: {}) -> None: break -def run_daemon(clacks: str, +def run_daemon(map_format: str, + clacks: str, preferred_podcast_formats: [], check_actor_timeout: int, crawlers_allowed: [], @@ -20948,6 +20960,9 @@ def run_daemon(clacks: str, httpd.vcard_is_active = False httpd.masto_api_is_active = False + # use kml or gpx format for hashtag maps + httpd.map_format = map_format.lower() + httpd.dyslexic_font = dyslexic_font # license for content of the instance diff --git a/epicyon.py b/epicyon.py index c1752ad89..a80a62e6c 100644 --- a/epicyon.py +++ b/epicyon.py @@ -735,6 +735,9 @@ def _command_options() -> None: help='Category of item being shared') parser.add_argument('--location', dest='location', type=str, default=None, help='Location/City of item being shared') + parser.add_argument('--mapFormat', dest='mapFormat', type=str, + default='kml', + help='Format for hashtag maps GPX/KML') parser.add_argument('--duration', dest='duration', type=str, default=None, help='Duration for which to share an item') parser.add_argument('--registration', dest='registration', type=str, @@ -3380,6 +3383,12 @@ def _command_options() -> None: if not registration: registration = False + map_format = get_config_param(base_dir, 'mapFormat') + if map_format: + argb.mapFormat = map_format + else: + set_config_param(base_dir, 'mapFormat', argb.mapFormat) + minimumvotes = get_config_param(base_dir, 'minvotes') if minimumvotes: argb.minimumvotes = int(minimumvotes) @@ -3626,7 +3635,8 @@ def _command_options() -> None: if __name__ == "__main__": argb2, opt2 = _command_options() print('allowdeletion: ' + str(argb2.allowdeletion)) - run_daemon(argb2.clacks, + run_daemon(argb2.mapFormat, + argb2.clacks, opt2['preferred_podcast_formats'], argb2.check_actor_timeout, opt2['crawlers_allowed'], diff --git a/maps.py b/maps.py index 5a6eafac7..17a23ab03 100644 --- a/maps.py +++ b/maps.py @@ -526,20 +526,81 @@ def _hashtag_map_to_kml(base_dir: str, tag_name: str, return kml_str -def _hashtag_map_kml_within_hours(base_dir: str, tag_name: str, - hours: int) -> str: - """Returns kml for a hashtag containing maps for the last number of hours +def _hashtag_map_to_gpx(base_dir: str, tag_name: str, + start_hours_since_epoch: int, + end_hours_since_epoch: int) -> str: + """Returns the GPX for a given hashtag between the given times + """ + place_ctr = 0 + osm_domain = 'openstreetmap.org' + tag_map_filename = base_dir + '/tagmaps/' + tag_name + '.txt' + + gpx_str = '\n' + gpx_str += '\n' + + if os.path.isfile(tag_map_filename): + map_links = [] + try: + with open(tag_map_filename, 'r', encoding='utf-8') as fp_tag: + map_links = fp_tag.read().split('\n') + except OSError: + print('EX: unable to read tag map links ' + tag_map_filename) + if map_links: + start_secs_since_epoch = int(start_hours_since_epoch * 60 * 60) + end_secs_since_epoch = int(end_hours_since_epoch * 60 * 60) + for link_line in map_links: + link_line = link_line.strip().split(' ') + if len(link_line) < 3: + continue + secs_since_epoch = int(link_line[0]) + if secs_since_epoch < start_secs_since_epoch or \ + secs_since_epoch > end_secs_since_epoch: + continue + map_link = link_line[1] + zoom, latitude, longitude = \ + geocoords_from_map_link(map_link, osm_domain) + if not zoom: + continue + if not latitude: + continue + if not longitude: + continue + post_id = link_line[2] + place_ctr += 1 + gpx_str += '\n' + gpx_str += ' ' + post_id + '\n' + gpx_str += ' \n' + gpx_str += '\n' + + gpx_str += '' + if place_ctr == 0: + return None + return gpx_str + + +def _hashtag_map_within_hours(base_dir: str, tag_name: str, + hours: int, map_format: str) -> str: + """Returns gpx/kml for a hashtag containing maps for the + last number of hours """ secs_since_epoch = \ int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds()) - end_hours_since_epoch = int(secs_since_epoch / (60 * 60)) - start_hours_since_epoch = end_hours_since_epoch - hours - kml_str = \ - _hashtag_map_to_kml(base_dir, tag_name, - start_hours_since_epoch, - end_hours_since_epoch) - return kml_str + curr_hours_since_epoch = int(secs_since_epoch / (60 * 60)) + start_hours_since_epoch = curr_hours_since_epoch - abs(hours) + end_hours_since_epoch = curr_hours_since_epoch + 2 + if map_format == 'gpx': + map_str = \ + _hashtag_map_to_gpx(base_dir, tag_name, + start_hours_since_epoch, + end_hours_since_epoch) + else: + map_str = \ + _hashtag_map_to_kml(base_dir, tag_name, + start_hours_since_epoch, + end_hours_since_epoch) + return map_str def _get_tagmaps_time_periods() -> {}: @@ -560,8 +621,9 @@ def _get_tagmaps_time_periods() -> {}: } -def kml_from_tagmaps_path(base_dir: str, path: str) -> str: - """Returns kml for a given tagmaps path +def map_format_from_tagmaps_path(base_dir: str, path: str, + map_format: str) -> str: + """Returns gpx/kml for a given tagmaps path /tagmaps/tagname-time_period """ if '/tagmaps/' not in path: @@ -577,13 +639,13 @@ def kml_from_tagmaps_path(base_dir: str, path: str) -> str: endpoint_str = \ '/tagmaps/' + tag_name + '-' + period_str2.replace(' ', '_') if path == endpoint_str: - return _hashtag_map_kml_within_hours(base_dir, tag_name, - abs(hours)) + return _hashtag_map_within_hours(base_dir, tag_name, + hours, map_format) return None def html_hashtag_maps(base_dir: str, tag_name: str, - translate: {}) -> str: + translate: {}, map_format: str) -> str: """Returns html for maps associated with a hashtag """ tag_map_filename = base_dir + '/tagmaps/' + tag_name + '.txt' @@ -593,21 +655,22 @@ def html_hashtag_maps(base_dir: str, tag_name: str, time_period = _get_tagmaps_time_periods() html_str = '' - kml_str = None + map_str = None for period_str, hours in time_period.items(): - new_kml_str = \ - _hashtag_map_kml_within_hours(base_dir, tag_name, abs(hours)) - if not new_kml_str: + new_map_str = \ + _hashtag_map_within_hours(base_dir, tag_name, hours, + map_format) + if not new_map_str: continue - if new_kml_str == kml_str: + if new_map_str == map_str: continue - kml_str = new_kml_str + map_str = new_map_str period_str2 = period_str.replace('Last ', '').lower() endpoint_str = \ '/tagmaps/' + tag_name + '-' + period_str2.replace(' ', '_') download_filename = \ (tag_name + '-' + - period_str.lower()).replace(' ', '_') + '.kml' + period_str.lower()).replace(' ', '_') + '.' + map_format if html_str: html_str += ' ' description = period_str @@ -617,5 +680,5 @@ def html_hashtag_maps(base_dir: str, tag_name: str, '" download="' + download_filename + '">' + \ description + '' if html_str: - html_str = '
🌍 ' + html_str + '
\n' + html_str = '🌍 ' + html_str return html_str diff --git a/tests.py b/tests.py index 3db7589d9..3dcb75603 100644 --- a/tests.py +++ b/tests.py @@ -841,8 +841,10 @@ def create_server_alice(path: str, domain: str, port: int, check_actor_timeout = 2 preferred_podcast_formats = None clacks = None + map_format = 'gpx' print('Server running: Alice') - run_daemon(clacks, preferred_podcast_formats, + run_daemon(map_format, + clacks, preferred_podcast_formats, check_actor_timeout, crawlers_allowed, dyslexic_font, @@ -1002,8 +1004,10 @@ def create_server_bob(path: str, domain: str, port: int, check_actor_timeout = 2 preferred_podcast_formats = None clacks = None + map_format = 'gpx' print('Server running: Bob') - run_daemon(clacks, preferred_podcast_formats, + run_daemon(map_format, + clacks, preferred_podcast_formats, check_actor_timeout, crawlers_allowed, dyslexic_font, @@ -1085,8 +1089,10 @@ def create_server_eve(path: str, domain: str, port: int, federation_list: [], check_actor_timeout = 2 preferred_podcast_formats = None clacks = None + map_format = 'gpx' print('Server running: Eve') - run_daemon(clacks, preferred_podcast_formats, + run_daemon(map_format, + clacks, preferred_podcast_formats, check_actor_timeout, crawlers_allowed, dyslexic_font, @@ -1170,8 +1176,10 @@ def create_server_group(path: str, domain: str, port: int, check_actor_timeout = 2 preferred_podcast_formats = None clacks = None + map_format = 'gpx' print('Server running: Group') - run_daemon(clacks, preferred_podcast_formats, + run_daemon(map_format, + clacks, preferred_podcast_formats, check_actor_timeout, crawlers_allowed, dyslexic_font, diff --git a/webapp_search.py b/webapp_search.py index 333471058..6fc10788a 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -738,7 +738,7 @@ def html_hashtag_search(nickname: str, domain: str, port: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, timezone: str, bold_reading: bool, - dogwhistles: {}) -> str: + dogwhistles: {}, map_format: str) -> str: """Show a page containing search results for a hashtag or after selecting a hashtag from the swarm """ @@ -792,18 +792,24 @@ def html_hashtag_search(nickname: str, domain: str, port: int, if nickname: hashtag_search_form += '
\n' + \ '

#' + \ - hashtag + '

\n' + hashtag + '' else: hashtag_search_form += '
\n' + \ - '

#' + hashtag + '

\n' + '

#' + hashtag # RSS link for hashtag feed - hashtag_search_form += '' + hashtag_search_form += ' ' hashtag_search_form += \ '

\n' + 'icons/logorss.png" />\n' + + # maps for geolocations with this hashtag + maps_str = html_hashtag_maps(base_dir, hashtag, translate, map_format) + if maps_str: + maps_str = '
' + maps_str + '
\n' + hashtag_search_form += maps_str # edit the category for this hashtag if is_editor(base_dir, nickname): @@ -825,8 +831,6 @@ def html_hashtag_search(nickname: str, domain: str, port: int, hashtag_search_form += ' \n' hashtag_search_form += '\n' - hashtag_search_form += html_hashtag_maps(base_dir, hashtag, translate) - if start_index > 0: # previous page link hashtag_search_form += \