Compare commits

..

15 Commits

20 changed files with 308 additions and 421 deletions

View File

@ -2,10 +2,8 @@
language: python
python:
- 3.7
- 3.6
- 3.5
- 3.4
- 2.7
# Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
install: pip install -U tox-travis

View File

@ -57,7 +57,7 @@ If you are proposing a feature:
Get Started!
------------
Ready to contribute? Here's how to set up `erepublik_script` for local development.
Ready to contribute? Here's how to set up `erepublik` for local development.
1. Fork the `erepublik_script` repo on GitHub.
2. Clone your fork locally::
@ -66,8 +66,8 @@ Ready to contribute? Here's how to set up `erepublik_script` for local developme
3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
$ mkvirtualenv erepublik_script
$ cd erepublik_script/
$ mkvirtualenv erepublik
$ cd erepublik/
$ python setup.py develop
4. Create a branch for local development::
@ -79,7 +79,7 @@ Ready to contribute? Here's how to set up `erepublik_script` for local developme
5. When you're done making changes, check that your changes pass flake8 and the
tests, including testing other Python versions with tox::
$ flake8 erepublik_script tests
$ flake8 erepublik tests
$ python setup.py test or py.test
$ tox
@ -102,7 +102,7 @@ Before you submit a pull request, check that it meets these guidelines:
2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring, and add the
feature to the list in README.rst.
3. The pull request should work for Python 2.7, 3.4, 3.5 and 3.6, and for PyPy. Check
3. The pull request should work for Python 3.7.1. Check
https://travis-ci.org/eeriks/erepublik_script/pull_requests
and make sure that the tests pass for all supported Python versions.

View File

@ -6,3 +6,9 @@ History
------------------
* First release on PyPI.
0.14.4 (2019-07-23)
-------------------
* Wall post comment endpoints updated with comment create endpoints

View File

@ -51,7 +51,7 @@ clean-test: ## remove test and coverage artifacts
rm -fr .pytest_cache
lint: ## check style with flake8
flake8 erepublik_script tests
flake8 erepublik tests
test: ## run tests quickly with the default Python
python setup.py test
@ -60,15 +60,15 @@ test-all: ## run tests on every Python version with tox
tox
coverage: ## check code coverage quickly with the default Python
coverage run --source erepublik_script setup.py test
coverage run --source erepublik setup.py test
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/erepublik_script.rst
rm -f docs/erepublik.rst
rm -f docs/modules.rst
sphinx-apidoc -o docs/ erepublik_script
sphinx-apidoc -o docs/ erepublik
$(MAKE) -C docs clean
$(MAKE) -C docs html
$(BROWSER) docs/_build/html/index.html

View File

@ -3,11 +3,11 @@ eRepublik script
================
.. image:: https://img.shields.io/pypi/v/erepublik_script.svg
:target: https://pypi.python.org/pypi/erepublik_script
.. image:: https://img.shields.io/pypi/v/erepublik.svg
:target: https://pypi.python.org/pypi/erepublik
.. image:: https://readthedocs.org/projects/erepublik-script/badge/?version=latest
:target: https://erepublik-script.readthedocs.io/en/latest/?badge=latest
.. image:: https://readthedocs.org/projects/erepublik/badge/?version=latest
:target: https://erepublik.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
@ -15,7 +15,7 @@ Python package for automated eRepublik playing
* Free software: MIT license
* Documentation: https://erepublik-script.readthedocs.io.
* Documentation: https://erepublik.readthedocs.io.
Features

View File

@ -4,7 +4,7 @@
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = python -msphinx
SPHINXPROJ = erepublik_script
SPHINXPROJ = erepublik
SOURCEDIR = .
BUILDDIR = _build

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# erepublik_script documentation build configuration file, created by
# erepublik documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 9 13:47:02 2017.
#
# This file is execfile()d with the current directory set to its
@ -22,7 +22,7 @@ import os
import sys
sys.path.insert(0, os.path.abspath('..'))
import erepublik_script
import erepublik
# -- General configuration ---------------------------------------------
@ -56,9 +56,9 @@ author = u"Eriks Karls"
# the built documents.
#
# The short X.Y version.
version = erepublik_script.__version__
version = erepublik.__version__
# The full version, including alpha/beta/rc tags.
release = erepublik_script.__version__
release = erepublik.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -101,7 +101,7 @@ html_static_path = ['_static']
# -- Options for HTMLHelp output ---------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'erepublik_scriptdoc'
htmlhelp_basename = 'erepublikdoc'
# -- Options for LaTeX output ------------------------------------------
@ -128,7 +128,7 @@ latex_elements = {
# (source start file, target name, title, author, documentclass
# [howto, manual, or own class]).
latex_documents = [
(master_doc, 'erepublik_script.tex',
(master_doc, 'erepublik.tex',
u'eRepublik script Documentation',
u'Eriks Karls', 'manual'),
]
@ -139,7 +139,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'erepublik_script',
(master_doc, 'erepublik',
u'eRepublik script Documentation',
[author], 1)
]
@ -151,10 +151,10 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'erepublik_script',
(master_doc, 'erepublik',
u'eRepublik script Documentation',
author,
'erepublik_script',
'erepublik',
'One line description of project.',
'Miscellaneous'),
]

View File

@ -1,5 +1,5 @@
Welcome to eRepublik script's documentation!
======================================
============================================
.. toctree::
:maxdepth: 2

View File

@ -12,7 +12,7 @@ To install eRepublik script, run this command in your terminal:
.. code-block:: console
$ pip install erepublik_script
$ pip install erepublik
This is the preferred method to install eRepublik script, as it will always install the most recent stable release.

View File

@ -4,4 +4,4 @@ Usage
To use eRepublik script in a project::
import erepublik_script
import erepublik

10
erepublik/__init__.py Normal file
View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
"""Top-level package for eRepublik script."""
__author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv'
__version__ = '0.14.6'
from erepublik import classes, utils
from erepublik.citizen import Citizen

View File

