Example #1
0
 def open_connection(self, token=None):
     self.cached_data = {}
     refresh_token = self.get_password()
     if not refresh_token:
         return False
     if not token:
         # create expired token
         token = {
             'access_token': 'xxx',
             'refresh_token': refresh_token,
             'expires_in': -30,
         }
     client_id = key_store.get('googlephotos', 'client_id')
     client_secret = key_store.get('googlephotos', 'client_secret')
     auto_refresh_kwargs = {
         'client_id': client_id,
         'client_secret': client_secret,
     }
     token_url = self.oauth_url + 'v4/token'
     self.api = OAuth2Session(client_id=client_id,
                              token=token,
                              token_updater=self.save_token,
                              auto_refresh_kwargs=auto_refresh_kwargs,
                              auto_refresh_url=token_url)
     if token['expires_in'] < 0:
         # refresh token
         self.api.refresh_token(token_url, **auto_refresh_kwargs)
     self.connection_changed.emit(self.api.authorized)
     return self.api.authorized
Example #2
0
 def get_auth_url(self, level):
     logger.info('using %s', keyring.get_keyring().__module__)
     api_key    = key_store.get('flickr', 'api_key')
     api_secret = key_store.get('flickr', 'api_secret')
     token = flickrapi.auth.FlickrAccessToken('', '', self.perms[level])
     self.api = flickrapi.FlickrAPI(
         api_key, api_secret, token=token, store_token=False)
     self.api.get_request_token(oauth_callback='oob')
     return self.api.auth_url(perms=self.perms[level])
Example #3
0
 def get_auth_url(self, level):
     logger.info('using %s', keyring.get_keyring().__module__)
     api_key    = key_store.get('flickr', 'api_key')
     api_secret = key_store.get('flickr', 'api_secret')
     token = flickrapi.auth.FlickrAccessToken('', '', self.perms[level])
     self.api = flickrapi.FlickrAPI(
         api_key, api_secret, token=token, store_token=False)
     self.api.get_request_token(oauth_callback='oob')
     return self.api.auth_url(perms=self.perms[level])
Example #4
0
 def get_access_token(self, auth_code):
     # Fix for requests-oauthlib bug #157
     # https://github.com/requests/requests-oauthlib/issues/157
     os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = 'True'
     client_id = key_store.get('picasa', 'client_id')
     client_secret = key_store.get('picasa', 'client_secret')
     self.token = self.session.fetch_token(
         self.token_url, code=auth_code,
         auth=requests.auth.HTTPBasicAuth(client_id, client_secret))
     self._save_token(self.token)
     self.session = None
Example #5
0
 def get_access_token(self, auth_code):
     # Fix for requests-oauthlib bug #157
     # https://github.com/requests/requests-oauthlib/issues/157
     os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = 'True'
     client_id = key_store.get('picasa', 'client_id')
     client_secret = key_store.get('picasa', 'client_secret')
     self.token = self.session.fetch_token(
         self.token_url, code=auth_code,
         auth=requests.auth.HTTPBasicAuth(client_id, client_secret))
     self._save_token(self.token)
     self.session = None
Example #6
0
 def get_auth_url(self, level):
     api_key = key_store.get('flickr', 'api_key')
     api_secret = key_store.get('flickr', 'api_secret')
     token = flickrapi.auth.FlickrAccessToken('', '', 'write')
     self.api = flickrapi.FlickrAPI(api_key,
                                    api_secret,
                                    token=token,
                                    store_token=False,
                                    format='parsed-json')
     self.api.get_request_token(oauth_callback='oob')
     return self.api.auth_url(perms='write')
Example #7
0
 def permitted(self, level):
     stored_token = keyring.get_password('photini', 'flickr')
     if not stored_token:
         self.api = None
         return False
     if not self.api:
         api_key    = key_store.get('flickr', 'api_key')
         api_secret = key_store.get('flickr', 'api_secret')
         token, token_secret = stored_token.split('&')
         token = flickrapi.auth.FlickrAccessToken(
             token, token_secret, self.perms[level])
         self.api = flickrapi.FlickrAPI(
             api_key, api_secret, token=token, store_token=False)
     return self.api.token_valid(perms=self.perms[level])
