diff --git a/.gitignore b/.gitignore index 023fe5e..8a565b0 100644 --- a/.gitignore +++ b/.gitignore @@ -101,17 +101,17 @@ ENV/ .mypy_cache/ #my login -login.py -Utlities/login.py +*login.py #pycharm .idea/ #files used by program blockusers.txt -posts_written_to.txt -writes.txt -replies.txt #logs *.log +logs/ + +#good bot bad bot file +comments_written_to.txt \ No newline at end of file diff --git a/README.md b/README.md index 6e285c8..40fddcb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Bot for duplicates # How to use * Unzip -* Create login.py with the following code: +* Go into the modules folder and create login.py with the following code: ```python import praw @@ -17,3 +17,23 @@ reddit = praw.Reddit(username = 'yourusername', password = 'yourpassword', clien * Use + +# Extra scripts + +There are extra scripts that come with the bot. + +## Delete.py + +This script will delete any comment if a person comments delete. It is a mandatory run. + +## gb-bb.py + +This script controls the good bot/bad bot reply part. It is optional. + +## lowpostremover.py + +This script removes any comment below 1 karma. It is optional but recommended. + +## deleteallcomments.py + +If the bot has screwed up and made major mistakes, this script will delete all of the bot's comments. diff --git a/_config.yml b/_config.yml index 3397c9a..0ebaa3d 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1,2 @@ -theme: jekyll-theme-architect \ No newline at end of file +theme: jekyll-theme-architect +show_downloads: true diff --git a/delete.py b/delete.py index e1c53eb..4eab928 100644 --- a/delete.py +++ b/delete.py @@ -1,15 +1,33 @@ -import praw -from login import reddit - - -def main(limit, count=0): - for comment in r.redditor(str(user)).comments.new(limit=limit): - comment.delete() - count = count + 1 - print('Finished comment #'+str(count)) - -if __name__ == '__main__': - limit = input('How many recent comments to delete? Type None for all comments') - count = 0 - main(limit, count) - print('Complete') \ No newline at end of file +import logging +import time + +from modules.logger import setup_logger +from modules.login import reddit + +logger = setup_logger('user_removed_comments') + + +def main(): + try: + for item in reddit.inbox.stream(): + logger.debug('On item {}'.format(str(item))) + try: + if 'delete' in item.body.lower() and item.author == item.submission.author: + item.parent().delete() + logging.info('Comment {} removed'.format(str(item.parent()))) + item.author.message('Removal of comment {}'.format(str(item.parent())), + 'The top level post has been removed.') + except AttributeError: + pass + except: + logging.debug('Item {} skipped'.format(str(item))) + except(KeyboardInterrupt): + raise KeyboardInterrupt + except: + logging.error('Error!', exc_info=True) + main() + + +while True: + main() + time.sleep(30) diff --git a/deleteallcomments.py b/deleteallcomments.py new file mode 100644 index 0000000..35468e7 --- /dev/null +++ b/deleteallcomments.py @@ -0,0 +1,20 @@ +import praw +from modules.logger import setup_logger +from modules.login import reddit as r +import logging + +logger = setup_logger('remove_all_comments') + + +def main(count=0): + for comment in r.redditor(str(r.user.me())).comments.new(limit=None): + comment.delete() + logging.info('Finished comment #'+str(count)+', id {}'.format(str(comment))) + count += 1 + +if __name__ == '__main__': + while True: + try: + main() + except: + logging.error('Error!', exc_info=True) \ No newline at end of file diff --git a/duplicate.py b/duplicate.py index dc5cd62..5c6ebe8 100644 --- a/duplicate.py +++ b/duplicate.py @@ -1,77 +1,176 @@ -from datetime import datetime +# +# +# PPPPPPPPPPPPPPPPP kkkkkkkk +# P::::::::::::::::P k::::::k +# P::::::PPPPPP:::::P k::::::k +# PP:::::P P:::::P k::::::k +# P::::P P:::::P ooooooooooo k:::::k kkkkkkk eeeeeeeeeeee +# P::::P P:::::Poo:::::::::::oo k:::::k k:::::kee::::::::::::ee +# P::::PPPPPP:::::Po:::::::::::::::o k:::::k k:::::ke::::::eeeee:::::ee +# P:::::::::::::PP o:::::ooooo:::::o k:::::k k:::::ke::::::e e:::::e +# P::::PPPPPPPPP o::::o o::::o k::::::k:::::k e:::::::eeeee::::::e +# P::::P o::::o o::::o k:::::::::::k e:::::::::::::::::e +# P::::P o::::o o::::o k:::::::::::k e::::::eeeeeeeeeee +# P::::P o::::o o::::o k::::::k:::::k e:::::::e +# PP::::::PP o:::::ooooo:::::ok::::::k k:::::ke::::::::e +# P::::::::P o:::::::::::::::ok::::::k k:::::ke::::::::eeeeeeee +# P::::::::P oo:::::::::::oo k::::::k k:::::kee:::::::::::::e +# PPPPPPPPPP ooooooooooo kkkkkkkk kkkkkkk eeeeeeeeeeeeee +# SSSSSSSSSSSSSSS tttt +# SS:::::::::::::::S ttt:::t +# S:::::SSSSSS::::::S t:::::t +# S:::::S SSSSSSS t:::::t +# S:::::S ttttttt:::::ttttttt aaaaaaaaaaaaa rrrrr rrrrrrrrr +# S:::::S t:::::::::::::::::t a::::::::::::a r::::rrr:::::::::r +# S::::SSSS t:::::::::::::::::t aaaaaaaaa:::::ar:::::::::::::::::r +# SS::::::SSSSStttttt:::::::tttttt a::::arr::::::rrrrr::::::r +# SSS::::::::SS t:::::t aaaaaaa:::::a r:::::r r:::::r +# SSSSSS::::S t:::::t aa::::::::::::a r:::::r rrrrrrr +# S:::::S t:::::t a::::aaaa::::::a r:::::r +# S:::::S t:::::t tttttta::::a a:::::a r:::::r +# SSSSSSS S:::::S t::::::tttt:::::ta::::a a:::::a r:::::r +# S::::::SSSSSS:::::S tt::::::::::::::ta:::::aaaa::::::a r:::::r +# S:::::::::::::::SS tt:::::::::::tt a::::::::::aa:::ar:::::r +# SSSSSSSSSSSSSSS ttttttttttt aaaaaaaaaa aaaarrrrrrr +# FFFFFFFFFFFFFFFFFFFFFF +# F::::::::::::::::::::F +# F::::::::::::::::::::F +# FF::::::FFFFFFFFF::::F +# F:::::F FFFFFFaaaaaaaaaaaaa nnnn nnnnnnnn +# F:::::F a::::::::::::a n:::nn::::::::nn +# F::::::FFFFFFFFFF aaaaaaaaa:::::an::::::::::::::nn +# F:::::::::::::::F a::::ann:::::::::::::::n +# F:::::::::::::::F aaaaaaa:::::a n:::::nnnn:::::n +# F::::::FFFFFFFFFF aa::::::::::::a n::::n n::::n +# F:::::F a::::aaaa::::::a n::::n n::::n +# F:::::F a::::a a:::::a n::::n n::::n +# FF:::::::FF a::::a a:::::a n::::n n::::n +# F::::::::FF a:::::aaaa::::::a n::::n n::::n +# F::::::::FF a::::::::::aa:::a n::::n n::::n +# FFFFFFFFFFF aaaaaaaaaa aaaa nnnnnn nnnnnn +# +# +# +# +# +# +# import logging +from datetime import datetime + import praw import prawcore -import sys -from login import reddit +from markdowntable import Table as ta +from pokestarfansloggingsetup import setup_logger +from modules.login import reddit -file_handler = logging.FileHandler(filename='duplicates_{}.log'.format(datetime.now().strftime('%m_%d_%y'))) -stdout_handler = logging.StreamHandler(sys.stdout) -handlers = [file_handler, stdout_handler] +logger = setup_logger('duplicates') -logging.basicConfig( - level=logging.INFO, - format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', - handlers=handlers -) -logger = logging.getLogger(__name__) +# noinspection PyBroadException +def generate_and_reply(submission): + starter = ta('Title') + starter.all_columns('Subreddit', 'Author', 'Time', 'Karma') + footer = '\n\n----\n\n I am a bot [FAQ](https://www.reddit.com/r/DuplicatesBot/wiki/index)-[' \ + 'Code](https://github.com/PokestarFan/DuplicateBot)-[Bugs](' \ + 'https://www.reddit.com/r/DuplicatesBot/comments/6ypgmx/bugs_and_problems/)-[Suggestions](' \ + 'https://www.reddit.com/r/DuplicatesBot/comments/6ypg85/suggestion_for_duplicatesbot/)-[Block ' \ + 'user (op only)' \ + '](' \ + 'https://www.reddit.com/message/compose/?to=DuplicatesBotBlocker&subject=remove%20user&message' \ + '={user})-[Block from subreddit (mods only)](' \ + 'https://www.reddit.com/message/compose/?to=DuplicatesBotBlocker&subject=remove%20subreddit' \ + '&message={sub})\n' \ + '\nNow you can remove the comment by replying delete! '.format(user= + str( + submission.author), sub=str(submission.subreddit)) + global message + sub_id = submission.subreddit + for dup_sub in submission.duplicates(): + duplicates = [] + time = dup_sub.created + time = str(datetime.fromtimestamp(time)) + author = '/u/' + str(dup_sub.author) + if str(submission.author) == author: + author = author + ' [author of both threads]' + duplicates.append(['[{}]({})'.format(str(dup_sub.title), 'https://www.reddit.com' + str(dup_sub.permalink)), + '/r/' + str(dup_sub.subreddit), author, str(time), str(dup_sub.score)]) + if len(duplicates) > 0: + message = 'Here is a list of threads in other subreddits about the same content:\n' + for dup in duplicates: + starter.add_row_with_list(dup) + message += '\n' + starter.table + message += '\n' + footer + try: + submission.reply(message) + logger.info('Message posted on {}'.format(str(submission))) + logger.debug('Message: {}'.format(message)) + except(praw.exceptions.APIException, UnboundLocalError): + logger.debug('Submission {} has been skipped due to missing text.'.format(sub_id)) + except prawcore.exceptions.Forbidden: + logger.debug('You are blocked on /r/{}'.format(str(submission.subreddit))) + except AssertionError: + logger.debug('Assertion Error occured! Printing message and traceback.') + logger.debug(message + str(len(message)), exc_info=True) + except(KeyboardInterrupt, SystemExit): + raise + except Exception: + logger.error('Error occurred!', exc_info=True) + except: + logger.critical( + 'Massive Error occurred! Not part of the Exception, KeyboardInterrupt or SystemExit exceptions. Fix ASAP.', + exc_info=True) + finally: + message = '' + + +def run_bot(sub_id): + global blocked_sub + if True: + try: + logging.debug('Starting submission {}'.format(str(sub_id))) + blocked_user = 0 + blocked_sub = 0 + submission = sub_id + try: + with open('blockusers.txt', 'r') as new_file: + for line in new_file.readlines(): + line = line.strip('\n') + if str(submission.author).lower() == line.lower() or 'bot' in str(submission.author).lower(): + blocked_user = 1 + break + except FileNotFoundError: + with open('blockusers.txt', 'w'): + blocked_user = 0 + try: + with open('blockedsubs.txt', 'r') as new_file: + for line in new_file.readlines(): + line = line.strip('\n') + if str(submission.subreddit).lower() == line.lower(): + blocked_sub = 1 + break + except FileNotFoundError: + with open('blockedsubs.txt', 'w'): + blocked_sub = 0 + if blocked_user == 0 and blocked_sub == 0: + generate_and_reply(sub_id) + except(KeyboardInterrupt, SystemExit): + raise + except Exception: + logger.error('Error on submission {} occurred.'.format(str(sub_id)), exc_info=True) + def action(): for sub_id in reddit.subreddit('all').stream.submissions(): - logging.debug('Starting submission {}'.format(sub_id)) - blockeduser = 0 - duplicates = [] - submission = praw.models.Submission(reddit, id = sub_id) - with open('blockusers.txt','r') as newfile: - for line in newfile.readlines(): - line = line.strip('\n') - if str(submission.author) == line or 'bot' in str(submission.author).lower(): - blockeduser = 1 - logger.debug('User {}\'s submission {} was blocked from posting'.format(str(submission.author),str(sub_id))) - else: - pass - if blockeduser == 0: - for duplicate in submission.duplicates(): - dup_sub = praw.models.Submission(reddit, id = duplicate) - if 'imagesof' not in str(dup_sub.subreddit).lower() and 'auto' not in str(dup_sub.subreddit).lower() and 'bot' not in str(dup_sub.author).lower(): - time = dup_sub.created - time = str(datetime.fromtimestamp(time)) - author = str(dup_sub.author) - if str(submission.author) == author: - author = author + '[author of both threads]' - duplicates.append({'title':str(dup_sub.title), 'subreddit':str(dup_sub.subreddit), 'link':'https://www.reddit.com'+str(dup_sub.permalink), 'time':str(time), 'author':author, 'karma': str(dup_sub.score)}) - if len(duplicates) > 0: - message = 'Here is a list of threads in other subreddits about the same content:\n' - for dup in duplicates: - message = str(message + '\n * [{}]({}) on /r/{} with {} karma (created at {} by {})').format(dup['title'], dup['link'], dup['subreddit'], dup['karma'],dup['time'], dup['author']) - message = message + '\n\n ---- \n\n ^^I ^^am ^^a ^^bot ^^[FAQ](https://www.reddit.com/r/DuplicatesBot/wiki/index)-[Code](https://github.com/PokestarFan/DuplicateBot)-[Bugs](https://www.reddit.com/r/DuplicatesBot/comments/6ypgmx/bugs_and_problems/)-[Suggestions](https://www.reddit.com/r/DuplicatesBot/comments/6ypg85/suggestion_for_duplicatesbot/)-[Block](https://www.reddit.com/r/DuplicatesBot/wiki/index#wiki_block_bot_from_tagging_on_your_posts)' - try: - submission.reply(message) - logger.info('Message posted on {}'.format(sub_id)) - logger.debug('Message: {}'.format(message)) - message = '' - except(praw.exceptions.APIException, UnboundLocalError)as e: - logger.info('Submission {} has been skipped due to missing text'.format(sub_id)) - try: - logger.debug('Message: {}'.format(message)) - except: - logger.debug('Message output for exception ') - message = '' - except(prawcore.exceptions.Forbidden): - logger.info('You are blocked on /r/{}'.format(str(submission.subreddit))) - message = '' - except: - logger.error('Error occured!', exc_info=True) - message = '' - + run_bot(sub_id) + if __name__ == '__main__': while True: try: action() - except(KeyboardInterrupt): - raise KeyboardInterrupt - except: - logger.critical('Error has occured when running main loop, please resolve asap', exc_info=True) \ No newline at end of file + except(KeyboardInterrupt, SystemExit): + raise + except Exception: + logger.critical('Error has occured when running main loop, please resolve asap', exc_info=True) diff --git a/entriesadder.py b/entriesadder.py new file mode 100644 index 0000000..21fa0c1 --- /dev/null +++ b/entriesadder.py @@ -0,0 +1,52 @@ +import logging + +from pokestarfansloggingsetup import setup_logger + +from modules.entrylogin import reddit + +logger = setup_logger('usersubblocker') + + +def write_to_user_file(text): + with open('blockusers.txt', 'a') as file: + file.write(text) + + +def write_to_sub_file(text): + with open('blockedsubs.txt', 'a') as file: + file.write(text) + + +def strip_message(message): + try: + if message.subject == 'remove subreddit': + subreddit = reddit.subreddit(message) + mod = False + for moderator in reddit.subreddit(subreddit).moderator(): + if str(message.author) == str(moderator): + mod = True + break + if mod: + write_to_sub_file(message.body) + else: + message.reply('You are not a moderator of the subreddit so your request has not been preformed.') + elif message.subject == 'remove user': + if str(message.author) == message.body: + write_to_user_file(message.body) + else: + message.reply('You are not the OP of the submission so your request has not been preformed.') + except Exception: + logging.warning('', exc_info=True) + + +def check_for_messages(reddit): + try: + for message in reddit.inbox.unread(mark_read=True): + strip_message(message) + reddit.inbox.mark_read(message) + except Exception: + logging.error('error!', exc_info=True) + + +while True: + check_for_messages(reddit) diff --git a/gb-bb.py b/gb-bb.py new file mode 100644 index 0000000..d268de7 --- /dev/null +++ b/gb-bb.py @@ -0,0 +1,56 @@ +import praw +import prawcore +from modules.logger import setup_logger +from modules.login import reddit +import logging +from modules.footer import footer + +logger = setup_logger('good_bot_bad_bot') + +def main(): + try: + for item in reddit.inbox.stream(): + try: + written_to = 0 + text = '' + with open('comments_written_to.txt', 'r') as file: + for line in file.readlines(): + if line == str(item) and written_to == 0: + written_to = 1 + logging.info('Comment {} has been already replied to.'.format(str(item))) + if written_to == 0: + if 'good bot' in str(item.body.lower()): + text = 'Good human' + item.reply(text+footer) + logging.info('Message with the text {} replied to comment {}'.format(text, str(item))) + with open('comments_written_to.txt', 'a') as file: + file.write(str(item)+'\n') + elif 'bad bot' in str(item.body.lower()): + text = 'Bad human' + item.reply(text+footer) + logging.info('Message with the text {} replied to comment {}'.format(text, str(item))) + with open('comments_written_to.txt', 'a') as file: + file.write(str(item)+'\n') + elif 'average bot' in str(item.body.lower()): + text = 'Average human' + item.reply(text+footer) + logging.info('Message with the text {} replied to comment {}'.format(text, str(item))) + with open('comments_written_to.txt', 'a') as file: + file.write(str(item)+'\n') + except(prawcore.exceptions.Forbidden): + logging.info('Blocked on /r/{}'.format(str(item.subreddit))) + except(KeyboardInterrupt): + raise KeyboardInterrupt + except Exception as e: + logging.error('Error on item {}. {}'.format(str(item),str(e)), exc_info=True) + except(KeyboardInterrupt): + raise KeyboardInterrupt + except Exception as e: + logging.critical('Error on main loop! {}'.format(str(e)), exc_info=True) + +if __name__ == '__main__': + while True: + try: + main() + except(KeyboardInterrupt): + raise KeyboardInterrupt \ No newline at end of file diff --git a/goodbadbot.py b/goodbadbot.py deleted file mode 100644 index 6241bd8..0000000 --- a/goodbadbot.py +++ /dev/null @@ -1,27 +0,0 @@ -import time -import praw -from login import reddit - - -def main(): - while True: - for item in reddit.inbox.all(limit=5): - with open('replies.txt', 'r') as readfile: - for line in readfile.readlines(): - if line == item: - pass - else: - try: - if 'good' and 'bot' in item.body: - item.reply('Good human') - with open('replies.txt', 'a') as file: - file.write(str(item)+'\n') - elif 'bad' and 'bot' in item.body: - item.reply('bad human') - with open('replies.txt', 'a') as file: - file.write(str(item)+'\n') - except: - pass - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/lowpostremover.py b/lowpostremover.py index 85a2c9b..86011c5 100644 --- a/lowpostremover.py +++ b/lowpostremover.py @@ -9,10 +9,14 @@ import time import praw -from login import reddit as r +from modules.logger import setup_logger +from modules.login import reddit as r +import logging + +logger = setup_logger('low_score_remover') ########################### -# definitions +# defistarnitions ########################### #defining the log in process @@ -23,61 +27,13 @@ #defining the searching and removal def action(): - global submission_titles #making global submission title list - global comment_submissions #making glocal comment submission title list - comment_submissions = [] - submission_titles = [] - submission_number = 0 - comment_number = 0 - current_submission_number = 0 - current_comment_number = 0 - print('Searching...') user = r.user.me() - for submission in r.redditor(str(user)).submissions.new(limit=None): #scanning all submissions by reddit user without limit - if submission.score < setvalue: #if statement checking the submission score < 0 - submission.delete() #deleting the submission - submission_titles.append(submission.title) #adding the submission title to the list for comment in r.redditor(str(user)).comments.new(limit=None): #scanning all comments by reddit user without limit + logging.debug('On comment {}'.format(str(comment))) if comment.score < setvalue: #if statement checking the comment score < 0 comment.delete() #deleteing the comment if < 0 - comment_submissions.append(comment.submission.title) #adding the comment's original submission title to the list - -#defining the outputs -def print_results(): - print('Search Complete') - print('--------------------------------------------------') - #if statement. True if there is 1 or more submissions removed. - if len(submission_titles) > 0: - #printing true results - print('Removed ' + str(len(submission_titles)) + ' submission(s).') - print('Submission title(s) include: ') - print(*submission_titles, sep='\n') #printing submission titles with line breaks - print('--------------------------------------------------') - else: - #printing false results - print('No submissions removed.') - print('--------------------------------------------------') - #if statement. True if there is 1 or more comments removed. - if len(comment_submissions) > 0: - #printing true results - print('Removed ' + str(len(comment_submissions)) + ' comment(s).') - print('Comments were under the following submissions: ') - print(*comment_submissions, sep='\n') #printing comment's submission's titles with line breaks - print('--------------------------------------------------') - else: - #printing false results - print('No comments removed.') - print('--------------------------------------------------') - -########################### -# code execution -########################### - + logging.info('Removed comment {}'.format(str(comment))) -def main(): - action() - print_results() - -while True: - main() - time.sleep(600) \ No newline at end of file +while True: + action() + time.sleep(60) \ No newline at end of file diff --git a/modules/logger.py b/modules/logger.py new file mode 100644 index 0000000..102cd48 --- /dev/null +++ b/modules/logger.py @@ -0,0 +1,19 @@ +import logging +from datetime import datetime +import sys + + +def setup_logger(name, loglevel=logging.INFO): + file_handler = logging.FileHandler(filename='logs/{}_{}.log'.format(name, datetime.now().strftime('%m_%d_%y'))) + stdout_handler = logging.StreamHandler(sys.stdout) + handlers = [file_handler, stdout_handler] + + logging.basicConfig( + level=loglevel, + format='[%(asctime)s] {%(filename)s:%(lineno)d} (%(funcName)s) %(levelname)s - %(message)s', + handlers=handlers + ) + + logger = logging.getLogger(__name__) + return logger + diff --git a/modules/table.py b/modules/table.py new file mode 100644 index 0000000..c2bb0ef --- /dev/null +++ b/modules/table.py @@ -0,0 +1,4 @@ +from markdowntable import Table as ta + +starter = ta('Title') +starter.all_columns('Subreddit','Author','Time','Karma') \ No newline at end of file diff --git a/run.bat b/run.bat new file mode 100644 index 0000000..3cf1a42 --- /dev/null +++ b/run.bat @@ -0,0 +1,5 @@ +@echo off +start py duplicate.py +start py delete.py +start py lowpostremover.py +start py gb-bb.py \ No newline at end of file diff --git a/updateblockedusers.bat b/updateblockedusers.bat new file mode 100644 index 0000000..50a1554 --- /dev/null +++ b/updateblockedusers.bat @@ -0,0 +1,4 @@ +@echo off +SET /P somevar= Username: +echo %somevar%>>blockusers.txt +updateblockedusers.bat