Browse Source

Coordinates!

Douglas William Thrift 14 years ago
parent
commit
6bd18f2c41
1 changed files with 67 additions and 26 deletions
  1. 67 26
      locationbot.py

+ 67 - 26
locationbot.py

@@ -89,7 +89,8 @@ class LocationBot(ircbot.SingleServerIRCBot):
 			self.__reloading = True
 
 		self.__quiting = False
-		self.__variables = frozenset(['nick', 'secret', 'masks', 'channels', 'timezone', 'location', 'latitude'])
+		self.__variables = frozenset(['nick', 'secret', 'masks', 'channels', 'timezone', 'location', 'coordinates', 'latitude'])
+		self.__geocode = self.__variables.intersection(['location', 'coordinates'])
 		self.__lists = self.__variables.intersection(['masks', 'channels'])
 		self.__unsetable = self.__variables.difference(['nick', 'secret'])
 
@@ -196,28 +197,14 @@ class LocationBot(ircbot.SingleServerIRCBot):
 				new_location = locations.get(latitude)
 
 				if latitude not in locations:
-					url = 'http://www.google.com/latitude/apps/badge/api?' + urllib.urlencode({'user': latitude, 'type': 'json'})
-
-					try:
-						response = urllib2.urlopen(url)
-					except urllib2.URLError, error:
-						print error
-						continue
-
-					try:
-						geo = json.load(response)
-					except (TypeError, ValueError), error:
-						print error
-						continue
-
 					try:
-						feature = geo['features'][0]
+						feature = json.load(urllib2.urlopen('http://www.google.com/latitude/apps/badge/api?' + urllib.urlencode({'user': latitude, 'type': 'json'})))['features'][0]
 						coordinates = tuple(reversed(feature['geometry']['coordinates']))
 						properties = feature['properties']
 						new_location = properties['reverseGeocode']
 						locations[latitude] = new_location
 						updated = datetime.fromtimestamp(properties['timeStamp'], pytz.utc)
-					except (IndexError, KeyError), error:
+					except Exception, error:
 						print error
 						continue
 
@@ -389,7 +376,7 @@ class LocationBot(ircbot.SingleServerIRCBot):
 			connection.privmsg(nick, '\x02variable    value\x0f')
 
 			for variable, value in zip(variables, cursor.fetchone()):
-				connection.privmsg(nick, '%-8s    %s' % (variable, ' '.join(value) if isinstance(value, list) else value))
+				connection.privmsg(nick, '%-11s %s' % (variable, ' '.join(value) if isinstance(value, list) else '%f,%f' % value if isinstance(value, tuple) else value))
 		else:
 			def invalid(value, variable = variable):
 				connection.privmsg(nick, 'invalid %s ("%s")' % (variable, value))
@@ -412,10 +399,62 @@ class LocationBot(ircbot.SingleServerIRCBot):
 					value = int(re.sub(r'^(?:http://(?:www\.)?google\.com/latitude/apps/badge/api\?user=)?([0-9]+)(?:&type=.*)?$', r'\1', value))
 				except ValueError:
 					return invalid(value)
-			elif variable == 'location':
+			elif variable in self.__geocode:
 				cursor.execute('select channels, location from locationbot.nick where nick = %s', (login,))
 
-				channels, location = cursor.fetchone()
+				channels, old_location = cursor.fetchone()
+				parameters = {'sensor': 'false'}
+
+				if variable == 'location':
+					parameters['address'] = value
+				else:
+					coordinates = value.split(None, 1)
+
+					if len(coordinates) == 1:
+						coordinates = coordinates[0].split(',', 1)
+
+					try:
+						coordinates = tuple(map(lambda a: float(a), coordinates))
+					except ValueError:
+						return invalid(value)
+
+					parameters['latlng'] = '%f,%f' % coordinates
+
+				geocode = json.load(urllib2.urlopen('http://maps.google.com/maps/api/geocode/json?' + urllib.urlencode(parameters)))
+				status = geocode['status']
+
+				if status != 'OK':
+					if status == 'ZERO_RESULTS':
+						return invalid(value)
+					else:
+						raise Exception(status)
+
+				results = geocode['results']
+				result = results[0]
+				new_location = result['formatted_address']
+
+				if variable == 'location':
+					location = result['geometry']['location']
+					coordinates = (location['lat'], location['lng'])
+					value = new_location
+				else:
+					types = frozenset([
+						'country',
+						'administrative_area_level_1',
+						'administrative_area_level_2',
+						'administrative_area_level_3',
+						'colloquial_area',
+						'locality',
+						'sublocality',
+						'neighborhood',
+					])
+
+					for result in results:
+						if not types.isdisjoint(result['types']):
+							new_location = result['formatted_address']
+							break
+
+					value = coordinates
 			elif variable == 'nick':
 				_nick = value.split(None, 1)
 
@@ -426,7 +465,7 @@ class LocationBot(ircbot.SingleServerIRCBot):
 					return invalid(value)
 
 			try:
-				cursor.execute('update locationbot.nick set ' + variable + ' = ' + ('md5(%s)' if variable == 'secret' else '%s') + (', coordinates = null, updated = now()' if variable == 'location' else '') + ' where nick = %s', (value, login))
+				cursor.execute('update locationbot.nick set ' + ('location = %s, coordinates = point %s, updated = now()' if variable in self.__geocode else variable + ' = ' + ('md5(%s)' if variable == 'secret' else '%s')) + ' where nick = %s', (new_location, coordinates, login) if variable in self.__geocode else (value, login))
 				db.commit()
 			except psycopg2.IntegrityError:
 				if variable == 'nick':
@@ -436,10 +475,10 @@ class LocationBot(ircbot.SingleServerIRCBot):
 
 			if variable == 'nick':
 				self.__logins[nick] = (value, nickmask)
-			elif variable == 'location':
-				self.__location(nick, channels, location, value)
+			elif variable in self.__geocode:
+				self.__location(nick, channels, old_location, new_location, coordinates)
 
-			connection.privmsg(nick, 'variable ("%s") successfully set to value ("%s")' % (variable, ' '.join(value) if isinstance(value, list) else value))
+			connection.privmsg(nick, 'variable ("%s") successfully set to value ("%s")' % (variable, ' '.join(value) if isinstance(value, list) else '%f,%f' % value if isinstance(value, tuple) else value))
 
 	def __status(self, connection, nick, login, arguments):
 		_nick = arguments.split(None, 1)[0] if arguments else None
@@ -484,7 +523,7 @@ class LocationBot(ircbot.SingleServerIRCBot):
 
 		db, cursor = self.__db()
 
-		cursor.execute('update locationbot.nick set ' + variable + ' = null' + (', coordinates = null, updated = null' if variable == 'location' else '') + ' where nick = %s and ' + variable + ' is not null', (login,))
+		cursor.execute('update locationbot.nick set ' + ('location = null, coordinates = null, updated = null' if variable in self.__geocode else variable + ' = null') + ' where nick = %s and ' + variable + ' is not null', (login,))
 		db.commit()
 		connection.privmsg(nick, 'variable ("%s") %s unset' % (variable, 'successfuly' if cursor.rowcount == 1 else 'already'))
 
@@ -602,7 +641,7 @@ class LocationBot(ircbot.SingleServerIRCBot):
 				self.__who(connection, nick)
 			else:
 				self.__unknown(connection, nick, command)
-		except psycopg2.Error, error:
+		except Exception, error:
 			print error
 
 			connection.privmsg(nick, 'an error occurred')
@@ -679,6 +718,8 @@ if __name__ == '__main__':
 
 	try:
 		while bot.start():
+			import locationbot
+
 			try:
 				bot = reload(locationbot).LocationBot(bot)
 			except (ImportError, SyntaxError), error: