def run(self): cache = Cache() lastCall = 0 wait = 300 # time between 2 requests in ms while True: try: # Block waiting for addChatEntry() to enqueue something chatEntry = self.queue.get() charname = chatEntry.message.user avatar = None if charname == "VINTEL": with open(resourcePath("vi/ui/res/logo_small.png"), "rb") as f: avatar = f.read() if not avatar: avatar = cache.getAvatar(charname) if not avatar: diffLastCall = time.time() - lastCall if diffLastCall < wait: time.sleep((wait - diffLastCall) / 1000.0) avatar = evegate.getAvatarForPlayer(charname) lastCall = time.time() if avatar: cache.putAvatar(charname, avatar) if avatar: self.emit(SIGNAL("avatar_update"), chatEntry, avatar) except Exception as e: print "An error in the AvatarFindThread : {0}".format(str(e))
def run(self): cache = Cache() lastCall = 0 wait = 300 # time between 2 requests in ms while True: try: # Block waiting for addChatEntry() to enqueue something chatEntry = self.queue.get() if not self.active: return charname = chatEntry.message.user logging.debug("AvatarFindThread getting avatar for %s" % charname) avatar = None if charname == "VINTEL": with open(resourcePath("vi/ui/res/logo_small.png"), "rb") as f: avatar = f.read() if not avatar: avatar = cache.getAvatar(charname) if avatar: logging.debug("AvatarFindThread found cached avatar for %s" % charname) if not avatar: diffLastCall = time.time() - lastCall if diffLastCall < wait: time.sleep((wait - diffLastCall) / 1000.0) avatar = evegate.getAvatarForPlayer(charname) lastCall = time.time() if avatar: cache.putAvatar(charname, avatar) if avatar: logging.debug("AvatarFindThread emit avatar_update for %s" % charname) self.emit(SIGNAL("avatar_update"), chatEntry, avatar) except Exception as e: logging.error("Error in AvatarFindThread : %s", e)
def namesToIds(names): """ Uses the EVE API to convert a list of names to ids_to_names names: list of names returns a dict: key=name, value=id """ if len(names) == 0: return {} data = {} apiCheckNames = set() cache = Cache() # do we have allready something in the cache? for name in names: cacheKey = "_".join(("id", "name", name)) id = cache.getFromCache(cacheKey) if id: data[name] = id else: apiCheckNames.add(name) try: # not in cache? asking the EVE API if len(apiCheckNames) > 0: # writing the cache for name in apiCheckNames: data[name] = charnameToId(name) cacheKey = "_".join(("id", "name", name)) cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365) except Exception as e: logging.error("Exception during namesToIds: %s", e) return data
def getCorpIdsForCharId(char_id, use_outdated=True): """Returns a list with the ids if the corporation history of a charId returns a list of only the corp ids """ cache_key = "_".join(("corp_history_id_", str(char_id))) cache = Cache() corp_ids = cache.getFromCache(cache_key, use_outdated) if corp_ids is not None: corp_ids = eval(corp_ids) else: try: char_id = int(char_id) url = "https://esi.evetech.net/latest/characters/{id}/corporationhistory/?datasource=tranquility".format( id=char_id ) response = requests.get(url) response.raise_for_status() corp_ids = response.json() cache.putIntoCache(cache_key, response.text, 86400) except requests.exceptions.RequestException as e: # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only if e.response.status_code != 400: logging.error("Exception during getCharInfoForCharId: %s", str(e)) id_list = list() for elem in corp_ids: id_list.append(elem["corporation_id"]) return id_list
def charNameToId(name, use_outdated=False): """Uses the EVE API to convert a character name to their ID""" cache_key = "_".join(("name", "id", name)) cache = Cache() cached_id = cache.getFromCache(cache_key, use_outdated) if cached_id: return cached_id else: url = "https://esi.evetech.net/latest/search/?categories=character&datasource=tranquility&language=en-us&search={iname}&strict=true" response = requests.get(url.format(iname=name)) response.raise_for_status() content = response.json() if "character" in content.keys(): for idFound in content["character"]: url = "https://esi.evetech.net/latest/characters/{id}/?datasource=tranquility".format( id=idFound ) response = requests.get(url.format(name)) response.raise_for_status() details = response.json() if "name" in details.keys(): name_found = details["name"] if name_found.lower() == name.lower(): cache.putIntoCache(cache_key, idFound, 60 * 60 * 24 * 365) return idFound return None
def addChatEntry(self, chatEntry, clearCache=False): try: if clearCache: cache = Cache() cache.removeAvatar(chatEntry.message.user) # Enqeue the data to be picked up in run() self.queue.put(chatEntry) except Exception as e: logging.error("Error in AvatarFindThread: %s", e)
def addChatEntry(self, chatEntry, clearCache=False): try: if clearCache: cache = Cache() cache.removeAvatar(chatEntry.message.user) # Enqeue the data to be picked up in run() self.queue.put(chatEntry) except Exception as e: print "An error in the AvatarFindThread: ", str(e)
def __init__(self, parent): QtGui.QDialog.__init__(self, parent) uic.loadUi(resourcePath("vi/ui/RegionChooser.ui"), self) self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept) self.connect(self.saveButton, SIGNAL("clicked()"), self.saveClicked) cache = Cache() regionName = cache.getFromCache("region_name") if not regionName: regionName = u"Providence" self.regionNameField.setPlainText(regionName)
def __init__(self, parent): QtGui.QDialog.__init__(self, parent) uic.loadUi(resourcePath("vi/ui/RegionChooser.ui"), self) self.connect(self.cancelButton, Qt.SIGNAL("clicked()"), self.accept) self.connect(self.saveButton, Qt.SIGNAL("clicked()"), self.saveClicked) cache = Cache() regionName = cache.getFromCache("region_name") if not regionName: regionName = u"Providence" self.regionNameField.setPlainText(regionName)
def __init__(self, parent): QtWidgets.QDialog.__init__(self, parent) uic.loadUi(resource_stream(__name__, "RegionChooser.ui"), self) self.cancelButton.clicked.connect(self.accept) self.saveButton.clicked.connect(self.saveClicked) cache = Cache() regionName = cache.getFromCache("region_name") if not regionName: regionName = u"Providence" self.regionNameField.setPlainText(regionName)
def __init__(self, parent): QtWidgets.QDialog.__init__(self, parent) uic.loadUi(resource_stream(__name__, "ChatroomsChooser.ui"), self) self.defaultButton.clicked.connect(self.setDefaults) self.cancelButton.clicked.connect(self.accept) self.saveButton.clicked.connect(self.saveClicked) cache = Cache() roomnames = cache.getFromCache("room_names") if not roomnames: roomnames = u"TheCitadel,North Provi Intel,North Catch Intel,North Querious Intel" self.roomnamesField.setPlainText(roomnames)
def __init__(self): self.sounds = {} self.worker = QThread() # self.speach_engine = QTextToSpeech() cache = Cache() self.setSoundFile( "alarm", "178032__zimbot__redalert-klaxon-sttos-recreated.wav") vol = cache.getFromCache("soundsetting.volume") if vol: self.setSoundVolume(float(vol)) self.loadSoundFiles()
def __init__(self, parent): QtGui.QDialog.__init__(self, parent) uic.loadUi(resourcePath("vi/ui/ChatroomsChooser.ui"), self) self.connect(self.defaultButton, SIGNAL("clicked()"), self.setDefaults) self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept) self.connect(self.saveButton, SIGNAL("clicked()"), self.saveClicked) cache = Cache() roomnames = cache.getFromCache("room_names") if not roomnames: roomnames = u"TheCitadel,North Provi Intel,4THINTEL" self.roomnamesField.setPlainText(roomnames)
def __init__(self, parent): QtGui.QDialog.__init__(self, parent) uic.loadUi(resourcePath("vi/ui/ChatroomsChooser.ui"), self) self.connect(self.defaultButton, Qt.SIGNAL("clicked()"), self.setDefaults) self.connect(self.cancelButton, Qt.SIGNAL("clicked()"), self.accept) self.connect(self.saveButton, Qt.SIGNAL("clicked()"), self.saveClicked) cache = Cache() roomnames = cache.getFromCache("room_names") if not roomnames: roomnames = u"TheCitadel,North Provi Intel,North Catch Intel" self.roomnamesField.setPlainText(roomnames)
def __init__(self, parent): QDialog.__init__(self, parent) uic.loadUi(resource_path("vi/ui/ChatroomsChooser.ui"), self) self.default_button.clicked.connect(self.set_defaults) self.cancel_button.clicked.connect(self.accept) self.save_button.clicked.connect(self.save_clicked) cache = Cache() roomnames = cache.get_from_cache("roomnames") if not roomnames: roomnames = u"TheCitadel, North Provi Intel" self.roomnames_field.setPlainText(roomnames)
def __init__(self, parent): QDialog.__init__(self, parent) uic.loadUi(resource_path("vi/ui/RegionChooser.ui"), self) self.default_button.clicked.connect(self.set_defaults) self.cancel_button.clicked.connect(self.accept) self.save_button.clicked.connect(self.save_clicked) cache = Cache() regionname = cache.get_from_cache("regionname") if not regionname: regionname = u"Providence" self.regionname_field.setPlainText(regionname)
def getAllRegions(use_outdated=False): """Uses the EVE API to get the list of all region ids""" cache = Cache() all_systems = cache.getFromCache("universe_regions", use_outdated) if all_systems is not None: return eval(all_systems) else: url = "https://esi.evetech.net/latest/universe/regions/?datasource=tranquility" response = requests.get(url) response.raise_for_status() content = response.json() cache.putIntoCache("universe_regions", str(content), 60 * 60 * 24 * 365) return content
def getConstellationInformation(constellation_id: int, use_outdated=False): cache_key = "_".join(("universe", "constellations", str(constellation_id))) cache = Cache() cached_id = cache.getFromCache(cache_key, use_outdated) if cached_id: return eval(cached_id) else: req = "https://esi.evetech.net/latest/universe/constellations/{}/?datasource=tranquility&language=en".format( constellation_id ) res_constellation = requests.get(req) res_constellation.raise_for_status() cache.putIntoCache(cache_key, res_constellation.text) return res_constellation.json()
def getCampaigns(use_outdated=False): """builds a list of reinforced campaigns for IHUB and TCU dicts cached 60s""" cache = Cache() cache_key = "campaigns" result = cache.getFromCache(cache_key, use_outdated) if result: campaigns_list = json.loads(result) else: req = "https://esi.evetech.net/latest/sovereignty/campaigns/?datasource=tranquility" result = requests.get(req) result.raise_for_status() cache.putIntoCache(cache_key, result.text, 60) # 5 seconds from esi campaigns_list = result.json() return campaigns_list
def getIncursions(use_outdated=False): """builds a list of incursion dicts cached 300s""" cache = Cache() cache_key = "incursions" result = cache.getFromCache(cache_key, use_outdated) if result: incursion_list = json.loads(result) else: req = "https://esi.evetech.net/latest/incursions/?datasource=tranquility" result = requests.get(req) result.raise_for_status() cache.putIntoCache(cache_key, result.text, 300) incursion_list = result.json() return incursion_list
def getAlliances(alliance_id, use_outdated=True): """gets the alliance from allicance id""" cache_key = "_".join(("alliance", str(alliance_id))) cache = Cache() cached_id = cache.getFromCache(cache_key, use_outdated) if cached_id: return eval(cached_id) else: req = "https://esi.evetech.net/latest/alliances/{}/?datasource=tranquility".format( alliance_id ) res_system = requests.get(req) res_system.raise_for_status() cache.putIntoCache(cache_key, res_system.text, 3600) return res_system.json()
def getSolarSystemInformation(system_id, use_outdated=False): """gets the solar system info from system id""" cache_key = "_".join(("universe", "systems", str(system_id))) cache = Cache() cached_id = cache.getFromCache(cache_key, use_outdated) if cached_id: return eval(cached_id) else: req = "https://esi.evetech.net/latest/universe/systems/{}/?datasource=tranquility&language=en".format( system_id ) res_system = requests.get(req) res_system.raise_for_status() cache.putIntoCache(cache_key, res_system.text) return res_system.json()
def namesToIds(names, use_outdated=False): """Uses the EVE API to convert a list of names to ids_to_names names: list of names returns a dict: key=name, value=id """ if len(names) == 0: return {} data = {} api_check_names = set() cache = Cache() # do we have already something in the cache? for name in names: cache_key = "_".join(("id", "name", name)) id_from_cache = cache.getFromCache(cache_key, use_outdated) if id_from_cache: data[name] = id_from_cache else: api_check_names.add(name) try: # not in cache? asking the EVE API if len(api_check_names) > 0: list_of_name = "" for name in names: if list_of_name != "": list_of_name = list_of_name + "," list_of_name = list_of_name + '"{}"'.format(name) url = "https://esi.evetech.net/latest/universe/ids/?datasource=tranquility" response = requests.post(url, data="[{}]".format(list_of_name)) response.raise_for_status() content = response.json() if "characters" in content.keys(): for char in content["characters"]: data[char["name"]] = char["id"] if "systems" in content.keys(): for system in content["systems"]: data[system["name"]] = system["id"] if "regions" in content.keys(): for region in content["regions"]: data[region["name"]] = region["id"] # writing the cache for name in data: cache_key = "_".join(("id", "name", name)) cache.putIntoCache(cache_key, data[name], 60 * 60 * 24 * 365) except Exception as e: logging.error("Exception during namesToIds: %s", e) return data
def getPlayerSovereignty( use_outdated=False, fore_refresh=True, show_npc=True, callback=None ): seq = 0 def update_callback(seq): if callable(callback): icons = ["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"] seq += 1 if seq >= len(icons): seq = 0 callback(f"updating alliance and system database {icons[seq]}") return seq cache_key = "player_sovereignty" cache = Cache() cached_result = cache.getFromCache(cache_key, use_outdated) if cached_result and not fore_refresh: return json.loads(cached_result) else: player_sov = dict() npc_sov = dict() list_of_all_alliances = list() list_of_all_factions = list() for sov in getSovereignty(use_outdated, fore_refresh): if len(sov) > 2: player_sov[str(sov["system_id"])] = sov elif show_npc and len(sov) > 1: list_of_all_factions.append(sov["faction_id"]) npc_sov[str(sov["system_id"])] = sov for sov in player_sov.values(): if "alliance_id" in sov.keys(): alli_id = sov["alliance_id"] sov["ticker"] = getAlliances(alli_id)["ticker"] seq = update_callback(seq) if show_npc: npc_list = idsToNames(list_of_all_factions) for sov in npc_sov.values(): if "faction_id" in sov.keys(): faction_id = sov["faction_id"] sov["ticker"] = npc_list[faction_id] seq = update_callback(seq) player_sov.update(npc_sov) cache.putIntoCache(cache_key, json.dumps(player_sov), 3600) return player_sov
def saveClicked(self): text = six.text_type(self.regionNameField.toPlainText()) text = dotlan.convertRegionName(text) self.regionNameField.setPlainText(text) correct = False try: url = dotlan.Map.DOTLAN_BASIC_URL.format(text) content = requests.get(url).text if u"not found" in content: correct = False # Fallback -> ships vintel with this map? try: with open(resourcePath("vi/ui/res/mapdata/{0}.svg".format(text))) as _: correct = True except Exception as e: logging.error(e) correct = False if not correct: QMessageBox.warning(self, u"No such region!", u"I can't find a region called '{0}'".format(text)) else: correct = True except Exception as e: QMessageBox.critical(self, u"Something went wrong!", u"Error while testing existing '{0}'".format(str(e))) logging.error(e) correct = False if correct: Cache().putIntoCache("region_name", text, 60 * 60 * 24 * 365) self.accept() self.emit(SIGNAL("new_region_chosen"))
def getSovereignty(use_outdated=False, fore_refresh=False): """builds a list of reinforced campaigns for hubs and tcus dicts cached 60s https://esi.evetech.net/ui/?version=latest#/Sovereignty/get_sovereignty_map """ cache = Cache() cache_key = "sovereignty" result = cache.getFromCache(cache_key, use_outdated) if result and not fore_refresh: campaigns_list = json.loads(result) else: req = "https://esi.evetech.net/latest/sovereignty/map/?datasource=tranquility" result = requests.get(req) result.raise_for_status() cache.putIntoCache(cache_key, result.text, 3600) campaigns_list = result.json() return campaigns_list
def run(self): cache = Cache() last_call = 0 wait = 300 # time between 2 requests in ms while True: try: chatentry = self.q.get() charname = chatentry.message.user avatar = None logging.debug('loading avatar for {0}'.format(charname)) if charname == "VINTEL": logging.debug('fetching VINTEL avatar') with open(resource_path("vi/ui/res/logo_small.png"), "rb") as f: avatar = f.read() if not avatar: logging.debug('getting avatar from cache') avatar = cache.get_avatar(charname) if not avatar: diff_last_call = time.time() - last_call if diff_last_call < wait: time.sleep((wait - diff_last_call) / 1000.0) logging.debug('getting avatar from evegate') avatar = evegate.get_avatar_for_player(charname) last_call = time.time() if avatar: logging.debug('saving avatar from evegate to cache') cache.put_avatar(charname, avatar) if avatar: if isinstance(avatar, str): self.avatar_update.emit(chatentry, eval(avatar)) elif isinstance(avatar, bytes): self.avatar_update.emit(chatentry, avatar) else: logging.warning('unknown avatar object type {0}'.format(type(avatar))) except Exception as e: print("An error in the avatar-find-thread:", str(e))
def idsToNames(ids, use_outdated=False): """Returns the names for ids ids = iterable list of ids returns a dict key = id, value = name """ data = {} if len(ids) == 0: return data api_check_ids = set() cache = Cache() # something already in the cache? for checked_id in ids: cache_key = "_".join(("name", "id", str(checked_id))) name = cache.getFromCache(cache_key, use_outdated) if name: data[checked_id] = name else: api_check_ids.add(checked_id) if len(api_check_ids) == 0: return data try: list_of_ids = "" for checked_id in api_check_ids: if list_of_ids != "": list_of_ids = list_of_ids + "," list_of_ids = list_of_ids + str(checked_id) url = "https://esi.evetech.net/latest/universe/names/?datasource=tranquility" response = requests.post(url, data="[{}]".format(list_of_ids)) response.raise_for_status() content = response.json() if len(content) > 0: for elem in content: data[elem["id"]] = elem["name"] # and writing into cache for checked_id in api_check_ids: cache_key = "_".join(("name", "id", str(checked_id))) if checked_id in data.keys(): cache.putIntoCache( cache_key, data[int(checked_id)], 60 * 60 * 24 * 365 ) except Exception as e: logging.error("Exception during idsToNames: %s", e) return data
def setSoundFile(self, mask, filename): if mask in self.SOUNDS.keys(): if filename == "": filename = "178032__zimbot__redalert-klaxon-sttos-recreated.wav" self.SOUNDS[mask] = filename self.sounds[mask] = QSoundEffect() url = QUrl.fromLocalFile(self.SOUNDS[mask]) self.sounds[mask].setSource(url) Cache().putIntoCache("soundsetting.{}".format(mask), filename) self.loadSoundFiles()
def save_clicked(self): text = str(self.regionname_field.toPlainText()) text = dotlan.convert_regionname(text) self.regionname_field.setPlainText(text) correct = False try: url = dotlan.Map.DOTLAN_BASIC_URL.format(text) content = requests.get(url).text # request = urllib.request.urlopen(url) # content = request.read() if u"not found" in content: correct = False # Fallback -> ships vintel with this map? try: with open( resource_path("vi/ui/res/mapdata/{0}.svg".format( text))) as _: correct = True except Exception as e: print(str(e)) correct = False if not correct: QMessageBox.warning( None, u"No such region!", u"I can't find a region called '{0}'".format(text), QMessageBox.Ok) else: correct = True except Exception as e: QMessageBox.critical( None, u"Something went wrong!", u"Error while testing existing '{0}'".format(str(e)), QMessageBox.Ok) correct = False if correct: c = Cache() c.put_into_cache("regionname", text, 60 * 60 * 24 * 365) QMessageBox.information( None, u"VINTEL needs restart", u"Region was changed, you need to restart VINTEL!", QMessageBox.Ok) self.accept()
def set_jumpbridges(self, url): if url is None: url = "" try: data = [] if url != "": content = requests.get(url).text for line in content.split("\n"): parts = line.strip().split() if len(parts) == 3: data.append(parts) else: data = drachenjaeger.get_jumpbridge_data( self.dotlan.region.lower()) self.dotlan.set_jumpbridges(data) c = Cache() c.put_into_cache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8) except Exception as e: QMessageBox.warning(None, "Loading jumpbridges failed!", "Error: {0}".format(str(e)), QMessageBox.Ok)
def getCharinfoForCharId(charId): cacheKey = u"_".join(("playerinfo_id_", six.text_type(charId))) cache = Cache() soup = cache.getFromCache(cacheKey) if soup is not None: soup = BeautifulSoup(soup, 'html.parser') else: try: charId = int(charId) url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx" content = requests.get(url, params={'characterID': charId}).text soup = BeautifulSoup(content, 'html.parser') cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, str(soup), diff.seconds) except requests.exceptions.RequestException as e: # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only if (e.response.status_code != 400): logging.error("Exception during getCharinfoForCharId: %s", str(e)) return soup
def run(self): cache = Cache() lastCall = 0 wait = 300 # time between 2 requests in ms while True: try: # Block waiting for addChatEntry() to enqueue something chatEntry = self.queue.get() if not self.active: return charname = chatEntry.message.user logging.debug("AvatarFindThread getting avatar for %s" % charname) avatar = None if charname == "VINTEL": with open( resource_filename(__name__, "ui/res/logo_small.png"), "rb") as f: avatar = f.read() if not avatar: avatar = cache.getAvatar(charname) if avatar: logging.debug( "AvatarFindThread found cached avatar for %s" % charname) if not avatar: diffLastCall = time.time() - lastCall if diffLastCall < wait: time.sleep((wait - diffLastCall) / 1000.0) avatar = evegate.getAvatarForPlayer(charname) lastCall = time.time() if avatar: cache.putAvatar(charname, avatar) if avatar: logging.debug( "AvatarFindThread emit avatar_update for %s" % charname) self.avatar_update.emit(chatEntry, avatar) except Exception as e: logging.error("Error in AvatarFindThread : %s", e)
def getCharinfoForCharId(charId): cacheKey = u"_".join(("playerinfo_id_", unicode(charId))) cache = Cache() soup = cache.getFromCache(cacheKey) if soup is not None: soup = BeautifulSoup(soup, 'html.parser') else: try: charId = int(charId) url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx" data = urllib.urlencode({"characterID": charId}) content = urllib2.urlopen(url=url, data=data).read() soup = BeautifulSoup(content, 'html.parser') cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, str(soup), diff.seconds) except urllib2.HTTPError as e: # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only if (e.code != 400): print "Exception during getCharinfoForCharId: {0}".format(str(e)) return soup
def getJumpbridgeData(region): try: cacheKey = "jb_" + region cache = Cache() data = cache.getFromCache(cacheKey) if data: data = json.loads(data) else: data = [] url = "https://s3.amazonaws.com/vintel-resources/{region}_jb.txt" resp = requests.get(url.format(region=region)) for line in resp.iter_lines(decode_unicode=True): splits = line.strip().split() if len(splits) == 3: data.append(splits) cache.putIntoCache(cacheKey, json.dumps(data), 60 * 60 * 12) return data except Exception as e: logging.error("Getting Jumpbridgedata failed with: %s", e) return []
def getCharinfoForCharId(charId): cacheKey = u"_".join(("playerinfo_id_", six.text_type(charId))) cache = Cache() soup = cache.getFromCache(cacheKey) if soup is not None: soup = BeautifulSoup(soup, 'html.parser') else: try: charId = int(charId) url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx" content = requests.get(url, params={'characterID': charId}).text soup = BeautifulSoup(content, 'html.parser') cacheUntil = datetime.datetime.strptime( soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, str(soup), diff.seconds) except requests.exceptions.RequestException as e: # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only if (e.response.status_code != 400): logging.error("Exception during getCharinfoForCharId: %s", str(e)) return soup
def namesToIds(names): """ Uses the EVE API to convert a list of names to ids_to_names names: list of names returns a dict: key=name, value=id """ if len(names) == 0: return {} data = {} apiCheckNames = set() cache = Cache() # do we have allready something in the cache? for name in names: cacheKey = "_".join(("id", "name", name)) id = cache.getFromCache(cacheKey) if id: data[name] = id else: apiCheckNames.add(name) try: # not in cache? asking the EVE API if len(apiCheckNames) > 0: url = "https://api.eveonline.com/eve/CharacterID.xml.aspx" content = requests.get(url, params={ 'names': ','.join(apiCheckNames) }).text soup = BeautifulSoup(content, 'html.parser') rowSet = soup.select("rowset")[0] for row in rowSet.select("row"): data[row["name"]] = row["characterid"] # writing the cache for name in apiCheckNames: cacheKey = "_".join(("id", "name", name)) cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365) except Exception as e: logging.error("Exception during namesToIds: %s", e) return data
def idsToNames(ids): """ Returns the names for ids ids = iterable list of ids returns a dict key = id, value = name """ data = {} if len(ids) == 0: return data apiCheckIds = set() cache = Cache() # something allready in the cache? for id in ids: cacheKey = u"_".join(("name", "id", unicode(id))) name = cache.getFromCache(cacheKey) if name: data[id] = name else: apiCheckIds.add(id) try: # call the EVE-Api for those entries we didn't have in the cache url = "https://api.eveonline.com/eve/CharacterName.xml.aspx" if len(apiCheckIds) > 0: requestData = urllib.urlencode({"ids": ",".join(apiCheckIds)}) request = urllib2.urlopen(url=url, data=requestData) content = request.read() soup = BeautifulSoup(content, 'html.parser') rowSet = soup.select("rowset")[0] for row in rowSet.select("row"): data[row["characterid"]] = row["name"] # and writing into cache for id in apiCheckIds: cacheKey = u"_".join(("name", "id", unicode(id))) cache.putIntoCache(cacheKey, data[id], 60 * 60 * 24 * 365) except Exception as e: print "Exception during idsToNames: {0}".format(str(e)) return data
def getJumpbridgeData(region): try: cacheKey = "jb_" + region cache = Cache() data = cache.getFromCache(cacheKey) if data: data = json.loads(data) else: data = [] url = "https://s3.amazonaws.com/vintel-resources/{region}_jb.txt" request = urllib2.urlopen(url.format(region=region)) content = request.read() for line in content.split("\n"): splits = line.strip().split() if len(splits) == 3: data.append(splits) cache.putIntoCache(cacheKey, json.dumps(data), 60*60*24) return data except Exception as e: print("Getting Jumpbridgedata failed with: {0}".format(str(e))) return []
def namesToIds(names): """ Uses the EVE API to convert a list of names to ids_to_names names: list of names returns a dict: key=name, value=id """ if len(names) == 0: return {} data = {} apiCheckNames = set() cache = Cache() # do we have allready something in the cache? for name in names: cacheKey = "_".join(("id", "name", name)) id = cache.getFromCache(cacheKey) if id: data[name] = id else: apiCheckNames.add(name) try: # not in cache? asking the EVE API if len(apiCheckNames) > 0: url = "https://api.eveonline.com/eve/CharacterID.xml.aspx" requestData = urllib.urlencode({"names": u",".join(apiCheckNames)}) request = urllib2.urlopen(url=url, data=requestData) content = request.read() soup = BeautifulSoup(content, 'html.parser') rowSet = soup.select("rowset")[0] for row in rowSet.select("row"): data[row["name"]] = row["characterid"] # writing the cache for name in apiCheckNames: cacheKey = "_".join(("id", "name", name)) cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365) except Exception as e: print "Exception during namesToIds: {0}".format(str(e)) return data
def __init__(self, region, svgFile=None): self.region = region cache = Cache() self.outdatedCacheError = None if not svgFile: # want map from dotlan. Is it in the cache? svg = cache.getFromCache("map_" + self.region) else: svg = svgFile if not svg: try: svg = self._getSvgFromDotlan(self.region) cache.putIntoCache("map_" + self.region, svg, evegate.secondsTillDowntime() + 60*60) except Exception as e: self.outdatedCacheError = e svg = cache.getFromCache("map_" + self.region, True) if not svg: t = "No Map in cache, nothing from dotlan. Must give up "\ "because this happened:\n{0} {1}\n\nThis could be a "\ "temporary problem (like dotlan is not reachable), or "\ "everythig went to hell. Sorry. This makes no sense "\ "without the map.\n\nRemember the site for possible "\ "updates: https://github.com/Xanthos-Eve/vintel"\ .format(type(e), unicode(e)) raise DotlanException(t) # and now creating soup from the svg self.soup = BeautifulSoup(svg, 'html.parser') self.systems = self._extractSystemsFromSoup(self.soup) self.systemsById = {} for system in self.systems.values(): self.systemsById[system.systemId] = system self._prepareSvg(self.soup, self.systems) self._connectNeighbours() self._jumpMapsVisible = False self._statisticsVisible = False self.marker = self.soup.select("#select_marker")[0]
def idsToNames(ids): """ Returns the names for ids ids = iterable list of ids returns a dict key = id, value = name """ data = {} if len(ids) == 0: return data apiCheckIds = set() cache = Cache() # something allready in the cache? for id in ids: cacheKey = u"_".join(("name", "id", six.text_type(id))) name = cache.getFromCache(cacheKey) if name: data[id] = name else: apiCheckIds.add(six.text_type(id)) try: # call the EVE-Api for those entries we didn't have in the cache url = "https://api.eveonline.com/eve/CharacterName.xml.aspx" if len(apiCheckIds) > 0: content = requests.get(url, params={'ids': ','.join(apiCheckIds)}).text soup = BeautifulSoup(content, 'html.parser') rowSet = soup.select("rowset")[0] for row in rowSet.select("row"): data[row["characterid"]] = row["name"] # and writing into cache for id in apiCheckIds: cacheKey = u"_".join(("name", "id", six.text_type(id))) cache.putIntoCache(cacheKey, data[id], 60 * 60 * 24 * 365) except Exception as e: logging.error("Exception during idsToNames: %s", e) return data
def __init__(self, args): super(Application, self).__init__(args) # Set up paths chatLogDirectory = "" if len(sys.argv) > 1: chatLogDirectory = sys.argv[1] if not os.path.exists(chatLogDirectory): if sys.platform.startswith("darwin"): chatLogDirectory = os.path.join(os.path.expanduser("~"), "Library", "Application Support", "Eve Online", "p_drive", "User", "My Documents", "EVE", "logs", "Chatlogs") elif sys.platform.startswith("linux"): chatLogDirectory = os.path.join(os.path.expanduser("~"), "EVE", "logs", "Chatlogs") elif sys.platform.startswith("win32") or sys.platform.startswith("cygwin"): import ctypes.wintypes buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH) ctypes.windll.shell32.SHGetFolderPathW(0, 5, 0, 0, buf) documentsPath = buf.value chatLogDirectory = os.path.join(documentsPath, "EVE", "logs", "Chatlogs") if not os.path.exists(chatLogDirectory): # None of the paths for logs exist, bailing out QMessageBox.critical(None, "No path to Logs", "No logs found at: " + chatLogDirectory, "Quit") sys.exit(1) # Setting local directory for cache and logging vintelDirectory = os.path.join(os.path.dirname(os.path.dirname(chatLogDirectory)), "vintel") if not os.path.exists(vintelDirectory): os.mkdir(vintelDirectory) cache.Cache.PATH_TO_CACHE = os.path.join(vintelDirectory, "cache-2.sqlite3") vintelLogDirectory = os.path.join(vintelDirectory, "logs") if not os.path.exists(vintelLogDirectory): os.mkdir(vintelLogDirectory) splash = QtGui.QSplashScreen(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png"))) vintelCache = Cache() logLevel = vintelCache.getFromCache("logging_level") if not logLevel: logLevel = logging.WARN backGroundColor = vintelCache.getFromCache("background_color") if backGroundColor: self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor) splash.show() self.processEvents() # Setup logging for console and rotated log files formatter = logging.Formatter('%(asctime)s| %(message)s', datefmt='%m/%d %I:%M:%S') rootLogger = logging.getLogger() rootLogger.setLevel(level=logLevel) logFilename = vintelLogDirectory + "/output.log" fileHandler = RotatingFileHandler(maxBytes=(1048576*5), backupCount=7, filename=logFilename, mode='a') fileHandler.setFormatter(formatter) rootLogger.addHandler(fileHandler) consoleHandler = StreamHandler() consoleHandler.setFormatter(formatter) rootLogger.addHandler(consoleHandler) logging.critical("") logging.critical("------------------- Vintel %s starting up -------------------", version.VERSION) logging.critical("") logging.debug("Looking for chat logs at: %s", chatLogDirectory) logging.debug("Cache maintained here: %s", cache.Cache.PATH_TO_CACHE) logging.debug("Writing logs to: %s", vintelLogDirectory) trayIcon = systemtray.TrayIcon(self) trayIcon.show() self.mainWindow = viui.MainWindow(chatLogDirectory, trayIcon, backGroundColor) self.mainWindow.show() self.mainWindow.raise_() splash.finish(self.mainWindow)
class MainWindow(QtGui.QMainWindow): def __init__(self, pathToLogs, trayIcon, backGroundColor): QtGui.QMainWindow.__init__(self) self.cache = Cache() if backGroundColor: self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor) uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self) self.setWindowTitle("Vintel " + vi.version.VERSION + "{dev}".format(dev="-SNAPSHOT" if vi.version.SNAPSHOT else "")) self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png")) self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png")) self.setWindowIcon(self.taskbarIconQuiescent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.pathToLogs = pathToLogs self.mapTimer = QtCore.QTimer(self) self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView) self.clipboardTimer = QtCore.QTimer(self) self.oldClipboardContent = "" self.trayIcon = trayIcon self.trayIcon.activated.connect(self.systemTrayActivated) self.clipboard = QtGui.QApplication.clipboard() self.clipboard.clear(mode=self.clipboard.Clipboard) self.alarmDistance = 0 self.lastStatisticsUpdate = 0 self.chatEntries = [] self.frameButton.setVisible(False) self.scanIntelForKosRequestsEnabled = True self.initialMapPosition = None self.mapPositionsDict = {} # Load user's toon names self.knownPlayerNames = self.cache.getFromCache("known_player_names") if self.knownPlayerNames: self.knownPlayerNames = set(self.knownPlayerNames.split(",")) else: self.knownPlayerNames = set() diagText = "Vintel scans EVE system logs and remembers your characters as they change systems.\n\nSome features (clipboard KOS checking, alarms, etc.) may not work until your character(s) have been registered. Change systems, with each character you want to monitor, while Vintel is running to remedy this." QtGui.QMessageBox.warning(None, "Known Characters not Found", diagText, "Ok") # Set up user's intel rooms roomnames = self.cache.getFromCache("room_names") if roomnames: roomnames = roomnames.split(",") else: roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel", "North Querious Intel") self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5) self.roomnames = roomnames # Disable the sound UI if sound is not available if not SoundManager().soundAvailable: self.changeSound(disable=True) else: self.changeSound() # Set up Transparency menu - fill in opacity values and make connections self.opacityGroup = QtGui.QActionGroup(self.menu) for i in (100, 80, 60, 40, 20): action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True) if i == 100: action.setChecked(True) action.opacity = i / 100.0 self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity) self.opacityGroup.addAction(action) self.menuTransparency.addAction(action) # # Platform specific UI resizing - we size items in the resource files to look correct on the mac, # then resize other platforms as needed # if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"): font = self.statisticsButton.font() font.setPointSize(8) self.statisticsButton.setFont(font) self.jumpbridgesButton.setFont(font) elif sys.platform.startswith("linux"): pass self.wireUpUIConnections() self.recallCachedSettings() self.setupThreads() self.setupMap(True) def paintEvent(self, event): opt = QStyleOption() opt.initFrom(self) painter = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self) def recallCachedSettings(self): try: self.cache.recallAndApplySettings(self, "settings") except Exception as e: logging.error(e) # todo: add a button to delete the cache / DB self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1) def wireUpUIConnections(self): # Wire up general UI connections self.connect(self.clipboard, Qt.SIGNAL("changed(QClipboard::Mode)"), self.clipboardChanged) self.connect(self.autoScanIntelAction, Qt.SIGNAL("triggered()"), self.changeAutoScanIntel) self.connect(self.kosClipboardActiveAction, Qt.SIGNAL("triggered()"), self.changeKosCheckClipboard) self.connect(self.zoomInButton, Qt.SIGNAL("clicked()"), self.zoomMapIn) self.connect(self.zoomOutButton, Qt.SIGNAL("clicked()"), self.zoomMapOut) self.connect(self.statisticsButton, Qt.SIGNAL("clicked()"), self.changeStatisticsVisibility) self.connect(self.jumpbridgesButton, Qt.SIGNAL("clicked()"), self.changeJumpbridgesVisibility) self.connect(self.chatLargeButton, Qt.SIGNAL("clicked()"), self.chatLarger) self.connect(self.chatSmallButton, Qt.SIGNAL("clicked()"), self.chatSmaller) self.connect(self.infoAction, Qt.SIGNAL("triggered()"), self.showInfo) self.connect(self.showChatAvatarsAction, Qt.SIGNAL("triggered()"), self.changeShowAvatars) self.connect(self.alwaysOnTopAction, Qt.SIGNAL("triggered()"), self.changeAlwaysOnTop) self.connect(self.chooseChatRoomsAction, Qt.SIGNAL("triggered()"), self.showChatroomChooser) self.connect(self.catchRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.catchRegionAction)) self.connect(self.providenceRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceRegionAction)) self.connect(self.queriousRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.queriousRegionAction)) self.connect(self.providenceCatchRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceCatchRegionAction)) self.connect(self.providenceCatchCompactRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceCatchCompactRegionAction)) self.connect(self.chooseRegionAction, Qt.SIGNAL("triggered()"), self.showRegionChooser) self.connect(self.showChatAction, Qt.SIGNAL("triggered()"), self.changeChatVisibility) self.connect(self.soundSetupAction, Qt.SIGNAL("triggered()"), self.showSoundSetup) self.connect(self.activateSoundAction, Qt.SIGNAL("triggered()"), self.changeSound) self.connect(self.useSpokenNotificationsAction, Qt.SIGNAL("triggered()"), self.changeUseSpokenNotifications) self.connect(self.trayIcon, Qt.SIGNAL("alarm_distance"), self.changeAlarmDistance) self.connect(self.framelessWindowAction, Qt.SIGNAL("triggered()"), self.changeFrameless) self.connect(self.trayIcon, Qt.SIGNAL("change_frameless"), self.changeFrameless) self.connect(self.frameButton, Qt.SIGNAL("clicked()"), self.changeFrameless) self.connect(self.quitAction, Qt.SIGNAL("triggered()"), self.close) self.connect(self.trayIcon, Qt.SIGNAL("quit"), self.close) self.connect(self.jumpbridgeDataAction, Qt.SIGNAL("triggered()"), self.showJumbridgeChooser) self.mapView.page().scrollRequested.connect(self.mapPositionChanged) def setupThreads(self): # Set up threads and their connections self.avatarFindThread = AvatarFindThread() self.connect(self.avatarFindThread, QtCore.SIGNAL("avatar_update"), self.updateAvatarOnChatEntry) self.avatarFindThread.start() self.kosRequestThread = KOSCheckerThread() self.connect(self.kosRequestThread, Qt.SIGNAL("kos_result"), self.showKosResult) self.kosRequestThread.start() self.filewatcherThread = filewatcher.FileWatcher(self.pathToLogs) self.connect(self.filewatcherThread, QtCore.SIGNAL("file_change"), self.logFileChanged) self.filewatcherThread.start() self.versionCheckThread = amazon_s3.NotifyNewVersionThread() self.versionCheckThread.connect(self.versionCheckThread, Qt.SIGNAL("newer_version"), self.notifyNewerVersion) self.versionCheckThread.start() self.statisticsThread = MapStatisticsThread() self.connect(self.statisticsThread, Qt.SIGNAL("statistic_data_update"), self.updateStatisticsOnMap) self.statisticsThread.start() # statisticsThread is blocked until first call of requestStatistics def setupMap(self, initialize=False): self.mapTimer.stop() self.filewatcherThread.paused = True logging.info("Finding map file") regionName = self.cache.getFromCache("region_name") if not regionName: regionName = "Providence" svg = None try: with open(resourcePath("vi/ui/res/mapdata/{0}.svg".format(regionName))) as svgFile: svg = svgFile.read() except Exception as e: pass try: self.dotlan = dotlan.Map(regionName, svg) except dotlan.DotlanException as e: logging.error(e) QtGui.QMessageBox.critical(None, "Error getting map", six.text_type(e), "Quit") sys.exit(1) if self.dotlan.outdatedCacheError: e = self.dotlan.outdatedCacheError diagText = "Something went wrong getting map data. Proceeding with older cached data. " \ "Check for a newer version and inform the maintainer.\n\nError: {0} {1}".format(type(e), six.text_type(e)) logging.warn(diagText) QtGui.QMessageBox.warning(None, "Using map from cache", diagText, "Ok") # Load the jumpbridges logging.critical("Load jump bridges") self.setJumpbridges(self.cache.getFromCache("jumpbridge_url")) self.systems = self.dotlan.systems logging.critical("Creating chat parser") self.chatparser = chatparser.ChatParser(self.pathToLogs, self.roomnames, self.systems) # Menus - only once if initialize: logging.critical("Initializing contextual menus") # Add a contextual menu to the mapView def mapContextMenuEvent(event): #if QApplication.activeWindow() or QApplication.focusWidget(): self.mapView.contextMenu.exec_(self.mapToGlobal(QPoint(event.x(), event.y()))) self.mapView.contextMenuEvent = mapContextMenuEvent self.mapView.contextMenu = self.trayIcon.contextMenu() # Clicking links self.mapView.connect(self.mapView, Qt.SIGNAL("linkClicked(const QUrl&)"), self.mapLinkClicked) # Also set up our app menus if not regionName: self.providenceCatchRegionAction.setChecked(True) elif regionName.startswith("Providencecatch"): self.providenceCatchRegionAction.setChecked(True) elif regionName.startswith("Catch"): self.catchRegionAction.setChecked(True) elif regionName.startswith("Providence"): self.providenceRegionAction.setChecked(True) elif regionName.startswith("Querious"): self.queriousRegionAction.setChecked(True) else: self.chooseRegionAction.setChecked(True) self.jumpbridgesButton.setChecked(False) self.statisticsButton.setChecked(False) # Update the new map view, then clear old statistics from the map and request new logging.critical("Updating the map") self.updateMapView() self.setInitialMapPositionForRegion(regionName) self.mapTimer.start(MAP_UPDATE_INTERVAL_MSECS) # Allow the file watcher to run now that all else is set up self.filewatcherThread.paused = False logging.critical("Map setup complete") # def eventFilter(self, obj, event): # if event.type() == QtCore.QEvent.WindowDeactivate: # self.enableContextMenu(False) # return True # elif event.type() == QtCore.QEvent.WindowActivate: # self.enableContextMenu(True) # return True # return False def startClipboardTimer(self): """ Start a timer to check the keyboard for changes and kos check them, first initializing the content so we dont kos check from random content """ self.oldClipboardContent = tuple(six.text_type(self.clipboard.text())) self.connect(self.clipboardTimer, QtCore.SIGNAL("timeout()"), self.clipboardChanged) self.clipboardTimer.start(CLIPBOARD_CHECK_INTERVAL_MSECS) def stopClipboardTimer(self): if self.clipboardTimer: self.disconnect(self.clipboardTimer, QtCore.SIGNAL("timeout()"), self.clipboardChanged) self.clipboardTimer.stop() def closeEvent(self, event): """ Persisting things to the cache before closing the window """ # Known playernames if self.knownPlayerNames: value = ",".join(self.knownPlayerNames) self.cache.putIntoCache("known_player_names", value, 60 * 60 * 24 * 30) # Program state to cache (to read it on next startup) settings = ((None, "restoreGeometry", str(self.saveGeometry())), (None, "restoreState", str(self.saveState())), ("splitter", "restoreGeometry", str(self.splitter.saveGeometry())), ("splitter", "restoreState", str(self.splitter.saveState())), ("mapView", "setZoomFactor", self.mapView.zoomFactor()), (None, "changeChatFontSize", ChatEntryWidget.TEXT_SIZE), (None, "changeOpacity", self.opacityGroup.checkedAction().opacity), (None, "changeAlwaysOnTop", self.alwaysOnTopAction.isChecked()), (None, "changeShowAvatars", self.showChatAvatarsAction.isChecked()), (None, "changeAlarmDistance", self.alarmDistance), (None, "changeSound", self.activateSoundAction.isChecked()), (None, "changeChatVisibility", self.showChatAction.isChecked()), (None, "loadInitialMapPositions", self.mapPositionsDict), (None, "setSoundVolume", SoundManager().soundVolume), (None, "changeFrameless", self.framelessWindowAction.isChecked()), (None, "changeUseSpokenNotifications", self.useSpokenNotificationsAction.isChecked()), (None, "changeKosCheckClipboard", self.kosClipboardActiveAction.isChecked()), (None, "changeAutoScanIntel", self.scanIntelForKosRequestsEnabled)) self.cache.putIntoCache("settings", str(settings), 60 * 60 * 24 * 30) # Stop the threads try: SoundManager().quit() self.avatarFindThread.quit() self.avatarFindThread.wait() self.filewatcherThread.quit() self.filewatcherThread.wait() self.kosRequestThread.quit() self.kosRequestThread.wait() self.versionCheckThread.quit() self.versionCheckThread.wait() self.statisticsThread.quit() self.statisticsThread.wait() except Exception: pass self.trayIcon.hide() event.accept() def notifyNewerVersion(self, newestVersion): self.trayIcon.showMessage("Newer Version", ("An update is available for Vintel.\nhttps://github.com/Xanthos-Eve/vintel"), 1) def changeChatVisibility(self, newValue=None): if newValue is None: newValue = self.showChatAction.isChecked() self.showChatAction.setChecked(newValue) self.chatbox.setVisible(newValue) def changeKosCheckClipboard(self, newValue=None): if newValue is None: newValue = self.kosClipboardActiveAction.isChecked() self.kosClipboardActiveAction.setChecked(newValue) if newValue: self.startClipboardTimer() else: self.stopClipboardTimer() def changeAutoScanIntel(self, newValue=None): if newValue is None: newValue = self.autoScanIntelAction.isChecked() self.autoScanIntelAction.setChecked(newValue) self.scanIntelForKosRequestsEnabled = newValue def changeUseSpokenNotifications(self, newValue=None): if SoundManager().platformSupportsSpeech(): if newValue is None: newValue = self.useSpokenNotificationsAction.isChecked() self.useSpokenNotificationsAction.setChecked(newValue) SoundManager().setUseSpokenNotifications(newValue) else: self.useSpokenNotificationsAction.setChecked(False) self.useSpokenNotificationsAction.setEnabled(False) def changeOpacity(self, newValue=None): if newValue is not None: for action in self.opacityGroup.actions(): if action.opacity == newValue: action.setChecked(True) action = self.opacityGroup.checkedAction() self.setWindowOpacity(action.opacity) def changeSound(self, newValue=None, disable=False): if disable: self.activateSoundAction.setChecked(False) self.activateSoundAction.setEnabled(False) self.soundSetupAction.setEnabled(False) #self.soundButton.setEnabled(False) QtGui.QMessageBox.warning(None, "Sound disabled", "The lib 'pyglet' which is used to play sounds cannot be found, ""so the soundsystem is disabled.\nIf you want sound, please install the 'pyglet' library. This warning will not be shown again.", "OK") else: if newValue is None: newValue = self.activateSoundAction.isChecked() self.activateSoundAction.setChecked(newValue) SoundManager().soundActive = newValue def changeAlwaysOnTop(self, newValue=None): if newValue is None: newValue = self.alwaysOnTopAction.isChecked() self.hide() self.alwaysOnTopAction.setChecked(newValue) if newValue: self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) else: self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.WindowStaysOnTopHint)) self.show() def changeFrameless(self, newValue=None): if newValue is None: newValue = not self.frameButton.isVisible() self.hide() if newValue: self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.changeAlwaysOnTop(True) else: self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.FramelessWindowHint)) self.menubar.setVisible(not newValue) self.frameButton.setVisible(newValue) self.framelessWindowAction.setChecked(newValue) for cm in TrayContextMenu.instances: cm.framelessCheck.setChecked(newValue) self.show() def changeShowAvatars(self, newValue=None): if newValue is None: newValue = self.showChatAvatarsAction.isChecked() self.showChatAvatarsAction.setChecked(newValue) ChatEntryWidget.SHOW_AVATAR = newValue for entry in self.chatEntries: entry.avatarLabel.setVisible(newValue) def changeChatFontSize(self, newSize): if newSize: for entry in self.chatEntries: entry.changeFontSize(newSize) ChatEntryWidget.TEXT_SIZE = newSize def chatSmaller(self): newSize = ChatEntryWidget.TEXT_SIZE - 1 self.changeChatFontSize(newSize) def chatLarger(self): newSize = ChatEntryWidget.TEXT_SIZE + 1 self.changeChatFontSize(newSize) def changeAlarmDistance(self, distance): self.alarmDistance = distance for cm in TrayContextMenu.instances: for action in cm.distanceGroup.actions(): if action.alarmDistance == distance: action.setChecked(True) self.trayIcon.alarmDistance = distance def changeJumpbridgesVisibility(self): newValue = self.dotlan.changeJumpbridgesVisibility() self.jumpbridgesButton.setChecked(newValue) self.updateMapView() def changeStatisticsVisibility(self): newValue = self.dotlan.changeStatisticsVisibility() self.statisticsButton.setChecked(newValue) self.updateMapView() if newValue: self.statisticsThread.requestStatistics() def clipboardChanged(self, mode=0): if not (mode == 0 and self.kosClipboardActiveAction.isChecked() and self.clipboard.mimeData().hasText()): return content = six.text_type(self.clipboard.text()) contentTuple = tuple(content) # Limit redundant kos checks if contentTuple != self.oldClipboardContent: parts = tuple(content.split("\n")) knownPlayers = self.knownPlayerNames for part in parts: # Make sure user is in the content (this is a check of the local system in Eve). # also, special case for when you have no knonwnPlayers (initial use) if not knownPlayers or part in knownPlayers: self.trayIcon.setIcon(self.taskbarIconWorking) self.kosRequestThread.addRequest(parts, "clipboard", True) break self.oldClipboardContent = contentTuple def mapLinkClicked(self, url): systemName = six.text_type(url.path().split("/")[-1]).upper() system = self.systems[str(systemName)] sc = SystemChat(self, SystemChat.SYSTEM, system, self.chatEntries, self.knownPlayerNames) sc.connect(self, Qt.SIGNAL("chat_message_added"), sc.addChatEntry) sc.connect(self, Qt.SIGNAL("avatar_loaded"), sc.newAvatarAvailable) sc.connect(sc, Qt.SIGNAL("location_set"), self.setLocation) sc.show() def markSystemOnMap(self, systemname): self.systems[six.text_type(systemname)].mark() self.updateMapView() def setLocation(self, char, newSystem): for system in self.systems.values(): system.removeLocatedCharacter(char) if not newSystem == "?" and newSystem in self.systems: self.systems[newSystem].addLocatedCharacter(char) self.setMapContent(self.dotlan.svg) def setMapContent(self, content): if self.initialMapPosition is None: scrollPosition = self.mapView.page().mainFrame().scrollPosition() else: scrollPosition = self.initialMapPosition self.mapView.setContent(content) self.mapView.page().mainFrame().setScrollPosition(scrollPosition) self.mapView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) # Make sure we have positioned the window before we nil the initial position; # even though we set it, it may not take effect until the map is fully loaded scrollPosition = self.mapView.page().mainFrame().scrollPosition() if scrollPosition.x() or scrollPosition.y(): self.initialMapPosition = None def loadInitialMapPositions(self, newDictionary): self.mapPositionsDict = newDictionary def setInitialMapPositionForRegion(self, regionName): try: if not regionName: regionName = self.cache.getFromCache("region_name") if regionName: xy = self.mapPositionsDict[regionName] self.initialMapPosition = QPoint(xy[0], xy[1]) except Exception: pass def mapPositionChanged(self, dx, dy, rectToScroll): regionName = self.cache.getFromCache("region_name") if regionName: scrollPosition = self.mapView.page().mainFrame().scrollPosition() self.mapPositionsDict[regionName] = (scrollPosition.x(), scrollPosition.y()) def showChatroomChooser(self): chooser = ChatroomsChooser(self) chooser.connect(chooser, Qt.SIGNAL("rooms_changed"), self.changedRoomnames) chooser.show() def showJumbridgeChooser(self): url = self.cache.getFromCache("jumpbridge_url") chooser = JumpbridgeChooser(self, url) chooser.connect(chooser, Qt.SIGNAL("set_jumpbridge_url"), self.setJumpbridges) chooser.show() def setSoundVolume(self, value): SoundManager().setSoundVolume(value) def setJumpbridges(self, url): if url is None: url = "" try: data = [] if url != "": resp = requests.get(url) for line in resp.iter_lines(decode_unicode=True): parts = line.strip().split() if len(parts) == 3: data.append(parts) else: data = amazon_s3.getJumpbridgeData(self.dotlan.region.lower()) self.dotlan.setJumpbridges(data) self.cache.putIntoCache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8) except Exception as e: QtGui.QMessageBox.warning(None, "Loading jumpbridges failed!", "Error: {0}".format(six.text_type(e)), "OK") def handleRegionMenuItemSelected(self, menuAction=None): self.catchRegionAction.setChecked(False) self.providenceRegionAction.setChecked(False) self.queriousRegionAction.setChecked(False) self.providenceCatchRegionAction.setChecked(False) self.providenceCatchCompactRegionAction.setChecked(False) self.chooseRegionAction.setChecked(False) if menuAction: menuAction.setChecked(True) regionName = six.text_type(menuAction.property("regionName").toString()) regionName = dotlan.convertRegionName(regionName) Cache().putIntoCache("region_name", regionName, 60 * 60 * 24 * 365) self.setupMap() def showRegionChooser(self): def handleRegionChosen(): self.handleRegionMenuItemSelected(None) self.chooseRegionAction.setChecked(True) self.setupMap() self.chooseRegionAction.setChecked(False) chooser = RegionChooser(self) self.connect(chooser, Qt.SIGNAL("new_region_chosen"), handleRegionChosen) chooser.show() def addMessageToIntelChat(self, message): scrollToBottom = False if (self.chatListWidget.verticalScrollBar().value() == self.chatListWidget.verticalScrollBar().maximum()): scrollToBottom = True chatEntryWidget = ChatEntryWidget(message) listWidgetItem = QtGui.QListWidgetItem(self.chatListWidget) listWidgetItem.setSizeHint(chatEntryWidget.sizeHint()) self.chatListWidget.addItem(listWidgetItem) self.chatListWidget.setItemWidget(listWidgetItem, chatEntryWidget) self.avatarFindThread.addChatEntry(chatEntryWidget) self.chatEntries.append(chatEntryWidget) self.connect(chatEntryWidget, Qt.SIGNAL("mark_system"), self.markSystemOnMap) self.emit(Qt.SIGNAL("chat_message_added"), chatEntryWidget) self.pruneMessages() if scrollToBottom: self.chatListWidget.scrollToBottom() def pruneMessages(self): try: now = time.mktime(evegate.currentEveTime().timetuple()) for row in range(self.chatListWidget.count()): chatListWidgetItem = self.chatListWidget.item(0) chatEntryWidget = self.chatListWidget.itemWidget(chatListWidgetItem) message = chatEntryWidget.message if now - time.mktime(message.timestamp.timetuple()) > MESSAGE_EXPIRY_SECS: self.chatEntries.remove(chatEntryWidget) self.chatListWidget.takeItem(0) for widgetInMessage in message.widgets: widgetInMessage.removeItemWidget(chatListWidgetItem) else: break except Exception as e: logging.error(e) def showKosResult(self, state, text, requestType, hasKos): if not self.scanIntelForKosRequestsEnabled: return try: if hasKos: SoundManager().playSound("kos", text) if state == "ok": if requestType == "xxx": # An xxx request out of the chat self.trayIcon.showMessage("Player KOS-Check", text, 1) elif requestType == "clipboard": # request from clipboard-change if len(text) <= 0: text = "None KOS" self.trayIcon.showMessage("Your KOS-Check", text, 1) text = text.replace("\n\n", "<br>") message = chatparser.chatparser.Message("Vintel KOS-Check", text, evegate.currentEveTime(), "VINTEL", [], states.NOT_CHANGE, text.upper(), text) self.addMessageToIntelChat(message) elif state == "error": self.trayIcon.showMessage("KOS Failure", text, 3) except Exception: pass self.trayIcon.setIcon(self.taskbarIconQuiescent) def changedRoomnames(self, newRoomnames): self.cache.putIntoCache("room_names", u",".join(newRoomnames), 60 * 60 * 24 * 365 * 5) self.chatparser.rooms = newRoomnames def showInfo(self): infoDialog = QtGui.QDialog(self) uic.loadUi(resourcePath("vi/ui/Info.ui"), infoDialog) infoDialog.versionLabel.setText(u"Version: {0}".format(vi.version.VERSION)) infoDialog.logoLabel.setPixmap(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png"))) infoDialog.connect(infoDialog.closeButton, Qt.SIGNAL("clicked()"), infoDialog.accept) infoDialog.show() def showSoundSetup(self): dialog = QtGui.QDialog(self) uic.loadUi(resourcePath("vi/ui/SoundSetup.ui"), dialog) dialog.volumeSlider.setValue(SoundManager().soundVolume) dialog.connect(dialog.volumeSlider, Qt.SIGNAL("valueChanged(int)"), SoundManager().setSoundVolume) dialog.connect(dialog.testSoundButton, Qt.SIGNAL("clicked()"), SoundManager().playSound) dialog.connect(dialog.closeButton, Qt.SIGNAL("clicked()"), dialog.accept) dialog.show() def systemTrayActivated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: if self.isMinimized(): self.showNormal() self.activateWindow() elif not self.isActiveWindow(): self.activateWindow() else: self.showMinimized() def updateAvatarOnChatEntry(self, chatEntry, avatarData): updated = chatEntry.updateAvatar(avatarData) if not updated: self.avatarFindThread.addChatEntry(chatEntry, clearCache=True) else: self.emit(Qt.SIGNAL("avatar_loaded"), chatEntry.message.user, avatarData) def updateStatisticsOnMap(self, data): if not self.statisticsButton.isChecked(): return if data["result"] == "ok": self.dotlan.addSystemStatistics(data["statistics"]) elif data["result"] == "error": text = data["text"] self.trayIcon.showMessage("Loading statstics failed", text, 3) logging.error("updateStatisticsOnMap, error: %s" % text) def updateMapView(self): logging.debug("Updating map start") self.setMapContent(self.dotlan.svg) logging.debug("Updating map complete") def zoomMapIn(self): self.mapView.setZoomFactor(self.mapView.zoomFactor() + 0.1) def zoomMapOut(self): self.mapView.setZoomFactor(self.mapView.zoomFactor() - 0.1) def logFileChanged(self, path): messages = self.chatparser.fileModified(path) for message in messages: # If players location has changed if message.status == states.LOCATION: self.knownPlayerNames.add(message.user) self.setLocation(message.user, message.systems[0]) elif message.status == states.KOS_STATUS_REQUEST: # Do not accept KOS requests from monitored intel channels # as we don't want to encourage the use of xxx in those channels. if not message.room in self.roomnames: text = message.message[4:] text = text.replace(" ", ",") parts = (name.strip() for name in text.split(",")) self.trayIcon.setIcon(self.taskbarIconWorking) self.kosRequestThread.addRequest(parts, "xxx", False) # Otherwise consider it a 'normal' chat message elif message.user not in ("EVE-System", "EVE System") and message.status != states.IGNORE: self.addMessageToIntelChat(message) # For each system that was mentioned in the message, check for alarm distance to the current system # and alarm if within alarm distance. if message.systems: for system in message.systems: systemname = system.name self.dotlan.systems[systemname].setStatus(message.status) if message.status in (states.REQUEST, states.ALARM) and message.user not in self.knownPlayerNames: alarmDistance = self.alarmDistance if message.status == states.ALARM else 0 for nSystem, data in system.getNeighbours(alarmDistance).items(): distance = data["distance"] chars = nSystem.getLocatedCharacters() if len(chars) > 0 and message.user not in chars: self.trayIcon.showNotification(message, system.name, ", ".join(chars), distance) self.setMapContent(self.dotlan.svg)
# Setting local directory for cache and logging vintelDirectory = os.path.join(os.path.dirname(os.path.dirname(chatLogDirectory)), "vintel") if not os.path.exists(vintelDirectory): os.mkdir(vintelDirectory) cache.Cache.PATH_TO_CACHE = os.path.join(vintelDirectory, "cache-2.sqlite3") vintelLogDirectory = os.path.join(vintelDirectory, "logs") if not os.path.exists(vintelLogDirectory): os.mkdir(vintelLogDirectory) # Setup the application object, display splash screen app = QtGui.QApplication(sys.argv) splash = QtGui.QSplashScreen(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png"))) vintelCache = Cache() logLevel = vintelCache.getFromCache("logging_level") if not logLevel: logLevel = logging.WARN backGroundColor = vintelCache.getFromCache("background_color") if backGroundColor: app.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor) splash.show() app.processEvents() # Setup logging for console and rotated log files formatter = logging.Formatter('%(asctime)s| %(message)s', datefmt='%m/%d %I:%M:%S') rootLogger = logging.getLogger() rootLogger.setLevel(level=logLevel)
class MainWindow(QtGui.QMainWindow): def __init__(self, pathToLogs, trayIcon): QtGui.QMainWindow.__init__(self) uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self) self.setWindowTitle("Vintel " + VERSION) self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png")) self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png")) self.setWindowIcon(self.taskbarIconQuiescent) self.pathToLogs = pathToLogs self.trayIcon = trayIcon self.cache = Cache() # Load my toon names self.knownPlayerNames = self.cache.getFromCache("known_player_names") if self.knownPlayerNames: self.knownPlayerNames = set(self.knownPlayerNames.split(",")) else: self.knownPlayerNames = set() # Set up my intel rooms roomnames = self.cache.getFromCache("room_names") if roomnames: roomnames = roomnames.split(",") else: roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel") self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5) self.roomnames = roomnames # Disable the sound UI if sound is not available if not SoundManager().soundAvailable: self.changeSound(disable=True) else: self.changeSound() # Initialize state self.initMapPosition = None self.oldClipboardContent = "" self.alarmDistance = 0 self.lastStatisticsUpdate = 0 self.alreadyShowedSoundWarning = False self.chatEntries = [] self.frameButton.setVisible(False) self.trayIcon.activated.connect(self.systemTrayActivated) self.clipboard = QtGui.QApplication.clipboard() self.clipboard.clear(mode=self.clipboard.Clipboard) # Fill in opacity values and connections self.opacityGroup = QtGui.QActionGroup(self.menu) for i in (100, 80, 60, 40, 20): action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True) if i == 100: action.setChecked(True) action.opacity = i / 100.0 self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity) self.opacityGroup.addAction(action) self.menuTransparency.addAction(action) # Wire up UI connections self.connect(self.clipboard, Qt.SIGNAL("changed(QClipboard::Mode)"), self.clipboardChanged) self.connect(self.zoomInButton, Qt.SIGNAL("clicked()"), self.zoomMapIn) self.connect(self.zoomOutButton, Qt.SIGNAL("clicked()"), self.zoomMapOut) self.connect(self.statisticsButton, Qt.SIGNAL("clicked()"), self.changeStatisticsVisibility) self.connect(self.jumpbridgesButton, Qt.SIGNAL("clicked()"), self.changeJumpbridgesVisibility) self.connect(self.chatLargeButton, Qt.SIGNAL("clicked()"), self.chatLarger) self.connect(self.chatSmallButton, Qt.SIGNAL("clicked()"), self.chatSmaller) self.connect(self.infoAction, Qt.SIGNAL("triggered()"), self.showInfo) self.connect(self.showChatAvatarsAction, Qt.SIGNAL("triggered()"), self.changeShowAvatars) self.connect(self.alwaysOnTopAction, Qt.SIGNAL("triggered()"), self.changeAlwaysOnTop) self.connect(self.chooseChatRoomsAction, Qt.SIGNAL("triggered()"), self.showChatroomChooser) self.connect(self.catchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.catchRegionAction: self.handleRegionMenuItemSelected(item)) self.connect(self.providenceRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceRegionAction: self.handleRegionMenuItemSelected(item)) self.connect(self.providenceCatchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceCatchRegionAction: self.handleRegionMenuItemSelected(item)) self.connect(self.chooseRegionAction, Qt.SIGNAL("triggered()"), self.showRegionChooser) self.connect(self.showChatAction, Qt.SIGNAL("triggered()"), self.changeChatVisibility) self.connect(self.soundSetupAction, Qt.SIGNAL("triggered()"), self.showSoundSetup) self.connect(self.activateSoundAction, Qt.SIGNAL("triggered()"), self.changeSound) self.connect(self.useSpokenNotificationsAction, Qt.SIGNAL("triggered()"), self.changeUseSpokenNotifications) self.connect(self.floatingOverviewAction, Qt.SIGNAL("triggered()"), self.showFloatingOverview) self.connect(self.trayIcon, Qt.SIGNAL("alarm_distance"), self.changeAlarmDistance) self.connect(self.framelessWindowAction, Qt.SIGNAL("triggered()"), self.changeFrameless) self.connect(self.trayIcon, Qt.SIGNAL("change_frameless"), self.changeFrameless) self.connect(self.frameButton, Qt.SIGNAL("clicked()"), self.changeFrameless) self.connect(self.quitAction, Qt.SIGNAL("triggered()"), self.close) self.connect(self.trayIcon, Qt.SIGNAL("quit"), self.close) self.connect(self.jumpbridgeDataAction, Qt.SIGNAL("triggered()"), self.showJumbridgeChooser) # Create a timer to refresh the map, then load up the map, either from cache or dotlan self.mapTimer = QtCore.QTimer(self) self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView) self.setupMap(True) # Recall cached user settings try: self.cache.recallAndApplySettings(self, "settings") except Exception as e: print str(e) self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1) # Set up threads and their connections self.avatarFindThread = AvatarFindThread() self.connect(self.avatarFindThread, QtCore.SIGNAL("avatar_update"), self.updateAvatarOnChatEntry) self.avatarFindThread.start() self.kosRequestThread = KOSCheckerThread() self.connect(self.kosRequestThread, Qt.SIGNAL("kos_result"), self.showKosResult) self.kosRequestThread.start() self.filewatcherThread = filewatcher.FileWatcher(self.pathToLogs, 60 * 60 * 24) self.connect(self.filewatcherThread, QtCore.SIGNAL("file_change"), self.logFileChanged) self.filewatcherThread.start() self.versionCheckThread = amazon_s3.NotifyNewVersionThread() self.versionCheckThread.connect(self.versionCheckThread, Qt.SIGNAL("newer_version"), self.notifyNewerVersion) self.versionCheckThread.start() if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"): font = self.statisticsButton.font() font.setPointSize(8) self.statisticsButton.setFont(font) self.jumpbridgesButton.setFont(font) def setupMap(self, initialize=False): self.mapTimer.stop() regionName = self.cache.getFromCache("region_name") if not regionName: regionName = "Providence" svg = None try: with open(resourcePath("vi/ui/res/mapdata/{0}.svg".format(regionName))) as svgFile: svg = svgFile.read() except Exception as e: pass try: self.dotlan = dotlan.Map(regionName, svg) except dotlan.DotlanException as e: QtGui.QMessageBox.critical(None, "Error getting map", unicode(e), "Quit") sys.exit(1) if self.dotlan.outdatedCacheError: e = self.dotlan.outdatedCacheError diagText = "Something went wrong getting map data. Proceeding with older cached data. " \ "Check for a newer version and inform the maintainer.\n\nError: {0} {1}".format(type(e), unicode(e)) print str(e) QtGui.QMessageBox.warning(None, "Using map from cache", diagText, "Ok") # Load the jumpbridges self.setJumpbridges(self.cache.getFromCache("jumpbridge_url")) self.initMapPosition = None # We read this after first rendering self.systems = self.dotlan.systems self.chatparser = chatparser.ChatParser(self.pathToLogs, self.roomnames, self.systems) # Menus - only once if initialize: # Add a contextual menu to the mapView def mapContextMenuEvent(event): self.mapView.contextMenu.exec_(self.mapToGlobal(QPoint(event.x(), event.y()))) self.setMapContent(self.dotlan.svg) self.mapView.contextMenu = TrayContextMenu(self.trayIcon) self.mapView.contextMenuEvent = mapContextMenuEvent self.mapView.connect(self.mapView, Qt.SIGNAL("linkClicked(const QUrl&)"), self.mapLinkClicked) # Also set up our app menus regionName = self.cache.getFromCache("region_name") if not regionName: self.providenceRegionAction.setChecked(True) elif regionName.startswith("Providencecatch"): self.providenceCatchRegionAction.setChecked(True) elif regionName.startswith("Catch"): self.catchRegionAction.setChecked(True) elif regionName.startswith("Providence"): self.providenceRegionAction.setChecked(True) else: self.chooseRegionAction.setChecked(True) self.updateMapView(force=True) self.mapTimer.start(MAP_UPDATE_INTERVAL_IN_MSECS) self.jumpbridgesButton.setChecked(False) self.statisticsButton.setChecked(False) def closeEvent(self, event): """ Persisting things to the cache before closing the window """ # Known playernames if self.knownPlayerNames: value = ",".join(self.knownPlayerNames) self.cache.putIntoCache("known_player_names", value, 60 * 60 * 24 * 365) # Program state to cache (to read it on next startup) settings = ((None, "restoreGeometry", str(self.saveGeometry())), (None, "restoreState", str(self.saveState())), ("splitter", "restoreGeometry", str(self.splitter.saveGeometry())), ("splitter", "restoreState", str(self.splitter.saveState())), ("mapView", "setZoomFactor", self.mapView.zoomFactor()), (None, "changeChatFontSize", ChatEntryWidget.TEXT_SIZE), (None, "changeOpacity", self.opacityGroup.checkedAction().opacity), (None, "changeAlwaysOnTop", self.alwaysOnTopAction.isChecked()), (None, "changeShowAvatars", self.showChatAvatarsAction.isChecked()), (None, "changeAlarmDistance", self.alarmDistance), (None, "changeSound", self.activateSoundAction.isChecked()), (None, "changeChatVisibility", self.showChatAction.isChecked()), (None, "setInitMapPosition", (self.mapView.page().mainFrame().scrollPosition().x(), self.mapView.page().mainFrame().scrollPosition().y())), (None, "setSoundVolume", SoundManager().soundVolume), (None, "changeFrameless", self.framelessWindowAction.isChecked()), (None, "changeUseSpokenNotifications", self.useSpokenNotificationsAction.isChecked()), (None, "changeClipboard", self.kosClipboardActiveAction.isChecked()), (None, "changeFloatingOverview", self.floatingOverviewAction.isChecked()), (None, "changeAlreadyShowedSoundWarning", self.alreadyShowedSoundWarning)) self.cache.putIntoCache("settings", str(settings), 60 * 60 * 24 * 365) # Stop the threads try: self.filewatcherThread.quit() self.kosRequestThread.quit() SoundManager().quit() self.versionCheckThread.quit() except Exception: pass event.accept() def notifyNewerVersion(self, newestVersion): self.trayIcon.showMessage("Newer Version", ("An update is available for Vintel.\nhttps://github.com/Xanthos-Eve/vintel"), 1) def changeFloatingOverview(self, newValue=None): pass def changeAlreadyShowedSoundWarning(self, newValue): self.alreadyShowedSoundWarning = newValue def changeChatVisibility(self, newValue=None): if newValue is None: newValue = self.showChatAction.isChecked() self.showChatAction.setVisible(newValue) self.chatbox.setVisible(newValue) def changeClipboard(self, newValue=None): if newValue is None: newValue = self.kosClipboardActiveAction.isChecked() self.kosClipboardActiveAction.setChecked(newValue) def changeUseSpokenNotifications(self, newValue=None): if SoundManager().platformSupportsSpeech(): if newValue is None: newValue = self.useSpokenNotificationsAction.isChecked() self.useSpokenNotificationsAction.setChecked(newValue) SoundManager().setUseSpokenNotifications(newValue) else: self.useSpokenNotificationsAction.setChecked(False) self.useSpokenNotificationsAction.setEnabled(False) def changeOpacity(self, newValue=None): if newValue is not None: for action in self.opacityGroup.actions(): if action.opacity == newValue: action.setChecked(True) action = self.opacityGroup.checkedAction() self.setWindowOpacity(action.opacity) def changeSound(self, newValue=None, disable=False): if disable: self.activateSoundAction.setChecked(False) self.activateSoundAction.setEnabled(False) self.soundSetupAction.setEnabled(False) self.soundButton.setEnabled(False) if not self.alreadyShowedSoundWarning: self.alreadyShowedSoundWarning = True QtGui.QMessageBox.warning(None, "Sound disabled", "The lib 'pyglet' which is used to play sounds cannot be found, ""so the soundsystem is disabled.\nIf you want sound, please install the 'pyglet' library. This warning will not be shown again.", "OK") else: if newValue is None: newValue = self.activateSoundAction.isChecked() self.activateSoundAction.setChecked(newValue) SoundManager().soundActive = newValue def changeAlwaysOnTop(self, newValue=None): if newValue is None: newValue = self.alwaysOnTopAction.isChecked() self.hide() self.alwaysOnTopAction.setChecked(newValue) if newValue: self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) else: self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.WindowStaysOnTopHint)) self.show() def changeFrameless(self, newValue=None): if newValue is None: newValue = not self.frameButton.isVisible() self.hide() if newValue: self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.changeAlwaysOnTop(True) else: self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.FramelessWindowHint)) self.menubar.setVisible(not newValue) self.frameButton.setVisible(newValue) self.framelessWindowAction.setChecked(newValue) for cm in TrayContextMenu.instances: cm.framelessCheck.setChecked(newValue) self.show() def changeShowAvatars(self, newValue=None): if newValue is None: newValue = self.showChatAvatarsAction.isChecked() self.showChatAvatarsAction.setChecked(newValue) ChatEntryWidget.SHOW_AVATAR = newValue for entry in self.chatEntries: entry.avatarLabel.setVisible(newValue) def changeChatFontSize(self, newSize): if newSize: for entry in self.chatEntries: entry.changeFontSize(newSize) ChatEntryWidget.TEXT_SIZE = newSize def chatSmaller(self): newSize = ChatEntryWidget.TEXT_SIZE - 1 self.changeChatFontSize(newSize) def chatLarger(self): newSize = ChatEntryWidget.TEXT_SIZE + 1 self.changeChatFontSize(newSize) def changeAlarmDistance(self, distance): self.alarmDistance = distance for cm in TrayContextMenu.instances: for action in cm.distanceGroup.actions(): if action.alarmDistance == distance: action.setChecked(True) self.trayIcon.alarmDistance = distance def changeJumpbridgesVisibility(self): newValue = self.dotlan.changeJumpbridgesVisibility() self.jumpbridgesButton.setChecked(newValue) self.updateMapView() def changeStatisticsVisibility(self): newValue = self.dotlan.changeStatisticsVisibility() self.statisticsButton.setChecked(newValue) self.updateMapView() def clipboardChanged(self, mode): if not (mode == 0 and self.kosClipboardActiveAction.isChecked() and self.clipboard.mimeData().hasText()): return content = unicode(self.clipboard.text()) contentTuple = tuple(content) # Limit redundant kos checks if contentTuple != self.oldClipboardContent: parts = tuple(content.split("\n")) for part in parts: # Make sure user is in the content (this is a check of the local system in Eve) if part in self.knownPlayerNames: self.trayIcon.setIcon(self.taskbarIconWorking) self.kosRequestThread.addRequest(parts, "clipboard", True) break self.oldClipboardContent = contentTuple def mapLinkClicked(self, url): systemName = unicode(url.path().split("/")[-1]).upper() system = self.systems[str(systemName)] sc = SystemChat(self, SystemChat.SYSTEM, system, self.chatEntries, self.knownPlayerNames) sc.connect(self, Qt.SIGNAL("chat_message_added"), sc.addChatEntry) sc.connect(self, Qt.SIGNAL("avatar_loaded"), sc.newAvatarAvailable) sc.connect(sc, Qt.SIGNAL("location_set"), self.setLocation) sc.show() def markSystemOnMap(self, systemname): self.systems[unicode(systemname)].mark() self.updateMapView() def setLocation(self, char, newSystem): for system in self.systems.values(): system.removeLocatedCharacter(char) if not newSystem == "?" and newSystem in self.systems: self.systems[newSystem].addLocatedCharacter(char) self.setMapContent(self.dotlan.svg) def setMapContent(self, content): if self.initMapPosition is None: scrollposition = self.mapView.page().mainFrame().scrollPosition() else: scrollposition = self.initMapPosition self.initMapPosition = None self.mapView.setContent(content) self.mapView.page().mainFrame().setScrollPosition(scrollposition) self.mapView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) def setInitMapPosition(self, xy): self.initMapPosition = QPoint(xy[0], xy[1]) def showChatroomChooser(self): chooser = ChatroomsChooser(self) chooser.connect(chooser, Qt.SIGNAL("rooms_changed"), self.changedRoomnames) chooser.show() def showJumbridgeChooser(self): url = self.cache.getFromCache("jumpbridge_url") chooser = JumpbridgeChooser(self, url) chooser.connect(chooser, Qt.SIGNAL("set_jumpbridge_url"), self.setJumpbridges) chooser.show() def setSoundVolume(self, value): SoundManager().setSoundVolume(value) def setJumpbridges(self, url): if url is None: url = "" try: data = [] if url != "": content = urllib2.urlopen(url).read() for line in content.split("\n"): parts = line.strip().split() if len(parts) == 3: data.append(parts) else: data = amazon_s3.getJumpbridgeData(self.dotlan.region.lower()) self.dotlan.setJumpbridges(data) self.cache.putIntoCache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8) except Exception as e: QtGui.QMessageBox.warning(None, "Loading jumpbridges failed!", "Error: {0}".format(unicode(e)), "OK") def handleRegionMenuItemSelected(self, menuAction=None): self.catchRegionAction.setChecked(False) self.providenceRegionAction.setChecked(False) self.providenceCatchRegionAction.setChecked(False) self.chooseRegionAction.setChecked(False) if menuAction: menuAction.setChecked(True) regionName = unicode(menuAction.property("regionName").toString()) regionName = dotlan.convertRegionName(regionName) Cache().putIntoCache("region_name", regionName, 60 * 60 * 24 * 365) self.setupMap() def showRegionChooser(self): def handleRegionChosen(): self.handleRegionMenuItemSelected(None) self.chooseRegionAction.setChecked(True) self.setupMap() self.chooseRegionAction.setChecked(False) chooser = RegionChooser(self) self.connect(chooser, Qt.SIGNAL("new_region_chosen"), handleRegionChosen) chooser.show() def addMessageToIntelChat(self, message): scrollToBottom = False if (self.chatListWidget.verticalScrollBar().value() == self.chatListWidget.verticalScrollBar().maximum()): scrollToBottom = True chatEntryWidget = ChatEntryWidget(message) listWidgetItem = QtGui.QListWidgetItem(self.chatListWidget) listWidgetItem.setSizeHint(chatEntryWidget.sizeHint()) self.chatListWidget.addItem(listWidgetItem) self.chatListWidget.setItemWidget(listWidgetItem, chatEntryWidget) self.avatarFindThread.addChatEntry(chatEntryWidget) self.chatEntries.append(chatEntryWidget) self.connect(chatEntryWidget, Qt.SIGNAL("mark_system"), self.markSystemOnMap) self.emit(Qt.SIGNAL("chat_message_added"), chatEntryWidget) self.pruneMessages() if scrollToBottom: self.chatListWidget.scrollToBottom() def pruneMessages(self): try: now = time.mktime(evegate.currentEveTime().timetuple()) for row in range(self.chatListWidget.count()): chatListWidgetItem = self.chatListWidget.item(0) chatEntryWidget = self.chatListWidget.itemWidget(chatListWidgetItem) message = chatEntryWidget.message if now - time.mktime(message.timestamp.timetuple()) > MESSAGE_EXPIRY_IN_SECONDS: self.chatEntries.remove(chatEntryWidget) self.chatListWidget.takeItem(0) for widgetInMessage in message.widgets: widgetInMessage.removeItemWidget(chatListWidgetItem) else: break except Exception as e: print e def showKosResult(self, state, text, requestType, hasKos): try: if hasKos: SoundManager().playSound("kos", text) if state == "ok": if requestType == "xxx": # a xxx request out of the chat self.trayIcon.showMessage("Player KOS-Check", text, 1) elif requestType == "clipboard": # request from clipboard-change if len(text) <= 0: text = "None KOS" self.trayIcon.showMessage("Your KOS-Check", text, 1) text = text.replace("\n\n", "<br>") message = chatparser.chatparser.Message("Vintel KOS-Check", text, evegate.currentEveTime(), "VINTEL", [], states.NOT_CHANGE, text.upper(), text) self.addMessageToIntelChat(message) elif state == "error": self.trayIcon.showMessage("KOS Failure", text, 3) except Exception: pass self.trayIcon.setIcon(self.taskbarIconQuiescent) def changedRoomnames(self, newRoomnames): self.cache.putIntoCache("room_names", u",".join(newRoomnames), 60 * 60 * 24 * 365 * 5) self.chatparser.rooms = newRoomnames def showInfo(self): infoDialog = QtGui.QDialog(self) uic.loadUi(resourcePath("vi/ui/Info.ui"), infoDialog) infoDialog.versionLabel.setText(u"Version: {0}".format(VERSION)) infoDialog.logoLabel.setPixmap(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png"))) infoDialog.connect(infoDialog.closeButton, Qt.SIGNAL("clicked()"), infoDialog.accept) infoDialog.show() def showFloatingOverview(self): pass def showSoundSetup(self): dialog = QtGui.QDialog(self) uic.loadUi(resourcePath("vi/ui/SoundSetup.ui"), dialog) dialog.volumeSlider.setValue(SoundManager().soundVolume) dialog.connect(dialog.volumeSlider, Qt.SIGNAL("valueChanged(int)"), SoundManager().setSoundVolume) dialog.connect(dialog.testSoundButton, Qt.SIGNAL("clicked()"), SoundManager().playSound) dialog.connect(dialog.closeButton, Qt.SIGNAL("clicked()"), dialog.accept) dialog.show() def systemTrayActivated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: if self.isMinimized(): self.showNormal() self.activateWindow() elif not self.isActiveWindow(): self.activateWindow() else: self.showMinimized() def updateAvatarOnChatEntry(self, chatEntry, avatarData): updated = chatEntry.updateAvatar(avatarData) if not updated: self.avatarFindThread.addChatEntry(chatEntry, clearCache=True) else: self.emit(Qt.SIGNAL("avatar_loaded"), chatEntry.message.user, avatarData) def updateMapView(self, force=False): def updateStatisticsOnMap(data): if data["result"] == "ok": self.dotlan.addSystemStatistics(data["statistics"]) elif data["result"] == "error": text = data["text"] self.trayIcon.showMessage("Loading statstics failed", text, 3) if force or self.lastStatisticsUpdate < time.time() - STATISTICS_UPDATE_INTERVAL_IN_MSECS: self.lastStatisticsUpdate = time.time() statisticsThread = MapStatisticsThread() self.connect(statisticsThread, Qt.SIGNAL("statistic_data_update"), updateStatisticsOnMap) statisticsThread.start() self.setMapContent(self.dotlan.svg) def zoomMapIn(self): self.mapView.setZoomFactor(self.mapView.zoomFactor() + 0.1) def zoomMapOut(self): self.mapView.setZoomFactor(self.mapView.zoomFactor() - 0.1) def logFileChanged(self, path): messages = self.chatparser.fileModified(path) for message in messages: # If players location has changed if message.status == states.LOCATION: self.knownPlayerNames.add(message.user) self.setLocation(message.user, message.systems[0]) # SOUND_TEST special elif message.status == states.SOUND_TEST and message.user in self.knownPlayerNames: words = message.message.split() if len(words) > 1: SoundManager().playSound(words[1]) # KOS request elif message.status == states.KOS_STATUS_REQUEST: text = message.message[4:] text = text.replace(" ", ",") parts = (name.strip() for name in text.split(",")) self.trayIcon.setIcon(self.taskbarIconWorking) self.kosRequestThread.addRequest(parts, "xxx", False) # Otherwise consider it a 'normal' chat message elif (message.user not in ("EVE-System", "EVE System") and message.status != states.IGNORE): self.addMessageToIntelChat(message) # For each system that was mentioned in the message, check for alarm distance to the current system # and alarm if within alarm distance. if message.systems: for system in message.systems: systemname = system.name self.dotlan.systems[systemname].setStatus(message.status) if message.status in (states.REQUEST, states.ALARM) and message.user not in self.knownPlayerNames: alarmDistance = self.alarmDistance if message.status == states.ALARM else 0 for nSystem, data in system.getNeighbours(alarmDistance).items(): distance = data["distance"] chars = nSystem.getLocatedCharacters() if len(chars) > 0 and message.user not in chars: self.trayIcon.showNotification(message, system.name, ", ".join(chars), distance) self.setMapContent(self.dotlan.svg)
def __init__(self, pathToLogs, trayIcon): QtGui.QMainWindow.__init__(self) uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self) self.setWindowTitle("Vintel " + VERSION) self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png")) self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png")) self.setWindowIcon(self.taskbarIconQuiescent) self.pathToLogs = pathToLogs self.trayIcon = trayIcon self.cache = Cache() # Load my toon names self.knownPlayerNames = self.cache.getFromCache("known_player_names") if self.knownPlayerNames: self.knownPlayerNames = set(self.knownPlayerNames.split(",")) else: self.knownPlayerNames = set() # Set up my intel rooms roomnames = self.cache.getFromCache("room_names") if roomnames: roomnames = roomnames.split(",") else: roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel") self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5) self.roomnames = roomnames # Disable the sound UI if sound is not available if not SoundManager().soundAvailable: self.changeSound(disable=True) else: self.changeSound() # Initialize state self.initMapPosition = None self.oldClipboardContent = "" self.alarmDistance = 0 self.lastStatisticsUpdate = 0 self.alreadyShowedSoundWarning = False self.chatEntries = [] self.frameButton.setVisible(False) self.trayIcon.activated.connect(self.systemTrayActivated) self.clipboard = QtGui.QApplication.clipboard() self.clipboard.clear(mode=self.clipboard.Clipboard) # Fill in opacity values and connections self.opacityGroup = QtGui.QActionGroup(self.menu) for i in (100, 80, 60, 40, 20): action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True) if i == 100: action.setChecked(True) action.opacity = i / 100.0 self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity) self.opacityGroup.addAction(action) self.menuTransparency.addAction(action) # Wire up UI connections self.connect(self.clipboard, Qt.SIGNAL("changed(QClipboard::Mode)"), self.clipboardChanged) self.connect(self.zoomInButton, Qt.SIGNAL("clicked()"), self.zoomMapIn) self.connect(self.zoomOutButton, Qt.SIGNAL("clicked()"), self.zoomMapOut) self.connect(self.statisticsButton, Qt.SIGNAL("clicked()"), self.changeStatisticsVisibility) self.connect(self.jumpbridgesButton, Qt.SIGNAL("clicked()"), self.changeJumpbridgesVisibility) self.connect(self.chatLargeButton, Qt.SIGNAL("clicked()"), self.chatLarger) self.connect(self.chatSmallButton, Qt.SIGNAL("clicked()"), self.chatSmaller) self.connect(self.infoAction, Qt.SIGNAL("triggered()"), self.showInfo) self.connect(self.showChatAvatarsAction, Qt.SIGNAL("triggered()"), self.changeShowAvatars) self.connect(self.alwaysOnTopAction, Qt.SIGNAL("triggered()"), self.changeAlwaysOnTop) self.connect(self.chooseChatRoomsAction, Qt.SIGNAL("triggered()"), self.showChatroomChooser) self.connect(self.catchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.catchRegionAction: self.handleRegionMenuItemSelected(item)) self.connect(self.providenceRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceRegionAction: self.handleRegionMenuItemSelected(item)) self.connect(self.providenceCatchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceCatchRegionAction: self.handleRegionMenuItemSelected(item)) self.connect(self.chooseRegionAction, Qt.SIGNAL("triggered()"), self.showRegionChooser) self.connect(self.showChatAction, Qt.SIGNAL("triggered()"), self.changeChatVisibility) self.connect(self.soundSetupAction, Qt.SIGNAL("triggered()"), self.showSoundSetup) self.connect(self.activateSoundAction, Qt.SIGNAL("triggered()"), self.changeSound) self.connect(self.useSpokenNotificationsAction, Qt.SIGNAL("triggered()"), self.changeUseSpokenNotifications) self.connect(self.floatingOverviewAction, Qt.SIGNAL("triggered()"), self.showFloatingOverview) self.connect(self.trayIcon, Qt.SIGNAL("alarm_distance"), self.changeAlarmDistance) self.connect(self.framelessWindowAction, Qt.SIGNAL("triggered()"), self.changeFrameless) self.connect(self.trayIcon, Qt.SIGNAL("change_frameless"), self.changeFrameless) self.connect(self.frameButton, Qt.SIGNAL("clicked()"), self.changeFrameless) self.connect(self.quitAction, Qt.SIGNAL("triggered()"), self.close) self.connect(self.trayIcon, Qt.SIGNAL("quit"), self.close) self.connect(self.jumpbridgeDataAction, Qt.SIGNAL("triggered()"), self.showJumbridgeChooser) # Create a timer to refresh the map, then load up the map, either from cache or dotlan self.mapTimer = QtCore.QTimer(self) self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView) self.setupMap(True) # Recall cached user settings try: self.cache.recallAndApplySettings(self, "settings") except Exception as e: print str(e) self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1) # Set up threads and their connections self.avatarFindThread = AvatarFindThread() self.connect(self.avatarFindThread, QtCore.SIGNAL("avatar_update"), self.updateAvatarOnChatEntry) self.avatarFindThread.start() self.kosRequestThread = KOSCheckerThread() self.connect(self.kosRequestThread, Qt.SIGNAL("kos_result"), self.showKosResult) self.kosRequestThread.start() self.filewatcherThread = filewatcher.FileWatcher(self.pathToLogs, 60 * 60 * 24) self.connect(self.filewatcherThread, QtCore.SIGNAL("file_change"), self.logFileChanged) self.filewatcherThread.start() self.versionCheckThread = amazon_s3.NotifyNewVersionThread() self.versionCheckThread.connect(self.versionCheckThread, Qt.SIGNAL("newer_version"), self.notifyNewerVersion) self.versionCheckThread.start() if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"): font = self.statisticsButton.font() font.setPointSize(8) self.statisticsButton.setFont(font) self.jumpbridgesButton.setFont(font)
def getSystemStatistics(): """ Reads the informations for all solarsystems from the EVE API Reads a dict like: systemid: "jumps", "shipkills", "factionkills", "podkills" """ data = {} systemData = {} cache = Cache() # first the data for the jumps cacheKey = "jumpstatistic" jumpData = cache.getFromCache(cacheKey) try: if jumpData is None: jumpData = {} url = "https://api.eveonline.com/map/Jumps.xml.aspx" content = requests.get(url).text soup = BeautifulSoup(content, 'html.parser') for result in soup.select("result"): for row in result.select("row"): jumpData[int(row["solarsystemid"])] = int(row["shipjumps"]) cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, json.dumps(jumpData), diff.seconds) else: jumpData = json.loads(jumpData) # now the further data cacheKey = "systemstatistic" systemData = cache.getFromCache(cacheKey) if systemData is None: systemData = {} url = "https://api.eveonline.com/map/Kills.xml.aspx" content = requests.get(url).text soup = BeautifulSoup(content, 'html.parser') for result in soup.select("result"): for row in result.select("row"): systemData[int(row["solarsystemid"])] = {"ship": int(row["shipkills"]), "faction": int(row["factionkills"]), "pod": int(row["podkills"])} cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, json.dumps(systemData), diff.seconds) else: systemData = json.loads(systemData) except Exception as e: logging.error("Exception during getSystemStatistics: : %s", e) # We collected all data (or loaded them from cache) - now zip it together for i, v in jumpData.items(): i = int(i) if i not in data: data[i] = {"shipkills": 0, "factionkills": 0, "podkills": 0} data[i]["jumps"] = v for i, v in systemData.items(): i = int(i) if i not in data: data[i] = {"jumps": 0} data[i]["shipkills"] = v["ship"] if "ship" in v else 0 data[i]["factionkills"] = v["faction"] if "faction" in v else 0 data[i]["podkills"] = v["pod"] if "pod" in v else 0 return data
def __init__(self, pathToLogs, trayIcon, backGroundColor): QtGui.QMainWindow.__init__(self) self.cache = Cache() if backGroundColor: self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor) uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self) self.setWindowTitle("Vintel " + vi.version.VERSION + "{dev}".format(dev="-SNAPSHOT" if vi.version.SNAPSHOT else "")) self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png")) self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png")) self.setWindowIcon(self.taskbarIconQuiescent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.pathToLogs = pathToLogs self.mapTimer = QtCore.QTimer(self) self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView) self.clipboardTimer = QtCore.QTimer(self) self.oldClipboardContent = "" self.trayIcon = trayIcon self.trayIcon.activated.connect(self.systemTrayActivated) self.clipboard = QtGui.QApplication.clipboard() self.clipboard.clear(mode=self.clipboard.Clipboard) self.alarmDistance = 0 self.lastStatisticsUpdate = 0 self.chatEntries = [] self.frameButton.setVisible(False) self.scanIntelForKosRequestsEnabled = True self.initialMapPosition = None self.mapPositionsDict = {} # Load user's toon names self.knownPlayerNames = self.cache.getFromCache("known_player_names") if self.knownPlayerNames: self.knownPlayerNames = set(self.knownPlayerNames.split(",")) else: self.knownPlayerNames = set() diagText = "Vintel scans EVE system logs and remembers your characters as they change systems.\n\nSome features (clipboard KOS checking, alarms, etc.) may not work until your character(s) have been registered. Change systems, with each character you want to monitor, while Vintel is running to remedy this." QtGui.QMessageBox.warning(None, "Known Characters not Found", diagText, "Ok") # Set up user's intel rooms roomnames = self.cache.getFromCache("room_names") if roomnames: roomnames = roomnames.split(",") else: roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel", "North Querious Intel") self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5) self.roomnames = roomnames # Disable the sound UI if sound is not available if not SoundManager().soundAvailable: self.changeSound(disable=True) else: self.changeSound() # Set up Transparency menu - fill in opacity values and make connections self.opacityGroup = QtGui.QActionGroup(self.menu) for i in (100, 80, 60, 40, 20): action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True) if i == 100: action.setChecked(True) action.opacity = i / 100.0 self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity) self.opacityGroup.addAction(action) self.menuTransparency.addAction(action) # # Platform specific UI resizing - we size items in the resource files to look correct on the mac, # then resize other platforms as needed # if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"): font = self.statisticsButton.font() font.setPointSize(8) self.statisticsButton.setFont(font) self.jumpbridgesButton.setFont(font) elif sys.platform.startswith("linux"): pass self.wireUpUIConnections() self.recallCachedSettings() self.setupThreads() self.setupMap(True)