from geopy.geocoders import Nominatim from nio import RoomMessageUnknown from modules.common.module import BotModule class MatrixModule(BotModule): def __init__(self, name): super().__init__(name) self.bot = None self.enabled_rooms = [] def matrix_start(self, bot): super().matrix_start(bot) self.bot = bot bot.client.add_event_callback(self.unknown_cb, RoomMessageUnknown) def matrix_stop(self, bot): super().matrix_stop(bot) bot.remove_callback(self.unknown_cb) ''' Location events are like: https://spec.matrix.org/v1.2/client-server-api/#mlocation { "content": { "body": "geo:61.49342512194717,23.765914658307736", "geo_uri": "geo:61.49342512194717,23.765914658307736", "msgtype": "m.location", "org.matrix.msc1767.text": "geo:61.49342512194717,23.765914658307736", "org.matrix.msc3488.asset": { "type": "m.pin" }, "org.matrix.msc3488.location": { "description": "geo:61.49342512194717,23.765914658307736", "uri": "geo:61.49342512194717,23.765914658307736" }, "org.matrix.msc3488.ts": 1653837929839 }, "room_id": "!xsBGdLYGrfYhGfLtHG:hacklab.fi", "type": "m.room.message" } BUT sometimes there's ; separating altitude?? { "content": { "body": "geo:61.4704211,23.4864855;36.900001525878906", "geo_uri": "geo:61.4704211,23.4864855;36.900001525878906", "msgtype": "m.location", "org.matrix.msc1767.text": "geo:61.4704211,23.4864855;36.900001525878906", "org.matrix.msc3488.asset": { "type": "m.self" }, "org.matrix.msc3488.location": { "description": "geo:61.4704211,23.4864855;36.900001525878906", "uri": "geo:61.4704211,23.4864855;36.900001525878906" }, "org.matrix.msc3488.ts": 1653931683087 }, "origin_server_ts": 1653931683998, "sender": "@cos:hacklab.fi", "type": "m.room.message", "unsigned": { "age": 70 }, "event_id": "$6xXutKF9EppPMMdc4aQLZjHyd8My0rIZuNZEcuSIPws", "room_id": "!CLofqdurVWZCMpFnqM:hacklab.fi" } ''' async def unknown_cb(self, room, event): if event.msgtype != 'm.location': return if room.room_id not in self.enabled_rooms: return location_text = event.content['body'] # Fallback if body is empty if (len(location_text) == 0) or ('geo:' in location_text): location_text = 'location' sender_response = await self.bot.client.get_displayname(event.sender) sender = sender_response.displayname geo_uri = event.content['geo_uri'] try: geo_uri = geo_uri[4:] # Strip geo: if ';' in geo_uri: # Strip altitude, if present geo_uri = geo_uri.split(';')[0] latlon = geo_uri.split(',') # Sanity checks to avoid url manipulation float(latlon[0]) float(latlon[1]) except Exception: self.bot.send_text(room, "Error: Invalid location " + geo_uri) return osm_link = f"https://www.openstreetmap.org/?mlat={latlon[0]}&mlon={latlon[1]}" plain = f'{sender} sent {location_text} {osm_link} 🚩' html = f'{sender} sent {location_text} 🚩' await self.bot.send_html(room, html, plain) async def matrix_message(self, bot, room, event): args = event.body.split() args.pop(0) if len(args) == 0: await bot.send_text(room, 'Usage: !loc ') return elif len(args) == 1: if args[0] == 'enable': bot.must_be_admin(room, event) self.enabled_rooms.append(room.room_id) self.enabled_rooms = list(dict.fromkeys(self.enabled_rooms)) # Deduplicate await bot.send_text(room, "Ok, sending locations events here as text versions") bot.save_settings() return if args[0] == 'disable': bot.must_be_admin(room, event) self.enabled_rooms.remove(room.room_id) await bot.send_text(room, "Ok, disabled here") bot.save_settings() return query = event.body[4:] geolocator = Nominatim(user_agent=bot.appid) self.logger.info('loc: looking up %s ..', query) location = geolocator.geocode(query) self.logger.info('loc rx %s', location) if location: await bot.send_location(room, location.address, location.latitude, location.longitude, "m.pin") else: await bot.send_text(room, "Can't find " + query + " on map!") def help(self): return 'Search for locations and display Matrix location events as OSM links' def get_settings(self): data = super().get_settings() data["enabled_rooms"] = self.enabled_rooms return data def set_settings(self, data): super().set_settings(data) if data.get("enabled_rooms"): self.enabled_rooms = data["enabled_rooms"]