forked from 0xGrimnir/Simple-Retweet-Bot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathretweet.py
196 lines (178 loc) · 10.2 KB
/
retweet.py
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# DezNat Retweet bot for Twitter, using Python and Tweepy.
# by bobdaduck, modifying "simple retweet bot"'s source on github.Author: Tyler L. Jones || CyberVox
# Resources: https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/tweet-object
# http://docs.tweepy.org/en/latest/api.html?highlight=search
import tweepy #let python handle the twitter api stuff
import datetime
import fileinput
from time import sleep
from keys import *
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth, wait_on_rate_limit=True) # "api" variable now calls whatever twitter api you give it, like on line 17
seconds_between_retweets = 5
minimum_account_age = 7 #in days
minimum_account_follower = 40 #in followers
#metrics
authorsToday= []
uniqueAuthors = 0
uniqueTweets = 0
timesLooped = 0
blockedAttempts = 0
mutedReplies = 0
repliesToTrolls = 0
sessionDate = str(datetime.datetime.now())
def incremintMetrics(tweet):
global uniqueAuthors
global uniqueTweets
if(tweet.user.screen_name not in authorsToday):
authorsToday.append(tweet.user.screen_name)
uniqueAuthors += 1
uniqueTweets += 1
def isGreenFlaggedAccount(tweet):
#accounts we follow get retweeted even if they're low clout
if(tweet.user.id in following_list):
return True
else:
return False
def containsRedFlagWords(tweet):
fullText = str(api.get_status(tweet.id, tweet_mode="extended").full_text).lower()
if('#exmormon' in fullText or '#exmo' in fullText or ' mormons' in fullText or 'deznats' in fullText or 'nuts' in fullText or 'deez' in fullText or 'a mormon' in fullText or 'blocked me' in fullText or ' crowd' in fullText or 'exposedeznat' in fullText):
global blockedAttempts
blockedAttempts = blockedAttempts + 1
return True
else:
return False
def containsYellowFlagWords(tweet): #fine but spammy
fullText = str(api.get_status(tweet.id, tweet_mode="extended").full_text).lower()
if("#iglesiadejesucristo" in fullText):
return True
elif('#nacdes' in fullText):
return True
elif('#escúchalo' in fullText):
return True
elif(fullText.count('#') > 6):
return True
else:
return False
def containsRedFlagBio(tweet):
bio = tweet.user.description.lower()
if("utes" in bio or "jazz" in bio or "takenote" in bio or "exmo" in bio or "he/him" in bio or "she/her" in bio or "they/them" in bio or "feminist" in bio or "queer" in bio or " ally" in bio or "onlyfans" in bio or "blm" in bio or "antifa" in bio or "acab" in bio):
return True
def isNotAThread(tweet):
replyTo = tweet.in_reply_to_status_id
replyText = ""
if(replyTo is not None):#don't retweet every hashtag in a 50 tweet thread where all have the hashtag
replyText = str(api.get_status(replyTo, tweet_mode="extended").full_text).lower() #"extended" gets full text rather than 40 chars of each tweet
if('#deznat' in replyText):
#print("above tweet already tagged #DezNat, skipping @" + tweet.user.screen_name + "'s tweet: " + str(tweet.id))
#print(replyText + "\n")
return False
return True
def blockedAccountsInReplies(tweet):
replyTo = tweet.in_reply_to_status_id
if(replyTo is not None):#don't retweet every hashtag in a 50 tweet thread where all have the hashtag
if(hasattr(replyTo, 'in_reply_to_user_id')):
if(replyTo.in_reply_to_user_id in blocked_users or replyTo.in_reply_to_user_id in muted_users):
return True
else:
if(blockedAccountsInReplies(replyTo)): #this calls itself recursively until there's no reply above (which would return false)
return True
return False
def meetsRetweetConditions(tweet): #filter out trolls
if tweet.user.id in blocked_users:
return False
if tweet.user.id in muted_users:
return False
if(blockedAccountsInReplies(tweet)):
print(tweet.user.screen_name + " is replying to a troll, skipping. tweet ID: " + str(tweet.id) + "\n")
return False
if(not isGreenFlaggedAccount(tweet)):
account_age = datetime.datetime.now() - tweet.user.created_at
if account_age.days < minimum_account_age: #less than a week old
print("~~~~~~~@" + tweet.user.screen_name + "\a new or low-clout. Evaluate and RT manually. Tweet ID (to paste): " + str(tweet.id))
print(tweet.text+ "\n") #/n just means newline
incremintMetrics(tweet)
return False
if tweet.user.followers_count < minimum_account_follower: #fewer than 40 followers
print("~~~~~~~@" + tweet.user.screen_name + "\a new or low-clout. Evaluate and RT manually. Tweet ID (to paste): " + str(tweet.id))
print(tweet.text + "\n")
incremintMetrics(tweet)
return False
if(containsRedFlagWords(tweet)):
print("~~~~~~~ @" + tweet.user.screen_name + "\a using red flag language. Tweet ID (to paste): " + str(tweet.id) + " ~~~~~")
return False
if(containsYellowFlagWords(tweet)):
print("~~~~~~~ @" + tweet.user.screen_name + "\a using yellow flag language. Tweet ID (to paste): " + str(tweet.id) + " ~~~~~")
incremintMetrics(tweet)
return False
if(containsRedFlagBio(tweet)):
print("~~~~~~~ @" + tweet.user.screen_name + "\a otherwise fine but has red flags in Bio: Tweet ID (to paste): " + str(tweet.id) + " ~~~~~")
global mutedReplies
mutedReplies += 1
return False
return True
def EvaluateAndRetweet(tweet):
if(tweet.id not in searched_store): #save CPU time if we already saw this since last time we started the bot
searched_store.append(tweet.id)
if(tweet.in_reply_to_user_id not in blocked_users and tweet.in_reply_to_user_id not in muted_users): #don't drag us into your nonsense
if(hasattr(tweet, "retweeted_status") == False): #tweet is an original tweet
#print("new tweet found by " + tweet.user.screen_name + ", tweet ID: " + str(tweet.id))
#print("has attribute retweeted status: " + str(hasattr(tweet, "retweeted_status")))
if(meetsRetweetConditions(tweet) and isNotAThread(tweet)): #Not blocked, new, or low-clout
tweet.retweet() #if its already retweeted, this gives 327 error and moves on
print('retweeted tweet by @' + tweet.user.screen_name + '. Tweet ID: ' + str(tweet.id))
print(tweet.text + "\n")
incremintMetrics(tweet)
sleep(seconds_between_retweets) #halt bot process for 10 seconds
elif(isGreenFlaggedAccount(tweet) and isNotAThread(tweet)):
tweet.retweet() #if its already retweeted, this gives 327 error and moves on
print("\n- - - - @" + tweet.user.screen_name + " is a low follower account we've greenflagged- - - -")
print('retweeted tweet by @' + tweet.user.screen_name + '. Tweet ID: ' + str(tweet.id))
print(tweet.text + "\n")
incremintMetrics(tweet)
sleep(seconds_between_retweets) #halt bot process for 10 seconds
elif(tweet.user.id in muted_users):
global mutedReplies
mutedReplies = mutedReplies + 1
print("!!!!!!!!!!!!! " + tweet.user.screen_name + "\a is muted. Consider blocking or unmuting. tweet ID: " + str(tweet.id) + " !!!!!!!!\n")
elif(tweet.user.id in blocked_users):
global blockedAttempts
blockedAttempts = blockedAttempts + 1
#print(tweet.user.screen_name + " is blocked")
elif(tweet.user.id not in blocked_users and tweet.user.id not in muted_users):
global repliesToTrolls
repliesToTrolls = repliesToTrolls + 1
#print(tweet.user.screen_name + " is replying to a troll, skipping. tweet ID: " + str(tweet.id) + "\n") #/n just means newline
pass #print(str(tweet.user.screen_name) + " FOUND ON BLOCK LIST, IGNORE HIM")
following_list = []
searched_store = [] #cut down on log printing after first iteration by memorizing what we've retweeted
f = open("trends.csv", "a") #set newline on file up before the loop runs
f.write("\n" + sessionDate + " || authors: " + str(uniqueAuthors) + ", total retweets: " + str(uniqueTweets))
f.close()
while True: #run infinitely until aborted
blocked_users = api.blocks_ids()
muted_users = api.mutes_ids()
following_list = api.friends_ids()
for tweet in tweepy.Cursor(api.search, q='#DezNat OR #deznat OR #Deznat', count=100).items(100): #q= search query, items = max items to try
try:
EvaluateAndRetweet(tweet)
except tweepy.TweepError as error:
errCode = error.api_code
if(errCode == 327): #327 = already retweeted. #503 = server down
pass
elif(errCode == 136):
print(tweet.user.screen_name + " has blocked us, consider blocking back to cut down on these messages (ID:) " + str(tweet.id))
#this part also is triggered if the reply tweet is blocked, idk
else:
print(error.api_code)
print('\n%%%%%%%Error. Retweet for @' + tweet.user.screen_name + ' failed: ' + error.reason)
print('tweet ID: ' + str(tweet.id))
except StopIteration:
break
print("loop finished, waiting to retry. Since startup, " + str(uniqueAuthors) + " unique authors and " + str(uniqueTweets) + " retweets")
lines = open('trends.csv').read().splitlines()
lines[-1] = sessionDate + ", " + str(uniqueAuthors) + ", " + str(uniqueTweets)+ ", " + str(timesLooped) + ", " + str(blockedAttempts) + ", " + str(repliesToTrolls) + ", " + str(mutedReplies)
open('trends.csv','w').write('\n'.join(lines))
timesLooped = timesLooped + 1
sleep(120) #halt bot process for X seconds