Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Twitter bot
- * github.com/henriquesa
- * MIT license
- *
- * Every account posts a status and every other retweets it;
- * You can have unlimited accounts;
- * You need to have an API with write privileges (get it on dev.twitter.com);
- * The default rate is way below the maximum barrier;
- * Each account will be performing [number of total accounts] actions every time;
- * Educational tool only, please do not use this bot;
- * Provided AS IS, not liable for anything done with this.
- *
- */
- var util = require('util'),
- twttr = require('twit'),
- async = require('async'),
- OAuth = require('oauth').OAuth,
- prompt = require('prompt'),
- googl = require('goo.gl');
- var clients = [], iterations, interval, twitter;
- var config = {};
- /*
- * config = {
- * tokens: {
- * consumer_key: String,
- * consumer_secret: String,
- * },
- *
- * tweet: {
- * beforeNumber: String,
- * afterNumber: String
- * },
- *
- * iterations: Number,
- * rate: Number,
- * innerRate: Number
- * }
- */
- config.tokens = {
- consumer_key: 'ADD-YOUR-KEY!',
- consumer_secret: 'IT-HAS-TO-HAVE-WRITE-PRIVILEGE'
- };
- addClients();
- function addClients(){
- async.waterfall([getRequestToken, askPin, getAccessToken], function(err, result){
- if(err) throw err;
- clients.push(result);
- prompt.start();
- prompt.confirm('Add one more account?', function(err, result){
- if(err) throw err;
- if(result) addClients();
- else initialConfig();
- });
- });
- }
- function initialConfig(){
- // Creates a twttr instance for each account, and pushes them to the twitter array
- twitter = [];
- clients.forEach(function(client){
- var clientObject = mergeObjects(client, config.tokens); // Merges client tokens with API tokens
- twitter.push(new twttr(clientObject));
- });
- // Number of status posts from each account that will be retweeted (number of accounts - 1) times
- // default = 400
- config.iterations = config.iterations || 400;
- // Limiting rate between operations in milliseconds
- // default = 1 minute * number of accounts
- config.rate = config.rate || clients.length * 1000 * 60;
- // Limiting rate between every request in each update in milliseconds; does not affect regular rate
- // default = 5 seconds
- config.innerRate = config.innerRate || 5000;
- // Gap between posting and RTing the statuses
- // default = 20 seconds
- config.delayRt = config.delayRt || 20000;
- // Tweet components
- config.tweet = config.tweet || {};
- config.tweet.beforeNumber = config.tweet.beforeNumber || 'Ajudante Beta';
- config.tweet.afterNumber = config.tweet.afterNumber || 'Veja no GitHub: tim-beta barra twitter-bot';
- // Set update trigger at the configured rate, but adjusts for the delay between each request
- iteration = 0;
- update();
- }
- function update(){
- iteration++; // Number inside loop, used to place the tweet number in the status update
- if(iteration > config.iterations){ // Over the limit of iterations, end execution
- clearInterval(interval);
- console.log('Done without errors');
- } else {
- postStatuses(); // Inside the limit, post statuses
- }
- function postStatuses(){
- var postArray = [];
- twitter.forEach(function(account){ // Places all posting functions for all accounts inside an array...
- postArray.push(function(callback){
- postStatus(account, callback);
- });
- });
- async.series(postArray, statusCallback); // ...and calls them serially afterwards with the help of the async lib.
- }
- function postStatus(account, callback){ // Called on each status update
- var before = Date.now();
- process.stdout.write('(' + (twitter.indexOf(account)+1) + '/' + twitter.length + ') Posting tweet... ');
- account.post('statuses/update', {status: composeStatus(), trim_user: true}, function(err, data, response){ // Posts tweet
- if(err){
- callback(err, response); // Ends all execution for the iteration
- return;
- }
- process.stdout.write('#' + data.id_str + ' ');
- callbackAfterDelay(before, data.id_str, callback);
- });
- }
- function statusCallback(err, statusArray){
- if(err){ // If there was an error, end execution
- console.log('Error while posting statuses.');
- console.log(statusArray);
- clearInterval(interval);
- throw err;
- }
- var startRT = function(){
- retweetStatuses(statusArray);
- }
- setTimeout(startRT, config.delayRt); // Every status was posted correctly, now retweet them
- }
- function retweetStatuses(statusArray){
- var retweetArray = [];
- statusArray.forEach(function(statusId, statusIndex){ // Places all RTing functions for all statuses and accounts inside an array
- twitter.forEach(function(account, accountIndex){
- if(statusIndex !== accountIndex){ // Only retweet if the status isn't from the account
- retweetArray.push(function(callback){
- postRetweet(account, statusId, callback);
- });
- }
- });
- });
- async.series(retweetArray, retweetCallback);
- }
- function retweetCallback(err, statusArray){
- if(err){ // If there was an error, end execution
- console.log('Error while retweeting statuses.');
- console.log(statusArray);
- clearInterval(interval);
- throw err;
- }
- var intervalTime = (config.rate - clients.length * config.innerRate) - config.delayRt; // Compensate for all the delays
- console.log('---- ' + iteration + ' out of ' + config.iterations + ' done. Sleeping for ' + intervalTime/1000 + 's ----');
- interval = setInterval(update, intervalTime);
- }
- function postRetweet(account, statusId, callback){ // Called on each RT
- var before = Date.now();
- process.stdout.write('Retweeting #' + statusId + ' (account ' + (twitter.indexOf(account)+1) + ')... ');
- account.post('statuses/retweet/' + statusId, {trim_user: true}, function(err, data, response){
- if(err){
- callback(err, response);
- return;
- }
- callbackAfterDelay(before, data.id, callback);
- });
- }
- function callbackAfterDelay(before, data, callback){
- var timeSpan = Date.now() - before; // Calculates the time difference between now and prior to the AJAX call
- console.log('OK (' + timeSpan + 'ms)');
- var _callback = function(){
- callback(null, data);
- };
- // If the AJAX call took longer than the regular delay, run callback. Else, run the callback after the complete delay occurs
- timeSpan >= config.innerRate ? _callback() : setTimeout(_callback, config.innerRate - timeSpan);
- }
- function composeStatus(){
- return config.tweet.beforeNumber + ' ' +
- Math.floor(Math.random()*10000) + ' ' +
- iteration + ' ' +
- config.tweet.afterNumber;
- }
- }
- function mergeObjects(obj1, obj2){
- for(attrName in obj2){
- obj1[attrName] = obj2[attrName];
- }
- return obj1;
- }
- /*
- * Functions by tanepiper: https://gist.github.com/tanepiper/575303
- * Heavily modified.
- */
- function askPin(oa, oauth_token, oauth_token_secret, callback){
- prompt.start();
- prompt.get('token', function(err, result){
- if(err) callback(err);
- callback(null, oa, oauth_token, oauth_token_secret, result.token);
- });
- }
- function getRequestToken(callback) {
- var oauth = new OAuth(
- "https://api.twitter.com/oauth/request_token",
- "https://api.twitter.com/oauth/access_token",
- config.tokens.consumer_key,
- config.tokens.consumer_secret,
- "1.0",
- "oob",
- "HMAC-SHA1"
- );
- oauth.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){
- if(error) {
- callback([error.statusCode, error.data].join(': '));
- } else {
- var authUrl = 'https://twitter.com/oauth/authorize?oauth_token=';
- googl.shorten(authUrl + oauth_token)
- .then(function(shortUrl){
- console.log(('Access ' + shortUrl + ' on your browser and enter the token number.').underline.green);
- callback(null, oauth, oauth_token, oauth_token_secret);
- })
- .catch(function(){
- console.log('\tAccess \n' + authUrl + oauth_token + '\n\ton your browser and enter the token number.');
- callback(null, oauth, oauth_token, oauth_token_secret);
- });
- }
- });
- }
- function getAccessToken(oa, oauth_token, oauth_token_secret, pin, callback) {
- oa.getOAuthAccessToken(oauth_token, oauth_token_secret, pin,
- function(error, oauth_access_token, oauth_access_token_secret, results2) {
- if (error) {
- if (parseInt(error.statusCode) == 401) {
- callback('The pin number you have entered is incorrect');
- }
- }
- callback(null, {access_token: oauth_access_token, access_token_secret: oauth_access_token_secret});
- });
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement