Beispiel #1
0
def load_pgpool_accounts(count, reuse=False):
    addl_text = " Reusing previous accounts." if reuse else ""
    log.info("Trying to load {} accounts from PGPool.{}".format(
        count, addl_text))
    if count == 1:
        accounts = {}
    else:
        accounts = []
    for x in range(count):
        if (not 'auth_service' in load_pgpool_accounts.PreviousAccount) or (
                load_pgpool_accounts.AccUsed >= 3):
            request = {
                'system_id': cfg_get('pgpool_system_id'),
                'count': 1,
                'min_level': cfg_get('level'),
                'reuse': reuse
            }
            r = requests.get("{}/account/request".format(
                cfg_get('pgpool_url')),
                             params=request)
            load_pgpool_accounts.PreviousAccount = r.json()
            load_pgpool_accounts.AccUsed = 0
            accounts.append(r.json())
        else:
            load_pgpool_accounts.AccUsed += 1
            accounts.append(load_pgpool_accounts.PreviousAccount)
    return accounts
Beispiel #2
0
def load_accounts(jobs):
    accounts_file = cfg_get('accounts_file')

    accounts = []
    if accounts_file:
        log.info("Loading accounts from file {}.".format(accounts_file))
        with open(accounts_file, 'r') as f:
            for num, line in enumerate(f, 1):
                fields = line.split(",")
                fields = map(str.strip, fields)
                accounts.append(
                    ScoutGuard(fields[0], fields[1], fields[2], jobs))
    elif cfg_get('pgpool_url') and cfg_get(
            'pgpool_system_id') and cfg_get('pgpool_num_accounts') > 0:

        acc_json = load_pgpool_accounts(cfg_get('pgpool_num_accounts'),
                                        reuse=True)
        if isinstance(acc_json, dict):
            acc_json = [acc_json]

        if len(acc_json) > 0:
            log.info("Loaded {} accounts from PGPool.".format(len(acc_json)))
            for acc in acc_json:
                accounts.append(
                    ScoutGuard(acc['auth_service'], acc['username'],
                               acc['password'], jobs))

    if len(accounts) == 0:
        log.error("Could not load any accounts. Nothing to do. Exiting.")
        sys.exit(1)

    return accounts
Beispiel #3
0
def get_iv():
    if not app_state.accept_new_requests:
        return reject('Not accepting new requests.')
    if not have_active_scouts():
        return reject('No active scout available. All banned?')

    pokemon_id = request.args["pokemon_id"]
    pokemon_name = get_pokemon_name(pokemon_id)
    forced = request.args.get('forced')
    prio = PRIO_HIGH if forced is not None else get_pokemon_prio(pokemon_id)

    cache_enable = cfg_get('cache_timer') > 0
    max_queued_jobs = cfg_get('max_queued_jobs')
    num_jobs = jobs.qsize()
    if max_queued_jobs and num_jobs >= max_queued_jobs and prio == PRIO_LOW:
        return reject(
            "Job queue full ({} items). Rejecting encounter with priority '{}'."
            .format(num_jobs, PRIO_NAMES[prio]))

    lat = request.args["latitude"]
    lng = request.args["longitude"]
    weather = request.args.get("weather", "unknown")

    encounter_id = normalize_encounter_id(request.args.get("encounter_id"))
    # Spawn point ID is assumed to be a hex string
    spawn_point_id = request.args.get("spawn_point_id")
    despawn_time = request.args.get("despawn_time")

    if cache_enable:
        # Check cache
        cache_key = "{}-{}".format(
            encounter_id, weather) if encounter_id else "{}-{}-{}".format(
                pokemon_id, lat, lng)
        result = get_cached_encounter(cache_key)
        if result:
            log.info(
                u"Returning cached result: {:.1f}% level {} {} with {} CP".
                format(result['iv_percent'], result['level'], pokemon_name,
                       result['cp']))
            return jsonify(result)

    # Create a ScoutJob
    job = ScoutJob(pokemon_id,
                   encounter_id,
                   spawn_point_id,
                   lat,
                   lng,
                   despawn_time=despawn_time)

    # Enqueue and wait for job to be processed
    jobs.put((prio, time.time(), job))
    while not job.processed:
        time.sleep(1)

    # Cache successful jobs and return result
    if cache_enable and job.result['success']:
        cache_encounter(cache_key, job.result)
    return jsonify(job.result)
