Twitter AutoResponder with Google Scripts

Use this Google Script to setup Out of Office auto-replies in Twitter. The script reads all the Twitter @mentions and sends them a tweet with a custom status message.

 

/*     O U T   O F   O F F I C E   F O R   T W I T T E R    */
/*     - - -   - -   - - - - - -   - - -   - - - - - - -    */

/*     Written by Amit Agarwal http://labnol.org?p=27911    */
/*     For help, email amit@labnol.org or tweet @labnol     */

function start() {
  
  // Please enter dates in YYYY-MM-DD HH:MM format
  
  var OUTOFOFFICE_START_DATE  = "03/11/2013 18:13"; 
  var OUTOFOFFICE_END_DATE    = "03/11/2013 19:00";
  
  // This is your Out-Of-Office reply. Keep it less than 120 characters.
  
  var OUTOFOFFICE_TEXT = "I am currently out of the office,
                              with limited access to Twitter. Thanks!";  
   
  // Get your Twitter keys from dev.twitter.com
  
  var CONSUMER_KEY     = "AAA";
  var CONSUMER_SECRET  = "BBB";

  // Change this with your Twitter handle

  var TWITTER_HANDLE   = "labnol"; 
    
  // DO NOT MODIFY ANYTHING AFTER THIS LINE
  
  storeKeys ( CONSUMER_KEY, CONSUMER_SECRET, 
                       OUTOFOFFICE_TEXT, TWITTER_HANDLE );
  
  initialize ( OUTOFOFFICE_START_DATE, OUTOFOFFICE_END_DATE );
  
  // Make sure that Twitter oAuth is working

  doTwitter();
   
}


// Delete exiting Apps Script triggers, if any

function removeTriggers() {

  var triggers = ScriptApp.getScriptTriggers();
  
  for(var i=0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);
  }
  
  clearDatabase();

}

function storeKeys(key, secret, text, handle) {
  
  ScriptProperties.setProperty("TWITTER_CONSUMER_KEY",    key);
  ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", secret);
  
  ScriptProperties.setProperty("OUTOFOFFICE_TEXT", text);  
  ScriptProperties.setProperty("MAX_TWITTER_ID",   0);  
  ScriptProperties.setProperty("TWITTER_HANDLE",   handle);  

}

// Clean and Initialize the ScriptDB database

function clearDatabase() {
  
  var db = ScriptDb.getMyDb();
  while (true) {
    
    var result = db.query({}); 
    
    if (result.getSize() == 0) {
      break;
    }
    
    while (result.hasNext()) {
      db.remove(result.next());
    }
  }
}

// Setup triggers for the START and END dates

function initialize(start, end) {
  
  var startDate = new Date(start);
  var endDate   = new Date(end);
  
  removeTriggers();
      
  ScriptApp.newTrigger("autoReply")
           .timeBased()
           .at(startDate)
           .create();
  
  ScriptApp.newTrigger("removeTriggers")
           .timeBased()
           .at(endDate)
           .create();
   
} 

function autoReply() {
  
  clearDatabase();

  ScriptApp.newTrigger("outOfOffice")
           .timeBased()
           .everyMinutes(5)
           .create();

}

function oAuth() {

 var oauthConfig = UrlFetchApp.addOAuthService("twitter");
 oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
 oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
 oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authorize");
 oauthConfig.setConsumerKey(
                 ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
 oauthConfig.setConsumerSecret(
                 ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
 
}

// This function will poll twitter every 5 minutes for any @mentions

function outOfOffice() {

  oAuth();
  
  var twitter_handle = ScriptProperties.getProperty("TWITTER_HANDLE");
  
  var phrase = "to:" + twitter_handle;
  var search = "https://api.twitter.com/1.1/search/tweets.json?count=10" 
             + "&include_entities=false&result_type=recent&q="
             + encodeString(phrase) + "&since_id=" 
             + ScriptProperties.getProperty("MAX_TWITTER_ID");    

  var options =
  {
    "method": "get",
    "oAuthServiceName":"twitter",
    "oAuthUseToken":"always"
  };
  
  try {

    var result = UrlFetchApp.fetch(search, options);    

    if (result.getResponseCode() === 200) {
      
      var data = Utilities.jsonParse(result.getContentText());
      
      if (data) {
        
        var tweets = data.statuses;
        
        if (tweets.length) {
          
          var db    = ScriptDb.getMyDb();
          var reply = ScriptProperties.getProperty("OUTOFOFFICE_TEXT");
          
          for (var i=tweets.length-1; i>=0; i--) {
            
            var sender = tweets[i].user.screen_name; 
            var found = db.query({user: sender});
            
            if ( ! found.hasNext() ) {
              db.save({user:sender});
              sendTweet(sender, tweets[i].id_str, reply);
            }
          }
        }
      }
    }    
  } catch (e) {
    Logger.log(e.toString());
  }
}

// If an @mention is found, send an Out of Office tweet to that user.

function sendTweet(user, reply_id, tweet) {

  var options =
  {
    "method": "POST",
    "oAuthServiceName":"twitter",
    "oAuthUseToken":"always"    
  };
  
  var text   =  "@" + user + " " + tweet;
  text   =  encodeString(text.substr(0, 140));
  
  var status = "https://api.twitter.com/1.1/statuses/update.json"
             + "?status=" + text + "&in_reply_to_status_id=" + reply_id;
  
  try {
    var result = UrlFetchApp.fetch(status, options);
    ScriptProperties.setProperty("MAX_TWITTER_ID", reply_id);
  }  
  catch (e) {
    Logger.log(e.toString());
  }  
  
}

function doTwitter() {

  oAuth();
  
  var req = "https://api.twitter.com/1.1/application/rate_limit_status.json"; 
      
  var options =
  {
    "method": "get",
    "oAuthServiceName":"twitter",
    "oAuthUseToken":"always"
  };
  
  try {

    var result = UrlFetchApp.fetch(req, options);    
   
  } catch (e) {
    Logger.log(e.toString());
  }
}


function encodeString (q) {
   var str =  encodeURIComponent(q);
   str = str.replace(/!/g,'%21');
   str = str.replace(/\*/g,'%2A');
   str = str.replace(/\(/g,'%28');
   str = str.replace(/\)/g,'%29');
   str = str.replace(/'/g,'%27');
   return str;
}

&nbsp;