Compare commits

..

7 Commits

8 changed files with 86 additions and 54 deletions

View File

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

View File

@ -13,43 +13,43 @@ __all__ = ['SlowRequests', 'CitizenAPI']
class SlowRequests(Session):
last_time: datetime.datetime
timeout: datetime.timedelta = datetime.timedelta(milliseconds=500)
uas: List[str] = [
_uas: List[str] = [
# Chrome
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36',
# FireFox
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:82.0) Gecko/20100101 Firefox/82.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0',
]
debug: bool = False
def __init__(self, proxies: Dict[str, str] = None):
def __init__(self, proxies: Dict[str, str] = None, user_agent: str = None):
super().__init__()
if proxies:
self.proxies = proxies
if user_agent is None:
user_agent = random.choice(self._uas)
self.request_log_name = utils.get_file(utils.now().strftime("debug/requests_%Y-%m-%d.log"))
self.last_time = utils.now()
self.headers.update({
'User-Agent': random.choice(self.uas)
})
self.headers.update({'User-Agent': user_agent})
@property
def as_dict(self):
return dict(last_time=self.last_time, timeout=self.timeout, user_agent=self.headers['User-Agent'],
request_log_name=self.request_log_name, debug=self.debug)
return dict(last_time=self.last_time, timeout=self.timeout, cookies=self.cookies.get_dict(), debug=self.debug,
user_agent=self.headers['User-Agent'], request_log_name=self.request_log_name, proxies=self.proxies)
def request(self, method, url, *args, **kwargs):
self._slow_down_requests()

View File

@ -12,6 +12,7 @@ from typing import Any, Dict, List, NoReturn, Optional, Set, Tuple, Union
from requests import HTTPError, RequestException, Response
from . import access_points, classes, constants, types, utils
from .access_points import SlowRequests
from .classes import OfferItem
@ -468,7 +469,7 @@ class BaseCitizen(access_points.CitizenAPI):
self._req.debug = bool(debug)
def to_json(self, indent: bool = False) -> str:
return utils.json.dumps(self, cls=classes.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
return utils.json.dumps(self, cls=classes.ErepublikJSONEncoder, indent=4 if indent else None, sort_keys=True)
def get_countries_with_regions(self) -> Set[constants.Country]:
r_json = self._post_main_travel_data().json()
@ -482,13 +483,13 @@ class BaseCitizen(access_points.CitizenAPI):
filename = f"{self.__class__.__name__}__dump.json"
with open(filename, 'w') as f:
utils.json.dump(dict(config=self.config, cookies=self._req.cookies.get_dict(),
user_agent=self._req.headers.get("User-Agent")), f, cls=classes.MyJSONEncoder)
user_agent=self._req.headers.get("User-Agent")), f, cls=classes.ErepublikJSONEncoder)
self.write_log(f"Session saved to: '{filename}'")
@classmethod
def load_from_dump(cls, dump_name: str):
with open(dump_name) as f:
data = utils.json.load(f)
data = utils.json.load(f, object_hook=utils.json_decode_object_hook)
player = cls(data['config']['email'], "")
player._req.cookies.update(data['cookies'])
player._req.headers.update({"User-Agent": data['user_agent']})
@ -508,7 +509,7 @@ class BaseCitizen(access_points.CitizenAPI):
self.write_log(f"Resumed as: {self.name}")
if re.search('<div id="accountSecurity" class="it-hurts-when-ip">', resp.text):
self.restricted_ip = True
self.report_error("eRepublik has blacklisted IP. Limited functionality!", True)
# self.report_error("eRepublik has blacklisted IP. Limited functionality!", True)
self.logged_in = True
self.get_csrf_token()
@ -732,7 +733,7 @@ class BaseCitizen(access_points.CitizenAPI):
self.get_csrf_token()
if re.search('<div id="accountSecurity" class="it-hurts-when-ip">', self.r.text):
self.restricted_ip = True
self.report_error("eRepublik has blacklisted IP. Limited functionality!", True)
# self.report_error("eRepublik has blacklisted IP. Limited functionality!", True)
self.logged_in = True
@ -747,6 +748,9 @@ class BaseCitizen(access_points.CitizenAPI):
if response.status_code >= 400:
self.r = response
if response.status_code >= 500:
if self.restricted_ip:
self._req.cookies.clear()
return True
self.write_log("eRepublik servers are having internal troubles. Sleeping for 5 minutes")
self.sleep(5 * 60)
else:
@ -778,7 +782,7 @@ class BaseCitizen(access_points.CitizenAPI):
:param msg: Message about the action
:param kwargs: Extra information regarding action
"""
kwargs = utils.json.loads(utils.json.dumps(kwargs or {}, cls=classes.MyJSONEncoder))
kwargs = utils.json.loads(utils.json.dumps(kwargs or {}, cls=classes.ErepublikJSONEncoder))
action = action[:32]
self.write_log(msg)
if self.reporter.allowed:
@ -2705,13 +2709,14 @@ class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
def state_update_repeater(self):
try:
start_time = self.now.replace(second=0, microsecond=0)
if start_time.minute <= 30:
start_time = start_time.replace(minute=30)
else:
start_time = utils.good_timedelta(start_time.replace(minute=0), timedelta(hours=1))
start_time = self.now.replace(minute=(self.now.minute // 10) * 10, second=0, microsecond=0)
if not self.restricted_ip:
if start_time.minute <= 30:
start_time = start_time.replace(minute=30)
else:
start_time = utils.good_timedelta(start_time.replace(minute=0), timedelta(hours=1))
while not self.stop_threads.is_set():
start_time = utils.good_timedelta(start_time, timedelta(minutes=30))
start_time = utils.good_timedelta(start_time, timedelta(minutes=10 if self.restricted_ip else 30))
self.update_citizen_info()
self.update_weekly_challenge()
self.send_state_update()

View File

@ -3,16 +3,15 @@ import hashlib
import threading
import weakref
from decimal import Decimal
from typing import Any, Dict, Generator, Iterable, List, NamedTuple, NoReturn, Tuple, Union
from typing import Any, Dict, Generator, Iterable, List, NamedTuple, NoReturn, Union
from requests import Response, Session, post
from . import constants, types, utils
__all__ = ['Battle', 'BattleDivision', 'BattleSide', 'Company', 'Config', 'Details', 'Energy', 'ErepublikException',
'ErepublikNetworkException', 'EnergyToFight',
'Holding', 'MyCompanies', 'MyJSONEncoder', 'OfferItem', 'Politics', 'Reporter', 'TelegramReporter',
'Inventory']
'ErepublikJSONEncoder', 'ErepublikNetworkException', 'EnergyToFight', 'Holding', 'Inventory', 'MyCompanies',
'OfferItem', 'Politics', 'Reporter', 'TelegramReporter', ]
class ErepublikException(Exception):
@ -599,10 +598,10 @@ class Reporter:
if self.__to_update:
for unreported_data in self.__to_update:
unreported_data.update(player_id=self.citizen_id, key=self.key)
unreported_data = utils.json.loads(utils.json.dumps(unreported_data, cls=MyJSONEncoder))
unreported_data = utils.json.loads(utils.json.dumps(unreported_data, cls=ErepublikJSONEncoder))
self._req.post(f"{self.url}/bot/update", json=unreported_data)
self.__to_update.clear()
data = utils.json.loads(utils.json.dumps(data, cls=MyJSONEncoder))
data = utils.json.loads(utils.json.dumps(data, cls=ErepublikJSONEncoder))
r = self._req.post(f"{self.url}/bot/update", json=data)
return r
@ -671,16 +670,19 @@ class Reporter:
except: # noqa
return []
def fetch_tasks(self) -> List[Union[str, Tuple[Any]]]:
def fetch_tasks(self) -> List[Dict[str, Any]]:
try:
task_response = self._req.get(f'{self.url}/api/v1/command',
params=dict(citizen=self.citizen_id, key=self.key))
return task_response.json().get('task_collection')
task_response = self._req.post(
f'{self.url}/api/v1/command', data=dict(citizen=self.citizen_id, key=self.key)).json()
if task_response.get('status'):
return task_response.get('data')
else:
return []
except: # noqa
return []
class MyJSONEncoder(utils.json.JSONEncoder):
class ErepublikJSONEncoder(utils.json.JSONEncoder):
def default(self, o):
from erepublik.citizen import Citizen
if isinstance(o, Decimal):
@ -694,7 +696,7 @@ class MyJSONEncoder(utils.json.JSONEncoder):
return dict(__type__='timedelta', days=o.days, seconds=o.seconds,
microseconds=o.microseconds, total_seconds=o.total_seconds())
elif isinstance(o, Response):
return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
return dict(headers=dict(o.__dict__['headers']), url=o.url, text=o.text, status_code=o.status_code)
elif hasattr(o, 'as_dict'):
return o.as_dict
elif isinstance(o, set):

View File

@ -12,6 +12,7 @@ from decimal import Decimal
from pathlib import Path
from typing import Any, Dict, List, Union
import pytz
import requests
from . import __version__, constants
@ -25,11 +26,8 @@ __all__ = ['VERSION', 'calculate_hit', 'caught_error', 'date_from_eday', 'eday_f
'get_air_hit_dmg_value', 'get_file', 'get_ground_hit_dmg_value', 'get_sleep_seconds', 'good_timedelta',
'interactive_sleep', 'json', 'localize_dt', 'localize_timestamp', 'normalize_html_json', 'now',
'process_error', 'process_warning', 'send_email', 'silent_sleep', 'slugify', 'write_file', 'write_request',
'write_interactive_log', 'write_silent_log', 'get_final_hit_dmg', 'wait_for_lock']
if not sys.version_info >= (3, 6):
raise AssertionError('This script requires Python version 3.6 and higher\n'
'But Your version is v{}.{}.{}'.format(*sys.version_info))
'write_interactive_log', 'write_silent_log', 'get_final_hit_dmg', 'wait_for_lock',
'json_decode_object_hook', 'json_load', 'json_loads']
VERSION: str = __version__
@ -234,8 +232,8 @@ def send_email(name: str, content: List[Any], player=None, local_vars: Dict[str,
if isinstance(local_vars.get('citizen'), Citizen):
local_vars['citizen'] = repr(local_vars['citizen'])
from erepublik.classes import MyJSONEncoder
files.append(('file', ("local_vars.json", json.dumps(local_vars, cls=MyJSONEncoder),
from erepublik.classes import ErepublikJSONEncoder
files.append(('file', ("local_vars.json", json.dumps(local_vars, cls=ErepublikJSONEncoder),
"application/json")))
if isinstance(player, Citizen):
files.append(('file', ("instance.json", player.to_json(indent=True), "application/json")))
@ -380,12 +378,6 @@ def get_final_hit_dmg(base_dmg: Union[Decimal, float, str], rang: int,
return Decimal(dmg)
# def _clear_up_battle_memory(battle):
# del battle.invader._battle, battle.defender._battle
# for div_id, division in battle.div.items():
# del division._battle
def deprecation(message):
warnings.warn(message, DeprecationWarning, stacklevel=2)
@ -409,3 +401,36 @@ def wait_for_lock(function):
return ret
return wrapper
def json_decode_object_hook(
o: Union[Dict[str, Any], List[Any], int, float, str]
) -> Union[Dict[str, Any], List[Any], int, float, str, datetime.date, datetime.datetime, datetime.timedelta]:
""" Convert classes.ErepublikJSONEncoder datetime, date and timedelta to their python objects
:param o:
:return: Union[Dict[str, Any], List[Any], int, float, str, datetime.date, datetime.datetime, datetime.timedelta]
"""
if o.get('__type__'):
_type = o.get('__type__')
if _type == 'datetime':
dt = datetime.datetime.strptime(f"{o['date']} {o['time']}", "%Y-%m-%d %H:%M:%S")
if o.get('tzinfo'):
dt = pytz.timezone(o['tzinfo']).localize(dt)
return dt
elif _type == 'date':
dt = datetime.datetime.strptime(f"{o['date']}", "%Y-%m-%d")
return dt.date()
elif _type == 'timedelta':
return datetime.timedelta(seconds=o['total_seconds'])
return o
def json_load(f, **kwargs):
kwargs.update(object_hook=json_decode_object_hook)
return json.load(f, **kwargs)
def json_loads(s: str, **kwargs):
kwargs.update(object_hook=json_decode_object_hook)
return json.loads(s, **kwargs)

View File

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

View File

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

View File

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