def StartSearchName(self,name:str=""): """ 开始一轮搜索。 """ global current_thread_set if name=="": name = self.EdtName.text() #检查这是否是一个合适的name name = name.strip(" \n\"\'“”‘’") if name == "": self.statusBar().showMessage("错误:没有输入名字") return - 1 #如果是一个zkb链接 fetch = re.search(r"https://zkillboard\.com/character/([0-9]*)/", name) if fetch != None: log("导入zkb链接"+fetch.group(0)) self.RefreshLabelList({"LoadFromzkbLink": [TMsgEntry( "导入zkb链接 " + fetch.group(0), style_str=MDStyleStr(color=settings["clHint"], font_size=settings["labelFontSize"]) ),TMsgEntry( "正在搜索...", style_str=MDStyleStr(color=settings["clHint"], font_size=settings["labelFontSize"]) )]}) self.MultiThreadRun(func=SearchName, args=(None, int(fetch.group(1)))) else: name=re.search(r"^[a-zA-Z0-9 '\-_]*$", name) if name==None: #名字中含有非法字符 self.statusBar().showMessage("错误:名字中含有非法字符") return - 1 else: name=name.group(0) self.MsgEntryList = {} current_thread_set = set() log("搜索"+name) self.RefreshLabelList({"SearchName": { "Searching": [name, TMsgEntry("正在搜索名字包含" + name + '的角色...', style_str=MDStyleStr( color=settings["clHint"], font_size=settings["labelFontSize"] ) ), ] }}) self.MultiThreadRun(func=SearchName, args=(name,)) return 0
def mousePressEvent(self, e): # 单击 global current_thread_set self.on_events = True self.parent().parent().LabelList_click_no = self.no if self.MsgEntry.ClickEvent != None: log("label:"+self.text()+",ClickEvent="+str(self.MsgEntry.ClickEvent)+",ClickArgs="+str(self.MsgEntry.ClickArgs)) current_thread_set=set() self.parent().parent().EndSearchEvent() if self.MsgEntry.ClickEvent == SearchName: self.parent().parent().RefreshLabelList({"Searching": TMsgEntry( text="正在搜索角色{name}...".format(name=str(self.MsgEntry.ClickArgs[0])), style_str=MDStyleStr( color=settings["clHint"], font_size=settings["labelFontSize"] ))}) self.MsgEntry.ClickReturn = self.parent().parent().MultiThreadRun(func=self.MsgEntry.ClickEvent, args=self.MsgEntry.ClickArgs) elif self.MsgEntry.ClickEvent == SearchKM: #TODO:增加一个判断,如果已经获取了km则不重复获取 if self.MsgEntry.ClickReturn == None: self.parent().parent().StatusBar.showMessage("正在获取km...") self.MsgEntry.ClickReturn = self.parent().parent().MultiThreadRun(func=self.MsgEntry.ClickEvent, args=self.MsgEntry.ClickArgs) # else: # self.MsgEntry.enable = not self.MsgEntry.enable # self.parent().parent().RefreshLabelList() self.on_events=False
def __init__(self, m=TMsgEntry(),no=-1,): super(TMsgLabel, self).__init__() self.no = no #在LabelList中的序号 self.on_events = False #正在响应事件 self.MsgEntry=m left, top = self.MsgEntry.left, self.MsgEntry.top + (self.no * settings["labelFontSize"] * 6) self.move(left,top) self.setScaledContents = True #自动拉伸 self.setWordWrap = True self.setFont(QFont(font_path[settings["lang"]])) self.setTextFormat(Qt.MarkdownText) self.setText(font_path[settings["lang"]]) if self.MsgEntry.style_str != "": #将html标签形式的font包装成text l= re.findall(r"<([a-zA-Z0-9\-_]*)([a-zA-Z0-9\-_#= ]*)>",self.MsgEntry.style_str) self.setText(self.MsgEntry.style_str + self.MsgEntry.text + ''.join(["</" + i[0] + ">" for i in l])) # 添加阴影 self.effect_shadow = QGraphicsDropShadowEffect(self) text_color = re.search(r"color=(#[0-9A-F]*)", self.text()) text_color = RGB2Hex((8,8,160,127)) if text_color == None else text_color.group(1) self.effect_shadow.setOffset(0,0) # 偏移 self.effect_shadow.setColor(QColor(text_color)) # 阴影颜色 self.effect_shadow.setBlurRadius(10) # 阴影半径 self.setGraphicsEffect(self.effect_shadow) # 将设置套用到widget窗口中
def addName(ID: int, no: int = 0): """ 为characterID获取name。 ID(int):要搜索name的ID。 no(int):第no个搜索项。 """ url = r"https://esi.evetech.net/latest/characters/" + str( ID) + r"/?datasource=tranquility" Msg = {"addName": []} try: with rq.get(url, timeout=5) as ret: ret = loads(ret.content) except Exception as e: log("addName:" + str(e), level="error") return Msg log("addName:ID={ID}已获取到".format(ID=ID)) if "name" in ret: history.update({ret["name"]: {"characterID": ID}}) Msg["addName"].append([ ID, TMsgEntry(ret["name"], ClickEvent=SearchName, ClickArgs=(ret["name"], ID), style_str=MDStyleStr( color=settings["claddName"], font_size=settings["labelFontSize"])) ]) return Msg
def EndSearchEvent(self,e=None): """ 搜索结束事件。 将传递信息的线程传来的 """ if isinstance(self.sender(), TThread): log("EndSearch:"+str(self.sender().__name__)) MutEndSearch.lock() Msg = self.sender().Msg log("Msg="+str(Msg)) if id(self.sender()) not in current_thread_set: #说明不是此次搜索的返回线程,直接丢弃 MutEndSearch.unlock() return - 1 #由SearchName返回 if "getKMList" in Msg:#完成了一轮完整的搜索流程 self.MsgEntryList = {} self.MsgEntryList.update(Msg) self.statusBar().showMessage("搜索完成") self.EdtName.setStyleSheet(""" TEdtName{ border: 2px groove white; border-radius: 3px; padding:2px 3px; color:rgb(255,0,0); background-color:rgba(0,0,0,0) } TEdtName:focus{ color:rgb(0,255,0); background-color: rgb(0,0,0) } """) elif "Error" in Msg: #SearchName返回错误 self.MsgEntryList = {} self.MsgEntryList.update(Msg) if Msg["Error"] == "getKMListError": self.MsgEntryList.update({"ErrorLabel": TMsgEntry("获取KM列表失败",style_str=MDStyleStr(color=settings["clFailed"],font_size=settings["labelFontSize"]))}) elif Msg["Error"] == "zkbError": self.MsgEntryList.update({"ErrorLabel": TMsgEntry("zkb查询失败",style_str=MDStyleStr(color=settings["clFailed"],font_size=settings["labelFontSize"]))}) elif Msg["Error"] == "esiError": self.MsgEntryList.update({"ErrorLabel": TMsgEntry("查询角色ID失败", style_str=MDStyleStr(color=settings["clFailed"], font_size=settings["labelFontSize"]))}) elif Msg["Error"] == "SearchKMError": self.MsgEntryList.update({"ErrorLabel": TMsgEntry("查询KM失败", style_str=MDStyleStr(color=settings["clFailed"], font_size=settings["labelFontSize"]))}) elif Msg["Error"] == "NoSuchCharacterError": self.MsgEntryList.update({"ErrorLabel": TMsgEntry("无此角色", style_str=MDStyleStr(color=settings["clFailed"], font_size=settings["labelFontSize"]))}) elif Msg["Error"] == "PlayerNoPVPData": self.MsgEntryList.update({"ErrorLabel": TMsgEntry("没有该角色的统计数据",style_str=MDStyleStr(color=settings["clHint"],font_size=settings["labelFontSize"]))}) elif "NameList" in Msg: #多个搜索结果命中 self.MsgEntryList.update({"MultipleHits": TMsgEntry("命中" + str(len(Msg["NameList"])) + "条搜索结果...",style_str=MDStyleStr(color=settings["clHint"],font_size=settings["labelFontSize"]))}) NameList = Msg["NameList"][:] no=0 for c in NameList: no+=1 self.MultiThreadRun(func=addName, args=(c, no)) elif "TooManyResults" in Msg: #搜索结果命中数超过ResultCountLimit self.MsgEntryList.update(Msg) self.MultiThreadRun(func=SearchName,args=(Msg["name"],-1,True)) #由addName返回 elif "addName" in Msg: #处理addName返回的情况 #addName会多并发调用EndSearchEvent,因此需要QMutex #addName会返回成对的name和characterID,每个返回都应被添加至self.MsgEntryList["addName"] if "addName" not in self.MsgEntryList: self.MsgEntryList["addName"]=[] self.MsgEntryList["addName"] += Msg["addName"] #由SearchKM返回 elif "SearchKM" in Msg: if self.LabelList_click_no != -1: #需要找到被单击的Label在self.MsgEntryList中的位置 for i in range(len(self.MsgEntryList["getKMList"])): #如果getKMList中记录的killmail_id==LabelList中记录的killmail_id if (self.MsgEntryList["getKMList"][i][0][0]==self.LabelList[self.LabelList_click_no].MsgEntry.ClickArgs[1]): self.MsgEntryList["getKMList"][i][2]=Msg break self.statusBar().showMessage("KM已获取") MutEndSearch.unlock() self.RefreshLabelList()
def SearchName(name: str = '', ID: int = -1, is_strict=False): """ 获取角色ID与zkb统计信息。 name(str):角色名 ID(int):如果已有角色ID则跳过搜索characterID的步骤 is_strict(bool):严格模式,只搜索与name完全一致的角色名 """ global MutSearchName MutSearchName.lock() Msg = {} log("SearchName:name={name},ID={ID},is_strict={is_strict}".format( name=name, ID=ID, is_strict=is_strict)) #characterID if ID < 0: #如果没有给出characterID name = name.strip(" \n") for i in history: if i.upper() == name.upper(): name = i ID = history[name]["characterID"] break if ID < 0: #搜索历史记录未命中 log("SearchName:历史记录未命中") strict = "&strict=true" if is_strict else "&strict=false" url = r"https://esi.evetech.net/latest/search/?categories=character&datasource=tranquility&language=en-us&search=" + name.replace( " ", "+") + strict try: with rq.get(url, timeout=5) as ret: ret = loads(ret.content) except Exception as e: log("SearchName:" + str(e), level="error") Msg.update({"Error": "esiError"}) MutSearchName.unlock() return Msg if "character" in ret: ID = ret["character"] if (len(ID) > 1): log("SearchName:命中{l}/{lmax}个结果".format( l=len(ID), lmax=settings["ResultCountLimit"])) #有多个命中结果 if len(ID) < settings["ResultCountLimit"]: Msg.update({"NameList": ID}) MutSearchName.unlock() return Msg else: #结果过多 Msg.update({ "TooManyResults": TMsgEntry("搜索结果数量超过" + \ str(settings["ResultCountLimit"]) + "个,改为严格模式...", style_str=MDStyleStr( color=settings["clHint"], font_size=settings["labelFontSize"] )), "name": name }) MutSearchName.unlock() return Msg else: ID = ID[0] else: Msg.update({"Error": "NoSuchCharacterError"}) log("SearchName:esi查询失败:{name}".format(name=name), level="warning") MutSearchName.unlock() return Msg Msg.update({"SearchName": [name, ID]}) #zkb url = r"https://zkillboard.com/api/stats/characterID/" + str(ID) + r"/" try: with rq.get(url, timeout=5) as ret: ret = loads(ret.content) except Exception as e: Msg.update({"Error": "zkbError"}) MutSearchName.unlock() return Msg #角色信息为None if (ret == {}) or (ret["info"] == None): Msg.update({"Error": "PlayerNoPVPData"}) MutSearchName.unlock() return Msg if "dangerRatio" not in ret: ret["dangerRatio"] = 0 danger_ratio_color = (int(ret["dangerRatio"] / 100 * 255), int((1 - (ret["dangerRatio"] / 100)) * 255), 0) if "gangRatio" not in ret: ret["gangRatio"] = 100 solo_ratio_color = (int((1 - (ret["gangRatio"] / 100)) * 255), int(ret["gangRatio"] / 100 * 255), 0) Msg.update({ "SearchKB": { "name": [ ret["info"]["name"], TMsgEntry( r"<a href='https://zkillboard.com/character/" + str(ID) + r"' style='color:blue'>" + ret["info"]["name"] + "</a>", style_str=MDStyleStr(color=settings["clURL"], font_size=settings["labelFontSize"])) ], "dangerRatio": [ ret["dangerRatio"], TMsgEntry("危险度:" + str(ret["dangerRatio"]) + "%", style_str=MDStyleStr( color=danger_ratio_color, font_size=settings["labelFontSize"])) ], "soloRatio": [ ret["gangRatio"], TMsgEntry("solo率:" + str(100 - ret["gangRatio"]) + "%", style_str=MDStyleStr( color=solo_ratio_color, font_size=settings["labelFontSize"])) ], "topShips": [[i["shipTypeID"] for i in ret["topLists"][3]["values"][:3]], TMsgEntry("最高击杀舰船:" + ','.join([ getNamebyID(i["shipTypeID"]) + "(" + str(i["kills"]) + "次)" for i in ret["topLists"][3]["values"][:3] if i["shipName"] != "Capsule" ]), style_str=MDStyleStr( color=settings["cltopShips"], font_size=settings["labelFontSize"]))], "topSolarSystem": [[i["solarSystemName"] for i in ret["topLists"][4]["values"][:3]], TMsgEntry("最常出没:" + ','.join([ i["solarSystemName"] + "(" + str(i["kills"]) + "次)" for i in ret["topLists"][4]["values"][:3] ]), style_str=MDStyleStr( color=settings["cltopSolarSystem"], font_size=settings["labelFontSize"]))] } }) history.update({ret["info"]["name"]: {"characterID": ID}}) SaveFile(history, settings["workingDir"] + "history.json") #getKMList url = r"https://zkillboard.com/api/kills/characterID/" + str(ID) + r"/" try: with rq.get(url, timeout=5) as ret: ret = loads(ret.content) except Exception as e: log("getKMList:" + str(e), level="error") Msg.update({"Error": "getKMListError"}) MutSearchName.unlock() return Msg #玩家可能没有击杀km if ret == []: Msg.update({"getKMList": []}) MutSearchName.unlock() return Msg km_count = min(settings["KMCounts"], len(ret)) killmail_pairs = [(ret[i]["killmail_id"], ret[i]["zkb"]["hash"]) for i in range(km_count)] remap = [] label_list = [ TMsgEntry(str(i + 1) + ".最近km(" + Valuable(ret[i]["zkb"]["totalValue"]) + ' isk)', style_str=MDStyleStr(color=settings["clKM"], font_size=settings["labelFontSize"]), ClickEvent=SearchKM, ClickArgs=(ID, killmail_pairs[i][0], killmail_pairs[i][1])) for i in range(len(killmail_pairs)) ] for i in killmail_pairs: remap.append([i, label_list[0], {}]) label_list = label_list[1:] Msg.update({"getKMList": remap}) log("getKMList:完成") MutSearchName.unlock() return Msg
def SearchKM(character_id: int, killmail_id: int = 0, killmail_hash: str = ''): """ 获取一个特定的km character_id(int):角色id killmail_id(int):该killmail的id killmail_hash(str):由ccp给出的km哈希值 """ global MutSearchKM MutSearchKM.lock() Msg = {} log("SearchKM:character_id={character_id},killmail_id={killmail_id},killmail_hash={killmail_hash}" .format(character_id=character_id, killmail_id=killmail_id, killmail_hash=killmail_hash)) url = r"https://esi.evetech.net/latest/killmails/"\ + str(killmail_id)\ + r"/" + killmail_hash + r"/?datasource=tranquility" try: with rq.get(url, timeout=5) as ret: ret = loads(ret.content) except Exception as e: log("SearchKM:" + str(e), level="error") Msg.update({"Error": "SearchKMError"}) MutSearchKM.unlock() return -1 Msg = { "SearchKM": { "time": [ ret["killmail_time"].replace('T', ' ').replace('Z', ''), TMsgEntry( " (" + ret["killmail_time"].replace('T', ' ').replace( 'Z', '' + ")"), style_str=MDStyleStr(color=settings["clHint"], font_size=settings["labelFontSize"])) ], "victimShip": [ ret["victim"]["ship_type_id"], TMsgEntry( r" <a href='https://zkillboard.com/kill/" + str(killmail_id) + r"/' style='color:blue'>击毁:" + getNamebyID(ret["victim"]["ship_type_id"]) + r"</a>", style_str=MDStyleStr(color=settings["clURL"], font_size=settings["labelFontSize"])) ] } } for i in ret["attackers"]: if ("character_id" in i) and (i["character_id"] == character_id): ship = getNamebyID( i["ship_type_id"]) if "ship_type_id" in i else "(?)" weapon = getNamebyID( i["weapon_type_id"]) if "weapon_type_id" in i else "(?)" if ship == weapon: weapon = "(混合)" Msg["SearchKM"].update({ "shipType": [ ship, TMsgEntry(" · " + ship, style_str=MDStyleStr( color=settings["clshipType"], font_size=settings["labelFontSize"])) ], "weaponType": [ weapon, TMsgEntry(" · " + weapon, style_str=MDStyleStr( color=settings["clweaponType"], font_size=settings["labelFontSize"])) ] }) break log("SearchKM:完成") MutSearchKM.unlock() return Msg