Example #8
0
 def permitted(self, level):
     stored_token = keyring.get_password('photini', 'flickr')
     if not stored_token:
         self.api = None
         return False
     if not self.api:
         api_key    = key_store.get('flickr', 'api_key')
         api_secret = key_store.get('flickr', 'api_secret')
         token, token_secret = stored_token.split('&')
         token = flickrapi.auth.FlickrAccessToken(
             token, token_secret, self.perms[level])
         self.api = flickrapi.FlickrAPI(
             api_key, api_secret, token=token, store_token=False)
     return self.api.token_valid(perms=self.perms[level])
Example #9
0
class TabWidget(PhotiniMap):
    api_key = key_store.get('bingmap', 'api_key')

    @staticmethod
    def tab_name():
        return translate('MapTabBing', 'Map (&Bing)')

    def get_geocoder(self):
        return BingGeocoder(parent=self)

    def get_head(self):
        url = 'http://www.bing.com/api/maps/mapcontrol?callback=initialize'
        url += '&key=' + self.api_key
        lang, encoding = locale.getdefaultlocale()
        if lang:
            culture = lang.replace('_', '-')
            url += '&setMkt=' + culture
            language, sep, region = culture.partition('-')
            url += '&setLang=' + language
        if self.app.options.test:
            url += '&branch=experimental'
        return '''    <script type="text/javascript"
      src="{}" async>
    </script>'''.format(url)

    @catch_all
    def new_status(self, status):
        super(TabWidget, self).new_status(status)
        if 'session_id' in status:
            # use map session key to make API calls non-billable
            self.geocoder.api_key = status['session_id']
Example #10
0
 def __init__(self, *arg, **kw):
     super(OpenStreetMap, self).__init__(*arg, **kw)
     self.block_timer = QtCore.QTimer(self)
     self.block_timer.setInterval(10000)
     self.block_timer.setSingleShot(True)
     self.block_timer.timeout.connect(self.enable_search)
     self.api_key = key_store.get('opencagedata', 'api_key')
Example #11
0
 def permitted(self, level):
     refresh_token = keyring.get_password('photini', 'picasa')
     if not refresh_token:
         self.session = None
         self.token = None
         return False
     if not self.token:
         # create expired token
         self.token = {
             'access_token': 'xxx',
             'refresh_token': refresh_token,
             'expires_in': -30,
         }
         self.session = None
     if not self.session:
         # create new session
         client_id = key_store.get('picasa', 'client_id')
         client_secret = key_store.get('picasa', 'client_secret')
         auto_refresh_kwargs = {
             'client_id': client_id,
             'client_secret': client_secret,
         }
         if self.auto_refresh:
             self.session = OAuth2Session(
                 client_id,
                 token=self.token,
                 token_updater=self._save_token,
                 auto_refresh_kwargs=auto_refresh_kwargs,
                 auto_refresh_url=self.token_url,
             )
         else:
             self.session = OAuth2Session(client_id, token=self.token)
         self.session.verify = certifi.old_where()
         # refresh manually to get a valid token now
         self.token = self.session.refresh_token(self.token_url,
                                                 **auto_refresh_kwargs)
         self.session.headers.update({'GData-Version': '2'})
         # verify the token
         resp = self._check_response(
             self.session.get(
                 'https://www.googleapis.com/oauth2/v3/tokeninfo',
                 params={'access_token':
                         self.token['access_token']})).json()
         if resp['scope'] != self.scope[level] or resp['aud'] != client_id:
             return False
     return True
Example #12
0
 def permitted(self, level):
     stored_token = self.get_password()
     if not stored_token:
         self.api = None
         return False
     if not self.api:
         api_key = key_store.get('flickr', 'api_key')
         api_secret = key_store.get('flickr', 'api_secret')
         token, token_secret = stored_token.split('&')
         token = flickrapi.auth.FlickrAccessToken(token, token_secret,
                                                  'write')
         self.api = flickrapi.FlickrAPI(api_key,
                                        api_secret,
                                        token=token,
                                        store_token=False,
                                        format='parsed-json')
     return self.api.token_valid(perms='write')
Example #13
0
 def get_auth_url(self, level):
     logger.info('using %s', keyring.get_keyring().__module__)
     client_id = key_store.get('picasa', 'client_id')
     self.session = OAuth2Session(
         client_id, scope=self.scope[level],
         redirect_uri='urn:ietf:wg:oauth:2.0:oob')
     return self.session.authorization_url(
         'https://accounts.google.com/o/oauth2/v2/auth')[0]
