2 # -*- coding: utf-8 -*-
8 from datetime import datetime
11 from http.cookiejar import CookieJar
13 from html_parser import *
20 HOME = os.environ['HOME']
21 ARCHIVE = HOME + '/fourmizzz/archive.py'
22 RESULT = HOME + '/fourmizzz/results.log'
26 That function will read config.py in fourmizzz directory
27 and set up globals SERVER, LOGIN, PASSWORD, and BASE_URL.
29 global SERVER, LOGIN, PASSWORD
31 CONFIG_TEMPLATE='''# Veuillez modifier les lignes ci dessous avec vos paramètres:
32 SERVER = 's1.fourmizzz.fr'
33 LOGIN = 'MonIdentifiant'
34 PASSWORD = 'MonMotDePasse'
37 sys.path.append(HOME+'/fourmizzz')
41 CONFIG = HOME+'/fourmizzz/config.py'
42 logging.fatal("No configuration file. Creating %s", CONFIG)
43 f = open(CONFIG, mode='w+', encoding='utf-8')
44 f.write(CONFIG_TEMPLATE)
46 logging.fatal("Please update this file with your details.")
48 SERVER = config.SERVER
50 PASSWORD = config.PASSWORD
51 BASE_URL = 'http://%s' % SERVER
53 def hide_password_from_log(txt):
54 return re.sub('mot_passe=.*', 'mot_passe=********', txt)
57 def httpopen(url, post_data=None):
59 log_post_data = hide_password_from_log(post_data)
60 post_data = post_data.encode('utf-8') # str->bytes
61 logging.debug('HTTP POST %s %s', url, log_post_data)
63 logging.debug('HTTP GET %s', url)
65 if __opener__ is None:
66 cookiejar = CookieJar()
67 __opener__ = urllib.request.build_opener()
68 __opener__.add_handler(urllib.request.HTTPCookieProcessor(cookiejar))
69 http_response = __opener__.open(url, post_data)
73 logging.debug('Waiting %s seconds', seconds)
77 return calendar.timegm(datetime.now().timetuple())
87 result = ('%03d' % d3) + result
89 result = ('%d' % d3) + result
93 def tdc_get(alliance_tag=None):
94 #httpresponse = httpopen(BASE_URL + '/')
95 #html = httpresponse.read().decode('utf-8')
98 httpresponse = httpopen(BASE_URL + '/index.php?connexion=1', 'serveur=%s&pseudo=%s&mot_passe=%s' % (SERVER, LOGIN, PASSWORD))
99 #httpresponse = httpopen(BASE_URL + '/index.php?connexion=1', 'serveur=%s&pseudo=%s&mot_passe=%s&connexion=Connexion' % (SERVER, LOGIN, PASSWORD))
100 html = httpresponse.read().decode('utf-8')
101 if "redirectReine" not in html:
102 logging.fatal("Impossible de s'authentifier. Vérifiez vos paramètres dans config.py")
107 #httpresponse = httpopen(BASE_URL + '/alliance.php?Membres')
108 #html = httpresponse.read().decode('utf-8')
113 httpresponse = httpopen(BASE_URL + '/alliance.php?Membres',
114 'xajax=membre&xajaxr='+str(timestamp()))
115 html = httpresponse.read().decode('utf-8')
119 root = html_parse(html)
120 table = get_elem(root, 'table')[0]
121 td = get_elem(table, 'td')[3]
122 table = get_elem(td, 'table')[0]
124 #print_idented_tree(table)
126 httpresponse = httpopen(BASE_URL + '/classementAlliance.php?alliance=%s' % alliance_tag)
127 html = httpresponse.read().decode('utf-8')
129 root = html_parse(html)
130 table = get_elem(root, 'table')[2]
132 #print_idented_tree(table)
135 for tr in get_elem(table, 'tr'):
136 row = get_elem(tr, 'td')
137 if not alliance_tag and len(row) != 10:
139 if alliance_tag and len(row) != 6:
142 #print_idented_tree(tr)
144 nick = get_merged_leaf_content(row[3])
145 tdc = get_merged_leaf_content(row[4]).replace(' ', '')
147 nick = get_merged_leaf_content(row[2])
148 tdc = get_merged_leaf_content(row[3]).replace(' ', '')
153 logging.debug('%s members - total tdc = %s cm²', len(summary), number_format(sum(summary.values())))
157 def tdc_compare(oldtdc, newtdc):
160 for nick in newtdc.keys():
161 told = oldtdc.get(nick, 0)
165 changes[nick] = { 'old': told, 'new': tnew, 'delta': tnew-told }
167 for nick in oldtdc.keys():
168 if nick not in newtdc:
171 changes[nick] = { 'old': told, 'new': 0, 'delta': -told }
172 #for nick, change in changes.items():
173 # print(nick, ' - ', change['old'], ' - ', change['new'], ' - ', change['delta'])
177 logging.info('No changes')
180 for nick in changes.keys():
181 delta = changes[nick]['delta']
183 continue # 0 is already process, <0 will be processed when nick swaps with nick2
184 for nick2 in changes.keys():
185 if changes[nick2]['delta'] == 0:
186 continue # already done
187 if changes[nick2]['delta'] != -delta:
188 continue # not the good one
189 percent = float(oldtdc[nick2] - newtdc[nick2]) / oldtdc[nick2] * 100.
190 txtchanges.append('%s a pris %s cm² à %s (%.2f%%)' % (nick, number_format(delta), nick2, percent))
191 changes[nick]['delta'] = 0
192 changes[nick2]['delta'] = 0
195 for nick, change in changes.items():
196 delta = change['delta']
199 percent = float(-delta) / oldtdc[nick] * 100.
200 txtchanges.append('%s a perdu %s cm² (%.2f%%)' % (nick, number_format(-delta), percent))
202 txtchanges.append("%s a quité l'alliance avec %s cm²" % (nick, number_format(-delta)))
205 txtchanges.append('%s a gagné %s cm²' % (nick, number_format(delta)))
207 txtchanges.append("%s a rejoint l'alliance avec %s cm²" % (nick, number_format(delta)))
209 for txtchange in txtchanges:
210 logging.info(txtchange)
213 if __name__ == '__main__':
214 from optparse import OptionParser
215 parser = OptionParser()
216 parser.add_option('-d', '--debug',
217 action='store_true', dest='debug', default=False,
219 parser.add_option('-a', '--alliance',
221 help="alliance tag. default is to process player own alliance.")
222 parser.add_option('--dry-run',
223 action='store_true', dest='dryrun', default=False,
224 help="don't store result in archives.")
225 options, args = parser.parse_args()
228 loglevel = logging.DEBUG
230 loglevel = logging.INFO
231 logging.basicConfig(filename=RESULT, level=loglevel, format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S %Z')
237 f = open(ARCHIVE, mode='r+', encoding='utf-8')
238 except IOError as err:
239 if err.errno == 2: # No such file or directory
240 logging.warning("No archive file, creating one.")
241 f = open(ARCHIVE, mode='w+', encoding='utf-8')
245 oldtdc = eval(f.read())
247 newtdc = tdc_get(options.alliance)
248 if oldtdc is not None:
249 tdc_compare(oldtdc, newtdc)
251 # Save archive only after processing, just in case it crashes
252 if not options.dryrun:
254 f.write(repr(newtdc))