| @@ -2,6 +2,7 @@ | |||
| import time | |||
| from flask import g | |||
| import requests | |||
| from ..exceptions import ZKillboardError | |||
| @@ -20,6 +21,45 @@ class ZKillboard: | |||
| self._base_url = "https://zkillboard.com/api" | |||
| self._last_query = 0 | |||
| def _extend_killmail(self, kill): | |||
| """Extend a killmail object to match the old ZKill format. | |||
| Requires ESI API calls to fill in entity names. If we can't do them, | |||
| we'll just set the names to be empty. | |||
| """ | |||
| esi = g.eve.esi() | |||
| victim = kill["victim"] | |||
| if "character_id" in victim: | |||
| char_info = esi.v4.characters(victim["character_id"]).get() | |||
| victim["character_name"] = char_info["name"] | |||
| else: | |||
| victim["character_id"] = 0 | |||
| victim["character_name"] = "" | |||
| if "corporation_id" in victim: | |||
| corp_info = esi.v3.corporations(victim["corporation_id"]).get() | |||
| victim["corporation_name"] = corp_info["corporation_name"] | |||
| else: | |||
| victim["corporation_id"] = 0 | |||
| victim["corporation_name"] = "" | |||
| if "alliance_id" in victim: | |||
| alliance_info = esi.v2.alliances(victim["alliance_id"]).get() | |||
| victim["alliance_name"] = alliance_info["alliance_name"] | |||
| else: | |||
| victim["alliance_id"] = 0 | |||
| victim["alliance_name"] = "" | |||
| if "faction_id" in victim: | |||
| factions = esi.v1.universe.factions.get() | |||
| matches = [fac["faction_name"] for fac in factions | |||
| if fac["faction_id"] == victim["faction_id"]] | |||
| victim["faction_name"] = matches[0] if matches else "" | |||
| else: | |||
| victim["faction_id"] = 0 | |||
| victim["faction_name"] = "" | |||
| def query(self, *args): | |||
| """Make an API query using the given arguments.""" | |||
| query = "/" + "".join(str(arg) + "/" for arg in args) | |||
| @@ -47,10 +87,15 @@ class ZKillboard: | |||
| self._last_query = time.time() | |||
| return result | |||
| def iter_killmails(self, *args): | |||
| def iter_killmails(self, *args, extended=False): | |||
| """Return an iterator over killmails using the given API arguments. | |||
| Automagically follows pagination as far as possible. (Be careful.) | |||
| If extended is True, we will provide extra information for each kill | |||
| (names of entities instead of just IDs), which requires ESI API calls. | |||
| This matches the original API format of ZKill before it was, er, | |||
| "simplified". | |||
| """ | |||
| page = 1 | |||
| while True: | |||
| @@ -60,7 +105,11 @@ class ZKillboard: | |||
| result = self.query(*args) | |||
| if result: | |||
| yield from result | |||
| if extended: | |||
| for kill in result: | |||
| yield self._extend_killmail(kill) | |||
| else: | |||
| yield from result | |||
| page += 1 | |||
| else: | |||
| break | |||
| @@ -94,10 +94,10 @@ class CampaignDB: | |||
| def add_kill(self, kill): | |||
| """Insert a killmail into the database.""" | |||
| try: | |||
| datetime.strptime(kill["killTime"], "%Y-%m-%d %H:%M:%S") | |||
| datetime.strptime(kill["killmail_time"], "%Y-%m-%d %H:%M:%S") | |||
| except ValueError: | |||
| raise RuntimeError("Invalid kill_date=%s for kill_id=%d" % ( | |||
| kill["killTime"], kill["killID"])) | |||
| kill["killmail_time"], kill["killmail_id"])) | |||
| query = """INSERT OR REPLACE INTO kill ( | |||
| kill_id, kill_date, kill_system, kill_victim_shipid, | |||
| @@ -108,12 +108,13 @@ class CampaignDB: | |||
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""" | |||
| victim = kill["victim"] | |||
| args = ( | |||
| int(kill["killID"]), kill["killTime"], int(kill["solarSystemID"]), | |||
| int(victim["shipTypeID"]), int(victim["characterID"]), | |||
| victim["characterName"], int(victim["corporationID"]), | |||
| victim["corporationName"], int(victim["allianceID"]), | |||
| victim["allianceName"], int(victim["factionID"]), | |||
| victim["factionName"], float(kill["zkb"]["totalValue"])) | |||
| int(kill["killmail_id"]), kill["killmail_time"], | |||
| int(kill["solar_system_id"]), int(victim["ship_type_id"]), | |||
| int(victim["character_id"]), victim["character_name"], | |||
| int(victim["corporation_id"]), victim["corporation_name"], | |||
| int(victim["alliance_id"]), victim["alliance_name"], | |||
| int(victim["faction_id"]), victim["faction_name"], | |||
| float(kill["zkb"]["totalValue"])) | |||
| with self._conn as conn: | |||
| conn.execute(query, args) | |||
| @@ -33,7 +33,7 @@ def _build_filter(qualifiers, arg): | |||
| def _store_kill(cname, opnames, kill): | |||
| """Store the given kill and its associations into the database.""" | |||
| kid = kill["killID"] | |||
| kid = kill["killmail_id"] | |||
| if g.campaign_db.has_kill(kid): | |||
| current = g.campaign_db.get_kill_associations(cname, kid) | |||
| opnames -= set(current) | |||
| @@ -59,12 +59,16 @@ def _update_killboard_operations(cname, opnames, min_kill_id): | |||
| "no-attackers", "orderDirection", "desc"] | |||
| max_kill_id = min_kill_id | |||
| for kill in g.eve.zkill.iter_killmails(*args): | |||
| kid = kill["killID"] | |||
| for kill in g.eve.zkill.iter_killmails(*args, extended=True): | |||
| kid = kill["killmail_id"] | |||
| if min_kill_id > 0 and kid == min_kill_id: | |||
| # TODO: This fails if ZKill receives kills out of order. | |||
| # Should look ahead for kills within, say, 12 hours of the | |||
| # min_kill_id, and extend code below to ignore kills aleady | |||
| # included instead of re-adding. | |||
| break | |||
| ktime = kill["killTime"] | |||
| ktime = kill["killmail_time"] | |||
| logger.debug("Evaluating kill date=%s id=%d for campaign=%s " | |||
| "operations=%s", ktime, kid, cname, ",".join(opnames)) | |||
| max_kill_id = max(max_kill_id, kid) | |||