Beispiel #4
0
    def run(self):
        self.log_info("Waiting for job...")
        while True:
            (prio, t, job) = self.job_queue.get()
            try:
                if job.expired():
                    self.log_warning(
                        u"Scout job for {} at {}, {} expired. Rejecting.".format(job.pokemon_name, job.lat, job.lng))
                    job.result = self.scout_error(self.last_msg)
                    continue

                self.log_info(u"Scouting a {} at {}, {} with {} priority".format(job.pokemon_name, job.lat, job.lng,
                                                                                 PRIO_NAMES[prio]))

                # Initialize API
                (lat, lng) = jitter_location(job.lat, job.lng)
                self.set_position(lat, lng, job.altitude)
                if not self.check_login():
                    job.result = self.scout_error(self.last_msg)
                    if self.is_banned() or self.has_captcha():
                        if cfg_get('discord_webhook'):
                            self.post_discord_webhook(banned=True)
                        break
                    else:
                        continue

                if job.encounter_id and job.spawn_point_id:
                    job.result = self.scout_by_encounter_id(job)
                else:
                    if self.find_pokemon(job):
                        time.sleep(2)
                        job.result = self.scout_by_encounter_id(job)
                    else:
                        job.result = self.scout_error("Could not determine encounter_id for {} at {}, {}".format(job.pokemon_name, job.lat, job.lng))

                # Mark shadowbanned if too many errors
                sb_threshold = cfg_get('shadowban_threshold')
                if sb_threshold and self.errors >= sb_threshold:
                    self.shadowbanned = True

                if self.shadowbanned:
                    self.log_warning("Account probably shadowbanned. Stopping.")
                    if cfg_get('discord_webhook'):
                        self.post_discord_webhook(shadowbanned=True)
                    break

            except (AuthException, BannedAccountException, CaptchaException) as e:
                job.result = self.scout_error(self.last_msg)
                if cfg_get('discord_webhook'):
                    self.post_discord_webhook(banned=True)
                break
            except Exception:
                job.result = self.scout_error(repr(sys.exc_info()))
            finally:
                job.processed = True
Beispiel #5
0
def load_pgpool_accounts(count, reuse=False):
    addl_text = " Reusing previous accounts." if reuse else ""
    log.info("Trying to load {} accounts from PGPool.{}".format(count, addl_text))
    request = {
        'system_id': cfg_get('pgpool_system_id'),
        'count': count,
        'min_level': cfg_get('level'),
        'reuse': reuse
    }
    r = requests.get("{}/account/request".format(cfg_get('pgpool_url')), params=request)
    return r.json()
Beispiel #6
0
 def post_discord_webhook(self, banned=False, shadowbanned=False):
     running_time = (time.time() - self.start_time)/ 3600.0
     if banned:
         message = "Account {} (Level {}) is banned or has captcha after {} encounters ({:.2f} hours). Releasing.".format(self.username,
                                                                                   self.get_stats('level'), self.total_encounters, running_time)
     elif shadowbanned:
         message = "Account {} (Level {}) is probably shadowbanned after {} encounters ({:.2f} hours). Releasing.".format(self.username,
                                                                                       self.get_stats('level'), self.total_encounters, running_time)
     else:
         message = self.last_msg
     if discord_webhook(cfg_get('discord_user', cfg_get('pgpool_system_id')), message):
         self.log_info("Message posted to Discord")
     else:
         self.log_warn("Error posting message to Discord")
Beispiel #7
0
    def __init__(self, auth, username, password, job_queue):
        self.auth = auth
        self.username = username
        self.password = password
        self.job_queue = job_queue

        # Stats
        self.last_request = None
        self.previous_encounter = None
        self.last_msg = ""
        self.total_encounters = 0

        # Things needed for requests
        self.inventory_timestamp = None

        # Collects the last few pauses between encounters to measure a "encounters per hour" value
        self.past_pauses = deque()
        self.encounters_per_hour = float(0)

        # instantiate pgoapi
        self.api = PGoApi()
        self.api.activate_hash_server(cfg_get('hash_key'))

        if have_proxies():
            self.proxy = get_new_proxy()
            self.log_info("Using Proxy: {}".format(self.proxy))
            self.api.set_proxy({
                'http': self.proxy,
                'https': self.proxy
            })
Beispiel #8
0
    def check_login(self):
        # Logged in? Enough time left? Cool!
        if self.api._auth_provider and self.api._auth_provider._ticket_expire:
            remaining_time = self.api._auth_provider._ticket_expire / 1000 - time.time()
            if remaining_time > 60:
                self.log_debug(
                    'Credentials remain valid for another {} seconds.'.format(remaining_time))
                return

        # Try to login. Repeat a few times, but don't get stuck here.
        num_tries = 0
        # One initial try + login_retries.
        while num_tries < 3:
            try:
                self.api.set_authentication(
                    provider=self.auth,
                    username=self.username,
                    password=self.password)
                break
            except AuthException:
                num_tries += 1
                self.log_error(
                    'Failed to login. ' +
                    'Trying again in {} seconds.'.format(6))
                time.sleep(6)

        if num_tries >= 3:
            self.log_error(
                'Failed to login for {} tries. Giving up.'.format(
                    num_tries))
            raise TooManyLoginAttempts('Exceeded login attempts.')

        wait_after_login = cfg_get('wait_after_login')
        self.log_info('Login successful. Waiting {} more seconds.'.format(wait_after_login))
        time.sleep(wait_after_login)
