Re-implement the GetFriends() of python-twitter with paging logic so that all friends...
[hermes] / package / src / org / maemo / hermes / engine / twitter / api.py
diff --git a/package/src/org/maemo/hermes/engine/twitter/api.py b/package/src/org/maemo/hermes/engine/twitter/api.py
new file mode 100644 (file)
index 0000000..44aca61
--- /dev/null
@@ -0,0 +1,127 @@
+from org.maemo.hermes.engine.twitter.user import User
+import urllib, urllib2
+import base64
+import simplejson
+import urlparse
+
+class TwitterApi():
+    """Twitter backend for Hermes. Inspired by
+          http://code.google.com/p/python-twitter/source/browse/twitter.py
+       
+       Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
+       Released under the Artistic Licence."""
+       
+       
+    # -----------------------------------------------------------------------
+    def __init__(self, username, password):
+        self._username = username
+        self._password = password
+
+
+    # -----------------------------------------------------------------------
+    def get_friends(self):
+        '''Return the full list of people being followed by 'username'.'''
+
+        url = 'https://twitter.com/statuses/friends.json'
+        cursor = -1
+        users = []
+        while True:
+            json = self._FetchUrl(url, parameters = { 'cursor': cursor})
+            data = simplejson.loads(json)
+            if 'error' in data:
+                raise Exception(data['error'])
+
+            for x in data['users']:
+                users.append(User.NewFromJsonDict(x))
+
+            cursor = data['next_cursor']
+            if cursor <= data['previous_cursor']:
+                break
+
+        return users
+
+
+    # -----------------------------------------------------------------------
+    def _FetchUrl(self,
+                  url,
+                  parameters=None):
+        '''Fetch a URL, optionally caching for a specified time.
+
+        Args:
+          url:
+            The URL to retrieve
+          parameters:
+            A dict whose key/value pairs should encoded and added
+            to the query string. [optional]
+
+        Returns:
+          A string containing the body of the response.
+        '''
+
+        # Build the extra parameters dict
+        extra_params = {}
+        if parameters:
+            extra_params.update(parameters)
+
+        # Add key/value parameters to the query string of the url
+        url = self._BuildUrl(url, extra_params=extra_params)
+
+        # Get a url opener that can handle basic auth
+        basic_auth = base64.encodestring('%s:%s' % (self._username, self._password))[:-1]
+
+        handler = urllib2.HTTPBasicAuthHandler()
+        (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
+        handler.add_password('Twitter API', netloc, self._username, self._password)
+        opener = urllib2.build_opener(handler)
+        opener.addheaders = {'Authorization': 'Basic %s' % basic_auth}.items()
+    
+        url_data = opener.open(url, None).read()
+        opener.close()
+        return url_data
+
+
+    # -----------------------------------------------------------------------
+    def _BuildUrl(self, url, path_elements=None, extra_params=None):
+        # Break url into consituent parts
+        (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
+
+        # Add any additional path elements to the path
+        if path_elements:
+            # Filter out the path elements that have a value of None
+            p = [i for i in path_elements if i]
+            if not path.endswith('/'):
+                path += '/'
+            path += '/'.join(p)
+
+        # Add any additional query parameters to the query string
+        if extra_params and len(extra_params) > 0:
+            extra_query = self._EncodeParameters(extra_params)
+            # Add it to the existing query
+            if query:
+                query += '&' + extra_query
+            else:
+                query = extra_query
+
+        # Return the rebuilt URL
+        return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
+
+
+
+    # -----------------------------------------------------------------------
+    def _EncodeParameters(self, parameters):
+        '''Return a string in key=value&key=value form
+
+        Values of None are not included in the output string.
+
+        Args:
+          parameters:
+            A dict of (key, value) tuples, where value is encoded as
+            specified by self._encoding
+        Returns:
+          A URL-encoded string in "key=value&key=value" form
+        '''
+        if parameters is None:
+            return None
+        else:
+            return urllib.urlencode(dict([(k, unicode(v).encode('utf-8')) for k, v in parameters.items() if v is not None]))
+