/*
org.manalith.ircbot.plugin.twitreader/TwitReaderRunner.java
ManalithBot - An open source IRC bot based on the PircBot Framework.
Copyright (C) 2011, 2012 Seong-ho, Cho <darkcircle.0426@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.manalith.ircbot.plugin.tweetreader;
import java.io.File;
import java.util.regex.Pattern;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.jsoup.Jsoup;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
public class TweetReader {
public static enum TwitterUrlType {
UserHome(
"http(s)?\\:\\/\\/twitter\\.com\\/(\\#\\!\\/)?([a-zA-Z0-9\\_]{1,15}(\\/)?){1}"), Tweet(
"http(s)?\\:\\/\\/twitter\\.com\\/(\\#\\!\\/)?[a-zA-Z0-9\\_]{1,15}\\/status\\/[0-9]+"), Photo(
"http(s)?\\:\\/\\/twitter\\.com\\/(\\#\\!\\/)?[a-zA-Z0-9\\_]{1,15}\\/status\\/[0-9]+/photo/[0-9]{1}(/|(/large))?");
Pattern pattern;
TwitterUrlType(String textPattern) {
pattern = Pattern.compile(textPattern);
}
}
private static final String TARGET_DATE_PATTERN = "yyyy년 MM월 dd일 E요일 HH:mm:ss";
private String consumerKey;
private String consumerSecret;
private String username;
private String password;
private PropertiesConfiguration config;
private WebDriver driver;
private JavascriptExecutor jse;
private Twitter tweet;
private RequestToken requestToken;
public TweetReader(String resourcePath, String consumerKey,
String consumerSecret) throws ConfigurationException {
try {
config = new PropertiesConfiguration(resourcePath
+ "keybox.property");
} catch (ConfigurationException e) {
config = new PropertiesConfiguration();
config.setFile(new File(resourcePath + "keybox.property"));
config.save();
}
setConsumerKey(consumerKey);
setConsumerSecret(consumerSecret);
}
public void setConsumerKey(String consumerKey) {
this.consumerKey = consumerKey;
}
public void setConsumerSecret(String consumerSecret) {
this.consumerSecret = consumerSecret;
}
public void setTwitterUsernameOrEmail(String username) {
this.username = username;
}
public void setTwitterPassword(String password) {
this.password = password;
}
private void setAcecssToken(String accessToken, String accessSecret) {
setAccessToken(new AccessToken(accessToken, accessSecret));
}
private void setAccessToken(AccessToken accessToken) {
tweet.setOAuthAccessToken(accessToken);
}
private enum UrlType {
TweetURL, UserURL, PhotoURL
}
private void initWebAutomateObject() {
driver = new HtmlUnitDriver();
((HtmlUnitDriver) driver).setJavascriptEnabled(true);
jse = (JavascriptExecutor) driver;
}
private void initTwitter4j() throws TwitterException {
ConfigurationBuilder builder = new ConfigurationBuilder();
Configuration config = builder.setDebugEnabled(false)
.setJSONStoreEnabled(true).setOAuthConsumerKey(consumerKey)
.setOAuthConsumerSecret(consumerSecret).build();
tweet = new TwitterFactory(config).getInstance();
requestToken = tweet.getOAuthRequestToken();
}
private String getTwitterAuthorizationPINPageSource() {
String url = requestToken.getAuthenticationURL();
driver.get(url);
jse.executeScript("document.getElementById('username_or_email').setAttribute('value','"
+ username + "')"); // Twitter ID
jse.executeScript("document.getElementById('password').setAttribute('value','"
+ password + "')"); // Twitter Password
jse.executeScript("document.getElementById('allow').click()");
driver.getPageSource();
return driver.getPageSource();
}
private String getTwitterAuthPINString() throws TwitterException {
return Jsoup.parse(getTwitterAuthorizationPINPageSource())
.getAllElements().select("div#oauth_pin>p>kbd>code").text();
}
private void authorizeTwitter() throws TwitterException,
ConfigurationException {
// init selenium web automation object
initWebAutomateObject();
// to success authorization for owners' twitter account
AccessToken accessToken = tweet.getOAuthAccessToken(requestToken,
getTwitterAuthPINString());
setAccessToken(accessToken);
tweet.verifyCredentials().getId(); // pass.
config.setProperty("com.twitter.accessKey", accessToken.getToken());
config.setProperty("com.twitter.accessSecret",
accessToken.getTokenSecret());
config.save();
}
private Status getStatus(String url, UrlType type) throws TwitterException {
Status stat = null;
String[] urlArray = url.split("\\/");
switch (type) {
case TweetURL:
case PhotoURL:
int statusIdIdx = 0;
for (; statusIdIdx < urlArray.length; statusIdIdx++)
if (urlArray[statusIdIdx++].equals("status"))
break;
long tweetId = NumberUtils.toLong(urlArray[statusIdIdx]);
stat = tweet.showStatus(tweetId);
if (stat == null)
return null;
break;
case UserURL:
String screenName = urlArray[urlArray.length - 1];
ResponseList<Status> resp = tweet.getUserTimeline(screenName);
if (resp.size() == 0)
return null;
stat = resp.get(0);
break;
}
return stat;
}
private String getText(String twitterurl, UrlType type) {
if (type == null)
return null;
// init twitter4j
try {
initTwitter4j();
} catch (TwitterException e) {
return e.getMessage();
}
if (StringUtils.isEmpty(config.getString("com.twitter.accessKey"))
|| StringUtils.isEmpty(config
.getString("com.twitter.accessSecret"))) {
try {
authorizeTwitter();
} catch (TwitterException e) {
return "[twitter4j.TwitterException] " + e.getMessage();
} catch (ConfigurationException e) {
return "[org.apache.common.configuration.ConfigutaionException] "
+ e.getMessage();
}
} else {
String accessToken = config.getString("com.twitter.accessKey");
String accessSecret = config.getString("com.twitter.accessSecret");
setAcecssToken(accessToken, accessSecret);
}
Status stat = null;
try {
stat = getStatus(twitterurl, type);
} catch (TwitterException e) {
return "[twitter4j.TwitterException] " + e.getMessage();
}
if (stat == null)
return null;
String author = stat.getUser().getName();
String createdAt = DateFormatUtils.format(stat.getCreatedAt(),
TARGET_DATE_PATTERN);
String message = stat.getText();
return String.format("작성자: %s, 작성일시: %s, 본문: %s", author, createdAt,
message);
}
private UrlType validateUrl(String url) {
if (StringUtils.isEmpty(url))
return null;
if (TwitterUrlType.Tweet.pattern.matcher(url).matches())
return UrlType.TweetURL;
if (TwitterUrlType.UserHome.pattern.matcher(url).matches())
return UrlType.UserURL;
if (TwitterUrlType.Photo.pattern.matcher(url).matches())
return UrlType.PhotoURL;
return null;
}
public String read(String[] strs) {
for (String str : strs) {
String result = getText(str, validateUrl(str));
if (result != null)
return result;
}
return null;
}
}