Beispiel #9
0
def print_scouts(lines, state, scouts):
    def scout_line(current_line, scout_guard):
        scout = scout_guard.acc
        warn = scout.get_state('warn')
        warn_str = '' if warn is None else ('Yes' if warn else 'No')
        active = 'Yes' if scout_guard.active else 'No'
        if cfg_get('proxies'):
            return line_tmpl.format(
                current_line, scout.username, scout.proxy_url, warn_str,
                active, scout.total_encounters,
                "{:5.1f}".format(scout.encounters_per_hour),
                hr_tstamp(scout.previous_encounter), scout.last_msg)
        else:
            return line_tmpl.format(
                current_line, scout.username, warn_str, active,
                scout.total_encounters,
                "{:5.1f}".format(scout.encounters_per_hour),
                hr_tstamp(scout.previous_encounter), scout.last_msg)

    len_username = str(
        reduce(lambda l1, l2: max(l1, l2),
               map(lambda s: len(s.acc.username), scouts)))
    len_num = str(len(str(len(scouts))))
    if cfg_get('proxies'):
        line_tmpl = u'{:' + len_num + '} | {:' + len_username + '} | {:25} | {:4} | {:6} | {:10} | {:5} | {:14} | {}'
        lines.append(
            line_tmpl.format('#', 'Scout', 'Proxy', 'Warn', 'Active',
                             'Encounters', 'Enc/h', 'Last Encounter',
                             'Message'))
    else:
        line_tmpl = u'{:' + len_num + '} | {:' + len_username + '} | {:4} | {:6} | {:10} | {:5} | {:14} | {}'
        lines.append(
            line_tmpl.format('#', 'Scout', 'Warn', 'Active', 'Encounters',
                             'Enc/h', 'Last Encounter', 'Message'))
    return print_lines(lines, scout_line, scouts, 4, state)
Beispiel #10
0
def cache_cleanup_thread():
    minutes = cfg_get('cache_timer')
    while True:
        time.sleep(60)
        num_deleted = cleanup_cache(minutes)
        log.info(
            "Cleaned up {} entries from encounter cache.".format(num_deleted))
Beispiel #11
0
    def __init__(self, auth, username, password, job_queue):
        super(Scout, self).__init__(auth, username, password,
                                    hash_key_provider=cfg_get('hash_key_provider'),
                                    proxy_provider=cfg_get('proxy_provider'))

        self.job_queue = job_queue

        # Stats
        self.previous_encounter = None
        self.total_encounters = 0

        # Collects the last few pauses between encounters to measure a "encounters per hour" value
        self.past_pauses = deque()
        self.encounters_per_hour = float(0)

        # Number of errors that may be the cause of a shadowban
        self.errors = 0
Beispiel #12
0
def get_iv():
    error = None
    if not app_state.accept_new_requests:
        error = 'Not accepting new requests.'
    if not have_active_scouts():
        error = 'No active scout available. All banned?'
    max_queued_jobs = cfg_get('max_queued_jobs')
    num_jobs = jobs.qsize()
    if max_queued_jobs and num_jobs >= max_queued_jobs:
        error = "Job queue full ({} items). Perform less encounters or add more scouts.".format(
            num_jobs)

    if error:
        log.warning(error)
        return jsonify({'success': False, 'error': error})

    pokemon_id = request.args["pokemon_id"]
    pokemon_name = get_pokemon_name(pokemon_id)
    lat = request.args["latitude"]
    lng = request.args["longitude"]
    weather = request.args.get("weather", "unknown")

    encounter_id = normalize_encounter_id(request.args.get("encounter_id"))
    # Spawn point ID is assumed to be a hex string
    spawn_point_id = request.args.get("spawn_point_id")
    despawn_time = request.args.get("despawn_time")

    # Check cache
    cache_key = "{}-{}".format(encounter_id,
                               weather) if encounter_id else "{}-{}-{}".format(
                                   pokemon_id, lat, lng)
    result = get_cached_encounter(cache_key)
    if result:
        log.info(
            u"Returning cached result: {:.1f}% level {} {} with {} CP".format(
                result['iv_percent'], result['level'], pokemon_name,
                result['cp']))
        return jsonify(result)

    # Create a ScoutJob
    job = ScoutJob(pokemon_id,
                   encounter_id,
                   spawn_point_id,
                   lat,
                   lng,
                   despawn_time=despawn_time)

    # Enqueue and wait for job to be processed
    jobs.put(job)
    while not job.processed:
        time.sleep(1)

    # Cache successful jobs and return result
    if job.result['success']:
        cache_encounter(cache_key, job.result)
    return jsonify(job.result)
Beispiel #13
0
def load_accounts(jobs):
    accounts_file = cfg_get('accounts_file')

    accounts = []
    if accounts_file:
        log.info("Loading accounts from file {}.".format(accounts_file))
        with codecs.open(accounts_file, mode='r', encoding='utf-8') as f:
            for line in f:
                fields = line.split(",")
                fields = map(unicode.strip, fields)
                accounts.append(ScoutGuard(fields[0], fields[1], fields[2], jobs))
    elif cfg_get('pgpool_url') and cfg_get('pgpool_system_id') and cfg_get('pgpool_num_accounts') > 0:

        acc_json = load_pgpool_accounts(cfg_get('pgpool_num_accounts'), reuse=True)
        if isinstance(acc_json, dict) and len(acc_json) > 0:
            acc_json = [acc_json]

        for i in range(0, cfg_get('pgpool_num_accounts')):
            if i < len(acc_json):
                accounts.append(ScoutGuard(acc_json[i]['auth_service'], acc_json[i]['username'], acc_json[i]['password'],
                                           jobs))
            else:
                #We are using PGPool, load empty ScoutGuards that can be filled later
                accounts.append(ScoutGuard(auth="", username="******", password="", job_queue=jobs))

    if len(accounts) == 0:
        log.error("Could not load any accounts. Nothing to do. Exiting.")
        sys.exit(1)

    return accounts
