def check_subreddits(self): """ Evaluate new comments from configured subreddits """ lg.debug("> CointipBot::check_subreddits()") try: # Process comments until old comment reached # Get last_processed_comment_time if necessary if not hasattr(self.conf.reddit, 'last_processed_comment_time') or self.conf.reddit.last_processed_comment_time <= 0: self.conf.reddit.last_processed_comment_time = ctb_misc.get_value(conn=self.db, param0='last_processed_comment_time') updated_last_processed_time = 0 # Fetch comments from subreddits my_comments = ctb_misc.praw_call(self.conf.reddit.subreddits.get_comments, limit=self.conf.reddit.scan.batch_limit) # Match each comment against regex counter = 0 for c in my_comments: # Stop processing if old comment reached #lg.debug("check_subreddits(): c.id %s from %s, %s <= %s", c.id, c.subreddit.display_name, c.created_utc, self.conf.reddit.last_processed_comment_time) if c.created_utc <= self.conf.reddit.last_processed_comment_time: lg.debug("CointipBot::check_subreddits(): old comment reached") break counter += 1 if c.created_utc > updated_last_processed_time: updated_last_processed_time = c.created_utc # Ignore duplicate comments (may happen when bot is restarted) if ctb_action.check_action(msg_id=c.id, ctb=self): lg.warning("CointipBot::check_inbox(): duplicate action detected (comment.id %s), ignoring", c.id) continue # Ignore comments from banned users if c.author and self.conf.reddit.banned_users: lg.debug("CointipBot::check_subreddits(): checking whether user '%s' is banned..." % c.author) u = ctb_user.CtbUser(name = c.author.name, redditobj = c.author, ctb = self) if u.banned: lg.info("CointipBot::check_subreddits(): ignoring banned user '%s'" % c.author) continue # Attempt to evaluate comment action = ctb_action.eval_comment(c, self) # Perform action, if found if action: lg.info("CointipBot::check_subreddits(): %s from %s (%s)", action.type, action.u_from.name, c.id) lg.debug("CointipBot::check_subreddits(): comment body: <%s>", c.body) action.do() else: lg.info("CointipBot::check_subreddits(): no match") lg.debug("CointipBot::check_subreddits(): %s comments processed", counter) if counter >= self.conf.reddit.scan.batch_limit - 1: lg.warning("CointipBot::check_subreddits(): conf.reddit.scan.batch_limit (%s) was not large enough to process all comments", self.conf.reddit.scan.batch_limit) except (HTTPError, RateLimitExceeded, timeout) as e: lg.warning("CointipBot::check_subreddits(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.error("CointipBot::check_subreddits(): coudln't fetch comments: %s", e) raise # Save updated last_processed_time value if updated_last_processed_time > 0: self.conf.reddit.last_processed_comment_time = updated_last_processed_time ctb_misc.set_value(conn=self.db, param0='last_processed_comment_time', value0=self.conf.reddit.last_processed_comment_time) lg.debug("< CointipBot::check_subreddits() DONE") return True
def check_inbox(self): """ Evaluate new messages in inbox """ lg.debug('> CointipBot::check_inbox()') try: # Try to fetch some messages messages = list(ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit)) messages.reverse() # Process messages for m in messages: # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info("CointipBot::check_inbox(): ignoring msg with no author") ctb_misc.praw_call(m.mark_as_read) continue lg.info("CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name) # Ignore duplicate messages (sometimes Reddit fails to mark messages as read) if ctb_action.check_action(msg_id=m.id, ctb=self): lg.warning("CointipBot::check_inbox(): duplicate action detected (msg.id %s), ignoring", m.id) ctb_misc.praw_call(m.mark_as_read) continue # Ignore self messages if m.author and m.author.name.lower() == self.conf.reddit.auth.user.lower(): lg.debug("CointipBot::check_inbox(): ignoring message from self") ctb_misc.praw_call(m.mark_as_read) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug("CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name = m.author.name, redditobj = m.author, ctb = self) if u.banned: lg.info("CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) ctb_misc.praw_call(m.mark_as_read) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # Perform action, if found if action: lg.info("CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id) lg.debug("CointipBot::check_inbox(): message body: <%s>", m.body) action.do() else: lg.info("CointipBot::check_inbox(): no match") if self.conf.reddit.messages.sorry and not m.subject in ['post reply', 'comment reply']: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template('didnt-understand.tpl') msg = tpl.render(user_from=user.name, what='comment' if m.was_comment else 'message', source_link=m.permalink if hasattr(m, 'permalink') else None, ctb=self) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell(subj='What?', msg=msg, msgobj=m if not m.was_comment else None) # Mark message as read ctb_misc.praw_call(m.mark_as_read) except (HTTPError, ConnectionError, Timeout, timeout) as e: lg.warning("CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except RateLimitExceeded as e: lg.warning("CointipBot::check_inbox(): rate limit exceeded, sleeping for %s seconds", e.sleep_time) time.sleep(e.sleep_time) time.sleep(1) pass except Exception as e: lg.error("CointipBot::check_inbox(): %s", e) raise lg.debug("< CointipBot::check_inbox() DONE") return True
def check_subreddits(self): """ Evaluate new comments from configured subreddits """ lg.debug("> CointipBot::check_subreddits()") try: # Process comments until old comment reached # Get last_processed_comment_time if necessary if (not hasattr(self.conf.reddit, "last_processed_comment_time") or self.conf.reddit.last_processed_comment_time <= 0): self.conf.reddit.last_processed_comment_time = ctb_misc.get_value( conn=self.db, param0="last_processed_comment_time") updated_last_processed_time = 0 # Fetch comments from subreddits my_comments = ctb_misc.praw_call( self.conf.reddit.subreddits.get_comments, limit=self.conf.reddit.scan.batch_limit, ) # Match each comment against regex counter = 0 for c in my_comments: # Stop processing if old comment reached # lg.debug("check_subreddits(): c.id %s from %s, %s <= %s", c.id, c.subreddit.display_name, c.created_utc, self.conf.reddit.last_processed_comment_time) if c.created_utc <= self.conf.reddit.last_processed_comment_time: lg.debug( "CointipBot::check_subreddits(): old comment reached") break counter += 1 if c.created_utc > updated_last_processed_time: updated_last_processed_time = c.created_utc # Ignore duplicate comments (may happen when bot is restarted) if ctb_action.check_action(msg_id=c.id, ctb=self): lg.warning( "CointipBot::check_inbox(): duplicate action detected (comment.id %s), ignoring", c.id, ) continue # Ignore comments from banned users if c.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_subreddits(): checking whether user '%s' is banned..." % c.author) u = ctb_user.CtbUser(name=c.author.name, redditobj=c.author, ctb=self) if u.banned: lg.info( "CointipBot::check_subreddits(): ignoring banned user '%s'" % c.author) continue # Attempt to evaluate comment action = ctb_action.eval_comment(c, self) # Perform action, if found if action: lg.info( "CointipBot::check_subreddits(): %s from %s (%s)", action.type, action.u_from.name, c.id, ) lg.debug( "CointipBot::check_subreddits(): comment body: <%s>", c.body) action.do() else: lg.info("CointipBot::check_subreddits(): no match") lg.debug("CointipBot::check_subreddits(): %s comments processed", counter) if counter >= self.conf.reddit.scan.batch_limit - 1: lg.warning( "CointipBot::check_subreddits(): conf.reddit.scan.batch_limit (%s) was not large enough to process all comments", self.conf.reddit.scan.batch_limit, ) except (HTTPError, RateLimitExceeded, timeout) as e: lg.warning( "CointipBot::check_subreddits(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.error( "CointipBot::check_subreddits(): coudln't fetch comments: %s", e) raise # Save updated last_processed_time value if updated_last_processed_time > 0: self.conf.reddit.last_processed_comment_time = updated_last_processed_time ctb_misc.set_value( conn=self.db, param0="last_processed_comment_time", value0=self.conf.reddit.last_processed_comment_time, ) lg.debug("< CointipBot::check_subreddits() DONE") return True
def check_inbox(self): """ Evaluate new messages in inbox """ lg.debug("> CointipBot::check_inbox()") try: # Try to fetch some messages messages = list( ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit)) messages.reverse() # Process messages for m in messages: # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info( "CointipBot::check_inbox(): ignoring msg with no author" ) ctb_misc.praw_call(m.mark_as_read) continue lg.info( "CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name, ) # Ignore duplicate messages (sometimes Reddit fails to mark messages as read) if ctb_action.check_action(msg_id=m.id, ctb=self): lg.warning( "CointipBot::check_inbox(): duplicate action detected (msg.id %s), ignoring", m.id, ) ctb_misc.praw_call(m.mark_as_read) continue # Ignore self messages if (m.author and m.author.name.lower() == self.conf.reddit.auth.user.lower()): lg.debug( "CointipBot::check_inbox(): ignoring message from self" ) ctb_misc.praw_call(m.mark_as_read) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) if u.banned: lg.info( "CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) ctb_misc.praw_call(m.mark_as_read) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # Perform action, if found if action: lg.info( "CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id, ) lg.debug("CointipBot::check_inbox(): message body: <%s>", m.body) action.do() else: lg.info("CointipBot::check_inbox(): no match") if self.conf.reddit.messages.sorry and m.subject not in [ "post reply", "comment reply", ]: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template("didnt-understand.tpl") msg = tpl.render( user_from=user.name, what="comment" if m.was_comment else "message", source_link=ctb_misc.permalink(m), ctb=self, ) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell( subj="What?", msg=msg, msgobj=m if not m.was_comment else None, ) # Mark message as read ctb_misc.praw_call(m.mark_as_read) except (HTTPError, ConnectionError, Timeout, RateLimitExceeded, timeout) as e: lg.warning( "CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.exception("CointipBot::check_inbox(): %s", e) # raise # ^ what do we say to death? # lg.error("^not today (^skipped raise)") # raise #not sure if right number of spaces; try to quit on error # for now, quitting on error because of dealing with on-going issues; switch # back when stable lg.debug("< CointipBot::check_inbox() DONE") return True
def check_inbox(self): """ Evaluate new messages in inbox """ lg.debug('> CointipBot::check_inbox()') try: # Try to fetch some messages messages = list( ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit)) messages.reverse() # Process messages for m in messages: # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info( "CointipBot::check_inbox(): ignoring msg with no author" ) ctb_misc.praw_call(m.mark_as_read) continue lg.info("CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name) # Ignore duplicate messages (sometimes Reddit fails to mark messages as read) if ctb_action.check_action(msg_id=m.id, ctb=self): lg.warning( "CointipBot::check_inbox(): duplicate action detected (msg.id %s), ignoring", m.id) ctb_misc.praw_call(m.mark_as_read) continue # Ignore self messages if m.author and m.author.name.lower( ) == self.conf.reddit.auth.user.lower(): lg.debug( "CointipBot::check_inbox(): ignoring message from self" ) ctb_misc.praw_call(m.mark_as_read) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) if u.banned: lg.info( "CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) ctb_misc.praw_call(m.mark_as_read) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # Perform action, if found if action: lg.info("CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id) lg.debug("CointipBot::check_inbox(): message body: <%s>", m.body) action.do() else: lg.info("CointipBot::check_inbox(): no match") if self.conf.reddit.messages.sorry and not m.subject in [ 'post reply', 'comment reply' ]: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template('didnt-understand.tpl') msg = tpl.render( user_from=user.name, what='comment' if m.was_comment else 'message', source_link=m.permalink if hasattr(m, 'permalink') else None, ctb=self) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell(subj='What?', msg=msg, msgobj=m if not m.was_comment else None) # Mark message as read ctb_misc.praw_call(m.mark_as_read) except (HTTPError, ConnectionError, Timeout, timeout) as e: lg.warning( "CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except RateLimitExceeded as e: lg.warning( "CointipBot::check_inbox(): rate limit exceeded, sleeping for %s seconds", e.sleep_time) time.sleep(e.sleep_time) time.sleep(1) pass except Exception as e: lg.error("CointipBot::check_inbox(): %s", e) raise lg.debug("< CointipBot::check_inbox() DONE") return True
def check_mentions(self, ctb): """ Evaluate new comments from self.configured subreddits """ if not (self.conf.scan.my_subreddits or hasattr(self.conf.scan, 'these_subreddits')): lg.debug( "> RedditNetwork::check_mentions(): nothing to check. return now." ) return True lg.debug("> RedditNetwork::check_mentions()") updated_last_processed_time = 0 try: # Process comments until old comment reached # Get last_processed_comment_time if necessary if not hasattr(self.conf, 'last_processed_comment_time' ) or self.conf.last_processed_comment_time <= 0: self.conf.last_processed_comment_time = ctb_misc.get_value( conn=self.db, param0='last_processed_comment_time') # Fetch comments from subreddits my_comments = self.praw_call(self.conf.subreddits.comments, limit=self.conf.scan.batch_limit) # Match each comment against regex counter = 0 for c in my_comments: # Stop processing if old comment reached #lg.debug("check_mentions(): c.id %s from %s, %s <= %s", c.id, c.subreddit.display_name, c.created_utc, self.conf.last_processed_comment_time) if c.created_utc <= self.conf.last_processed_comment_time: lg.debug( "RedditNetwork::check_mentions(): old comment reached") break counter += 1 if c.created_utc > updated_last_processed_time: updated_last_processed_time = c.created_utc # Ignore duplicate comments (may happen when bot is restarted) if ctb_action.check_action(msg_id=c.id, ctb=ctb): lg.warning( "RedditNetwork::check_inbox(): duplicate action detected (comment.id %s), ignoring", c.id) continue # Ignore comments from banned users if c.author and self.conf.banned_users: lg.debug( "RedditNetwork::check_mentions(): checking whether user '%s' is banned..." % c.author) if self.is_user_banned(c.author.name): lg.info( "RedditNetwork::check_mentions(): ignoring banned user '%s'" % c.author) continue # Attempt to evaluate comment action = ctb_action.eval_reddit_comment(c, ctb) # Perform action, if found if action: lg.info("RedditNetwork::check_mentions(): %s from %s (%s)", action.type, action.u_from.name, c.id) lg.debug( "RedditNetwork::check_mentions(): comment body: <%s>", c.body) action.do() else: lg.info("RedditNetwork::check_mentions(): no match") lg.debug("RedditNetwork::check_mentions(): %s comments processed", counter) if counter >= self.conf.scan.batch_limit - 1: lg.warning( "RedditNetwork::check_mentions(): conf.network.scan.batch_limit (%s) was not " + "large enough to process all comments", self.conf.scan.batch_limit) except (HTTPError, ClientException, socket.timeout) as e: lg.warning( "RedditNetwork::check_mentions(): Reddit is down (%s), sleeping", e) time.sleep(self.ctb.conf.misc.times.sleep_seconds) pass except Exception as e: lg.error( "RedditNetwork::check_mentions(): coudln't fetch comments: %s", e) raise # Save updated last_processed_time value if updated_last_processed_time > 0: self.conf.last_processed_comment_time = updated_last_processed_time ctb_misc.set_value(conn=self.db, param0='last_processed_comment_time', value0=self.conf.last_processed_comment_time) lg.debug("< RedditNetwork::check_mentions() DONE") return True