Example #14
0
 def get_auth_url(self, level):
     logger.info('using %s', keyring.get_keyring().__module__)
     client_id = key_store.get('picasa', 'client_id')
     self.session = OAuth2Session(client_id,
                                  scope=self.scope[level],
                                  redirect_uri='urn:ietf:wg:oauth:2.0:oob')
     return self.session.authorization_url(
         'https://accounts.google.com/o/oauth2/v2/auth')[0]
Example #15
0
 def get_auth_url(self, redirect_uri):
     code_verifier = ''
     while len(code_verifier) < 43:
         code_verifier += OAuth2Session().new_state()
     self.auth_params = {
         'client_id': key_store.get('googlephotos', 'client_id'),
         'client_secret': key_store.get('googlephotos', 'client_secret'),
         'code_verifier': code_verifier,
         'redirect_uri': redirect_uri,
     }
     url = 'https://accounts.google.com/o/oauth2/v2/auth'
     url += '?client_id=' + self.auth_params['client_id']
     url += '&redirect_uri=' + self.auth_params['redirect_uri']
     url += '&response_type=code'
     url += '&scope=' + urllib.parse.quote(' '.join(self.scope))
     url += '&code_challenge=' + self.auth_params['code_verifier']
     return url
Example #16
0
class GoogleGeocoder(GeocoderBase):
    api_key = key_store.get('googlemap', 'api_key')
    interval = 50

    def query(self, url, params):
        params['key'] = self.api_key
        with Busy():
            self.rate_limit()
            try:
                rsp = requests.get(url, params=params, timeout=5)
            except Exception as ex:
                logger.error(str(ex))
                return []
        rsp = rsp.json()
        if rsp['status'] != 'OK':
            if 'error_message' in rsp:
                logger.error('Search error: %s: %s', rsp['status'],
                             rsp['error_message'])
            else:
                logger.error('Search error: %s', rsp['status'])
            return []
        results = rsp['results']
        if not results:
            logger.error('No results found')
            return []
        return results

    def get_altitude(self, coords):
        params = {'locations': coords.replace(' ', '')}
        results = self.query(
            'https://maps.googleapis.com/maps/api/elevation/json', params)
        if results:
            return results[0]['elevation']
        return None

    def search(self, search_string, bounds=None):
        params = {'address': search_string}
        lang, encoding = locale.getdefaultlocale()
        if lang:
            params['language'] = lang
        if bounds:
            north, east, south, west = bounds
            params['bounds'] = '{!r},{!r}|{!r},{!r}'.format(
                south, west, north, east)
        for result in self.query(
                'https://maps.googleapis.com/maps/api/geocode/json', params):
            bounds = result['geometry']['viewport']
            yield (bounds['northeast']['lat'], bounds['northeast']['lng'],
                   bounds['southwest']['lat'], bounds['southwest']['lng'],
                   result['formatted_address'])

    def search_terms(self):
        widget = QtWidgets.QLabel(
            translate('MapTabGoogle', 'Search and altitude lookup') +
            '\npowered by Google')
        widget.setAlignment(Qt.AlignRight)
        scale_font(widget, 80)
        return [widget]
Example #17
0
 def connect(self):
     api_key    = key_store.get('flickr', 'api_key')
     api_secret = key_store.get('flickr', 'api_secret')
     stored_token = self.get_password()
     if stored_token:
         token, token_secret = stored_token.split('&')
     else:
         token, token_secret = '', ''
     token = flickrapi.auth.FlickrAccessToken(token, token_secret, 'write')
     self.api = flickrapi.FlickrAPI(
         api_key, api_secret, token=token, store_token=False,
         format='parsed-json')
     self.cached_data = {}
     try:
         if self.api.token_valid(perms='write'):
             self.connection_changed.emit(True)
             return True
     except flickrapi.FlickrError as ex:
         logger.error(str(ex))
     return False