Beispiel #14
0
    def __init__(self, auth, username, password, job_queue, duplicate):
        super(Scout,
              self).__init__(auth,
                             username,
                             password,
                             hash_key_provider=cfg_get('hash_key_provider'),
                             proxy_provider=cfg_get('proxy_provider'))

        self.job_queue = job_queue

        # Stats
        self.start_time = time.time()
        self.previous_encounter = None
        self.total_encounters = 0
        self.duplicate = duplicate  # 0 = master account, 1 = duplicate account, 2 = release duplicate account from semaphore loop

        # Collects the last few pauses between encounters to measure a "encounters per hour" value
        self.past_pauses = deque()
        self.encounters_per_hour = float(0)

        # Number of errors that may be the cause of a shadowban
        self.errors = 0
Beispiel #15
0
def init_resoures_from_file(name, filename_key):
    resources = []
    resource_file = cfg_get(filename_key)
    if resource_file:
        try:
            with open(resource_file) as f:
                for line in f:
                    # Ignore blank lines and comment lines.
                    if len(line.strip()) == 0 or line.startswith('#'):
                        continue
                    resource = line.strip()
                    resources.append(resource)
        except IOError:
            log.exception('Could not load {} from {}.'.format(resource_file))
            exit(1)
    return resources
Beispiel #16
0
    def __init__(self, auth, username, password, job_queue):
        self.auth = auth
        self.username = username
        self.password = password
        self.job_queue = job_queue

        # Stats
        self.last_request = None
        self.last_msg = ""
        self.total_scouts = 0

        # Holds timestamps of scout requests of the last hour
        self.history = deque()

        # instantiate pgoapi
        self.api = PGoApi()
        self.api.activate_hash_server(cfg_get('hash_key'))
Beispiel #17
0
 def scout_line(current_line, scout_guard):
     scout = scout_guard.acc
     warn = scout.get_state('warn')
     warn_str = '' if warn is None else ('Yes' if warn else 'No')
     active = 'Yes' if scout_guard.active else 'No'
     if cfg_get('proxies'):
         return line_tmpl.format(
             current_line, scout.username, scout.proxy_url, warn_str,
             active, scout.total_encounters,
             "{:5.1f}".format(scout.encounters_per_hour),
             hr_tstamp(scout.previous_encounter), scout.last_msg)
     else:
         return line_tmpl.format(
             current_line, scout.username, warn_str, active,
             scout.total_encounters,
             "{:5.1f}".format(scout.encounters_per_hour),
             hr_tstamp(scout.previous_encounter), scout.last_msg)
Beispiel #18
0
    def run(self):
        self.log_info("Waiting for job...")
        while True:
            job = self.job_queue.get()
            try:
                self.log_info(u"Scouting a {} at {}, {}".format(
                    job.pokemon_name, job.lat, job.lng))
                # Initialize API
                (lat, lng) = jitter_location(job.lat, job.lng)
                self.set_position(lat, lng, job.altitude)
                if not self.check_login():
                    job.result = self.scout_error(self.last_msg)
                    continue

                # Check if banned.
                if self.is_banned():
                    job.result = self.scout_error("Account banned")
                    break

                if job.encounter_id and job.spawn_point_id:
                    job.result = self.scout_by_encounter_id(job)
                else:
                    if self.find_pokemon(job):
                        time.sleep(2)
                        job.result = self.scout_by_encounter_id(job)
                    else:
                        job.result = self.scout_error(
                            "Could not determine encounter_id for {} at {}, {}"
                            .format(job.pokemon_name, job.lat, job.lng))

                # Check shadowban status
                if self.shadowbanned or self.errors >= cfg_get(
                        'shadowban_threshold'):
                    self.shadowbanned = True
                    self.log_warning(
                        "Account probably shadowbanned. Stopping.")
                    break

            except:
                job.result = self.scout_error(repr(sys.exc_info()))
            finally:
                job.processed = True
                self.update_history()
Beispiel #19
0
    def __init__(self,
                 pokemon_id,
                 encounter_id,
                 spawn_point_id,
                 lat,
                 lng,
                 despawn_time=None):
        self.pokemon_id = int(pokemon_id)
        self.pokemon_name = get_pokemon_name(pokemon_id)
        self.encounter_id = encounter_id
        self.spawn_point_id = spawn_point_id
        self.lat = float(lat)
        self.lng = float(lng)
        self.despawn_time = despawn_time

        self.processed = False
        self.result = {}

        # Set a time when this job expires if a TTL was given
        ttl = cfg_get('max_job_ttl')
        self.expire_at = time.time() + (ttl * 60) if ttl else None

        # Use fixed random altitude per job
        self.altitude = random.randint(12, 108)
