openstreetmap.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. # SPDX-License-Identifier: AGPL-3.0-or-later
  2. """
  3. OpenStreetMap (Map)
  4. """
  5. import re
  6. from json import loads
  7. from flask_babel import gettext
  8. # about
  9. about = {
  10. "website": 'https://www.openstreetmap.org/',
  11. "wikidata_id": 'Q936',
  12. "official_api_documentation": 'http://wiki.openstreetmap.org/wiki/Nominatim',
  13. "use_official_api": True,
  14. "require_api_key": False,
  15. "results": 'JSON',
  16. }
  17. # engine dependent config
  18. categories = ['map']
  19. paging = False
  20. # search-url
  21. base_url = 'https://nominatim.openstreetmap.org/'
  22. search_string = 'search/{query}?format=json&polygon_geojson=1&addressdetails=1'
  23. result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}'
  24. route_url = 'https://graphhopper.com/maps/?point={}&point={}&locale=en-US&vehicle=car&weighting=fastest&turn_costs=true&use_miles=false&layer=Omniscale' # noqa
  25. route_re = re.compile('(?:from )?(.+) to (.+)')
  26. # do search-request
  27. def request(query, params):
  28. params['url'] = base_url + search_string.format(query=query)
  29. params['route'] = route_re.match(query)
  30. return params
  31. # get response from search-request
  32. def response(resp):
  33. results = []
  34. json = loads(resp.text)
  35. if resp.search_params['route']:
  36. results.append({
  37. 'answer': gettext('Get directions'),
  38. 'url': route_url.format(*resp.search_params['route'].groups()),
  39. })
  40. # parse results
  41. for r in json:
  42. if 'display_name' not in r:
  43. continue
  44. title = r['display_name'] or ''
  45. osm_type = r.get('osm_type', r.get('type'))
  46. url = result_base_url.format(osm_type=osm_type,
  47. osm_id=r['osm_id'])
  48. osm = {'type': osm_type,
  49. 'id': r['osm_id']}
  50. geojson = r.get('geojson')
  51. # if no geojson is found and osm_type is a node, add geojson Point
  52. if not geojson and osm_type == 'node':
  53. geojson = {'type': 'Point', 'coordinates': [r['lon'], r['lat']]}
  54. address_raw = r.get('address')
  55. address = {}
  56. # get name
  57. if r['class'] == 'amenity' or\
  58. r['class'] == 'shop' or\
  59. r['class'] == 'tourism' or\
  60. r['class'] == 'leisure':
  61. if address_raw.get('address29'):
  62. address = {'name': address_raw.get('address29')}
  63. else:
  64. address = {'name': address_raw.get(r['type'])}
  65. # add rest of adressdata, if something is already found
  66. if address.get('name'):
  67. address.update({'house_number': address_raw.get('house_number'),
  68. 'road': address_raw.get('road'),
  69. 'locality': address_raw.get('city',
  70. address_raw.get('town', # noqa
  71. address_raw.get('village'))), # noqa
  72. 'postcode': address_raw.get('postcode'),
  73. 'country': address_raw.get('country'),
  74. 'country_code': address_raw.get('country_code')})
  75. else:
  76. address = None
  77. # append result
  78. results.append({'template': 'map.html',
  79. 'title': title,
  80. 'content': '',
  81. 'longitude': r['lon'],
  82. 'latitude': r['lat'],
  83. 'boundingbox': r['boundingbox'],
  84. 'geojson': geojson,
  85. 'address': address,
  86. 'osm': osm,
  87. 'url': url})
  88. # return results
  89. return results