@ -9,7 +9,7 @@ from typing import Dict, List, Tuple, Any, Union
import requests
from requests import Response, RequestException
from erepublik_script import classes, utils
from erepublik import classes, utils
class Citizen(classes.CitizenAPI):
@ -94,6 +94,8 @@ class Citizen(classes.CitizenAPI):
ret = super().__dict__.copy()
ret.pop('reporter', None)
ret.pop('stop_threads', None)
ret.pop('_Citizen__last_war_update_data', None)
ret.update(all_battles=self.all_battles)
return ret
@ -134,7 +136,7 @@ class Citizen(classes.CitizenAPI):
def _login(self):
# MUST BE CALLED TROUGH self.get_csrf_token()
r = self.post_login(self.token, self.config.email, self.config.password)
r = self.post_login(self.config.email, self.config.password)
self.r = r
if r.url == "{}/login".format(self.url):
@ -360,7 +362,7 @@ class Citizen(classes.CitizenAPI):
"""
if currency not in [1, 62]:
currency = 62
resp = self.post_economy_exchange_retrieve(self.token, False, page, currency)
resp = self.post_economy_exchange_retrieve(False, page, currency)
self.details.cc = float(resp.json().get("ecash").get("value"))
self.details.gold = float(resp.json().get("gold").get("value"))
return resp
@ -424,11 +426,7 @@ class Citizen(classes.CitizenAPI):
if status == "rewarded":
continue
elif status == "completed":
data = {
"_token": self.token,
"rewardId": reward.get("id", 0)
}
self.post_weekly_challenge_reward(self.token, reward.get("id", 0))
self.post_weekly_challenge_reward(reward.get("id", 0))
elif reward.get("icon", "") == "energy_booster":
pps = re.search(r"Reach (\d+) Prestige Points to unlock the following reward: \+1 Energy",
reward.get("tooltip", ""))
@ -440,6 +438,7 @@ class Citizen(classes.CitizenAPI):
self.update_citizen_info()
resp_json = self.get_military_campaigns().json()
self.all_battles = {}
if resp_json.get("countries"):
for c_id, c_data in resp_json.get("countries").items():
if int(c_id) not in self.countries:
@ -487,7 +486,7 @@ class Citizen(classes.CitizenAPI):
self.write_log(self.health_info)
def _eat(self, colour: str = "blue") -> Response:
response = self.post_eat(self.token, colour)
response = self.post_eat(colour)
r_json = response.json()
next_recovery = r_json.get("food_remaining_reset").split(":")
self.energy.set_reference_time(
@ -619,10 +618,8 @@ class Citizen(classes.CitizenAPI):
battle_id = r.get("citizen_contribution")[0].get("battle_id", 0)
ret_battles.append(battle_id)
ret_battles += (cs_battles_air + cs_battles_ground +
deployed_battles_air + deployed_battles_ground +
ally_battles_air + ally_battles_ground +
other_battles_air + other_battles_ground)
ret_battles += cs_battles_air + cs_battles_ground + deployed_battles_air + deployed_battles_ground + \
ally_battles_air + ally_battles_ground + other_battles_air + other_battles_ground
return ret_battles
@property
@ -643,8 +640,8 @@ class Citizen(classes.CitizenAPI):
if battle.is_rw:
side_id = battle.defender.id if self.config.rw_def_side else battle.invader.id
else:
side_id = battle.defender.id if (self.details.current_country in battle.defender.allies +
[battle.defender.id, ]) else battle.invader.id
side = self.details.current_country in battle.defender.allies + [battle.defender.id, ]
side_id = battle.defender.id if side else battle.invader.id
try:
def_points = battle.div.get(div).dom_pts.get('def')
inv_points = battle.div.get(div).dom_pts.get('inv')
@ -689,7 +686,7 @@ class Citizen(classes.CitizenAPI):
break
def fight(self, battle_id: int, side_id: int, is_air: bool = False, count: int = None):
data = dict(sideId=side_id, battleId=battle_id, _token=self.token)
data = dict(sideId=side_id, battleId=battle_id)
error_count = 0
ok_to_fight = True
if count is None:
@ -718,9 +715,9 @@ class Citizen(classes.CitizenAPI):
def _shoot(self, air: bool, data: dict):
if air:
response = self.post_military_fight_air(self.token, data['battleId'], data['sideId'])
response = self.post_military_fight_air(data['battleId'], data['sideId'])
else:
response = self.post_military_fight_ground(self.token, data['battleId'], data['sideId'])
response = self.post_military_fight_ground(data['battleId'], data['sideId'])
if "Zone is not meant for " in response.text:
self.sleep(5)
@ -752,7 +749,7 @@ class Citizen(classes.CitizenAPI):
# I"m not checking for 1h cooldown. Beware of nightshift work, if calling more than once every 60min
self.update_job_info()
if self.ot_points >= 24 and self.energy.food_fights > 1:
r = self.post_economy_work_overtime(self.token)
r = self.post_economy_work_overtime()
if not r.json().get("status") and r.json().get("message") == "money":
self.resign()
self.find_new_job()
@ -770,7 +767,7 @@ class Citizen(classes.CitizenAPI):
def work(self):
if self.energy.food_fights >= 1:
response = self.post_economy_work(self.token, "work")
response = self.post_economy_work("work")
js = response.json()
good_msg = ["already_worked", "captcha"]
if not js.get("status") and not js.get("message") in good_msg:
@ -802,7 +799,7 @@ class Citizen(classes.CitizenAPI):
tgs.append(data["id"])
if tgs:
if self.energy.food_fights >= len(tgs):
response = self.post_economy_train(self.token, tgs)
response = self.post_economy_train(tgs)
if not response.json().get("status"):
self.update_citizen_info()
self.train()
@ -868,7 +865,6 @@ class Citizen(classes.CitizenAPI):
employee_companies = {}
data = {
"action_type": "production",
"_token": self.token,
}
extra = {}
wam_list = []
@ -905,7 +901,7 @@ class Citizen(classes.CitizenAPI):
wam_holding = self.my_companies.holdings.get(wam_holding_id)
if not self.details.current_region == wam_holding['region_id']:
self.travel(holding_id=wam_holding_id, region_id=wam_holding['region_id'])
response = self.post_economy_work(self.token, "production", wam=wam_list, employ=employee_companies).json()
response = self.post_economy_work("production", wam=wam_list, employ=employee_companies).json()
self.reporter.report_action("WORK_WAM_EMPLOYEES", response)
if response.get("status"):
if self.config.auto_sell:
@ -1006,7 +1002,7 @@ class Citizen(classes.CitizenAPI):
"inRegionId": region_id,
"battleId": 0,
}
return self.post_travel(self.token, "moveAction", **data)
return self.post_travel("moveAction", **data)
def get_travel_regions(self, holding_id: int = 0, battle_id: int = 0, region_id: int = 0,
country_id: int = 0) -> Response:
@ -1016,7 +1012,7 @@ class Citizen(classes.CitizenAPI):
"regionId": region_id,
}
data.update(countryId=country_id)
return self.post_travel_data(self.token, **data)
return self.post_travel_data(**data)
def parse_notifications(self, page: int = 1) -> list:
response = self.get_message_alerts(page)
@ -1029,7 +1025,7 @@ class Citizen(classes.CitizenAPI):
response = self.get_message_alerts()
while notification_ids(response.text):
response = self.post_messages_alert(self.token, notification_ids(response.text))
response = self.post_messages_alert(notification_ids(response.text))
def collect_weekly_reward(self):
self.update_weekly_challenge()
@ -1037,7 +1033,7 @@ class Citizen(classes.CitizenAPI):
def collect_daily_task(self) -> Response or None:
self.update_citizen_info()
if self.details.daily_task_done and not self.details.daily_task_reward:
return self.post_daily_task_reward(self.token)
return self.post_daily_task_reward()
def send_mail_to_owner(self) -> Response or None:
if not self.details.citizen_id == 1620414:
@ -1045,7 +1041,7 @@ class Citizen(classes.CitizenAPI):
self.sleep(1)
msg_id = re.search(r"<input type=\"hidden\" value=\"(\d+)\" "
r"id=\"delete_message_(\d+)\" name=\"delete_message\[]\">", self.r.text).group(1)
return self.post_delete_message(self.token, [msg_id])
return self.post_delete_message([msg_id])
def get_market_offers(self, country_id: int = None, product: str = None, quality: int = None) -> dict:
ret = dict()
@ -1083,7 +1079,7 @@ class Citizen(classes.CitizenAPI):
str_q = "q%i" % q
data = {'country': country, 'industry': self.available_industries[industry], 'quality': q}
r = self.post_economy_marketplace(self.token, **data)
r = self.post_economy_marketplace(**data)
rjson = r.json()
obj = items[industry][str_q]
if not rjson.get("error", False):
@ -1151,7 +1147,7 @@ class Citizen(classes.CitizenAPI):
return sorted(ret, key=lambda o: (o["price"], -o["amount"]))
def buy_monetary_market_offer(self, offer: int, amount: float, currency: int) -> bool:
response = self.post_economy_exchange_purchase(self.token, amount, currency, offer)
response = self.post_economy_exchange_purchase(amount, currency, offer)
self.details.cc = float(response.json().get("ecash").get("value"))
self.details.gold = float(response.json().get("gold").get("value"))
self.reporter.report_action("BUY_GOLD", json_val=response.json(),
@ -1169,26 +1165,26 @@ class Citizen(classes.CitizenAPI):
duration = 28800
elif self.boosters.get("100_damageBoosters_5_86400", 0) > 2:
duration = 86400
return self.post_fight_activate_booster(self.token, battle_id, 5, duration, "damage")
return self.post_fight_activate_booster(battle_id, 5, duration, "damage")
def activate_battle_effect(self, battle_id: int, kind: str):
return self.post_activate_battle_effect(self.token, battle_id, kind, self.details.citizen_id)
return self.post_activate_battle_effect(battle_id, kind, self.details.citizen_id)
def activate_pp_booster(self, battle_id: int):
return self.post_fight_activate_booster(self.token, battle_id, 1, 180, "prestige_points")
return self.post_fight_activate_booster(battle_id, 1, 180, "prestige_points")
def donate_money(self, citizen_id: int = 1620414, amount: float = 0.0, currency: int = 62):
""" currency: gold = 62, cc = 1 """
return self.post_economy_donate_money_action(self.token, citizen_id, amount, currency)
return self.post_economy_donate_money_action(citizen_id, amount, currency)
def donate_items(self, citizen_id: int = 1620414, amount: int = 0, industry_id: int = 1,
quality: int = 1) -> Response:
ind = {v: k for k, v in self.available_industries.items()}
self.write_log("D,{},q{},{},{}".format(amount, quality, ind[industry_id], citizen_id))
return self.post_economy_donate_items_action(self.token, citizen_id, amount, industry_id, quality)
return self.post_economy_donate_items_action(citizen_id, amount, industry_id, quality)
def candidate_for_congress(self, presentation: str = "") -> Response:
return self.post_candidate_for_congress(self.token, presentation)
return self.post_candidate_for_congress(presentation)
def candidate_for_party_presidency(self) -> Response:
return self.get_candidate_party(self.politics.party_slug)
@ -1197,7 +1193,7 @@ class Citizen(classes.CitizenAPI):
for notification in self.parse_notifications():
don_id = re.search(r"erepublik.functions.acceptRejectDonation\(\"accept\", (\d+)\)", notification)
if don_id:
self.get_money_donation_accept(self.token, int(don_id.group(1)))
self.get_money_donation_accept(int(don_id.group(1)))
self.sleep(5)
def reject_money_donations(self) -> int:
@ -1206,7 +1202,7 @@ class Citizen(classes.CitizenAPI):
donation_ids = re.findall(r"erepublik.functions.acceptRejectDonation\(\"reject\", (\d+)\)", r.text)
while donation_ids:
for don_id in donation_ids:
self.get_money_donation_reject(self.token, int(don_id))
self.get_money_donation_reject(int(don_id))
count += 1
self.sleep(5)
r = self.get_message_alerts()
@ -1285,12 +1281,12 @@ class Citizen(classes.CitizenAPI):
if count > 0 and not force_fight:
if self.my_companies.ff_lockdown and self.details.pp > 75:
if self.energy.food_fights - self.my_companies.ff_lockdown > 0:
if count - self.my_companies.ff_lockdown > 0:
log_msg = ("Fight count modified (old count: {} | FF: {} | "
"WAM ff_lockdown: {} | New count: {})").format(
count, self.energy.food_fights, self.my_companies.ff_lockdown,
self.energy.food_fights - self.my_companies.ff_lockdown)
count = self.energy.food_fights - self.my_companies.ff_lockdown
count - self.my_companies.ff_lockdown)
count -= self.my_companies.ff_lockdown
else:
count = 0
if count <= 0:
@ -1375,8 +1371,8 @@ class Citizen(classes.CitizenAPI):
return self.energy.limit + self.details.xp_till_level_up * 10 <= self.energy.available
return False
def get_article_comments(self, article_id: int = 2645676, page_id: int = 0):
return self.post_article_comments(self.token, article_id, page_id)
def get_article_comments(self, article_id: int = 2645676, page_id: int = 1):
return self.post_article_comments(article_id, page_id)
def comment_article(self, article_id: int = 2645676, msg: str = None) -> Response:
if msg is None:
@ -1389,14 +1385,14 @@ class Citizen(classes.CitizenAPI):
return r
def write_article_comment(self, message: str, article_id: int, parent_id: int = None):
return self.post_article_comments_create(self.token, message, article_id, parent_id)
return self.post_article_comments_create(message, article_id, parent_id)
def publish_article(self, title: str, content: str, kind: int):
kinds = {1: "First steps in eRepublik", 2: "Battle orders", 3: "Warfare analysis",
4: "Political debates and analysis", 5: "Financial business",
6: "Social interactions and entertainment"}
if kind in kinds:
return self.post_write_article(self.token, title, content, self.details.citizenship, kind)
return self.post_write_article(title, content, self.details.citizenship, kind)
else:
raise classes.ErepublikException(
"Article kind must be one of:\n{}\n'{}' is not supported".format(
@ -1410,7 +1406,6 @@ class Citizen(classes.CitizenAPI):
self.write_log("Trying to sell unsupported industry {}".format(industry))
data = {
"token": self.token,
"country": self.details.citizenship,
"industry": industry,
"quality": quality,
@ -1423,7 +1418,7 @@ class Citizen(classes.CitizenAPI):
return ret
def buy_from_market(self, offer: int, amount: int) -> Response:
ret = self.post_economy_marketplace_actions(self.token, amount, True, offer=offer)
ret = self.post_economy_marketplace_actions(amount, True, offer=offer)
json_ret = ret.json()
if json_ret.get('error'):
return ret
@ -1446,11 +1441,12 @@ class Citizen(classes.CitizenAPI):
raw = wrm
else:
continue
effective_bonus = cdata["effective_bonus"]
base_prod = float(cdata["base_production"])
if cdata["is_raw"]:
raw += float(cdata["base_production"]) * cdata["effective_bonus"] / 100
raw += base_prod * effective_bonus / 100
else:
raw -= cdata["effective_bonus"] / 100 * cdata["base_production"] * \
cdata["upgrades"][str(cdata["quality"])]["raw_usage"]
raw -= effective_bonus / 100 * base_prod * cdata["upgrades"][str(cdata["quality"])]["raw_usage"]
if cdata["industry_token"] == "FOOD":
frm = raw
elif cdata["industry_token"] == "WEAPON":
@ -1460,14 +1456,11 @@ class Citizen(classes.CitizenAPI):
def assign_factory_to_holding(self, factory_id: int, holding_id: int) -> Response:
"""
Assigns factory to new holding
:type factory_id: int
:type holding_id: int
:return: Response object
"""
return self.post_economy_assign_to_holding(self.token, factory_id, holding_id)
return self.post_economy_assign_to_holding(factory_id, holding_id)
def upgrade_factory(self, factory_id: int, level: int) -> Response:
return self.post_economy_upgrade_company(self.token, factory_id, level, self.details.pin)
return self.post_economy_upgrade_company(factory_id, level, self.details.pin)
def create_factory(self, industry_id: int, building_type: int = 1) -> Response:
"""
@ -1477,10 +1470,10 @@ class Citizen(classes.CitizenAPI):
Storage={1000: 1, 2000: 2} <- Building_type 2
"""
return self.post_economy_create_company(self.token, industry_id, building_type)
return self.post_economy_create_company(industry_id, building_type)
def dissolve_factory(self, factory_id: int) -> Response:
return self.post_economy_sell_company(self.token, factory_id, self.details.pin, sell=False)
return self.post_economy_sell_company(factory_id, self.details.pin, sell=False)
@property
def available_industries(self) -> Dict[str, int]:
@ -1500,7 +1493,7 @@ class Citizen(classes.CitizenAPI):
return self.available_industries.get(industry_name, 0)
def buy_tg_contract(self) -> Response:
ret = self.post_buy_gold_items(self.token, 'gold', "TrainingContract2", 1)
ret = self.post_buy_gold_items('gold', "TrainingContract2", 1)
self.reporter.report_action("BUY_TG_CONTRACT", ret.json())
return ret
@ -1508,13 +1501,13 @@ class Citizen(classes.CitizenAPI):
self.update_job_info()
if self.r.json().get("isEmployee"):
self.reporter.report_action("RESIGN", self.r.json())
return self.post_economy_resign(self.token)
return self.post_economy_resign()
return None
def find_new_job(self) -> Response:
r = self.get_economy_job_market_json(self.details.current_country)
jobs = r.json().get("jobs")
data = dict(token=self.token, citizen=0, salary=10)
data = dict(citizen=0, salary=10)
for posting in jobs:
salary = posting.get("netSalary")
limit = posting.get("salaryLimit", 0)
@ -1529,7 +1522,7 @@ class Citizen(classes.CitizenAPI):
resp = self.get_citizen_hovercard(player_id)
rjson = resp.json()
if not any([rjson["isBanned"], rjson["isDead"], rjson["isFriend"], rjson["isOrg"], rjson["isSelf"]]):
r = self.post_citizen_add_remove_friend(self.token, int(player_id), True)
r = self.post_citizen_add_remove_friend(int(player_id), True)
self.write_log("{:<64} (id:{:>11}) added as friend".format(rjson["name"], player_id))
return r
return resp
@ -1578,13 +1571,13 @@ class Citizen(classes.CitizenAPI):
if ids is None:
ids = [1620414, ]
for player_id in ids:
self.post_messages_compose(self.token, subject, msg, [player_id])
self.post_messages_compose(subject, msg, [player_id])
def add_every_player_as_friend(self):
cities = []
cities_dict = {}
self.write_log("WARNING! This will take a lot of time.")
rj = self.post_travel_data(self.token, regionId=662, check="getCountryRegions").json()
rj = self.post_travel_data(regionId=662, check="getCountryRegions").json()
for region_data in rj.get("regions", {}).values():
cities.append(region_data['cityId'])
cities_dict.update({region_data['cityId']: region_data['cityName']})
@ -1612,7 +1605,7 @@ class Citizen(classes.CitizenAPI):
raise NotImplementedError
def _launch_battle(self, war_id: int, region_id: int) -> Response:
return self.post_wars_attack_region(self.token, war_id, region_id)
return self.post_wars_attack_region(war_id, region_id)
def state_update_repeater(self):
try:
@ -1724,20 +1717,20 @@ class Citizen(classes.CitizenAPI):
def activate_house(self, quality: int) -> datetime.datetime:
active_until = self.now
r = self.post_economy_activate_house(self.token, quality)
r = self.post_economy_activate_house(quality)
if r.json().get("status") and not r.json().get("error"):
house = r.json()["inventoryItems"]["activeEnhancements"]["items"]["4_%i_active" % quality]
active_until = utils.good_timedelta(active_until, datetime.timedelta(seconds=house["active"]["time_left"]))
return active_until
def collect_anniversary_reward(self) -> Response:
return self.post_collect_anniversary_reward(self.token)
return self.post_collect_anniversary_reward()
def get_battle_round_data(self, battle_id: int, round_id: int, division: int = None) -> dict:
battle = self.all_battles.get(battle_id)
if not battle:
return {}
r = self.post_battle_console(self.token, battle_id, battle.zone_id, round_id, division, 1, True)
r = self.post_battle_console(battle_id, battle.zone_id, round_id, division, 1, True)
return {battle.invader.id: r.json().get(str(battle.invader.id)).get("fighterData"),
battle.defender.id: r.json().get(str(battle.defender.id)).get("fighterData")}
@ -1748,7 +1741,7 @@ class Citizen(classes.CitizenAPI):
return False
json = dict(country=71, action='currency', value=amount)
self.reporter.report_action("CONTRIBUTE_CC", json)
r = self.post_country_donate(self.token, **json)
r = self.post_country_donate(**json)
return r.json().get('status') or not r.json().get('error')
def contribute_food_to_country(self, amount: int = 0, quality: int = 1) -> bool:
@ -1758,7 +1751,7 @@ class Citizen(classes.CitizenAPI):
return False
json = dict(country=71, action='food', value=amount, quality=quality)
self.reporter.report_action("CONTRIBUTE_FOOD", json)
r = self.post_country_donate(self.token, **json)
r = self.post_country_donate(**json)
return r.json().get('status') or not r.json().get('error')
def contribute_gold_to_country(self, amount: int) -> bool:
@ -1768,7 +1761,7 @@ class Citizen(classes.CitizenAPI):
return False
json = dict(country=71, action='gold', value=amount)
self.reporter.report_action("CONTRIBUTE_GOLD", json)
r = self.post_country_donate(self.token, **json)
r = self.post_country_donate(**json)
return r.json().get('status') or not r.json().get('error')
def write_on_country_wall(self, message: str) -> bool:
@ -1776,7 +1769,7 @@ class Citizen(classes.CitizenAPI):
post_to_wall_as = re.findall(r"""id="post_to_country_as".*?<option value="(.*?)">.*?</option>.*</select>""",
self.r.text, re.S | re.M)
if post_to_wall_as:
self.post_country_post_create(self.token, message, max(post_to_wall_as))
self.post_country_post_create(message, max(post_to_wall_as))
return True
return False
@ -1788,7 +1781,7 @@ class Citizen(classes.CitizenAPI):
round_id = battle.get('zone_id')
division = self.division if round_id % 4 else 11
resp = self.post_military_battle_console(self.token, battle_id, round_id, division).json()
resp = self.post_military_battle_console(battle_id, round_id, division).json()
resp.pop('rounds', None)
ret = dict()
for country_id, data in resp.items():

View File

@ -9,9 +9,8 @@ from json import JSONDecodeError, loads, JSONEncoder
from typing import Any, Dict, List, Union
from requests import Response, Session
from slugify import slugify
from erepublik_script import utils
from erepublik import utils
class ErepublikException(Exception):
@ -223,12 +222,12 @@ class SlowRequests(Session):
body = "[{dt}]\tURL: '{url}'\tMETHOD: {met}\tARGS: {args}\n".format(dt=utils.now().strftime("%F %T"),
url=url, met=method, args=args)
utils.get_file(self.request_log_name)
with open(self.request_log_name, 'ab') as file:
file.write(body.encode("UTF-8"))
def _log_response(self, url, resp, redirect: bool = False):
from erepublik_script import Citizen
from erepublik import Citizen
if self.debug:
if resp.history and not redirect:
for hist_resp in resp.history:
@ -239,7 +238,7 @@ class SlowRequests(Session):
file_data = {
"path": 'debug/requests',
"time": self.last_time.strftime('%Y-%m-%d_%H-%M-%S'),
"name": slugify(url[len(Citizen.url):]),
"name": utils.slugify(url[len(Citizen.url):]),
"extra": "_REDIRECT" if redirect else ""
}
@ -358,6 +357,7 @@ class Energy:
def available(self):
return self.recovered + self.recoverable
@property
def __dict__(self):
return dict(
limit=self.limit,
@ -437,8 +437,9 @@ class House(object):
class CitizenAPI:
url = "https://www.erepublik.com/en"
_req = SlowRequests
url: str = "https://www.erepublik.com/en"
_req: SlowRequests = None
token: str = ""
def __init__(self):
self._req = SlowRequests()
@ -467,7 +468,9 @@ class CitizenAPI:
def get_citizen_daily_assistant(self):
return self.get("{}/main/citizenDailyAssistant".format(self.url))
def get_city_data_residents(self, city: int, page: int = 1, params: Dict[str, Any] = {}):
def get_city_data_residents(self, city: int, page: int = 1, params: Dict[str, Any] = None):
if params is None:
params = {}
return self.get("{}/main/city-data/{}/residents".format(self.url, city), params={"currentPage": page, **params})
def get_country_military(self, country: str) -> Response:
@ -513,15 +516,15 @@ class CitizenAPI:
def get_military_campaigns(self) -> Response:
return self.get("{}/military/campaigns-new/".format(self.url))
def get_military_unit_data(self, unit_id: int, page: int = 1) -> Response:
params = {"groupId": unit_id, "panel": "members", "currentPage": page}
def get_military_unit_data(self, unit_id: int, **kwargs) -> Response:
params = {"groupId": unit_id, "panel": "members", **kwargs}
return self.get("{}/military/military-unit-data/".format(self.url), params=params)
def get_money_donation_accept(self, token: str, donation_id: int) -> Response:
return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": token})
def get_money_donation_accept(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": self.token})
def get_money_donation_reject(self, token: str, donation_id: int) -> Response:
return self.get("{}/main/money-donation/reject/{}".format(self.url, donation_id), params={"_token": token})
def get_money_donation_reject(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/reject/{}".format(self.url, donation_id), params={"_token": self.token})
def get_party_members(self, party: int) -> Response:
return self.get("{}/main/party-members/{}".format(self.url, party))
@ -535,26 +538,26 @@ class CitizenAPI:
def get_weekly_challenge_data(self) -> Response:
return self.get("{}/main/weekly-challenge-data".format(self.url))
def post_activate_battle_effect(self, token: str, battle: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=token)
def post_activate_battle_effect(self, battle: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=self.token)
return self.post("{}/main/fight-activateBattleEffect".format(self.url), data=data)
def post_article_comments(self, token: str, article: int, page: int = 0) -> Response:
data = dict(_token=token, articleId=article, page=page)
def post_article_comments(self, article: int, page: int = 1) -> Response:
data = dict(_token=self.token, articleId=article, page=page)
if page:
data.update({'page': page})
return self.post("{}/main/articleComments".format(self.url), data=data)
def post_article_comments_create(self, token: str, message: str, article: int, parent: int = 0) -> Response:
data = dict(_token=token, message=message, articleId=article)
def post_article_comments_create(self, message: str, article: int, parent: int = 0) -> Response:
data = dict(_token=self.token, message=message, articleId=article)
if parent:
data.update({"parentId": parent})
return self.post("{}/main/articleComments/create".format(self.url), data=data)
def post_battle_console(self, token: str, battle: int, zone: int, round_id: int, division: int, page: int,
def post_battle_console(self, battle: int, zone: int, round_id: int, division: int, page: int,
damage: bool) -> Response:
data = dict(battleId=battle, zoneId=zone, action="battleStatistics", round=round_id, division=division,
leftPage=page, rightPage=page, _token=token)
leftPage=page, rightPage=page, _token=self.token)
if damage:
data.update({"type": "damage"})
else:
@ -562,108 +565,108 @@ class CitizenAPI:
return self.post("{}/military/battle-console".format(self.url), data=data)
def post_buy_gold_items(self, token: str, currency: str, item: str, amount: int) -> Response:
data = dict(itemId=item, currency=currency, amount=amount, _token=token)
def post_buy_gold_items(self, currency: str, item: str, amount: int) -> Response:
data = dict(itemId=item, currency=currency, amount=amount, _token=self.token)
return self.post("{}/main/buyGoldItems".format(self.url), data=data)
def post_candidate_for_congress(self, token: str, presentation: str = "") -> Response:
data = dict(_token=token, presentation=presentation)
def post_candidate_for_congress(self, presentation: str = "") -> Response:
data = dict(_token=self.token, presentation=presentation)
return self.post("{}/candidate-for-congress".format(self.url), data=data)
def post_citizen_add_remove_friend(self, token: str, citizen: int, add: bool) -> Response:
data = dict(_token=token, citizenId=citizen, url="//www.erepublik.com/en/main/citizen-addRemoveFriend")
def post_citizen_add_remove_friend(self, citizen: int, add: bool) -> Response:
data = dict(_token=self.token, citizenId=citizen, url="//www.erepublik.com/en/main/citizen-addRemoveFriend")
if add:
data.update({"action": "addFriend"})
else:
data.update({"action": "removeFriend"})
return self.post("{}/main/citizen-addRemoveFriend".format(self.url), data=data)
def post_collect_anniversary_reward(self, token: str) -> Response:
return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": token})
def post_collect_anniversary_reward(self) -> Response:
return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": self.token})
def post_country_donate(self, token: str, country: int, action: str, value: Union[int, float], quality: int = None):
json = dict(countryId=country, action=action, _token=token, value=value, quality=quality)
def post_country_donate(self, country: int, action: str, value: Union[int, float], quality: int = None):
json = dict(countryId=country, action=action, _token=self.token, value=value, quality=quality)
return self.post("{}/main/country-donate".format(self.url), data=json,
headers={"Referer": "{}/country/economy/Latvia".format(self.url)})
def post_daily_task_reward(self, token: str) -> Response:
return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=token))
def post_daily_task_reward(self) -> Response:
return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=self.token))
def post_delete_message(self, token: str, msg_id: list) -> Response:
data = {"_token": token, "delete_message[]": msg_id}
def post_delete_message(self, msg_id: list) -> Response:
data = {"_token": self.token, "delete_message[]": msg_id}
return self.post("{}/main/messages-delete".format(self.url), data)
def post_eat(self, token: str, color: str) -> Response:
data = dict(_token=token, buttonColor=color)
def post_eat(self, color: str) -> Response:
data = dict(_token=self.token, buttonColor=color)
return self.post("{}/main/eat".format(self.url), params=data)
def post_economy_activate_house(self, token: str, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": token}
def post_economy_activate_house(self, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": self.token}
return self.post("{}/economy/activateHouse".format(self.url), data=data)
def post_economy_assign_to_holding(self, token: str, factory: int, holding: int) -> Response:
data = dict(_token=token, factoryId=factory, action="assign", holdingCompanyId=holding)
def post_economy_assign_to_holding(self, factory: int, holding: int) -> Response:
data = dict(_token=self.token, factoryId=factory, action="assign", holdingCompanyId=holding)
return self.post("{}/economy/assign-to-holding".format(self.url), data=data)
def post_economy_create_company(self, token: str, industry: int, building_type: int = 1) -> Response:
data = {"_token": token, "company[industry_id]": industry, "company[building_type]": building_type}
def post_economy_create_company(self, industry: int, building_type: int = 1) -> Response:
data = {"_token": self.token, "company[industry_id]": industry, "company[building_type]": building_type}
return self.post("{}/economy/create-company".format(self.url), data=data,
headers={"Referer": "{}/economy/create-company".format(self.url)})
def post_economy_donate_items_action(self, token: str, citizen: int, amount: int, industry: int,
def post_economy_donate_items_action(self, citizen: int, amount: int, industry: int,
quality: int) -> Response:
data = dict(citizen_id=citizen, amount=amount, industry_id=industry, quality=quality, _token=token)
data = dict(citizen_id=citizen, amount=amount, industry_id=industry, quality=quality, _token=self.token)
return self.post("{}/economy/donate-items-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-items/{}".format(self.url, citizen)})
def post_economy_donate_money_action(self, token: str, citizen: int, amount: float = 0.0,
def post_economy_donate_money_action(self, citizen: int, amount: float = 0.0,
currency: int = 62) -> Response:
data = dict(citizen_id=citizen, _token=token, currency_id=currency, amount=amount)
data = dict(citizen_id=citizen, _token=self.token, currency_id=currency, amount=amount)
return self.post("{}/economy/donate-money-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-money/{}".format(self.url, citizen)})
def post_economy_exchange_purchase(self, token: str, amount: float, currency: int, offer: int) -> Response:
data = dict(_token=token, amount=amount, currencyId=currency, offerId=offer)
def post_economy_exchange_purchase(self, amount: float, currency: int, offer: int) -> Response:
data = dict(_token=self.token, amount=amount, currencyId=currency, offerId=offer)
return self.post("{}/economy/exchange/purchase/".format(self.url), data=data)
def post_economy_exchange_retrieve(self, token: str, personal: bool, page: int, currency: int) -> Response:
data = dict(_token=token, personalOffers=int(personal), page=page, currencyId=currency)
def post_economy_exchange_retrieve(self, personal: bool, page: int, currency: int) -> Response:
data = dict(_token=self.token, personalOffers=int(personal), page=page, currencyId=currency)
return self.post("{}/economy/exchange/retrieve/".format(self.url), data=data)
def post_economy_job_market_apply(self, token: str, citizen: int, salary: int) -> Response:
data = dict(_token=token, citizenId=citizen, salary=salary)
def post_economy_job_market_apply(self, citizen: int, salary: int) -> Response:
data = dict(_token=self.token, citizenId=citizen, salary=salary)
return self.post("{}/economy/job-market-apply".format(self.url), data=data)
def post_economy_marketplace(self, token: str, country: int, industry: int, quality: int,
def post_economy_marketplace(self, country: int, industry: int, quality: int,
order_asc: bool = True) -> Response:
data = dict(countryId=country, industryId=industry, quality=quality, ajaxMarket=1,
orderBy="price_asc" if order_asc else "price_desc", _token=token)
orderBy="price_asc" if order_asc else "price_desc", _token=self.token)
return self.post("{}/economy/marketplaceAjax".format(self.url), data=data)
def post_economy_marketplace_actions(self, token: str, amount: int, buy: bool = False, **kwargs) -> Response:
def post_economy_marketplace_actions(self, amount: int, buy: bool = False, **kwargs) -> Response:
if buy:
data = dict(_token=token, offerId=kwargs['offer'], amount=amount, orderBy="price_asc", currentPage=1,
data = dict(_token=self.token, offerId=kwargs['offer'], amount=amount, orderBy="price_asc", currentPage=1,
buyAction=1)
else:
data = dict(_token=token, countryId=kwargs["country"], price=kwargs["price"], industryId=kwargs["industry"],
quality=kwargs["quality"], amount=amount, sellAction='postOffer')
data = dict(_token=self.token, countryId=kwargs["country"], price=kwargs["price"],
industryId=kwargs["industry"], quality=kwargs["quality"], amount=amount, sellAction='postOffer')
return self.post("{}/economy/marketplaceActions".format(self.url), data=data)
def post_economy_resign(self, token: str) -> Response:
def post_economy_resign(self) -> Response:
return self.post("{}/economy/resign".format(self.url),
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={"_token": token, "action_type": "resign"})
data={"_token": self.token, "action_type": "resign"})
def post_economy_sell_company(self, token: str, factory: int, pin: int = None, sell: bool = True) -> Response:
def post_economy_sell_company(self, factory: int, pin: int = None, sell: bool = True) -> Response:
url = "{}/economy/sell-company/{}".format(self.url, factory)
data = dict(_token=token, pin="" if pin is None else pin)
data = dict(_token=self.token, pin="" if pin is None else pin)
if sell:
data.update({"sell": "sell"})
else:
data.update({"dissolve": factory})
return self.post(url, data=data, headers={"Referer": url})
def post_economy_train(self, token: str, tg_ids: List[int]) -> Response:
def post_economy_train(self, tg_ids: List[int]) -> Response:
data: Dict[str, Union[int, str]] = {}
if not tg_ids:
return self.get_training_grounds_json()
@ -672,14 +675,14 @@ class CitizenAPI:
data["grounds[%i][id]" % idx] = tg_id
data["grounds[%i][train]" % idx] = 1
if data:
data['_token'] = token
data['_token'] = self.token
return self.post("{}/economy/train".format(self.url), data=data)
def post_economy_upgrade_company(self, token: str, factory: int, level: int, pin: str = None) -> Response:
data = dict(_token=token, type="upgrade", companyId=factory, level=level, pin="" if pin is None else pin)
def post_economy_upgrade_company(self, factory: int, level: int, pin: str = None) -> Response:
data = dict(_token=self.token, type="upgrade", companyId=factory, level=level, pin="" if pin is None else pin)
return self.post("{}/economy/upgrade-company".format(self.url), data=data)
def post_economy_work(self, token: str, action_type: str, wam: List[int] = None, employ: Dict[int, int] = None):
def post_economy_work(self, action_type: str, wam: List[int] = None, employ: Dict[int, int] = None):
"""
:return: requests.Response or None
"""
@ -687,7 +690,7 @@ class CitizenAPI:
employ = dict()
if wam is None:
wam = []
data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=token)
data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=self.token)
if action_type == "work":
return self.post("{}/economy/work".format(self.url), data=data)
elif action_type == "production":
@ -710,124 +713,140 @@ class CitizenAPI:
else:
return
def post_economy_work_overtime(self, token: str) -> Response:
data = dict(action_type="workOvertime", _token=token)
def post_economy_work_overtime(self) -> Response:
data = dict(action_type="workOvertime", _token=self.token)
return self.post("{}/economy/workOvertime".format(self.url), data=data)
def post_forgot_password(self, token: str, email: str) -> Response:
data = dict(_token=token, email=email, commit="Reset password")
def post_forgot_password(self, email: str) -> Response:
data = dict(_token=self.token, email=email, commit="Reset password")
return self.post("{}/forgot-password".format(self.url), data=data)
def post_fight_activate_booster(self, token: str, battle: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=token)
def post_fight_activate_booster(self, battle: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=self.token)
return self.post("{}/military/fight-activateBooster".format(self.url), data=data)
def post_login(self, token: str, email: str, password: str) -> Response:
data = dict(csrf_token=token, citizen_email=email, citizen_password=password, remember='on')
def post_login(self, email: str, password: str) -> Response:
data = dict(csrf_token=self.token, citizen_email=email, citizen_password=password, remember='on')
return self.post("{}/login".format(self.url), data=data)
def post_messages_alert(self, token: str, notification_ids: list) -> Response:
data = {"_token": token, "delete_alerts[]": notification_ids, "deleteAllAlerts": "1", "delete": "Delete"}
def post_messages_alert(self, notification_ids: list) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids, "deleteAllAlerts": "1", "delete": "Delete"}
return self.post("{}/main/messages-alerts/1".format(self.url), data=data)
def post_messages_compose(self, token: str, subject: str, body: str, citizens: List[int]) -> Response:
def post_messages_compose(self, subject: str, body: str, citizens: List[int]) -> Response:
url_pk = 0 if len(citizens) > 1 else str(citizens[0])
data = dict(citizen_name=",".join([str(x) for x in citizens]),
citizen_subject=subject, _token=token, citizen_message=body)
citizen_subject=subject, _token=self.token, citizen_message=body)
return self.post("{}/main/messages-compose/{}}".format(self.url, url_pk), data=data)
def post_military_battle_console(self, token: str, battle_id: int, round_id: int, division: int) -> Response:
def post_military_battle_console(self, battle_id: int, round_id: int, division: int) -> Response:
data = dict(battleId=battle_id, zoneId=round_id, action="battleStatistics", round=round_id, division=division,
type="damage", leftPage=1, rightPage=1, _token=token)
type="damage", leftPage=1, rightPage=1, _token=self.token)
return self.post("{}/military/battle-console".format(self.url, battle_id), data=data)
def post_military_fight_air(self, token: str, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=token)
def post_military_fight_air(self, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token)
return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data)
def post_military_fight_ground(self, token: str, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=token)
def post_military_fight_ground(self, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token)
return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data)
def post_military_group_missions(self, token: str) -> Response:
data = dict(action="check", _token=token)
def post_military_group_missions(self) -> Response:
data = dict(action="check", _token=self.token)
return self.post("{}/military/group-missions".format(self.url), data=data)
def post_travel(self, token: str, check: str, **kwargs) -> Response:
data = dict(_token=token, check=check, **kwargs)
def post_travel(self, check: str, **kwargs) -> Response:
data = dict(_token=self.token, check=check, **kwargs)
return self.post("{}/main/travel".format(self.url), data=data)
def post_travel_data(self, token: str, **kwargs) -> Response:
return self.post("{}/main/travelData".format(self.url), data=dict(_token=token, **kwargs))
def post_travel_data(self, **kwargs) -> Response:
return self.post("{}/main/travelData".format(self.url), data=dict(_token=self.token, **kwargs))
def post_wars_attack_region(self, token: str, war: int, region: int) -> Response:
data = dict(_token=token)
def post_wars_attack_region(self, war: int, region: int) -> Response:
data = dict(_token=self.token)
return self.post("{}/wars/attack-region/{}/{}".format(self.url, war, region), data=data)
def post_weekly_challenge_reward(self, token: str, reward_id: int) -> Response:
data = dict(_token=token, rewardId=reward_id)
def post_weekly_challenge_reward(self, reward_id: int) -> Response:
data = dict(_token=self.token, rewardId=reward_id)
return self.post("{}/main/weekly-challenge-collect-reward".format(self.url), data=data)
def post_write_article(self, token: str, title: str, content: str, location: int, kind: int) -> Response:
data = dict(_token=token, article_name=title, article_body=content, article_location=location,
def post_write_article(self, title: str, content: str, location: int, kind: int) -> Response:
data = dict(_token=self.token, article_name=title, article_body=content, article_location=location,
article_category=kind)
return self.post("{}/main/write-article".format(self.url), data=data)
# Wall Posts
# ## Country
def post_country_comment_retrieve(self, token: str, post_id: int):
data = {"_token": token, "postId": post_id}
def post_country_comment_retrieve(self, post_id: int):
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/country-comment/retrieve/json".format(self.url), data=data)
def post_country_post_create(self, token: str, body: str, post_as: int):
data = {"_token": token, "post_message": body, "post_as": post_as}
def post_country_comment_create(self, post_id: int, comment_message: str):
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/country-comment/create/json".format(self.url), data=data)
def post_country_post_create(self, body: str, post_as: int):
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/country-post/create/json".format(self.url), data=data)
def post_country_post_retrieve(self, token: str):
data = {"_token": token, "page": 1, "switchedFrom": False}
def post_country_post_retrieve(self):
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/country-post/retrieve/json".format(self.url), data=data)
# ## Military Unit
def post_military_unit_comment_retrieve(self, token: str, post_id: int):
data = {"_token": token, "postId": post_id}
def post_military_unit_comment_retrieve(self, post_id: int):
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/military-unit-comment/retrieve/json".format(self.url), data=data)
def post_military_unit_post_create(self, token: str, body: str, post_as: int):
data = {"_token": token, "post_message": body, "post_as": post_as}
def post_military_unit_comment_create(self, post_id: int, comment_message: str):
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/military-unit-comment/create/json".format(self.url), data=data)
def post_military_unit_post_create(self, body: str, post_as: int):
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/military-unit-post/create/json".format(self.url), data=data)
def post_military_unit_post_retrieve(self, token: str):
data = {"_token": token, "page": 1, "switchedFrom": False}
def post_military_unit_post_retrieve(self):
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/military-unit-post/retrieve/json".format(self.url), data=data)
# ## Party
def post_party_comment_retrieve(self, token: str, post_id: int):
data = {"_token": token, "postId": post_id}
def post_party_comment_retrieve(self, post_id: int):
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/party-comment/retrieve/json".format(self.url), data=data)
def post_party_post_create(self, token: str, body: str):
data = {"_token": token, "post_message": body}
def post_party_comment_create(self, post_id: int, comment_message: str):
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/party-comment/create/json".format(self.url), data=data)
def post_party_post_create(self, body: str):
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/party-post/create/json".format(self.url), data=data)
def post_party_post_retrieve(self, token: str):
data = {"_token": token, "page": 1, "switchedFrom": False}
def post_party_post_retrieve(self):
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/party-post/retrieve/json".format(self.url), data=data)
# ## Friend's Wall
def post_wall_comment_retrieve(self, token: str, post_id: int):
data = {"_token": token, "postId": post_id}
def post_wall_comment_retrieve(self, post_id: int):
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/wall-comment/retrieve/json".format(self.url), data=data)
def post_wall_post_create(self, token: str, body: str):
data = {"_token": token, "post_message": body}
def post_wall_comment_create(self, post_id: int, comment_message: str):
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/wall-comment/create/json".format(self.url), data=data)
def post_wall_post_create(self, body: str):
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/wall-post/create/json".format(self.url), data=data)
def post_wall_post_retrieve(self, token: str):
data = {"_token": token, "page": 1, "switchedFrom": False}
def post_wall_post_retrieve(self):
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data)
@ -921,7 +940,7 @@ class MyJSONEncoder(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(_content=o._content.decode("UTF-8"), headers=o.headers.__dict__, url=o.url, text=o.text)
return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
elif hasattr(o, '__dict__'):
return o.__dict__
elif isinstance(o, deque):
@ -998,21 +1017,24 @@ class Battle(object):
else:
end = datetime.datetime.max
self.div.update({div: BattleDivision(end, data.get('epic_type') in [1, 5],
data.get('dom_pts').get("inv"), data.get('dom_pts').get("def"),
data.get('wall').get("for"), data.get('wall').get("dom"))})
battle_div = BattleDivision(
end=end, epic=data.get('epic_type') in [1, 5],
inv_pts=data.get('dom_pts').get("inv"), def_pts=data.get('dom_pts').get("def"),
wall_for=data.get('wall').get("for"), wall_dom=data.get('wall').get("dom")
)
self.div.update({div: battle_div})
def __repr__(self):
now = utils.now()
is_started = self.start < utils.now()
if is_started:
timepart = "{}".format(now - self.start)
time_part = "{}".format(now - self.start)
else:
timepart = "- {}".format(self.start - now)
return "Battle {} | {:>21.21}:{:<21.21} | Round {:2} | Start {}".format(self.id,
utils.COUNTRIES[self.invader.id],
utils.COUNTRIES[self.defender.id],
self.zone_id, timepart)
time_part = "- {}".format(self.start - now)
return "Battle {} | {:>21.21}:{:<21.21} | Round {:2} | Start {}".format(
self.id, utils.COUNTRIES[self.invader.id], utils.COUNTRIES[self.defender.id], self.zone_id, time_part
)
class EnergyToFight:

View File

@ -6,6 +6,7 @@ import re
import sys
import time
import traceback
import unicodedata
from collections import deque
from decimal import Decimal
from json import JSONEncoder
@ -15,7 +16,6 @@ from typing import Union
import pytz
import requests
from requests import Response
from slugify import slugify
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz",
@ -214,7 +214,7 @@ def write_file(filename: str, content: str) -> int:
def write_request(response: requests.Response, is_error: bool = False):
from erepublik_script import Citizen
from erepublik import Citizen
# Remove GET args from url name
url = response.url
last_index = url.index("?") if "?" in url else len(response.url)
@ -237,8 +237,8 @@ def write_request(response: requests.Response, is_error: bool = False):
"mimetype": "application/json" if ext == "json" else "text/html"}
def send_email(name, content: list, player=None, local_vars=dict, promo: bool = False, captcha: bool = False):
from erepublik_script import Citizen
def send_email(name: str, content: list, player=None, local_vars=dict, promo: bool = False, captcha: bool = False):
from erepublik import Citizen
file_content_template = "<html><head><title>{title}</title></head><body>{body}</body></html>"
if isinstance(player, Citizen):
@ -284,156 +284,6 @@ def send_email(name, content: list, player=None, local_vars=dict, promo: bool =
requests.post('https://pasts.72.lv', data=data, files=files)
def parse_input(msg: str) -> bool:
msg += " (y|n):"
data = None
while data not in ['', 'y', 'Y', 'n', 'N']:
try:
data = input(msg)
except EOFError:
data = 'n'
return data in ['', 'y', 'Y']
def parse_config(config=None) -> dict:
if config is None:
config = {}
if not config.get('email'):
config['email'] = input("Player email: ")
if not config.get('password'):
config['password'] = input("Player password: ")
if 'wt' in config:
config['work'] = config['wt']
config['train'] = config['wt']
if 'work' not in config:
config['work'] = parse_input('Should I work')
if 'train' not in config:
config['train'] = parse_input('Should I train')
if 'ot' not in config:
config['ot'] = parse_input('Should I work overtime')
if 'wam' not in config:
config['wam'] = parse_input('Should I WAM')
if 'employ' not in config:
config['employ'] = parse_input('Should I employ employees')
if config['wam'] or config['employ']:
if "autosell" in config:
config.pop("autosell")
if "autosell_raw" in config:
config.pop("autosell_raw")
if "autosell_final" in config:
config.pop("autosell_final")
if 'auto_sell' not in config or not isinstance(config['auto_sell'], list):
if parse_input('Should I auto sell produced products'):
config['auto_sell'] = []
if parse_input("Should I auto sell Food products"):
if parse_input("Should I auto sell Food products"):
config['auto_sell'].append("food")
if parse_input("Should I auto sell Weapon products"):
config['auto_sell'].append("weapon")
if parse_input("Should I auto sell House products"):
config['auto_sell'].append("house")
if parse_input("Should I auto sell Aircraft products"):
config['auto_sell'].append("airplane")
if parse_input("Should I auto sell raw products"):
if parse_input("Should I auto sell Food raw"):
config['auto_sell'].append("foodRaw")
if parse_input("Should I auto sell Weapon raw"):
config['auto_sell'].append("weaponRaw")
if parse_input("Should I auto sell House raw"):
config['auto_sell'].append("houseRaw")
if parse_input("Should I auto sell Airplane raw"):
config['auto_sell'].append("airplaneRaw")
if config['auto_sell']:
if 'auto_sell_all' not in config:
print("When selling produced items should I also sell items already in inventory?")
config['auto_sell_all'] = parse_input('Y - sell all, N - only just produced')
else:
config['auto_sell_all'] = False
if 'auto_buy_raw' not in config:
config['auto_buy_raw'] = parse_input('Should I auto buy raw deficit at WAM or employ')
else:
config['auto_sell'] = []
config['auto_sell_all'] = False
config['auto_buy_raw'] = False
if 'fight' not in config:
config['fight'] = parse_input('Should I fight')
if config.get('fight'):
if 'air' not in config:
config['air'] = parse_input('Should I fight in AIR')
if 'ground' not in config:
config['ground'] = parse_input('Should I fight in GROUND')
if 'all_in' not in config:
print("When full energy should I go all in")
config['all_in'] = parse_input('Y - all in, N - 1h worth of energy')
if 'next_energy' not in config:
config['next_energy'] = parse_input('Should I fight when next pp +1 energy available')
if 'boosters' not in config:
config['boosters'] = parse_input('Should I use +50% dmg boosters')
if 'travel_to_fight' not in config:
config['travel_to_fight'] = parse_input('Should I travel to fight')
if 'epic_hunt' not in config:
config['epic_hunt'] = parse_input('Should I check for epic battles')
if not config['epic_hunt']:
config['epic_hunt_ebs'] = False
if not config['epic_hunt']:
config['epic_hunt_ebs'] = False
elif 'epic_hunt_ebs' not in config:
config['epic_hunt_ebs'] = parse_input('Should I eat EBs when fighting in epic battle')
if 'rw_def_side' not in config:
config['rw_def_side'] = parse_input('Should I fight on defenders side in RWs')
if 'continuous_fighting' not in config:
config['continuous_fighting'] = parse_input('If already fought in any battle, \n'
'should I continue to fight all FF in that battle')
else:
config['air'] = False
config['ground'] = False
config['all_in'] = False
config['next_energy'] = False
config['boosters'] = False
config['travel_to_fight'] = False
config['epic_hunt'] = False
config['epic_hunt_ebs'] = False
config['rw_def_side'] = False
config['continuous_fighting'] = False
if 'debug' not in config:
config['debug'] = parse_input('Should I generate debug files')
if 'random_sleep' not in config:
config['random_sleep'] = parse_input('Should I add random amount (0-120sec) to sleep time')
if 'gold_buy' not in config:
config['gold_buy'] = parse_input('Should I auto buy 10g every day')
if 'interactive' not in config:
config['interactive'] = parse_input('Should I print output to console?')
return config
def normalize_html_json(js: str) -> str:
js = re.sub(r' \'(.*?)\'', lambda a: '"%s"' % a.group(1), js)
js = re.sub(r'(\d\d):(\d\d):(\d\d)', r'\1\2\3', js)
@ -446,7 +296,6 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
interactive: bool = False):
"""
Process error logging and email sending to developer
:param error:
:param interactive: Should print interactively
:param log_info: String to be written in output
:param name: String Instance name
@ -462,4 +311,25 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
write_interactive_log(log_info)
else:
write_silent_log(log_info)
send_email(name, bugtrace, citizen, local_vars=inspect.trace()[-1][0].f_locals)
trace = inspect.trace()
if trace:
trace = trace[-1][0].f_locals
else:
trace = dict()
send_email(name, bugtrace, citizen, local_vars=trace)
def slugify(value, allow_unicode=False):
"""
Function copied from Django2.2.1 django.utils.text.slugify
Convert to ASCII if 'allow_unicode' is False. Convert spaces to hyphens.
Remove characters that aren't alphanumerics, underscores, or hyphens.
Convert to lowercase. Also strip leading and trailing whitespace.
"""
value = str(value)
if allow_unicode:
value = unicodedata.normalize('NFKC', value)
else:
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub(r'[^\w\s-]', '', value).strip().lower()
return re.sub(r'[-\s]+', '-', value)

