Reputation: 507
currently I am working with unity. In this project, I need to post some status with image to twitter. However, I got a problem to upload the image to the Twitter.
Here is the code, which I used to upload the Image:
private const string UploadMediaURL = "https://upload.twitter.com/1.1/media/upload.json";
public static IEnumerator UploadMedia(string consumerKey, string consumerSecret, string filePath, AccessTokenResponse response){
Dictionary<string, string> mediaParameters = new Dictionary<string, string>();
mediaParameters.Add("media", System.Convert.ToBase64String(File.ReadAllBytes(filePath)));
// Add data to the form to post.
WWWForm mediaForm = new WWWForm();
mediaForm.AddField("media", System.Convert.ToBase64String(File.ReadAllBytes(filePath)));
print (System.Convert.ToBase64String (File.ReadAllBytes (filePath)));
// HTTP header
var mediaHeaders = new Hashtable();
mediaHeaders["Authorization"] = GetHeaderWithAccessToken("POST", UploadMediaURL, consumerKey, consumerSecret, response, mediaParameters);
WWW mw = new WWW(UploadMediaURL, mediaForm.data, mediaHeaders);
yield return mw;
if (!string.IsNullOrEmpty (mw.error)) {
Debug.Log(string.Format("PostTweet - failed. {0}"));
} else {
SetMediaWeb(mw);
}
}
When I call above method, I got bellow error:
UriFormatException: Uri is longer than the maximum {0} characters. System.Uri.EscapeDataString (System.String stringToEscape)
FYI image size is not big, it's only 23 kb and the type of the image is png.
What is wrong with my code. Thanks for your help.
Upvotes: 1
Views: 4077
Reputation: 1
here's code I have working including a post with a status. I'm using Lets Tweet's code : https://www.assetstore.unity3d.com/en/#!/content/536 Thanks to everyone who posted earlier to help get the image uploading portion working properly. With Patrick's changes this should let you upload and post any image or media file up to 5MB.
Dictionary<string, string> mediaParameters = new Dictionary<string, string> ();
string mediaString = System.Convert.ToBase64String (File.ReadAllBytes (filePath));
mediaParameters.Add ("media_data", mediaString);
mediaParameters.Add ("status", text);
// Add data to the form to post.
WWWForm mediaForm = new WWWForm ();
mediaForm.AddField ("media_data", mediaString);
mediaForm.AddField ("status", text);
// Debug.Log (System.Convert.ToBase64String (File.ReadAllBytes (filePath)));
// HTTP header
Dictionary<string, string> mediaHeaders = new Dictionary<string, string> ();
string url = UploadMediaURL;
string auth = GetHeaderWithAccessToken ("POST", UploadMediaURL, consumerKey, consumerSecret, response, mediaParameters);
mediaHeaders.Add ("Authorization", auth);
mediaHeaders.Add ("Content-Transfer-Encoding", "base64");
WWW mw = new WWW (UploadMediaURL, mediaForm.data, mediaHeaders);
yield return mw;
string mID = Regex.Match(mw.text, @"(\Dmedia_id\D\W)(\d*)").Groups[2].Value;
Debug.Log ("response from media request : " + mw.text);
Debug.Log ("mID = " + mID);
if (!string.IsNullOrEmpty (mw.error)) {
Debug.Log (string.Format ("PostTweet - failed. {0}\n{1}", mw.error, mw.text));
callback (false);
} else {
string error = Regex.Match (mw.text, @"<error>([^&]+)</error>").Groups [1].Value;
if (!string.IsNullOrEmpty (error)) {
Debug.Log (string.Format ("PostTweet - failed. {0}", error));
callback (false);
} else {
callback (true);
}
}
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("status", text);
parameters.Add ("media_ids", mID);
// Add data to the form to post.
WWWForm form = new WWWForm();
form.AddField("status", text);
form.AddField ("media_ids", mID);
// HTTP header
var headers = new Dictionary<string, string>();
headers["Authorization"] = GetHeaderWithAccessToken("POST", PostTweetURL, consumerKey, consumerSecret, response, parameters);
WWW web = new WWW(PostTweetURL, form.data, headers);
yield return web;
if (!string.IsNullOrEmpty(web.error))
{
Debug.Log(string.Format("PostTweet - failed. {0}\n{1}", web.error, web.text));
callback(false);
}
else
{
string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value;
if (!string.IsNullOrEmpty(error))
{
Debug.Log(string.Format("PostTweet - failed. {0}", error));
callback(false);
}
else
{
callback(true);
}
}
Upvotes: 0
Reputation: 21
I don't have enough rep to leave a comment, but Antony's code was useful in getting things moving.
The issue is that the Uri.EscapeDataString method used by the library has a character limit, so if you have a large file-size (and therefore a long base-64 string), that method will fail to add the correct signature/timestamp stuff for Twitter, therefore resulting in a 401 when trying to upload the media.
So an easy work-around is to split up the base64 string into smaller chunks, escape those, and then piece it all together for the final POST. The code below was actually taken from another SO question about Uri.EscapeDataString. Simply call this method instead of Uri.EscapeDataString when building the form object and you should be all good.
private static string EscapeString(string originalString)
{
int limit = 2000;
StringBuilder sb = new StringBuilder();
int loops = originalString.Length / limit;
for (int i = 0; i <= loops; i++)
{
if (i < loops)
{
sb.Append(Uri.EscapeDataString(originalString.Substring(limit * i, limit)));
}
else
{
sb.Append(Uri.EscapeDataString(originalString.Substring(limit * i)));
}
}
return sb.ToString();
}
I've been using this on my latest game, and it allows players to upload animated GIFs with ease, and have yet to find any issues, our max file size is around 2mb and works fine.
Good luck!
Upvotes: 2
Reputation: 46
I also had the same issue. I solved it by reducing the size of the image I was trying to post. I'm not sure what the limit is but I found 256*256 jpg worked fine.
I also noticed your code is a little different to mine. Here's my code
Dictionary<string, string> parameters = new Dictionary<string, string>();
string encoded64ImageData = ImageToBase64( imageData );
parameters.Add("media_data", encoded64ImageData );
// Add data to the form to post.
WWWForm form = new WWWForm();
form.AddField( "media_data", encoded64ImageData );
// HTTP header
Dictionary<string, string> headers = new Dictionary<string, string>();
string url = UploadMediaURL;
string auth = GetHeaderWithAccessToken("POST", url, consumerKey, consumerSecret, accessToken, parameters);
headers.Add( "Authorization", auth );
headers.Add( "Content-Transfer-Encoding", "base64" );
WWW web = new WWW(url, form.data, headers);
yield return web;
The Twitter docs say you need to use media_data when submitting 64bit encoded media. media/upload
I also read that you need to define "Content-Transfer-Encoding=base64" when submitting 64bit data forms... This may or may not be necessary, I haven't tried it without.
Upvotes: 2
Reputation: 99
You should add the media parameter only in the WWWForm object. According to the documentation, when uploading media:
OAuth is handled a little differently. POST or query string parameters are not used when calculating an OAuth signature basestring or signature. Only the oauth_* parameters are used.
Add the media in the parameter dictionary is generating the error during the creation of a signature (made by GetHeaderWithAccessToken).
Upvotes: 0