Compare commits

..

4 Commits

7 changed files with 35 additions and 146 deletions

View File

@ -4,7 +4,7 @@
__author__ = """Eriks Karls""" __author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv' __email__ = 'eriks@72.lv'
__version__ = '0.24.0.2' __version__ = '0.23.4.16'
from erepublik import classes, constants, utils from erepublik import classes, constants, utils
from erepublik.citizen import Citizen from erepublik.citizen import Citizen

View File

@ -418,8 +418,10 @@ class ErepublikMilitaryAPI(CitizenBaseAPI):
data = dict(_token=self.token, sideCountryId=side_id, battleId=battle_id) data = dict(_token=self.token, sideCountryId=side_id, battleId=battle_id)
return self.post(f"{self.url}/main/battlefieldTravel", data=data) return self.post(f"{self.url}/main/battlefieldTravel", data=data)
def _post_main_battlefield_change_division(self, battle_id: int, division_id: int) -> Response: def _post_main_battlefield_change_division(self, battle_id: int, division_id: int, side_id: int = None) -> Response:
data = dict(_token=self.token, battleZoneId=division_id, battleId=battle_id) data = dict(_token=self.token, battleZoneId=division_id, battleId=battle_id)
if side_id is not None:
data.update(sideCountryId=side_id)
return self.post(f"{self.url}/main/battlefieldTravel", data=data) return self.post(f"{self.url}/main/battlefieldTravel", data=data)
def _get_wars_show(self, war_id: int) -> Response: def _get_wars_show(self, war_id: int) -> Response:
@ -455,39 +457,9 @@ class ErepublikMilitaryAPI(CitizenBaseAPI):
data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id) data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post(f"{self.url}/military/fight-shooot/{battle_id}", data=data) return self.post(f"{self.url}/military/fight-shooot/{battle_id}", data=data)
def _post_fight_deploy_deploy_report_data(self, deployment_id: int) -> Response: def _post_fight_deploy_deploy_report_data(self, deployment_id: int):
data = dict(_token=self.token, deploymentId=deployment_id) data = dict(_token=self.token, deploymentId=deployment_id)
return self.post(f"{self.url}/military/fightDeploy-deployReportData", data=data) return self.post(f"{self.url}/military/fightDeploy-deployReportData", json=data)
def _post_fight_deploy_get_inventory(self, battle_id: int, side_id: int, battle_zone_id: int) -> Response:
data = dict(_token=self.token, battleId=battle_id, sideCountryId=side_id, battleZoneId=battle_zone_id)
return self.post(f"{self.url}/military/fightDeploy-getInventory", data=data)
def _post_fight_deploy_start_deploy(
self, battle_id: int, side_id: int, battle_zone_id: int, energy: int, weapon: int, **kwargs
) -> Response:
data = dict(_token=self.token, battleId=battle_id, battleZoneId=battle_zone_id, sideCountryId=side_id,
weaponQuality=weapon, totalEnergy=energy, **kwargs)
return self.post(f"{self.url}/military/fightDeploy-startDeploy", data=data)
def _get_main_session_captcha(self) -> Response:
return self.get(f'{self.url}/main/sessionCaptcha')
def _get_main_session_unlock_popup(self) -> Response:
return self.get(f'{self.url}/main/sessionUnlockPopup')
def _post_main_session_get_challenge(self, captcha_id: int) -> Response:
env = dict(l=['tets', ], s=[], c=["l_chathwe", "l_chatroom"], m=0)
data = dict(_token=self.token, captchaId=captcha_id, env=utils.b64json(env))
return self.post(f'{self.url}/main/sessionGetChallenge', data=data)
def _post_main_session_unlock(
self, captcha: int, image: str, challenge: str, coords: List[Dict[str, int]], src: str
) -> Response:
env = dict(l=['tets', ], s=[], c=["l_chathwe", "l_chatroom"], m=0)
data = dict(_token=self.token, captchaId=captcha, imageId=image, challengeId=challenge,
clickMatrix=utils.json.dumps(coords), isMobile=0, env=utils.b64json(env), src=src)
return self.post(f'{self.url}/main/sessionUnlock', data=data)
class ErepublikPoliticsAPI(CitizenBaseAPI): class ErepublikPoliticsAPI(CitizenBaseAPI):

View File

@ -27,7 +27,6 @@ class BaseCitizen(access_points.CitizenAPI):
eb_normal: int = 0 eb_normal: int = 0
eb_double: int = 0 eb_double: int = 0
eb_small: int = 0 eb_small: int = 0
eb_triple: int = 0
division: int = 0 division: int = 0
maverick: bool = False maverick: bool = False
@ -242,27 +241,6 @@ class BaseCitizen(access_points.CitizenAPI):
""" """
self._update_inventory_data(self._get_economy_inventory_items().json()) self._update_inventory_data(self._get_economy_inventory_items().json())
def do_captcha_challenge(self) -> bool:
r = self._get_main_session_captcha()
data = re.search(r'\$j\.extend\(SERVER_DATA,([^)]+)\)', r.text)
if data:
data = utils.json_loads(utils.normalize_html_json(data.group(1)))
captcha_id = data.get('sessionValidation', {}).get("captchaId")
captcha_data = self._post_main_session_get_challenge(captcha_id).json()
coordinates = self.solve_captcha(captcha_data.get('src'))
r = self._post_main_session_unlock(
captcha_id, captcha_data['imageId'], captcha_data['challengeId'], coordinates, captcha_data['src']
).json()
if not r.get('error') and r.get('verified'):
return True
else:
self.report_error('Captcha failed!')
return self.do_captcha_challenge()
return False
def solve_captcha(self, src: str) -> List[Dict[str, int]]:
raise NotImplemented
@property @property
def inventory(self) -> classes.Inventory: def inventory(self) -> classes.Inventory:
return self.get_inventory() return self.get_inventory()
@ -293,7 +271,7 @@ class BaseCitizen(access_points.CitizenAPI):
return return
self._last_inventory_update = self.now self._last_inventory_update = self.now
self.food.update(q1=0, q2=0, q3=0, q4=0, q5=0, q6=0, q7=0) self.food.update(q1=0, q2=0, q3=0, q4=0, q5=0, q6=0, q7=0)
self.eb_triple = self.eb_small = self.eb_double = self.eb_normal = 0 self.eb_small = self.eb_double = self.eb_normal = 0
active_items: types.InvFinal = {} active_items: types.InvFinal = {}
if data.get('activeEnhancements', {}).get('items', {}): if data.get('activeEnhancements', {}).get('items', {}):
for item_data in data.get('activeEnhancements', {}).get('items', {}).values(): for item_data in data.get('activeEnhancements', {}).get('items', {}).values():
@ -311,8 +289,7 @@ class BaseCitizen(access_points.CitizenAPI):
expiration_info = [_expire_value_to_python(v) for v in expire_info['value']] expiration_info = [_expire_value_to_python(v) for v in expire_info['value']]
if not item_data.get('icon') and item_data.get('isPackBooster'): if not item_data.get('icon') and item_data.get('isPackBooster'):
item_data['icon'] = f"//www.erepublik.com/images/icons/boosters/52px/{item_data.get('type')}.png" item_data['icon'] = f"//www.erepublik.com/images/icons/boosters/52px/{item_data.get('type')}.png"
icon = item_data['icon'] if item_data[ icon = item_data['icon'] if item_data['icon'] else "//www.erepublik.net/images/modules/manager/tab_storage.png"
'icon'] else "//www.erepublik.net/images/modules/manager/tab_storage.png"
inv_item: types.InvFinalItem = dict( inv_item: types.InvFinalItem = dict(
name=item_data.get('name'), time_left=item_data['active']['time_left'], icon=icon, name=item_data.get('name'), time_left=item_data['active']['time_left'], icon=icon,
kind=kind, expiration=expiration_info, quality=item_data.get('quality', 0) kind=kind, expiration=expiration_info, quality=item_data.get('quality', 0)
@ -356,12 +333,15 @@ class BaseCitizen(access_points.CitizenAPI):
self.eb_normal = amount self.eb_normal = amount
elif q == 11: elif q == 11:
self.eb_double = amount self.eb_double = amount
item_data.update(token='energy_bar') elif q == 13:
elif 11 < q < 17: self.eb_small += amount
elif q == 14:
self.eb_small += amount
elif q == 15:
self.eb_small += amount self.eb_small += amount
item_data.update(token='energy_bar') item_data.update(token='energy_bar')
elif q == 17: elif q == 16:
self.eb_triple = amount self.eb_small += amount
item_data.update(token='energy_bar') item_data.update(token='energy_bar')
kind = re.sub(r'_q\d\d*', "", item_data.get('token')) kind = re.sub(r'_q\d\d*', "", item_data.get('token'))
@ -547,7 +527,7 @@ class BaseCitizen(access_points.CitizenAPI):
ret = super().as_dict ret = super().as_dict
ret.update( ret.update(
name=self.name, __str__=self.__str__(), name=self.name, __str__=self.__str__(),
ebs=dict(normal=self.eb_normal, double=self.eb_double, small=self.eb_small, triple=self.eb_triple), ebs=dict(normal=self.eb_normal, double=self.eb_double, small=self.eb_small),
promos=self.promos, inventory=self._inventory.as_dict, ot_points=self.ot_points, food=self.food, promos=self.promos, inventory=self._inventory.as_dict, ot_points=self.ot_points, food=self.food,
division=self.division, maveric=self.maverick, eday=self.eday, wheel_of_fortune=self.wheel_of_fortune, division=self.division, maveric=self.maverick, eday=self.eday, wheel_of_fortune=self.wheel_of_fortune,
debug=self.debug, debug=self.debug,
@ -717,10 +697,12 @@ class BaseCitizen(access_points.CitizenAPI):
self.eb_normal -= amount self.eb_normal -= amount
elif q == '11': elif q == '11':
self.eb_double -= amount self.eb_double -= amount
elif 11 < int(q) < 17: elif q == '12':
self.eb_small -= amount
elif q == '15':
self.eb_small -= amount
elif q == '16':
self.eb_small -= amount self.eb_small -= amount
elif q == '17':
self.eb_triple -= amount
next_recovery = r_json.get('food_remaining_reset').split(":") next_recovery = r_json.get('food_remaining_reset').split(":")
self.energy.set_reference_time( self.energy.set_reference_time(
utils.good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2]))) utils.good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
@ -761,9 +743,6 @@ class BaseCitizen(access_points.CitizenAPI):
pass pass
if response.status_code >= 400: if response.status_code >= 400:
self.r = response self.r = response
if response.text == 'Please verify your account.':
self.do_captcha_challenge()
return True
if response.status_code >= 500: if response.status_code >= 500:
if self.restricted_ip: if self.restricted_ip:
self._req.cookies.clear() self._req.cookies.clear()
@ -2005,16 +1984,18 @@ class CitizenMilitary(CitizenTravel):
self._report_action('MILITARY_BOMB', f"Deployed {deployed_count} bombs in battle {battle.id}") self._report_action('MILITARY_BOMB', f"Deployed {deployed_count} bombs in battle {battle.id}")
return deployed_count return deployed_count
def change_division(self, battle: classes.Battle, division: classes.BattleDivision) -> bool: def change_division(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None) -> bool:
"""Change division. """Change division.
:param battle: Battle :param battle: classes.Battle
:type battle: Battle :type battle: classes.Battle
:param division: int target division to switch to :param division: int target division to switch to
:type division: BattleDivision :type division: classes.BattleDivision
:param side: Side to choose
:type side: classes.BattleSide
:return: :return:
""" """
resp = self._post_main_battlefield_change_division(battle.id, division.id) resp = self._post_main_battlefield_change_division(battle.id, division.id, side.id if side else None)
if resp.json().get('error'): if resp.json().get('error'):
self.write_log(resp.json().get('message')) self.write_log(resp.json().get('message'))
return False return False
@ -2251,59 +2232,11 @@ class CitizenMilitary(CitizenTravel):
if division.wall['dom'] == 50 or division.wall['dom'] > 98: if division.wall['dom'] == 50 or division.wall['dom'] > 98:
yield division, division.wall['for'] == battle.invader.country.id yield division, division.wall['for'] == battle.invader.country.id
def report_fighting(self, battle: classes.Battle, invader: bool, division: classes.BattleDivision, damage: float, def report_fighting(self, battle: classes.Battle, invader: bool, division: classes.BattleDivision, damage: float, hits: int):
hits: int):
self.reporter.report_fighting(battle, invader, division, damage, hits) self.reporter.report_fighting(battle, invader, division, damage, hits)
if self.config.telegram: if self.config.telegram:
self.telegram.report_fight(battle, invader, division, damage, hits) self.telegram.report_fight(battle, invader, division, damage, hits)
def get_deploy_inventory(self, division: classes.BattleDivision, side: classes.BattleSide):
ret = self._post_fight_deploy_get_inventory(division.battle.id, side.id, division.id).json()
# if ret.get('recoverableEnergyBuyFood'):
# self.buy_food()
# return self.get_deploy_inventory(division, side)
if ret.get('captcha'):
while not self.do_captcha_challenge():
self.sleep(5)
return ret
def deploy(self, division: classes.BattleDivision, side: classes.BattleSide, energy: int):
_energy = int(energy)
deploy_inv = self.get_deploy_inventory(division, side)
if not deploy_inv['minEnergy'] <= energy <= deploy_inv['maxEnergy']:
return 0
energy_sources = {}
source_idx = 0
recoverable = deploy_inv['recoverableEnergy']
for source in reversed(sorted(deploy_inv['energySources'], key=lambda s: (s['type'], s.get('quality', 0)))):
if source['type'] == 'pool':
_energy -= source['energy']
elif source['type'] in ['food', 'energy_bar']:
recovers = source['energy'] / source['amount']
amount = recoverable // recovers
amount = amount if amount < source['amount'] else source['amount']
if amount > 0:
energy_sources.update({f'energySources[{source_idx}][quality]': source['quality']})
energy_sources.update({f'energySources[{source_idx}][amount]': amount})
source_idx += 1
used_energy = amount * recovers
recoverable -= used_energy
_energy -= used_energy
energy -= _energy
weapon_q = -1
weapon_strength = 0
if not division.is_air:
for weapon in sorted(deploy_inv['weapons'], key=lambda w: w['damageperHit']):
if (weapon['damageperHit'] or 0) > weapon_strength and (weapon['amount'] or 0) > 50:
weapon_q = weapon['quality']
r = self._post_fight_deploy_start_deploy(
division.battle.id, side.id, division.id, energy, weapon_q, **energy_sources
).json()
self.write_log(r.get('message'))
if r.get('error'):
self.report_error('Deploy failed!')
return energy
class CitizenPolitics(BaseCitizen): class CitizenPolitics(BaseCitizen):
def get_country_parties(self, country: constants.Country = None) -> dict: def get_country_parties(self, country: constants.Country = None) -> dict:

View File

@ -7,7 +7,6 @@ import time
import traceback import traceback
import unicodedata import unicodedata
import warnings import warnings
from base64 import b64encode
from decimal import Decimal from decimal import Decimal
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Union from typing import Any, Dict, List, Union
@ -430,17 +429,3 @@ def json_load(f, **kwargs):
def json_loads(s: str, **kwargs): def json_loads(s: str, **kwargs):
kwargs.update(object_hook=json_decode_object_hook) kwargs.update(object_hook=json_decode_object_hook)
return json.loads(s, **kwargs) return json.loads(s, **kwargs)
def b64json(obj: Union[Dict[str, Union[int, List[str]]], List[str]]):
if isinstance(obj, list):
return b64encode(json.dumps(obj).encode('utf-8')).decode('utf-8')
elif isinstance(obj, (int, str)):
return obj
elif isinstance(obj, dict):
for k, v in obj.items():
obj[k] = b64json(v)
else:
from .classes import ErepublikException
raise ErepublikException(f'Unhandled object type! obj is {type(obj)}')
return b64encode(json.dumps(obj).encode('utf-8')).decode('utf-8')

View File

@ -1,20 +1,19 @@
bump2version==1.0.1 bump2version==1.0.1
coverage==5.4 coverage==5.3.1
edx-sphinx-theme==1.6.1 edx-sphinx-theme==1.6.1
flake8==3.8.4 flake8==3.8.4
ipython>=7.19.0 ipython>=7.19.0
jedi!=0.18.0
isort==5.7.0 isort==5.7.0
pip==21.0 pip==20.3.3
pre-commit==2.9.3 pre-commit==2.9.3
pur==5.3.0 pur==5.3.0
PyInstaller==4.2 PyInstaller==4.2
PySocks==1.7.1 PySocks==1.7.1
pytest==6.2.2 pytest==6.2.1
pytz>=2020.5 pytz>=2020.5
requests>=2.25.1 requests>=2.25.1
responses==0.12.1 responses==0.12.1
setuptools==52.0.0 setuptools==51.3.3
Sphinx==3.4.3 Sphinx==3.4.3
twine==3.3.0 twine==3.3.0
wheel==0.36.2 wheel==0.36.2

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.24.0.2 current_version = 0.23.4.16
commit = True commit = True
tag = True tag = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)? parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)?

View File

@ -50,6 +50,6 @@ setup(
test_suite='tests', test_suite='tests',
tests_require=test_requirements, tests_require=test_requirements,
url='https://github.com/eeriks/erepublik/', url='https://github.com/eeriks/erepublik/',
version='0.24.0.2', version='0.23.4.16',
zip_safe=False, zip_safe=False,
) )