Last active
April 5, 2017 19:11
-
-
Save vincekd/c0b9357487bf43102f12d293d54381b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Script to remove retweets after a certain number of days (defaults to 10) | |
* @author vincekd | |
* @copyright 2017 | |
* @license GPL v3.0 | |
* dependencies: node-twitter-api, prompt, opn | |
* usage: `node /path/to/script/remove_retweets.js [CONSUMER_KEY] [CONSUMER_SECRET] [USERNAME] [NUMBER_OF_DAYS]` | |
*/ | |
"use strict"; | |
const DEFAULT_MAX_DAYS = 10, | |
MS_PER_DAY = (1000*60*60*24), | |
CONSUMER_KEY = process.argv[2], | |
CONSUMER_SECRET = process.argv[3], | |
USERNAME = process.argv[4], | |
MAX_DAYS = (process.argv[5] ? parseInt(process.argv[5], 10) : DEFAULT_MAX_DAYS); | |
if (!CONSUMER_KEY || !CONSUMER_SECRET || !USERNAME) { | |
console.warn("No consumer key or secret or username"); | |
return; | |
} else { | |
console.log("Removing retweets older than " + MAX_DAYS + " days from user @" + USERNAME); | |
} | |
var twitterAPI = require("node-twitter-api"), | |
prompt = require("prompt"), | |
opn = require("opn"); | |
var twitter = new twitterAPI({ | |
"consumerKey": CONSUMER_KEY, | |
"consumerSecret": CONSUMER_SECRET, | |
"oauth_callback": "oob" | |
}), | |
tokens = authenticate(); | |
tokens.then(fetchTweets); | |
function fetchTweets(data, maxID) { | |
console.log("fetching tweets") | |
let params = { | |
"screen_name": "@" + USERNAME, | |
"trim_user": true, | |
"exclude_replies": true, | |
"include_entitites": false, | |
"include_rts": true, | |
"count": 200 | |
}; | |
if (typeof maxID === "number" && maxID > 0) { | |
console.log("max ID", maxID); | |
params["max_id"] = maxID; | |
} | |
twitter.getTimeline("user_timeline", params, data.accessToken, data.accessTokenSecret, function(error, tweets, response) { | |
if (error) { | |
console.warn("Error fetching tweets", error); | |
} else { | |
if (tweets.length > 0) { | |
console.log("fetched " + tweets.length + " tweets"); | |
processTweets(data, tweets); | |
} else { | |
console.log("no tweets returned"); | |
} | |
} | |
}); | |
} | |
function processTweets(data, tweets) { | |
var before = (Date.now() - (MAX_DAYS * MS_PER_DAY)), | |
lowestID = Number.POSITIVE_INFINITY, | |
retweets = tweets.filter(tweet => { | |
if (tweet.id < lowestID) { | |
lowestID = tweet.id; | |
} | |
return tweet.retweeted_status && ((new Date(tweet.created_at)).getTime() <= before); | |
}); | |
if (retweets.length > 0) { | |
prompt.start(); | |
prompt.get({ | |
"properties": { | |
"continue": { | |
"message": "Unretweet " + retweets.length + " items? (y/n)", | |
"required": true | |
} | |
} | |
}, function (err, result) { | |
if (!err && result["continue"] === "y") { | |
//console.log("removing retweets", retweets); | |
unretweet(data, retweets).then(function() { | |
console.log("unretweeted all!"); | |
if (lowestID < Number.POSITIVE_INFINITY) { | |
fetchTweets(data, lowestID); | |
} | |
}); | |
} | |
}); | |
} | |
} | |
function unretweet(data, tweets) { | |
return new Promise(function(resolve, reject) { | |
var tweet = tweets.pop(), | |
id = tweet.retweeted_status.id_str; | |
twitter.statuses("unretweet", { | |
"id": id, | |
"trim_user": true | |
}, data.accessToken, data.accessTokenSecret, function(error, orig, resp) { | |
if (error) { | |
switch (error.statusCode) { | |
case 404: | |
console.warn("tweet not found", id, error); | |
break; | |
case 429: | |
console.warn("hit update limits, please try again later", id, error); | |
reject(); | |
process.exit(1); | |
break; | |
default: | |
console.warn("error unretweeting tweet", id, error); | |
} | |
} | |
console.log("unretweeted", orig.id, new Date(orig.created_at)); | |
if (tweets.length > 0) { | |
unretweet(data, tweets).then(function() { | |
resolve(); | |
}); | |
} else { | |
resolve(); | |
} | |
}); | |
}); | |
} | |
function authenticate() { | |
return new Promise(function(resolve, reject) { | |
new Promise(function(resolve, reject) { | |
twitter.getRequestToken(function(error, requestToken, requestTokenSecret, results){ | |
if (error) { | |
console.log("Error getting OAuth request token : ", error); | |
reject(); | |
} else { | |
var url = twitter.getAuthUrl(requestToken); | |
opn(url); | |
prompt.start(); | |
prompt.get(['Pin'], function (err, result) { | |
if (err) { | |
console.warn("Error in prompt", err); | |
return; | |
} | |
resolve({ | |
"requestToken": requestToken, | |
"requestTokenSecret": requestTokenSecret, | |
"pin": result.Pin | |
}); | |
}); | |
} | |
}); | |
}).then(data => { | |
twitter.getAccessToken(data.requestToken, data.requestTokenSecret, data.pin, function(error, accessToken, accessTokenSecret, results) { | |
if (error) { | |
console.warn("Error getting access token"); | |
reject(); | |
} else { | |
data.accessToken = accessToken; | |
data.accessTokenSecret = accessTokenSecret; | |
data.accessResults = results; | |
resolve(data); | |
} | |
}); | |
}); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment