自分がふぁぼったツイートをRSSフィードにしたいと思って、JavaでふぁぼツイートをRSSフィードにするコードを書いてみた。

環境

  • Java 1.6
  • ROME 1.0 (rome-1.0.jar, jdom.jar)
  • Twitter4J 3.0.3 (twitter4j-core-3.0.3.jar)

サンプル ソースコード


import java.util.*;
import java.io.*;
 
import com.sun.syndication.feed.synd.*;
import com.sun.syndication.io.*;
 
import twitter4j.*;
import twitter4j.auth.*;
import twitter4j.conf.*;
 
public class TwitterFavoritesFeedMaker {
 
  public static void main(String[] args) throws Exception {
    
    // parameters
    String outputFilePath;
    if(args.length > 0){
      outputFilePath = args[0];
    }else{
      outputFilePath = System.getProperty("user.home") + "/twitter_favorites.xml";
    }
    
    String screenname = "<YOUR SCREENNAME>";
    String consumerKey = "<YOUR CONSUMER KEY>";
    String consumerSecret = "<YOUR CONSUMER SECRET>";
    String accessToken = "<YOUR ACCESS TOKEN>";
    String accessTokenSecret = "<YOUR ACCESS TOKEN SECRET>";
    
    TwitterFavoritesFeedMaker feedmaker = new TwitterFavoritesFeedMaker(screenname, consumerKey, consumerSecret, accessToken, accessTokenSecret);
    //Writer out = new OutputStreamWriter(System.out, "Shift_JIS");
    OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(outputFilePath), "UTF-8");
    feedmaker.output(out, "rss_2.0");
    out.close();
  }
  
  private final String screenname;
  private final String consumerKey;
  private final String consumerSecret;
  private final String accessToken;
  private final String accessTokenSecret;
  
  public TwitterFavoritesFeedMaker(String screenname, String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret){
    this.screenname = screenname;
    this.consumerKey = consumerKey;
    this.consumerSecret = consumerSecret;
    this.accessToken = accessToken;
    this.accessTokenSecret = accessTokenSecret;
  }
  
  private Twitter getTwitter(){
    ConfigurationBuilder cb = new ConfigurationBuilder();
    cb.setDebugEnabled(true)
      .setOAuthConsumerKey(consumerKey)
      .setOAuthConsumerSecret(consumerSecret)
      .setOAuthAccessToken(accessToken)
      .setOAuthAccessTokenSecret(accessTokenSecret);
    TwitterFactory factory = new TwitterFactory(cb.build());
    AccessToken token = new AccessToken(accessToken, accessTokenSecret);
    Twitter twitter = factory.getInstance(token);
    return twitter;
  }
  
  private void output(Writer out, String feedType) throws Exception {
    
    // APIからツイートを取得
    final int limitCallApi = 3;
    final int limitTweets = 200;
    ArrayList<MiniBlogEntry> tweets = getFavoriteTweets(limitCallApi, limitTweets);
    
    // ツイートを出力
    writeEntryFeed(tweets, out, feedType);
  }
  
  /**
   * ふぁぼツイートを取得する。
   * @param limitCallApi 最大APIコール回数
   * @param limitTweets 最大ツイート取得数(超えるけど)
   * @return
   * @throws Exception
   */
  private ArrayList<MiniBlogEntry> getFavoriteTweets(int limitCallApi, int limitTweets) throws Exception {
    
    ArrayList<MiniBlogEntry> tweets = new ArrayList<MiniBlogEntry>(); 
    Twitter twitter = getTwitter();
    Paging paging = new Paging(1, 200); // count=200
    
    // APIにてツイートを取得
    for(int j=0; j<limitCallApi; j++){
      ResponseList<Status> statusList = twitter.getFavorites(screenname, paging);
      if(statusList.size() == 0){
        break;
      }
      for(int i=0; i<statusList.size(); i++){
        Status s = statusList.get(i);
        if(!s.getUser().isProtected()){ // 鍵付きユーザのツイートは含めない
          MiniBlogEntry entry = new MiniBlogEntry();
          entry.id = s.getId();
          entry.posttime = s.getCreatedAt();
          entry.screenname = s.getUser().getScreenName();
          entry.body = s.getText();
          tweets.add(entry);
        }
      }
      long max_id = statusList.get(statusList.size() - 1).getId() - 1;
      paging.setMaxId(max_id);
      
      // APIを何回コールしたかのインジケーター。
      System.out.print("A");
      
      if(tweets.size() >= limitTweets){ // 指定数以上のツイートを取得していたら終了
        break;
      }
      
      // for sleep
      try{Thread.sleep(1000);}catch(Exception e){}
    }
    
    // APIを何回コールしたかのインジケーターを改行。
    System.out.println("");
    return tweets;
  }
  
  /**
   * フィードを生成する。
   * @param writer 出力先
   * @param feedType フィードのフォーマット。rss_2.0とか。
   * @throws Exception
   */
  public void writeEntryFeed(ArrayList<MiniBlogEntry> tweets, Writer writer, String feedType) throws Exception{
    
    // フィードを生成
    //String feedType = "rss_2.0";
    SyndFeed outfeed = new SyndFeedImpl();
    outfeed.setFeedType(feedType);
    outfeed.setTitle("Favorite Tweets by NI-Lab.");
    outfeed.setDescription("Favorite Tweets by NI-Lab. ");
    outfeed.setLink("http://www.nilab.info/");
    outfeed.setAuthor("NI-Lab.");
    outfeed.setLanguage("ja");
    outfeed.setEncoding("UTF-8");
    outfeed.setPublishedDate(new Date());
    
    ArrayList<SyndEntry> entries = new ArrayList<SyndEntry>();
    outfeed.setEntries(entries);

    // エントリを生成
    for(int j=0; j<tweets.size(); j++){
      MiniBlogEntry tweet = tweets.get(j);
      // エントリを生成
      SyndEntry entry = new SyndEntryImpl();
      entry.setAuthor("NI-Lab.");
      entry.setTitle(deleteMeta(tweet.screenname + ": " + tweet.body));
      entry.setPublishedDate(tweet.posttime);
      entry.setLink("https://twitter.com/" + tweet.screenname + "/status/" + tweet.id);
      // コンテンツを生成
      SyndContent content = new SyndContentImpl();
      content.setMode("escaped");
      content.setType("text/html");
      content.setValue(getDisplayableBody(tweet.screenname + ": " + tweet.body));
      // コンテンツをエントリに追加
      ArrayList<SyndContent> contents = new ArrayList<SyndContent>();
      contents.add(content);
      entry.setContents(contents);
      // エントリリストに追加
      entries.add(entry);
    }
    
    SyndFeedOutput output = new SyndFeedOutput();
    output.output(outfeed, writer);
  }
  
  /**
   * 文字列からメタ文字を削除します。
   * @exception NullPointerException
   */
  public static final String deleteMeta(String str) {
    if (str == null){
      throw new NullPointerException("deleteMeta");
    }
    if (str.equals("")){
      return str;
    }
    StringBuffer result = new StringBuffer(str.length());
    for (int i = 0; i < str.length(); i++) {
      char ch = str.charAt(i);
      if (!isMeta(ch)) {
        result.append(ch);
      }
    }
    return result.toString();
  }

  /**
   * メタ文字であれば true を返します。
   */
  public static final boolean isMeta(char ch) {
    // 0x00〜0x1f 制御文字
    // 0x20       空白
    // 0x21〜0x7e 図形文字
    // 0x7f     制御文字
    if (ch < 0x20 || ch == 0x7f){
      return true;
    }else{
      return false;
    }
  }
  
  public static String getDisplayableBody(String s){
    s = sanitize(s);
    s = s.replaceAll("\r\n", "\n");
    s = s.replaceAll("\n", "<br />");
    return s;
  }
  
  public static String sanitize(String s){
    if(s == null){
      return null;
    }
    return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("'", "&#39;").replace("\"", "&quot;");
  }
  
  public static class MiniBlogEntry {
    
    public long id; // ツイートの固有ID
    public Date posttime; // YYYY-MM-DD HH:MM:SS
    public String screenname; // ユーザー名
    public String body; // ツイートの中身
    
    public String toString(){
      StringBuffer sb = new StringBuffer();
      sb.append("MiniBlogEntry: ");
      sb.append("id=[");
      sb.append(id);
      sb.append("], ");
      sb.append("posttime=[");
      sb.append(posttime);
      sb.append("], ");
      sb.append("screenname=[");
      sb.append(screenname);
      sb.append("], ");
      sb.append("body=[");
      sb.append(body);
      sb.append("]");
      return sb.toString();
    }
  }
}

setPublishedDate でツイート日時を指定したのは失敗かも。本来ならふぁぼった日時を指定したいところ。見た感じ Twitter4J にふぁぼった日時を取得する機能は無さそう、そもそも Twitter API にも無さそう。。。

tags: java twiter twitter4j rome

Posted by NI-Lab. (@nilab)