Uploading Images to tumblr API from Android
Asked Answered
H

5

17

One assumed using the Tumblr API to upload images would be easy. It isn't. (EDIT It is now, see Edit 2 at the end of this entry)

My app is supposed to upload an image to tumblr. I would prefer doing that from a service but for now I use an activity that closes itself as soon as its done uploading. In OnCreate() the user is authenticated:

consumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);

// It uses this signature by default
// consumer.setMessageSigner(new HmacSha1MessageSigner());

provider = new CommonsHttpOAuthProvider(REQUEST_TOKEN_URL,ACCESS_TOKEN_URL,AUTH_URL);

String authUrl;
try 
{
authUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
Log.d(TAG, "Auth url:" + authUrl);

startActivity(new Intent("android.intent.action.VIEW", Uri.parse(authUrl)));

} 

This opens a browser activity where the user can add username and passoword and then the app returns to the activity (this is also why I have to use an activity, I don't know how to do this from a service)

Returning from the browser the data is extracted:

Uri uri = context.getIntent().getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) 
{  
    Log.d(TAG, "uri!=null");
    String verifier = uri.getQueryParameter("oauth_verifier");  
    Log.d(TAG, "verifier"+verifier);
    try 
    {
        provider.setOAuth10a(true);
        provider.retrieveAccessToken(consumer, verifier);
        Log.d(TAG, "try");
    } 
    catch (Exception e) 
    {
        Log.e(TAG, e.toString());
        e.printStackTrace();
    } 
OAUTH_TOKEN = consumer.getToken();
OAUTH_SECRET = consumer.getTokenSecret();

Most of these two snippets I got from here and they work well.

With these tokens I can now try putting data on tumblr. When I try to add Text this works fine using this method:

private void createText()
{
    if(!OAUTH_TOKEN.equals(""))
    {

        HttpContext context = new BasicHttpContext();
        HttpPost request = new HttpPost("http://api.tumblr.com/v2/blog/" + blogname + ".tumblr.com/post");

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs.add(new BasicNameValuePair("type", "text")); 
        nameValuePairs.add(new BasicNameValuePair("body", "this is just a test"));  

        try 
        {
        request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        } 
        catch (UnsupportedEncodingException e1) 
        {
            Log.e(TAG, e1.toString());
            e1.printStackTrace();
        }

        if (consumer == null)
        {
            consumer = new CommonsHttpOAuthConsumer(OAuthConstants.TUMBR_CONSUMERKEY, OAuthConstants.TUMBR_SECRETKEY);
        }
        if (OAUTH_TOKEN == null || OAUTH_SECRET == null)
        {
            Log.e(TAG, "Not logged in error");
        }
        consumer.setTokenWithSecret(OAUTH_TOKEN, OAUTH_SECRET);

        try 
        {
            consumer.sign(request);
        } 
        catch (OAuthMessageSignerException e) 
        {

        } 
        catch (OAuthExpectationFailedException e) 
        {
        } 
        catch (OAuthCommunicationException e) 
        {
        }
        HttpClient client = new DefaultHttpClient();
        //finally execute this request
        try 
        {
            HttpResponse response = client.execute(request, context);
            HttpEntity responseEntity = response.getEntity(); 
            if (responseEntity != null) 
            { 
                Log.d(TAG, "responseEntety!=null");
                try 
                {
                    Log.d(TAG, EntityUtils.toString(responseEntity));
                } 
                catch (ParseException e) 
                {
                    e.printStackTrace();
                    Log.e(TAG, e.toString());
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                    Log.e(TAG, e.toString());
                } // gives me {"meta":{"status":401,"msg":"Not Authorized"},"response":[]} when I try to upload a photo
            }
            else
            {
                Log.d(TAG, "responseEntety==null");
            }
        } 
        catch (ClientProtocolException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    PostToTumblr.this.finish();
}

As you can see here http://www.tumblr.com/blog/snapnowandroid (at least as of this time) the text "this is just a test" is posted.

However, when I try to post images, it gets strange. Now I have checked around and apparently this is a well known issue with the tumblr API, which has excessively been discussed here and some have solved it in other programming languages (for example here) but I have been unable to repeat those successes.

The method (in its entirety below) has the exact same structure to the above method (that works), the nameValuePairs are just different

The method is given a Bitmap variable called photo:

    private void uploadToTumblr(Bitmap photo)

This bitmap is converted into an array:

ByteArrayOutputStream stream = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();

The nameValuePairs are filled as follows:

nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("type", enc), URLEncoder.encode("photo", enc)));
nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("caption", enc), URLEncoder.encode(text, enc))); 
nameValuePairs.add(new BasicNameValuePair("data", Base64.encodeToString(bytes, Base64.URL_SAFE))); 

