title: How to post image on twitter in Phonegap using javascript
body: <p>I'm currently implementing a web smartphone application with Phonegap. On this application, users can post images they take with the phone camera on Facebook. This feature has been succesfully implemented only using javascript, by sending a base 64 encoded image. Now, I want to implement the same feature using Twitter.</p>
  
  <p>I found some very interesting blog posts about this and I'm already be able to update the user status only using javascript... but I can't post images too using the update_with_media Twitter web service.</p>
  
  <p>According too this <a href="http://mywebsolutions.blogspot.fr/2013/02/post-image-on-twitter-in-phonegap-using.html">post</a>, someone says it's impossible to implement this operation without using a server side code (like a php script for example).</p>
  
  <p>So my question is : is it possible to use the update_with_media Twitter web service only with javascript ?</p>
  
  <p>I send you my code to have an overview of the current solution. I've taken this article as working base : <a href="http://oodlestechnologies.com/blogs/Twitter-integration-on-PhoneGap-using-ChildBrowser-and-OAuth-for-iOS-and-Android-Platforms">http://oodlestechnologies.com/blogs/Twitter-integration-on-PhoneGap-using-ChildBrowser-and-OAuth-for-iOS-and-Android-Platforms</a></p>
  
  <p>Here is my HTML code. </p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
      &lt;head&gt;
          &lt;title&gt;Test&lt;/title&gt;
          &lt;script type="text/javascript" src="../js/jquery/jquery.min.js"&gt;&lt;/script&gt;
          &lt;script type="text/javascript" src="../cordova-2.5.0.js"&gt;&lt;/script&gt;
          &lt;script type="text/javascript" src="../js/childBrowser/childbrowser.js"&gt;&lt;/script&gt;
          &lt;script type="text/javascript" src="../js/helpers/jsOAuth-1.3.6.js"&gt;&lt;/script&gt;
          &lt;script type="text/javascript" src="../js/helpers/twitter.js"&gt;&lt;/script&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;h4&gt;Oodles Twitter App&lt;/h4&gt;
          &lt;table border="1"&gt;
              &lt;tr&gt;
                  &lt;th&gt;Login using Twitter&lt;/th&gt;
                  &lt;th&gt;
                      &lt;button id="loginBtn" onclick="Twitter.init();"&gt;Login&lt;/button&gt;
                      &lt;button id="logoutBtn" onclick="logOut();"&gt;Logout&lt;/button&gt;
                  &lt;/th&gt;
              &lt;/tr&gt;
              &lt;tr id="tweetText"&gt;
                  &lt;td colspan="2"&gt;&lt;textarea id="tweet"&gt;&lt;/textarea&gt;&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr id="tweetBtn"&gt;
                  &lt;td colspan="2" align="right"&gt;
                      &lt;button id="tweeter" onclick="Twitter.tweet();"&gt;Tweet&lt;/button&gt;
                  &lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;&lt;td colspan="2"&gt;&lt;div id="welcome"&gt;Please Login to use this app&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
          &lt;/table&gt;
          &lt;br/&gt;
          &lt;br/&gt;
          &lt;button onclick="javascript:location.reload();"&gt;Recharger la page&lt;/button&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>Here is my twitter.js code : (The point is in the post method)</p>
  
  <pre><code>$(document).ready(function() {
      document.addEventListener("deviceready", onDeviceReady, false);
  });
  
  function onDeviceReady() {
      var root = this;
      cb = window.plugins.childBrowser;
      if (!localStorage.getItem(twitterKey)) {
          $("#loginBtn").show();
          $("#logoutBtn").hide();
          $("tweetBtn").hide();
          $("tweetText").hide();
      }
      else {
          $("#loginBtn").hide();
          $("#logoutBtn").show();
          $("tweetBtn").show();
          $("tweetText").show();
      }
  
      if (cb != null) {
          cb.onLocationChange = function(loc) {
              root.locChanged(loc);
          };
          cb.onClose = function() {
              root.onCloseBrowser()
          };
          cb.onOpenExternal = function() {
              root.onOpenExternal();
          };
      }
  }
  
  function onCloseBrowser() {
      console.log("onCloseBrowser!");
  }
  
  function locChanged(loc) {
      console.log("locChanged!");
  }
  
  function onOpenExternal() {
      console.log("onOpenExternal!");
  }
  
  // Consumer key : ...
  // Consumer secret : ...
  
  // GLOBAL VARS
  var oauth; // It Holds the oAuth data request
  var requestParams; // Specific param related to request
  var options = {consumerKey: '...', consumerSecret: '...', callbackUrl: "http://www.google.fr"};
  var twitterKey = "twtrKey"; // This key is used for storing Information related   
  var Twitter = {
      init: function() {
          // Apps storedAccessData , Apps Data in Raw format
          var storedAccessData, rawData = localStorage.getItem(twitterKey);
          // here we are going to check whether the data about user is already with us.
          if (localStorage.getItem(twitterKey) !== null) {
              // when App already knows data
              storedAccessData = JSON.parse(rawData); //JSON parsing
              //options.accessTokenKey = storedAccessData.accessTokenKey; // data will be saved when user first time signin
              options.accessTokenSecret = storedAccessData.accessTokenSecret; // data will be saved when user first first signin
  
              // javascript OAuth take care of everything for app we need to provide just the options
              oauth = OAuth(options);
              oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
                      function(data) {
                          var entry = JSON.parse(data.text);
                          console.log("USERNAME: " + entry.screen_name);
                      }
              );
          }
          else {
              // we have no data for save user
              oauth = OAuth(options);
              oauth.get('https://api.twitter.com/oauth/request_token',
                      function(data) {
                          requestParams = data.text;
                          cb.showWebPage('https://api.twitter.com/oauth/authorize?' + data.text); // This opens the Twitter authorization / sign in page
                          cb.onLocationChange = function(loc) {
                              Twitter.success(loc);
                          }; // Here will will track the change in URL of ChildBrowser
                      },
                      function(data) {
                          console.log("ERROR: " + JSON.stringify(data));
                      }
              );
          }
      },
      /*
       When ChildBrowser's URL changes we will track it here.
       We will also be acknowledged was the request is a successful or unsuccessful
       */
      success: function(loc) {
  
          // Here the URL of supplied callback will Load
  
          /*
           Here Plugin will check whether the callback Url matches with the given Url
           */
          if (loc.indexOf("http://www.google.fr") &gt;= 0) {
  
              // Parse the returned URL
              var index, verifier = '';
              var params = loc.substr(loc.indexOf('?') + 1);
  
              params = params.split('&amp;');
              for (var i = 0; i &lt; params.length; i++) {
                  var y = params[i].split('=');
                  if (y[0] === 'oauth_verifier') {
                      verifier = y[1];
                  }
              }
  
              // Here we are going to change token for request with token for access
  
              /*
               Once user has authorised us then we have to change the token for request with token of access
               here we will give data to localStorage.
               */
              oauth.get('https://api.twitter.com/oauth/access_token?oauth_verifier=' + verifier + '&amp;' + requestParams,
                      function(data) {
                          var accessParams = {};
                          var qvars_tmp = data.text.split('&amp;');
                          for (var i = 0; i &lt; qvars_tmp.length; i++) {
                              var y = qvars_tmp[i].split('=');
                              accessParams[y[0]] = decodeURIComponent(y[1]);
                          }
  
                          $('#oauthStatus').html('&lt;span style="color:green;"&gt;Success!&lt;/span&gt;');
                          $('#stage-auth').hide();
                          $('#stage-data').show();
                          oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);
  
                          // Saving token of access in Local_Storage
                          var accessData = {};
                          accessData.accessTokenKey = accessParams.oauth_token;
                          accessData.accessTokenSecret = accessParams.oauth_token_secret;
  
                          // Configuring Apps LOCAL_STORAGE
                          console.log("TWITTER: Storing token key/secret in localStorage");
                          localStorage.setItem(twitterKey, JSON.stringify(accessData));
  
                          oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
                                  function(data) {
                                      var entry = JSON.parse(data.text);
                                      console.log("TWITTER USER: " + entry.screen_name);
                                      $("#welcome").show();
                                      document.getElementById("welcome").innerHTML = "welcome " + entry.screen_name;
                                      successfulLogin();
                                      // Just for eg.
                                      app.init();
                                  },
                                  function(data) {
                                      console.log("ERROR: " + data);
                                  }
                          );
  
                          // Now we have to close the child browser because everthing goes on track.
  
                          window.plugins.childBrowser.close();
                      },
                      function(data) {
                          console.log(data);
  
  
                      }
              );
          }
          else {
              // Just Empty
          }
      },
      tweet: function() {
          var storedAccessData, rawData = localStorage.getItem(twitterKey);
  
          storedAccessData = JSON.parse(rawData); // Paring Json 
          options.accessTokenKey = storedAccessData.accessTokenKey; // it will be saved on first signin
          options.accessTokenSecret = storedAccessData.accessTokenSecret; // it will be save on first login
  
          // javascript OAuth will care of else for app we need to send only the options
          oauth = OAuth(options);
          oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
                  function(data) {
                      var entry = JSON.parse(data.text);
                      Twitter.post();
                  }
          );
      },
      /*
       We now have the data to tweet
       */
      post: function() {
          alert('Post !');
          var theTweet = $("#tweet").val(); // You can change it with what else you likes.
  
          oauth.post('https://upload.twitter.com/1/statuses/update_with_media.json',
                  {
                      'status': theTweet,
                      'media': //HERE IS THE PROBLEM, WHAT TO DO HERE ?
                  }, "multipart/form-data",
                  function(data)
                  {
                      alert('Data 1 !');
                      console.log('------Data1 : ' + data);
                      var entry = JSON.parse(data.text);
                      console.log(entry);
                      done();
                  },
                  function(data) {
                      //var json_result = JSON.parse(data);
                      //alert(json_result.text.error);
                      var entry = JSON.stringify(data);
                      console.log('------Data2 : ' + entry);
                  }
          );
      }
  
  }
  
  function done() {
      alert("OKKK !");
      $("#tweet").val('');
  }
  
  
  function successfulLogin() {
      $("#loginBtn").hide();
      $("#logoutBtn,#tweet,#tweeter,#tweetBtn,#tweetText").show();
  
  }
  
  function logOut() {
      //localStorage.clear();
      window.localStorage.removeItem(twitterKey);
      document.getElementById("welcome").innerHTML = "Please Login to use this app";
      $("#loginBtn").show();
      $("#logoutBtn,#tweet,#tweeter,#tweetText,#tweetBtn").hide();
  
  }
  </code></pre>
  
  <p>After many tests (sending a base64 image, sending a blob, sending a binary file, ...) here is the return message from Twitter I have :</p>
  
  <blockquote>
    <p>{\"errors\":[{\"message\":\"Internal
    error\",\"code\":131}]}","xml":"","requestHeaders":{"Content-Type":"multipart/form-data"},"responseHeaders":{"date":"Fri,
    19 Apr 2013 15:45:28
    GMT","content-encoding":"deflate","strict-transport-security":"max-age=631138519","status":"500
    Internal Server
    Error","server":"tfe","content-type":"application/json;
    charset=utf-8","version":"HTTP/1.1"}}</p>
  </blockquote>
  
  <p>A "solution" (by send a blob) have been posted on the Twitter dev forum but not working for me : dev.twitter.com/discussions/6969</p>
  
  <p>Does anyone want to implement the same feature or have a solution ? Thank you !</p>
  
  <p><strong>------ EDITED :</strong></p>
  
  <p>I just want to use <strong>Javascript</strong> and I don't want to implement any server-side solution (no PHP, C#, Java...).</p>