Beispiel #20
0
    def parse_encounter_response(self, responses, job):
        if not responses:
            return self.scout_error("Empty encounter response.")

        if self.has_captcha():
            return self.scout_error("Scout account captcha'd.")

        encounter = responses.get('ENCOUNTER', {})
        enc_status = encounter.get('status', None)

        # Check for shadowban - ENCOUNTER_BLOCKED_BY_ANTICHEAT
        if enc_status == 8:
            self.shadowbanned = True

        if enc_status != 1:
            return self.scout_error(ENCOUNTER_RESULTS[enc_status])

        if 'wild_pokemon' not in encounter:
            return self.scout_error("No wild pokemon info found.")

        scout_level = self.player_stats['level']
        if scout_level < cfg_get("require_min_trainer_level"):
            return self.scout_error(
                "Trainer level {} is too low. Needs to be {}+".format(
                    scout_level, cfg_get("require_min_trainer_level")))

        pokemon_info = encounter['wild_pokemon']['pokemon_data']
        cp = pokemon_info['cp']
        pokemon_level = calc_pokemon_level(pokemon_info['cp_multiplier'])
        probs = encounter['capture_probability']['capture_probability']

        at = pokemon_info.get('individual_attack', 0)
        df = pokemon_info.get('individual_defense', 0)
        st = pokemon_info.get('individual_stamina', 0)
        iv = calc_iv(at, df, st)
        moveset_grades = get_moveset_grades(job.pokemon_id, job.pokemon_name,
                                            pokemon_info['move_1'],
                                            pokemon_info['move_2'])

        responses = {
            'success': True,
            'encounter_id': job.encounter_id,
            'encounter_id_b64': b64encode(str(job.encounter_id)),
            'height': pokemon_info['height_m'],
            'weight': pokemon_info['weight_kg'],
            'gender': pokemon_info['pokemon_display']['gender'],
            'iv_percent': iv,
            'iv_attack': at,
            'iv_defense': df,
            'iv_stamina': st,
            'move_1': pokemon_info['move_1'],
            'move_2': pokemon_info['move_2'],
            'rating_attack': moveset_grades['offense'],
            'rating_defense': moveset_grades['defense'],
            'cp': cp,
            'cp_multiplier': pokemon_info['cp_multiplier'],
            'level': pokemon_level,
            'catch_prob_1': probs[0],
            'catch_prob_2': probs[1],
            'catch_prob_3': probs[2],
            'scout_level': scout_level,
            'encountered_time': time.time()
        }

        # Add form of Unown
        if job.pokemon_id == 201:
            responses['form'] = pokemon_info['pokemon_display'].get('form',
                                                                    None)

        self.log_info(
            u"Found a {:.1f}% ({}/{}/{}) L{} {} with {} CP (scout level {}).".format(
                iv, at, df, st, pokemon_level, job.pokemon_name, cp, scout_level))
        inc_for_pokemon(job.pokemon_id)
        return responses
Beispiel #21
0
def check_proxies():

    source_proxies = []

    check_results = [0] * (check_result_max + 1)

    # Load proxies from the file if such a file is configured.
    proxies_file = cfg_get('proxies_file')
    if not proxies_file:
        return source_proxies

    log.info('Loading proxies from file {}.'.format(proxies_file))

    try:
        with open(proxies_file) as f:
            for line in f:
                # Ignore blank lines and comment lines.
                if len(line.strip()) == 0 or line.startswith('#'):
                    continue
                source_proxies.append(line.strip())
    except IOError:
        log.error('Could not load proxies from {}.'.format(proxies_file))
        return []

    log.info('Loaded {} proxies.'.format(len(source_proxies)))

    if len(source_proxies) == 0:
        log.error('Proxy file {} was configured but ' +
                  'no proxies were loaded. Aborting.'.format(proxies_file))
        sys.exit(1)

    proxy_queue = Queue()
    total_proxies = len(source_proxies)

    log.info('Checking proxies...')

    working_proxies = []

    for proxy in enumerate(source_proxies):
        proxy_queue.put(proxy)

        t = Thread(target=check_proxy,
                   name='check_proxy',
                   args=(proxy_queue, 5, working_proxies, check_results))
        t.daemon = True
        t.start()

    # This is painful but we need to wait here until proxy_queue is
    # completed so we have a working list of proxies.
    proxy_queue.join()

    num_working_proxies = len(working_proxies)

    if num_working_proxies == 0:
        log.error('Proxies were configured but no working ' +
                  'proxies were found. Aborting.')
        sys.exit(1)
    else:
        other_fails = (check_results[check_result_failed] +
                       check_results[check_result_wrong] +
                       check_results[check_result_exception] +
                       check_results[check_result_empty])
        log.info('Proxy check completed. Working: %d, banned: %d, ' +
                 'timeout: %d, other fails: %d of total %d configured.',
                 num_working_proxies, check_results[check_result_banned],
                 check_results[check_result_timeout],
                 other_fails,
                 total_proxies)
        return working_proxies
Beispiel #22
0
def run_webserver():
    app.run(threaded=True, port=cfg_get('port'))