The result is a {"meta":{"status":400,"msg":"Bad Request"},"response":{"errors":["Error uploading photo."]}} from the tumblr api.

I have tries encoding the picture differently as discribed in this article but without any changes.

//http://www.coderanch.com/t/526487/java/java/Java-Byte-Hex-String
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 3];
int v;
for ( int j = 0; j < bytes.length; j++ ) 
{
    v = bytes[j] & 0xFF;
    hexChars[j * 3] = '%';
    hexChars[j * 3 + 1] = hexArray[v >>> 4];
    hexChars[j * 3 + 2] = hexArray[v & 0x0F];
}
String s = new String(hexChars);                
s = URLEncoder.encode(s, enc);
nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("data", enc), s)); 

Here the entire method (without the hex encoding):

private void uploadToTumblr(Bitmap photo)
{
    if(!OAUTH_TOKEN.equals(""))
    {

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byte[] bytes = stream.toByteArray();

        String text ="SNAP";


        HttpContext context = new BasicHttpContext();
        HttpPost request = new HttpPost("http://api.tumblr.com/v2/blog/" + blogname + ".tumblr.com/post");

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); 
        String enc = "UTF-8"; 

        try 
        {
            nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("type", enc), URLEncoder.encode("photo", enc)));
            nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("caption", enc), URLEncoder.encode(text, enc))); 
            nameValuePairs.add(new BasicNameValuePair("data", Base64.encodeToString(bytes, Base64.URL_SAFE))); 
        } 
        catch (UnsupportedEncodingException e2) 
        {
            Log.e(TAG, e2.toString());
            e2.printStackTrace();
        } 
        try 
        {
            request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        } 
        catch (UnsupportedEncodingException e1) 
        {
            Log.e(TAG, e1.toString());
            e1.printStackTrace();
        }

        if (consumer == null)
        {
            consumer = new CommonsHttpOAuthConsumer(OAuthConstants.TUMBR_CONSUMERKEY, OAuthConstants.TUMBR_SECRETKEY);
        }
        if (OAUTH_TOKEN == null || OAUTH_SECRET == null)
        {
            //throw new LoginErrorException(LoginErrorException.NOT_LOGGED_IN);
            Log.e(TAG, "Not logged in error");
        }
        consumer.setTokenWithSecret(OAUTH_TOKEN, OAUTH_SECRET);

            try 
            {
                consumer.sign(request);
            } 
            catch (OAuthMessageSignerException e) 
            {

            } 
            catch (OAuthExpectationFailedException e) 
            {

            } 
            catch (OAuthCommunicationException e) 
            {
            }

            HttpClient client = new DefaultHttpClient();

            //finally execute this request
            try 
            {
                HttpResponse response = client.execute(request, context);
                HttpEntity responseEntity = response.getEntity(); 
                if (responseEntity != null) 
                { 
                    Log.d(TAG, "responseEntety!=null");
                    try 
                    {
                        Log.d(TAG, EntityUtils.toString(responseEntity));
                    } 
                    catch (ParseException e) 
                    {
                        e.printStackTrace();
                        Log.e(TAG, e.toString());
                    } 
                    catch (IOException e) 
                    {
                        e.printStackTrace();
                        Log.e(TAG, e.toString());
                    } 
                }
                else
                {
                    Log.d(TAG, "responseEntety==null");
                }
            } 
            catch (ClientProtocolException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


    }

    else
    {
        Log.d(TAG, "upload imposble... Toklen not set");
    }
    PostToTumblr.this.finish();
}

Now, while there are several things I am unhappy with (for example that this is done using an activity instead of a service) the big issue here is clearly the problem of uploading images. I am by no means the first to have this problem, so has anyone been able to get this done in java?

Edit 1

Have not made any progress with the problem at hand but created a workaround that might be nice for people who have the same issue. Tumblr offers posting via mail and you can programm android to send emails in the background as shown here. This works very well but you need to ask users to provide their mail account data and the Tumblr-mail Adress to post.

Edit 2

Years have pased and using email is no longer the easy way to do it. With jumblr there is finally a good API for Java that will work on android. OAuth-Authentication is no fun (it never is) but once you get past this, its fantastic.

Now, technically the question of how to do the authentication does not belong here but It's my overly long question, so I'll just paste some code here and if it's not interesting to you just skip it.

This uses a jar called jumblr-0.0.10-jar-with-dependencies.jar

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;

import com.tumblr.jumblr.JumblrClient;
import com.tumblr.jumblr.request.RequestBuilder;
import com.tumblr.jumblr.types.Blog;
import com.tumblr.jumblr.types.User;

import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.TumblrApi;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;

import java.io.File;


public class Tumblr
{
private static final String PROTECTED_RESOURCE_URL = "http://api.tumblr.com/v2/user/info";

static OAuthService service;
static Token requestToken=null;


public static void share(final Activity ctx, File file)
{
    Thread tt = new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            JumblrClient client = new JumblrClient(Tumblr_Constants.CONSUMER_KEY, Tumblr_Constants.CONSUMER_SECRET);
            RequestBuilder requestBuilder = client.getRequestBuilder();
            requestBuilder.setConsumer(Tumblr_Constants.CONSUMER_KEY, Tumblr_Constants.CONSUMER_SECRET);
            SharedPreferences settings = ctx.getSharedPreferences("TumblrData", 0);
            String oauthToken=settings.getString("OauthToken", "");
            String oauthTokenSecret=settings.getString("OauthSecret", "");
            if(oauthToken.equals("") || oauthTokenSecret.equals(""))
            {
                authenticate(ctx);
                while(WebViewFragment.verifier.equals(""))
                {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                String v = WebViewFragment.verifier;
                Token accessToken = authenticatefurther(v);
                SharedPreferences.Editor edit = settings.edit();
                edit.putString("OauthToken", accessToken.getToken());
                edit.putString("OauthSecret", accessToken.getSecret());
                edit.commit();
                oauthToken=settings.getString("OauthToken", "");
                oauthTokenSecret=settings.getString("OauthSecret", "");
            }
            if(!oauthToken.equals("") && !oauthTokenSecret.equals(""))
            {
                client.setToken(oauthToken, oauthTokenSecret);

                User user = client.user();
                System.out.println(user.getName());

                for (Blog blog : user.getBlogs()) {
                    Log.d("TUMBLR", blog.getTitle());
                }
            }
        }

    });
    tt.start();

}

private static void authenticate(Context ctx) {
    service = new ServiceBuilder()
            .provider( TumblrApi.class )
            .apiKey(Tumblr_Constants.CONSUMER_KEY)
            .apiSecret(Tumblr_Constants.CONSUMER_SECRET)
            .callback("snapnao://snapnao.de/ok") // OOB forbidden. We need an url and the better is on the tumblr website !
            .build();


    Log.d("TUMBLR", "=== Tumblr's OAuth Workflow ===" );
    System.out.println();

    // Obtain the Request Token
    Log.d("TUMBLR", "Fetching the Request Token...");
    requestToken = service.getRequestToken();
    Log.d("TUMBLR", "Got the Request Token!");
    Log.d("TUMBLR", "");

    Log.d("TUMBLR", "Now go and authorize Scribe here:" );
    Log.d("TUMBLR", service.getAuthorizationUrl( requestToken ) );

    String url = service.getAuthorizationUrl(requestToken);


    Intent i = new Intent(ctx, WebViewFragment.class);
    i.putExtra("url", url);
    ctx.startActivity(i);


}

private static Token authenticatefurther(String v)
{
    Token accessToken = null;
    Log.d("TUMBLR", "And paste the verifier here");
    Log.d("TUMBLR", ">>");

    Verifier verifier = new Verifier( v);
    Log.d("TUMBLR", "");

    // Trade the Request Token and Verfier for the Access Token
    Log.d("TUMBLR", "Trading the Request Token for an Access Token...");
    accessToken = service.getAccessToken( requestToken ,
            verifier );
    Log.d("TUMBLR", "Got the Access Token!");
    Log.d("TUMBLR", "(if your curious it looks like this: " + accessToken + " )");

    Log.d("TUMBLR", "");

    return accessToken;
}


}

The WebViewFragement looks like this:

import android.app.Activity;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Bundle;
import android.util.Log;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;


public class WebViewFragment extends Activity 
{
public static String verifier="";
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.webviewfragment);

    String url = getIntent().getStringExtra("url");
    Log.d("TUMBLR", "webview-> "+url);
    WebView view = (WebView) findViewById(R.id.webView);
    view.setWebViewClient(
            new SSLTolerentWebViewClient()
    );
    view.getSettings().setJavaScriptEnabled(true);
    view.loadUrl(url);
}

// SSL Error Tolerant Web View Client
private class SSLTolerentWebViewClient extends WebViewClient {

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed(); // Ignore SSL certificate errors
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        Log.d("TUMBLR", "+++++"+url);
        if(url.contains("oauth_verifier="))
        {
            String[] x = url.split("oauth_verifier=");
            verifier=x[1].replace("#_=_", "");
            WebViewFragment.this.finish();
        }
    }
}
}
Hazaki answered 12/12, 2012 at 17:22 Comment(6)
Why are you not encoding the data input name in the name-value pairs like you are type and caption?Crepuscular
Actually encoding the input name is not neccesary (as one can see from the working code for text posts in the beginning of the post) It's just one of the things I tried to get it to work. Should have taken that out again for clarity in the example code.Hazaki
First thing I notice is that you're using data not source but you're sending it a string not an array. Try using source with an encoded string or data as an array with one encoded string element if you're just uploading one photo.Impulse
Someone was able to upload a jpg image. Try Bitmap.CompressFormat.JPEG instead.Foster
@Impulse 'source' is used for URLs to an image, 'data' is used if you are sending the actual bytes of the image. This is outlined here: tumblr.com/docs/en/api/v2#postingWindsor
plz answer my question if any body have any solution.#21739514Glaswegian
R
3

Why don't you use Jumblr the official Java client for Tumblr.

Regards.

Radarscope answered 16/4, 2013 at 1:26 Comment(3)
From the commit history I gather that it did not exist when I posted the question. Seems worth a look now. Thanks.Hazaki
Oops, maybe I thought you had a flux capacitor :DRadarscope
I tried Jumblr and I couldn't get image upload to work... #26272023Somniloquy
M
3

You can easily do this using jumblr - Tumblr java client

JumblrClient client = new JumblrClient(Constant.CONSUMER_KEY,Constant.CONSUMER_SECRET);

client.setToken(preferences.getString("token",null), preferences.getString("token_secret", null));

PhotoPost pp = client.newPost(client.user().getBlogs().get(0).getName(),PhotoPost.class);

pp.setCaption(caption);
// pp.setLinkUrl(link);
// pp.setSource(mImage); // String URL
pp.setPhoto(new Photo(imgFile));
pp.save();
Marismarisa answered 29/8, 2014 at 10:10 Comment(1)
Thanks, eltabo mentioned this in another answer. back when I had this problem jumblr did not exist, now it is the best solution.Hazaki
S
0

This worked for me...

nameValuePairs.add(new BasicNameValuePair(URLEncoder
                .encode("type", "UTF-8"),
                     URLEncoder.encode("photo", "UTF-8")));
