|
15 | 15 |
|
16 | 16 | import json |
17 | 17 | import time |
| 18 | +from datetime import datetime |
18 | 19 | from typing import Any, Dict, List, Optional, Tuple |
19 | 20 |
|
20 | 21 | import requests |
@@ -249,13 +250,13 @@ class Api_checker: |
249 | 250 |
|
250 | 251 | def __init__(self): |
251 | 252 | self.force_stop = False |
252 | | - self.last_match_timestamp = -1 |
253 | | - self.last_rating_timestamp = -1 |
| 253 | + self.last_match_timestamp = datetime(1900, 1, 1, 0, 0, 0) |
| 254 | + self.last_rating_timestamp = datetime(1900, 1, 1, 0, 0, 0) |
254 | 255 |
|
255 | 256 | def reset(self): |
256 | 257 | """ Resets last timestamps""" |
257 | | - self.last_match_timestamp = -1 |
258 | | - self.last_rating_timestamp = -1 |
| 258 | + self.last_match_timestamp = datetime(1900, 1, 1, 0, 0, 0) |
| 259 | + self.last_rating_timestamp = datetime(1900, 1, 1, 0, 0, 0) |
259 | 260 |
|
260 | 261 | def sleep(self, seconds: int) -> bool: |
261 | 262 | """ Sleeps while checking for force_stop |
@@ -284,133 +285,56 @@ def check_for_new_game(self, |
284 | 285 | return |
285 | 286 |
|
286 | 287 | def get_data(self) -> Optional[Dict[str, Any]]: |
287 | | - """ Returns match data if there is a new game""" |
288 | 288 | if self.force_stop: |
289 | 289 | return |
290 | 290 |
|
291 | | - # Match history |
| 291 | + # Get last match from aoe4world.com |
292 | 292 | try: |
293 | | - match_history = get_match_history(amount=1, raise_exception=True) |
294 | | - except json.decoder.JSONDecodeError: |
295 | | - # AoEIV.net down |
296 | | - return {'server_down': True} |
| 293 | + url = f"https://aoe4world.com/api/v0/players/{settings.profile_id}/games/last" |
| 294 | + resp = session.get(url) |
| 295 | + data = json.loads(resp.text) |
297 | 296 | except Exception: |
298 | | - return |
299 | | - |
300 | | - if not match_history: |
301 | | - return |
302 | | - |
303 | | - match = match_history[0] |
304 | | - leaderboard_id = match_mode(match) |
305 | | - |
306 | | - # No players in the game |
307 | | - if not match['players']: |
| 297 | + logger.exception("") |
308 | 298 | return |
309 | 299 |
|
310 | 300 | if self.force_stop: |
311 | 301 | return |
312 | | - |
313 | | - # Show the last game |
314 | | - if match['started'] > self.last_match_timestamp: |
315 | | - self.last_match_timestamp = match['started'] |
316 | | - |
317 | | - # Remove duplicated players |
318 | | - match['players'] = self.get_unique_players(match['players']) |
319 | | - # Gets additional player data from leaderboards stats (in-place) |
320 | | - for player in match['players']: |
321 | | - self.get_player_data(leaderboard_id, player) |
322 | | - return match |
323 | | - |
324 | | - # Rating history |
325 | | - if not quickmatch_game(match): |
326 | | - return |
327 | | - rating_history = get_rating_history(leaderboard_id, amount=1) |
328 | | - if not rating_history: |
| 302 | + if "error" in data: |
329 | 303 | return |
330 | | - rating = rating_history[0] |
331 | | - |
332 | | - # Check for new rating data |
333 | | - if self.last_match_timestamp != -1 and \ |
334 | | - rating['timestamp'] > self.last_rating_timestamp: |
335 | 304 |
|
336 | | - self.last_rating_timestamp = rating['timestamp'] |
337 | | - return {"new_rating": True, 'timestamp': rating['timestamp']} |
| 305 | + # Calc old leaderboard id |
| 306 | + data['leaderboard_id'] = 0 |
| 307 | + try: |
| 308 | + data['leaderboard_id'] = int(data['kind'][-1]) + 16 |
| 309 | + except Exception: |
| 310 | + logger.exception("") |
338 | 311 |
|
339 | | - @staticmethod |
340 | | - def get_unique_players( |
341 | | - players: List[Dict[str, Any]]) -> List[Dict[str, Any]]: |
342 | | - """ Create a new list of players that has only unique players |
| 312 | + # Calc started time |
| 313 | + started = datetime.strptime(data['started_at'], |
| 314 | + "%Y-%m-%dT%H:%M:%S.000Z") |
| 315 | + data['started_sec'] = started.timestamp() |
343 | 316 |
|
344 | | - AoEIV.net sometimes returns players multiple times in player list """ |
345 | | - ids = set() |
346 | | - filtered = list() |
| 317 | + # Show the last game |
| 318 | + if started > self.last_match_timestamp: # and data['ongoing']: |
| 319 | + self.last_match_timestamp = started |
| 320 | + return data |
347 | 321 |
|
348 | | - for p in players: |
349 | | - playerid = p["profile_id"] |
350 | | - if playerid in ids: |
351 | | - continue |
352 | | - ids.add(playerid) |
353 | | - filtered.append(p) |
354 | | - return filtered |
| 322 | + if not "qm_" in data['kind']: |
| 323 | + return |
355 | 324 |
|
356 | | - @staticmethod |
357 | | - def get_player_data(leaderboard_id: int, player_dict: Dict[str, Any]): |
358 | | - """ Updates player data inplace""" |
| 325 | + # When a game finished |
| 326 | + if started > self.last_rating_timestamp and not data['ongoing']: |
359 | 327 |
|
360 | | - try: |
361 | | - url = f"https://aoe4world.com/api/v0/players/{player_dict['profile_id']}" |
362 | | - data = json.loads(session.get(url).text) |
363 | | - player_dict['name'] = data['name'] |
364 | | - |
365 | | - data = data['modes'][f'qm_{mode_data[leaderboard_id]}'] |
366 | | - player_dict['rank'] = zeroed(data["rank"]) |
367 | | - player_dict['rating'] = zeroed(data["rating"]) |
368 | | - player_dict['wins'] = zeroed(data["wins_count"]) |
369 | | - player_dict['losses'] = zeroed(data["games_count"]) - zeroed( |
370 | | - data["wins_count"]) |
371 | | - player_dict['streak'] = zeroed(data["streak"]) |
372 | | - |
373 | | - # AoE4World.com civ stats currently work only for 1v1 |
374 | | - if mode_data[leaderboard_id] == "1v1": |
375 | | - civ_name = net_to_world.get(player_dict['civ']) |
376 | | - for civ in data['civilizations']: |
377 | | - if civ['civilization'] == civ_name: |
378 | | - player_dict['civ_games'] = civ['games_count'] |
379 | | - player_dict['civ_winrate'] = civ['win_rate'] |
380 | | - player_dict['civ_win_length_median'] = civ[ |
381 | | - 'game_length']['wins_median'] |
382 | | - return |
383 | | - logger.warning( |
384 | | - f"Didn't find civ: {civ_name} in aoe4world.com player civ list" |
385 | | - ) |
386 | | - return |
387 | | - except Exception: |
388 | | - logger.exception( |
389 | | - f"AoE4wWorld.com failed for player {player_dict.get('profile_id')}" |
390 | | - ) |
| 328 | + # Check for new ratings |
| 329 | + if not data['leaderboard_id']: |
| 330 | + return |
391 | 331 |
|
392 | | - # If AoE4World.com fails, default to aoeiv.net |
393 | | - try: |
394 | | - url = f"https://aoeiv.net/api/leaderboard?game=aoe4&leaderboard_id={leaderboard_id}&profile_id={player_dict['profile_id']}&count=1" |
395 | | - data = json.loads(session.get(url).text) |
396 | | - |
397 | | - if data['leaderboard']: |
398 | | - data = data["leaderboard"][0] |
399 | | - player_dict['rank'] = data["rank"] |
400 | | - player_dict['rating'] = data["rating"] |
401 | | - player_dict['wins'] = data["wins"] |
402 | | - player_dict['losses'] = data["losses"] |
403 | | - player_dict['streak'] = data["streak"] |
404 | | - |
405 | | - # Sometimes AoEIV.net returns no name for the player |
406 | | - if player_dict['name'] is None: |
407 | | - player_dict['name'] = data['name'] |
408 | | - else: |
409 | | - player_dict['rating'] = "–" |
| 332 | + rating_history = get_rating_history(data['leaderboard_id'], |
| 333 | + amount=1) |
410 | 334 |
|
411 | | - except Exception: |
412 | | - logger.exception("Failed to get player data from aoeiv.net") |
| 335 | + if not rating_history: |
| 336 | + return |
413 | 337 |
|
414 | | - # Last check on AoE4World for player name |
415 | | - if player_dict['name'] is None: |
416 | | - player_dict['name'] = get_player_name(player_dict['profile_id']) |
| 338 | + self.last_rating_timestamp = started |
| 339 | + rating = rating_history[0] |
| 340 | + return {"new_rating": True, 'timestamp': rating['timestamp']} |
0 commit comments