python-twitter-tools / twitter

Python Twitter API
http://mike.verdone.ca/twitter/
MIT License
3.2k stars 715 forks source link

update_with_media: Code 189 #224

Closed WaffleStudios closed 10 years ago

WaffleStudios commented 10 years ago

I'm trying to use PTT to send a Twitter update with an image attached. Here's a sample of my code

params = {"media[]": encoded_string,"status":"TEST MESSAGE"}
t.statuses.update_with_media(**params)

Where encoded_string is a base64 encoded string of the image file. Every time I try to send it, I get the following error.

Traceback (most recent call last):
  File "test.py", line 65, in <module>
    t.statuses.update_with_media(**params)
  File "build/bdist.macosx-10.9-intel/egg/twitter/api.py", line 245, in __call__
  File "build/bdist.macosx-10.9-intel/egg/twitter/api.py", line 276, in _handle_response
twitter.api.TwitterHTTPError: Twitter sent status 403 for URL: 1.1/statuses/update_with_media.json using parameters: (OAUTH_INFORMATION)
details: {"errors":[{"code":189,"message":"Error creating status."}]}

I can't seem to find any helpful information after a lot of Googling, and I don't understand the nature of this issue. Is this an issue with PTT, or is there just something I'm missing?

RouxRC commented 10 years ago

Hi, this is Twitter's classic error code when something is wrong while sending a wrong image (Twitter accepts only small images in jpeg png or gif(not animated))
Could you please give more information on the image and how you convert it as such ?

FYI: you shouldn't need to convert your image to base64, just pure python binary read of a file is fine, for instance:

with open('img.jpg', 'rb') as f:
    t.statuses.update_with_media(status="Youpi !", 'media[]' = f.read())
WaffleStudios commented 10 years ago

Whenever I try to run it without encoding it, using open('img.jpg', 'rb') and f.read() like you suggested, it gives me this error

Traceback (most recent call last):
  File "test.py", line 64, in <module>
    t.statuses.update_with_media(**params)
  File "build/bdist.macosx-10.9-intel/egg/twitter/api.py", line 240, in __call__
UnicodeDecodeError: 'ascii' codec can't decode byte 0x89 in position 0: ordinal not in range(128)

As for information about the image, I'm building an image using PIL, saving it to disk (originally as a png 500x500, but using jpeg 250x250 did not change the result), and then attempting to upload it. I've encoded it to base64 both by using img.encode("base64") as well as base64.b64encode(img)

hugovk commented 10 years ago

Quick sanity check: can you post the image to Twitter using the Twitter website?

WaffleStudios commented 10 years ago

Yes, I can. I cleared out all the items from the directory, re-ran my program, and uploaded the picture to Twitter using the Twitter website, and it went up fine.

RouxRC commented 10 years ago

Mmm... I may have an idea but it's hard to try. Could you post the image or the code online somewhere for tryouts?

WaffleStudios commented 10 years ago

Full code is right here (minus my OAUTH keys and such)

from __future__ import unicode_literals
from PIL import Image
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

import json
import textwrap

import requests
from requests_oauthlib import OAuth1
from urlparse import parse_qs

from twitter import *
import StringIO
import base64

REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token"
AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token="
ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token"

CONSUMER_KEY = "[CONSUMER_KEY]"
CONSUMER_SECRET = "[CONSUMER_SECRET]"

OAUTH_TOKEN = "[OAUTH_TOKEN]"
OAUTH_TOKEN_SECRET = "[OAUTH_TOKEN_SECRET]"

t = Twitter(
            auth=OAuth(OAUTH_TOKEN, OAUTH_TOKEN_SECRET,
                       CONSUMER_KEY, CONSUMER_SECRET)
           )

topString = "how does this thing handle really long strings lorem ipsum ipsos something latin i don't know filler text boston red sox fever pitch don jerry film in toronto. i think this is long enough."
img = Image.new("RGB", (250, 250), "white")

imageSize = img.size

fontSize = imageSize[1] / 20
font = ImageFont.truetype("[DIR_TO_FONT]", fontSize)
topTextSize = font.getsize(topString)

# find top centered position for top text
topTextPositionX = (imageSize[0]/2) - (topTextSize[0]/2)
topTextPositionY = 0
topTextPosition = (topTextPositionX, topTextPositionY)

draw = ImageDraw.Draw(img)

margin = offset = 25
for line in textwrap.wrap(topString, width=30):
    # thin border
    draw.text((margin-1, offset-1), line, font=font, fill="#000000")
    draw.text((margin+1, offset-1), line, font=font, fill="#000000")
    draw.text((margin-1, offset+1), line, font=font, fill="#000000")
    draw.text((margin-1, offset+1), line, font=font, fill="#000000")
    draw.text((margin-1, offset), line, font=font, fill="#FFFFFF")
    offset += font.getsize(line)[1]

img.save("temp.jpg", "JPEG")

with open("temp.jpg", "rb") as open_file:
    params = {"media[]": base64.b64encode(open_file.read()), "status": "TEST MESSAGE HTWER"}

t.statuses.update_with_media(**params)

print "done"

Only requires PIL and PTT. Anything other imports are just extra junk from earlier attempts and can be disregarded. I know image generation works, and I can send updates without media. It's just when I try to send a picture that it gives me 189.

RouxRC commented 10 years ago

All right, just tried and got it to work by removing the base64.b64encode() around the open_file.read() Have you tried that?

with open("temp.jpg", "rb") as open_file:
    params = {"media[]": open_file.read(), "status": "TEST MESSAGE HTWER"}

Otherwise, looking at your final print, I'd say you're using python-2 as I did in my tryouts, so I really don't know why it would work for me and not for you :/ Maybe adding a # -*- coding: utf-8 -*- at the top of your code?...

WaffleStudios commented 10 years ago

I'm using Python 2.7.5 (just checked the version number). I added # -*- coding: utf-8 -*-, but that did not affect it. I posted this earlier, but if I don't encode it, I get this error

Traceback (most recent call last):
  File "test.py", line 65, in <module>
    t.statuses.update_with_media(**params)
  File "build/bdist.macosx-10.9-intel/egg/twitter/api.py", line 240, in __call__
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0: ordinal not in range(128)
RouxRC commented 10 years ago

Well I can't reproduce it unfortunately so I really don't know how to help, sorry :(

RouxRC commented 10 years ago

Hi there, It ended up not working anymore for me either and I seem to have just fixed it (see https://github.com/sixohsix/twitter/commit/94fb8fab211ba987f4661150c95817bd073bd4a6#commitcomment-7106511) Could you please try again and see if this works for you now?

geper commented 10 years ago

where if media: api.py why no encod('utf-8')?