"""Look up geolocation information for media objects.""" from os import path from ConfigParser import ConfigParser import fractions import requests import urllib from elodie import constants from elodie.localstorage import Db class Fraction(fractions.Fraction): """Only create Fractions from floats. Should be compatible with Python 2.6, though untested. >>> Fraction(0.3) Fraction(3, 10) >>> Fraction(1.1) Fraction(11, 10) """ def __new__(cls, value, ignore=None): return fractions.Fraction.from_float(value).limit_denominator(99999) def coordinates_by_name(name): # Try to get cached location first db = Db() cached_coordinates = db.get_location_coordinates(name) if(cached_coordinates is not None): return { 'latitude': cached_coordinates[0], 'longitude': cached_coordinates[1] } # If the name is not cached then we go ahead with an API lookup geolocation_info = lookup(name) if(geolocation_info is not None): if( 'results' in geolocation_info and len(geolocation_info['results']) != 0 and 'locations' in geolocation_info['results'][0] and len(geolocation_info['results'][0]['locations']) != 0 ): # By default we use the first entry unless we find one with # geocodeQuality=city. geolocation_result = geolocation_info['results'][0] use_location = geolocation_result['locations'][0]['latLng'] # Loop over the locations to see if we come accross a # geocodeQuality=city. # If we find a city we set that to the use_location and break for location in geolocation_result['locations']: if( 'latLng' in location and 'lat' in location['latLng'] and 'lng' in location['latLng'] and location['geocodeQuality'].lower() == 'city' ): use_location = location['latLng'] break return { 'latitude': use_location['lat'], 'longitude': use_location['lng'] } return None def decimal_to_dms(decimal): decimal = float(decimal) decimal_abs = abs(decimal) minutes, seconds = divmod(decimal_abs*3600, 60) degrees, minutes = divmod(minutes, 60) degrees = degrees sign = 1 if decimal >= 0 else -1 return (degrees, minutes, seconds, sign) def dms_to_decimal(degrees, minutes, seconds, direction=' '): sign = 1 if(direction[0] in 'WSws'): sign = -1 return ( float(degrees) + float(minutes) / 60 + float(seconds) / 3600 ) * sign def dms_string(decimal, type='latitude'): # Example string -> 38 deg 14' 27.82" S dms = decimal_to_dms(decimal) if type == 'latitude': direction = 'N' if decimal >= 0 else 'S' elif type == 'longitude': direction = 'E' if decimal >= 0 else 'W' return '{} deg {}\' {}" {}'.format(dms[0], dms[1], dms[2], direction) def get_key(): config_file = '%s/config.ini' % constants.application_directory if not path.exists(config_file): return None config = ConfigParser() config.read(config_file) if('MapQuest' not in config.sections()): return None return config.get('MapQuest', 'key') def place_name(lat, lon): # Convert lat/lon to floats if not isinstance(lat, float): lat = float(lat) if not isinstance(lon, float): lon = float(lon) # Try to get cached location first db = Db() # 3km distace radious for a match cached_place_name = db.get_location_name(lat, lon, 3000) if(cached_place_name is not None): return cached_place_name lookup_place_name = None geolocation_info = reverse_lookup(lat, lon) if(geolocation_info is not None): if('address' in geolocation_info): address = geolocation_info['address'] if('city' in address): lookup_place_name = address['city'] elif('state' in address): lookup_place_name = address['state'] elif('country' in address): lookup_place_name = address['country'] if(lookup_place_name is not None): db.add_location(lat, lon, lookup_place_name) # TODO: Maybe this should only be done on exit and not for every write. db.update_location_db() return lookup_place_name def reverse_lookup(lat, lon): if(lat is None or lon is None): return None key = get_key() try: params = {'format': 'json', 'key': key, 'lat': lat, 'lon': lon} headers = {"Accept-Language": constants.accepted_language} r = requests.get( 'http://open.mapquestapi.com/nominatim/v1/reverse.php?%s' % urllib.urlencode(params), headers=headers ) return r.json() except requests.exceptions.RequestException as e: if(constants.debug is True): print e return None except ValueError as e: if(constants.debug is True): print r.text print e return None def lookup(name): if(name is None or len(name) == 0): return None key = get_key() try: params = {'format': 'json', 'key': key, 'location': name} if(constants.debug is True): print 'http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params) # noqa r = requests.get( 'http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params) ) return r.json() except requests.exceptions.RequestException as e: if(constants.debug is True): print e return None except ValueError as e: if(constants.debug is True): print r.text print e return None