View File

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
"""Top-level package for eRepublik script."""
__author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv'
__version__ = '0.14.3'
__all__ = ["Citizen"]
from erepublik_script import classes, utils
from erepublik_script.citizen import Citizen

View File

@ -1,6 +1,6 @@
pip==19.1.1
bumpversion==0.5.3
wheel==0.32.1
wheel==0.33.4
watchdog==0.9.0
flake8==3.7.8
tox==3.13.2

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.14.3
current_version = 0.14.6
commit = True
tag = True
@ -7,7 +7,7 @@ tag = True
search = version='{current_version}'
replace = version='{new_version}'
[bumpversion:file:erepublik_script/__init__.py]
[bumpversion:file:erepublik/__init__.py]
search = __version__ = '{current_version}'
replace = __version__ = '{new_version}'
@ -17,7 +17,7 @@ universal = 1
[flake8]
exclude = docs
max-line-length = 120
ignore = E722
ignore = E722 F401
[aliases]

View File

@ -11,7 +11,7 @@ with open('README.rst') as readme_file:
with open('HISTORY.rst') as history_file:
history = history_file.read()
requirements = ['pytz==2019.1', 'requests==2.22.0', 'python-slugify<3.0.0']
requirements = ['pytz==2019.1', 'requests==2.22.0']
setup_requirements = [ ]
@ -21,26 +21,26 @@ setup(
author="Eriks Karls",
author_email='eriks@72.lv',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
],
description="Python package for eRepublik automated playing",
description="Python package for automated eRepublik playing",
entry_points={},
install_requires=requirements,
license="MIT license",
long_description=readme + '\n\n' + history,
include_package_data=True,
keywords='erepublik_script',
name='erepublik_script',
packages=find_packages(include=['erepublik_script']),
keywords='erepublik',
name='eRepublik',
packages=find_packages(include=['erepublik']),
setup_requires=setup_requirements,
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/eeriks/erepublik_script',
version='0.14.3',
version='0.14.6',
zip_safe=False,
)

View File

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Unit test package for erepublik_script."""
"""Unit test package for erepublik."""

View File

@ -1,18 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tests for `erepublik_script` package."""
"""Tests for `erepublik` package."""
import unittest
from click.testing import CliRunner
from erepublik_script import Citizen
from erepublik_script import cli
from erepublik import Citizen
from erepublik import cli
class TestErepublik_script(unittest.TestCase):
"""Tests for `erepublik_script` package."""
"""Tests for `erepublik` package."""
def setUp(self):
"""Set up test fixtures, if any."""
@ -28,7 +28,7 @@ class TestErepublik_script(unittest.TestCase):
runner = CliRunner()
result = runner.invoke(cli.main)
assert result.exit_code == 0
assert 'erepublik_script.cli.main' in result.output
assert 'erepublik.cli.main' in result.output
help_result = runner.invoke(cli.main, ['--help'])
assert help_result.exit_code == 0
assert '--help Show this message and exit.' in help_result.output