Javascript 更新ScriptProperty以避免检索重复的Twitter状态

Javascript 更新ScriptProperty以避免检索重复的Twitter状态,javascript,twitter,google-apps-script,Javascript,Twitter,Google Apps Script,我有兴趣写一个推特机器人来帮助当地滑雪胜地的一些朋友。我从Amit Agarwal那里找到了这本教程,它给了我足够的时间开始学习(自从我做了很多修改之后,我确实花了5分钟多的时间)。我在谷歌文档上托管脚本 首先我认为这是javascript(我的理解是google apps脚本使用javascript…),当我到目前为止遇到代码问题时,google搜索javascript之类的东西很有帮助,但是如果这不是javascript,请让我知道,这样我可以相应地更新标签 我以前没有使用javascrip

我有兴趣写一个推特机器人来帮助当地滑雪胜地的一些朋友。我从Amit Agarwal那里找到了这本教程,它给了我足够的时间开始学习(自从我做了很多修改之后,我确实花了5分钟多的时间)。我在谷歌文档上托管脚本

首先我认为这是javascript(我的理解是google apps脚本使用javascript…),当我到目前为止遇到代码问题时,google搜索javascript之类的东西很有帮助,但是如果这不是javascript,请让我知道,这样我可以相应地更新标签

我以前没有使用javascript的经验,所以我很高兴它能真正工作。但我想看看我做得对不对

start
函数启动触发器,每隔30分钟启动一次
fetchTweets()
函数。为了避免重复(我遇到的第一个错误)&可能被标记为垃圾邮件,我需要一种方法来确保我不会一次又一次地发布相同的tweet。在
start()
函数中,初始
since\u id
值被分配:

ScriptProperties.setProperty("SINCE_TWITTER_ID",        "404251049889759234");
fetchTweet()
函数中,我想我正在用以下语句更新此属性:

ScriptProperties.setProperty("SINCE_TWITTER_ID", lastID + '\n');
这是一个好方法吗?还是有更好/更可靠的方法?如果是这样,我如何确定它正在更新属性?(我可以检查日志文件,它似乎正在这样做,因此我可能只需要为记录器创建一个永久文本文件)

非常感谢您的帮助

/**     A  S I M P L E   T W I T T E R   B O T           **/
/**     =======================================          **/
/**     Written by Amit Agarwal @labnol on 03/08/2013    **/
/**     Modified by David Zemens @agnarchy on 11/21/2013 **/
/**     Tutorial link: http://www.labnol.org/?p=27902    **/
/**     Live demo at http://twitter.com/DearAssistant    **/
/**     Last updated on 09/07/2013 - Twitter API Fix     **/


function start() {

  Logger.log("start!" + '\n')

  // REPLACE THESE DUMMY VALUES
  // https://script.google.com/macros/d/18DGYaa-jbaAK9rEv0HZ2cMcWjFGgkvVcvr6TfksMNbbu2Brk3gZeZ46R/edit
  var TWITTER_CONSUMER_KEY     = "___REDACTED___";
  var TWITTER_CONSUMER_SECRET  = "___REDACTED___";
  var TWITTER_HANDLE           = "___REDACTED___";  
  var SEARCH_QUERY             = "___REDACTED___" + TWITTER_HANDLE;

  // Store variables
  ScriptProperties.setProperty("TWITTER_CONSUMER_KEY",    TWITTER_CONSUMER_KEY);
  ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", TWITTER_CONSUMER_SECRET);
  ScriptProperties.setProperty("TWITTER_HANDLE",          TWITTER_HANDLE);
  ScriptProperties.setProperty("SEARCH_QUERY",            SEARCH_QUERY);
  ScriptProperties.setProperty("SINCE_TWITTER_ID",        "404251049889759234");

  // Delete exiting triggers, if any
  var triggers = ScriptApp.getScriptTriggers();

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

  // Setup trigger to read Tweets every 2 hours

  ScriptApp.newTrigger("fetchTweets")
          .timeBased()
          .everyMinutes(30)
          //.everyHours(2)
          .create();

}

function oAuth() {
//Authentication
  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"));

}

