Skip to content

Instantly share code, notes, and snippets.

@vincekd
Last active April 5, 2017 19:11
Show Gist options
  • Save vincekd/c0b9357487bf43102f12d293d54381b4 to your computer and use it in GitHub Desktop.
Save vincekd/c0b9357487bf43102f12d293d54381b4 to your computer and use it in GitHub Desktop.
/*
* 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