Navigation Menu

Skip to content

Commit

Permalink
Fixing flow. Updating readme. Finished ES6 Rewriting.
Browse files Browse the repository at this point in the history
  • Loading branch information
raulrene committed Jan 4, 2017
1 parent 6de0b9e commit 2c0dd49
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 34 deletions.
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -4,19 +4,19 @@ A Javascript bot that searches for tweets about contests and Retweets them. If n

Inspired by http://www.hscott.net/twitter-contest-winning-as-a-service/

##Disclaimer
## Disclaimer

This bot is written purely for educational purposes. I hold no liability for what you do with this bot or what happens to you by using this bot. Abusing this bot can get you banned from Twitter, so make sure to read up on proper usage of the Twitter API.

##Installation
## Installation
* Make sure you have NodeJS up and running
* `git clone` the repository, or download the zip file and unzip it
* `npm install` in the directory where you cloned the repository (this is needed for installing dependencies)
* Edit the `config.js` file with your Twitter API Credentials
* run `node index.js`

## Dependencies
It makes use of the <a href="https://github.com/request/request-promise"><b>request-promise</b></a> library, a HTTP JS client.
It makes use of [request-promise](https://github.com/request/request-promise) - a HTTP JS client

## Alternatives
If you're looking for similar projects in alternative languages, check these out:
Expand Down
2 changes: 1 addition & 1 deletion api-functions.js
Expand Up @@ -53,7 +53,7 @@ const API = {

if (result && result.statuses) {
result.statuses.forEach(item => allItems.push(item));
console.log('So far we have a total of:', allItems.length);
console.log('[Search] So far we have', allItems.length, 'items');

// If we have the next_results, search again for the rest (sort of a pagination)
const nextRes = result.search_metadata.next_results;
Expand Down
65 changes: 37 additions & 28 deletions index.js
Expand Up @@ -23,36 +23,43 @@ class ContestJSBot {
this.search();

// Start the Retweet worker after short grace period for search results to come in
setTimeout(() => this.retweetWorker.bind(this), 8000);
setTimeout(() => this.retweetWorker(), config.RETWEET_TIMEOUT);
})
.catch((err) => console.error('Your credentials are not valid. Check the config.js file and ensure you supply the correct API keys.', err.messsage));
.catch(err => console.error('Your credentials are not valid. Check the config.js file and ensure you supply the correct API keys.', err));
}

/** The Search function */
search() {
// Don't search if limit lockout is in effect
if (this.limitLockout) return;

console.log('Searching for tweets...');
let text = '';
const since_id = this.last_tweet_id;
console.log('[Search] Searching for tweets...');

config.SEARCH_QUERIES.forEach((searchQuery) => {
let doSearch = (index) => {
// Construct the query
text = searchQuery + config.SEARCH_QUERY_FILTERS;
let text = config.SEARCH_QUERIES[index] + config.SEARCH_QUERY_FILTERS;

// Append preferred accounts if it's the case
if (config.PREFERRED_ACCOUNTS) {
text += ` from:${config.PREFERRED_ACCOUNTS.join(' OR from:')}`;
}

API.search({text, result_type: config.RESULT_TYPE, since_id: this.last_tweet_id})
.then(res => this.searchCallback(res))
API.search({text, result_type: config.RESULT_TYPE, since_id})
.then(res => {
// Call the search callback to process the data
this.searchCallback(res);

if (config.SEARCH_QUERIES[index + 1]) {
// Sleep between searches so we do not trigger rate limit lockout
console.log(`[Search] Sleeping for ${config.RATE_SEARCH_TIMEOUT / 1000} seconds between searches so we don't trigger rate limit`);
setTimeout(() => doSearch(index++), config.RATE_SEARCH_TIMEOUT);
}
})
.catch(err => this.errorHandler(err));
};

// we need to wait between search queries so we do not trigger rate limit lockout
// sleepFor(config.RATE_SEARCH_TIMEOUT);
// console.log(`Sleeping for ${config.RATE_SEARCH_TIMEOUT} ms between searches so we don't trigger rate limit`);
});
doSearch(0);
}

/** The Callback function for the Search API */
Expand All @@ -75,16 +82,18 @@ class ContestJSBot {
if (this.blockedUsers.indexOf(searchItem.user.id) > -1) return;

// We ignore users with high amounts of tweets (likely bots)
if (config.MAX_USER_TWEETS && searchItem.user.statuses_count < config.MAX_USER_TWEETS) {
// Save the search item in the Search Results array
this.searchResultsArr.push(searchItem);
}
// may be a spam bot, do we want to block them?
else if (config.MAX_USER_TWEETS_BLOCK) {
this.blockedUsers.push(searchItem.user.id);
API.blockUser(searchItem.user.id)
.then(() => console.log('Blocked possible bot user ' + searchItem.user.id));
if (config.MAX_USER_TWEETS && searchItem.user.statuses_count >= config.MAX_USER_TWEETS) {
// may be a spam bot, do we want to block them?
if (config.MAX_USER_TWEETS_BLOCK) {
this.blockedUsers.push(searchItem.user.id);
API.blockUser(searchItem.user.id)
.then(() => console.log('Blocked possible bot user' + searchItem.user.id));
}
return;
}

// Save the search item in the Search Results array
this.searchResultsArr.push(searchItem);
});
}

Expand Down Expand Up @@ -119,22 +128,22 @@ class ContestJSBot {
this.searchResultsArr.shift();

// Retweet
console.log('[Retweeting]', searchItem.id);
console.log('[Retweeting Tweet #]', searchItem.id);
API.retweet(searchItem.id_str)
.then(() => {

// On success, try to Favorite/Like and Follow
if (searchItem.text.toLowerCase().indexOf('fav') > -1 || searchItem.text.toLowerCase().indexOf('like') > -1) {
API.favorite(searchItem.id_str);
console.log('[Favorite]', searchItem.id);
console.log('[Marking as Favorite tweet #]', searchItem.id);
}
if (searchItem.text.toLowerCase().indexOf('follow') > -1) {
API.follow(searchItem.user.id_str);
console.log('[Follow]', searchItem.user.screen_name);
console.log('[Following user]', searchItem.user.screen_name);
}

// Then, re-queue the RT Worker
setTimeout(() => this.retweetWorker.bind(this), config.RETWEET_TIMEOUT);
setTimeout(() => this.retweetWorker(), config.RETWEET_TIMEOUT);
})
.catch(() => {
console.error('[Error] RT Failed for', searchItem.id, '. Likely has already been retweeted. Adding to blacklist.');
Expand All @@ -143,7 +152,7 @@ class ContestJSBot {
this.badTweetIds.push(searchItem.id);

// Then, re-start the RT Worker
setTimeout(() => this.retweetWorker.bind(this), config.RETWEET_TIMEOUT);
setTimeout(() => this.retweetWorker(), config.RETWEET_TIMEOUT);
});

}
Expand All @@ -152,15 +161,15 @@ class ContestJSBot {
else {
if (this.limitLockout) {
// we must schedule this to rerun, or else the program will exit when a lockout occurs
setTimeout(() => this.retweetWorker.bind(this), config.RATE_SEARCH_TIMEOUT);
setTimeout(() => this.retweetWorker(), config.RATE_SEARCH_TIMEOUT);
return;
}

console.log('No more results. Will search and analyze again in ', config.RATE_SEARCH_TIMEOUT / 1000 + ' seconds.');

// go fetch new results
this.search();
setTimeout(() => this.retweetWorker.bind(this), config.RATE_SEARCH_TIMEOUT);
setTimeout(() => this.retweetWorker(), config.RATE_SEARCH_TIMEOUT);
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions package.json
@@ -1,7 +1,13 @@
{
"name": "Twitter contest JS bot",
"description": "A Javascript bot that searches for tweets about contests and retweets them.",
"name": "twitter-contest-js-bot",
"version": "2.0.0",
"author": "Raul Rene Lepsa <raul.lepsa@gmail.com>",
"description": "A Javascript bot that searches for tweets about contests and retweets them.",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/raulrene/twitter-contest-js-bot.git"
},
"dependencies": {
"request-promise": "^0.4.3"
}
Expand Down

0 comments on commit 2c0dd49

Please sign in to comment.