Skip to content

Instantly share code, notes, and snippets.

@kyle-ssg
Created February 16, 2018 10:30
Show Gist options
  • Save kyle-ssg/ddcc0255d5dd66ce572394042282c87d to your computer and use it in GitHub Desktop.
Save kyle-ssg/ddcc0255d5dd66ce572394042282c87d to your computer and use it in GitHub Desktop.
Node Twitter List Follower
const admin = require("firebase-admin");
const Twit = require('twit')
const serviceAccount = require("./firebase-service-account.json");
const config = require('../config').twitter;
const T = new Twit(config)
const _ = require('lodash');
const SIMULATE = false;
console.log(JSON.stringify(config, null, 2))
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://chorus-ac2f0.firebaseio.com"
});
const db = admin.database();
const listsRef = db.ref("lists")
const listProcessingRef = db.ref("lists-processing")
const listProcessed = db.ref("lists-processed")
const listErrorsRef = db.ref("lists-errors")
const errorLogRef = db.ref("error-log")
const membersRef = db.ref("members")
const followingRef = db.ref("follow-processed")
const followingErrorRef = db.ref("follow-error")
//1 - turn a list into members
const processList = function (screen_name, slug) {
console.log("Processing", screen_name, slug);
return new Promise((resolve, reject)=> {
T.get('users/lookup', {screen_name: screen_name}, function (err, data, response) {
var users = [];
if (err || !data || !data[0]) {
reject({error: err || data, screen_name, slug})
return
}
var getSubscribers = (cursor)=> {
T.get('lists/members', {
cursor,
slug: slug,
skip_status: true,
owner_id: data[0].id_str,
slug
}, function (err, data, response) {
if (err || !data) {
reject({error: err || data, screen_name, slug});
}
else {
_.each(data.users, (user)=> {
membersRef.child(user.id_str).set(Object.assign({}, {
id_str: user.id_str,
name: user.name,
screen_name: user.screen_name,
description: user.description,
location: user.location
}, {list: `${screen_name}/${slug}`}))
})
if (!data.next_cursor) {
return resolve(data.users)
} else {
getSubscribers(data.next_cursor);
}
}
})
}
getSubscribers();
})
});
};
listProcessingRef.on('child_added', (snap)=> {
const bits = snap.val().split("/");
processList(bits[0].replace("@", ""), bits[1])
.then((res)=> {
listProcessingRef.child(snap.key).remove()
listProcessed.push(snap.val())
})
.catch((e)=> {
listProcessingRef.child(snap.key).remove()
errorLogRef.push(e);
listErrorsRef.push(snap.val())
})
});
listsRef.on('child_added', (snap)=> {
if (snap.key != "add list paths here") {
listsRef.child(snap.key).remove();
listProcessingRef.push(snap.val());
}
});
listProcessingRef.on('child_added', (snap)=> {
console.log(snap.val())
});
let membersList = {};
membersRef.on('child_added', (snap)=> {
const userId = snap.key;
membersList[userId] = snap.val();
});
setInterval(()=> {
const keys = Object.keys(membersList);
if (keys.length) {
const key = keys[0];
delete membersList[key];
const user = Object.assign({}, membersList[key]);
if (SIMULATE) {
console.log("Followed", key);
followingRef.child(key).set("true");
membersRef.child(key).remove();
} else {
T.post('friendships/create', {user_id: key, follow: true}, function (err, data, response) {
if (err) {
console.log("Error following", key);
followingErrorRef.child(key).set(err);
} else {
console.log("Followed", key);
followingRef.child(key).set("true");
}
membersRef.child(key).remove();
})
}
}
}, 1000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment