Trouble Uploading Media for Tweet in Google Apps Script

media
javascript
media-upload
animatedgif
api

#1

Hey all!

I have working code to get my Google Apps Script posting a tweet just fine, but I’m having trouble sending a Tweet with Image.

Boilerplate Code:

// https://github.com/googlesamples/apps-script-oauth1
// uses hard-coded access tokens from https://apps.twitter.com/app/#######/keys
// therefore, should be permanently accessing the twitter api as my user
//
function getTwitterService() {
  return OAuth1.createService('twitter')
    // Set the endpoint URLs.
    .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
    .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
    .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
    
    // Set the consumer key and secret.
    .setConsumerKey('############')
    .setConsumerSecret('#######################')
  
    .setAccessToken('#######################', '#######################')
}

Working code:

function getLatestTweet(id) {
  var twitterService = getTwitterService();
  var response = twitterService.fetch('https://api.twitter.com/1.1/statuses/user_timeline.json?count=1&tweet_mode=extended&user_id=' + id + '&screen_name=' + id);
  response = response.getContentText();
  return response; // string
}
function tweet(status) {
  var twitterService = getTwitterService();
  var response = twitterService.fetch('https://api.twitter.com/1.1/statuses/update.json',
    {
      "method": "post",
      "payload": {
        "status": status
      }
    }
  );
  response = response.getContentText();
  return response; // string
}

The function I’m trying to get working:

function tweetWithImage(status, imageurl) {
  
  var image = UrlFetchApp.fetch(imageurl).getBlob();
  
  // lol. the only way i can get the size of a blob is to add it to Drive, get it's size, then delete it 🙄
  var file = DriveApp.createFile(image);
  var size = file.getSize();
  file.setTrashed(true);
  
  var twitterService = getTwitterService();
  var response = twitterService.fetch('https://upload.twitter.com/1.1/media/upload.json?command=INIT&media_type=image/gif&total_bytes=' + size.toString(),
    {
      "muteHttpExceptions": true,
      "method": "post",
      "payload": {
        "media": image
      }
    });
  response = response.getContentText();
  Logger.log(response);
  return response; // string
}

When I call this function, I get
{"errors":[{"code":32,"message":"Could not authenticate you."}]}, which is odd, since the same keys work fine on the other functions. Help?


#2

Turns out, Twitter returns a very unhelpful “cannot authenticate you” error if your URL is bad.

Fixed code:

function tweetWithGIF(status, imageurl) {
  
  var image = UrlFetchApp.fetch(imageurl).getBlob();
  
  var size = getSize(image); // using ImgApp https://github.com/tanaikech/ImgApp
  
  if (size.filesize >= 5242880) {
    throw "Image must be below 5MB"
  }
  
  var twitterService = getTwitterService();
  // first, we tell twitter that we'd like a new media object to deposit an image into
  // https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init
  var response = twitterService.fetch('https://upload.twitter.com/1.1/media/upload.json',
    {
      "muteHttpExceptions": true,
      "method": "post",
      "payload": {
        "command": "INIT",
        "media_type": "image/gif",
        "media_category": "tweet_gif", // not in the docs as of july 2018, but mentioned by twitter employees in forums: https://twittercommunity.com/t/media-category-values/64781/7
        "total_bytes": size.filesize
      }
    });
  response = JSON.parse(response.getContentText());
  Logger.log(JSON.stringify(response));

  // great. now we have our media ID
  var mediaid = response.media_id_string;
  
  // ...and append media from there

}

Currently stuck trying to append the image data from the blob now…