1 | commit 624276b81844714a8fde292489b879b4aa7da91b |
2 | Author: acidvegas <acid.vegas@acid.vegas> |
3 | Date: Thu Jun 27 23:41:18 2019 -0400 |
4 | |
5 | Initial commit |
6 | --- |
7 | LICENSE | 15 +++++ |
8 | README.md | 23 +++++++ |
9 | booster/booster.py | 20 ++++++ |
10 | booster/config.py | 26 ++++++++ |
11 | booster/debug.py | 93 ++++++++++++++++++++++++++++ |
12 | booster/functions.py | 23 +++++++ |
13 | booster/twitter.py | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ |
14 | 7 files changed, 368 insertions(+) |
15 | |
16 | diff --git a/LICENSE b/LICENSE |
17 | new file mode 100644 |
18 | index 0000000..69997e8 |
19 | --- /dev/null |
20 | +++ b/LICENSE |
21 | @@ -0,0 +1,15 @@ |
22 | +ISC License |
23 | + |
24 | +Copyright (c) 2019, acidvegas <acid.vegas@acid.vegas> |
25 | + |
26 | +Permission to use, copy, modify, and/or distribute this software for any |
27 | +purpose with or without fee is hereby granted, provided that the above |
28 | +copyright notice and this permission notice appear in all copies. |
29 | + |
30 | +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
31 | +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
32 | +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
33 | +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
34 | +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
35 | +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
36 | +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
37 | diff --git a/README.md b/README.md |
38 | new file mode 100644 |
39 | index 0000000..2a46e03 |
40 | --- /dev/null |
41 | +++ b/README.md |
42 | @@ -0,0 +1,23 @@ |
43 | +###### Requirments |
44 | +* [Tweepy](http://pypi.python.org/pypi/tweepy) |
45 | + |
46 | +###### Instructions |
47 | +Register a Twitter account, and [sign up](http://dev.twitter.com/apps/new) for a new developer application. |
48 | + |
49 | +Go to your new application settings "Keys and Access Tokens" tab. |
50 | + |
51 | +Click the "Create Your Access Token" button on the bottom. |
52 | + |
53 | +These will be used in the config to connect to your Twitter account. |
54 | + |
55 | +Go to your new application settings "Permissions". |
56 | + |
57 | +Change your access to "Read, Write and Access direct messages". |
58 | + |
59 | +Edit your `config.py` and change the Twitter API settings. |
60 | + |
61 | +###### Mirrors |
62 | +- [acid.vegas](https://acid.vegas/booster) *(main)* |
63 | +- [SuperNETs](https://git.supernets.org/acidvegas/booster) |
64 | +- [GitHub](https://github.com/acidvegas/booster) |
65 | +- [GitLab](https://gitlab.com/acidvegas/booster) |
66 | diff --git a/booster/booster.py b/booster/booster.py |
67 | new file mode 100644 |
68 | index 0000000..d28b7d2 |
69 | --- /dev/null |
70 | +++ b/booster/booster.py |
71 | @@ -0,0 +1,20 @@ |
72 | +#!/usr/bin/env python |
73 | +# Booster Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/booster) |
74 | +# booster.py |
75 | + |
76 | +import sys |
77 | + |
78 | +sys.dont_write_bytecode = True |
79 | + |
80 | +import debug |
81 | + |
82 | +debug.info() |
83 | +if not debug.check_version(3): |
84 | + debug.error_exit('Requires Python version 3 to run!') |
85 | +if debug.check_privileges(): |
86 | + debug.error_exit('Do not run as admin/root!') |
87 | +debug.check_imports() |
88 | +debug.check_config() |
89 | +import twitter |
90 | +twitter.Booster().run() |
91 | +debug.keep_alive() |
92 | diff --git a/booster/config.py b/booster/config.py |
93 | new file mode 100644 |
94 | index 0000000..0a9a261 |
95 | --- /dev/null |
96 | +++ b/booster/config.py |
97 | @@ -0,0 +1,26 @@ |
98 | +#!/usr/bin/env python |
99 | +# Booster Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/booster) |
100 | +# config.py |
101 | + |
102 | +# API Settings |
103 | +consumer_key = 'CHANGEME' |
104 | +consumer_secret = 'CHANGEME' |
105 | +access_token = 'CHANGEME' |
106 | +access_token_secret = 'CHANGEME' |
107 | + |
108 | +# Boost Keywords |
109 | +boost_keywords = ['500aday','autofollow','autofollowback','f4f','follow','follow4follow','followback','followtrain','instantfollow','instantfollowback','teamfollowback','wefollowback'] |
110 | + |
111 | +# Throttling |
112 | +max_favorites = 75 # Only use up to 100 to avoid suspension. |
113 | +max_follows = 75 # Only use up to 100 to avoid suspension. |
114 | +max_messages = 750 # Only use up to 1000 to avoid suspension. |
115 | +max_tweets = 750 # Only use up to 1000 to avoid suspension. |
116 | +max_unfollows = 75 # Only use up to 100 to avoid suspension. |
117 | + |
118 | +# Messaging |
119 | +send_message = False # Send a message to anyone who follows you. |
120 | +message = 'Thank you for following our Twitter account!' |
121 | + |
122 | +# Where On Earth ID's (http://www.woeidlookup.com/) |
123 | +woeid = 23424975 # United States |
124 | diff --git a/booster/debug.py b/booster/debug.py |
125 | new file mode 100644 |
126 | index 0000000..904f181 |
127 | --- /dev/null |
128 | +++ b/booster/debug.py |
129 | @@ -0,0 +1,93 @@ |
130 | +#!/usr/bin/env python |
131 | +# Booster Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/booster) |
132 | +# debug.py |
133 | + |
134 | +import ctypes |
135 | +import os |
136 | +import sys |
137 | +import time |
138 | + |
139 | +import config |
140 | + |
141 | +def action(msg): |
142 | + print('%s | [#] - %s' % (get_time(), msg)) |
143 | + |
144 | +def alert(msg): |
145 | + print('%s | [+] - %s' % (get_time(), msg)) |
146 | + |
147 | +def check_config(): |
148 | + for item in (config.consumer_key, config.consumer_secret, config.access_token, config.access_token_secret): |
149 | + if item == 'CHANGEME': |
150 | + error_exit('Edit your config file!') |
151 | + |
152 | +def check_imports(): |
153 | + try: |
154 | + import tweepy |
155 | + except ImportError: |
156 | + error_exit('Failed to import the Tweepy library! (http://pypi.python.org/pypi/tweepy)') |
157 | + |
158 | +def check_privileges(): |
159 | + if check_windows(): |
160 | + if ctypes.windll.shell32.IsUserAnAdmin() != 0: |
161 | + return True |
162 | + else: |
163 | + return False |
164 | + else: |
165 | + if os.getuid() == 0 or os.geteuid() == 0: |
166 | + return True |
167 | + else: |
168 | + return False |
169 | + |
170 | +def check_version(major): |
171 | + if sys.version_info.major == major: |
172 | + return True |
173 | + else: |
174 | + return False |
175 | + |
176 | +def check_windows(): |
177 | + if os.name == 'nt': |
178 | + return True |
179 | + else: |
180 | + return False |
181 | + |
182 | +def clear(): |
183 | + if check_windows(): |
184 | + os.system('cls') |
185 | + else: |
186 | + os.system('clear') |
187 | + |
188 | +def error(msg, reason=None): |
189 | + if reason: |
190 | + print('%s | [!] - %s (%s)' % (get_time(), msg, str(reason))) |
191 | + else: |
192 | + print('%s | [!] - %s' % (get_time(), msg)) |
193 | + |
194 | +def error_exit(msg): |
195 | + raise SystemExit('%s | [!] - %s' % (get_time(), msg)) |
196 | + |
197 | +def get_time(): |
198 | + return time.strftime('%I:%M:%S') |
199 | + |
200 | +def get_windows(): |
201 | + if os.name == 'nt': |
202 | + return True |
203 | + else: |
204 | + return False |
205 | + |
206 | +def info(): |
207 | + clear() |
208 | + print(''.rjust(56, '#')) |
209 | + print('#{0}#'.format(''.center(54))) |
210 | + print('#{0}#'.format('Booster Twitter Bot'.center(54))) |
211 | + print('#{0}#'.format('Developed by acidvegas in Python 3'.center(54))) |
212 | + print('#{0}#'.format('https://acid.vegas/booster'.center(54))) |
213 | + print('#{0}#'.format(''.center(54))) |
214 | + print(''.rjust(56, '#')) |
215 | + |
216 | + |
217 | +def keep_alive(): |
218 | + try: |
219 | + while True: |
220 | + input('') |
221 | + except KeyboardInterrupt: |
222 | + sys.exit() |
223 | diff --git a/booster/functions.py b/booster/functions.py |
224 | new file mode 100644 |
225 | index 0000000..956cb06 |
226 | --- /dev/null |
227 | +++ b/booster/functions.py |
228 | @@ -0,0 +1,23 @@ |
229 | +#!/usr/bin/env python |
230 | +# Booster Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/booster) |
231 | +# functions.py |
232 | + |
233 | +import datetime |
234 | +import random |
235 | +import urllib.request |
236 | + |
237 | +def get_day(): |
238 | + return datetime.datetime.today().weekday() |
239 | + |
240 | +def get_source(url): |
241 | + req = urllib.request.Request(url) |
242 | + req.add_header('User-Agent', 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)') |
243 | + source = urllib.request.urlopen(req, timeout=10) |
244 | + charset = source.headers.get_content_charset() |
245 | + if charset: |
246 | + return source.read().decode(charset) |
247 | + else: |
248 | + return source.read().decode() |
249 | + |
250 | +def random_int(min, max): |
251 | + return random.randint(min, max) |
252 | diff --git a/booster/twitter.py b/booster/twitter.py |
253 | new file mode 100644 |
254 | index 0000000..e2ba905 |
255 | --- /dev/null |
256 | +++ b/booster/twitter.py |
257 | @@ -0,0 +1,168 @@ |
258 | +#!/usr/bin/env python |
259 | +# Booster Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/booster) |
260 | +# twitter.py |
261 | + |
262 | +import random |
263 | +import threading |
264 | +import time |
265 | + |
266 | +import tweepy |
267 | + |
268 | +import config |
269 | +import debug |
270 | +import functions |
271 | + |
272 | +class Booster(object): |
273 | + def __init__(self): |
274 | + self.api = None |
275 | + self.me = None |
276 | + self.favorites = 0 |
277 | + self.max_favorites = config.max_favorites |
278 | + self.follows = 0 |
279 | + self.max_follows = config.max_follows |
280 | + self.messages = 0 |
281 | + self.max_messages = config.max_messages |
282 | + self.tweets = 0 |
283 | + self.max_tweets = config.max_tweets |
284 | + self.unfollows = 0 |
285 | + self.max_unfollows = config.max_unfollows |
286 | + self.send_message = config.send_message |
287 | + self.message = config.message |
288 | + |
289 | + def run(self): |
290 | + self.login() |
291 | + threading.Thread(target=self.loop_boost).start() |
292 | + threading.Thread(target=self.loop_favorite).start() |
293 | + threading.Thread(target=self.loop_follow).start() |
294 | + threading.Thread(target=self.loop_search).start() |
295 | +# threading.Thread(target=self.loop_trend).start() |
296 | + |
297 | + def login(self): |
298 | + try: |
299 | + auth = tweepy.OAuthHandler(config.consumer_key, config.consumer_secret) |
300 | + auth.set_access_token(config.access_token, config.access_token_secret) |
301 | + self.api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True) |
302 | + self.me = self.api.me() |
303 | + except tweepy.TweepError as ex: |
304 | + debug.error_exit('Failed to login to Twitter! ({0})'.format(str(ex))) |
305 | + |
306 | + def loop_boost(self): |
307 | + while True: |
308 | + try: |
309 | + if 'boost_tweet' in locals(): self.api.destroy_status(boost_tweet.id) |
310 | + boost_tweet = self.api.update_status('RT for followers! #' + ' #'.join(config.boost_keywords)) |
311 | + self.tweets += 1 |
312 | + debug.alert('Re-posted boost tweet.') |
313 | + except tweepy.TweepError as ex: |
314 | + debug.error('Error occured in the boost loop', ex) |
315 | + finally: |
316 | + random.shuffle(config.boost_keywords) |
317 | + time.sleep(60*5) |
318 | + |
319 | + def loop_favorite(self): |
320 | + while True: |
321 | + try: |
322 | + for tweet in tweepy.Cursor(api.home_timeline, exclude_replies=True).items(50): |
323 | + if tweet.user.screen_name != me.screen_name: |
324 | + if not tweet.favorited: |
325 | + if random.choice((True, False, False, False, False)): |
326 | + api.create_favorite(tweet.id) |
327 | + self.favorites += 1 |
328 | + debug.alert('Favorited a friends tweet!') |
329 | + time.sleep(30) |
330 | + except tweepy.TweepError as ex: |
331 | + debug.error('Error occured in the favorite loop!', ex) |
332 | + finally: |
333 | + time.sleep(60*15) |
334 | + |
335 | + def loop_follow(self): |
336 | + while True: |
337 | + try: |
338 | + followers = api.followers_ids(me.screen_name) |
339 | + friends = api.friends_ids(me.screen_name) |
340 | + non_friends = [friend for friend in followers if friend not in friends] |
341 | + debug.action('Following back {0} supporters...'.format(len(non_friends))) |
342 | + for follower in non_friends: |
343 | + api.create_friendship(follower) |
344 | + self.follows += 1 |
345 | + debug.alert('Followed back a follower!') |
346 | + if self.follows >= self.max_follows: |
347 | + break |
348 | + if self.send_message: |
349 | + api.send_direct_message(screen_name=follower, text=self.message) |
350 | + time.sleep(30) |
351 | + except tweepy.TweepError as ex: |
352 | + debug.error('Error occured in the follow loop!', ex) |
353 | + finally: |
354 | + time.sleep(60*15) |
355 | + |
356 | + def loop_search(self): |
357 | + while True: |
358 | + try: |
359 | + query = random.choice(config.boost_keywords) |
360 | + for item in api.search(q='#' + query, count=50, lang='en', result_type='recent'): |
361 | + if not item.user.following and not item.favorited: |
362 | + try: |
363 | + api.create_favorite(item.id) |
364 | + api.create_friendship(item.user.screen_name) |
365 | + self.favorites += 1 |
366 | + self.follows += 1 |
367 | + debug.alert('Followed a booster twitter!') |
368 | + except tweepy.TweepError as ex: |
369 | + debug.error('Unknown error occured in the search loop!', ex) |
370 | + time.sleep(30) |
371 | + except tweepy.TweepError as ex: |
372 | + debug.error('Error occured in the search loop!', ex) |
373 | + finally: |
374 | + time.sleep(60*15) |
375 | + |
376 | + def loop_trend(self): |
377 | + while True: |
378 | + try: |
379 | + trends = self.api.trends_place(str(config.woeid)) |
380 | + hashtags = [x['name'] for x in trends[0]['trends'] if x['name'].startswith('#')] |
381 | + for trend in hashtags: |
382 | + for item in self.api.search(q=trend, count=5, lang='en', result_type='top'): |
383 | + #self.api.update_status(item.tweet) # FIX THIS PART |
384 | + time.sleep(30) |
385 | + except tweepy.TweepError as ex: |
386 | + debug.error('Error occured in the trend loop!', ex) |
387 | + finally: |
388 | + time.sleep(60*15) |
389 | + |
390 | + def loop_unfollow(self): |
391 | + try: |
392 | + followers = self.api.followers_ids(self.me.screen_name) |
393 | + friends = self.api.friends_ids(self.me.screen_name) |
394 | + non_friends = [friend for friend in friends if friend not in followers] |
395 | + non_friends.reverse() |
396 | + debug.action('Unfollowing {0} unsupporting friends...'.format(len(non_friends))) |
397 | + for friend in non_friends: |
398 | + self.api.destroy_friendship(friend) |
399 | + self.unfollows += 1 |
400 | + debug.alert('Unfollowed an unsupporting friend!') |
401 | + if self.unfollows == self.max_unfollows: |
402 | + break |
403 | + else: |
404 | + time.sleep(60*functions.random_int(10,15)) |
405 | + except tweepy.TweepError as ex: |
406 | + debug.error('Error occured in the unfollow loop!', ex) |
407 | + finally: |
408 | + self.unfollows = 0 |
409 | + |
410 | + def ratio_check(self): |
411 | + if self.follows >= max_follows: |
412 | + time.sleep(86400) |
413 | + if me.friends_count >= 2000: |
414 | + ratio = me.friends_count + (me.followers_count/10) |
415 | + if me.friends_count >= ratio: |
416 | + debug.action('Following to follower ratio is off! Starting the unfollow loop...') |
417 | + unfollow_loop() |
418 | + |
419 | + def stats(self): |
420 | + debug.action('SceenName : ' + self.me.screen_name) |
421 | + debug.action('Registered : ' + self.me.created_at) |
422 | + debug.action('Favorites : ' + self.me.favourites_count) |
423 | + debug.action('Following : ' + self.me.friends_count) |
424 | + debug.action('Followers : ' + self.me.followers_count) |
425 | + debug.action('Tweets : ' + self.me.statuses_count) |