def receive(self): """Gets a list of each friend's most recent check-ins.""" token = self._get_access_token() result = Downloader(RECENT_URL.format(access_token=token)).get_json() response_code = result.get('meta', {}).get('code') if response_code != 200: raise FriendsError('FourSquare: Error: {}'.format(result)) checkins = result.get('response', {}).get('recent', []) for checkin in checkins: user = checkin.get('user', {}) avatar = user.get('photo', {}) checkin_id = checkin.get('id', '') tz_offset = checkin.get('timeZoneOffset', 0) epoch = checkin.get('createdAt', 0) venue = checkin.get('venue', {}) location = venue.get('location', {}) self._publish( message_id=checkin_id, stream='messages', sender=_full_name(user), from_me=(user.get('relationship') == 'self'), timestamp=iso8601utc(epoch, tz_offset), message=checkin.get('shout', ''), likes=checkin.get('likes', {}).get('count', 0), icon_uri='{prefix}100x100{suffix}'.format(**avatar), url=venue.get('canonicalUrl', ''), location=venue.get('name', ''), latitude=location.get('lat', 0.0), longitude=location.get('lng', 0.0), ) return self._get_n_rows()
def upload(self, picture_uri, description=''): # http://developers.facebook.com/docs/reference/api/photo/ """Upload local or remote image or video to album.""" url = '{}/photos?access_token={}'.format( ME_URL, self._get_access_token()) response = Uploader( url, picture_uri, description, picture_key='source', desc_key='message').get_json() self._is_error(response) post_id = response.get('post_id') if post_id is not None: destination_url = PERMALINK.format(id=post_id) self._publish( from_me=True, stream='images', message_id=post_id, message=description, sender=self._account.user_name, sender_id=self._account.user_id, sender_nick=self._account.user_name, timestamp=iso8601utc(int(time.time())), url=destination_url, icon_uri=(API_BASE.format(id=self._account.user_id) + '/picture?type=large')) return destination_url else: raise FriendsError(str(response))
def _publish_comment(self, comment, stream): """Publish a single comment into the Dee.SharedModel.""" message_id = comment.get('id') if message_id is None: return message = comment.get('text', '') person = comment.get('from', {}) sender_nick = person.get('username') timestamp = comment.get('created_time') if timestamp is not None: timestamp = iso8601utc(parsetime(timestamp)) icon_uri = person.get('profile_picture') sender_id = person.get('id') sender = person.get('full_name') args = dict( stream=stream, message_id=message_id, message=message, timestamp=timestamp, sender_nick=sender_nick, icon_uri=icon_uri, sender_id=sender_id, sender=sender, ) self._publish(**args)
def _publish_entry(self, entry, stream='messages'): """Publish a single update into the Dee.SharedModel.""" message_id = entry.get('updateKey') content = entry.get('updateContent', {}) person = content.get('person', {}) name = make_fullname(**person) person_id = person.get('id', '') status = person.get('currentStatus') picture = person.get('pictureUrl', '') url = person.get('siteStandardProfileRequest', {}).get('url', '') timestamp = entry.get('timestamp', 0) # We need to divide by 1000 here, as LinkedIn's timestamps have # milliseconds. iso_time = iso8601utc(int(timestamp / 1000)) likes = entry.get('numLikes', 0) if None in (message_id, status): # Something went wrong; just ignore this malformed message. return args = dict(message_id=message_id, stream=stream, message=status, likes=likes, sender_id=person_id, sender=name, icon_uri=picture, url=url, timestamp=iso_time) self._publish(**args)
def upload(self, picture_uri, title=''): """Upload local or remote image or video to album.""" self._get_access_token() args = dict( api_key=self._account.consumer_key, title=title, ) headers = self._get_oauth_headers( method='POST', url=UPLOAD_SERVER, data=args, ) response = Uploader( UPLOAD_SERVER, picture_uri, picture_key='photo', headers=headers, **args ).get_string() try: post_id = PHOTOID(response).group(1) except AttributeError: raise FriendsError(response) else: destination_url = IMAGE_PAGE_URL.format( owner=self._account.user_name, photo=post_id, ) self._publish( from_me=True, stream='images', message_id=post_id, message=title, sender=self._account.user_full_name, sender_id=self._account.user_id, sender_nick=self._account.user_name, timestamp=iso8601utc(int(time.time())), url=destination_url, icon_uri=self._get_avatar(self._account.user_id), ) return destination_url
def _get(self, url, stream): """Retrieve a list of Facebook objects. A maximum of 50 objects are requested. """ access_token = self._get_access_token() since = self._timestamps.get( stream, iso8601utc(int(time.time()) - TEN_DAYS)) entries = [] params = dict(access_token=access_token, since=since, limit=self._DOWNLOAD_LIMIT) entries = self._follow_pagination(url, params) # https://developers.facebook.com/docs/reference/api/post/ for entry in entries: self._publish_entry(entry, stream=stream)
def test_iso8601_west_of_utc_with_sep(self): # Convert a Unix epoch time seconds plus an offset to an ISO 8601 UTC # date time string, with a different separator. self.assertEqual(iso8601utc(1336657005, -400, sep=' '), '2012-05-10 17:36:45')
def test_iso8601_west_of_utc(self): # Convert a Unix epoch time seconds plus an offset to an ISO 8601 UTC # date time string. self.assertEqual(iso8601utc(1336657005, -400), '2012-05-10T17:36:45Z')
def test_iso8601_utc_with_sep(self): # Convert a Unix epoch time seconds in UTC (the default) to an ISO # 8601 UTC date time string with a different separator. self.assertEqual(iso8601utc(1336657005, sep=' '), '2012-05-10 13:36:45')
def test_iso8601_utc(self): # Convert a Unix epoch time seconds in UTC (the default) to an ISO # 8601 UTC date time string. self.assertEqual(iso8601utc(1336657005), '2012-05-10T13:36:45Z')
def _publish_entry(self, entry, stream='messages'): message_id = entry.get('id') message_type = entry.get('type') if "reply" in stream: message_type = "reply" if None in (message_id, message_type): # We can't do much with this entry. return if 'to' in entry: # Somebody posted on somebodies wall # This cannot be displayed properly in friends so ignore return place = entry.get('place', {}) location = place.get('location', {}) link_pic = entry.get('picture', '') # Use objectID to get a highres version of the picture # Does not seem to work for links object_id = entry.get('object_id') if object_id and ('photo' in message_type): link_pic = "http://graph.facebook.com/" + object_id + "/picture?type=normal" args = dict( message_id=message_id, stream='images' if ('photo' in message_type) else stream, message=entry.get('message', '') or entry.get('story', ''), icon_uri=entry.get('icon', ''), link_picture=link_pic, link_name=entry.get('name', ''), link_url=entry.get('link', ''), link_desc=entry.get('description', ''), link_caption=entry.get('caption', ''), location=place.get('name', ''), latitude=location.get('latitude', 0.0), longitude=location.get('longitude', 0.0), ) # Posts gives us a likes dict, while replies give us an int. likes = entry.get('likes', 0) if isinstance(likes, dict): likes = likes.get('count', 0) args['likes'] = likes # Fix for LP:1185684 - JPM post_id = message_id.split('_')[1] if '_' in message_id else message_id from_record = entry.get('from') if from_record is not None: args['sender'] = from_record.get('name', '') args['sender_id'] = sender_id = from_record.get('id', '') args['url'] = STORY_PERMALINK.format( id=sender_id, post_id=post_id) args['icon_uri'] = (API_BASE.format(id=sender_id) + '/picture?width=840&height=840') args['sender_nick'] = from_record.get('name', '') args['from_me'] = (sender_id == self._account.user_id) # Normalize the timestamp. timestamp = entry.get('updated_time', entry.get('created_time')) if timestamp is not None: timestamp = args['timestamp'] = iso8601utc(parsetime(timestamp)) # We need to record timestamps for use with since=. Note that # _timestamps is a special dict subclass that only accepts # timestamps that are larger than the existing value, so at any # given time it will map the stream to the most # recent timestamp we've seen for that stream. self._timestamps[stream] = timestamp # Publish this message into the SharedModel. self._publish(**args) # If there are any replies, publish them as well. for comment in entry.get('comments', {}).get('data', []): if comment: self._publish_entry( stream='reply_to/{}'.format(message_id), entry=comment) return args['url']
def receive(self): """Download all of a user's public photos.""" # Trigger loggin in. self._get_access_token() args = dict( api_key=self._account.consumer_key, method='flickr.photos.getContactsPhotos', format='json', nojsoncallback='1', extras='date_upload,owner_name,icon_server,geo', ) response = self._get_url(args) for data in response.get('photos', {}).get('photo', []): # Pre-calculate some values to publish. username = data.get('username', '') ownername = data.get('ownername', '') photo_id = data.get('id') if photo_id is None: # Can't do anything without this, really. continue # Icons. icon_farm = data.get('iconfarm') icon_server = data.get('iconserver') owner = data.get('owner') icon_uri = '' url = '' from_me = (ownername == username) if None not in (icon_farm, icon_server, owner): icon_uri = BUDDY_ICON_URL.format( farm=icon_farm, server=icon_server, nsid=owner) url = IMAGE_PAGE_URL.format(owner=owner, photo=photo_id) # Calculate the ISO 8601 UTC time string. try: timestamp = iso8601utc(parsetime(data.get('dateupload', ''))) except ValueError: timestamp = '' # Images. farm = data.get('farm') server = data.get('server') secret = data.get('secret') img_src, img_thumb = '', '' if None not in (farm, server, secret): args = dict( farm=farm, server=server, photo=photo_id, secret=secret, ) img_src = IMAGE_URL.format(type='m', **args) img_thumb = IMAGE_URL.format(type='t', **args) self._publish( message_id=photo_id, message=data.get('title', ''), stream='images', sender=ownername, sender_id=owner, sender_nick=ownername, icon_uri=icon_uri, url=url, from_me=from_me, timestamp=timestamp, link_url=url, link_picture=img_src, link_icon=img_thumb, latitude=data.get('latitude', 0.0), longitude=data.get('longitude', 0.0), ) return self._get_n_rows()
def _publish_entry(self, entry, stream='messages'): """Publish a single update into the Dee.SharedModel.""" message_id = entry.get('id') if message_id is None: # We can't do much with this entry. return person = entry.get('user') nick = person.get('username') name = person.get('full_name') person_id = person.get('id') message= '%s shared a picture on Instagram.' % nick person_icon = person.get('profile_picture') person_url = 'http://instagram.com/' + nick picture = entry.get('images').get('thumbnail').get('url') if entry.get('caption'): desc = entry.get('caption').get('text', '') else: desc = '' url = entry.get('link') timestamp = entry.get('created_time') if timestamp is not None: timestamp = iso8601utc(parsetime(timestamp)) likes = entry.get('likes').get('count') liked = entry.get('user_has_liked') location = entry.get('location', {}) if location: latitude = location.get('latitude', '') longitude = location.get('longitude', '') else: latitude = 0 longitude = 0 args = dict( message_id=message_id, message=message, stream=stream, likes=likes, sender_id=person_id, sender=name, sender_nick=nick, url=person_url, icon_uri=person_icon, link_url=url, link_picture=picture, link_desc=desc, timestamp=timestamp, liked=liked, latitude=latitude, longitude=longitude ) self._publish(**args) # If there are any replies, publish them as well. parent_id = message_id for comment in entry.get('comments', {}).get('data', []): if comment: self._publish_comment( comment, stream='reply_to/{}'.format(parent_id)) return args['url']
def _publish_tweet(self, tweet, stream='messages'): """Publish a single tweet into the Dee.SharedModel.""" tweet_id = tweet.get('id_str') or str(tweet.get('id', '')) if not tweet_id: log.info('Ignoring tweet with no id_str value') return # We need to record tweet_ids for use with since_id. Note that # _tweet_ids is a special dict subclass that only accepts # tweet_ids that are larger than the existing value, so at any # given time it will map the stream to the largest (most # recent) tweet_id we've seen for that stream. self._tweet_ids[stream] = tweet_id # 'user' for tweets, 'sender' for direct messages. user = tweet.get('user', {}) or tweet.get('sender', {}) screen_name = user.get('screen_name', '') avatar_url = ( user.get('profile_image_url_https') or # Twitter, or user.get('profile_image_url') or # Identi.ca '') permalink = self._tweet_permalink.format(user_id=screen_name, tweet_id=tweet_id) # If this is an RT, we are more interested in the original tweet retweet = tweet.get('retweeted_status', {}) entities = retweet.get('entities', {}) or tweet.get('entities', {}) message = retweet.get('text', '') or tweet.get('text', '') picture_url = '' urls = {} for url in (entities.get('urls', []) + entities.get('media', []) + entities.get('user_mentions', []) + entities.get('hashtags', [])): begin, end = url.get('indices', (None, None)) #Drop invalid entities (just to be safe) if None not in (begin, end): urls[begin] = url for key, url in sorted(urls.items(), reverse=True): begin, end = url.get('indices', (None, None)) expanded_url = url.get('expanded_url') display_url = url.get('display_url') other_url = url.get('url') mention_name = url.get('screen_name') picture_url = url.get('media_url', picture_url) hashtag = url.get('text') content = None # Friends has no notion of display URLs, so this is handled at the protocol level if (other_url or expanded_url): content = self._linkify(expanded_url or other_url, display_url or other_url) # Linkify hashtags until supported by friends-app if hashtag: content = self._linkify( 'https://twitter.com/search?q=%23' + hashtag + '&src=hash', '#' + hashtag) # Linkify a mention until they are supported natively by friends if mention_name: content = self._linkify_mention(mention_name) if content: message = ''.join([message[:begin], content, message[end:]]) if retweet: message = 'RT {}: {}'.format( self._linkify_mention( retweet.get('user', {}).get('screen_name', '')), message) if picture_url: stream = 'images' self._publish( message_id=tweet_id, message=message, timestamp=iso8601utc(parsetime(tweet.get('created_at', ''))), stream=stream, sender=user.get('name', ''), sender_id=str(user.get('id', '')), sender_nick=screen_name, from_me=(screen_name == self._account.user_name), icon_uri=avatar_url.replace('_normal.', '.'), liked=tweet.get('favorited', False), url=permalink, link_picture=picture_url, ) return permalink