Created
May 24, 2014 07:06
-
-
Save kamend/85c37cb2e6260a2ecf2d to your computer and use it in GitHub Desktop.
How post an image to Tumblr via their V2 API, inside Unity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Text; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Text.RegularExpressions; | |
using System.Globalization; | |
using System.Security.Cryptography; | |
using System.IO; | |
public class URLUtils { | |
private static string _UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; | |
public static string URLEncodeBytes(byte[] value, bool encodePercent) | |
{ | |
var osb = new StringBuilder(value.Length * 3); | |
for (var x = 0; x < value.Length; x++) | |
{ | |
var b = value[x]; | |
if( (char)b == '%') { | |
osb.Append ("%25"); | |
} else if ((_UnreservedChars.IndexOf((char)b) == -1) && ((char)b) != '~' && (((char)b) != '%')) | |
{ | |
osb.AppendFormat("%{0:X2}", b); | |
} | |
else | |
{ | |
osb.Append((char)b); | |
} | |
} | |
if(encodePercent) { | |
osb = osb.Replace("%", "%25");// Revisit to encode actual %'s | |
} | |
return osb.ToString(); | |
} | |
} | |
public class TumblrOAuth : MonoBehaviour { | |
private string consumerKey = ""; | |
private string consumerSecret = ""; | |
private string accessToken = ""; | |
private string accessTokenSecret = ""; | |
void Start () { | |
string imagePath = "file://"+Application.dataPath + "/../image.png"; | |
StartCoroutine(UploadImage("xxxx.tumblr.com", imagePath)); | |
} | |
private static string GenerateTimeStamp() | |
{ | |
// Default implementation of UNIX time of the current UTC time | |
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); | |
return Convert.ToInt64(ts.TotalSeconds, CultureInfo.CurrentCulture).ToString(CultureInfo.CurrentCulture); | |
} | |
private static string GenerateNonce() | |
{ | |
// Just a simple implementation of a random number between 123400 and 9999999 | |
return new System.Random().Next(123400, int.MaxValue).ToString(); | |
} | |
IEnumerator UploadImage(string blogAddress, string imagePath) { | |
string uri = string.Format("http://api.tumblr.com/v2/blog/{0}/post",blogAddress); | |
// download image | |
WWW img = new WWW(imagePath); | |
yield return img; | |
// signature | |
Dictionary<string, string> options = new Dictionary<string, string>(); | |
string timestamp = GenerateTimeStamp(); | |
string nonce = timestamp+GenerateNonce(); | |
string method = "POST"; | |
options.Add("oauth_nonce", nonce); | |
options.Add("oauth_timestamp", timestamp); | |
var stringBuilder = new StringBuilder(); | |
stringBuilder.Append(method+"&"); | |
stringBuilder.Append(Uri.EscapeDataString(uri)); | |
stringBuilder.Append("&"); | |
//the key value pairs have to be sorted by encoded key | |
var dictionary = new SortedDictionary<string, string> | |
{ | |
//oauth | |
{"oauth_token", accessToken}, | |
{"oauth_consumer_key", consumerKey}, | |
{"oauth_timestamp", timestamp}, | |
{"oauth_nonce", nonce}, | |
{"oauth_signature_method", "HMAC-SHA1"}, | |
{"oauth_version", "1.0"}, | |
// post params | |
{"type","photo"}, | |
{"data[0]",""} | |
}; | |
// encode all params | |
foreach (var keyValuePair in dictionary) | |
{ | |
byte[] bytesValue = System.Text.Encoding.ASCII.GetBytes(keyValuePair.Value); | |
string encodedValue; | |
if(keyValuePair.Key.IndexOf("data") > -1) { | |
// encode image data directly from the image bytes | |
// when creating the signature the % must be changed with %25, hence the true param for URLEncodeBytes | |
encodedValue = URLUtils.URLEncodeBytes(img.bytes, true); | |
} else { | |
encodedValue = URLUtils.URLEncodeBytes(bytesValue,false); | |
} | |
byte[] bytesKey = System.Text.Encoding.ASCII.GetBytes(keyValuePair.Key); | |
string encodedKey = URLUtils.URLEncodeBytes(bytesKey,false); | |
//append a = between the key and the value and a & after the value | |
stringBuilder.Append(string.Format("{0}%3D{1}%26", encodedKey, encodedValue)); | |
} | |
// the holy signature base! | |
string signatureBaseString = stringBuilder.ToString().Substring(0, stringBuilder.Length - 3); | |
string signatureKey = | |
Uri.EscapeDataString(consumerSecret) + "&" + | |
Uri.EscapeDataString(accessTokenSecret); | |
var hmacsha1 = new HMACSHA1( | |
System.Text.Encoding.ASCII.GetBytes(signatureKey) | |
); | |
// teh signature string | |
string signatureString = Convert.ToBase64String( | |
hmacsha1.ComputeHash( | |
System.Text.Encoding.ASCII.GetBytes(signatureBaseString))); | |
signatureString = Uri.EscapeDataString(signatureString); | |
// the authorize header | |
string auth = "OAuth oauth_token=\""+accessToken+"\", oauth_consumer_key=\""+consumerKey+"\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\""+timestamp+"\", oauth_nonce=\""+nonce+"\", oauth_version=\"1.0\", oauth_signature=\""+signatureString+"\""; | |
// the post data | |
// we have to build it ourselves, because if we use WWWForm, it will enforce it's own way of | |
// encoding the image data, and it will break things | |
// we don't change % to %25 when adding the post data | |
string imgDataEncoded = URLUtils.URLEncodeBytes(img.bytes, false); | |
StringBuilder postData = new StringBuilder(); | |
postData.Append("data%5B0%5D="); | |
postData.Append (imgDataEncoded); | |
postData.Append ("&type=photo"); | |
// send request | |
Hashtable headers = new Hashtable(); | |
headers["Authorization"] = auth; | |
headers["Content-type"] = "application/x-www-form-urlencoded"; | |
WWW web = new WWW(uri, System.Text.Encoding.ASCII.GetBytes(postData.ToString()), headers); | |
yield return web; | |
if (!string.IsNullOrEmpty(web.error)) | |
{ | |
Debug.Log(string.Format("GetAccessToken - failed. error : {0}", web.error)); | |
} else { | |
Debug.Log (web.text); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment