/******************************************************************************
*
* Copyright 2014 Paphus Solutions Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.botlibre.sense.twitter;
import java.io.StringWriter;
import java.net.URL;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.botlibre.Bot;
import org.botlibre.BotException;
import org.botlibre.api.knowledge.Network;
import org.botlibre.api.knowledge.Relationship;
import org.botlibre.api.knowledge.Vertex;
import org.botlibre.knowledge.Primitive;
import org.botlibre.self.SelfCompiler;
import org.botlibre.sense.BasicSense;
import org.botlibre.sense.http.Http;
import org.botlibre.thought.language.Language;
import org.botlibre.thought.language.Language.LanguageState;
import org.botlibre.util.TextStream;
import org.botlibre.util.Utils;
import twitter4j.Paging;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.StatusUpdate;
import twitter4j.Trends;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.api.SearchResource;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import twitter4j.conf.ConfigurationBuilder;
/**
* Enables receiving a sending messages through Twitter.
*/
public class Twitter extends BasicSense {
public static int TREND_CHECK = 1000 * 60 * 60 * 1; // 1 hour.
public static int MAX_LOOKUP = 100;
public static String oauthKey = "key";
public static String oauthSecret = "secret";
protected String userName = "";
protected String token = "";
protected String tokenSecret = "";
protected boolean initProperties;
protected boolean autoFollow = false;
protected boolean autoFollowFriendsFriends = false;
protected boolean autoFollowFriendsFollowers = false;
protected boolean followMessages = false;
protected String welcomeMessage = "";
protected int maxFriends = 100;
protected int maxFriendsPerCycle = 5;
protected int maxWelcomesPerCycle = 20;
protected int maxPage = 5;
protected int maxStatus = 20;
protected int maxFeed = 20;
protected int maxSearch = 20;
protected int maxErrors = 5;
protected int errors;
protected boolean processStatus = false;
protected boolean listenStatus = false;
protected boolean tweetChats = true;
protected boolean replyToMentions = true;
protected boolean replyToMessages = true;
protected boolean autoTweet = false;
protected boolean learn = false;
protected boolean learnFromSelf = false;
protected int autoTweetHours = 24;
protected List<String> retweet = new ArrayList<String>();
protected List<String> tweetRSS = new ArrayList<String>();
protected List<String> rssKeywords = new ArrayList<String>();
protected List<String> tweetSearch = new ArrayList<String>();
protected List<String> statusKeywords = new ArrayList<String>();
protected List<String> autoFollowKeywords = new ArrayList<String>();
protected List<String> autoFollowSearch = new ArrayList<String>();
protected boolean checkTrends = false;
protected long lastTrendsCheck;
protected Set<Long> processedTweets = new HashSet<Long>();
protected int tweets;
protected int tweetsProcessed;
protected int retweets;
protected twitter4j.Twitter connection;
public Twitter(boolean enabled) {
this.isEnabled = enabled;
this.languageState = LanguageState.Discussion;
}
public Twitter() {
this(false);
}
public boolean getListenStatus() {
initProperties();
return listenStatus;
}
public void setListenStatus(boolean listenStatus) {
initProperties();
this.listenStatus = listenStatus;
}
public int getTweets() {
return tweets;
}
public void setTweets(int tweets) {
this.tweets = tweets;
}
public int getTweetsProcessed() {
return tweetsProcessed;
}
public void setTweetsProcessed(int tweetsProcessed) {
this.tweetsProcessed = tweetsProcessed;
}
public int getRetweets() {
return retweets;
}
public void setRetweets(int retweets) {
this.retweets = retweets;
}
public String getWelcomeMessage() {
initProperties();
return welcomeMessage;
}
public void setWelcomeMessage(String welcomeMessage) {
initProperties();
this.welcomeMessage = welcomeMessage;
}
public List<String> getRssKeywords() {
initProperties();
return rssKeywords;
}
public void setRssKeywords(List<String> rssKeywords) {
initProperties();
this.rssKeywords = rssKeywords;
}
public int getMaxSearch() {
initProperties();
return maxSearch;
}
public void setMaxSearch(int maxSearch) {
initProperties();
this.maxSearch = maxSearch;
}
public List<String> getAutoFollowSearch() {
initProperties();
return autoFollowSearch;
}
public void setAutoFollowSearch(List<String> autoFollowSearch) {
initProperties();
this.autoFollowSearch = autoFollowSearch;
}
public boolean getAutoFollowFriendsFriends() {
initProperties();
return autoFollowFriendsFriends;
}
public void setAutoFollowFriendsFriends(boolean autoFollowFriendsFriends) {
initProperties();
this.autoFollowFriendsFriends = autoFollowFriendsFriends;
}
public boolean getAutoFollowFriendsFollowers() {
initProperties();
return autoFollowFriendsFollowers;
}
public void setAutoFollowFriendsFollowers(boolean autoFollowFriendsFollowers) {
initProperties();
this.autoFollowFriendsFollowers = autoFollowFriendsFollowers;
}
public int getMaxFeed() {
initProperties();
return maxFeed;
}
public void setMaxFeed(int maxFeed) {
initProperties();
this.maxFeed = maxFeed;
}
public boolean getAutoTweet() {
initProperties();
return autoTweet;
}
public void setAutoTweet(boolean autoTweet) {
initProperties();
this.autoTweet = autoTweet;
}
public int getAutoTweetHours() {
initProperties();
return autoTweetHours;
}
public void setAutoTweetHours(int autoTweetHours) {
initProperties();
this.autoTweetHours = autoTweetHours;
}
public List<Vertex> getAutoTweets(Network network) {
return network.createVertex(getPrimitive()).orderedRelations(Primitive.AUTOTWEETS);
}
public List<String> getStatusKeywords() {
initProperties();
return statusKeywords;
}
public void setStatusKeywords(List<String> statusKeywords) {
initProperties();
this.statusKeywords = statusKeywords;
}
public List<String> getAutoFollowKeywords() {
initProperties();
return autoFollowKeywords;
}
public void setAutoFollowKeywords(List<String> autoFollowKeywords) {
initProperties();
this.autoFollowKeywords = autoFollowKeywords;
}
/**
* Authorise a new account to be accessible by Bot.
* Return the request token that contains the URL that the user must use to authorise twitter.
*/
public RequestToken authorizeAccount() throws TwitterException {
twitter4j.Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(getOauthKey(), getOauthSecret());
RequestToken requestToken = twitter.getOAuthRequestToken();
setConnection(twitter);
return requestToken;
}
/**
* Authorise a new account to be accessible by Bot.
*/
public void authorizeComplete() throws TwitterException {
AccessToken token = getConnection().getOAuthAccessToken();
setToken(token.getToken());
setTokenSecret(token.getTokenSecret());
}
/**
* Authorise a new account to be accessible by Bot.
*/
public void authorizeComplete(String pin) throws TwitterException {
AccessToken token = getConnection().getOAuthAccessToken(pin);
setToken(token.getToken());
setTokenSecret(token.getTokenSecret());
}
/**
* Start sensing.
*/
@Override
public void awake() {
String user = this.bot.memory().getProperty("Twitter.user");
if (user != null) {
this.userName = user;
}
String token = this.bot.memory().getProperty("Twitter.token");
if (token != null) {
this.token = token;
}
String secret = this.bot.memory().getProperty("Twitter.secret");
if (secret != null) {
String data = secret;
// Check if encrypted from && prefix.
if (data.startsWith("&&")) {
try {
this.tokenSecret = Utils.decrypt(Utils.KEY, data.substring(2, data.length()));
} catch (Exception exception) {
this.tokenSecret = data;
}
} else {
this.tokenSecret = data;
}
setIsEnabled(true);
}
String property = this.bot.memory().getProperty("Twitter.tweetChats");
if (property != null) {
this.tweetChats = Boolean.valueOf(property);
}
}
/**
* Migrate to new properties system.
*/
public void migrateProperties() {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex user = twitter.getRelationship(Primitive.USER);
if (user != null) {
this.userName = (String)user.getData();
}
Vertex token = twitter.getRelationship(Primitive.TOKEN);
if (token != null) {
this.token = (String)token.getData();
}
Vertex secret = twitter.getRelationship(Primitive.SECRET);
if (secret != null) {
String data = (String)secret.getData();
// Check if encrypted from && prefix.
if (data.startsWith("&&")) {
try {
this.tokenSecret = Utils.decrypt(Utils.KEY, data.substring(2, data.length()));
} catch (Exception exception) {
this.tokenSecret = data;
}
} else {
this.tokenSecret = data;
}
setIsEnabled(true);
}
Vertex property = twitter.getRelationship(Primitive.TWEETCHATS);
if (property != null) {
this.tweetChats = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.WELCOME);
if (property != null) {
this.welcomeMessage = (String)property.getData();
}
property = twitter.getRelationship(Primitive.AUTOFOLLOW);
if (property != null) {
this.autoFollow = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.AUTOFOLLOWFRIENDSFRIENDS);
if (property != null) {
this.autoFollowFriendsFriends = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.AUTOFOLLOWFRIENDSFOLLOWERS);
if (property != null) {
this.autoFollowFriendsFollowers = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.FOLLOWMESSAGES);
if (property != null) {
this.followMessages = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.MAXFRIENDS);
if (property != null) {
this.maxFriends = ((Number)property.getData()).intValue();
}
property = twitter.getRelationship(Primitive.MAXSTATUSCHECKS);
if (property != null) {
this.maxStatus = ((Number)property.getData()).intValue();
}
property = twitter.getRelationship(Primitive.PROCESSSTATUS);
if (property != null) {
this.processStatus = (Boolean)property.getData();
}
this.statusKeywords = new ArrayList<String>();
List<Relationship> keywords = twitter.orderedRelationships(Primitive.STATUSKEYWORDS);
if (keywords != null) {
for (Relationship relationship : keywords) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.statusKeywords.add(text);
}
}
}
this.retweet = new ArrayList<String>();
keywords = twitter.orderedRelationships(Primitive.RETWEET);
if (keywords != null) {
for (Relationship relationship : keywords) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.retweet.add(text);
}
}
}
this.autoFollowKeywords = new ArrayList<String>();
List<Relationship> search = twitter.orderedRelationships(Primitive.AUTOFOLLOWKEYWORDS);
if (search != null) {
for (Relationship relationship : search) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.autoFollowKeywords.add(text);
}
}
}
this.autoFollowSearch = new ArrayList<String>();
search = twitter.orderedRelationships(Primitive.AUTOFOLLOWSEARCH);
if (search != null) {
for (Relationship relationship : search) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.autoFollowSearch.add(text);
}
}
}
this.tweetSearch = new ArrayList<String>();
search = twitter.orderedRelationships(Primitive.TWEETSEARCH);
if (search != null) {
for (Relationship relationship : search) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.tweetSearch.add(text);
}
}
}
this.tweetRSS = new ArrayList<String>();
List<Relationship> rss = twitter.orderedRelationships(Primitive.TWEETRSS);
if (rss != null) {
for (Relationship relationship : rss) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.tweetRSS.add(text);
}
}
}
this.rssKeywords = new ArrayList<String>();
keywords = twitter.orderedRelationships(Primitive.RSSKEYWORDS);
if (keywords != null) {
for (Relationship relationship : keywords) {
String text = ((String)relationship.getTarget().getData()).trim();
this.rssKeywords.add(text);
}
}
property = twitter.getRelationship(Primitive.REPLYTOMENTIONS);
if (property != null) {
this.replyToMentions = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.REPLYTOMESSAGES);
if (property != null) {
this.replyToMessages = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.AUTOTWEET);
if (property != null) {
this.autoTweet = (Boolean)property.getData();
}
property = twitter.getRelationship(Primitive.AUTOTWEETHOURS);
if (property != null) {
this.autoTweetHours = ((Number)property.getData()).intValue();
}
// Remove old properties.
twitter.internalRemoveRelationships(Primitive.USER);
twitter.internalRemoveRelationships(Primitive.TOKEN);
twitter.internalRemoveRelationships(Primitive.SECRET);
twitter.internalRemoveRelationships(Primitive.TWEETCHATS);
twitter.internalRemoveRelationships(Primitive.WELCOME);
twitter.internalRemoveRelationships(Primitive.AUTOFOLLOW);
twitter.internalRemoveRelationships(Primitive.AUTOFOLLOWFRIENDSFOLLOWERS);
twitter.internalRemoveRelationships(Primitive.FOLLOWMESSAGES);
twitter.internalRemoveRelationships(Primitive.MAXFRIENDS);
twitter.internalRemoveRelationships(Primitive.MAXSTATUSCHECKS);
twitter.internalRemoveRelationships(Primitive.PROCESSSTATUS);
twitter.internalRemoveRelationships(Primitive.REPLYTOMENTIONS);
twitter.internalRemoveRelationships(Primitive.REPLYTOMESSAGES);
twitter.internalRemoveRelationships(Primitive.AUTOTWEET);
twitter.internalRemoveRelationships(Primitive.AUTOTWEETHOURS);
memory.save();
saveProperties(null);
}
/**
* Load settings.
*/
public void initProperties() {
if (this.initProperties) {
return;
}
synchronized (this) {
if (this.initProperties) {
return;
}
getBot().memory().loadProperties("Twitter");
String property = this.bot.memory().getProperty("Twitter.welcomeMessage");
if (property != null) {
this.welcomeMessage = property;
}
property = this.bot.memory().getProperty("Twitter.autoFollow");
if (property != null) {
this.autoFollow = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.autoFollowFriendsFriends");
if (property != null) {
this.autoFollowFriendsFriends = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.autoFollowFriendsFollowers");
if (property != null) {
this.autoFollowFriendsFollowers = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.followMessages");
if (property != null) {
this.followMessages = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.maxFriends");
if (property != null) {
this.maxFriends = Integer.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.maxStatus");
if (property != null) {
this.maxStatus = Integer.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.maxSearch");
if (property != null) {
this.maxSearch = Integer.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.processStatus");
if (property != null) {
this.processStatus = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.listenStatus");
if (property != null) {
this.listenStatus = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.learn");
if (property != null) {
this.learn = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.learnFromSelf");
if (property != null) {
this.learnFromSelf = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.replyToMentions");
if (property != null) {
this.replyToMentions = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.replyToMessages");
if (property != null) {
this.replyToMessages = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.autoTweet");
if (property != null) {
this.autoTweet = Boolean.valueOf(property);
}
property = this.bot.memory().getProperty("Twitter.autoTweetHours");
if (property != null) {
this.autoTweetHours = Integer.valueOf(property);
}
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
this.statusKeywords = new ArrayList<String>();
List<Relationship> keywords = twitter.orderedRelationships(Primitive.STATUSKEYWORDS);
if (keywords != null) {
for (Relationship relationship : keywords) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.statusKeywords.add(text);
}
}
}
this.retweet = new ArrayList<String>();
keywords = twitter.orderedRelationships(Primitive.RETWEET);
if (keywords != null) {
for (Relationship relationship : keywords) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.retweet.add(text);
}
}
}
this.autoFollowKeywords = new ArrayList<String>();
List<Relationship> search = twitter.orderedRelationships(Primitive.AUTOFOLLOWKEYWORDS);
if (search != null) {
for (Relationship relationship : search) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.autoFollowKeywords.add(text);
}
}
}
this.autoFollowSearch = new ArrayList<String>();
search = twitter.orderedRelationships(Primitive.AUTOFOLLOWSEARCH);
if (search != null) {
for (Relationship relationship : search) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.autoFollowSearch.add(text);
}
}
}
this.tweetSearch = new ArrayList<String>();
search = twitter.orderedRelationships(Primitive.TWEETSEARCH);
if (search != null) {
for (Relationship relationship : search) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.tweetSearch.add(text);
}
}
}
this.tweetRSS = new ArrayList<String>();
List<Relationship> rss = twitter.orderedRelationships(Primitive.TWEETRSS);
if (rss != null) {
for (Relationship relationship : rss) {
String text = ((String)relationship.getTarget().getData()).trim();
if (!text.isEmpty()) {
this.tweetRSS.add(text);
}
}
}
this.rssKeywords = new ArrayList<String>();
keywords = twitter.orderedRelationships(Primitive.RSSKEYWORDS);
if (keywords != null) {
for (Relationship relationship : keywords) {
String text = ((String)relationship.getTarget().getData()).trim();
this.rssKeywords.add(text);
}
}
this.initProperties = true;
}
}
public void saveProperties(List<String> autoTweets) {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
twitter.unpinChildren();
memory.saveProperty("Twitter.user", this.userName, true);
memory.saveProperty("Twitter.token", this.token, true);
memory.saveProperty("Twitter.secret", "&&" + Utils.encrypt(Utils.KEY, this.tokenSecret), true);
memory.saveProperty("Twitter.tweetChats", String.valueOf(this.tweetChats), true);
memory.saveProperty("Twitter.welcomeMessage", this.welcomeMessage, false);
memory.saveProperty("Twitter.autoFollow", String.valueOf(this.autoFollow), false);
memory.saveProperty("Twitter.autoFollowFriendsFriends", String.valueOf(this.autoFollowFriendsFriends), false);
memory.saveProperty("Twitter.autoFollowFriendsFollowers", String.valueOf(this.autoFollowFriendsFollowers), false);
memory.saveProperty("Twitter.followMessages", String.valueOf(this.followMessages), false);
memory.saveProperty("Twitter.maxFriends", String.valueOf(this.maxFriends), false);
memory.saveProperty("Twitter.maxStatus", String.valueOf(this.maxStatus), false);
memory.saveProperty("Twitter.maxSearch", String.valueOf(this.maxSearch), false);
memory.saveProperty("Twitter.processStatus", String.valueOf(this.processStatus), false);
memory.saveProperty("Twitter.listenStatus", String.valueOf(this.listenStatus), false);
memory.saveProperty("Twitter.learn", String.valueOf(this.learn), false);
memory.saveProperty("Twitter.learnFromSelf", String.valueOf(this.learnFromSelf), false);
memory.saveProperty("Twitter.replyToMentions", String.valueOf(this.replyToMentions), false);
memory.saveProperty("Twitter.replyToMessages", String.valueOf(this.replyToMessages), false);
memory.saveProperty("Twitter.autoTweet", String.valueOf(this.autoTweet), false);
memory.saveProperty("Twitter.autoTweetHours", String.valueOf(this.autoTweetHours), false);
twitter.internalRemoveRelationships(Primitive.STATUSKEYWORDS);
for (String text : this.statusKeywords) {
Vertex keywords = memory.createVertex(text);
twitter.addRelationship(Primitive.STATUSKEYWORDS, keywords);
}
twitter.internalRemoveRelationships(Primitive.RETWEET);
for (String text : this.retweet) {
Vertex keywords = memory.createVertex(text);
twitter.addRelationship(Primitive.RETWEET, keywords);
}
twitter.internalRemoveRelationships(Primitive.AUTOFOLLOWKEYWORDS);
for (String text : this.autoFollowKeywords) {
Vertex search = memory.createVertex(text);
twitter.addRelationship(Primitive.AUTOFOLLOWKEYWORDS, search);
}
twitter.internalRemoveRelationships(Primitive.AUTOFOLLOWSEARCH);
for (String text : this.autoFollowSearch) {
Vertex search = memory.createVertex(text);
twitter.addRelationship(Primitive.AUTOFOLLOWSEARCH, search);
}
twitter.internalRemoveRelationships(Primitive.TWEETSEARCH);
for (String text : this.tweetSearch) {
Vertex search = memory.createVertex(text);
twitter.addRelationship(Primitive.TWEETSEARCH, search);
}
twitter.internalRemoveRelationships(Primitive.TWEETRSS);
for (String text : this.tweetRSS) {
Vertex rss = memory.createVertex(text);
twitter.addRelationship(Primitive.TWEETRSS, rss);
}
twitter.internalRemoveRelationships(Primitive.RSSKEYWORDS);
for (String text : this.rssKeywords) {
Vertex keywords = memory.createVertex(text);
twitter.addRelationship(Primitive.RSSKEYWORDS, keywords);
}
if (autoTweets != null) {
Collection<Relationship> old = twitter.getRelationships(Primitive.AUTOTWEETS);
if (old != null) {
for (Relationship tweet : old) {
if (tweet.getTarget().instanceOf(Primitive.FORMULA)) {
SelfCompiler.getCompiler().unpin(tweet.getTarget());
}
}
}
twitter.internalRemoveRelationships(Primitive.AUTOTWEETS);
for (String text : autoTweets) {
Vertex tweet = memory.createSentence(text);
if (tweet.instanceOf(Primitive.FORMULA)) {
SelfCompiler.getCompiler().pin(tweet);
}
tweet.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
twitter.addRelationship(Primitive.AUTOTWEETS, tweet);
}
}
twitter.pinChildren();
memory.save();
}
public void connect() throws TwitterException {
initProperties();
ConfigurationBuilder config = new ConfigurationBuilder();
config.setOAuthConsumerKey(getOauthKey());
config.setOAuthConsumerSecret(getOauthSecret());
config.setOAuthAccessToken(getToken());
config.setOAuthAccessTokenSecret(getTokenSecret());
twitter4j.Twitter twitter = new TwitterFactory(config.build()).getInstance();
User user = twitter.verifyCredentials();
if (!this.userName.equals(user.getScreenName())) {
this.userName = user.getScreenName();
saveProperties(null);
}
//AccessToken accessToken = new AccessToken(getToken(), getTokenSecret());
//twitter4j.Twitter twitter = new TwitterFactory().getInstance(accessToken);
//twitter4j.Twitter twitter = new TwitterFactory().getInstance(getOauthKey(), getOauthSecret(), accessToken);
//twitter4j.Twitter twitter = new TwitterFactory().getInstance(getUsername(), getPassword());
setConnection(twitter);
}
/**
* Check profile for messages.
*/
public void checkProfile() {
log("Checking profile.", Level.INFO);
this.processedTweets = new HashSet<Long>();
try {
if (getConnection() == null) {
connect();
}
if (this.checkTrends) {
checkTrends();
}
checkFollowers();
checkStatus();
checkMentions();
checkSearch();
checkRSS();
checkAutoTweet();
} catch (Exception exception) {
log(exception);
}
log("Done checking profile.", Level.INFO);
}
/**
* Add the follower.
*/
public void addFriend(String friend) {
try {
getConnection().createFriendship(friend);
} catch (TwitterException exception) {
log(exception);
}
}
/**
* Add the follower.
*/
public void removeFriend(String friend) {
try {
getConnection().destroyFriendship(friend);
} catch (TwitterException exception) {
log(exception);
}
}
/**
* Check status.
*/
public void checkStatus() {
if (!getProcessStatus()) {
return;
}
log("Checking status", Level.FINE);
try {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTTIMELINE);
long last = 0;
if (vertex != null) {
last = ((Number)vertex.getData()).longValue();
}
long max = 0;
ResponseList<Status> timeline = null;
boolean more = true;
int page = 1;
int count = 0;
this.errors = 0;
while (more && (count <= this.maxStatus) && page <= this.maxPage) {
if (last == 0) {
timeline = getConnection().getHomeTimeline();
more = false;
} else {
Paging paging = new Paging(page, last);
timeline = getConnection().getHomeTimeline(paging);
if ((timeline == null) || (timeline.size() < 20)) {
more = false;
}
page++;
}
if ((timeline == null) || timeline.isEmpty()) {
break;
}
log("Processing status", Level.INFO, timeline.size());
for (int index = timeline.size() - 1; index >= 0; index--) {
if (count >= this.maxStatus) {
break;
}
if (this.errors > this.maxErrors) {
break;
}
Status status = timeline.get(index);
String name = status.getUser().getScreenName();
if (!name.equals(this.userName)) {
long statusTime = status.getCreatedAt().getTime();
long statusId = status.getId();
if (statusId > max) {
max = statusId;
}
if ((System.currentTimeMillis() - statusTime) > DAY) {
log("Day old status", Level.INFO, statusId, statusTime);
more = false;
continue;
}
if (statusId > last) {
if (Utils.checkProfanity(status.getText())) {
continue;
}
boolean match = false;
List<String> statusWords = new TextStream(status.getText().toLowerCase()).allWords();
if (getListenStatus()) {
this.languageState = LanguageState.Listening;
match = true;
} else {
for (String text : getStatusKeywords()) {
List<String> keywords = new TextStream(text.toLowerCase()).allWords();
if (!keywords.isEmpty() && statusWords.containsAll(keywords)) {
match = true;
break;
}
}
}
if (getLearn()) {
learnTweet(status, true, true, memory);
}
if (match) {
count++;
input(status);
Utils.sleep(500);
} else {
log("Skipping status, missing keywords", Level.FINE, status.getText());
if (!status.isRetweet() && !status.getUser().isProtected() && !status.isRetweetedByMe()) {
boolean retweeted = false;
// Check retweet.
for (String keywords : getRetweet()) {
List<String> keyWords = new TextStream(keywords.toLowerCase()).allWords();
if (!keyWords.isEmpty()) {
if (statusWords.containsAll(keyWords)) {
retweeted = true;
count++;
retweet(status);
Utils.sleep(500);
break;
}
}
}
if (!retweeted) {
log("Skipping rewteet, missing keywords", Level.FINE, status.getText());
}
} else if (!getRetweet().isEmpty()) {
if (status.isRetweet()) {
log("Skipping rewteet", Level.FINE, status.getText());
} else if (status.getUser().isProtected()) {
log("Skipping protected user", Level.FINE, status.getText());
} else if (status.isRetweetedByMe()) {
log("Skipping already retweeted", Level.FINE, status.getText());
}
}
}
} else {
log("Old status", Level.INFO, statusId, statusTime);
}
}
}
}
if (max != 0) {
twitter.setRelationship(Primitive.LASTTIMELINE, memory.createVertex(max));
memory.save();
}
} catch (Exception exception) {
log(exception);
}
// Wait for language processing.
int count = 0;
while (count < 60 && !getBot().memory().getActiveMemory().isEmpty()) {
Utils.sleep(1000);
}
}
/**
* Learn responses from the tweet search.
*/
public void learnSearch(String tweetSearch, int maxSearch, boolean processTweets, boolean processReplies) {
log("Learning from tweet search", Level.INFO, tweetSearch);
try {
Network memory = getBot().memory().newMemory();
int count = 0;
this.errors = 0;
Set<Long> processed = new HashSet<Long>();
Query query = new Query(tweetSearch);
query.count(100);
SearchResource search = getConnection().search();
QueryResult result = search.search(query);
List<Status> tweets = result.getTweets();
if (tweets != null) {
log("Processing search results", Level.INFO, tweets.size(), tweetSearch);
for (Status tweet : tweets) {
if (count > maxSearch) {
log("Max search results processed", Level.INFO, maxSearch);
break;
}
if (!processed.contains(tweet.getId())) {
log("Processing search result", Level.INFO, tweet.getUser().getScreenName(), tweetSearch, tweet.getText());
processed.add(tweet.getId());
learnTweet(tweet, processTweets, processReplies, memory);
count++;
}
}
memory.save();
}
// Search only returns 7 days, search for users as well.
TextStream stream = new TextStream(tweetSearch);
while (!stream.atEnd()) {
stream.skipToAll("from:", true);
if (stream.atEnd()) {
break;
}
String user = stream.nextWord();
String arg[] = new String[1];
arg[0] = user;
ResponseList<User> users = getConnection().lookupUsers(arg);
if (!users.isEmpty()) {
long id = users.get(0).getId();
boolean more = true;
int page = 1;
while (more) {
Paging pageing = new Paging(page);
ResponseList<Status> timeline = getConnection().getUserTimeline(id, pageing);
if ((timeline == null) || (timeline.size() < 20)) {
more = false;
}
page++;
if ((timeline == null) || timeline.isEmpty()) {
more = false;
break;
}
log("Processing user timeline", Level.INFO, user, timeline.size());
for (int index = timeline.size() - 1; index >= 0; index--) {
if (count >= maxSearch) {
more = false;
break;
}
Status tweet = timeline.get(index);
if (!processed.contains(tweet.getId())) {
log("Processing user timeline result", Level.INFO, tweet.getUser().getScreenName(), tweet.getText());
processed.add(tweet.getId());
learnTweet(tweet, processTweets, processReplies, memory);
count++;
}
}
memory.save();
}
if (count >= maxSearch) {
log("Max search results processed", Level.INFO, maxSearch);
break;
}
}
}
} catch (Exception exception) {
log(exception);
}
}
/**
* Learn from the profiles posts.
*/
public void checkLearning() {
if (!getLearnFromSelf()) {
return;
}
log("Checking learning", Level.FINE);
try {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTLEARN);
long last = 0;
if (vertex != null) {
last = ((Number)vertex.getData()).longValue();
}
long max = 0;
ResponseList<Status> timeline = getConnection().getUserTimeline();
if ((timeline == null) || timeline.isEmpty()) {
return;
}
log("Processing status", Level.INFO, timeline.size());
for (int index = timeline.size() - 1; index >= 0; index--) {
Status tweet = timeline.get(index);
long statusTime = tweet.getCreatedAt().getTime();
long statusId = tweet.getId();
if (statusId > max) {
max = statusId;
}
if ((System.currentTimeMillis() - statusTime) > DAY) {
log("Day old status", Level.INFO, statusId, statusTime);
continue;
}
if (statusId > last) {
learnTweet(tweet, true, true, memory);
} else {
log("Old status", Level.INFO, statusId, statusTime);
}
}
if (max != 0) {
twitter.setRelationship(Primitive.LASTTIMELINE, memory.createVertex(max));
memory.save();
}
} catch (Exception exception) {
log(exception);
}
}
public void learnTweet(Status tweet, boolean processTweets, boolean processReplies, Network memory) throws Exception {
String text = tweet.getText();
// Exclude retweets
if (tweet.isRetweet()) {
log("Tweet is retweet", Level.FINER, tweet.getText());
return;
}
if (Utils.checkProfanity(text)) {
log("Ignoring profanity", Level.INFO, text);
return;
}
// Exclude protected
if (tweet.getUser().isProtected() && !tweet.getUser().getScreenName().equals(getUserName())) {
log("Tweet is protected", Level.FINER, tweet.getText());
return;
}
log("Learning status", Level.INFO, text);
// Exclude replies/mentions
if (tweet.getText().indexOf('@') != -1) {
log("Tweet is reply", Level.FINER, tweet.getText());
if (!processReplies) {
return;
}
long id = tweet.getInReplyToStatusId();
if (id > 0) {
try {
Status reply = getConnection().showStatus(id);
String replyText = reply.getText();
if (replyText != null && !replyText.isEmpty()) {
// Filter out @users
for (String word : new TextStream(text).allWords()) {
if (word.startsWith("@")) {
text = text.replace(word, "");
}
}
for (String word : new TextStream(replyText).allWords()) {
if (word.startsWith("@")) {
replyText = replyText.replace(word, "");
}
}
Vertex question = memory.createSentence(replyText.trim());
Vertex sentence = memory.createSentence(text.trim());
Language.addResponse(question, sentence, memory);
}
} catch (Exception ignore) {
log(ignore.toString(), Level.WARNING);
}
}
return;
}
if (!processTweets) {
return;
}
Vertex sentence = memory.createSentence(text);
String keywords = "";
for (String word : new TextStream(text).allWords()) {
if (word.startsWith("#")) {
keywords = keywords + " " + word + " " + word.substring(1, word.length());
}
}
Language.addResponse(sentence, sentence, null, keywords, null, memory);
}
/**
* Check messages to this user.
*/
public void checkMentions() {
if (!getReplyToMentions()) {
return;
}
try {
log("Checking mentions", Level.FINE);
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTMENTION);
long last = 0;
if (vertex != null) {
last = ((Number)vertex.getData()).longValue();
}
long max = 0;
ResponseList<Status> mentions = null;
boolean more = true;
int page = 1;
while (more) {
if (last == 0) {
mentions = getConnection().getMentionsTimeline();
more = false;
} else {
Paging paging = new Paging(page, last);
mentions = getConnection().getMentionsTimeline(paging);
if ((mentions == null) || (mentions.size() < 20)) {
more = false;
}
page++;
}
if ((mentions == null) || mentions.isEmpty()) {
break;
}
log("Processing mentions", Level.FINE, mentions.size());
for (int index = mentions.size() - 1; index >= 0; index--) {
Status tweet = mentions.get(index);
long statusTime = tweet.getCreatedAt().getTime();
long statusId = tweet.getId();
if (statusId > max) {
max = statusId;
}
if ((System.currentTimeMillis() - statusTime) > DAY) {
log("Day old mention", Level.INFO, statusId, statusTime);
more = false;
continue;
}
// Exclude self
if (tweet.getUser().getScreenName().equals(getUserName())) {
continue;
}
if (statusId > last) {
log("Processing mention", Level.INFO, tweet.getText(), tweet.getUser().getScreenName());
input(tweet);
Utils.sleep(100);
} else {
log("Old mention", Level.INFO, statusId, statusTime);
}
}
}
if (max != 0) {
twitter.setRelationship(Primitive.LASTMENTION, memory.createVertex(max));
memory.save();
}
} catch (Exception exception) {
log(exception);
}
// Wait for language processing.
int count = 0;
while (count < 60 && !getBot().memory().getActiveMemory().isEmpty()) {
Utils.sleep(1000);
}
this.languageState = LanguageState.Discussion;
}
/**
* Check search keywords.
*/
public void checkSearch() {
if (getTweetSearch().isEmpty()) {
return;
}
log("Processing search", Level.FINE, getTweetSearch());
try {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTSEARCH);
long last = 0;
long max = 0;
int count = 0;
this.errors = 0;
if (vertex != null) {
last = ((Number)vertex.getData()).longValue();
}
Set<Long> processed = new HashSet<Long>();
for (String tweetSearch : getTweetSearch()) {
Query query = new Query(tweetSearch);
if (vertex != null) {
query.setSinceId(last);
}
SearchResource search = getConnection().search();
QueryResult result = search.search(query);
List<Status> tweets = result.getTweets();
if (tweets != null) {
log("Processing search results", Level.FINE, tweets.size(), tweetSearch);
for (Status tweet : tweets) {
if (count > this.maxSearch) {
log("Max search results processed", Level.FINE, this.maxSearch);
break;
}
if (tweet.getId() > last && !processed.contains(tweet.getId())) {
if (tweet.getId() > max) {
max = tweet.getId();
}
boolean match = false;
// Exclude replies/mentions
if (tweet.getText().indexOf('@') != -1) {
log("Tweet is reply", Level.FINER, tweet.getText());
continue;
}
// Exclude retweets
if (tweet.isRetweet()) {
log("Tweet is retweet", Level.FINER, tweet.getText());
continue;
}
// Exclude protected
if (tweet.getUser().isProtected()) {
log("Tweet is protected", Level.FINER, tweet.getText());
continue;
}
// Exclude self
if (tweet.getUser().getScreenName().equals(getUserName())) {
log("Tweet is from myself", Level.FINER, tweet.getText());
continue;
}
// Ignore profanity
if (Utils.checkProfanity(tweet.getText())) {
log("Tweet contains profanity", Level.FINER, tweet.getText());
continue;
}
List<String> statusWords = new TextStream(tweet.getText().toLowerCase()).allWords();
for (String text : getStatusKeywords()) {
List<String> keywords = new TextStream(text.toLowerCase()).allWords();
if (statusWords.containsAll(keywords)) {
match = true;
break;
}
}
if (getLearn()) {
learnTweet(tweet, true, true, memory);
}
if (match) {
processed.add(tweet.getId());
log("Processing search", Level.INFO, tweet.getUser().getScreenName(), tweetSearch, tweet.getText());
input(tweet);
Utils.sleep(500);
count++;
} else {
if (!tweet.isRetweetedByMe()) {
boolean found = false;
// Check retweet.
for (String keywords : getRetweet()) {
List<String> keyWords = new TextStream(keywords).allWords();
if (!keyWords.isEmpty()) {
if (statusWords.containsAll(keyWords)) {
found = true;
processed.add(tweet.getId());
count++;
retweet(tweet);
Utils.sleep(500);
break;
}
}
}
if (!found) {
log("Missing keywords", Level.FINER, tweet.getText());
}
} else {
log("Already retweeted", Level.FINER, tweet.getText());
}
}
}
}
}
if (count > this.maxSearch) {
break;
}
if (this.errors > this.maxErrors) {
break;
}
}
if (max != 0) {
twitter.setRelationship(Primitive.LASTSEARCH, memory.createVertex(max));
memory.save();
}
} catch (Exception exception) {
log(exception);
}
// Wait for language processing.
int count = 0;
while (count < 60 && !getBot().memory().getActiveMemory().isEmpty()) {
Utils.sleep(1000);
}
}
/**
* Check search keywords.
*/
public void checkAutoFollowSearch(int friendCount) {
if (getAutoFollowSearch().isEmpty()) {
return;
}
log("Processing autofollow search", Level.FINE, getAutoFollowSearch());
try {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTAUTOFOLLOWSEARCH);
long last = 0;
long max = 0;
int count = 0;
if (vertex != null) {
last = ((Number)vertex.getData()).longValue();
}
for (String followSearch : getAutoFollowSearch()) {
Query query = new Query(followSearch);
if (vertex != null) {
query.setSinceId(last);
}
SearchResource search = getConnection().search();
QueryResult result = search.search(query);
List<Status> tweets = result.getTweets();
if (tweets != null) {
for (Status tweet : tweets) {
if (count > this.maxSearch) {
break;
}
if (tweet.getId() > last) {
log("Autofollow search", Level.FINE, tweet.getText(), tweet.getUser().getScreenName(), followSearch);
if (checkFriendship(tweet.getUser().getId(), false)) {
friendCount++;
if (friendCount >= getMaxFriends()) {
log("Max friend limit", Level.FINE, getMaxFriends());
return;
}
}
count++;
if (tweet.getId() > max) {
max = tweet.getId();
}
}
}
}
if (count > this.maxSearch) {
break;
}
}
if (max != 0) {
twitter.setRelationship(Primitive.LASTAUTOFOLLOWSEARCH, memory.createVertex(max));
memory.save();
}
} catch (Exception exception) {
log(exception);
}
}
/**
* Check RSS feed.
*/
public void checkRSS() {
if (getTweetRSS().isEmpty()) {
return;
}
log("Processing RSS", Level.FINE, getTweetRSS());
try {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTRSS);
long last = 0;
if (vertex != null) {
last = ((Number)vertex.getData()).longValue();
}
int rssIndex = 0;
String keywordsText = "";
List<String> keywords = new ArrayList<String>();
for (String rss : getTweetRSS()) {
if (rssIndex < getRssKeywords().size()) {
keywordsText = getRssKeywords().get(rssIndex);
keywords = new TextStream(keywordsText.toLowerCase()).allWords();
}
rssIndex++;
TextStream stream = new TextStream(rss);
String prefix = stream.upToAll("http").trim();
if (prefix.isEmpty()) {
prefix = "";
}
prefix = prefix + " ";
String url = stream.nextWord();
String postfix = " " + stream.upToEnd().trim();
List<Map<String, Object>> feed = getBot().awareness().getSense(Http.class).parseRSSFeed(new URL(url), last);
if (feed != null) {
long max = 0;
int count = 0;
this.errors = 0;
log("Processing RSS feed", Level.FINE, feed.size(), rss);
for (int index = feed.size() - 1; index >= 0; index--) {
Map<String, Object> entry = feed.get(index);
long time = (Long)entry.get("published");
if ((System.currentTimeMillis() - time) > DAY) {
continue;
}
if (time > last) {
if (count > this.maxFeed) {
break;
}
if (this.errors > this.maxErrors) {
break;
}
String text = (String)entry.get("title");
if (!keywords.isEmpty()) {
if (!new TextStream(text.toLowerCase()).allWords().containsAll(keywords)) {
log("Skipping RSS, missing keywords", Level.FINE, keywords, text);
continue;
}
}
log("Tweeting RSS", Level.FINE, entry.get("title"));
text = prefix + text + postfix;
if (text.length() > 120) {
text = text.substring(0, 120);
}
tweet(text + " " + entry.get("link"), 0L);
Utils.sleep(500);
count++;
if (time > max) {
max = time;
}
}
}
if (max != 0) {
twitter.setRelationship(Primitive.LASTRSS, memory.createVertex(max));
memory.save();
}
}
}
} catch (Exception exception) {
log(exception);
}
}
/**
* Auto tweet.
*/
public void checkAutoTweet() {
if (!getAutoTweet()) {
return;
}
log("Autotweeting", Level.FINE);
try {
Network memory = getBot().memory().newMemory();
Vertex twitter = memory.createVertex(getPrimitive());
Vertex vertex = twitter.getRelationship(Primitive.LASTTWEET);
long last = 0;
if (vertex != null) {
last = ((Timestamp)vertex.getData()).getTime();
}
long millis = getAutoTweetHours() * 60 * 60 * 1000;
if ((System.currentTimeMillis() - last) < millis) {
log("Autotweeting hours not reached", Level.FINE, getAutoTweetHours());
return;
}
List<Vertex> autotweets = getAutoTweets(memory);
if (autotweets != null && !autotweets.isEmpty()) {
int index = Utils.random().nextInt(autotweets.size());
Vertex tweet = autotweets.get(index);
String text = null;
// Check for labels and formulas
if (tweet.instanceOf(Primitive.LABEL)) {
tweet = tweet.mostConscious(Primitive.RESPONSE);
}
if (tweet.instanceOf(Primitive.FORMULA)) {
Map<Vertex, Vertex> variables = new HashMap<Vertex, Vertex>();
SelfCompiler.addGlobalVariables(memory.createInstance(Primitive.INPUT), null, memory, variables);
Vertex result = getBot().mind().getThought(Language.class).evaluateFormula(tweet, variables, memory);
if (result != null) {
text = getBot().mind().getThought(Language.class).getWord(result, memory).getDataValue();
} else {
log("Invalid autotweet template formula", Level.WARNING, tweet);
text = null;
}
} else {
text = tweet.printString();
}
if (text != null) {
log("Autotweeting", Level.INFO, tweet);
tweet(text, 0L);
Utils.sleep(100);
twitter.setRelationship(Primitive.LASTTWEET, memory.createTimestamp());
memory.save();
}
}
} catch (Exception exception) {
log(exception);
}
}
/**
* Return the list of followers names.
*/
public List<String> getFollowers() {
List<String> followers = new ArrayList<String>();
try {
long[] ids = getConnection().getFollowersIDs(-1).getIDs();
if (ids.length == 0) {
return followers;
}
int index = 0;
while (ids.length > index) {
long[] lookup = ids;
if (index > 0) {
lookup = Arrays.copyOfRange(ids, index, Math.min(ids.length, index + MAX_LOOKUP));
} else if (ids.length > MAX_LOOKUP) {
lookup = Arrays.copyOf(ids, MAX_LOOKUP);
}
index = index + MAX_LOOKUP;
ResponseList<User> users = getConnection().lookupUsers(lookup);
for (User user : users) {
followers.add(user.getScreenName());
}
// Only return first 100.
break;
}
} catch (Exception exception) {
log(exception);
}
return followers;
}
/**
* Return the time-line.
*/
public List<String> getTimeline() {
List<String> timeline = new ArrayList<String>();
try {
ResponseList<Status> statuses = getConnection().getHomeTimeline();
for (Status status : statuses) {
timeline.add(status.getCreatedAt() + " - <b>" + status.getUser().getScreenName() + "</b>: " + status.getText());
}
} catch (Exception exception) {
log(exception);
throw new BotException(exception);
}
return timeline;
}
/**
* Return the total number of friends.
*/
public int getFriendsCount() {
try {
return getConnection().getFriendsIDs(-1).getIDs().length;
} catch (Exception exception) {
log(exception);
return 0;
}
}
/**
* Return the total number of followers.
*/
public int getFollowersCount() {
try {
return getConnection().getFollowersIDs(-1).getIDs().length;
} catch (Exception exception) {
log(exception);
return 0;
}
}
/**
* Return the list of friends names.
*/
public List<String> getFriends() {
List<String> friends = new ArrayList<String>();
try {
long[] friendIds = getConnection().getFriendsIDs(-1).getIDs();
int index = 0;
while (friendIds.length > index) {
long[] lookup = friendIds;
if (index > 0) {
lookup = Arrays.copyOfRange(friendIds, index, Math.min(friendIds.length, index + MAX_LOOKUP));
} else if (friendIds.length > MAX_LOOKUP) {
lookup = Arrays.copyOf(friendIds, MAX_LOOKUP);
}
index = index + MAX_LOOKUP;
ResponseList<User> users = getConnection().lookupUsers(lookup);
for (User user : users) {
friends.add(user.getScreenName());
}
// Only return first 100.
break;
}
} catch (Exception exception) {
log(exception);
}
return friends;
}
/**
* Check followers.
*/
public void checkFollowers() {
if (!getAutoFollow() && getWelcomeMessage().isEmpty()) {
return;
}
try {
log("Checking followers", Level.FINE);
long[] followerIds = getConnection().getFollowersIDs(-1).getIDs(); //max 5000
long[] friends = getConnection().getFriendsIDs(-1).getIDs();
int friendCount = friends.length;
int count = 0;
boolean welcomeOnly = false;
if (friendCount >= getMaxFriends()) {
if (!getWelcomeMessage().isEmpty()) {
welcomeOnly = true;
} else {
log("Max friend limit", Level.FINE, getMaxFriends());
return;
}
}
for (int index = 0; index < followerIds.length; index++) {
boolean found = false;
long followerId = followerIds[index];
for (long friend : friends) {
if (followerId == friend) {
found = true;
break;
}
}
if (!found) {
log("Checking new follower", Level.FINE, followerId);
boolean isNewFriend = checkFriendship(followerId, welcomeOnly);
if (!isNewFriend) {
// Followers are ordered, so if already followed ignore the rest.
break;
}
friendCount++;
if (friendCount >= getMaxFriends()) {
if (!getWelcomeMessage().isEmpty()) {
welcomeOnly = true;
} else {
return;
}
}
count++;
if (count >= this.maxFriendsPerCycle) {
if (!getWelcomeMessage().isEmpty() && count < this.maxWelcomesPerCycle) {
welcomeOnly = true;
} else {
log("Max friend per cycle limit", Level.FINE, this.maxFriendsPerCycle);
return;
}
}
if (!welcomeOnly && getAutoFollowFriendsFriends()) {
log("Checking friends friends", Level.FINE, followerId);
long[] friendsFriends = getConnection().getFriendsIDs(followerId, -1).getIDs();
for (long friendsFriend : friendsFriends) {
if (checkFriendship(friendsFriend, welcomeOnly)) {
friendCount++;
if (friendCount >= getMaxFriends()) {
log("Max friend limit", Level.FINE, getMaxFriends());
return;
}
count++;
if (count >= this.maxFriendsPerCycle) {
log("Max friend per cycle limit", Level.FINE, this.maxFriendsPerCycle);
return;
}
}
}
}
if (!welcomeOnly && getAutoFollowFriendsFollowers()) {
log("Checking friends followers", Level.FINE, followerId);
long[] friendsFollowers = getConnection().getFollowersIDs(followerId, -1).getIDs();
for (long friendsFollower : friendsFollowers) {
if (checkFriendship(friendsFollower, welcomeOnly)) {
friendCount++;
if (friendCount >= getMaxFriends()) {
log("Max friend limit", Level.FINE, getMaxFriends());
return;
}
count++;
if (count >= this.maxFriendsPerCycle) {
log("Max friend per cycle limit", Level.FINE, this.maxFriendsPerCycle);
return;
}
}
}
}
}
}
checkAutoFollowSearch(friendCount);
} catch (Exception exception) {
log(exception);
}
}
public boolean checkFriendship(long friendId, boolean welcomeOnly) throws TwitterException {
long[] lookup = new long[1];
lookup[0] = friendId;
ResponseList<User> users = getConnection().lookupUsers(lookup);
User friend = users.get(0);
if (friend.getScreenName().equals(getUserName())) {
return false;
}
if (!getAutoFollowKeywords().isEmpty()) {
StringWriter writer = new StringWriter();
writer.write(friend.getScreenName().toLowerCase());
writer.write(" ");
writer.write(friend.getDescription().toLowerCase());
writer.write(" ");
writer.write(friend.getLocation().toLowerCase());
writer.write(" ");
writer.write(friend.getLang().toLowerCase());
writer.write(" ");
writer.write(friend.getName().toLowerCase());
boolean match = false;
for (String text : getAutoFollowKeywords()) {
List<String> keywords = new TextStream(text.toLowerCase()).allWords();
if (new TextStream(writer.toString()).allWords().containsAll(keywords)) {
match = true;
break;
}
}
if (!match) {
log("Autofollow skipping friend, does not match keywords", Level.FINE, friend.getScreenName());
return false;
}
}
Network memory = getBot().memory().newMemory();
Vertex speaker = memory.createSpeaker(friend.getScreenName());
speaker.setPinned(true);
// Only try to follow a user once.
if (!speaker.hasRelationship(Primitive.FOLLOWED)) {
speaker.addRelationship(Primitive.FOLLOWED, memory.createTimestamp());
memory.save();
if (!welcomeOnly && getAutoFollow()) {
log("Adding autofollow friend.", Level.INFO, friend.getScreenName());
getConnection().createFriendship(friendId);
Utils.sleep(1000);
}
if (!getWelcomeMessage().isEmpty()) {
log("Sending welcome message.", Level.INFO, friend.getScreenName());
sendMessage(getWelcomeMessage(), friend.getScreenName());
Utils.sleep(1000);
}
if (welcomeOnly) {
return false;
}
return true;
}
log("Autofollow skipping friend, already followed once", Level.FINE, friend.getScreenName());
return false;
}
public void log(TwitterException exception) {
log(new TextStream(exception.toString()).nextLine(), Bot.WARNING);
}
/**
* Check trends.
*/
public void checkTrends() {
try {
Network network = getBot().memory().newMemory();
if ((this.lastTrendsCheck == 0)
|| ((System.currentTimeMillis() - this.lastTrendsCheck) > TREND_CHECK)) {
Vertex twitter = network.createVertex(getPrimitive());
Vertex lastCheck = twitter.getRelationship(Primitive.TREND);
if (lastCheck == null) {
twitter.addRelationship(Primitive.TREND, network.createTimestamp());
} else {
long lastCheckTime = ((Timestamp)lastCheck.getData()).getTime();
if ((System.currentTimeMillis() - lastCheckTime) < TREND_CHECK) { // 1 hours.
return;
}
}
log("Checking trends", Bot.FINE);
twitter.setRelationship(Primitive.TREND, network.createTimestamp());
/**List<Trends> dailyTrends = getConnection().getDailyTrends();
List<String> trendNames = new ArrayList<String>();
if (dailyTrends.size() > 0) {
for (Trend trend : dailyTrends.get(0).getTrends()) {
trendNames.add(trend.getName());
}
}
for (String text : trendNames) {
if (text.charAt(0) == '#') {
text = text.substring(1, text.length());
}
log("Trend:", Bot.FINE, text);
Vertex word = network.createWord(text);
network.save();
getBot().memory().addActiveMemory(word);
}*/
this.lastTrendsCheck = System.currentTimeMillis();
}
} catch (Exception exception) {
log(exception);
}
}
/**
* Tweet.
*/
public void tweet(String text, Long reply) {
text = format(text);
if (text.length() > 140) {
int index = text.indexOf("http://");
if (index == -1) {
text = text.substring(0, 140);
} else if (index > 120) {
text = text.substring(0, 120) + " " + text.substring(index, text.length());
}
}
this.tweets++;
log("Tweeting:", Level.INFO, text);
try {
if (getConnection() == null) {
connect();
}
StatusUpdate update = new StatusUpdate(text);
if (reply != null) {
update.setInReplyToStatusId(reply);
}
getConnection().updateStatus(update);
} catch (Exception exception) {
this.errors++;
log(exception.getMessage(), Level.WARNING, text);
}
}
public String format(String text) {
text = text.replace("<br/>", "\n");
text = text.replace("<br>", "\n");
text = text.replace("</br>", "");
text = text.replace("<li>", "\n");
text = text.replace("</li>", "");
text = Utils.stripTags(text);
return text;
}
/**
* Send a message to the user.
*/
public void sendMessage(String text, String replyUser) {
log("Sending message:", Level.INFO, text, replyUser);
try {
text = format(text);
getConnection().sendDirectMessage(replyUser, text);
} catch (Exception exception) {
this.errors++;
log(exception);
}
}
/**
* Retweet the tweet.
*/
public void retweet(Status tweet) {
if (tweet.isRetweet()) {
tweet = tweet.getRetweetedStatus();
}
if (tweet.getUser().isProtected()) {
log("Cannot retweet protected user", Level.INFO, tweet.getUser().getScreenName(), tweet.getText());
return;
}
this.retweets++;
log("Retweeting:", Level.INFO, tweet.getText(), tweet.getUser().getScreenName());
try {
if (getConnection() == null) {
connect();
}
getConnection().retweetStatus(tweet.getId());
} catch (Exception exception) {
if (exception.getMessage() != null && exception.getMessage().contains("authorized") && exception.getMessage().contains("endpoint")) {
this.errors = this.errors + 5;
}
this.errors++;
log(exception.toString(), Level.WARNING, tweet.getText());
}
}
/**
* Output the tweet if twitter is connected.
*/
public void outputTweet(String tweet) {
if (!isEnabled() || !getTweetChats()) {
return;
}
Network network = getBot().memory().newMemory();
Vertex setence = network.createSentence(tweet);
Vertex output = network.createInstance(Primitive.INPUT);
output.setName(tweet);
output.addRelationship(Primitive.INPUT, setence);
output.addRelationship(Primitive.SENSE, getPrimitive());
output.addRelationship(Primitive.SPEAKER, Primitive.SELF);
output.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
network.createVertex(Primitive.SELF).addRelationship(Primitive.TWEET, output);
Vertex target = output.mostConscious(Primitive.TARGET);
if (target != null) {
String replyTo = target.mostConscious(Primitive.WORD).getData().toString();
tweet = "@" + replyTo + " " + tweet;
}
network.save();
tweet(tweet, null);
}
/**
* Process the email message.
*/
@Override
public void input(Object input, Network network) {
if (!isEnabled()) {
return;
}
try {
if (input instanceof Status) {
Status tweet = (Status)input;
log("Processing status", Bot.FINE, tweet.getText(), tweet.getId());
if ((System.currentTimeMillis() - tweet.getCreatedAt().getTime()) > DAY) {
log("Day old status", Bot.FINE, tweet.getId(), tweet.getCreatedAt().getTime());
return;
}
if (this.processedTweets.contains(tweet.getId())) {
log("Already processed status", Bot.FINE, tweet.getText(), tweet.getId());
return;
}
this.processedTweets.add(tweet.getId());
String name = tweet.getUser().getScreenName();
String replyTo = tweet.getInReplyToScreenName();
String text = tweet.getText().trim();
TextStream stream = new TextStream(text);
String firstWord = null;
if (stream.peek() == '@') {
stream.next();
String replyTo2 = stream.nextWord();
firstWord = stream.peekWord();
text = stream.upToEnd().trim();
if (!replyTo2.equals(replyTo)) {
log("Reply to does not match:", Bot.FINE, replyTo2, replyTo);
}
replyTo = replyTo2;
if (replyTo.equals(this.userName)) {
if ("follow".equals(firstWord)) {
log("Adding friend", Level.INFO, tweet.getUser().getScreenName());
getConnection().createFriendship(tweet.getUser().getId());
} else if ("unfollow".equals(firstWord)) {
log("Removing friend", Level.INFO, tweet.getUser().getScreenName());
getConnection().destroyFriendship(tweet.getUser().getId());
}
}
}
if (!tweet.isRetweet() && !tweet.getUser().isProtected()) {
stream.reset();
List<String> words = stream.allWords();
for (String keywords : getRetweet()) {
List<String> keyWords = new TextStream(keywords).allWords();
if (!keyWords.isEmpty()) {
if (words.containsAll(keyWords)) {
retweet(tweet);
break;
}
}
}
}
log("Input status", Level.FINE, tweet.getText(), name, replyTo);
this.tweetsProcessed++;
inputSentence(text, name, replyTo, tweet, network);
}
} catch (Exception exception) {
log(exception);
}
}
/**
* Output the status or direct message reply.
*/
public void output(Vertex output) {
if (!isEnabled()) {
return;
}
Vertex sense = output.mostConscious(Primitive.SENSE);
// If not output to twitter, ignore.
if ((sense == null) || (!getPrimitive().equals(sense.getData()))) {
return;
}
output.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
output.getNetwork().createVertex(Primitive.SELF).addRelationship(Primitive.TWEET, output);
String text = printInput(output);
Vertex target = output.mostConscious(Primitive.TARGET);
if (target != null) {
String replyTo = target.mostConscious(Primitive.WORD).getData().toString();
text = "@" + replyTo + " " + text;
}
Vertex question = output.getRelationship(Primitive.QUESTION);
Long reply = null;
if (question != null) {
Vertex id = question.getRelationship(Primitive.ID);
if (id != null) {
reply = ((Number)id.getData()).longValue();
}
}
tweet(text, reply);
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
/**
* Process the text sentence.
*/
public void inputSentence(String text, String userName, String targetUserName, Status status, Network network) {
Vertex input = createInput(text.trim(), network);
Vertex sentence = input.getRelationship(Primitive.INPUT);
Vertex id = network.createVertex(status.getId());
if (sentence.hasRelationship(Primitive.TWEET, id)) {
log("Status already processed", Bot.FINE, status.getId(), status.getCreatedAt().getTime());
return;
}
sentence.addRelationship(Primitive.TWEET, id);
input.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
input.addRelationship(Primitive.CREATEDAT, network.createVertex(status.getCreatedAt().getTime()));
input.addRelationship(Primitive.ID, id);
Vertex conversation = network.createInstance(Primitive.CONVERSATION);
conversation.addRelationship(Primitive.TYPE, Primitive.TWEET);
Language.addToConversation(input, conversation);
Vertex user = network.createSpeaker(userName);
conversation.addRelationship(Primitive.SPEAKER, user);
input.addRelationship(Primitive.SPEAKER, user);
if (targetUserName != null) {
Vertex targetUser = null;
if (targetUserName.equals(getUserName())) {
targetUser = network.createVertex(Primitive.SELF);
} else {
targetUser = network.createSpeaker(targetUserName);
}
input.addRelationship(Primitive.TARGET, targetUser);
conversation.addRelationship(Primitive.SPEAKER, targetUser);
}
user.addRelationship(Primitive.TWEET, input);
network.save();
getBot().memory().addActiveMemory(input);
}
/**
* Create an input based on the sentence.
*/
protected Vertex createInput(String text, Network network) {
Vertex sentence = network.createSentence(text);
Vertex input = network.createInstance(Primitive.INPUT);
input.setName(text);
input.addRelationship(Primitive.SENSE, getPrimitive());
input.addRelationship(Primitive.INPUT, sentence);
sentence.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
return input;
}
public String getOauthKey() {
return oauthKey;
}
public void setOauthKey(String oauthKey) {
Twitter.oauthKey = oauthKey;
}
public String getOauthSecret() {
return oauthSecret;
}
public void setOauthSecret(String oauthSecret) {
Twitter.oauthSecret = oauthSecret;
}
public String getTokenSecret() {
return tokenSecret;
}
public void setTokenSecret(String tokenSecret) {
this.tokenSecret = tokenSecret;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public twitter4j.Twitter getConnection() throws TwitterException {
if (connection == null) {
connect();
}
return connection;
}
public void setConnection(twitter4j.Twitter connection) {
this.connection = connection;
}
public boolean getAutoFollow() {
initProperties();
return autoFollow;
}
public void setAutoFollow(boolean autoFollow) {
initProperties();
this.autoFollow = autoFollow;
}
public int getMaxFriends() {
initProperties();
return maxFriends;
}
public void setMaxFriends(int maxFriends) {
initProperties();
this.maxFriends = maxFriends;
}
public boolean getLearn() {
initProperties();
return learn;
}
public void setLearn(boolean learn) {
initProperties();
this.learn = learn;
}
public boolean getLearnFromSelf() {
initProperties();
return learnFromSelf;
}
public void setLearnFromSelf(boolean learnFromSelf) {
initProperties();
this.learnFromSelf = learnFromSelf;
}
public boolean getProcessStatus() {
initProperties();
return processStatus;
}
public void setProcessStatus(boolean processStatus) {
initProperties();
this.processStatus = processStatus;
}
public boolean getTweetChats() {
return tweetChats;
}
public boolean getReplyToMentions() {
initProperties();
return replyToMentions;
}
public boolean getReplyToMessages() {
initProperties();
return replyToMessages;
}
public void setTweetChats(boolean tweetChats) {
this.tweetChats = tweetChats;
}
public void setReplyToMentions(boolean replyToMentions) {
this.replyToMentions = replyToMentions;
}
public void setReplyToMessages(boolean replyToMessages) {
this.replyToMessages = replyToMessages;
}
public List<String> getRetweet() {
initProperties();
return retweet;
}
public void setRetweet(List<String> retweet) {
initProperties();
this.retweet = retweet;
}
public List<String> getTweetRSS() {
initProperties();
return tweetRSS;
}
public void setTweetRSS(List<String> tweetRSS) {
initProperties();
this.tweetRSS = tweetRSS;
}
public boolean getCheckTrends() {
return checkTrends;
}
public void setCheckTrends(boolean checkTrends) {
this.checkTrends = checkTrends;
}
public List<String> getTweetSearch() {
initProperties();
return tweetSearch;
}
public void setTweetSearch(List<String> tweetSearch) {
initProperties();
this.tweetSearch = tweetSearch;
}
public boolean getFollowMessages() {
initProperties();
return followMessages;
}
public void setFollowMessages(boolean followMessages) {
initProperties();
this.followMessages = followMessages;
}
public int getMaxStatus() {
initProperties();
return maxStatus;
}
public void setMaxStatus(int maxStatus) {
initProperties();
this.maxStatus = maxStatus;
}
// Self API
public void tweet(Vertex source, Vertex sentence) {
if (sentence.instanceOf(Primitive.FORMULA)) {
Map<Vertex, Vertex> variables = new HashMap<Vertex, Vertex>();
SelfCompiler.addGlobalVariables(sentence.getNetwork().createInstance(Primitive.INPUT), null, sentence.getNetwork(), variables);
sentence = getBot().mind().getThought(Language.class).evaluateFormula(sentence, variables, sentence.getNetwork());
if (sentence == null) {
log("Invalid template formula", Level.WARNING, sentence);
return;
}
}
String tweet = getBot().mind().getThought(Language.class).getWord(sentence, sentence.getNetwork()).getDataValue();
getBot().stat("twitter.tweet");
tweet(tweet, 0L);
}
// Self API
public Vertex trend(Network network) throws TwitterException {
Trends trends = getConnection().getPlaceTrends(1);
if (trends.getTrends().length > 0) {
return network.createObject(trends.getTrends()[0].getName());
}
return null;
}
}