Log.e("Tumblr", "Image shareing file path" + filePath);
nameValuePairs.add(new BasicNameValuePair("caption", caption));
nameValuePairs.add(new BasicNameValuePair("source", filePath));`

where filePath is http url.

Shul answered 12/6, 2013 at 12:17 Comment(2)
Thanks for your answer. I've submitted an edit to tidy up the format - When asking or answering questions, it's tidier if you indent code with four spaces rather than use grave accents, as they don't respect your newlines.Cattery
i got : {"meta":{"status":400,"msg":"Bad Request"},"response":{"errors":["Error uploading photo."]}}Glaswegian
G
0

I have done using following method. you can try this.

//paramString="text you want to put in caption"

private void postPhotoTumblr(String uploadedImagePhotoUrl, String paramString)
{
  CommonsHttpOAuthConsumer localCommonsHttpOAuthConsumer = getTumblrConsumer();
  String str1 = "logged in username";
  String encodedImage = uploadedImagePhotoUrl;
  DefaultHttpClient localDefaultHttpClient = new DefaultHttpClient();
  HttpPost localHttpPost = new HttpPost("http://api.tumblr.com/v2/blog/" + str1 + ".tumblr.com/post");
  try
  {

    ArrayList localArrayList = new ArrayList();
    localArrayList.add(new BasicNameValuePair("type", "photo"));
    BasicNameValuePair localBasicNameValuePair = new BasicNameValuePair("caption", paramString);
    localArrayList.add(localBasicNameValuePair);
    localArrayList.add(new BasicNameValuePair("data",encodedImage));
    UrlEncodedFormEntity localUrlEncodedFormEntity = new UrlEncodedFormEntity(localArrayList);
    localHttpPost.setEntity(localUrlEncodedFormEntity);
    localCommonsHttpOAuthConsumer.sign(localHttpPost);
    InputStream localInputStream = localDefaultHttpClient.execute(localHttpPost).getEntity().getContent();
    InputStreamReader localInputStreamReader = new InputStreamReader(localInputStream);
    BufferedReader localBufferedReader = new BufferedReader(localInputStreamReader);
    StringBuilder localStringBuilder = new StringBuilder();
    while (true)
    {
      String str2 = localBufferedReader.readLine();
      if (str2 == null)
      {
        Log.i("DATA post resp", localStringBuilder.toString());
        break;
      }
      localStringBuilder.append(str2);
    }
  }
  catch (ClientProtocolException localClientProtocolException)
  {
    localClientProtocolException.printStackTrace();
  }
  catch (IOException localIOException)
  {
    localIOException.printStackTrace();
  }
  catch (OAuthMessageSignerException localOAuthMessageSignerException)
  {
    localOAuthMessageSignerException.printStackTrace();
  }
  catch (OAuthExpectationFailedException localOAuthExpectationFailedException)
  {
    localOAuthExpectationFailedException.printStackTrace();
  }
  catch (OAuthCommunicationException localOAuthCommunicationException)
  {
    localOAuthCommunicationException.printStackTrace();
  }
}

EDIT : First Upload image to Web Server then get Url and try to Post with uploaded Url or File path. it will work fine sure... :)

Glanti answered 19/7, 2013 at 10:20 Comment(2)
i got {"meta":{"status":400,"msg":"Bad Request"},"response":{"errors":["Error uploading photo."]}}Glaswegian
i am able to post the text message this not an image. Will. u help me plzGlaswegian
B
0

I have use multipart public class VideoUploader extends AsyncTask {

    ProgressDialog progressDialog;

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        progressDialog = ProgressDialog.show(RecordingActivity.this, "",
                "Uploading video.. ");
        super.onPreExecute();
    }

    @Override
    protected JSONObject doInBackground(String... params) {
        JSONObject jsonObject = null;
        StringBuilder builder = new StringBuilder();
        try {
            String url = UrlConst.VIDEO_URL;
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(url);

            FileBody filebodyVideo = new FileBody(new File(params[0]));
            StringBody title = new StringBody("uploadedfile: " + params[0]);
            StringBody description = new StringBody(
                    "This is a video of the agent");
            // StringBody code = new StringBody(realtorCodeStr);

            MultipartEntity reqEntity = new MultipartEntity();
            reqEntity.addPart("uploadedfile", filebodyVideo);
            reqEntity.addPart("title", title);
            reqEntity.addPart("description", description);
            // reqEntity.adddPart("code", code);
            httppost.setEntity(reqEntity);

            // DEBUG
            System.out.println("executing request "
                    + httppost.getRequestLine());
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity resEntity = response.getEntity();

            // DEBUG
            StatusLine status = response.getStatusLine();
            int statusCode = status.getStatusCode();
            System.out.println(response.getStatusLine());
            if (resEntity != null) {
                System.out.println(EntityUtils.toString(resEntity));
            } // end if

            if (resEntity != null) {
                resEntity.consumeContent();
            } // end if
            if (statusCode == 200) {
                InputStream content = resEntity.getContent();
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(content));
                String line;
                while ((line = reader.readLine()) != null) {
                    builder.append(line);
                }
                jsonObject = new JSONObject(builder.toString());
                return jsonObject;
            } else {
                Log.e(LoginActivity.class.toString(),
                        "Failed to download file");
            }
            httpclient.getConnectionManager().shutdown();

        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }

    @Override
    protected void onPostExecute(JSONObject result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        progressDialog.dismiss();
        if (result != null) {

            try {

                JSONObject jsonObject = result
                        .getJSONObject(ParsingTagConst.COMMANDRESULT);
                String strSuccess = jsonObject
                        .getString(ParsingTagConst.SUCCESS);
                String responseString = jsonObject
                        .getString(ParsingTagConst.RESPONSE_STRING);
                Toast.makeText(RecordingActivity.this, "" + responseString,
                        Toast.LENGTH_LONG).show();
                if (strSuccess.equals("1")) {
                    // get here your response
                }

            } catch (Exception e) {
                // TODO: handle exception
            }
        }

    }

}



enter code here
Binnings answered 20/9, 2013 at 4:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.