def get_recent_post(self, user_id, **kwargs): variables = {"id": user_id, "first": 1} response = self.request(endpoint='graphql', query_variable=variables) if response.status_code is not 200: logger.error("Instagram responded with status code %s" % str(response.status_code)) raise Exception("Instagram responded with status_code %s" % str(response.status_code)) post = response.json( )['data']['user']['edge_owner_to_timeline_media']['edges'][0] post_data = { 'shortcode': post['node']['shortcode'], 'created_at_timestamp': post['node']['taken_at_timestamp'], 'caption': None, } if len(post['node']['edge_media_to_caption']['edges']) != 0: post_data["caption"] = post['node']['edge_media_to_caption'][ 'edges'][0]["node"]["text"] return post_data
def run(): last_post_time = time.time() while True: try: for submission in subreddit.new(limit=1): post_time = submission.created_utc if post_time > last_post_time: start_time = time.time() title = submission.title author = submission.author url = submission.shortlink if submission.is_self: post_type = 'text' else: post_type = 'link' message = ('New %s post in r/%s by u/%s: "%s"' % (post_type, subreddit, author, title)) # print(message) db.insert_message('Reddit', '', message, url, start_time) last_post_time = post_time time.sleep(2) except Exception as e: logger.error(str(e))
def comment_on_thread(submission, twitter_url_list, imgur_url_list): # Assembles the comment thread_comment = "**Max Resolution Twitter Link(s)**\n\n" for twitter_url in twitter_url_list: thread_comment += ("%s\n\n" % twitter_url) thread_comment += "**Imgur Mirror Link(s)**\n\n" for imgur_url in imgur_url_list: thread_comment += ("%s\n\n" % imgur_url) thread_comment += "---\n\n^^I'm ^^a ^^bot ^^made ^^by ^^[u\/jclishman](https://reddit.com/user/jclishman)!" thread_comment += " [^^[FAQ/Discussion]](http://reddit.com/user/SpaceXMirrorBot/comments/ad36dr/) [^^[Code]](https://github.com/jclishman/SpaceXMirrorBot)" # Posts the comment retries = 0 while retries < 5: try: thread_comment_id = submission.reply(thread_comment) logger.info("Comment made with ID: %s" % thread_comment_id) # Break from the while loop after successful post submission break except praw.exceptions.APIException as e: retries += 1 logger.error("Hit ratelimit, will try again in 5 minutes. (Attempt %d/5)" % retries) time.sleep(300)
def get_post_queue(): try: database = sqlite3.connect('database.db') post_cursor = database.cursor() post_cursor.execute("SELECT * FROM messages WHERE published = 0") return post_cursor.fetchall() except sqlite3.OperationalError as e: logger.error(str(e))
def update_after_publish(target_id): try: database = sqlite3.connect('database.db') update_cursor = database.cursor() update_cursor.execute( "UPDATE messages SET published = 1 WHERE id =%s" % str(target_id)) database.commit() except sqlite3.OperationalError as e: logger.error(str(e))
def get_tweet_posted(tweet_url): try: database = sqlite3.connect('database.db') get_tweet_posted_cursor = database.cursor() get_tweet_posted_cursor.execute( "SELECT id FROM messages WHERE url = ?", [tweet_url]) return get_tweet_posted_cursor.fetchall() except sqlite3.OperationalError as e: logger.error(str(e))
def unfollow_account(user_id): try: database = sqlite3.connect('database.db') unfollow_cursor = database.cursor() unfollow_cursor.execute("DELETE FROM following WHERE twitter_id = %s" % user_id) database.commit() logger.info('Deleted from DB') except sqlite3.OperationalError as e: logger.error(str(e))
def set_flags(user_id, retweets, replies): try: database = sqlite3.connect('database.db') set_flags_cursor = database.cursor() set_flags_cursor.execute( "UPDATE following SET retweets = %i, replies = %i WHERE twitter_id = %s" % (retweets, replies, user_id)) logger.info('Updated DB flags') database.commit() except sqlite3.OperationalError as e: logger.error(str(e))
def get_user_id(self, username): response = self.request(username=username, endpoint='username') if response.status_code is not 200: logger.error("Instagram responded with status code %s" % str(response.status_code)) raise Exception("Instagram responded with status_code %s" % str(response.status_code)) json_response = response.json() return json_response['graphql']['user']['id']
def send_mail(sender, recipient, time, content): try: database = sqlite3.connect('database.db') send_mail_cursor = database.cursor() send_mail_cursor.execute( "INSERT INTO mailbox (sender, recipient , date_sent, content, published) VALUES(?, ?, ?, ?, ?)", [sender, recipient, time, content, 0]) #print(f"DB: Mail sent to {recipient } from {sender} at {time} with body of {content}") database.commit() except sqlite3.OperationalError as e: logger.error(str(e))
def update_instagram_timestamp(username, timestamp): try: database = sqlite3.connect('database.db') insta_timestamp_cursor = database.cursor() insta_timestamp_cursor.execute( "UPDATE following SET instagram_timestamp_at = %s WHERE username = '******'" % (timestamp, username)) database.commit() except sqlite3.OperationalError as e: logger.error(str(e))
def insert_message(service, author, message, url, start_time): # print (service, author, message, url) try: database = sqlite3.connect('database.db') insert_message_cursor = database.cursor() insert_message_cursor.execute( "INSERT INTO messages (service, author, message, url, start_time) VALUES(?,?,?,?,?)", [service, author, message, url, start_time]) database.commit() except sqlite3.OperationalError as e: logger.error(str(e))
def get_instagram_timestamp(username): try: database = sqlite3.connect('database.db') insta_get_timestamp_cursor = database.cursor() insta_get_timestamp_cursor.execute( "SELECT instagram_timestamp_at FROM following WHERE username = '******'" % username) return insta_get_timestamp_cursor.fetchone()[0] except sqlite3.OperationalError as e: logger.error(str(e))
def follow_account(username, user_id, retweets, replies): try: database = sqlite3.connect('database.db') follow_cursor = database.cursor() follow_cursor.execute( "INSERT INTO following (username, twitter_id, retweets, replies) VALUES(?,?,?,?)", [username, user_id, retweets, replies]) logger.info('Added to DB') database.commit() except sqlite3.OperationalError as e: logger.error(str(e))
def get_following(platform): try: database = sqlite3.connect('database.db') get_following_cursor = database.cursor() if platform == 'twitter': get_following_cursor.execute( ("SELECT * FROM following WHERE twitter_id != 0")) # print("> db.py - Got the following list") return get_following_cursor.fetchall() except sqlite3.OperationalError as e: logger.error(str(e))
def get_mail(user): try: database = sqlite3.connect('database.db') get_mail_cursor = database.cursor() #print(f"DB: Getting mail for {user}") get_mail_cursor.execute( "SELECT * FROM mailbox WHERE published=0 and recipient = ?", [user]) mailbox = get_mail_cursor.fetchall() get_mail_cursor.execute( "UPDATE mailbox SET published=1 WHERE published=0 and recipient = ?", [user]) database.commit() return mailbox except sqlite3.OperationalError as e: logger.error(str(e))
def run(): logger.info("Starting Twitter Stream...") # Makes the stream object myStreamListener = MyStreamListener() myStream = tweepy.Stream(auth, myStreamListener) # Streams tweets try: myStream.filter(follow=following, stall_warnings=True) except Exception as e: logger.error("-----CAUGHT ERROR-----") logger.error(str(e)) logger.error("-----ATTEMPTING RECONNECT-----") run()
class MyStreamListener(StreamListener): try: def on_status(self, status): #print(status.text) #print(json.dumps(status._json)) # Converts the data into usable JSON data = status._json # Puts user attributes into this list if the tweeet is from somebody the bot is following # If the tweet isn't from someone the bot is following, set to None # For some reason the twitter API also tells you when someone deletes a tweet # If you try to get the needed properties from a deleted tweet, it throws a KeyError try: user_of_tweet = next( (x for x in users_list if x[1] == data['user']['id_str']), None) except KeyError as e: user_of_tweet = None # Sends the tweet to the database def send_tweet_to_db(tweet_data, start_time): # Gets the full tweet text if it's concatenated by Twitter if "extended_tweet" in tweet_data: text = html.unescape( tweet_data['extended_tweet']['full_text']) # Gets the full retweet text if it's concatenated by Twitter elif "retweeted_status" in tweet_data and "extended_tweet" in tweet_data[ 'retweeted_status']: rt_data = tweet_data['retweeted_status'] text = f"RT @{rt_data['user']['screen_name']}: {html.unescape(rt_data['extended_tweet']['full_text'])}" # Not an extended tweet else: text = html.unescape(tweet_data['text']) # Logs raw JSON #logger.info(json.dumps(data)) # Checks if the tweet is a parent to a reply, which won't have an ID if tweet_data['id_str'] is not None: tweet_url = make_url_from_tweet( tweet_data['user']['screen_name'], tweet_data['id_str']) else: tweet_url = '' db.insert_message('Twitter', tweet_data['user']['screen_name'], text.replace("\n", " "), tweet_url, start_time) # Is the tweet from somebody the bot cares about? if user_of_tweet is not None: start_time = time.time() # Is it a retweet? Is the retweet flag of the user set to 1? if "retweeted_status" in data and user_of_tweet[2] == 1: rt_data = data['retweeted_status'] # Has the retweeted status already been posted? # No, post it if not has_tweet_been_posted( rt_data['user']['screen_name'], rt_data['id_str']): send_tweet_to_db(data, start_time) # Yes, don't post it else: logger.info("Retweet has already been posted") # Is a reply? Is the reply flag of the user set to 1? elif data[ 'in_reply_to_status_id'] is not None and user_of_tweet[ 3] == 1: reply_data = get_status(data['in_reply_to_status_id']) # Has the parent tweet to the reply been posted already? # No, send it as context if not has_tweet_been_posted( reply_data['user']['screen_name'], reply_data['id_str']): # Avoid IRC double pings usernames_to_modify = ['@elonmusk', '@SpaceX'] for username in usernames_to_modify: ZWJ = "" # Inserts a Zero Width Joiner username_zwj = username[:2] + ZWJ + username[2:] reply_data['full_text'] = reply_data[ 'full_text'].replace(username, username_zwj) reply_data['text'] = reply_data['full_text'] # Don't send the ID of the reply tweet reply_data['id_str'] = None send_tweet_to_db(reply_data, start_time) time.sleep(0.5) send_tweet_to_db(data, start_time) # Yes, don't send it again else: send_tweet_to_db(data, start_time) logger.info("Parent tweet already posted") # If it's a normal tweet elif "retweeted_status" not in data and data[ "in_reply_to_status_id"] is None: send_tweet_to_db(data, start_time) except error as e: logger.error(str(e)) logger.error("-----FOUND ERROR-----") # Trying to find out what's causing the random Twitter crashes def on_error(self, status): if status == 420: logger.error("----RATELIMITED ERROR 420----") return False else: logger.error("----ERROR----")
def on_error(self, status): if status == 420: logger.error("----RATELIMITED ERROR 420----") return False else: logger.error("----ERROR----")
def parse(message_contents): # Default values retweets = 0 replies = 0 # Makes everything lowercase, removes the bot username, and take out all spaces message_clean = message_contents.replace(NICK + ': ', '').lower() # Splits the command into parts command = message_clean.split(' ') action = command[0].strip() # Error handling try: target = command[1].replace('@', '').strip() except: target = None try: retweets = int(command[2].strip()) except: retweets = None try: replies = int(command[3].strip()) except: replies = None if action == 'help': if target == 'follow': return 'Follows Twitter accounts, see MaxQ: help for syntax' elif target == 'unfollow': return 'Unfollows Twitter accounts, see MaxQ: help for syntax' elif target == 'set': return 'Changes flag(s) for accounts I\'m already following, see MaxQ: help for syntax' else: return 'Syntax: MaxQ: follow|unfollow|set @username 0|1 <retweets> 0|1 <replies>' elif action == 'unfollow': user_id = twitter.getID(target) if in_database(user_id): db.unfollow_account(user_id) return 'Unfollowed @%s' % target elif not in_database(user_id): return 'Error: @%s is not in the database' % target if type(retweets) is not int or type(replies) is not int: logger.error('Command error: not an int') return 'Error: Invalid command' if retweets > 1 or replies > 1: logger.error('Command Error: not 0 or 1') return 'Error: Invalid command' # print('Command: ' + str(command)) logger.info( f"Action: {action} | Target: {target} | Retweets: {retweets} | Replies: {replies}" ) if target is None: return 'Error: No target account' user_id = twitter.getID(target) # Is the target a user? Does the user actually exist? if user_id is None: return f"Error: @{target} does not exist" # Are flags specified? if retweets is None or replies is None: return 'Error: Missing valid flag(s)' if action == 'follow': # Is the user not already in the database? if not in_database(user_id): db.follow_account(target, user_id, retweets, replies) return f"@{target} is now being followed on Twitter | Retweets {retweets} | Replies {replies}" return f"@{target} is already being followed on Twitter" if action == 'set': if in_database(user_id): db.set_flags(user_id, retweets, replies) return f"@{target} now has retweets set to {retweets} and replies set to {replies}" return f"Error: @{target} is not in the database"
if irc_stream is not None and irc_stream.find('PING') != -1: pong(text) # print(time.ctime()) if irc_stream is not None and irc_stream.find('PRIVMSG') != -1: is_privmsg = False message_author = irc_stream.split('!', 1)[0][1:] message_channel = irc_stream.split('PRIVMSG', 1)[1].split(':', 1)[0].lstrip() message_contents = irc_stream.split('PRIVMSG', 1)[1].split(':', 1)[1] try: message_author_hostname = irc_stream.split('@', 1)[1].split()[0] except IndexError as e: logger.error(str(e)) message_author_hostname = '' logger.info('Author: ' + message_author) logger.info('Hostname: ' + message_author_hostname) logger.info('Channel: ' + message_channel) logger.info('Content: ' + message_contents) if not message_channel.startswith('#'): is_privmsg = True # Admins can make the bot check status, restart, and quit if message_author_hostname in admins: if message_contents.rstrip() == '!!status': status = get_status()