Example #18
0
 def permitted(self, level):
     refresh_token = keyring.get_password('photini', 'picasa')
     if not refresh_token:
         self.session = None
         self.token = None
         return False
     if not self.token:
         # create expired token
         self.token = {
             'access_token'  : 'xxx',
             'refresh_token' : refresh_token,
             'expires_in'    : -30,
             }
         self.session = None
     if not self.session:
         # create new session
         client_id     = key_store.get('picasa', 'client_id')
         client_secret = key_store.get('picasa', 'client_secret')
         auto_refresh_kwargs = {
             'client_id'    : client_id,
             'client_secret': client_secret,
             }
         if self.auto_refresh:
             self.session = OAuth2Session(
                 client_id, token=self.token, token_updater=self._save_token,
                 auto_refresh_kwargs=auto_refresh_kwargs,
                 auto_refresh_url=self.token_url,
                 )
         else:
             self.session = OAuth2Session(client_id, token=self.token)
         # refresh manually to get a valid token now
         self.token = self.session.refresh_token(
             self.token_url, **auto_refresh_kwargs)
         self.session.headers.update({'GData-Version': 2})
         # verify the token
         resp = self._check_response(self.session.get(
             'https://www.googleapis.com/oauth2/v3/tokeninfo',
             params={'access_token': self.token['access_token']})).json()
         if resp['scope'] != self.scope[level] or resp['aud'] != client_id:
             return False
     return True
Example #19
0
 def get_auth_url(self, level):
     logger.info('using %s', keyring.get_keyring().__module__)
     app_id = key_store.get('facebook', 'app_id')
     client = oauthlib.oauth2.MobileApplicationClient(app_id)
     self.session = OAuth2Session(
         client=client,
         scope=self.scope[level],
         redirect_uri='https://www.facebook.com/connect/login_success.html',
     )
     result = self.session.authorization_url(
         'https://www.facebook.com/dialog/oauth',
         display='popup',
         auth_type='rerequest')[0]
     # use unquote to prevent "redirect_uri URL is not properly
     # formatted" error on Windows
     return unquote(result)
Example #20
0
    def load_api(self):
        url = 'http://maps.googleapis.com/maps/api/js?v=3'
        if self.app.test_mode:
            url += '.exp'
        url += '&key=' + key_store.get('google', 'api_key')
        lang, encoding = locale.getdefaultlocale()
        if lang:
            match = re.match('[a-zA-Z]+[-_]([A-Z]+)', lang)
            if match:
                name = match.group(1)
                if name:
                    url += '&region=' + name
        return """
    <script type="text/javascript"
      src="{}">
    </script>
""".format(url)
Example #21
0
class TabWidget(PhotiniMap):
    api_key = key_store.get('mapboxmap', 'api_key')

    @staticmethod
    def tab_name():
        return translate('MapTabMapbox', 'Map (&Mapbox)')

    def get_geocoder(self):
        return MapboxGeocoder(parent=self)

    def get_head(self):
        return '''    <link rel="stylesheet" href="{url}/mapbox.css" />
    <script type="text/javascript" src="{url}/mapbox.js">
    </script>
    <script type="text/javascript">
      L.mapbox.accessToken = "{key}";
    </script>
    <script type="text/javascript" src="../openstreetmap/common.js">
    </script>'''.format(key=self.api_key,
                        url='https://api.mapbox.com/mapbox.js/v3.2.1')
Example #22
0
    def get_page_elements(self):
        url = 'http://maps.googleapis.com/maps/api/js?callback=initialize&v=3'
        if self.app.test_mode:
            url += '.exp'
        url += '&key=' + key_store.get('google', 'api_key')
        lang, encoding = locale.getdefaultlocale()
        if lang:
            match = re.match('[a-zA-Z]+[-_]([A-Z]+)', lang)
            if match:
                name = match.group(1)
                if name:
                    url += '&region=' + name
        return {
            'head':
            '',
            'body':
            '''
    <script type="text/javascript"
      src="{}" async defer>
    </script>
'''.format(url),
        }
Example #23
0
    def get_page_elements(self):
        url = 'http://www.bing.com/api/maps/mapcontrol?callback=initialize'
        lang, encoding = locale.getdefaultlocale()
        if lang:
            url += '&mkt={0},ngt'.format(lang.replace('_', '-'))
        else:
            url += '&mkt=ngt'
        if self.app.test_mode:
            url += '&branch=experimental'
        return {
            'head':
            '''
    <script type="text/javascript">
      var api_key = "{}";
    </script>
    <script type="text/javascript"
      src="{}" async defer>
    </script>
'''.format(key_store.get('bing', 'api_key'), url),
            'body':
            '',
        }
Example #24
0
    def load_api(self):
        if self.app.test_mode:
            src = 'http://www.bing.com/api/maps/mapcontrol?callback=initialize'
            src += '&branch=experimental'
            version_8 = 'true'
        else:
            src = 'http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0'
            version_8 = 'false'
        self.setProperty('api_key', key_store.get('bing', 'api_key'))
        if not self.app.test_mode:
            lang, encoding = locale.getdefaultlocale()
            if lang:
                src += '&mkt={0},ngt'.format(lang.replace('_', '-'))
            else:
                src += '&mkt=ngt'
        return """
    <script type="text/javascript">
      var VERSION_8 = {1};
    </script>
    <script charset="UTF-8" type="text/javascript"
      src="{0}">
    </script>
""".format(src, version_8)
Example #25
0
class TabWidget(PhotiniMap):
    api_key = key_store.get('googlemap', 'api_key')

    @staticmethod
    def tab_name():
        return translate('MapTabGoogle', 'Map (&Google)')

    def get_geocoder(self):
        return GoogleGeocoder(parent=self)

    def get_head(self):
        url = 'http://maps.googleapis.com/maps/api/js?callback=initialize&v=3'
        if self.app.test_mode:
            url += '.exp'
        url += '&key=' + self.api_key
        lang, encoding = locale.getdefaultlocale()
        if lang:
            language, sep, region = lang.replace('_', '-').partition('-')
            url += '&language=' + language
            if region:
                url += '&region=' + region
        return '''    <script type="text/javascript"
      src="{}" async>
    </script>'''.format(url)
Example #26
0
 def __init__(self, *arg, **kwds):
     super(UploaderSession, self).__init__(*arg, **kwds)
     self.api = None
     # get api client id and secret
     for option in key_store.config.options(self.name):
         setattr(self, option, key_store.get(self.name, option))
Example #27
0
class MapboxGeocoder(GeocoderBase):
    api_key = key_store.get('mapboxmap', 'api_key')

    def do_geocode(self, query, params={}):
        params['access_token'] = self.api_key
        params['autocomplete '] = 'false'
        lang, encoding = locale.getdefaultlocale()
        if lang:
            params['language'] = lang
        query += '.json'
        url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + query
        with Busy():
            self.rate_limit()
            try:
                rsp = requests.get(url, params=params, timeout=5)
            except Exception as ex:
                logger.error(str(ex))
                return []
        if rsp.status_code >= 400:
            logger.error('Search error %d', rsp.status_code)
            return []
        self.block_timer.setInterval(
            self.interval * 600 //
            max(int(rsp.headers['X-Rate-Limit-Limit']), 1))
        rsp = rsp.json()
        return rsp['features']

    def search(self, search_string, bounds=None):
        params = {
            'limit': 10,
        }
        if bounds:
            north, east, south, west = bounds
            margin = (10.0 + west - east) / 2.0
            if margin > 0.0:
                east += margin
                west -= margin
            margin = (10.0 + south - north) / 2.0
            if margin > 0.0:
                north = min(north + margin, 90.0)
                south = max(south - margin, -90.0)
            params['bbox'] = '{!r},{!r},{!r},{!r}'.format(
                west, south, east, north)
        for feature in self.do_geocode(search_string, params=params):
            if 'place_name' not in feature:
                continue
            if 'bbox' in feature:
                west, south, east, north = feature['bbox']
                yield north, east, south, west, feature['place_name']
            elif 'center' in feature:
                east, north = feature['center']
                yield north, east, None, None, feature['place_name']

    def search_terms(self):
        widget = CompactButton(
            translate('MapTabMapbox', 'Search powered by Mapbox'))
        widget.clicked.connect(self.load_mapbox_tos)
        return [widget]

    @QtCore.Slot()
    @catch_all
    def load_mapbox_tos(self):
        QtGui.QDesktopServices.openUrl(
            QtCore.QUrl('https://www.mapbox.com/tos/'))
