🢀 chir.py :: 010429d


commit 010429dae4163c7c8693ff10a572d5f2b148d736
Author: acidvegas <acid.vegas@acid.vegas>
Date:   Fri Jun 28 01:07:10 2019 -0400

    Initial commit

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..69997e8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2019, acidvegas <acid.vegas@acid.vegas>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2a37055
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+###### Requirments
+* [FeedParser](http://pypi.python.org/pypi/feedparser)
+* [Tweepy](http://pypi.python.org/pypi/tweepy)
+* [ndg-httpsclient](http://pypi.python.org/pypi/ndg-httpsclient) *(Install only if you are getting an "InsecurePlatformWarning" error.)*
+
+###### Instructions
+Register a Twitter account, and [sign up](http://dev.twitter.com/apps/new) for a new developer application.
+
+Go to your new application settings "Keys and Access Tokens" tab.
+Click the "Create Your Access Token" button on the bottom.
+These will be used in the config to connect to your Twitter account.
+Go to your new application settings "Permissions".
+Change your access to "Read, Write and Access direct messages".
+
+Register a [CoinURL](http://coinurl.com/) account and get your [api key](http://coinurl.com/profile-api.php).
+The random number you will see after "uuid" is your unique user id that will be use in the config.
+
+Edit your `config.py` and change the Twitter & CoinURL API settings.
+
+###### Mirrors
+- [acid.vegas](https://acid.vegas/chir.py) *(main)*
+- [SuperNETs](https://git.supernets.org/acidvegas/chir.py)
+- [GitHub](https://github.com/acidvegas/chir.py)
+- [GitLab](https://gitlab.com/acidvegas/chir.py)
diff --git a/chir.py/chir.py b/chir.py/chir.py
new file mode 100644
index 0000000..3466fc6
--- /dev/null
+++ b/chir.py/chir.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
+# chir.py
+
+import sys
+
+sys.dont_write_bytecode = True
+
+import debug
+
+debug.info()
+if not debug.check_version(3):
+    debug.error_exit('Chir.py requires Python version 3 to run!')
+if not debug.get_windows():
+    if debug.check_root():
+        debug.error_exit('Do not run Chir.py as root!')
+debug.check_imports()
+debug.check_config()
+import twitter
+twitter.login()
+twitter.main_loop()
+debug.keep_alive()
\ No newline at end of file
diff --git a/chir.py/config.py b/chir.py/config.py
new file mode 100644
index 0000000..79027bb
--- /dev/null
+++ b/chir.py/config.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
+# config.py
+
+# API Settings
+coinurl_uuid                = 'CHANGEME'
+twitter_consumer_key	    = 'CHANGEME'
+twitter_consumer_secret	    = 'CHANGEME'
+twitter_access_token	    = 'CHANGEME'
+twitter_access_token_secret = 'CHANGEME'
+
+# Keywords & News Sources (DO NOT EDIT)
+boost_keywords = ('500aday','autofollow','autofollowback','f4f','follow','follow4follow','followback','followtrain','teamfollowback','wefollowback')
+
+news_feeds = {
+    'baseball'   : 'https://sports.yahoo.com/mlb/rss.xml',
+    'basketball' : 'https://sports.yahoo.com/nba/rss.xml',
+    'boxing'     : 'https://sports.yahoo.com/box/rss.xml',
+    'football'   : 'https://sports.yahoo.com/nfl/rss.xml',
+    'golf'       : 'https://sports.yahoo.com/golf/rss.xml',
+    'hockey'     : 'https://sports.yahoo.com/nhl/rss.xml',
+    'mma'        : 'https://sports.yahoo.com/mma/rss.xml',
+    'nascar'     : 'https://sports.yahoo.com/nascar/rss.xml',
+    'soccer'     : 'https://sports.yahoo.com/soccer/rss.xml',
+    'tennis'     : 'https://sports.yahoo.com/tennis/rss.xml'
+}
+
+news_keywords = {
+    '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'),
+    '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'),
+    'boxing'     : ('boxing','fightnight'),
+    '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'),
+    'golf'       : ('fedexcup','owgr','pga','pgachampionship','pgatour'),
+    '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'),
+    'mma'        : ('bellator','martialarts','mixedmartialarts','mma','ufc','wsof'),
+    'nascar'     : ('buschseries','campingworldtruckseries','daytona500','iracing','nascar','sprintcup','sprintseries','winstoncup','winstoncupseries','xfinityseries'),
+    'soccer'     : ('fifa','soccer','worldcup'),
+    'tennis'     : ('atp','atpworldtour','masters1000','tennis','usopen')
+}
diff --git a/chir.py/debug.py b/chir.py/debug.py
new file mode 100644
index 0000000..8670f13
--- /dev/null
+++ b/chir.py/debug.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
+# debug.py
+
+import os
+import sys
+import time
+
+import config
+
+def action(msg):
+    print('%s | [#] - %s' % (get_time(), msg))
+
+def alert(msg):
+    print('%s | [+] - %s' % (get_time(), msg))
+
+def check_config():
+    for item in (config.coinurl_uuid, config.twitter_consumer_key, config.twitter_consumer_secret, config.twitter_access_token, config.twitter_access_token_secret):
+        if item == 'CHANGEME':
+            error_exit('Edit your config file!')
+
+def check_imports():
+    try:
+        import tweepy
+    except ImportError:
+        error_exit('Failed to import the Tweepy library! (http://pypi.python.org/pypi/tweepy)')
+    try:
+        import feedparser
+    except ImportError:
+        error_exit('Failed to import the FeedParser library! (http://pypi.python.org/pypi/feedparser)')
+
+def check_root():
+    if os.getuid() == 0 or os.geteuid() == 0:
+        return True
+    else:
+        return False
+
+def check_version(major):
+    if sys.version_info.major == major:
+        return True
+    else:
+        return False
+
+def check_windows():
+    if os.name == 'nt':
+        return True
+    else:
+        return False
+
+def clear():
+    if check_windows():
+        os.system('cls')
+    else:
+        os.system('clear')
+
+def error(msg, reason=None):
+    if reason:
+        print('%s | [!] - %s (%s)' % (get_time(), msg, str(reason)))
+    else:
+        print('%s | [!] - %s' % (get_time(), msg))
+
+def error_exit(msg):
+    raise SystemExit('%s | [!] - %s' % (get_time(), msg))
+
+def get_time():
+    return time.strftime('%I:%M:%S')
+
+def get_windows():
+    if os.name == 'nt':
+        return True
+    else:
+        return False
+
+def info():
+    clear()
+    print(''.rjust(56, '#'))
+    print('#' + ''.center(54) + '#')
+    print('#' + 'Chir.py Twitter Bot'.center(54) + '#')
+    print('#' + 'Developed by acidvegas in Python '.center(54) + '#')
+    print('#' + 'https://acid.vegas/chir.py'.center(54) + '#')
+    print('#' + ''.center(54) + '#')
+    print(''.rjust(56, '#'))
+
+def keep_alive():
+    try:
+        while True:
+            input('')
+    except KeyboardInterrupt:
+        sys.exit()
diff --git a/chir.py/functions.py b/chir.py/functions.py
new file mode 100644
index 0000000..4edf235
--- /dev/null
+++ b/chir.py/functions.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
+# functions.py
+
+import random
+import re
+import urllib.request
+
+import feedparser
+
+import config
+import debug
+
+def coinurl(url):
+    source  = urllib.request.urlopen('https://coinurl.com/api.php?uuid=%s&url=%s' % (config.coinurl_uuid, url))
+    charset = source.headers.get_content_charset()
+    if charset : return source.read().decode(charset)
+    else       : return source.read().decode()
+
+def get_news(): # This is very sloppy and needs some work.
+    news_list      = list()
+    sport          = random.choice(list(config.news_feeds.keys()))
+    sport_news     = feedparser.parse(config.news_feeds[sport])
+    sport_keywords = config.news_keywords[sport]
+    for item in sport_news.entries:
+        description = strip_html(item.summary)
+        if ') -- ' in description:
+            cutoff      = description.split(') -- ')[0]
+            description = description.split(cutoff)[1]
+        if ') - ' in description:
+            cutoff      = description.split(') - ')[0]
+            description = description.split(cutoff)[1]
+        description = description.replace('*',  '')
+        description = description.replace('\'', '')
+        description = description.replace('"',  '')
+        description = description.replace('--', '-')
+        description = description.replace('  ', ' ')
+        for word in sport_keywords:
+            if word in description.lower():
+                description = re.sub(word, '#' + word, description, flags=re.IGNORECASE)
+        if len(description) > 118:
+            description = description[:118]
+            split       = description.split()
+            description = description.split(split[len(split)-1])[0][:-1] + '... '
+        try:
+            link = coinurl(item.link)
+        except Exception as ex:
+            debug.error('Error occured creating PPC link!', ex)
+        else:
+            description = description + ' ' + link
+            news_list.append(description)
+    return news_list
+
+def strip_html(source):
+    return re.compile(r'<.*?>').sub('', source)
diff --git a/chir.py/twitter.py b/chir.py/twitter.py
new file mode 100644
index 0000000..e5638c1
--- /dev/null
+++ b/chir.py/twitter.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# Chir.py Twitter Bot - Developed by acidvegas in Python (https://acid.vegas/chir.py)
+# twitter.py
+
+import random
+import threading
+import time
+
+import tweepy
+
+import config
+import debug
+import functions
+
+api = None
+me  = None
+
+def login():
+    global api, me
+    try:
+        auth = tweepy.OAuthHandler(config.consumer_key, config.consumer_secret)
+        auth.set_access_token(config.access_token, config.access_token_secret)
+        api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
+        me  = api.me()
+    except tweepy.TweepError:
+        debug.error_exit('Failed to login to Twitter!')
+
+def stats():
+    debug.action('SceenName\t: %s'  % me.screen_name)
+    debug.action('Registered\t: %s' % me.created_at)
+    debug.action('Favorites\t: %s'  % me.favourites_count)
+    debug.action('Following\t: %s'  % me.friends_count)
+    debug.action('Followers\t: %s'  % me.followers_count)
+    debug.action('Tweets\t\t: %s'   % me.statuses_count)
+
+class boost_loop(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+    def run(self):
+        while True:
+            try:
+                if 'boost_tweet' in locals(): api.destroy_status(boost_tweet.id)
+                boost_tweet = api.update_status('Support our Twitter! #' + ' #'.join(config.boost))
+                debug.alert('Re-posted boost tweet.')
+            except tweepy.TweepError as ex:
+                debug.error('Error occured in the boost loop', ex)
+            finally:
+                random.shuffle(config.boost)
+                time.sleep(60*5)
+
+class favorite_loop(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+    def run(self):
+        while True:
+            try:
+                for tweet in tweepy.Cursor(api.home_timeline, exclude_replies=True).items(50):
+                    if tweet.user.screen_name != me.screen_name:
+                        if not tweet.favorited:
+                            if random.choice([True, False, False, False, False]):
+                                api.create_favorite(tweet.id)
+                                debug.alert('Favorited a friends tweet!')
+                    time.sleep(30)
+            except tweepy.TweepError as ex:
+                debug.error('Error occured in the favorite loop!', ex)
+            finally:
+                time.sleep(60*15)
+
+class follow_loop(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+    def run(self):
+        while True:
+            try:
+                followers = api.followers_ids(me.screen_name)
+                friends   = api.friends_ids(me.screen_name)
+                if me.friends_count / me.followers_count == 3:
+                    debug.action('Following to follower ratio is off! Starting the unfollow loop...')
+                    unfollow_loop()
+                for follower in followers:
+                    if not follower in friends:
+                        api.create_friendship(follower)
+                        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!')
+                        debug.alert('Followed back a follower!')
+                    time.sleep(30)
+            except tweepy.TweepError as ex:
+                debug.error('Error occured in the follow loop!', ex)
+            finally:
+                time.sleep(60*15)
+
+def main_loop():
+    boost_loop().start()
+    favorite_loop().start()
+    follow_loop().start()
+    news_loop().start()
+    search_loop().start()
+
+class news_loop(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+    def run(self):
+        while True:
+            try:
+                news   = functions.get_news()
+                tweets = list()
+                for item in tweepy.Cursor(api.user_timeline, exclude_replies=True).items(50):
+                    tweets.append(item.text.split('... ')[0])
+                    time.sleep(2)
+                for item in news:
+                    split = item.split('... ')[0]
+                    if split not in tweets:
+                        api.update_status(item)
+                        debug.alert('A tweet has been posted.')
+                    time.sleep(60*5)
+            except tweepy.TweepError as ex:
+                debug.error('Error occured in the news loop', ex)
+            finally:
+                time.sleep(60*15)
+
+class search_loop(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+    def run(self):
+        query_keywords = list()
+        for item in config.news_keywords:
+            query_keywords = query_keywords + list(config.news_keywords[item])
+        query_keywords = query_keywords + config.boost_keywords
+        while True:
+            try:
+                query = random.choice(query_keywords)
+                for item in api.search(q='#' + query, count=50, lang='en', result_type='mixed'):
+                    if not item.user.following and not item.favorited:
+                        try:
+                            api.create_favorite(item.id)
+                            api.create_friendship(item.user.screen_name)
+                            debug.alert('Followed a similar twitter!')
+                        except tweepy.TweepError as ex:
+                            debug.error('Unknown error occured in the search loop!', ex)
+                    time.sleep(30)
+            except tweepy.TweepError as ex:
+                debug.error('Error occured in the search loop!', ex)
+            finally:
+                time.sleep(60*15)
+
+def unfollow_loop():
+    try:
+        followers = api.followers_ids(me.screen_name)
+        friends   = api.friends_ids(me.screen_name)
+        for friend in friends:
+            if friend not in followers:
+                api.destroy_friendship(friend)
+                debug.alert('Unfollowed an unsupporting friend!')
+                time.sleep(30)
+    except tweepy.TweepError as ex:
+        debug.error('Error occured in the unfollow loop!', ex)