@ -2,9 +2,8 @@ import datetime
import decimal
import hashlib
import random
import sys
import threading
import time
import traceback
from collections import deque
from json import JSONDecodeError , loads , JSONEncoder
from typing import Any , Dict , List , Union , Mapping , Iterable , Tuple
@ -19,7 +18,7 @@ class ErepublikException(Exception):
super ( ) . __init__ ( message )
class ErepublikNetworkException ( Exception) :
class ErepublikNetworkException ( Erepublik Exception) :
def __init__ ( self , message , request ) :
super ( ) . __init__ ( message )
self . request = request
@ -41,7 +40,7 @@ class MyCompanies:
"""
:param holdings: Parsed JSON to dict from en/economy/myCompanies
"""
self . holdings = { }
self . holdings . clear ( )
template = dict ( id = 0 , num_factories = 0 , region_id = 0 , companies = [ ] )
for holding_id , holding in holdings . items ( ) :
@ -58,18 +57,20 @@ class MyCompanies:
"""
:param companies: Parsed JSON to dict from en/economy/myCompanies
"""
self . companies = { }
self . companies . clear ( )
template = dict ( id = None , quality = 0 , is_raw = False , resource_bonus = 0 , effective_bonus = 0 , raw_usage = 0 ,
production = 0 , base_production= 0 , wam_enabled = False , can_work_as_manager = False ,
base_production = 0 , wam_enabled = False , can_work_as_manager = False , industry_id = 0 , todays_works = 0 ,
preset_own_work = 0 , already_worked = False , can_assign_employees = False , preset_works = 0 ,
todays_works = 0 , holding_company_id= None , is_assigned_to_holding = False ,
cannot_work_as_manager_reason = False , industry_id = 0 )
holding_company_id = None , is_assigned_to_holding = False , cannot_work_as_manager_reason = False )
for c_id , company in companies . items ( ) :
tmp = { }
for key in template . keys ( ) :
if key in [ ' id ' , ' holding_company_id ' ] :
company [ key ] = int ( company [ key ] )
elif key == " raw_usage " :
if not company . get ( " is_raw " ) and company . get ( ' upgrades ' ) :
company [ key ] = company . get ( ' upgrades ' ) . get ( str ( company [ " quality " ] ) ) . get ( ' raw_usage ' )
tmp . update ( { key : company [ key ] } )
self . companies . update ( { int ( c_id ) : tmp } )
@ -77,9 +78,8 @@ class MyCompanies:
for company_id , company_data in self . companies . items ( ) :
if company_id not in self . holdings [ company_data [ ' holding_company_id ' ] ] [ ' companies ' ] :
self . holdings [ company_data [ ' holding_company_id ' ] ] [ ' companies ' ] . append ( company_id )
else :
for holding_id in self . holdings :
self . holdings [ holding_id ] [ ' companies ' ] . sort ( )
for holding_id in self . holdings :
self . holdings[ holding_id ] [ ' companies ' ] . sort ( )
def get_employable_factories ( self ) - > Dict [ int , int ] :
ret = { }
@ -161,13 +161,38 @@ class MyCompanies:
raise ErepublikException ( " Wrong function call " )
@property
def __dict__ ( self ) :
ret = { }
for ke y in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
def get_wam_raw_usage ( self ) - > Dict [ str , float ] :
frm = 0.00
wrm = 0.00
for compan y in self. companies . values ( ) :
if company [ ' wam_enabled ' ] :
effective_bonus = float ( company [ " effective_bonus " ] )
base_prod = float ( company [ " base_production " ] )
raw = base_prod * effective_bonus / 100
if not company [ " is_raw " ] :
raw * = - company [ " raw_usage " ]
if company [ " industry_id " ] in [ 1 , 7 , 8 , 9 , 10 , 11 ] :
frm + = raw
elif company [ " industry_id " ] in [ 2 , 12 , 13 , 14 , 15 , 16 ] :
wrm + = raw
return { ' frm ' : int ( frm * 1000 ) / 1000 , ' wrm ' : int ( wrm * 1000 ) / 1000 }
def __str__ ( self ) :
name = [ ]
for holding_id in sorted ( self . holdings . keys ( ) ) :
if not holding_id :
name . append ( f " Unassigned - { len ( self . holdings [ 0 ] [ ' companies ' ] ) } " )
else :
name . append ( f " { holding_id } - { len ( self . holdings [ holding_id ] [ ' companies ' ] ) } " )
return " | " . join ( name )
# @property
# def __dict__(self):
# ret = {}
# for key in dir(self):
# if not key.startswith('_'):
# ret[key] = getattr(self, key)
# return ret
class SlowRequests ( Session ) :
@ -202,7 +227,7 @@ class SlowRequests(Session):
@property
def __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 )
request_log_name = self . request_log_name , debug = self . debug )
def request ( self , method , url , * args , * * kwargs ) :
self . _slow_down_requests ( )
@ -221,7 +246,10 @@ class SlowRequests(Session):
def _log_request ( self , url , method , data = None , json = None , params = None , * * kwargs ) :
if self . debug :
args = { }
args . update ( { ' kwarg s' : kwargs } )
kw args. pop ( ' allow_redirect s' , None )
if kwargs :
args . update ( { ' kwargs ' : kwargs } )
if data :
args . update ( { " data " : data } )
@ -245,10 +273,9 @@ class SlowRequests(Session):
self . _log_request ( hist_resp . request . url , " REDIRECT " )
self . _log_response ( hist_resp . request . url , hist_resp , redirect = True )
# TODO: Must thoroughly check response writing on windows systems
file_data = {
" path " : ' debug/requests ' ,
" time " : self . last_time . strftime ( ' % Y- % m- %d _ % H- % M- % S ' ) ,
" time " : self . last_time . strftime ( ' % Y/ % m/ %d / % H- % M- % S ' ) ,
" name " : utils . slugify ( url [ len ( Citizen . url ) : ] ) ,
" extra " : " _REDIRECT " if redirect else " "
}
@ -270,7 +297,7 @@ class Config:
work = True
train = True
wam = False
auto_sell : List [ str ] = list ( )
auto_sell : List [ str ] = None
auto_sell_all = False
employees = False
fight = False
@ -294,17 +321,40 @@ class Config:
telegram_chat_id = 0
telegram_token = " "
def __init__ ( self ) :
self . auto_sell = [ ]
@property
def wt ( self ) :
return self . work and self . train
@property
def __dict__ ( self ) - > Dict [ str , Union [ bool , str , List [ str ] ] ] :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) and key not in [ ' email ' , ' password ' ] :
ret [ key ] = getattr ( self , key )
return ret
def reset ( self ) :
self . work = True
self . train = True
self . wam = False
self . auto_sell = list ( )
self . auto_sell_all = False
self . employees = False
self . fight = False
self . air = False
self . ground = False
self . all_in = False
self . next_energy = False
self . boosters = False
self . travel_to_fight = False
self . always_travel = False
self . epic_hunt = False
self . epic_hunt_ebs = False
self . rw_def_side = False
self . interactive = True
self . continuous_fighting = False
self . auto_buy_raw = False
self . force_wam = False
self . sort_battles_time = True
self . force_travel = False
self . telegram = True
self . telegram_chat_id = 0
self . telegram_token = " "
class Energy :
@ -351,22 +401,14 @@ class Energy:
def available ( self ) :
return self . recovered + self . recoverable
@property
def __dict__ ( self ) :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
class Details ( object ) :
class Details :
xp = 0
cc = 0
pp = 0
pin = None
gold = 0
next_pp : List [ int ] = [ ]
next_pp : List [ int ] = None
citizen_id = 0
citizenship = 0
current_region = 0
@ -377,6 +419,9 @@ class Details(object):
daily_task_reward = False
mayhem_skills = { 1 : 0 , 2 : 0 , 3 : 0 , 4 : 0 , 5 : 0 , 6 : 0 , 7 : 0 , 8 : 0 , 9 : 0 , 10 : 0 , 11 : 0 , 12 : 0 , 13 : 0 , 14 : 0 , }
def __init__ ( self ) :
self . next_pp = [ ]
@property
def xp_till_level_up ( self ) :
if self . xp > = 10000 :
@ -403,14 +448,6 @@ class Details(object):
next_level_up = ( 1 + ( self . xp / / 10 ) ) * 10
return next_level_up - self . xp
@property
def __dict__ ( self ) :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
class Politics :
is_party_member : bool = False
@ -421,16 +458,8 @@ class Politics:
is_congressman : bool = False
is_country_president : bool = False
@property
def __dict__ ( self ) :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
class House ( object ) :
class House :
quality = None
unactivated_count = 0
active_untill = utils . good_timedelta ( utils . now ( ) , - datetime . timedelta ( days = 1 ) )
@ -455,8 +484,8 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
"""
self . _req = SlowRequests ( )
def post ( self , url : str , * args , * * kwargs ) - > Response :
return self . _req . post ( url , * args , * * kwargs )
def post ( self , url : str , data = None , json = None , * * kwargs ) - > Response :
return self . _req . post ( url , data , json , * * kwargs )
def get ( self , url : str , * * kwargs ) - > Response :
return self . _req . get ( url , * * kwargs )
@ -467,6 +496,9 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
def _get_military_battlefield_choose_side ( self , battle : int , side : int ) - > Response :
return self . get ( " {} /military/battlefield-choose-side/ {} / {} " . format ( self . url , battle , side ) )
def _get_military_show_weapons ( self , battle : int ) - > Response :
return self . get ( " {} /military/show-weapons " . format ( self . url ) , params = { ' _token ' : self . token , ' battleId ' : battle } )
def _get_candidate_party ( self , party_slug : str ) - > Response :
return self . post ( " {} /candidate/ {} " . format ( self . url , party_slug ) )
@ -532,6 +564,9 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
def _get_military_campaigns ( self ) - > Response :
return self . get ( " {} /military/campaigns-new/ " . format ( self . url ) )
def _get_military_campaigns_json_list ( self ) - > Response :
return self . get ( " {} /military/campaignsJson/list " . format ( self . url ) )
def _get_military_show_weapons ( self , battle_id : int ) - > Response :
params = { " _token " : self . token , " battleId " : battle_id }
return self . get ( " {} /military/show-weapons " . format ( self . url ) , params = params )
@ -590,6 +625,10 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = dict ( _token = self . token , sideCountryId = side_id , battleId = battle_id )
return self . post ( " {} /main/battlefieldTravel " . format ( self . url ) , data = data )
def _post_main_battlefield_change_division ( self , battle_id : int , division_id : int ) - > Response :
data = dict ( _token = self . token , battleZoneId = division_id , battleId = battle_id )
return self . post ( " {} /main/battlefieldTravel " . format ( self . url ) , data = data )
def _post_main_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 )
@ -760,6 +799,10 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
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_military_change_weapon ( self , battle : int , battle_zone : int , weapon_level : int , ) - > Response :
data = dict ( battleId = battle , _token = self . token , battleZoneId = battle_zone , customizationLevel = weapon_level )
return self . post ( " {} /military/change-weapon " . format ( self . url ) , data = data )
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 )
@ -783,21 +826,16 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data . update ( page = page )
return self . post ( " {} /military/battle-console " . format ( self . url ) , data = data )
def _post_military_change_weapon ( self , battle_id : int , battle_zone_id : int , customization_level : int ) - > Response :
data = dict ( _token = self . token , battleZoneId = battle_zone_id , battleId = battle_id ,
customizationLevel = customization_level )
return self . post ( " {} /military/change-weapon " . format ( self . url ) , data = data )
def _post_military_deploy_bomb ( self , battle_id : int , bomb_id : int ) - > Response :
data = dict ( battleId = battle_id , bombId = bomb_id , _token = self . token )
return self . post ( " {} /military/deploy-bomb " . format ( self . url ) , data = data )
def _post_military_fight_air ( self , battle_id : int , side_id : int ) - > Response :
data = dict ( sideId = side_id , battleId = battle_id , _token = self . token )
def _post_military_fight_air ( self , battle_id : int , side_id : int , zone_id : int ) - > Response :
data = dict ( sideId = side_id , battleId = battle_id , _token = self . token , battleZoneId = zone_id )
return self . post ( " {} /military/fight-shoooot/ {} " . format ( self . url , battle_id ) , data = data )
def _post_military_fight_ground ( self , battle_id : int , side_id : int ) - > Response :
data = dict ( sideId = side_id , battleId = battle_id , _token = self . token )
def _post_military_fight_ground ( self , battle_id : int , side_id : int , zone_id : int ) - > Response :
data = dict ( sideId = side_id , battleId = battle_id , _token = self . token , battleZoneId = zone_id )
return self . post ( " {} /military/fight-shooot/ {} " . format ( self . url , battle_id ) , data = data )
def _post_military_group_missions ( self ) - > Response :
@ -897,29 +935,61 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = { " _token " : self . token , " post_message " : body }
return self . post ( " {} /main/wall-post/create/json " . format ( self . url ) , data = data )
def _post_main_wall_post_automatic ( self , * * kwargs ) - > Response :
kwargs . update ( _token = self . token )
return self . post ( " {} /main/wall-post/create/json " . format ( self . url ) , data = kwargs )
def _post_main_wall_post_retrieve ( self ) - > Response :
data = { " _token " : self . token , " page " : 1 , " switchedFrom " : False }
return self . post ( " {} /main/wall-post/retrieve/json " . format ( self . url ) , data = data )
# 12th anniversary endpoints
def _get_anniversary_quest_data ( self ) - > Response :
return self . get ( " {} /main/anniversaryQuestData " . format ( self . url ) )
def _post_map_rewards_unlock ( self , node_id : int ) - > Response :
data = { ' nodeId ' : node_id , ' _token ' : self . token }
return self . post ( " {} /main/map-rewards-unlock " . format ( self . url ) , data = data )
def _post_map_rewards_speedup ( self , node_id : int , currency_amount : int ) - > Response :
data = { ' nodeId ' : node_id , ' _token ' : self . token , " currencyCost " : currency_amount }
return self . post ( " {} /main/map-rewards-speedup " . format ( self . url ) , data = data )
def _post_map_rewards_claim ( self , node_id : int ) - > Response :
data = { ' nodeId ' : node_id , ' _token ' : self . token }
return self . post ( " {} /main/map-rewards-claim " . format ( self . url ) , data = data )
def _post_new_war ( self , self_country_id : int , attack_country_id : int , debate : str = " " ) - > Response :
data = dict ( requirments = 1 , _token = self . token , debate = debate ,
countryNameConfirm = utils . COUNTRY_LINK [ attack_country_id ] )
return self . post ( " {} / {} /new-war " . format ( self . url , utils . COUNTRY_LINK [ self_country_id ] ) , data = data )
def _post_new_donation ( self , country_id : int , amount : int , org_name : str , debate : str = " " ) - > Response :
data = dict ( requirments = 1 , _token = self . token , debate = debate , currency = 1 , value = amount , commit = ' Propose ' ,
type_name = org_name )
return self . post ( " {} / {} /new-donation " . format ( self . url , utils . COUNTRY_LINK [ country_id ] ) , data = data )
class Reporter :
__to_update : List [ Dict [ Any , Any ] ] = [ ]
__to_update : List [ Dict [ Any , Any ] ] = None
name : str = " "
email : str = " "
citizen_id : int = 0
key : str = " "
allowed : bool = False
@property
def __dict__ ( self ) :
return dict ( name = self . name , email = self . email , citizen_id = self . citizen_id , key = self . key , allowed = self . allowed ,
queue = self . __to_update )
def __init__ ( self ) :
self . _req = Session ( )
self . url = " https://api.erep.lv "
self . _req . headers . update ( { " user-agent " : " Bot reporter v2 " } )
self . __to_update = [ ]
self . __registered : bool = False
@property
def __dict__ ( self ) :
return dict ( allowed = self . allowed , __to_update = self . __to_update )
def do_init ( self , name : str = " " , email : str = " " , citizen_id : int = 0 ) :
self . name : str = name
self . email : str = email
@ -996,7 +1066,7 @@ class MyJSONEncoder(JSONEncoder):
return dict ( headers = o . headers . __dict__ , url = o . url , text = o . text )
elif hasattr ( o , ' __dict__ ' ) :
return o . __dict__
elif isinstance ( o , deque ) :
elif isinstance ( o , ( deque , set ) ):
return list ( o )
elif isinstance ( o , Citizen ) :
return o . to_json ( )
@ -1015,71 +1085,84 @@ class BattleSide:
self . allies = [ int ( ally ) for ally in allies ]
self . deployed = [ int ( ally ) for ally in deployed ]
@property
def __dict__ ( self ) :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
class BattleDivision :
end : datetime . datetime
epic : bool
dom_pts : Dict [ str , int ] = None
wall : Dict [ str , Union [ int , float ] ] = None
dom_pts : Dict [ str , int ]
wall : Dict [ str , Union [ int , float ] ]
battle_zone_id : int
def_medal : Dict [ str , int ]
inv_medal : Dict [ str , int ]
@property
def div_end ( self ) - > bool :
return utils . now ( ) > = self . end
def __init__ ( self , end : datetime . datetime , epic : bool , inv_pts : int , def_pts : int , wall_for : int , wall_dom : float ) :
def __init__ (
self , div_id : int , end : datetime . datetime , epic : bool , inv_pts : int , def_pts : int ,
wall_for : int , wall_dom : float , def_medal : Tuple [ int , int ] , inv_medal : Tuple [ int , int ]
) :
self . battle_zone_id = div_id
self . end = end
self . epic = epic
self . dom_pts = dict ( { " inv " : inv_pts , " def " : def_pts } )
self . wall = dict ( { " for " : wall_for , " dom " : wall_dom } )
@property
def __dict__ ( self ) :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
self . def_medal = { " id " : def_medal [ 0 ] , " dmg " : def_medal [ 1 ] }
self . inv_medal = { " id " : inv_medal [ 0 ] , " dmg " : inv_medal [ 1 ] }
class Battle ( object ) :
id : int = 0
war_id : int = 0
zone_id : int = 0
is_rw : bool = False
is_dict_lib : bool = False
start : datetime . datetime = None
invader : BattleSide = None
defender : BattleSide = None
div : Dict [ int , BattleDivision ] = None
class Battle :
id : int
war_id : int
zone_id : int
is_rw : bool
is_dict_lib : bool
start : datetime . datetime
invader : BattleSide
defender : BattleSide
div : Dict [ int , BattleDivision ]
@property
def is_air ( self ) - > bool :
return not bool ( self . zone_id % 4 )
def __init__ ( self , battle : Dict [ str , Any ] ) :
self . id = int ( battle . get ( ' id ' , 0 ) )
self . war_id = int ( battle . get ( ' war_id ' , 0 ) )
self . zone_id = int ( battle . get ( ' zone_id ' , 0 ) )
self . is_rw = bool ( battle . get ( ' is_rw ' ) )
self . is_as = bool ( battle . get ( ' is_as ' ) )
self . is_dict_lib = bool ( battle . get ( ' is_dict ' ) ) or bool ( battle . get ( ' is_lib ' ) )
self . start = datetime . datetime . fromtimestamp ( int ( battle . get ( ' start ' , 0 ) ) , tz = utils . erep_tz )
def __init__ ( self , battle : Dict [ str , Any ] = None ) :
""" Object representing eRepublik battle.
self . invader = BattleSide ( battle . get ( ' inv ' , { } ) . get ( ' id ' ) , battle . get ( ' inv ' , { } ) . get ( ' points ' ) ,
[ row . get ( ' id ' ) for row in battle . get ( ' inv ' , { } ) . get ( ' ally_list ' ) ] ,
[ row . get ( ' id ' ) for row in battle . get ( ' inv ' , { } ) . get ( ' ally_list ' ) if row [ ' deployed ' ] ] )
:param battle: Dict object for single battle from ' /military/campaignsJson/list ' response ' s ' battles ' object
"""
if battle is None :
battle = { }
self . id = 0
self . war_id = 0
self . zone_id = 0
self . is_rw = False
self . is_as = False
self . is_dict_lib = False
self . start = utils . now ( ) . min
self . invader = BattleSide ( 0 , 0 , [ ] , [ ] )
self . defender = BattleSide ( 0 , 0 , [ ] , [ ] )
else :
self . id = int ( battle . get ( ' id ' , 0 ) )
self . war_id = int ( battle . get ( ' war_id ' , 0 ) )
self . zone_id = int ( battle . get ( ' zone_id ' , 0 ) )
self . is_rw = bool ( battle . get ( ' is_rw ' ) )
self . is_as = bool ( battle . get ( ' is_as ' ) )
self . is_dict_lib = bool ( battle . get ( ' is_dict ' ) ) or bool ( battle . get ( ' is_lib ' ) )
self . start = datetime . datetime . fromtimestamp ( int ( battle . get ( ' start ' , 0 ) ) , tz = utils . erep_tz )
self . defen der = BattleSide ( battle . get ( ' def ' , { } ) . get ( ' id ' ) , battle . get ( ' def ' , { } ) . get ( ' points ' ) ,
[ row . get ( ' id ' ) for row in battle . get ( ' def ' , { } ) . get ( ' ally_list ' ) ] ,
[ row . get ( ' id ' ) for row in battle . get ( ' def ' , { } ) . get ( ' ally_list ' ) if row [ ' deployed ' ] ] )
self . inva der = BattleSide (
battle . get ( ' inv ' , { } ) . get ( ' id ' ) , battle . get ( ' inv ' , { } ) . get ( ' points ' ) ,
[ row . get ( ' id ' ) for row in battle . get ( ' inv ' , { } ) . get ( ' ally_list ' ) ] ,
[ row . get ( ' id ' ) for row in battle . get ( ' inv ' , { } ) . get ( ' ally_list ' ) if row [ ' deployed ' ] ]
)
self . defender = BattleSide (
battle . get ( ' def ' , { } ) . get ( ' id ' ) , battle . get ( ' def ' , { } ) . get ( ' points ' ) ,
[ row . get ( ' id ' ) for row in battle . get ( ' def ' , { } ) . get ( ' ally_list ' ) ] ,
[ row . get ( ' id ' ) for row in battle . get ( ' def ' , { } ) . get ( ' ally_list ' ) if row [ ' deployed ' ] ]
)
self . div = { }
for div , data in battle . get ( ' div ' , { } ) . items ( ) :
@ -1089,11 +1172,18 @@ class Battle(object):
else :
end = utils . localize_dt ( datetime . datetime . max - datetime . timedelta ( days = 1 ) )
battle_div = B attleDivision (
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 " )
)
if not d ata [ ' stats ' ] [ ' def ' ] :
def_medal = ( 0 , 0 )
else :
def_medal = ( data [ ' stats ' ] [ ' def ' ] [ ' citizenId ' ] , data [ ' stats ' ] [ ' def ' ] [ ' damage ' ] )
if not data [ ' stats ' ] [ ' inv ' ] :
inv_medal = ( 0 , 0 )
else :
inv_medal = ( data [ ' stats ' ] [ ' inv ' ] [ ' citizenId ' ] , data [ ' stats ' ] [ ' inv ' ] [ ' damage ' ] )
battle_div = BattleDivision ( end = end , epic = data . get ( ' epic_type ' ) in [ 1 , 5 ] , div_id = data . get ( ' id ' ) ,
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 " ) ,
def_medal = def_medal , inv_medal = inv_medal )
self . div . update ( { div : battle_div } )
@ -1104,17 +1194,10 @@ class Battle(object):
time_part = " {} " . format ( now - self . start )
else :
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
)
@property
def __dict__ ( self ) :
ret = { }
for key in dir ( self ) :
if not key . startswith ( ' _ ' ) :
ret [ key ] = getattr ( self , key )
return ret
return f " Battle {self . id } | " \
f " { utils . COUNTRIES [ self . invader . id ] : >21.21 } : { utils . COUNTRIES [ self . defender . id ] : <21.21 } | " \
f " Round { self . zone_id : 2 } | " \
f " Time since start { time_part } "
class EnergyToFight :
@ -1150,33 +1233,49 @@ class EnergyToFight:
class TelegramBot :
__initialized = False
__queue : List [ str ] = [ ]
__queue : List [ str ]
chat_id = 0
api_url = " "
player_name = " "
__last_time : datetime . datetime = None
__thread_stopper : threading . Event
_last_time : datetime . datetime
_last_full_energy_report : datetime . datetime
_next_time : datetime . datetime
_threads : List [ threading . Thread ]
def __init__ ( self , stop_event : threading . Event = None ) :
self . _threads = [ ]
self . __queue = [ ]
self . __thread_stopper = threading . Event ( ) if stop_event is None else stop_event
def __dict__ ( self ) :
return dict ( chat_id = self . chat_id , api_url = self . api_url , player = self . player_name , last_time = self . _last_time ,
next_time = self . _next_time , queue = self . __queue , initialized = self . __initialized ,
has_threads = bool ( len ( self . _threads ) ) )
def do_init ( self , chat_id : int , token : str , player_name : str = " " ) :
self . chat_id = chat_id
self . api_url = " https://api.telegram.org/bot {} /sendMessage " . format ( token )
self . player_name = player_name
self . __initialized = True
self . __ last_time = utils . good_timedelta ( utils . now ( ) , datetime . timedelta ( minutes = - 5 ) )
self . _last_time = utils . good_timedelta ( utils . now ( ) , datetime . timedelta ( minutes = - 5 ) )
self . _last_full_energy_report = utils . good_timedelta ( utils . now ( ) , datetime . timedelta ( minutes = - 30 ) )
if self . __queue :
self . send_message ( " \n \n – – – – – – – – – – – – – – – – – – – – – – \n \n " . join ( self . __queue ) )
def send_message ( self , message : str ) - > bool :
self . __queue . append ( message )
if not self . __initialized :
self . __queue . append ( message )
return True
if self . player_name :
message = f " Player * { self . player_name } * \n " + message
if utils . good_timedelta ( utils . now ( ) , datetime . timedelta ( seconds = - 1 ) ) < = self . __last_time :
tb = traceback . extract_stack ( )
message + = " \n \n ``` \n {} \n ``` " . format ( " \n " . join ( [ ' File " {} " , line {} , in {} \n ' . format ( l . filename , l . lineno , l . name ) for l in tb ] ) )
response = post ( self . api_url , json = dict ( chat_id = self . chat_id , text = message , parse_mode = " Markdown " ) )
self . __last_time = utils . now ( )
return response . json ( ) . get ( ' ok ' )
self . _threads = [ t for t in self . _threads if t . is_alive ( ) ]
self . _next_time = utils . good_timedelta ( utils . now ( ) , datetime . timedelta ( minutes = 1 ) )
if not self . _threads :
name = " telegram_ {} send " . format ( f " { self . player_name } _ " if self . player_name else " " )
send_thread = threading . Thread ( target = self . __send_messages , name = name )
send_thread . start ( )
self . _threads . append ( send_thread )
return True
def report_free_bhs ( self , battles : List [ Tuple [ int , int , int , int , datetime . timedelta ] ] ) :
battle_links = [ ]
@ -1195,8 +1294,26 @@ class TelegramBot:
self . send_message ( " Free BHs: \n " + " \n " . join ( battle_links ) )
def report_full_energy ( self , available : int , limit : int , interval : int ) :
message = f " F ull energy ( { available } hp/ { limit } hp + { interval } hp/6min) "
self . send_message ( message )
if ( utils . now ( ) - self . _last_f ull_ energy_report ) . total_seconds ( ) > = 30 * 60 :
self . _last_full_energy_report = utils . now ( )
message = f " Full energy ( { available } hp/ { limit } hp + { interval } hp/6min) "
self . send_message ( message )
def report_medal ( self , msg ) :
self . send_message ( f " New award: * { msg } * " )
def __send_messages ( self ) :
while self . _next_time > utils . now ( ) :
if self . __thread_stopper . is_set ( ) :
break
self . __thread_stopper . wait ( utils . get_sleep_seconds ( self . _next_time ) )
message = " \n \n – – – – – – – – – – – – – – – – – – – – – – \n \n " . join ( self . __queue )
if self . player_name :
message = f " Player * { self . player_name } * \n " + message
response = post ( self . api_url , json = dict ( chat_id = self . chat_id , text = message , parse_mode = " Markdown " ) )
self . _last_time = utils . now ( )
if response . json ( ) . get ( ' ok ' ) :
self . __queue = [ ]
return True
return False