Beispiel #23
0
    def parse_encounter_response(self, responses, job):
        if not responses:
            return self.scout_error("Empty encounter response")

        if self.has_captcha():
            return self.scout_error("Account captcha'd")

        if self.is_banned():
            return self.scout_error("Account banned")

        encounter = responses.get('ENCOUNTER')
        if not encounter:
            return self.scout_error("No encounter result returned.")
        if not encounter.HasField('wild_pokemon'):
            self.errors += 1
            return self.scout_error("No wild pokemon info found.")

        enc_status = encounter.status

        # Check for shadowban - ENCOUNTER_BLOCKED_BY_ANTICHEAT
        if enc_status == 8:
            self.errors += 1
            self.shadowbanned = True

        if enc_status != 1:
            return self.scout_error(ENCOUNTER_RESULTS[enc_status])

        scout_level = self.get_stats('level')
        if scout_level < cfg_get('level'):
            return self.scout_error(
                "Trainer level {} is too low. Needs to be {}+".format(
                    scout_level, cfg_get("level")))

        pokemon_info = encounter.wild_pokemon.pokemon_data
        cp = pokemon_info.cp
        pokemon_level = calc_pokemon_level(pokemon_info.cp_multiplier)
        probs = encounter.capture_probability.capture_probability

        at = pokemon_info.individual_attack
        df = pokemon_info.individual_defense
        st = pokemon_info.individual_stamina
        iv = calc_iv(at, df, st)
        moveset_grades = get_moveset_grades(job.pokemon_id, job.pokemon_name,
                                            pokemon_info.move_1,
                                            pokemon_info.move_2)

        responses = {
            'success': True,
            'encounter_id': job.encounter_id,
            'encounter_id_b64': b64encode(str(job.encounter_id)),
            'height': pokemon_info.height_m,
            'weight': pokemon_info.weight_kg,
            'gender': pokemon_info.pokemon_display.gender,
            'iv_percent': iv,
            'iv_attack': at,
            'iv_defense': df,
            'iv_stamina': st,
            'move_1': pokemon_info.move_1,
            'move_2': pokemon_info.move_2,
            'rating_attack': moveset_grades['offense'],
            'rating_defense': moveset_grades['defense'],
            'cp': cp,
            'cp_multiplier': pokemon_info.cp_multiplier,
            'level': pokemon_level,
            'catch_prob_1': probs[0],
            'catch_prob_2': probs[1],
            'catch_prob_3': probs[2],
            'scout_level': scout_level,
            'encountered_time': time.time()
        }

        # Add form of Unown
        if job.pokemon_id == 201:
            responses['form'] = pokemon_info.pokemon_display.form

        self.log_info(
            u"Found a {:.1f}% ({}/{}/{}) L{} {} with {} CP (scout level {}).".
            format(iv, at, df, st, pokemon_level, job.pokemon_name, cp,
                   scout_level))
        inc_for_pokemon(job.pokemon_id)
        return responses
Beispiel #24
0
def check_proxies():

    source_proxies = []

    check_results = [0] * (check_result_max + 1)

    # Load proxies from the file if such a file is configured.
    proxies_file = cfg_get('proxies_file')
    if not proxies_file:
        return source_proxies

    log.info('Loading proxies from file {}.'.format(proxies_file))

    try:
        with open(proxies_file) as f:
            for line in f:
                # Ignore blank lines and comment lines.
                if len(line.strip()) == 0 or line.startswith('#'):
                    continue
                source_proxies.append(line.strip())
    except IOError:
        log.error('Could not load proxies from {}.'.format(proxies_file))
        return []

    log.info('Loaded {} proxies.'.format(len(source_proxies)))

    if len(source_proxies) == 0:
        log.error('Proxy file {} was configured but ' +
                  'no proxies were loaded. Aborting.'.format(proxies_file))
        sys.exit(1)

    proxy_queue = Queue()
    total_proxies = len(source_proxies)

    log.info('Checking proxies...')

    working_proxies = []

    for proxy in enumerate(source_proxies):
        proxy_queue.put(proxy)

        t = Thread(target=check_proxy,
                   name='check_proxy',
                   args=(proxy_queue, 5, working_proxies, check_results))
        t.daemon = True
        t.start()

    # This is painful but we need to wait here until proxy_queue is
    # completed so we have a working list of proxies.
    proxy_queue.join()

    num_working_proxies = len(working_proxies)

    if num_working_proxies == 0:
        log.error('Proxies were configured but no working ' +
                  'proxies were found. Aborting.')
        sys.exit(1)
    else:
        other_fails = (check_results[check_result_failed] +
                       check_results[check_result_wrong] +
                       check_results[check_result_exception] +
                       check_results[check_result_empty])
        log.info(
            'Proxy check completed. Working: %d, banned: %d, ' +
            'timeout: %d, other fails: %d of total %d configured.',
            num_working_proxies, check_results[check_result_banned],
            check_results[check_result_timeout], other_fails, total_proxies)
        return working_proxies
Beispiel #25
0
    app.run(threaded=True, port=cfg_get('port'))


def cache_cleanup_thread():
    while True:
        time.sleep(60)
        num_deleted = cleanup_cache()
        log.info(
            "Cleaned up {} entries from encounter cache.".format(num_deleted))


# ===========================================================================

log.info("PGScout starting up.")

with open(cfg_get('accounts_file'), 'r') as f:
    for num, line in enumerate(f, 1):
        fields = line.split(",")
        fields = map(str.strip, fields)
        scout = Scout(fields[0], fields[1], fields[2], jobs)
        scouts.append(scout)
        t = Thread(target=scout.run, name="{}".format(scout.username))
        t.daemon = True
        t.start()

# Cleanup cache in background
t = Thread(target=cache_cleanup_thread, name="cache_cleaner")
t.daemon = True
t.start()

# Start thread to print current status and get user input.
Beispiel #26
0
log.info("PGScout starting up.")

cfg_init()

scouts = load_accounts(jobs)
for scout in scouts:
    t = Thread(target=scout.run)
    t.daemon = True
    t.start()

# Cleanup cache in background
t = Thread(target=cache_cleanup_thread, name="cache_cleaner")
t.daemon = True
t.start()

# Start thread to print current status and get user input.
t = Thread(target=print_status,
           name='status_printer', args=(scouts, cfg_get('initial_view'), jobs))
t.daemon = True
t.start()

# Launch the webserver
t = Thread(target=run_webserver, name='webserver')
t.daemon = True
t.start()

# Catch SIGINT to exit
signal.signal(signal.SIGINT, signal_handler)
while True:
    time.sleep(1)
