-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
141 lines (125 loc) · 4.63 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"use strict";
const unirest = require('unirest');
const Promise = require('bluebird');
const Twit = require('twit');
const botometer = function(config) {
// twitter api credentials
const T = new Twit({
consumer_key: config.consumer_key,
consumer_secret: config.consumer_secret,
access_token: config.access_token,
access_token_secret: config.access_token_secret,
app_only_auth: config.app_only_auth
});
// botometer api credentials
const mashape_key = config.mashape_key;
// delay for twitter API calls
const rate_limit = config.rate_limit || 0;
// whether to console log names as they're collected
const log_progress = config.log_progress || true;
// whether to include user data in output
const include_user = config.include_user || true;
// whether to include timeline data in output
const include_timeline = config.include_timeline || false;
// whether to include mentions data in output
const include_mentions = config.include_mentions || false;
// all logging here
const writeLog = function(message) {
if (log_progress) console.log(message);
}
// search with multiple endpoints
this.searchTwitter = function(ep,opts) {
return new Promise((resolve, reject) => {
setTimeout(() => {
T.get(ep,opts,function(e,data,r) {
if (e || r.statusCode !== 200) reject(new Error(e));
data = (ep == 'search/tweets') ? data.statuses : data;
resolve(data);
});
},rate_limit);
});
}
// get botometer score
this.getBotometer = function(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
unirest.post("https://osome-botometer.p.mashape.com/2/check_account")
.header("X-Mashape-Key", mashape_key)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.send(data)
.end(function (result) {
// writeLog(result.status, result.headers, result.body);
resolve(result.body);
});
},rate_limit);
});
}
// returns a user object, their latest tweets and mentions, and bot score
this.getBotScore = function(screen_name) {
const data = {user:null,timeline:null,mentions:null};
return new Promise((resolve, reject) => {
// get this user's timeline - latest 200 tweets
this.searchTwitter('statuses/user_timeline',{screen_name:screen_name,count:200})
.catch(e => {
// if error collecting timeline resolve with null
resolve(null);
})
.then(timeline => {
// save user and timeline data
data.user = timeline[0].user;
data.timeline = timeline;
// get latest 100 mentions of this user by search screen name
return this.searchTwitter('search/tweets',{q:"@"+screen_name,count:100})
})
.catch(e => {
// if error finding mentions move on with empty array
// because having zero mentions is meaningful
return [];
})
.then(mentions => {
// save mentions
data.mentions = mentions;
// get botometer scores
return this.getBotometer(data);
})
.catch(e => {
// if error on botometer resolve with null
resolve(null);
})
.then(botometer => {
// since we already save full user object,
// overwrite botometer user prop to keep basic user data
if(data.user && data.user.hasOwnProperty('screen_name') && data.user.hasOwnProperty('user_id')){
botometer.user = {
screen_name: data.user.screen_name,
user_id: data.user.user_id
}
}
// save botometer scores to data
data.botometer = botometer;
// delete any data not requested in config and resolve
if (!include_user && data.hasOwnProperty("user")) delete data.user;
if (!include_timeline && data.hasOwnProperty("timeline")) delete data.timeline;
if (!include_mentions && data.hasOwnProperty("mentions")) delete data.mentions;
resolve(data);
});
});
}
// takes like six seconds per account to complete
this.getBatchBotScores = async function(names,cb) {
const scores = [];
for (let name of names) {
writeLog("Awaiting score for "+name);
const data = await this.getBotScore(name);
if (data && typeof data.botometer.scores !== "undefined") {
scores.push(data);
writeLog(name+" is a "+data.botometer.scores.universal);
} else {
writeLog("No score found for "+name);
}
}
cb(scores);
}
}
module.exports = botometer;