←︎ chir.py :: 010429d


1
commit 010429dae4163c7c8693ff10a572d5f2b148d736
2
Author: acidvegas <acid.vegas@acid.vegas>
3
Date:   Fri Jun 28 01:07:10 2019 -0400
4
5
    Initial commit
6
---
7
 LICENSE              |  15 +++++
8
 README.md            |  24 ++++++++
9
 chir.py/chir.py      |  22 ++++++++
10
 chir.py/config.py    |  39 +++++++++++++
11
 chir.py/debug.py     |  89 +++++++++++++++++++++++++++++
12
 chir.py/functions.py |  55 ++++++++++++++++++
13
 chir.py/twitter.py   | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++
14
 7 files changed, 399 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..2a37055
40
--- /dev/null
41
+++ b/README.md
42
@@ -0,0 +1,24 @@
43
+###### Requirments
44
+* [FeedParser](http://pypi.python.org/pypi/feedparser)
45
+* [Tweepy](http://pypi.python.org/pypi/tweepy)
46
+* [ndg-httpsclient](http://pypi.python.org/pypi/ndg-httpsclient) *(Install only if you are getting an "InsecurePlatformWarning" error.)*
47
+
48
+###### Instructions
49
+Register a Twitter account, and [sign up](http://dev.twitter.com/apps/new) for a new developer application.
50
+
51
+Go to your new application settings "Keys and Access Tokens" tab.
52
+Click the "Create Your Access Token" button on the bottom.
53
+These will be used in the config to connect to your Twitter account.
54
+Go to your new application settings "Permissions".
55
+Change your access to "Read, Write and Access direct messages".
56
+
57
+Register a [CoinURL](http://coinurl.com/) account and get your [api key](http://coinurl.com/profile-api.php).
58
+The random number you will see after "uuid" is your unique user id that will be use in the config.
59
+
60
+Edit your `config.py` and change the Twitter & CoinURL API settings.
61
+
62
+###### Mirrors
63
+- [acid.vegas](https://acid.vegas/chir.py) *(main)*
64
+- [SuperNETs](https://git.supernets.org/acidvegas/chir.py)
65
+- [GitHub](https://github.com/acidvegas/chir.py)
66
+- [GitLab](https://gitlab.com/acidvegas/chir.py)
67
diff --git a/chir.py/chir.py b/chir.py/chir.py
68
new file mode 100644
69
index 0000000..3466fc6
70
--- /dev/null
71
+++ b/chir.py/chir.py
72
@@ -0,0 +1,22 @@
73
+#!/usr/bin/env python
74
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
75
+# chir.py
76
+
77
+import sys
78
+
79
+sys.dont_write_bytecode = True
80
+
81
+import debug
82
+
83
+debug.info()
84
+if not debug.check_version(3):
85
+    debug.error_exit('Chir.py requires Python version 3 to run!')
86
+if not debug.get_windows():
87
+    if debug.check_root():
88
+        debug.error_exit('Do not run Chir.py as root!')
89
+debug.check_imports()
90
+debug.check_config()
91
+import twitter
92
+twitter.login()
93
+twitter.main_loop()
94
+debug.keep_alive()
95
diff --git a/chir.py/config.py b/chir.py/config.py
96
new file mode 100644
97
index 0000000..79027bb
98
--- /dev/null
99
+++ b/chir.py/config.py
100
@@ -0,0 +1,39 @@
101
+#!/usr/bin/env python
102
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
103
+# config.py
104
+
105
+# API Settings
106
+coinurl_uuid                = 'CHANGEME'
107
+twitter_consumer_key	    = 'CHANGEME'
108
+twitter_consumer_secret	    = 'CHANGEME'
109
+twitter_access_token	    = 'CHANGEME'
110
+twitter_access_token_secret = 'CHANGEME'
111
+
112
+# Keywords & News Sources (DO NOT EDIT)
113
+boost_keywords = ('500aday','autofollow','autofollowback','f4f','follow','follow4follow','followback','followtrain','teamfollowback','wefollowback')
114
+
115
+news_feeds = {
116
+    'baseball'   : 'https://sports.yahoo.com/mlb/rss.xml',
117
+    'basketball' : 'https://sports.yahoo.com/nba/rss.xml',
118
+    'boxing'     : 'https://sports.yahoo.com/box/rss.xml',
119
+    'football'   : 'https://sports.yahoo.com/nfl/rss.xml',
120
+    'golf'       : 'https://sports.yahoo.com/golf/rss.xml',
121
+    'hockey'     : 'https://sports.yahoo.com/nhl/rss.xml',
122
+    'mma'        : 'https://sports.yahoo.com/mma/rss.xml',
123
+    'nascar'     : 'https://sports.yahoo.com/nascar/rss.xml',
124
+    'soccer'     : 'https://sports.yahoo.com/soccer/rss.xml',
125
+    'tennis'     : 'https://sports.yahoo.com/tennis/rss.xml'
126
+}
127
+
128
+news_keywords = {
129
+    'baseball'   : ('baseball','mlb','homerun','worldseries','springtraining','angels','astros','athletics','bluejays','braves','brewers','cardinals','cubs','diamondbacks','dodgers','giants','indians','mariners','marlins','mets','nationals','orioles','padres','phillies','pirates','rangers','rays','redsox','reds','rockies','royals','tigers','twins','whitesox','yankees'),
130
+    'basketball' : ('basketball','finals','nba','76ers','blazers','bucks','bulls','cavaliers','celtics','clippers','grizzlies','hawks','heat','hornets','jazz','kings','knicks','lakers','magic','mavericks','nets','nuggets','pacers','pistons','raptors','rockets','spurs','suns','thunder','timberwolves','warriors','wizards'),
131
+    'boxing'     : ('boxing','fightnight'),
132
+    'football'   : ('football','madden','nfl','superbowl','touchdown','49ers','bears','bengals','bills','broncos','browns','bucaneers','cardinals','chargers','cheifs','colts','cowboys','dolphins','eagles','falcons','giants','jaguars','jets','lions','packers','panthers','patriots','raiders','rams','ravens','redskins','saints','seahawks','steelers','texans','titans','vikings'),
133
+    'golf'       : ('fedexcup','owgr','pga','pgachampionship','pgatour'),
134
+    'hockey'     : ('hockey','nhl','worldcup','avalanche','blackhawks','bluejackets','blues','bruins','canadiens','canucks','capitals','coyotes','devils','ducks','flames','flyers','hurricanes','islanders','jets','kings','lightning','mapleleafs','oilers','panthers','penguins','predators','rangers','redwings','sabres','senators','sharks','stars','wild'),
135
+    'mma'        : ('bellator','martialarts','mixedmartialarts','mma','ufc','wsof'),
136
+    'nascar'     : ('buschseries','campingworldtruckseries','daytona500','iracing','nascar','sprintcup','sprintseries','winstoncup','winstoncupseries','xfinityseries'),
137
+    'soccer'     : ('fifa','soccer','worldcup'),
138
+    'tennis'     : ('atp','atpworldtour','masters1000','tennis','usopen')
139
+}
140
diff --git a/chir.py/debug.py b/chir.py/debug.py
141
new file mode 100644
142
index 0000000..8670f13
143
--- /dev/null
144
+++ b/chir.py/debug.py
145
@@ -0,0 +1,89 @@
146
+#!/usr/bin/env python
147
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
148
+# debug.py
149
+
150
+import os
151
+import sys
152
+import time
153
+
154
+import config
155
+
156
+def action(msg):
157
+    print('%s | [#] - %s' % (get_time(), msg))
158
+
159
+def alert(msg):
160
+    print('%s | [+] - %s' % (get_time(), msg))
161
+
162
+def check_config():
163
+    for item in (config.coinurl_uuid, config.twitter_consumer_key, config.twitter_consumer_secret, config.twitter_access_token, config.twitter_access_token_secret):
164
+        if item == 'CHANGEME':
165
+            error_exit('Edit your config file!')
166
+
167
+def check_imports():
168
+    try:
169
+        import tweepy
170
+    except ImportError:
171
+        error_exit('Failed to import the Tweepy library! (http://pypi.python.org/pypi/tweepy)')
172
+    try:
173
+        import feedparser
174
+    except ImportError:
175
+        error_exit('Failed to import the FeedParser library! (http://pypi.python.org/pypi/feedparser)')
176
+
177
+def check_root():
178
+    if os.getuid() == 0 or os.geteuid() == 0:
179
+        return True
180
+    else:
181
+        return False
182
+
183
+def check_version(major):
184
+    if sys.version_info.major == major:
185
+        return True
186
+    else:
187
+        return False
188
+
189
+def check_windows():
190
+    if os.name == 'nt':
191
+        return True
192
+    else:
193
+        return False
194
+
195
+def clear():
196
+    if check_windows():
197
+        os.system('cls')
198
+    else:
199
+        os.system('clear')
200
+
201
+def error(msg, reason=None):
202
+    if reason:
203
+        print('%s | [!] - %s (%s)' % (get_time(), msg, str(reason)))
204
+    else:
205
+        print('%s | [!] - %s' % (get_time(), msg))
206
+
207
+def error_exit(msg):
208
+    raise SystemExit('%s | [!] - %s' % (get_time(), msg))
209
+
210
+def get_time():
211
+    return time.strftime('%I:%M:%S')
212
+
213
+def get_windows():
214
+    if os.name == 'nt':
215
+        return True
216
+    else:
217
+        return False
218
+
219
+def info():
220
+    clear()
221
+    print(''.rjust(56, '#'))
222
+    print('#' + ''.center(54) + '#')
223
+    print('#' + 'Chir.py Twitter Bot'.center(54) + '#')
224
+    print('#' + 'Developed by acidvegas in Python '.center(54) + '#')
225
+    print('#' + 'https://acid.vegas/chir.py'.center(54) + '#')
226
+    print('#' + ''.center(54) + '#')
227
+    print(''.rjust(56, '#'))
228
+
229
+def keep_alive():
230
+    try:
231
+        while True:
232
+            input('')
233
+    except KeyboardInterrupt:
234
+        sys.exit()
235
diff --git a/chir.py/functions.py b/chir.py/functions.py
236
new file mode 100644
237
index 0000000..4edf235
238
--- /dev/null
239
+++ b/chir.py/functions.py
240
@@ -0,0 +1,55 @@
241
+#!/usr/bin/env python
242
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
243
+# functions.py
244
+
245
+import random
246
+import re
247
+import urllib.request
248
+
249
+import feedparser
250
+
251
+import config
252
+import debug
253
+
254
+def coinurl(url):
255
+    source  = urllib.request.urlopen('https://coinurl.com/api.php?uuid=%s&url=%s' % (config.coinurl_uuid, url))
256
+    charset = source.headers.get_content_charset()
257
+    if charset : return source.read().decode(charset)
258
+    else       : return source.read().decode()
259
+
260
+def get_news(): # This is very sloppy and needs some work.
261
+    news_list      = list()
262
+    sport          = random.choice(list(config.news_feeds.keys()))
263
+    sport_news     = feedparser.parse(config.news_feeds[sport])
264
+    sport_keywords = config.news_keywords[sport]
265
+    for item in sport_news.entries:
266
+        description = strip_html(item.summary)
267
+        if ') -- ' in description:
268
+            cutoff      = description.split(') -- ')[0]
269
+            description = description.split(cutoff)[1]
270
+        if ') - ' in description:
271
+            cutoff      = description.split(') - ')[0]
272
+            description = description.split(cutoff)[1]
273
+        description = description.replace('*',  '')
274
+        description = description.replace('\'', '')
275
+        description = description.replace('"',  '')
276
+        description = description.replace('--', '-')
277
+        description = description.replace('  ', ' ')
278
+        for word in sport_keywords:
279
+            if word in description.lower():
280
+                description = re.sub(word, '#' + word, description, flags=re.IGNORECASE)
281
+        if len(description) > 118:
282
+            description = description[:118]
283
+            split       = description.split()
284
+            description = description.split(split[len(split)-1])[0][:-1] + '... '
285
+        try:
286
+            link = coinurl(item.link)
287
+        except Exception as ex:
288
+            debug.error('Error occured creating PPC link!', ex)
289
+        else:
290
+            description = description + ' ' + link
291
+            news_list.append(description)
292
+    return news_list
293
+
294
+def strip_html(source):
295
+    return re.compile(r'<.*?>').sub('', source)
296
diff --git a/chir.py/twitter.py b/chir.py/twitter.py
297
new file mode 100644
298
index 0000000..e5638c1
299
--- /dev/null
300
+++ b/chir.py/twitter.py
301
@@ -0,0 +1,155 @@
302
+#!/usr/bin/env python
303
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
304
+# twitter.py
305
+
306
+import random
307
+import threading
308
+import time
309
+
310
+import tweepy
311
+
312
+import config
313
+import debug
314
+import functions
315
+
316
+api = None
317
+me  = None
318
+
319
+def login():
320
+    global api, me
321
+    try:
322
+        auth = tweepy.OAuthHandler(config.consumer_key, config.consumer_secret)
323
+        auth.set_access_token(config.access_token, config.access_token_secret)
324
+        api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
325
+        me  = api.me()
326
+    except tweepy.TweepError:
327
+        debug.error_exit('Failed to login to Twitter!')
328
+
329
+def stats():
330
+    debug.action('SceenName\t: %s'  % me.screen_name)
331
+    debug.action('Registered\t: %s' % me.created_at)
332
+    debug.action('Favorites\t: %s'  % me.favourites_count)
333
+    debug.action('Following\t: %s'  % me.friends_count)
334
+    debug.action('Followers\t: %s'  % me.followers_count)
335
+    debug.action('Tweets\t\t: %s'   % me.statuses_count)
336
+
337
+class boost_loop(threading.Thread):
338
+    def __init__(self):
339
+        threading.Thread.__init__(self)
340
+    def run(self):
341
+        while True:
342
+            try:
343
+                if 'boost_tweet' in locals(): api.destroy_status(boost_tweet.id)
344
+                boost_tweet = api.update_status('Support our Twitter! #' + ' #'.join(config.boost))
345
+                debug.alert('Re-posted boost tweet.')
346
+            except tweepy.TweepError as ex:
347
+                debug.error('Error occured in the boost loop', ex)
348
+            finally:
349
+                random.shuffle(config.boost)
350
+                time.sleep(60*5)
351
+
352
+class favorite_loop(threading.Thread):
353
+    def __init__(self):
354
+        threading.Thread.__init__(self)
355
+    def run(self):
356
+        while True:
357
+            try:
358
+                for tweet in tweepy.Cursor(api.home_timeline, exclude_replies=True).items(50):
359
+                    if tweet.user.screen_name != me.screen_name:
360
+                        if not tweet.favorited:
361
+                            if random.choice([True, False, False, False, False]):
362
+                                api.create_favorite(tweet.id)
363
+                                debug.alert('Favorited a friends tweet!')
364
+                    time.sleep(30)
365
+            except tweepy.TweepError as ex:
366
+                debug.error('Error occured in the favorite loop!', ex)
367
+            finally:
368
+                time.sleep(60*15)
369
+
370
+class follow_loop(threading.Thread):
371
+    def __init__(self):
372
+        threading.Thread.__init__(self)
373
+    def run(self):
374
+        while True:
375
+            try:
376
+                followers = api.followers_ids(me.screen_name)
377
+                friends   = api.friends_ids(me.screen_name)
378
+                if me.friends_count / me.followers_count == 3:
379
+                    debug.action('Following to follower ratio is off! Starting the unfollow loop...')
380
+                    unfollow_loop()
381
+                for follower in followers:
382
+                    if not follower in friends:
383
+                        api.create_friendship(follower)
384
+                        api.send_direct_message(screen_name=follower, text='Thanks for following our Twitter. Be sure to share us with your friends & keep up with the latest sports news!')
385
+                        debug.alert('Followed back a follower!')
386
+                    time.sleep(30)
387
+            except tweepy.TweepError as ex:
388
+                debug.error('Error occured in the follow loop!', ex)
389
+            finally:
390
+                time.sleep(60*15)
391
+
392
+def main_loop():
393
+    boost_loop().start()
394
+    favorite_loop().start()
395
+    follow_loop().start()
396
+    news_loop().start()
397
+    search_loop().start()
398
+
399
+class news_loop(threading.Thread):
400
+    def __init__(self):
401
+        threading.Thread.__init__(self)
402
+    def run(self):
403
+        while True:
404
+            try:
405
+                news   = functions.get_news()
406
+                tweets = list()
407
+                for item in tweepy.Cursor(api.user_timeline, exclude_replies=True).items(50):
408
+                    tweets.append(item.text.split('... ')[0])
409
+                    time.sleep(2)
410
+                for item in news:
411
+                    split = item.split('... ')[0]
412
+                    if split not in tweets:
413
+                        api.update_status(item)
414
+                        debug.alert('A tweet has been posted.')
415
+                    time.sleep(60*5)
416
+            except tweepy.TweepError as ex:
417
+                debug.error('Error occured in the news loop', ex)
418
+            finally:
419
+                time.sleep(60*15)
420
+
421
+class search_loop(threading.Thread):
422
+    def __init__(self):
423
+        threading.Thread.__init__(self)
424
+    def run(self):
425
+        query_keywords = list()
426
+        for item in config.news_keywords:
427
+            query_keywords = query_keywords + list(config.news_keywords[item])
428
+        query_keywords = query_keywords + config.boost_keywords
429
+        while True:
430
+            try:
431
+                query = random.choice(query_keywords)
432
+                for item in api.search(q='#' + query, count=50, lang='en', result_type='mixed'):
433
+                    if not item.user.following and not item.favorited:
434
+                        try:
435
+                            api.create_favorite(item.id)
436
+                            api.create_friendship(item.user.screen_name)
437
+                            debug.alert('Followed a similar twitter!')
438
+                        except tweepy.TweepError as ex:
439
+                            debug.error('Unknown error occured in the search loop!', ex)
440
+                    time.sleep(30)
441
+            except tweepy.TweepError as ex:
442
+                debug.error('Error occured in the search loop!', ex)
443
+            finally:
444
+                time.sleep(60*15)
445
+
446
+def unfollow_loop():
447
+    try:
448
+        followers = api.followers_ids(me.screen_name)
449
+        friends   = api.friends_ids(me.screen_name)
450
+        for friend in friends:
451
+            if friend not in followers:
452
+                api.destroy_friendship(friend)
453
+                debug.alert('Unfollowed an unsupporting friend!')
454
+                time.sleep(30)
455
+    except tweepy.TweepError as ex:
456
+        debug.error('Error occured in the unfollow loop!', ex)