def find_text(text, x1, y1, x2, y2): import emu_manager hwnd = emu_manager.get_instance( int(BotConfig().get_property("Emulator", "use_device"))) image = region_grabber_v2((x1, y1, x2, y2), hwnd) # image.save('testarea.png') # useful for debugging purposes, this will save the captured region as "testarea.png" image = np.array(image) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # check to see if we should apply thresholding to preprocess the # image # if args["preprocess"] == "thresh": # gray = cv2.threshold(gray, 0, 255, # cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # make a check to see if median blurring should be done to remove # noise # elif args["preprocess"] == "blur": # gray = cv2.medianBlur(gray, 3) # write the grayscale image to disk as a temporary file so we can # apply OCR to it filename = "temp.png" cv2.imwrite(filename, gray) # load the image as a PIL/Pillow image, apply OCR, and then delete # the temporary file Image.open(filename) result = pytesseract.image_to_string(Image.open(filename)) os.remove(filename) logger.info( "Text on screen: \"{}\", text to find: \"{}\", return: {}".format( result, text, text in result)) return text in result
def run(args): logging.info('Starting bot') config = BotConfig(args.config) logging.info('Will use next config parameters:\n%s' % config) global global_broker global_broker = TransmissionBroker(config, Persistence(config.persistence_file)) global global_updater global_updater = Updater(token=config.token) dispatcher = global_updater.dispatcher dispatcher.add_error_handler(telegram_error) list_handler = CommandHandler('list', list_command) dispatcher.add_handler(list_handler) add_handler = CommandHandler('add', add_command) dispatcher.add_handler(add_handler) stop_handler = CommandHandler('stop', stop_command) dispatcher.add_handler(stop_handler) remove_handler = CommandHandler('remove', remove_command) dispatcher.add_handler(remove_handler) help_handler = CommandHandler('help', help_command) dispatcher.add_handler(help_handler) start_handler = CommandHandler('start', start_command) dispatcher.add_handler(start_handler) secret_handler = CommandHandler('secret', secret_command) dispatcher.add_handler(secret_handler) os_handler = CommandHandler('uname', os_command) dispatcher.add_handler(os_handler) unknown_handler = MessageHandler([Filters.command], help_command) dispatcher.add_handler(unknown_handler) global_updater.start_polling() global global_error_exit global_updater.is_idle = True while global_updater.is_idle: if global_error_exit: global_updater.stop() sys.exit(1) time.sleep(0.1)
def do_main_loop(run_time, start_time=time.time(), hwnd=None): logger.info("Starting main task...") # test() time.sleep(1) # Turn on buff buffs = bot_cfg.get_buff_config() buff_on(buffs) while time.time() - start_time < run_time: # Show map panel while True: pos = screen_processor.abs_search("enter_map.png", ENTER_MAP_BOX) if pos[0] != -1: break # Click on map 20 emu_manager.mouse_click(MAP_20[0], MAP_20[1]) time.sleep(0.5) # Check for realm tickets first if realm_obj.is_max_tickets(MAP_PANEL_DISPLAY): if int(bot_cfg.get_property("Realm", "stop_map_farming_when_full_ticket")): # Quit farming logger.info("Realm tickets are full! Quitting farming..") break if bot_cfg.get_property("Realm", "auto_farm"): time.sleep(1) emu_manager.mouse_click(1050, 174, 1) enter_realm(start_time, run_time) if time.time() - start_time > run_time: # Finish break # emu_manager.mouse_click(1050, 174, 1) # enter_realm(start_time, run_time) # if time.time() - start_time > run_time: # # Finish # break # Check for payk payk_img = bot_cfg.get_payk_image() if payk_img is not None and len(payk_img) > 0: if screen_processor.abs_search(payk_img, click=True)[0] != -1: logger.info("Found payk {}".format(payk_img)) # Close map popup emu_manager.mouse_click(1042, 182) time.sleep(1) # Click again screen_processor.abs_search(payk_img, click=True) while screen_processor.abs_search("payk_fight_btn.png", click=True)[0] == -1: time.sleep(0.5) # if screen_processor.abs_search("payk_fight_btn.png", click=True)[0] != -1: logger.info("Creating party for payk") time.sleep(0.5) emu_manager.mouse_click(*PARTY_INVITE_ALL) emu_manager.mouse_click(*PARTY_CREATE_BTN) while screen_processor.abs_search("realm_back_btn.png")[0] == 1: emu_manager.mouse_click(*PARTY_START) logger.info("Starting payk battle..") emu_manager.mouse_click(*BATTLE_START_BTN) # Wait for map while screen_processor.abs_search("back.png", BACK_BTN_BOX)[0] == -1: time.sleep(0.5) # Click center of the screen with some offset emu_manager.mouse_click(663, 317) logger.info("Got back to map from payk battle!") continue enter_map() time.sleep(1) while True: mob_pos, is_boss = find_mobs_with_buff(fight_boss=BotConfig().should_fight_boss()) if mob_pos[0] != -1: process_battle(mob_pos, is_boss) if is_boss: # Finished this map break else: # TODO remove hard code here util.click_image("back.png", (16, 71)) # Confirm exit map emu_manager.mouse_click(EXIT_MAP_OK_BTN[0], EXIT_MAP_OK_BTN[1]) screen_processor.wait("buff_btn.png", BUFF_BTN_BOX, click=False) # time.sleep(2) # Click on map 20 in case of boss found in map break time.sleep(1) FINISHED_MAIN_LOOP = True logger.info("Ended main loop. Ran for {} seconds".format(time.time() - start_time)) logger.info("Turning off buffs...") # Turn off exp buff buff_off(buffs)
import win32con import bot_config from bot_config import BotConfig from common import * import emu_manager import time import screen_processor import util from realm import Realm, TICKET_AREAS, MAP_PANEL_DISPLAY, MAX_TICKETS FINISHED_MAIN_LOOP = False debug = 0 realm_obj = Realm() bot_cfg = BotConfig() logger = util.get_logger() def set_up(): logger.info("Setting up emulator...") # Find Nox and bring to foreground hwnd = emu_manager.get_instance(int(bot_cfg.get_property("Emulator", "use_device"))) if not hwnd: logger.info("ERROR!!! Could not get Nox instance") return logger.info("Got Nox player!") win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) # logger.info("Got Nox player 1!")
import subprocess import time import win32gui from bot_config import BotConfig from common import EMULATOR_CONFIGS NOX_ADB_PATH = BotConfig().get_emulator_path() EMU_ID = BotConfig().get_property("Emulator", "use_device") def mouse_click(x, y, sleep=0.2): subprocess.Popen("{} shell input tap {} {}".format(get_adb_prefix(), x, y)) time.sleep(sleep) def mouse_drag(x1, y1, x2, y2, duration=1500): subprocess.Popen("{} shell input swipe {} {} {} {} {}".format( get_adb_prefix(), x1, y1, x2, y2, duration)) def get_adb_prefix(): return "\"{}\\bin\\adb\" -s {}".format( NOX_ADB_PATH, EMULATOR_CONFIGS.get(EMU_ID).get("id")) def get_instance(index, force_start=True): win_title = "NoxPlayer" if index == 0 else "NoxPlayer{}".format(index) hwnd = win32gui.FindWindow(None, win_title) if not hwnd:
def do_all(): ''' Main moderation method ''' def save_changes(post_file, posts, users_file, users): ''' Save user and post files between runs ''' posts_file.seek(0) json.dump(posts, posts_file) posts_file.truncate() users_file.seek(0) json.dump(users, users_file) users_file.truncate() logger = logging.getLogger('feedback_bot') logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) logger.addHandler(ch) credentials = BotCredentials.from_config() # Loading credentials botConfig = BotConfig.from_config() # Loading configuration ''' Creating reddit praw client ''' reddit = praw.Reddit(client_id=credentials.client_id, client_secret=credentials.client_secret, user_agent=credentials.user_agent, username=credentials.bot_username, password=credentials.bot_password) ''' Requesting target subreddit ''' subreddit = reddit.subreddit(credentials.subreddit) logger.info('Starting moderation !') create_file_if_not_exit('users.json') create_file_if_not_exit('posts.json') with open('users.json', 'r+') as users_file, open('posts.json', 'r+') as posts_file: try: users = json.load(users_file) except JSONDecodeError: users = {} try: posts = json.load(posts_file) except JSONDecodeError: posts = {} if (not users) and (not posts): firstRun = True else: firstRun = False submissions = [] # Getting all the considered posts and storing them for temp_submission in subreddit.new(limit=botConfig.look_back_posts): submissions.append(temp_submission) # We iterate through the post in reverse chronological order so the score are up to date for new posts for submission in reversed(submissions): try: submission_author = submission.author.name logger.info("looking at submission {} from {}".format( submission.id, submission_author)) if not submission.id in posts: remove = False remove_reason = "" posts[submission.id] = {} posts[submission.id]["feedbacks"] = [] logger.info('New post found {}'.format(submission.id)) if not submission_author in users: remove = True remove_reason = "lowScore" users[submission_author] = {} users[submission_author]["posts"] = 0 users[submission_author]["feedbacks"] = 0 author_history = users[submission_author] else: author_history = users[submission_author] compiled_regex = map(lambda x: re.compile(x), botConfig.filter_regex) if (author_history["posts"] + 1) * botConfig.score_needed > author_history[ "feedbacks"]: remove = True remove_reason = "lowScore" elif (any( map(lambda x: x.match(submission.url), compiled_regex))): logger.info( submission.url + 'Should be removed for matching forbidden regex' ) remove = True remove_reason = "forbidden_regex" else: author_history[ "posts"] = author_history["posts"] + 1 users[submission_author] = author_history if firstRun: logger.info('recording the post for the first run') author_history["posts"] = author_history["posts"] + 1 users[submission_author] = author_history elif remove: logger.info('Removing {} because {}'.format( submission.id, remove_reason)) submission.mod.remove() if remove_reason == "lowScore": message = """ Bleep bloop I'm a bot.\n Sorry your submission was removed.\n Your score is only {} and you need at least {} to post.\n You need to give feedback on at least {} track(s) and try again !\n *If you just gave enough feedback but your score wasn't credited, try again in a few minutes, the score update takes a little time*\n You can know your score at anytime by Direct Messaging me (the bot) with the word "SCORE" as a subject.\n Please repost your song once you have a score of {}. """.format( author_history["feedbacks"] - (author_history["posts"]) * botConfig.score_needed, botConfig.score_needed, botConfig.score_needed - (author_history["feedbacks"] - (author_history["posts"]) * botConfig.score_needed), botConfig.score_needed) elif remove_reason == "forbidden_regex": message = """ Bleep bloop I'm a bot.\n Sorry your submission was removed.\n I detected that you were linking to a playlist... we only allow you to post one song at a time.\n Playlists are difficult to give feedback on, and this goes against the 1 song - {} comment system\n Please repost your music one song at a time and try again ! """.format(botConfig.score_needed) message = re.sub('\t', '', message) submission.mod.send_removal_message( message, title='submission removed', type='public') else: logger.info('Validating post {}'.format(submission.id)) message = """ Bleep bloop I'm a bot.\n Your submission was approved u/{}, thank you for posting !\n You can know your score at anytime by Direct Messaging me (the bot) with the word "SCORE" as a subject. """.format(submission_author) message = re.sub('\t', '', message) submission.reply(message) # Looking at comments from post to register potential new feedback comments = submission.comments.list() submission_feedbackers = posts[submission.id]["feedbacks"] for comment in comments: try: comment_author = comment.author.name if not comment_author == submission_author: if not comment_author in users: users[comment_author] = {} users[comment_author]["posts"] = 0 users[comment_author]["feedbacks"] = 0 if not comment_author in submission_feedbackers and comment.banned_by == None: logger.info( "new feedback from {} registered on {}". format(comment_author, submission.id)) if len(comment.body ) < botConfig.minimum_comment_length: logger.info( "new feedback is too short to be good") comment.reply_sort = 'new' comment.refresh() replies_authors = list( map(lambda x: x.author.name, comment.replies)) if not "IndieFeedbackBot" in replies_authors: logger.info( "first time seen, commenting to let the author know" ) msg_comment = """ Bleep bloop I'm a bot.\n Sorry, this comment won't count in your score, because it's not at least {} characters long :/\n """.format(minimum_comment_length) msg_comment = re.sub( '\t', '', msg_comment) comment.reply(msg_comment) else: submission_feedbackers.append( comment_author) users[comment_author]["feedbacks"] = users[ comment_author]["feedbacks"] + 1 feedbackers_set = set(submission_feedbackers) posts[submission.id]["feedbacks"] = list( feedbackers_set) except: logger.warning( "comment registering went wrong {}".format( str(comment))) except Exception as e: logger.warning( "submission registering went wrong {} {}".format( str(submission), e)) save_changes(posts_file, posts, users_file, users) # Replying to DMs asking for score for message in reddit.inbox.unread(mark_read=True, limit=None): if isinstance(message, Message): message.mark_read() if message.subject.lower() == "score" or message.body.lower( ) == "score": dm_author = message.author print('Sending score DM to {}'.format(dm_author.name)) if dm_author.name in users: dm_author_posts = users[dm_author.name]["posts"] dm_author_feedbacks = users[ dm_author.name]["feedbacks"] message.reply('Your score currently is {}'.format( dm_author_feedbacks - dm_author_posts * botConfig.score_needed)) else: pass message.reply('Your score currently is 0')
import inspect import unittest from datetime import time from unittest import TestCase from assertpy import assert_that from timebetween import is_time_between from bot_config import BotConfig from discord_utils import choose_member_from, find_role, sanitize_env_vars, SAFE_KEYS, current_configuration, \ SAFE_CONFIG_VARS, sanitize_config, health from member import Member from role import Role test_config = BotConfig("discord token", "guild name", "bot name", "started at", "heroku key") class TestDiscordUtils(TestCase): def test_time(self): start = time(7, 0) end = time(19, 0) inside_of_interval = time(11, 0) outside_of_interval = time(20, 0) assert_that(is_time_between(inside_of_interval, start, end)).is_true() assert_that(is_time_between(outside_of_interval, start, end)).is_false() def test_choose_member(self): m1 = Member("foo")
from PIL import Image # load the example image and convert it to grayscale import pytesseract import util from bot_config import BotConfig from common import WINDOW_WIDTH, WINDOW_HEIGHT from imagesearch import region_grabber, imagesearcharea, imagesearcharea_v2, region_grabber_v2 from util import click_image class ImageNotFoundException(Exception): pass IMAGE_FOLDER = BotConfig().get_property("General", "image_folder") logger = util.get_logger() # TODO test import emu_manager hwnd = emu_manager.get_instance( int(BotConfig().get_property("Emulator", "use_device"))) def find_text(text, x1, y1, x2, y2): import emu_manager hwnd = emu_manager.get_instance( int(BotConfig().get_property("Emulator", "use_device"))) image = region_grabber_v2((x1, y1, x2, y2), hwnd) # image.save('testarea.png') # useful for debugging purposes, this will save the captured region as "testarea.png"