Beispiel #27
0
            log.exception('Could not load {} from {}.'.format(resource_file))
            exit(1)
    return resources


# ===========================================================================

log.info("PGScout starting up.")

init_mr_mime()

init_proxies()

hash_key_provider = CyclicResourceProvider()

hash_key = cfg_get('hash_key')
if hash_key and len(hash_key) > 0:
    hash_key_provider.add_resource(hash_key)
    log.info("Loaded single hash key from config.")

hash_keys = cfg_get('hash_keys')
if hash_keys and len(hash_keys) > 0:
    for hk in hash_keys:
        hash_key_provider.add_resource(hk)
    log.info("Loaded {} hash keys from config.".format(len(hash_keys)))

hash_keys = init_resoures_from_file('hash keys', 'hash_key_file')
if hash_keys and len(hash_keys) > 0:
    for hk in hash_keys:
        hash_key_provider.add_resource(hk)
    log.info("Loaded {} hash keys from file {}.".format(
Beispiel #28
0
    def parse_encounter_response(self, responses, job):
        if not responses:
            return self.scout_error("Empty encounter response.")

        if self.has_captcha():
            return self.scout_error("Scout account captcha'd.")

        encounter = responses.get('ENCOUNTER', {})
        enc_status = encounter.get('status', None)

        # Check for shadowban - ENCOUNTER_BLOCKED_BY_ANTICHEAT
        if enc_status == 8:
            self.shadowbanned = True

        if enc_status != 1:
            return self.scout_error(ENCOUNTER_RESULTS[enc_status])

        if 'wild_pokemon' not in encounter:
            return self.scout_error("No wild pokemon info found.")

        scout_level = self.player_stats['level']
        if scout_level < cfg_get("require_min_trainer_level"):
            return self.scout_error(
                "Trainer level {} is too low. Needs to be {}+".format(
                    scout_level, cfg_get("require_min_trainer_level")))

        pokemon_info = encounter['wild_pokemon']['pokemon_data']
        cp = pokemon_info['cp']
        pokemon_level = calc_pokemon_level(pokemon_info['cp_multiplier'])
        probs = encounter['capture_probability']['capture_probability']

        at = pokemon_info.get('individual_attack', 0)
        df = pokemon_info.get('individual_defense', 0)
        st = pokemon_info.get('individual_stamina', 0)
        iv = calc_iv(at, df, st)
        moveset_grades = get_moveset_grades(job.pokemon_id, job.pokemon_name,
                                            pokemon_info['move_1'],
                                            pokemon_info['move_2'])

        responses = {
            'success': True,
            'encounter_id': job.encounter_id,
            'encounter_id_b64': b64encode(str(job.encounter_id)),
            'height': pokemon_info['height_m'],
            'weight': pokemon_info['weight_kg'],
            'gender': pokemon_info['pokemon_display']['gender'],
            'iv_percent': iv,
            'iv_attack': at,
            'iv_defense': df,
            'iv_stamina': st,
            'move_1': pokemon_info['move_1'],
            'move_2': pokemon_info['move_2'],
            'rating_attack': moveset_grades['offense'],
            'rating_defense': moveset_grades['defense'],
            'cp': cp,
            'cp_multiplier': pokemon_info['cp_multiplier'],
            'level': pokemon_level,
            'catch_prob_1': probs[0],
            'catch_prob_2': probs[1],
            'catch_prob_3': probs[2],
            'scout_level': scout_level,
            'encountered_time': time.time()
        }

        # Add form of Unown
        if job.pokemon_id == 201:
            responses['form'] = pokemon_info['pokemon_display'].get('form',
                                                                    None)

        self.log_info(
            u"Found a {:.1f}% ({}/{}/{}) L{} {} with {} CP (scout level {}).".format(
                iv, at, df, st, pokemon_level, job.pokemon_name, cp, scout_level))
        inc_for_pokemon(job.pokemon_id)
        return responses
Beispiel #29
0
def get_pokemon_prio(pokemon_id):
    low_prio_pokemon = cfg_get('low_prio_pokemon')
    return PRIO_NORMAL if low_prio_pokemon and int(
        pokemon_id) not in low_prio_pokemon else PRIO_LOW
Beispiel #30
0
def status(page=1):
    def td(cell):
        return "<td>{}</td>".format(cell)

    max_scouts_per_page = 25
    max_page = int(math.ceil(len(scouts) / float(max_scouts_per_page)))
    lines = "<style> th,td { padding-left: 10px; padding-right: 10px; border: 1px solid #ddd; } table { border-collapse: collapse } td { text-align:center }</style>"
    lines += "<meta http-equiv='Refresh' content='5'>"
    lines += "Accepting requests: {} | Job queue length: {} | Cached encounters: {} | Mem Usage: {}".format(
        app_state.accept_new_requests, jobs.qsize(), get_cached_count(),
        rss_mem_size())
    lines += "<br><br>"

    if cfg_get('proxies'):
        headers = [
            '#', 'Scout', 'Proxy', 'Start', 'Warn', 'Active', 'Encounters',
            'Enc/h', 'Errors', 'Last Encounter', 'Message'
        ]
    else:
        headers = [
            '#', 'Scout', 'Start', 'Warn', 'Active', 'Encounters', 'Enc/h',
            'Errors', 'Last Encounter', 'Message'
        ]

    lines += "<table><tr>"
    for h in headers:
        lines += "<th>{}</th>".format(h)
    lines += "</tr>"

    if page * max_scouts_per_page > len(
            scouts):  #Page number is too great, set to last page
        page = max_page
    if page < 1:
        page = 1
    for i in range((page - 1) * max_scouts_per_page,
                   page * max_scouts_per_page):
        if i >= len(scouts):
            break
        lines += "<tr>"
        s = scouts[i].acc
        warn = s.get_state('warn')
        warn_str = '' if warn is None else ('Yes' if warn else 'No')
        lines += td(i + 1)
        lines += td(s.username)
        lines += td(s.proxy_url) if cfg_get('proxies') else ""
        lines += td(hr_tstamp(s.start_time))
        lines += td(warn_str)
        lines += td('Yes' if scouts[i].active else 'No')
        lines += td(s.total_encounters)
        lines += td("{:5.1f}".format(s.encounters_per_hour))
        lines += td(s.errors)
        lines += td(hr_tstamp(s.previous_encounter))
        lines += td(s.last_msg.encode('utf-8'))
        lines += "</tr>"
    lines += "</table>"

    # Encounters
    enctotal = 0
    active = 0
    for scout in scouts:
        enctotal = enctotal + (scout.acc.encounters_per_hour
                               if scout.active else 0.0)
        active = active + (1 if scout.active else 0)
    lines += "<br>"
    lines += "Enc/hr Total:   {:5.0f} ({} active)".format(enctotal, active)
    lines += "<br>"

    if len(
            scouts
    ) > max_scouts_per_page:  # Use pages if we have more than max_scouts_per_page
        lines += "Page: "
        if max_page > 1 and page > 1:
            lines += "<a href={}>&lt;</a> | ".format(
                url_for('status', page=page - 1))
        for p in range(1, max_page + 1):
            if p == page:
                lines += str(p)
            else:
                url = url_for('status', page=p)
                lines += "<a href={}>{}</a>".format(url, p)
            if p < max_page:
                lines += " | "
        if max_page > 1 and page < max_page:
            lines += " | <a href={}>&gt;</a>".format(
                url_for('status', page=page + 1))

    return lines
Beispiel #31
0
    sys.exit(0)


# ===========================================================================

log.info("PGScout starting up.")

cfg_init()

scouts = load_accounts(jobs)
for scout in scouts:
    t = Thread(target=scout.run, args=(scouts))
    t.daemon = True
    t.start()

if cfg_get('cache_timer') > 0:
    # Cleanup cache in background
    t = Thread(target=cache_cleanup_thread, name="cache_cleaner")
    t.daemon = True
    t.start()

# Start thread to print current status and get user input.
t = Thread(target=print_status,
           name='status_printer',
           args=(scouts, cfg_get('initial_view'), jobs))
t.daemon = True
t.start()

# Launch the webserver
t = Thread(target=run_webserver, name='webserver')
t.daemon = True
Beispiel #32
0
def get_iv():
    if not app_state.accept_new_requests:
        return jsonify({
            'success': False,
            'error': 'Not accepting new requests.'
        })
        payload = {}
        payload['encounter_id'] = normalized['encounter_id']
        payload['pokemon_id'] = normalized['pokemon_id']
        payload['latitude'] = normalized['lat']
        payload['longitude'] = normalized['lon']
        payload[
            'error'] = "PGSCOUT ONTVANGEN, PGSCOUT ACCEPTEERT GEEN NIEUWE REQUESTS"
        response = requests.post('http://192.168.1.101:1418/test6',
                                 json=payload)
    #return_iv(request.args)
    payload = {}
    payload['encounter_id'] = request.args["encounter_id"]
    payload['pokemon_id'] = request.args["pokemon_id"]
    payload['latitude'] = request.args["latitude"]
    payload['longitude'] = request.args["longitude"]
    payload['pokehunt_id'] = request.args['pokehunt_id']
    #response = requests.post('http://192.168.1.101:1418/test3', json=payload)
    pokemon_id = request.args["pokemon_id"]
    pokemon_name = get_pokemon_name(pokemon_id)
    lat = request.args["latitude"]
    lng = request.args["longitude"]
    encounter_id = normalize_encounter_id(request.args.get("encounter_id"))
    spawn_point_id = normalize_spawn_point_id(
        request.args.get("spawn_point_id"))
    pokehunt_id = request.args["pokehunt_id"]

    # Check cache
    cache_key = encounter_id if encounter_id else "{}-{}-{}".format(
        pokemon_id, lat, lng)
    result = get_cached_encounter(cache_key)
    if result:
        log.info(
            u"Returning cached result: {:.1f}% level {} {} with {} CP".format(
                result['iv_percent'], result['level'], pokemon_name,
                result['cp']))
        response = requests.post(cfg_get('customwebhook'), json=job.result)
        if (response.status_code != 200):
            log.error("Error sending webhook: {}".format(
                response.raise_for_status()))
            return jsonify({
                'success': False,
                'error': 'Not accepting new requests.'
            })
        else:
            return jsonify({'success': True})

    # Create a ScoutJob
    job = ScoutJob(pokemon_id, encounter_id, spawn_point_id, lat, lng,
                   pokehunt_id)
    jobs.put(job)

    # Enqueue and wait for job to be processed NO
    return jsonify({
        'success': True,
    })