From 010429dae4163c7c8693ff10a572d5f2b148d736 Mon Sep 17 00:00:00 2001 From: acidvegas Date: Fri, 28 Jun 2019 01:07:10 -0400 Subject: [PATCH] Initial commit --- LICENSE | 15 +++++ README.md | 24 +++++++ chir.py/chir.py | 22 ++++++ chir.py/config.py | 39 +++++++++++ chir.py/debug.py | 89 +++++++++++++++++++++++++ chir.py/functions.py | 55 +++++++++++++++ chir.py/twitter.py | 155 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 399 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 chir.py/chir.py create mode 100644 chir.py/config.py create mode 100644 chir.py/debug.py create mode 100644 chir.py/functions.py create mode 100644 chir.py/twitter.py 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 + +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)