Example #28
0
 def __init__(self, image_list, parent=None):
     super(PhotiniMap, self).__init__(parent)
     self.app = QtWidgets.QApplication.instance()
     self.image_list = image_list
     self.geocode_cache = OrderedDict()
     name = self.__module__.split('.')[-1]
     self.api_key = key_store.get(name, 'api_key')
     self.search_key = key_store.get('opencage', 'api_key')
     self.script_dir = pkg_resources.resource_filename(
         'photini', 'data/' + name + '/')
     self.drag_icon = QtGui.QPixmap(
         os.path.join(self.script_dir, '../map_pin_grey.png'))
     self.drag_hotspot = 11, 35
     self.search_string = None
     self.map_loaded = False
     self.marker_info = {}
     self.map_status = {}
     self.dropped_images = []
     self.setChildrenCollapsible(False)
     left_side = QtWidgets.QWidget()
     self.addWidget(left_side)
     left_side.setLayout(QtWidgets.QFormLayout())
     left_side.layout().setContentsMargins(0, 0, 0, 0)
     left_side.layout().setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     # map
     # create handler for calls from JavaScript
     self.call_handler = CallHandler(parent=self)
     self.map = MapWebView(self.call_handler)
     self.map.drop_text.connect(self.drop_text)
     self.map.setAcceptDrops(False)
     self.addWidget(self.map)
     # search
     search_layout = QtWidgets.QFormLayout()
     search_layout.setContentsMargins(0, 0, 0, 0)
     search_layout.setVerticalSpacing(0)
     search_layout.setFieldGrowthPolicy(
         QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
     self.edit_box = ComboBox()
     self.edit_box.setEditable(True)
     self.edit_box.setInsertPolicy(QtWidgets.QComboBox.NoInsert)
     self.edit_box.lineEdit().setPlaceholderText(
         translate('PhotiniMap', '<new search>'))
     self.edit_box.lineEdit().returnPressed.connect(self.search)
     self.edit_box.activated.connect(self.goto_search_result)
     self.clear_search()
     self.edit_box.setEnabled(False)
     search_layout.addRow(translate('PhotiniMap', 'Search'), self.edit_box)
     # search terms and conditions
     terms = self.search_terms()
     if terms:
         search_layout.addRow(*terms)
     left_side.layout().addRow(search_layout)
     if terms:
         divider = QtWidgets.QFrame()
         divider.setFrameStyle(QtWidgets.QFrame.HLine)
         left_side.layout().addRow(divider)
     left_side.layout().addItem(
         QtWidgets.QSpacerItem(1,
                               1000,
                               vPolicy=QtWidgets.QSizePolicy.Expanding))
     # latitude & longitude
     layout = QtWidgets.QHBoxLayout()
     self.coords = SingleLineEdit()
     self.coords.editingFinished.connect(self.new_coords)
     self.coords.setEnabled(False)
     layout.addWidget(self.coords)
     # convert lat/lng to location info
     self.auto_location = QtWidgets.QPushButton(
         translate('PhotiniMap',
                   six.unichr(0x21e8) + ' address'))
     self.auto_location.setFixedHeight(self.coords.height())
     self.auto_location.setEnabled(False)
     self.auto_location.clicked.connect(self.get_address)
     layout.addWidget(self.auto_location)
     left_side.layout().addRow(translate('PhotiniMap', 'Lat, long'), layout)
     # location info
     self.location_widgets = []
     self.location_info = QtWidgets.QTabWidget()
     tab_bar = QTabBar()
     self.location_info.setTabBar(tab_bar)
     tab_bar.context_menu.connect(self.location_tab_context_menu)
     tab_bar.tabMoved.connect(self.location_tab_moved)
     self.location_info.setElideMode(Qt.ElideLeft)
     self.location_info.setMovable(True)
     self.location_info.setEnabled(False)
     left_side.layout().addRow(self.location_info)
     # address lookup (and default search) terms and conditions
     layout = QtWidgets.QHBoxLayout()
     if terms:
         widget = CompactButton(
             self.tr('Address lookup\npowered by OpenCage'))
     else:
         widget = CompactButton(
             self.tr('Search && lookup\npowered by OpenCage'))
     widget.clicked.connect(self.load_tou_opencage)
     layout.addWidget(widget)
     widget = CompactButton(
         self.tr('Geodata © OpenStreetMap\ncontributors'))
     widget.clicked.connect(self.load_tou_osm)
     layout.addWidget(widget)
     left_side.layout().addRow(layout)
     # other init
     self.image_list.image_list_changed.connect(self.image_list_changed)
     self.splitterMoved.connect(self.new_split)
     self.block_timer = QtCore.QTimer(self)
     self.block_timer.setInterval(5000)
     self.block_timer.setSingleShot(True)
     self.block_timer.timeout.connect(self.enable_search)
Example #29
0
class OpenCage(GeocoderBase):
    api_key = key_store.get('opencage', 'api_key')

    def __init__(self, *args, **kwds):
        super(OpenCage, self).__init__(*args, **kwds)
        self.geocode_cache = OrderedDict()

    def do_geocode(self, params):
        cache_key = params['q']
        if 'bounds' in params:
            cache_key += params['bounds']
        if cache_key in self.geocode_cache:
            return self.geocode_cache[cache_key]
        params['key'] = self.api_key
        params['abbrv'] = '1'
        params['no_annotations'] = '1'
        lang, encoding = locale.getdefaultlocale()
        if lang:
            params['language'] = lang
        with Busy():
            self.rate_limit()
            try:
                rsp = requests.get(
                    'https://api.opencagedata.com/geocode/v1/json',
                    params=params, timeout=5)
            except Exception as ex:
                logger.error(str(ex))
                return []
        if rsp.status_code >= 400:
            logger.error('Search error %d', rsp.status_code)
            return []
        rsp = rsp.json()
        status = rsp['status']
        if status['code'] != 200:
            logger.error(
                'Search error %d: %s', status['code'], status['message'])
            return []
        if rsp['total_results'] < 1:
            logger.error('No results found')
            return []
        rate = rsp['rate']
        self.block_timer.setInterval(
            5000 * rate['limit'] // max(rate['remaining'], 1))
        self.geocode_cache[cache_key] = rsp['results']
        while len(self.geocode_cache) > 20:
            self.geocode_cache.popitem(last=False)
        return rsp['results']

    def search(self, search_string, bounds=None):
        params = {
            'q'     : search_string,
            'limit' : '20',
            }
        if bounds:
            north, east, south, west = bounds
            margin = (10.0 + west - east) / 2.0
            if margin > 0.0:
                east += margin
                west -= margin
            margin = (10.0 + south - north) / 2.0
            if margin > 0.0:
                north = min(north + margin,  90.0)
                south = max(south - margin, -90.0)
            params['bounds'] = '{!r},{!r},{!r},{!r}'.format(
                west, south, east, north)
        for result in self.do_geocode(params):
            yield (result['bounds']['northeast']['lat'],
                   result['bounds']['northeast']['lng'],
                   result['bounds']['southwest']['lat'],
                   result['bounds']['southwest']['lng'],
                   result['formatted'])

    # Map OpenCage address components to IPTC address heirarchy. There
    # are many possible components (user generated data) so any
    # unrecognised ones are put in 'sublocation'. See
    # https://github.com/OpenCageData/address-formatting/blob/master/conf/components.yaml
    address_map = {
        'world_region'  :('continent',),
        'country_code'  :('ISO_3166-1_alpha-3', 'ISO_3166-1_alpha-2',
                          'country_code'),
        'country_name'  :('country', 'country_name'),
        'province_state':('county', 'county_code', 'local_administrative_area',
                          'state_district', 'state', 'state_code', 'province',
                          'region', 'island'),
        'city'          :('neighbourhood', 'suburb', 'city_district',
                          'district', 'quarter', 'residential', 'commercial',
                          'industrial', 'houses', 'subdivision',
                          'city', 'town', 'municipality', 'postcode'),
        'sublocation'   :('house_number', 'street_number',
                          'house', 'public_building', 'building', 'water',
                          'road', 'pedestrian', 'path',
                          'street_name', 'street', 'cycleway', 'footway',
                          'place', 'square',
                          'village', 'locality', 'hamlet', 'croft'),
        'ignore'        :('political_union', 'road_reference',
                          'road_reference_intl', 'road_type',
                          '_category', '_type'),
        }

    def get_address(self, coords):
        results = self.do_geocode({'q': coords.replace(' ', '')})
        if not results:
            return None
        address = dict(results[0]['components'])
        if 'county_code' in address and 'county' in address:
            del address['county_code']
        if 'state_code' in address and 'state' in address:
            del address['state_code']
        return Location.from_address(address, self.address_map)

    def search_terms(self, search=True):
        if search:
            text = self.tr('Search powered by OpenCage')
        else:
            text = self.tr('Address lookup powered by OpenCage')
        tou_opencage = CompactButton(text)
        tou_opencage.clicked.connect(self.load_tou_opencage)
        tou_osm = CompactButton(
            self.tr('Geodata © OpenStreetMap contributors'))
        tou_osm.clicked.connect(self.load_tou_osm)
        return [tou_opencage, tou_osm]

    @QtSlot()
    @catch_all
    def load_tou_opencage(self):
        QtGui.QDesktopServices.openUrl(
            QtCore.QUrl('https://geocoder.opencagedata.com/'))

    @QtSlot()
    @catch_all
    def load_tou_osm(self):
        QtGui.QDesktopServices.openUrl(
            QtCore.QUrl('http://www.openstreetmap.org/copyright'))