function fetchTweets() {

  oAuth();
  // I put this line in to monitor whether the property is getting "stored" so as to avoid
  // reading in duplicate tweets.
  Logger.log("Getting tweets since " + ScriptProperties.getProperty("SINCE_TWITTER_ID"))

  var twitter_handle = ScriptProperties.getProperty("TWITTER_HANDLE");
  var search_query = ScriptProperties.getProperty("SEARCH_QUERY")
  Logger.log("searching tweets to " + search_query + '\n');


  // form the base URL
  // restrict to a certain radius ---:
  //var search = "https://api.twitter.com/1.1/search/tweets.json?count=5&geocode=42.827934,-83.564306,75mi&include_entities=false&result_type=recent&q="; 

  // unrestricted radius:
  var search = "https://api.twitter.com/1.1/search/tweets.json?count=5&include_entities=false&result_type=recent&q="; 

  search = search + encodeString(search_query) + "&since_id=" + ScriptProperties.getProperty("SINCE_TWITTER_ID");    

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

  try {

    var result = UrlFetchApp.fetch(search, options);    
    var lastID = ScriptProperties.getProperty("SINCE_TWITTER_ID"); 
    if (result.getResponseCode() === 200) {

      var data = Utilities.jsonParse(result.getContentText());

      if (data) {

        var tweets = data.statuses;
        //Logger.log(data.statuses); 
        for (var i=tweets.length-1; i>=0; i--) {
          // Make sure this is a NEW tweet

          if (tweets[i].id > ScriptProperties.getProperty("SINCE_TWITTER_ID")) {
            lastID = (tweets[i].id_str); 
            var answer = tweets[i].text.replace(new RegExp("\@" + twitter_handle, "ig"), "").replace(twitter_handle, "");

            // I find this TRY block may be necessary since a failure to send one of the tweets 
            // may abort the rest of the loop.
            try {

              Logger.log("found >> " + tweets[i].text)
              Logger.log("converted >> " + answer + '\n');

              sendTweet(tweets[i].user.screen_name, tweets[i].id_str, answer.substring(0,140));   

              // Update the script property to avoid duplicates.
              ScriptProperties.setProperty("SINCE_TWITTER_ID", lastID);

              Logger.log("sent to @" + tweets[i].user.screen_name + '\n'); 
            } catch (e) {

              Logger.log(e.toString() + '\n');

            }
           }
        }
      }
    }
  } catch (e) {
    Logger.log(e.toString() + '\n');
  }

    Logger.log("Last used tweet.id: " + lastID + + "\n")
}

function sendTweet(user, reply_id, tweet) {

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

  var status = "https://api.twitter.com/1.1/statuses/update.json";

  status = status + "?status=" + encodeString("RT @" + user + " " + tweet + " - Thanks\!");
  status = status + "&in_reply_to_status_id=" + reply_id;


  try {
    var result = UrlFetchApp.fetch(status, options);

    Logger.log("JSON result = " + result.getContentText() + '\n');    
  }  
  catch (e) {
    Logger.log(e.toString() + '\n');
  }


}

// Thank you +Martin Hawksey - you are awesome

function encodeString (q) {

  // Update: 09/06/2013

  // Google Apps Script is having issues storing oAuth tokens with the Twitter API 1.1 due to some encoding issues.
  // Henc this workaround to remove all the problematic characters from the status message.

  var str = q.replace(/\(/g,'{').replace(/\)/g,'}').replace(/\[/g,'{').replace(/\]/g,'}').replace(/\!/g, '|').replace(/\*/g, 'x').replace(/\'/g, '');
  return encodeURIComponent(str);

//   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;

}
/**A S I M P L E T W I T T R B O T**/
/**     =======================================          **/
/**Amit Agarwal@labnol于2013年8月3日撰写**/
/**由David Zemens@agnarchy于2013年11月21日修改**/
/**教程链接:http://www.labnol.org/?p=27902    **/
/**现场演示http://twitter.com/DearAssistant    **/
/**最后更新于2013年7月9日-Twitter API修复**/
函数start(){
Logger.log(“开始!”+“\n”)
//替换这些虚拟值
// https://script.google.com/macros/d/18DGYaa-jbaAK9rEv0HZ2cMcWjFGgkvVcvr6TfksMNbbu2Brk3gZeZ46R/edit
var TWITTER_CONSUMER_KEY=“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
var TWITTER_CONSUMER_SECRET=“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
var TWITTER\u HANDLE=“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu”;
var SEARCH\u QUERY=“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
//存储变量
setProperty(“TWITTER\u CONSUMER\u KEY”,TWITTER\u CONSUMER\u KEY);
setproperties(“TWITTER\u CONSUMER\u SECRET”,TWITTER\u CONSUMER\u SECRET);
setProperty(“TWITTER\u句柄”,TWITTER\u句柄);
setProperty(“搜索查询”,搜索查询);
setProperties(“自TWITTER_ID”,“404251049889759234”);
//删除退出触发器(如果有)
var triggers=ScriptApp.getScriptTriggers();
对于(var i=0;i=0;i--){
//确保这是一条新的推文
if(tweets[i].id>ScriptProperties.getProperty(“自TWITTER\u id”)){
lastID=(tweets[i].id_str);
var answer=tweets[i].text.replace(新的RegExp(“\@”+twitter\u句柄,“ig”),”).replace(twitter\u句柄“”);
//我发现这个TRY块可能是必要的,因为发送一条tweet失败
//可能会中止循环的其余部分。
试一试{
Logger.log(“找到>>”+推文[i].text)
Logger.log(“已转换>>”+answer+'\n');
sendTweet(tweets[i].user.screen_name,tweets[i].id_str,answer.substring(0140));
//更新脚本属性以避免重复。
ScriptProperties.setProperty