Beispiel #1
0
    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()
Beispiel #2
0
    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))
Beispiel #3
0
    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)
Beispiel #4
0
    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)
Beispiel #5
0
    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
Beispiel #6
0
    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)
Beispiel #7
0
 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')
Beispiel #8
0
 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')
Beispiel #9
0
 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')
Beispiel #10
0
 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')
Beispiel #11
0
    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']
Beispiel #12
0
    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()
Beispiel #13
0
    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']
Beispiel #14
0
    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