Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@vmeyet
Copy link
Contributor

@vmeyet vmeyet commented Nov 21, 2013

See https://dev.twitter.com/docs/api/1.1/post/statuses/update_with_media

implement support for the update_with_media feature + test.

This code is based on another pull request (#180) but that PR is not compliant with the v1.1 of the Twitter api.

Important: In API v1.1, you now use api.twitter.com as the domain instead of upload.twitter.com.

very small code added.

See discussion on issue #119

@Aaron1011
Copy link
Contributor

@vmeyet: This looks great! @joshthecoder: Does this look good to you?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vmeyet: I think you forgot to define text here. Did you mean to write tweet_text?

@joshthecoder
Copy link
Member

Yes looks fine. We can just fix the test locally and push it manually.

@vmeyet
Copy link
Contributor Author

vmeyet commented Dec 23, 2013

@Aaron1011 @joshthecoder, thanks for taking care !

@petulla
Copy link

petulla commented Apr 22, 2014

Could you show an example of updating with an object rather than a local file? I am hoping to be able to encode images I scrape and update them to a Twitter account.

Thanks.

@vmeyet
Copy link
Contributor Author

vmeyet commented Apr 23, 2014

@petulla the problem is the _pack_image method which does various check regarding the file size etc.

For my use I made a workaround, by monkey patching _pack_image:

  • without the file checks and using 'Content-Transfer-Encoding: base64' the following would work:
import base64
import requests
from cStringIO import StringIO
thefile = base64.b64encode(StringIO(requests.get(url).content)

tweepy.API.update_with_media(thefile, status='my status')

May be it worth opening another issue, and to make a PR: there are some refacto needed with _pack_image, plus check for the url image to be thought.

@petulla
Copy link

petulla commented Apr 23, 2014

I had something similar but couldn't get it to work; your fix is also throwing an error for me.

Any ideas?

Here's the code:

image = value[0]
#encoding
image = base64.b64encode(StringIO(requests.get(image).content))
#passing
twitter_api.update_with_media(image, status=statustext)

Error: TypeError: must be string or buffer, not cStringIO.StringI

@vmeyet
Copy link
Contributor Author

vmeyet commented Apr 23, 2014

oups made a typo:
image = base64.b64encode(StringIO(requests.get(image).content).read())

@petulla
Copy link

petulla commented Apr 23, 2014

The encoding seems to be working. Still throwing an error, though. Indeed pack_image is unhappy.

'''
92 """ statuses/update_with_media """
93 def update_with_media(self, filename, _args, *_kwargs):
---> 94 headers, post_data = API._pack_image(filename, 3072, form_field='media[]')
95 kwargs.update({'headers': headers, 'post_data': post_data})
96

707 raise TweepError('File is too big, must be less than 700kb.')
708 except os.error:
--> 709 raise TweepError('Unable to access file')
710
711 # image must be gif, jpeg, or png

TweepError: Unable to access file'''

@vmeyet
Copy link
Contributor Author

vmeyet commented Apr 23, 2014

of course, you need to monkey patch the _pack_image method which it seems you have not. (that's one of the check in _pack_image that is used when this is a local file)

https://github.com/vmeyet/tweepy/blob/1c108bba79090b054b84d45d8031019ea3475585/tweepy/api.py#L690-694

@petulla
Copy link

petulla commented Apr 23, 2014

Do you mind breaking out how to do that? I have never done that before.

@vmeyet
Copy link
Contributor Author

vmeyet commented Apr 24, 2014

the basic idea is:

import base64
import requests
import tweepy
from cStringIO import StringIO
from tweepy.binder import bind_api


def _pack_image_from_url(url, max_size, form_field="image", file_type='image/png'):

    #
    # Checks for the url validity goes there
    base64_encoded = base64.b64encode(StringIO(requests.get(url).content).read())

    BOUNDARY = 'Tw3ePy Pa7cH3d'
    body = []
    body.append('--' + BOUNDARY)
    body.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (form_field, url))
    body.append('Content-Type: %s' % file_type)
    body.append('Content-Transfer-Encoding: base64')
    body.append('')
    body.append(base64_encoded)
    body.append('--' + BOUNDARY + '--')
    body.append('')
    body = '\r\n'.join(body)

    headers = {
        'Content-Type': 'multipart/form-data; boundary=%s' % BOUNDARY,
        'Content-Length': str(len(body))
    }

    return headers, body

def update_with_media_url(self, url, *args, **kwargs):
    headers, post_data = _pack_image_from_url(url, 3072, form_field='media[]')
    kwargs.update({'headers': headers, 'post_data': post_data})

    return bind_api(
        path='/statuses/update_with_media.json',
        method = 'POST',
        payload_type='status',
        allowed_param = [
            'status', 'possibly_sensitive', 'in_reply_to_status_id', 'lat', 'long',
            'place_id', 'display_coordinates'
        ],
        require_auth=True
    )(self, *args, **kwargs)


def patch_tweepy():
    tweepy.API.update_with_media_url = update_with_media_url


patch_tweepy()

# Now you can do
tweepy.API.update_with_media_url('http://mypic.jpg', status='my status')

But you should definitely open an issue for the tweepy lib to support the feature in the future

@Aaron1011
Copy link
Contributor

@vmeyet: I've added this in d908bf7

@vmeyet
Copy link
Contributor Author

vmeyet commented Apr 25, 2014

@Aaron1011 pretty cool how you are reactive. Thanks for that !

@petulla
Copy link

petulla commented May 13, 2014

@Aaron1011 @vmeyet

Hi I tried using the patch today but still aren't having any luck. I upgraded Tweepy to 2.3, which I assume has the file improvement.

I'm using the following code. Statustext and twitter_api are already defined. Do I need to pass in the type rather than the filename? I'm a bit confused by your documentation here: #422

#this is our url, assigned to variable image  
image = {an image url}

#get the filename from the url
    imagename = image.split('/')[-1].split('#')[0].split('?')[0]

#convert the url to an encoded image format
    imagere = StringIO(requests.get(image).content).read()
    imagefile = base64.b64encode(imagere)

#here is my argument. Where am I going wrong?
    twitter_api.update_with_media(file=imagefile, filename=imagename, status=statustext)  

@Aaron1011
Copy link
Contributor

@petulla: Sorry, I should have made it more clear.

file should be a file-like object. In this case, you'd want to pass the StringIO instance itself (skip the base64 encoding). Your code should look like this:

#this is our url, assigned to variable image  
image = {an image url}

#get the filename from the url
imagename = image.split('/')[-1].split('#')[0].split('?')[0]

#convert the url to an encoded image format
imagefile = StringIO(requests.get(image).content)

#here is my argument. Where am I going wrong?
twitter_api.update_with_media(file=imagefile, filename=imagename, status=statustext)  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants