Exemple #1
0
 def __init__(self, post_id, ok_id=None, todo_id=None):
     """Initialize."""
     reddit = Reddit(check_for_updates=False)
     self.post = reddit.submission(id=post_id)
     self.ok = None
     self.todo = None
     if ok_id:
         self.ok = reddit.comment(id=ok_id)
     if todo_id:
         self.todo = reddit.comment(id=todo_id)
Exemple #2
0
def get_via_praw(post_id, post_type,praw_cred):

	if praw_cred is None:
		raise IOError("Missing praw credentials")

	from praw import Reddit

	reddit = Reddit(client_id=praw_cred["client_id"], client_secret=praw_cred["client_secret"],
						 password=praw_cred["password"], user_agent=praw_cred["user_agent"],username=praw_cred["username"])

	if post_type == "post":
		submission = reddit.submission(post_id)
		created_utc = submission.mod.thing.created_utc
		selftext = submission.mod.thing.selftext
		selftext = re.sub(r'\s+',' ',selftext)
		selftext = selftext.replace("'","\\'")
		title = submission.mod.thing.title
		title = title.replace("'","\\'")
		out_json = "[{'id':'"+post_id+"','selftext':'"+selftext+"','created_utc':"+str(int(created_utc))+",'title':'"+title+"'}]"
	else:
		submission = reddit.comment(post_id)
		created_utc = submission.mod.thing.created_utc
		selftext = submission.mod.thing.body
		selftext = re.sub(r'\s+',' ',selftext)
		selftext = selftext.replace("'","\\'")
		title = ""
		out_json = "[{'id':'"+post_id+"','body':'"+selftext+"','created_utc':"+str(int(created_utc))+"}]"

	return out_json
Exemple #3
0
def migrate_saved(origin_account: praw.Reddit, destination_account: praw.Reddit, posts: list, verbose: bool = True):
    """
    Migrates saved posts from one reddit account to another
    """
    if utils.is_null_or_empty(posts):
        print("Posts list is empty or was not found.")
        return

    print(f"Total items: {len(posts)}")

    for index, post in enumerate(posts):
        try:
            print(f"Migrating post #{index + 1} with id: {post.id}")

            # Remove from origin account
            origin_account.submission(id=post.id).unsave()

            # Add to destination account
            if type(post) == praw.models.Submission:
                submission = destination_account.submission(id=post.id)

                if submission.saved is False:
                    submission.save()
            elif type(post) == praw.models.Comment:
                comment = destination_account.comment(id=post.id)

                if comment.saved is False:
                    comment.save()
        except Exception as ex:
            log.error(ex, f"An error occurred while migrating the post id {post.id}.")
Exemple #4
0
def migrate_upvoted(origin_account: praw.Reddit, destination_account: praw.Reddit, posts: list, verbose: bool = True):
    """
    Migrates a friend list from one reddit account to another
    """
    if utils.is_null_or_empty(posts):
        print("Friends list is empty or was not found.")
        return

    for post in posts:
        try:
            # Remove from origin account
            origin_account.submission(id=post.id).clear_vote()

            # Add to destination account
            if type(post) == praw.models.Submission:
                submission = destination_account.submission(id=post.id)

                if submission.likes is None:
                    submission.upvote()
            elif type(post) == praw.models.Comment:
                comment = destination_account.comment(id=post.id)

                if submission.likes is None:
                    comment.upvote()
        except Exception as ex:
            log.error(ex, f"An error occurred while migrating the post id {post.id}.")
Exemple #5
0
def _set_comment_score(api: praw.Reddit, id_):
    comm = api.comment(id_)
    return """
MATCH (n:Comment {id: "%s"})
WITH n
SET n.score = %s;
""" % (comm.id, comm.score)
Exemple #6
0
def force(comment_id, image):
    """Main function"""
    reddit = Reddit()
    comment = reddit.comment(comment_id)
    comment.body = image
    bot = RedditBot()
    print(bot.process_comment(comment))
Exemple #7
0
def get_comment_from_link(reddit: praw.Reddit,
                          link: str) -> praw.models.reddit.comment.Comment:
    comment_id = link.split("/")[-2]
    c = reddit.comment(comment_id)
    if not isinstance(c, praw.models.reddit.comment.Comment) or c.permalink not in link \
            or c.body in ("[deleted]", "[removed]") or c.body is None:
        raise CommentMissingException("Comment does not exist")
    return c
def test_get_comment_details(test_comment_id: str, expected_dict: dict,
                             reddit_instance: praw.Reddit):
    comment = reddit_instance.comment(id=test_comment_id)
    test_entry = CommentArchiveEntry(comment)
    result = test_entry.compile()
    assert all([
        result.get(key) == expected_dict[key] for key in expected_dict.keys()
    ])
Exemple #9
0
def get_context(comment: Comment, reddit: Reddit):
    submission = reddit.submission(id=comment.link_id.replace('t3_', ''))
    parent_comment = None
    if not comment.parent_id == comment.link_id:
        # not a top level comment, try to retrieve parent comment
        parent_comment = reddit.comment(
            id=comment.parent_id.replace('t1_', ''))
    return parent_comment, submission
Exemple #10
0
def get_via_praw(post_id, post_type, praw_cred):

    if praw_cred is None:
        raise IOError("Missing praw credentials")

    from praw import Reddit

    reddit = Reddit(client_id=praw_cred["client_id"],
                    client_secret=praw_cred["client_secret"],
                    password=praw_cred["password"],
                    user_agent=praw_cred["user_agent"],
                    username=praw_cred["username"])

    if post_type == "post":
        submission = reddit.submission(post_id)
        try:
            created_utc = submission.mod.thing.created_utc
        except:
            return ""
        selftext = submission.mod.thing.selftext
        selftext = re.sub(r'\s+', ' ', selftext)
        #selftext = selftext.replace("\\","\\\\").replace('"', '\\"').replace("\t"," ").replace("\t","\\t").replace("\r","\\r").replace("\n","\\n")
        selftext = json.dumps(selftext)
        title = submission.mod.thing.title
        title = title.replace('"', """)
        title = json.dumps(title)
        #title = title.replace('"', '\\"').replace("\t","\\t").replace("\r","\\r").replace("\n","\\n")#replace("'","\\'")
        author = submission.mod.thing.author
        if author is not None:
            author = author.name
        else:
            author = "unknown"
        out_json = '{"id":"'+post_id+'","selftext":'+selftext+',"created_utc":'+str(int(created_utc))+\
             ',"title":'+title+',"author":"'+author+'"}'
    else:
        submission = reddit.comment(post_id)
        created_utc = submission.mod.thing.created_utc
        selftext = submission.mod.thing.body
        selftext = re.sub(r'\s+', ' ', selftext)
        selftext = selftext.replace('"', '\\"').replace("'", "\\'")
        out_json = "[{'id':'" + post_id + "','body':'" + selftext + "','created_utc':" + str(
            int(created_utc)) + "}]"
    try:
        out_json = json.loads(out_json)
    except:
        print("Invalid json: " + out_json)
        quit()

    return out_json
Exemple #11
0
def make_package_infer_url(url: str, reddit: Reddit) -> dict:
    """Return package like astroturf.prawtools.make_package_training but for inference.

    Args:
        url (str): url for inference
        reddit (Reddit): ...
    """
    try:
        refobj = reddit.comment(url=url)
    except InvalidURL:
        refobj = reddit.submission(url=url)

    if isinstance(refobj, Submission):
        return make_package_infer_submission(refobj)
    elif isinstance(refobj, Comment):
        return make_package_infer_comment(refobj, reddit)
Exemple #12
0
def add_comment_parent_tree(reddit: Reddit, reddit_comment: Comment):
    """
    Starting with the comment that's the *parent* of the specified comment (non-inclusive),
    recursively crawl up the tree and add all of them to the database.
    Stops when it reaches a comment that already exists in the database or upon reaching the root.
    Needs improvements for efficiency.
    """

    # Could do this with recursive calls to this function, but
    # I don't know how deep reddit comment chains are allowed to get.
    # So instead we need to keep a stack of comments so we can insert
    # them in the correct order, root first then down the chain.
    # This is necessary because the parent_id of each needs to already exist.
    comment_stack = []

    # At the start of each loop, if we're at the top comment of the tree there will be no parents to add.
    # parent_id will return a submission for top level comments, so check is_root instead.
    while not reddit_comment.is_root:
        parent_id = reddit_comment.parent_id.split("t1_")[1]
        parent_exists = get_comment_by_id(parent_id)

        # Once we reach a child where the parent already exists, we can stop adding new comments up the chain.
        if parent_exists:
            break

        # Parent now becomes the base comment, then create a model for it (but don't insert yet).
        reddit_comment = reddit.comment(id=parent_id)
        comment = _create_comment_model(reddit_comment)
        comment_stack.append(comment)

        # Insert the author into the database if they don't exist yet.
        if reddit_comment.author is not None and not user_service.get_user(
                reddit_comment.author.name):
            user_service.add_user(reddit_comment.author)

        # Insert post into the database if it doesn't exist yet.
        if not post_service.get_post_by_id(reddit_comment.submission.id):
            post_service.add_post(reddit_comment.submission)

    # Reverse the order that we're iterating through the stack for inserting, last->first.
    for comment in comment_stack[::-1]:
        _comment_data.insert(comment, error_on_conflict=False)
 def __init__(self, api: praw.Reddit, id_):
     self.api = api
     self.id = id_
     self.resp = api.comment(id_)
Exemple #14
0
def check_comments(reddit: praw.Reddit, db: DatabaseHelper, rh: RedditHelper,
                   config):
    logger = logging.getLogger(__name__)
    subreddit = reddit.subreddit(config["subreddit"])

    # check if any new comments, update submissions accordingly
    comment_stream = subreddit.comments(limit=50)
    for comment in comment_stream:
        # checking whether we have all necessary values, as the post could've been deleted + some prerequisites
        try:
            assert comment and comment.author and comment.submission and comment.submission.author
        except AssertionError:
            break
        # much better than a big if!

        # we don't want to get in the way of mods
        if comment.author.name == 'AutoModerator':
            break
        elif rh.mod_overridden(comment.submission):
            break

        # on new comments made by OP
        if comment.author.name == comment.submission.author.name:
            # if OP's comment is "solved", flair submission as "solved"
            if not rh.already_solved(
                    comment.submission) and rh.solved_in_comment(comment):
                try:
                    # marking post as solved and changing the status in the DB
                    db.save_post(comment.submission.id, 'solved')
                    rh.apply_flair(submission=comment.submission,
                                   text=config["flairs"]["solved"]["text"],
                                   flair_id=config["flairs"]["solved"]["id"])
                    logger.info(
                        f"Marked submission {comment.submission.id} as solved")
                except exceptions.PRAWException:
                    logger.error(
                        f"Couldn't flair submission {comment.submission.id} as 'solved' following OP's new comment."
                    )

                # notifying the subscribers about the solve
                rh.notify_subscribers(post_id=comment.submission.id,
                                      sub_name=comment.subreddit.display_name,
                                      title=comment.submission.title,
                                      permalink=comment.submission.permalink)

                # no need to store them any further
                db.remove_all_subs(comment.submission.id)

                # we don't want to assign points when OP replied to themselves (or their submission)
                if not comment.parent_id.startswith('t3') and \
                        (parent := reddit.comment(comment.parent_id[3:])).author.name != comment.submission.author.name:
                    # adding a point to solver's balance
                    points = db.modify_points(parent.author.name, 1)

                    # modifying the flair of the person who solved the query
                    flair_index = 0  # index of the flair template ID on the template array

                    # if the user has more points than the highest bound, just apply the highest flair
                    if points >= (flair_bounds :=
                                  config["user_flairs"]["bounds"])[-1]:
                        flair_index = len(flair_bounds)

                    for index, bound in enumerate(flair_bounds):
                        # if user's points are smaller than the bound, then user qualifies for the flair
                        if points < bound:
                            flair_index = index
                            break

                    reddit.subreddit(config["subreddit"]).flair.set(
                        redditor=parent.author.name,
                        text=config["user_flairs"]["text"].format(points),
                        flair_template_id=config["user_flairs"][flair_index])

            # if OP's comment is not "solved", flair submission as "contested"
            elif not rh.already_contested(
                    comment.submission) and not rh.already_solved(
                        comment.submission):
                db.save_post(comment.submission.id, 'contested')
                rh.apply_flair(submission=comment.submission,
                               text=config["flairs"]["contested"]["text"],
                               flair_id=config["flairs"]["contested"]["id"])
                logger.info(
                    f"Marked submission {comment.submission.id} as contested")
def test_get_comment_replies(test_comment_id: str, expected_min_comments: int,
                             reddit_instance: praw.Reddit):
    comment = reddit_instance.comment(id=test_comment_id)
    test_entry = CommentArchiveEntry(comment)
    result = test_entry.compile()
    assert len(result.get('replies')) >= expected_min_comments
Exemple #16
0
class SearchEngine:

    __rd_socket = None
    __ps_api = None

    def __init__(self, user_agent=False, use_praw=False):
        rd_credential = (RedditCredential.objects.get(user_agent=user_agent)
                         if user_agent else RedditCredential.objects.first())

        self.__rd_socket = Reddit(client_id=rd_credential.client_id,
                                  client_secret=rd_credential.client_secret,
                                  user_agent=rd_credential.user_agent)

        self.__ps_api = PushshiftAPI(self.__rd_socket if use_praw else None)

    def new_credential(client_id, client_secret, user_agent, domain):
        rd_credential = RedditCredential(
            client_id=client_id,
            client_secret=client_secret,
            user_agent=user_agent,
            domain=domain,
        )
        rd_credential.save()

    def most_commented_submissions(self,
                                   subreddit=None,
                                   before=None,
                                   after=None,
                                   limit=10):
        return [
            {
                'id': submission.id,
                'title': submission.title,
                'body': submission.selftext,
                'url': submission.url,
                'subreddit': submission.subreddit,
                'author': submission.author,
                'num_comments': submission.num_comments,
                'created_at': datetime.utcfromtimestamp(
                    submission.created_utc),
                'retrieved_on': datetime.utcfromtimestamp(
                    submission.retrieved_on)
            } for submission in self.__ps_api.search_submissions(
                before=datetime.strptime(before, "%d-%m-%Y"
                                         ) if before else None,
                after=datetime.strptime(after, "%d-%m-%Y") if after else None,
                subreddit=subreddit,
                sort_type='num_comments',
                limit=limit)
        ] or [None]

    def retrive_submission_by_id(self, submission_id):
        submission = self.__rd_socket.submission(id=submission_id)

        submission = {
            'id': submission.id,
            'title': submission.title,
            'body': submission.selftext,
            'url': submission.url,
            'subreddit': submission.subreddit.display_name,
            'author': submission.author.name,
            'score': submission.score,
            'num_comments': submission.num_comments,
            'created_at': datetime.utcfromtimestamp(submission.created_utc),
            'retrieved_on': datetime.now()
        }

        return submission

    def retrive_submission_comments(self,
                                    submission_id,
                                    before=None,
                                    after=None,
                                    method='psaw'):
        comments = None

        if method == 'psaw':
            comments = [{
                'id':
                comment.id,
                'author_id':
                comment.author,
                'body':
                comment.body,
                'created_at':
                datetime.utcfromtimestamp(comment.created_utc),
                'submission_id':
                comment.link_id.split('_')[1],
                'parent':
                comment.parent_id.split('_')[1],
                'retrieved_on':
                datetime.utcfromtimestamp(comment.retrieved_on)
            } for comment in self.__ps_api.search_comments(
                link_id=submission_id,
                after=datetime.strptime(after, "%d-%m-%Y") if after else None,
                before=datetime.strptime(before, "%d-%m-%Y"
                                         ) if before else None,
            )]

        if method == 'praw' or not comments:
            comments = [{
                'id':
                comment.id,
                'author_id':
                comment.author.name if comment.author else None,
                'body':
                comment.body,
                'score':
                comment.score,
                'created_at':
                datetime.utcfromtimestamp(comment.created_utc),
                'submission_id':
                comment._submission.id,
                'parent':
                comment.parent_id.split('_')[1],
                'retrieved_on':
                datetime.now()
            } for comment in self.__rd_socket.submission(
                id=submission_id).comments.replace_more(limit=0)]

        return comments

    def retrive_redditor_submissions(self,
                                     redditor,
                                     domain=None,
                                     before=None,
                                     after=None,
                                     method='psaw'):
        submission = None

        if method == 'psaw':
            submissions = [{
                'id':
                submission.id,
                'title':
                submission.title,
                'body':
                submission.selftext,
                'url':
                submission.url,
                'subreddit':
                submission.subreddit,
                'author':
                submission.author,
                'num_comments':
                submission.num_comments,
                'created_at':
                datetime.utcfromtimestamp(submission.created_utc),
                'retrieved_on':
                datetime.utcfromtimestamp(submission.retrieved_on)
            } for submission in self.__ps_api.search_submissions(
                author=redditor,
                domain=domain,
                before=datetime.strptime(before, "%d-%m-%Y"
                                         ) if before else None,
                after=datetime.strptime(after, "%d-%m-%Y") if after else None)]

        if method == 'praw' or not submissions:
            submissions = [
                {
                    'id': submission.id,
                    'title': submission.title,
                    'body': submission.selftext,
                    'url': submission.url,
                    'subreddit': submission.subreddit.display_name,
                    'author': submission.author.name,
                    'score': submission.score,
                    'num_comments': submission.num_comments,
                    'created_at':
                    datetime.utcfromtimestamp(submission.created_utc),
                    'retrieved_on': datetime.now()
                } for submission in self.__rd_socket.redditor(
                    redditor).submissions.new()
                if not domain or submission.subreddit.display_name in domain
            ]

        return submissions

    def redditor_info(self, redditor):
        redditor = self.__rd_socket.redditor(redditor)

        return {
            'name':
            getattr(redditor, 'name'),
            'submissions_karma':
            getattr(redditor, 'link_karma'),
            'comments_karma':
            getattr(redditor, 'comment_karma'),
            'created_at':
            datetime.utcfromtimestamp(getattr(redditor, 'created_utc'))
        }

    def subreddit_info(self, subreddit):
        subreddit = self.__rd_socket.subreddit(subreddit)

        return {
            'name': subreddit.display_name,
            'description': subreddit.description[:5000],
            'short_description': subreddit.public_description,
            'num_subscribers': subreddit.subscribers,
            'created_at': datetime.utcfromtimestamp(subreddit.created_utc),
            'last_update': datetime.now()
        }

    def update_comments_score(self, comments_id):

        num_comments = len(comments_id)
        for i, comment_id in enumerate(comments_id):
            try:
                comment = Comment.objects.get(id=comment_id)
                score = self.__rd_socket.comment(id=comment_id).score
                comment.score = int(score)
                comment.save()
            except Exception as ex:
                print(ex)
                pass

            if i % 500 == 0:
                print(f'{i+1}/{num_comments}')

        print(f'{i+1}/{num_comments}')

    def update_submissions_score(self, submissions_id):

        num_submissions = len(submissions_id)
        for i, submission_id in enumerate(submissions_id):
            submission = Submission.objects.get(id=submission_id)
            score = self.__rd_socket.submission(id=submission_id).score
            submission.score = score
            submission.save()

            if i % 500 == 0:
                print(f'{i+1}/{num_submissions}')

        print(f'{i+1}/{num_submissions}')

    def update_submissions_comments(self, submissions_ids=None):
        comments_ids = {comment.id for comment in Comment.objects.all()}
        authors_names = {author.name for author in RedditUser.objects.all()}
        submissions = Submission.objects.filter(
            id__in=submissions_ids
        ) if submissions_ids else Submission.objects.all()

        for i, submission in enumerate(submissions):
            print(f'{i}/{len(submissions)} - {submission.id}')
            comments = [
                comment
                for comment in self.retrive_submission_comments(submission.id)
                if comment['id'] not in comments_ids
            ]

            authors = [
                comment['author_id'] for comment in comments
                if comment['author_id'] not in authors_names
            ]

            authors_bulk = []
            for author in authors:
                try:
                    authors_bulk.append(
                        RedditUser(**self.redditor_info(author)))
                except Exception:
                    authors_bulk.append(RedditUser(name=author))

            RedditUser.objects.bulk_create(authors_bulk, ignore_conflicts=True)

            comments = [Comment(**comment) for comment in comments]
            Comment.objects.bulk_create(comments, ignore_conflicts=True)
Exemple #17
0
class RedditBot:

    def __init__(self, mode='watch'):

        self._mode = mode

        # Configura e inicia banco de dados, reddit e etc...
        # assim que o objeto Redditbot foi instanciado.

        self._setup_logging()
        self._logger.info('The Bot is now starting in {} mode.'
                          .format(self._mode))
        self._load_config()
        self._setup_database()
        self._setup_reddit()

    # Configura o formato de saída dos logs, também o arquivo.
    # O bot executa dois processos separados, um "watch" e outro
    # "reply", cada processo tem o seu log.

    def _setup_logging(self):
        if not os.path.exists('logs'):
            os.makedirs('logs')

        self._logger = logging.getLogger(__name__)
        formatter = logging.Formatter('%(asctime)s '
                                      '[%(levelname)s] '
                                      '%(message)s')
        self._logger.setLevel(logging.INFO)
        ch = logging.StreamHandler()
        fh = logging.FileHandler('logs/{}.log'
                                 .format(self._mode))
        ch.setFormatter(formatter)
        fh.setFormatter(formatter)
        self._logger.addHandler(ch)
        self._logger.addHandler(fh)

    # Carrega o arquivo de configuração, qualquer erro
    # logga e raise a exception

    def _load_config(self):
        try:
            with open('config.yml', 'r') as file:
                self._config = yaml.load(file)
            self._logger.info('Loaded config file.')
        except Exception as e:
            self._logger.critical('Couldn\'t load config file.')
            self._logger.critical(e)
            raise

    # Cria o objecto Reddit, note que ele não automaticamente
    # conecta aqui, por isso para testar a conexão chamamos então
    # reddit.user.me() para que ele connecte e pegue o usuário
    # se falhar aqui, há um problema com autenticação ou etc...

    def _setup_reddit(self):
        try:
            self._reddit = Reddit(**self._config['reddit'])
            username = self._reddit.user.me()
            self._logger.info('Connected to Reddit as: {}.'
                              .format(username))
        except Exception as e:
            self._logger.critical('Couldn\'t connect to Reddit.')
            self._logger.critical(e)
            raise

    # Configua banco de dados

    def _setup_database(self):
        try:
            database = Database(**self._config['database'])
            self._db = database
            self._logger.info('Connected to database: '
                              '{driver}://{username}@{host}:{port}/{database}'
                              .format_map(self._config['database']))
        except Exception as e:
            self._logger.critical('Couldn\'t connect to database.')
            self._logger.critical(e)
            raise

    # Assiste (ou escuta) o stream de comentários dos subreddits
    # no arquivo de config.

    def watch(self):

        self._logger.info('Watching for new comments.')

        # Caso haja mais de um subreddit, junte-os separados por +,
        # exemplo: brasil+portugal, assim ele trabalhará nos dois
        # subreddits.

        subreddits_list = '+'.join(self._config['bot']['subreddits'])
        subreddits = self._reddit.subreddit(subreddits_list)

        while True:
            try:
                # Assiste o stream de comentários
                for comment in subreddits.stream.comments():
                    self._logger.info('Comment base36_id found: {}.'
                                      .format(comment.id))
                    # pega o comentário anterior ou a submission (publicação)
                    parent = comment.parent()

                    commands = self._config['bot']['commands']

                    # verifica se o corpo do comentário contém algum comando cadastrado na config
                    if comment.body.lower().startswith(tuple(commands)):
                        # a propriedade .author retorna None se a conta tiver sido apagada
                        # então verifica se a conta ainda existe antes de prosseguir.
                        # raramente acontece, mas é uma possibilidade.
                        if comment.author and parent.author:
                            # Verifica se o autor está votando para si mesmo ou para o próprio Bot
                            if comment.author != parent.author \
                            and parent.author != self._reddit.user.me():

                                self._logger.info('Comment base36_id: {} matches command.'
                                                  .format(comment.id))

                                # adiciona o usuario caso não exista no db, caso ja exista
                                # retorna apenas o resultado da query
                                from_user = self._db.get_or_add_user(username=comment.author)
                                to_user = self._db.get_or_add_user(username=parent.author)

                                # Verifica se usuario ja não votou para o mesmo comentario
                                if not self._db.get_comment(from_user_id = from_user.id,
                                                            parent_base36_id = parent.id):
                                    try:
                                        # Adiciona o comentário no db, para ser processado pelo
                                        # reply.
                                        self._db.add_comment(
                                            parent_base36_id = parent.id,
                                            base36_id = comment.id,
                                            from_user_id = from_user.id,
                                            to_user_id = to_user.id
                                        )
                                        # Adiciona +1 pontos ao usuário que recebeu o voto.
                                        to_user.points += 1
                                        self._db.session.commit()
                                        self._logger.info('Added to database!')

                                    except IntegrityError:
                                        self._logger.info('Already added to database!')
                                        self._db.session.rollback()
                                    except SQLAlchemyError:
                                        self._logger.info('Something went wrong with your database, rolling back!')
                                        self._db.session.rollback()

            # Pega qualquer Exception loga e tenta novamente em 5s,
            # Não é uma boa prática at all, mas está 
            # funcionando e não é prioridade.
            # Quem quiser melhorar isso aqui, só mandar PR =)
            except Exception as e:
                self._logger.error('Tried to read comments stream'
                                   ' but failed, trying again!')
                self._logger.error(e)
            time.sleep(5)

    def reply(self):

        self._logger.info('Looking for new comments to reply to.')

        while True:
            # Pega todos os comentários que foram adicionados ao db
            # mas ainda não foram respondidos.
            comments = self._db.get_comments(status='TO_REPLY')
            try:
                for comment in comments:
                    self._logger.info('Replying to comment base36_id: {}'
                                      .format(comment.base36_id))
                    # carrega o comentário
                    reddit_comment = self._reddit.comment(id=comment.base36_id)
                    # renderiza o template e gera o comentário de acordo com as informações
                    # do banco de dados.
                    render = render_template('default.md', comment=comment)
                    # Responde ao comentário e marca o status para DONE
                    reddit_comment.reply(render)
                    comment.status = 'DONE'
                    self._db.session.commit()
                    self._logger.info('Replied to comment base36_id: {}'
                                      .format(comment.base36_id))
                    # timer temporario, por ser uma conta nova devo limitar os comentários entre 9m.
                    #time.sleep(60 * 10)
                    # agora que a conta já tem karma suficiente, limitar apenas para cada dois segundos
                    # no mínimo, mas deixarei 4
                    time.sleep(4)


            # Pega todas as exceptions,
            # péssima prática mas tá valendo por enquanto.
            except Exception as e:
                comment.status = 'ERROR'
                self._db.session.commit()
                self._logger.error('Something went wrong!')
                self._logger.error(e)
            self._db.session.commit()
            time.sleep(5)
class reddit_bot(configuration_manager,Reddit):

    _COMMENT_MAX_LEN = 10000

    def __init__(self,configuration_json_file, configuation_json_item):
        self.bot = None
        self.bot_call = None
        self.bot_subreddit = None
        self.bot_database = None
        self.bot_name = None
        self.bot_objects = []
        self.configuation_json_item = configuation_json_item
        self.initialize_bot(configuration_json_file)
        self.subscribed_subreddits = self.get_subscribed_subreddits()

    def initialize_bot(self,PRAW_bot_json_file):
        PRAW_json_item = ','.join([self._firstItem,self.configuation_json_item])
        connection_string_list = self.config_arguments(PRAW_bot_json_file,PRAW_json_item)
        self.bot = Reddit(
        user_agent=connection_string_list['user_agent'],
        client_id=connection_string_list['client_id'],
        client_secret=connection_string_list['client_secret'],
        username=connection_string_list['username'],
        password=connection_string_list['password']
        )
        self.bot_name=connection_string_list['username']
        self.bot_call=connection_string_list['bot_call']
        self.bot_subreddit=self.bot.subreddit(connection_string_list['bot_subreddit'])
        self.bot_database=connection_string_list['source_database']
    
    def get_subscribed_subreddits(self):
        subreddit_list = []
        for subreddit in list(self.bot.user.subreddits(limit=None)):
            subreddit_list.append(subreddit.display_name)
        return '+'.join(subreddit_list)
    
    def get_reddit_obj_type(self,object_id):
        try:
            return str(self.bot.redditor(object_id[0:3]))
        except:
            print('didn\'t work')
    
    def get_reddit_obj(self,object_id):
        try:
            return self.bot.redditor(object_id)
        except:
            print('didn\'t work')

    def reddit_object_redditor_reply(self,object_id,source_redditor=None,return_comment_id=False):
        if source_redditor is None:
            source_redditor = self.bot_name
        if self.get_reddit_obj_type(object_id)==REDDIT_COMMENT:
            object_id=object_id.replace(REDDIT_COMMENT,'')
            calling_object = self.bot.comment(object_id)
            calling_object.comment_sort = 'new'
        elif self.get_reddit_obj_type(object_id)==REDDIT_LINK:
            object_id=object_id.replace(REDDIT_LINK,'')
            calling_object = self.bot.submission(object_id)
            calling_object.comment_sort = 'new'
            calling_object.reply_sort = 'new'
        try:
            replies = calling_object.comments
            for r in replies:
                if r.author == source_redditor:
                    if return_comment_id:
                        return r
                    else:
                        return True
            return False
        except:
            return False