import json import html import re import hashlib import asyncio import time from datetime import datetime from typing import TYPE_CHECKING, Dict, Any, Optional, List, Union from inspect import isawaitable from typing import Any, Awaitable, Callable, Dict, Optional from astrbot.api import logger from astrbot.api import AstrBotConfig import astrbot.api.message_components as Comp from .request import APIClient, APIErrorResponse from .sqlite import AsyncSQLiteDB from .fun_basic import load_template,gold_to_parts,week_to_num,compare_date_str,format_time,format_remaining if TYPE_CHECKING: from .cache import CacheService ROLE_RANK_NAMES = { "名士五十强", "老江湖五十强", "兵甲藏家五十强", "名师五十强", "阵营英雄五十强", "薪火相传五十强", "庐园广记一百强", } TONG_RANK_NAMES0 = { "赛季恶人五十强", "赛季浩气五十强", "本周恶人五十强", "本周浩气五十强", } TONG_RANK_NAMES1 = { "浩气神兵宝甲五十强", "恶人神兵宝甲五十强", "浩气爱心帮会五十强", "恶人爱心帮会五十强", } TONG_RANK_NAMES2 = { "上周恶人五十强", "上周浩气五十强", } GUILD_RANK_OPTIONS = { "1": "浩气神兵宝甲五十强", "2": "恶人神兵宝甲五十强", "3": "浩气爱心帮会五十强", "4": "恶人爱心帮会五十强", } CAMP_RANK_OPTIONS = { "1": "赛季恶人五十强", "2": "赛季浩气五十强", "3": "上周恶人五十强", "4": "上周浩气五十强", "5": "本周恶人五十强", "6": "本周浩气五十强", } OTHER_RANK_OPTIONS = { "1": "名士五十强", "2": "老江湖五十强", "3": "兵甲藏家五十强", "4": "名师五十强", "5": "阵营英雄五十强", "6": "薪火相传五十强", "7": "庐园广记一百强", } RANK_NAMES = frozenset().union( ROLE_RANK_NAMES, TONG_RANK_NAMES0, TONG_RANK_NAMES1, TONG_RANK_NAMES2, ) class JX3APIService: def __init__( self, config: AstrBotConfig, sqlite: AsyncSQLiteDB, cache: Optional["CacheService"] = None, ): # 实例化 API Client self._api: APIClient = APIClient() # 引用插件配置文件 self._config = config # 引用sqlite self._sql_db = sqlite self._cache = cache self._token_stats_cache: tuple[float, Dict[str, Any]] | None = None self._token_stats_lock = asyncio.Lock() # 获取配置中的 Token self.token = self._config.get("jx3api_token", "") if self.token == "": logger.warning("获取配置token失败,请正确填写token,否则部分功能无法正常使用") else: logger.debug(f"获取配置token成功。") # 获取配置中的 ticket self.ticket = self._config.get("jx3api_ticket", "") if self.ticket == "": logger.warning("获取配置ticket失败,请正确填写ticket,否则部分功能无法正常使用") else: logger.debug(f"获取配置ticket成功。") async def close(self): """释放底层 APIClient 资源""" if self._api: await self._api.close() async def server_list(self, force_refresh: bool = False) -> list[str]: """获取当前有效区服名称,供会话绑定和参数消歧使用。""" data, _ = await self._cached_request( "/server/status/check", {"server": "", "type": "其他"}, force_refresh=force_refresh, ) if not isinstance(data, list): return [] return sorted( { str(item.get("server") or "").strip() for item in data if isinstance(item, dict) and item.get("server") } ) async def token_stats(self) -> Optional[Dict[str, Any]]: """读取令牌统计;短时内存复用,避免 WebUI 保存配置时重复请求。""" if not str(self.token or "").strip(): return None now = time.monotonic() if self._token_stats_cache and self._token_stats_cache[0] > now: return dict(self._token_stats_cache[1]) async with self._token_stats_lock: now = time.monotonic() if self._token_stats_cache and self._token_stats_cache[0] > now: return dict(self._token_stats_cache[1]) result = await self._fetch_token_stats() if result is not None: self._token_stats_cache = (now + 30, dict(result)) return result async def _fetch_token_stats(self) -> Optional[Dict[str, Any]]: """查询当前配置 JX3API Token 的等级、用量及有效状态。""" if not str(self.token or "").strip(): return None async def requester(): return await self._api.post( "https://www.jx3api.com/token/stats", data={"token": self.token}, out_key="data", success_codes=(200, "200"), return_error=True, ) try: data = await requester() except Exception as exc: logger.warning(f"查询 JX3API Token 统计失败: {exc}") return None if isinstance(data, APIErrorResponse): logger.warning( f"JX3API Token 统计返回错误: " f"code={data.code}, msg={data.message or '未知错误'}" ) return None if not isinstance(data, dict): return None def nonnegative_int(value: Any) -> Optional[int]: if isinstance(value, bool): return None try: number = int(value) except (TypeError, ValueError): return None return number if number >= 0 else None valid = data.get("valid") return { "level": nonnegative_int(data.get("level")), "used": nonnegative_int(data.get("used")), "remaining": nonnegative_int(data.get("remaining")), "valid": valid if isinstance(valid, bool) else None, } def _init_return_data(self) -> Dict[str, Any]: """初始化标准的返回数据结构""" return { "code": 0, "msg": "功能函数未执行", "data": {}, "temp": "", "icons": {} } async def _base_request( self, api_path: str, params: Optional[Dict[str, Any]] = None, out: Optional[str] = "data" ) -> Optional[Any]: """ 基础请求封装,处理配置获取和API调用。 """ try: if not self._api: logger.error("API client is not initialized") return None base_url = "https://www.jx3api.com" api_url = base_url + api_path data = await self._api.get( api_url, params=params, out_key=out, success_codes=(200, "200"), return_error=True, ) if not data: logger.warning(f"获取接口信息失败或返回空数据: {api_url}") return data except Exception as e: logger.error(f"基础请求调用出错 ({api_path}): {e}") return None @staticmethod def _is_cacheable_response(data: Any) -> bool: return data is not None and not isinstance(data, APIErrorResponse) async def _cached_request( self, api_path: str, params: Optional[Dict[str, Any]] = None, out: Optional[str] = "data", force_refresh: bool = False, ) -> tuple[Any, dict[str, Any]]: request_params = params or {} if not self._cache: return await self._base_request(api_path, request_params, out), { "endpoint": api_path, "hit": False, "stale": False, "ttl_seconds": 0, } cache_params = dict(request_params) credential_values = [ str(value) for key, value in request_params.items() if str(key).lower() in {"token", "ticket"} and value ] if credential_values: cache_params["__credential_scope"] = hashlib.sha256( "|".join(credential_values).encode("utf-8") ).hexdigest() try: return await self._cache.request_api( api_path, cache_params, lambda: self._base_request(api_path, request_params, out), self._is_cacheable_response, force_refresh=force_refresh, ) except Exception as exc: logger.warning(f"接口缓存不可用,直接请求 JX3API endpoint={api_path}: {exc}") return await self._base_request(api_path, request_params, out), { "endpoint": api_path, "hit": False, "stale": False, "ttl_seconds": 0, } async def _request_api( self, path: str, params: Dict[str, Any], processor: Optional[ Callable[[Any, Dict[str, Any]], Any | Awaitable[Any]] ] = None, template: Optional[str] = None, ) -> Dict[str, Any]: """通用接口请求与模板处理。""" return_data = self._init_return_data() data, cache_metadata = await self._cached_request(path, params) return_data["_cache"] = cache_metadata if isinstance(data, APIErrorResponse): return_data["msg"] = data.message or "获取接口信息失败" return return_data if data is None: return_data["msg"] = "获取接口信息失败" return return_data try: await processor(data, return_data) except Exception as e: logger.exception(f"数据处理时出错: {e}") return_data["msg"] = "处理接口返回信息时出错" return return_data # template 为空时不加载模板 if template: try: return_data["temp"] = await load_template(template) except FileNotFoundError as e: logger.error(f"加载模板失败: {e}") return_data["msg"] = "系统错误:模板文件不存在" return return_data return_data["code"] = 200 return return_data # --- 业务功能函数 --- async def helps(self) -> Dict[str, Any]: """帮助""" return_data = self._init_return_data() # 加载模板 try: return_data["temp"] = await load_template("helps.html") except FileNotFoundError as e: logger.error(f"加载模板失败: {e}") return_data["msg"] = "系统错误:模板文件不存在" return return_data return_data["code"] = 200 return return_data async def richang(self, mode: str, num: int) -> Dict[str, Any]: """活动日历""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: if mode == "list": today = data.get("today") or {} total = data.get("total") or [] items = [ { "en": False, "compare": "", "date": "", "war": "", "battle": "", } for _ in range(week_to_num(today.get("week", "")) or 0) ] items.extend( { "en": True, "compare": compare_date_str(item.get("date", "")), "date": item.get("date", ""), "war": item.get("war", ""), "battle": item.get("battle", ""), } for item in total if isinstance(item, dict) ) return_data["data"]["items"] = items return_data["data"]["today"] = today return weekly = data.get("weekly") or {} return_data["data"] = ( f"{data.get('date', '')} 星期{data.get('week', '')}\n" f"大战:{data.get('war', '')}\n" f"战场:{data.get('battle', '')}\n" f"阵营:{data.get('orecar', '')}\n" f"宗门:{data.get('school', '')}\n" f"驰援:{data.get('rescue', '')}\n" f"【宠物福缘】\n{', '.join(data.get('lucky') or [])}\n" f"【家园声望·加倍道具】\n{', '.join(data.get('card') or [])}\n" f"【武林通鉴·公共任务】\n{', '.join(weekly.get('conn') or [])}\n" f"【武林通鉴·团队秘境】\n{', '.join(weekly.get('raid') or [])}\n" ) return await self._request_api( path="/active/calendar", params={"mode": mode, "num": num}, processor=processor, template="richangyuche.html" if mode == "list" else None, ) async def xingxiashijian(self,name: str) -> Dict[str, Any]: """地图活动""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["items"] = data return_data["data"]["name"] = name return await self._request_api( path="/active/celebs", params={ "name": name}, processor=processor, template="xingxiashijian.html" ) async def guanaishouling(self) -> Dict[str, Any]: """关隘首领""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: groups = [ { "server": group.get("server", ""), "records": [ { "camp_name": item.get("campName", ""), "castle": item.get("castle", ""), "str_status": item.get("statusText", ""), "start_time": format_time(item.get("startTime")), "end_time": format_time(item.get("endTime")), "remaining_time": format_remaining(item.get("endTime")), } for item in group.get("data", []) if isinstance(item, dict) ], } for group in data if isinstance(group, dict) and group.get("data") ] groups = [group for group in groups if group["records"]] if not groups: return_data["msg"] = "未查询到关隘首领信息" return return_data return_data["data"] = { "groups": groups, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/castle/status", params={"token": self.token}, processor=processor, template="guanaishouling.html" ) async def benrichitu(self) -> Dict[str, Any]: """本日赤兔""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: if not data or not isinstance(data, list): return_data["data"] = "今日赤兔 暂无数据" return result_lines = ["今日赤兔"] for item in data: result_lines.extend([ f"时间:{item['date']}", f"区服:{item['server']}", f"地图:{item['mapName']}", ]) return_data["data"] = "\n".join(result_lines).rstrip() return await self._request_api( path="/chitu/records", params={"token": self.token}, processor=processor, template="" ) async def benzhouchitu(self) -> Dict[str, Any]: """本周赤兔""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: if not data or not isinstance(data, list): return_data["data"] = "本周赤兔 暂无数据" return result_lines = ["本周赤兔"] for item in data: result_lines.extend([ f"时间:{item['date']}", f"区服:{item['server']}", f"地图:{item['mapName']}", ]) return_data["data"] = "\n".join(result_lines).rstrip() return await self._request_api( path="/chitu/week/records", params={"token": self.token}, processor=processor, template="" ) async def zhenyingevent(self,name: str,limit: str) -> Dict[str, Any]: """阵营事件""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["seizeTime"] = format_time(item.get("seizeTime")) return_data["data"] = { "items": data, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/fenxian/records", params={"token": self.token,"name": name, "limit": limit}, processor=processor, template="zhenyingevent.html" ) async def yanhuachaxun(self, server: str, name: str, limit: int) -> Dict[str, Any]: """烟花记录""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: data = data[:limit] for item in data: item["time"] = format_time(item.get("time")) return_data["data"]["list"] = data return await self._request_api( path="/firework/records", params={"token": self.token,"name": name, "server": server}, processor=processor, template="yanhuan.html" ) async def shuma(self,server:str) -> Dict[str, Any]: """刷马""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = ( f"【阴山大草原】\n{', '.join(data.get('阴山大草原') or [])}\n" f"【鲲鹏岛】\n{', '.join(data.get('鲲鹏岛') or [])}\n" f"【黑戈壁】\n{', '.join(data.get('黑戈壁') or [])}\n" ) return await self._request_api( path="/ranch/chat", params={"token": self.token, "server": server}, processor=processor, template="" ) async def machang(self, server: str, expired: int) -> Dict[str, Any]: """马场""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: data0 = data.get("data") return_data["data"] = ( f"【区服】:{data.get('server')}\n" f"【阴山大草原】\n{', '.join(data0.get('阴山大草原') or [])}\n" f"【鲲鹏岛】\n{', '.join(data0.get('鲲鹏岛') or [])}\n" f"【黑戈壁】\n{', '.join(data0.get('黑戈壁') or [])}\n" f"【龙泉府 / 进图(21:10)】\n{', '.join(data0.get('龙泉府 / 进图(21:10)') or [])}\n" f"\n{data.get('note')}\n" ) return await self._request_api( path="/ranch/records", params={"token": self.token, "server": server, "expired": expired}, processor=processor, template="" ) async def zhanji(self, name: str, server:str, mode:str) -> Dict[str, Any]: """战绩""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: performance_key = { "22": "2v2", "33": "3v3", "55": "5v5", }.get(str(mode), "3v3") data["currentPerformance"] = data["performance"][performance_key] return_data["data"] = data return await self._request_api( path="/arena/recent", params={"server": server, "name":name, "mode":mode, "token": self.token, "ticket": self.ticket}, processor=processor, template="zhanji.html" ) async def mingjianpaihang(self, limit: str, mode:str) -> Dict[str, Any]: """名剑排行""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["lists"] = data return await self._request_api( path="/arena/awesome", params={"limit": limit, "mode":mode, "token": self.token, "ticket": self.ticket}, processor=processor, template="mingjianpaihang.html" ) async def mingjiantongji(self, mode: str) -> Dict[str, Any]: """名剑统计""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = { "items": data, "mode": mode, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/arena/schools", params={"mode": mode, "token": self.token, "ticket": self.ticket}, processor=processor, template="mingjiantongji.html" ) async def kuafumingjian(self, server: str, mode: int = 1) -> Dict[str, Any]: """跨服名剑榜。""" mode_names = {0: "2v2", 1: "3v3", 2: "5v5"} async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data") or [] if not isinstance(items, list): items = [] return_data["data"] = { "items": [item for item in items if isinstance(item, dict)], "name": data.get("name") or "跨服名剑榜", "server": data.get("server") or server or "全区", "mode_name": mode_names[mode], "update_time": format_time(data.get("time")), } return await self._request_api( path="/rank/arena", params={"server": server, "mode": mode, "token": self.token}, processor=processor, template="kuafumingjian.html", ) async def wulinzhengba(self, server: str, camp: int = 1) -> Dict[str, Any]: """武林争霸赛帮会榜。""" camp_names = {1: "浩气盟", 2: "恶人谷"} def format_match_time(value: Any) -> str: try: total_seconds = int(value) except (TypeError, ValueError): return "" if total_seconds < 0: return "" hours, remainder = divmod(total_seconds, 3600) minutes, seconds = divmod(remainder, 60) if hours: return f"{hours}时{minutes:02d}分{seconds:02d}秒" return f"{minutes}分{seconds:02d}秒" async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data") or [] if not isinstance(items, list): items = [] rank_items = [] for item in items: if not isinstance(item, dict): continue rank_item = item.copy() rank_item["lastMatchTimeText"] = format_match_time( item.get("lastMatchTime") ) rank_items.append(rank_item) return_data["data"] = { "items": rank_items, "name": data.get("name") or "武林争霸赛", "server": data.get("server") or server or "全区", "camp_name": camp_names[camp], "update_time": format_time(data.get("time")), } return await self._request_api( path="/rank/championship", params={"server": server, "camp": camp, "token": self.token}, processor=processor, template="wulinzhengba.html", ) async def _bounty_rank(self,server: str,path: str,fallback_name: str,show_hostile_count: bool,) -> Dict[str, Any]: """处理捕快荣誉和江湖浪客共用的榜单结构。""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data") or [] if not isinstance(items, list): items = [] return_data["data"] = { "items": [item for item in items if isinstance(item, dict)], "name": data.get("name") or fallback_name, "server": data.get("server") or server or "全区", "show_hostile_count": show_hostile_count, "update_time": format_time(data.get("time")), } return await self._request_api( path=path, params={"server": server, "token": self.token}, processor=processor, template="bounty_rank.html", ) async def bukairongyu(self, server: str) -> Dict[str, Any]: """捕快荣誉榜。""" return await self._bounty_rank( server=server, path="/rank/constable", fallback_name="捕快荣誉榜", show_hostile_count=False, ) async def jianghulangke(self, server: str) -> Dict[str, Any]: """江湖浪客榜。""" return await self._bounty_rank( server=server, path="/rank/outlaw", fallback_name="江湖浪客榜", show_hostile_count=True, ) async def juedoutiaozhan(self,server: str,mode: int = 1,) -> Dict[str, Any]: """决斗挑战榜。""" mode_names = {1: "公开", 2: "私密"} async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data") or [] if not isinstance(items, list): items = [] now_timestamp = int(datetime.now().timestamp()) rank_items = [] for item in items: if not isinstance(item, dict): continue rank_item = item.copy() try: timeout = int(item.get("timeOut")) except (TypeError, ValueError): remaining_time = "" else: remaining_time = ( format_remaining(timeout) if timeout > now_timestamp else "已结束" ) rank_item["remainingTime"] = remaining_time rank_items.append(rank_item) return_data["data"] = { "items": rank_items, "name": data.get("name") or "决斗挑战榜", "server": data.get("server") or server or "全区", "mode_name": mode_names[mode], "update_time": format_time(data.get("time")), } return await self._request_api( path="/rank/wanted", params={"server": server, "mode": mode, "token": self.token}, processor=processor, template="juedoutiaozhan.html", ) async def banghui_rank_menu(self) -> Dict[str, str]: """帮会排行榜选择内容。""" return GUILD_RANK_OPTIONS.copy() async def zhenying_rank_menu(self) -> Dict[str, str]: """阵营排行榜选择内容。""" return CAMP_RANK_OPTIONS.copy() async def qita_rank_menu(self) -> Dict[str, str]: """其他排行榜选择内容。""" return OTHER_RANK_OPTIONS.copy() async def rank_statistical_select(self, server: str, selected: Dict[str, Any],) -> Dict[str, Any]: """排行榜次轮:根据单项选择数据查询对应榜单。""" if not isinstance(selected, dict) or len(selected) != 1: return_data = self._init_return_data() return_data["msg"] = "排行榜选项数据格式异常" return return_data rank_name = str(next(iter(selected.values())) or "").strip() if rank_name not in RANK_NAMES: return_data = self._init_return_data() return_data["msg"] = "无效排行榜选项" return return_data return await self.rank_statistical(rank_name, server) async def rank_statistical(self, name: str, server: str) -> Dict[str, Any]: """排行榜单""" if name in ROLE_RANK_NAMES: template_name = "rank_role.html" elif name in TONG_RANK_NAMES0: template_name = "rank_tong0.html" elif name in TONG_RANK_NAMES1: template_name = "rank_tong1.html" elif name in TONG_RANK_NAMES2: template_name = "rank_tong2.html" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data") or [] if isinstance(items, list): items = items[:50] else: items = [] return_data["data"] = { "items": items, "server": data.get("server", server), "rank_name": data.get("name", name), "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/rank/statistics", params={"server": server, "name": name, "token": self.token}, processor=processor, template=template_name ) async def shilianpaixing(self, name: str, server: str) -> Dict[str, Any]: """试炼排行""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data", []) return_data["data"] = { "items": items, "name": data.get("name", name), "server": data.get("server", server), "update_time": format_time(data.get("time")) } return await self._request_api( path="/rank/trials", params={"server": server,"name": name,"token": self.token,}, processor=processor, template="shilianpaixing.html" ) async def zhengyingpaimai(self, server: str, name: str, limit: int) -> Dict[str, Any]: """阵营拍卖""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["time"] = format_time(item["time"]) return_data["data"]["list"] = data return await self._request_api( path="/auction/records", params={"server": server, "name": name, "limit": limit, "token": self.token}, processor=processor, template="zhengyingpaimai.html" ) async def dilujilu(self, server: str) -> Dict[str, Any]: """的卢拍卖""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["refreshTime"] = format_time(item["refreshTime"]) item["captureTime"] = format_time(item["captureTime"]) item["auctionTime"] = format_time(item["auctionTime"]) return_data["data"]["list"] = data return await self._request_api( path="/steed/records", params={"server": server, "token": self.token}, processor=processor, template="dilujilu.html" ) async def jinjia(self, server: str, limit:str) -> Dict[str, Any]: """金价行情""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["items"] = data return await self._request_api( path="/trade/demon", params={"server": server, "limit": limit, "token": self.token}, processor=processor, template="jinjia.html" ) async def wujia(self, Name: str, server:str) -> Dict[str, Any]: """物价查询""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data return await self._request_api( path="/trade/records", params={"name": Name,"token": self.token, "server": server}, processor=processor, template="wujia.html" ) async def chengbeng(self, Name: str, server:str, source: int) -> Dict[str, Any]: """成本计算""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data return await self._request_api( path="/trade/manufacture", params={"name": Name,"token": self.token, "server": server, "source": source}, processor=processor, template="chengbeng.html" ) async def bianhao(self, id: str) -> Dict[str, Any]: """编号搜索""" # 数据处理 async def processor(data: Any, return_data: Dict[str, Any]) -> None: if not isinstance(data, dict): return_data["data"] = "账号角色数据格式错误" return # 同时兼容完整接口数据和直接传入 data 字段 data = data.get("data", data) if not isinstance(data, dict): return_data["data"] = "账号角色数据为空" return # 将 replyContent 中的 HTML 转换为纯文本 detail = str(data.get("replyContent") or "") detail = re.sub(r"", "\n", detail, flags=re.IGNORECASE) detail = re.sub(r"<[^>]+>", "", detail) detail = html.unescape(detail).strip() or "暂无账号详细信息" # 交易状态 trade_status = { 1: "公示中", 2: "出售中", 3: "出售中", 4: "已售出", 5: "已下架", }.get(data.get("tradeStatus"), f"状态码 {data.get('tradeStatus', '未知')}") # 调价记录,接口中的时间为毫秒时间戳 update_prices = data.get("updatePrices") or [] update_price_text = "\n".join( f"{index}. {format_time(int(item.get('updateTime') or 0) // 1000)}:" f"{item.get('updatePrice', 0)} 元" for index, item in enumerate(update_prices, start=1) if isinstance(item, dict) ) or "暂无调价记录" return_data["data"] = ( f"【万宝楼账号】\n" f"{data.get('replyTitle') or '暂无标题'}\n\n" f"【角色信息】\n" f"区服:{data.get('serverName') or '未知'}\n" f"角色:{data.get('roleName') or '未知'}\n" f"等级:{data.get('roleLevel') or 0}\n" f"门派:{data.get('forceName') or '未知'}\n" f"体型:{data.get('bodyName') or '未知'}\n" f"阵营:{data.get('campName') or '未知'}\n\n" f"【账号数据】\n" f"装备分数:{data.get('equipScore') or 0}\n" f"江湖资历:{data.get('seniorityNum') or 0}\n" f"约见次数:{data.get('meetingNum') or 0}\n" f"关注人数:{data.get('followNum') or 0}\n\n" f"【交易信息】\n" f"挂牌价格:{data.get('priceNum') or 0} 元\n" f"交易状态:{trade_status}\n" f"商品编号:{data.get('id') or '未知'}\n" f"发布时间:{format_time(data.get('replyTime') or 0)}\n\n" f"【调价记录】\n" f"{update_price_text}\n\n" f"【账号详情】\n" f"{detail}" ) return await self._request_api( path="/trade/wanbaolou", params={"id": id,"token": self.token}, processor=processor, template="" ) async def bangzhanjilu(self, server: str) -> Dict[str, Any]: """帮战记录""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["startTime"] = format_time(item["startTime"]) item["durationSeconds"] = format_remaining(item["durationSeconds"]) item["endTime"] = format_time(item["endTime"]) return_data["data"] = { "items": data, "server": server, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } return await self._request_api( path="/battle/records", params={"server": server}, processor=processor, template="bangzhanjilu.html" ) async def shapan(self, server: str) -> Dict[str, Any]: """阵营沙盘。""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: if not isinstance(data, dict): raise ValueError("沙盘接口返回的数据结构无效") records = data.get("data") if not isinstance(records, list) or not records: raise ValueError("沙盘接口未返回据点数据") items = [] for record in records: if not isinstance(record, dict): continue camp_id = record.get("campId") if camp_id not in (1, 2): continue castle_name = str(record.get("castleName") or "").strip() if not castle_name: continue items.append( { "castle_name": castle_name, "camp_key": "浩" if camp_id == 1 else "恶", "camp_name": str(record.get("campName") or ""), "tong_name": str(record.get("tongName") or ""), "master_name": str(record.get("masterName") or ""), "ride_piece": int(record.get("ridePiece") or 0), "defend_count": int(record.get("defendCount") or 0), } ) if not items: raise ValueError("沙盘接口未返回有效据点") update_time = format_time(data.get("update")) return_data["data"] = { "zone": str(data.get("zone") or ""), "server": str(data.get("server") or server), "reset": int(data.get("reset") or 0), "update_time": update_time, "items": items, } return await self._request_api( path="/sand/records", params={"server": server, "token": self.token}, processor=processor, template="shapan.html", ) async def zhueevent(self,server: str,limit: str) -> Dict[str, Any]: """诛恶事件""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["time"] = format_time(item["time"]) return_data["data"] = { "items": data, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/wicked/records", params={"token": self.token, "server": server, "limit": limit}, processor=processor, template="zhueevent.html" ) async def jueshemingpian(self, server: str, name: str) -> Dict[str, Any]: """名片缓存""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: url = data.get("showAvatar") if not url: return_data["msg"] = "未获取到名片图片" return return_data server_name = data.get("serverName", server) role_name = data.get("roleName", name) show_like = data.get("showLike", 0) msg0 = f"{server_name}-{role_name}" msg1 = f"点赞:{show_like}" return_data["data"] = [ Comp.Plain(msg0), Comp.Image.fromURL(url), Comp.Plain(msg1) ] return await self._request_api( path="/card/cached", params={"server": server, "name": name, "token": self.token}, processor=processor, template="" ) async def shuijimingpian(self, server:str, force: str, body:str,) -> Dict[str, Any]: """随机名片""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: url = data.get("showAvatar") if not url: return_data["msg"] = "未获取到名片图片" return return_data server_name = data.get("serverName") role_name = data.get("roleName") msg = f"{server_name}-{role_name}" return_data["data"] = [ Comp.Plain(msg), Comp.Image.fromURL(url), ] return await self._request_api( path="/card/random", params={"server": server, "body": body, "force":force, "token": self.token}, processor=processor, template="" ) async def shuoyoumingpian(self, server: str, name: str) -> Dict[str, Any]: """名片历史""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: chain = [] for m in data: status = "当前展示" if m.get("showActive") else "未展示" msg = f"第{m.get('showIndex')}张 {status}" url = m.get("showAvatar") if not url: logger.warning(f"第{m.get('showIndex')}张名片缺少图片URL,已跳过") continue chain.extend([ Comp.Plain(msg), Comp.Image.fromURL(url), ]) if not chain: return_data["msg"] = "未获取到有效的名片数据" return return_data return_data["data"] = chain return await self._request_api( path="/card/records", params={"server": server, "name": name, "token": self.token}, processor=processor, template="" ) async def qiyuhuizong(self, server: str, num: int) -> Dict[str, Any]: """奇遇汇总""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: latest = item.get("last") item["latest_name"] = latest.get("name") item["latest_time"] = format_time(latest.get("time")) return_data["data"] = { "items": data, "server": server, "num": num, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/event/collect", params={"server": server, "num": num, "token": self.token}, processor=processor, template="qiyuhuizong.html" ) async def weizuoqiyu(self, server: str, name: str, ) -> Dict[str, Any]: """未出奇遇""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["ptqy"] = [] return_data["data"]["jsqy"] = [] return_data["data"]["name"] = name return_data["data"]["server"] = server for item in data: try: level = int(item.get("level", 0)) except (TypeError, ValueError): continue event_item = { "event": item.get("name"), "time": "未触发" } if level == 1: return_data["data"]["ptqy"].append(event_item) elif level == 2: return_data["data"]["jsqy"].append(event_item) if not return_data["data"]["ptqy"] and not return_data["data"]["jsqy"]: return_data["msg"] = "未查询到未做普通或绝世奇遇" return return_data return await self._request_api( path="/event/missing", params={"server": server, "name": name, "token": self.token}, processor=processor, template="weizuoqiyu.html" ) async def jinqiqiyu(self, server: str, limit: int) -> Dict[str, Any]: """近期奇遇""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["time"] = format_time(item.get("time")) return_data["data"] = { "items": data, "server": server, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/event/recent", params={"server": server, "limit": limit, "token": self.token}, processor=processor, template="jinqiqiyu.html" ) async def juesheqiyu(self, server: str, name: str, full: int) -> Dict[str, Any]: """角色奇遇""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["ptqy"] = [] return_data["data"]["jsqy"] = [] return_data["data"]["cwqy"] = [] for item in data: item["time"] = datetime.fromtimestamp(item["time"]).strftime("%Y-%m-%d %H:%M:%S") if item["level"] == 1: return_data["data"]["ptqy"].append(item) if item["level"] == 2: return_data["data"]["jsqy"].append(item) if item["level"] == 3: return_data["data"]["cwqy"].append(item) return await self._request_api( path="/event/records", params= {"server": server, "name": name, "full": full, "token": self.token}, processor=processor, template="juesheqiyu.html" ) async def qiyutongji(self, name: str, server: str, limit: int) -> Dict[str, Any]: """奇遇统计""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["time"] = format_time(item.get("time")) return_data["data"] = { "items": data, "server": server, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "qiyuname": name } return await self._request_api( path="/event/statistics", params={"name": name, "server": server, "limit": limit, "token": self.token}, processor=processor, template="qiyuliebiao.html" ) async def jingnai(self, name: str, server: str) -> Dict[str, Any]: """角色百战""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("skillList", []) if not isinstance(items, list) or not items: return_data["msg"] = "未查询到技能信息" return return_data color_map = { 7: "黑色", 6: "紫色", 5: "红色", 4: "绿色", 3: "蓝色", 2: "黄色", 0: "无", } for item in items: if not isinstance(item, dict): continue color = item.get("nColor") try: color_key = int(color) except (TypeError, ValueError): color_key = None item["skill_color_text"] = color_map.get(color_key, str(color) if color is not None else "") return_data["data"] = { "server": data.get("server", server), "role_name": data.get("roleName", name), "skill_energy": data.get("skillEnergy", ""), "skill_stamina": data.get("skillStamina", ""), "skill_count": data.get("skillCount", len(items)), "items": items, "update_time": format_time( data.get("updateTime")) } return await self._request_api( path="/monster/records", params={"server": server, "name": name, "token": self.token}, processor=processor, template="jingnai.html" ) async def baizhan(self) -> Dict[str, Any]: """百战首领""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data return_data["data"]["start"] = format_time(data["start"]) return_data["data"]["end"] = format_time(data["end"]) return await self._request_api( path="/monster/weekly", params= { "token": self.token}, processor=processor, template="baizhan.html" ) async def chengjiuchaxun(self, server:str, role:str, name:str) -> Dict[str, Any]: """成就查询""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data return await self._request_api( path="/role/achievement", params= {"server": server, "role": role, "name": name, "token": self.token}, processor=processor, template="chengjiu.html" ) async def zili_menu(self) -> Dict[str, str]: """资历选择内容。""" return { "1": "总览", "2": "杂闻", "3": "武学", "4": "修为", "5": "装备", "6": "技艺", "7": "阅读", "8": "任务", "9": "足迹", "10": "战斗", "11": "声望", "12": "秘境", "13": "帮会", "14": "阵营", "15": "节日", "16": "活动", "17": "风雨江湖路", "18": "家园", "19": "剑侠录" } async def zili(self,server: str,name: str,selected: Dict[str, Any],) -> Dict[str, Any]: """资历分布""" if not isinstance(selected, dict) or len(selected) != 1: return_data = self._init_return_data() return_data["msg"] = "资历选项数据格式异常" return return_data selected_name = str(next(iter(selected.values())) or "").strip() selected_subclass = "" if selected_name == "总览" else selected_name async def processor(data: Any, return_data: Dict[str, Any]) -> None: statistics = data.get("data") or {} categories = statistics.get("total") or {} if not isinstance(categories, dict) or not categories: raise ValueError("接口未返回资历统计") # 查询总览时 total 为“大类 -> 小类 -> 统计”;指定 subclass 后, # JX3API 会去掉大类这一层,total 直接变成“小类 -> 统计”。 data["subclass"] = selected_subclass return_data["data"] = data return await self._request_api( path="/tuilan/achievement", params={"server": server,"name": name,"class": 1,"subclass": selected_subclass,"ticket": self.ticket,"token": self.token,}, processor=processor, template="zili.html", ) async def jueshe(self,server: str, name: str, history:int) -> Dict[str, Any]: """角色详情""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: role_history = data.get("roleHistory") or {} role_names = role_history.get("roleNames") or [] tong_names = role_history.get("TongNames") or [] # 角色名称历史 role_history_lines = [] for item in role_names: if not isinstance(item, dict): continue server = item.get("server") or "未知服务器" name = item.get("name") or "未知角色名" time_text = format_time(item.get("time", 0)) role_history_lines.append( f"{time_text} {server}·{name}" ) if role_history_lines: role_history_text = "\n".join(role_history_lines) else: role_history_text = "暂无角色历史记录" # 帮会历史 tong_history_lines = [] for item in tong_names: if not isinstance(item, dict): continue server = item.get("server") or "未知服务器" tong_name = item.get("name") or "无帮会" time_text = format_time(item.get("time", 0)) tong_history_lines.append( f"{time_text} {server}·{tong_name}" ) if tong_history_lines: tong_history_text = "\n".join(tong_history_lines) else: tong_history_text = "暂无帮会历史记录" return_data["data"] = ( f"服务器:{data.get('zoneName') or '未知'}·" f"{data.get('serverName') or '未知'}\n" f"名称:{data.get('roleName') or '未知'}\n" f"角色ID:{data.get('roleId') or '未知'}\n" f"推栏ID:{data.get('globalId') or '未知'}\n" f"职业:{data.get('forceName') or '未知'}·" f"{data.get('bodyName') or '未知'}\n" f"帮会:{data.get('tongName') or '无帮会'}\n" f"阵营:{data.get('campName') or '未知'}\n" f"\n" f"【角色历史】\n" f"{role_history_text}\n" f"\n" f"【帮会历史】\n" f"{tong_history_text}" ) return await self._request_api( path="/role/detail", params= {"server": server, "name": name, "history": history, "token": self.token}, processor=processor, template="" ) async def zhenyan(self, name: str) -> Dict[str, Any]: """阵眼""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data.get("data", []) if not isinstance(items, list) or not items: return_data["msg"] = "未查询到该心法阵眼信息" return return_data result_msg = f"{data.get('name', name)}-{data.get('skillName', '')}\n" for item in items: if not isinstance(item, dict): continue result_msg += f"{item.get('name', '')}:{item.get('desc', '')}\n" return_data["data"] = result_msg.rstrip() return await self._request_api( path="/school/matrix", params= {"name": name, "ticket": self.ticket, "token": self.token}, processor=processor, template="" ) async def zilipaixing(self,server: str, school: str) -> Dict[str, Any]: """资历排行""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = { "items": data, "school": school, "server": server, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/school/seniority", params= {"server": server,"school": school,"ticket": self.ticket,"token": self.token,}, processor=processor, template="zilipaixing.html" ) async def jineng(self, name: str,update:int) -> Dict[str, Any]: """技能""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: groups = [] for group in data: if not isinstance(group, dict): continue skills = group.get("data", []) if not isinstance(skills, list) or not skills: continue parsed_skills = [] for skill in skills: if not isinstance(skill, dict): continue parsed_skills.append({ "name": skill.get("name", ""), "icon": skill.get("icon", ""), "desc": skill.get("desc", ""), "interval": skill.get("interval", ""), "distance": skill.get("distance", ""), "release_type": skill.get("releaseType", ""), "weapon": skill.get("weapon", ""), }) if parsed_skills: groups.append({ "title": group.get("class", "其他技能"), "skills": parsed_skills, }) if not groups: return_data["msg"] = "未查询到该心法技能信息" return return_data return_data["data"] = { "name": name, "groups": groups, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/school/skills", params= {"name": name,"update": update, "ticket": self.ticket, "token": self.token}, processor=processor, template="jineng.html" ) async def qixue(self, name: str, update:int) -> Dict[str, Any]: """奇穴""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: level_titles = { 1: "主奇穴", 2: "第一重", 3: "第二重", 4: "第三重", 5: "第四重", 6: "第五重", 7: "第六重", 8: "混池", } groups = [] for group in data: if not isinstance(group, dict): continue level = group.get("level") try: level_key = int(level) except (TypeError, ValueError): level_key = 0 items = group.get("data", []) if not isinstance(items, list) or not items: continue parsed_items = [] for item in items: if not isinstance(item, dict): continue class_value = item.get("class") is_active = class_value == 1 or str(class_value) == "1" parsed_items.append({ "name": item.get("name", ""), "icon": item.get("icon", ""), "desc": item.get("desc", ""), "class_text": "主动" if is_active else "被动", "interval": item.get("interval", "") if is_active else "", }) if parsed_items: groups.append({ "level": level_key, "title": level_titles.get(level_key, f"第{level_key}组"), "talents": parsed_items, }) if not groups: return_data["msg"] = "未查询到该心法奇穴信息" return return_data groups.sort(key=lambda item: item["level"]) return_data["data"] = { "name": name, "groups": groups, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/school/talent", params= {"name": name,"update": update, "ticket": self.ticket, "token": self.token}, processor=processor, template="qixue.html" ) async def juesheliaotian(self, server:str, name: str, limit:int, page:int) -> Dict[str, Any]: """角色聊天""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: chat_list = data.get("list", []) for item in chat_list: item["time"] = format_time(item.get("time", 0)) return_data["data"] = data return await self._request_api( path="/chat/records", params= {"server": server,"name": name, "limit": limit, "page": page, "token": self.token}, processor=processor, template="juesheliaotian.html" ) async def tongzhanyy(self, server: str) -> Dict[str, Any]: """统战歪歪""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: lines = ["【统战歪歪】"] for group in data: group_server = group.get("server", "") channels = group.get("data", []) if len(lines) > 1: lines.append("") lines.append(f"服务器:{group_server}") for item in channels: if not isinstance(item, dict): continue short_id = item.get("esid") or item.get("asid", "") lines.extend([ f"阵营:{item.get('campName', '')}", f"频道ID:{item.get('sid', '')}", f"短位ID:{short_id}", f"在线人数:{item.get('users', '')}", f"频道名:{item.get('snick', '')}", "", ]) return_data["data"] = "\n".join(lines) return await self._request_api( path="/duowan/statistics", params= {"server": server}, processor=processor, template="" ) async def xiaoyao(self, name:str) -> Dict[str, Any]: """小吃小药""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: result = {} for item in data: k = item["kungfu"] color = item["color"] cls = item["class"] name = item["name"] if k not in result: result[k] = { "kungfu": k, "purple": {}, "blue": {} } if color == "紫": result[k]["purple"][cls] = name else: result[k]["blue"][cls] = name return_data["data"]["items"] = list(result.values()) return await self._request_api( path="/food/list", params= {"name": name}, processor=processor, template="xiaoyao.html" ) async def pianzhi(self, server:str, uid: str) -> Dict[str, Any]: """骗子查询""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: records = data["records"] if not records: result_msg = "未找到该用户行骗记录,很棒!继续保持!" else: result_msg = "" for record in records: result_msg += f"区服:{record['server']} 标签:{record['tieba']}\n\n" for item in record["data"]: result_msg += f"标题:{item['title']}\n" result_msg += f"地址:{item['url']}\n" result_msg += f"ID:{item['tid']}\n" result_msg += f"内容:{item['text']}\n" result_msg += ( f"时间:{datetime.fromtimestamp(item['time']).strftime('%Y-%m-%d %H:%M:%S')}\n\n" ) result_msg += "\n\n" return_data["data"] = result_msg return await self._request_api( path="/fraud/detail", params= {"server": server, "uid": uid, "token": self.token}, processor=processor, template="" ) async def huajia(self,server: str, name: str, map: str) -> Dict[str, Any]: """家园鲜花""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["data"] = data return_data["data"]["server"] = server return await self._request_api( path="/home/flower", params= {"server": server, "name": name, "map": map}, processor=processor, template="huajia.html" ) async def zhuangshi(self,name: str) -> Dict[str, Any]: """家园装饰""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["data"] = data return await self._request_api( path="/home/furniture", params= { "name": name}, processor=processor, template="zhuangshi.html" ) async def qiwu(self,name: str) -> Dict[str, Any]: """器物图谱""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["data"] = data return_data["data"]["name"] = name return await self._request_api( path="/home/travel", params= { "name": name}, processor=processor, template="qiwu.html" ) async def shitu(self, label: int, server: str, keyword: str, limit:int) -> Dict[str, Any]: """师徒招募""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: items = data if not items: return_data["msg"] = "未查询到师徒招募信息" return return_data title = "收徒信息" if label == 1 else "拜师信息" return_data["data"] = { "items": items, "server": server, "keyword": keyword, "type_value": label, "title": title, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/mentor/search", params= {"label": label, "server": server, "keyword": keyword, "limit": limit, "token": self.token}, processor=processor, template="shitu.html" ) async def weihu(self, limit:int) -> Dict[str, Any]: """维护公告""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: result = data[0] result_msg = "维护公告\n" # 仅展示前1条,避免消息过长 for i, item in enumerate(data[:limit], 1): result_msg += f"{i}. 【{item.get('type', '无类型')}】\n" result_msg += f"标题:{item.get('title', '未知时间')}\n" result_msg += f"时间:{item.get('date', '未知时间')}\n" result_msg += f"链接:{item.get('url', '无链接')}\n" return_data["data"] = result_msg return await self._request_api( path="/news/announce", params= {"limit": limit}, processor=processor, template="" ) async def xinwen(self, limit:int) -> Dict[str, Any]: """新闻资讯""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: result = data[0] result_msg = "新闻资讯\n" # 仅展示前1条,避免消息过长 for i, item in enumerate(data[:limit], 1): result_msg += f"{i}. 【{item.get('type', '无类型')}】\n" result_msg += f"标题:{item.get('title', '未知时间')}\n" result_msg += f"时间:{item.get('date', '未知时间')}\n" result_msg += f"链接:{item.get('url', '无链接')}\n" return_data["data"] = result_msg return await self._request_api( path="/news/records", params= {"limit": limit}, processor=processor, template="" ) async def tuanduizhaomu(self, server: str, label:int, keyword: str, limit:int) -> Dict[str, Any]: """团队招募""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["createTime"] = format_time(item["createTime"]) item["maxMemberCount"] = f"{item['currentMemberCount']}/{item['maxMemberCount']}" return_data["data"]["list"] = data return await self._request_api( path="/recruit/search", params= {"server": server, "label": label, "keyword": keyword, "limit": limit, "token": self.token}, processor=processor, template="tuanduizhaomu.html" ) async def daanzhishu(self) -> Dict[str, Any]: """答案之书""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = ( f"答案:{data.get('answer', '')}\n" f"鼓励:{data.get('hearten', '')}\n" ) return await self._request_api( path="/saohua/answer", params= {}, processor=processor, template="" ) async def tiangou(self) -> Dict[str, Any]: """舔狗日志""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data.get('text') return await self._request_api( path="/saohua/content", params= {}, processor=processor, template="" ) async def fengleiyulu(self, name:str) -> Dict[str, Any]: """分类语录""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data.get('content') return await self._request_api( path="/saohua/context", params= { "name": name, "token": self.token}, processor=processor, template="" ) async def heshengme(self) -> Dict[str, Any]: """喝什么""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = ( f"{', '.join(data or [])}\n" ) return await self._request_api( path="/saohua/drink", params= {}, processor=processor, template="" ) async def chishengme(self) -> Dict[str, Any]: """吃什么""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = ( f"{', '.join(data or [])}\n" ) return await self._request_api( path="/saohua/eat", params= {}, processor=processor, template="" ) async def shaohua(self) -> Dict[str, Any]: """随机骚话""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data.get('text') return await self._request_api( path="/saohua/random", params= {}, processor=processor, template="" ) async def zhananyulu(self) -> Dict[str, Any]: """渣男语录""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = data.get('text') return await self._request_api( path="/saohua/zhanan", params= {}, processor=processor, template="" ) async def keju(self,subject: str, limit: int) -> Dict[str, Any]: """科举""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: result_msg = "" for m in data: result_msg += f"{m['id']}.{m['question']}\n" result_msg += f"答案:{m['answer']}\n\n" return_data["data"] = result_msg return await self._request_api( path="/exam/search", params= {"subject": subject, "limit": limit}, processor=processor, template="" ) async def zhuangtai(self,server:str) -> Dict[str, Any]: """区服状态""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: server_wj = [] server_dx = [] server_sx = [] for itme in data: if itme['zone'] == "无界区": server_wj.append(itme) elif itme['zone'] == "电信区": server_dx.append(itme) elif itme['zone'] == "双线区": server_sx.append(itme) return_data["data"]["server_wj"] = server_wj return_data["data"]["server_dx"] = server_dx return_data["data"]["server_sx"] = server_sx return await self._request_api( path="/server/status/check", params= {"server": server, "type": "其他"}, processor=processor, template="qufuzhuangtai.html" ) async def kaifu(self, server: str) -> Dict[str, Any]: """开服状态查询""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: list_data = data[0] status = list_data.get("status") if status == 1: status_str = f"{server}服务器已开服,快冲,快冲!" status_bool = True else: status_str = f"{server}服务器当前维护中,等会再来吧!" status_bool = False return_data["status"] = status_bool return_data["data"] = status_str return await self._request_api( path="/server/status/check", params= {"server": server, "type": 1}, processor=processor, template="qufuzhuangtai.html" ) async def jigai(self) -> Dict[str, Any]: """技改记录""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: result_msg = "最近技改\n" for i, item in enumerate(data[:3], 1): result_msg += f"{i}. {item.get('title', '无标题')}\n" result_msg += f"时间:{item.get('time', '未知时间')}\n" result_msg += f"链接:{item.get('url', '无链接')}\n\n" return_data["data"] = result_msg return await self._request_api( path="/skill/rework", params= {}, processor=processor, template="" ) async def jiemi(self) -> Dict[str, Any]: """解密""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"] = "\n".join([ "解密", f"当前时间:{data.get('nowTime', '')}", f"当前节点:{data.get('nowNode', '')}", f"当前结果:{data.get('nowResult', '')}", f"下轮节点:{data.get('nextNode', '')}", f"下轮结果:{data.get('nextResult', '')}", f"剩余时间:{data.get('intervalTime', '')}", ]) return await self._request_api( path="/mech/decrypt", params= {"token": self.token}, processor=processor, template="" ) async def diaoluo(self, name: str, server: str, limit: int ) -> Dict[str, Any]: """物品掉落记录""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: for item in data: item["time"] = format_time(item.get("time")) return_data["data"] = { "items": data, "name": name, "limit": limit, "server": server, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return await self._request_api( path="/reward/statistics", params= {"server": server, "name": name, "limit": limit, "token": self.token}, processor=processor, template="diaoluo.html" ) async def tiebawujia(self, name: str, server: str, limit: int ) -> Dict[str, Any]: """贴吧物价""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: lines = [ f"贴吧物价:{name}", f"服务器:{server}", f"记录数:{len(data)}", "", ] for index, item in enumerate(data, start=1): if not isinstance(item, dict): continue item_time = item.get("time", "") if item_time: try: item_time = datetime.fromtimestamp(int(item_time)).strftime("%Y-%m-%d %H:%M:%S") except (TypeError, ValueError, OSError): item_time = str(item_time) lines.extend([ f"{index}. {item.get('name', '')}", f"区服:{item.get('zone', '')} 服务器:{item.get('server', '')}", f"内容:{item.get('context', '')}", f"回复:{item.get('reply', '')} 楼层:{item.get('floor', '')}", f"时间:{item_time}", f"链接:https://tieba.baidu.com/p/{item.get('url', '')}", "", ]) if len(lines) <= 4: return_data["msg"] = "未查询到贴吧物价记录" return return_data return_data["data"] = "\n".join(lines).rstrip() return await self._request_api( path="/tieba/item/records", params= {"server": server,"name": name,"limit": limit,"token": self.token,}, processor=processor, template="" ) async def bagua(self, tags: str, server:str, limit:str ) -> Dict[str, Any]: """八卦""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: if not data: result_msg = f"未找到相关 {tags} 记录。\n" result_msg += f"可选范围:818 616 鬼网三 鬼网3 树洞 记录 教程 街拍 故事 避雷 吐槽 提问" else: result_msg = f"类型:【{tags}】\n\n" for item in data: result_msg += f"{item['title']}\n" result_msg += f"服务器:{item['server']}\n" result_msg += f"所属吧:{item['name']}\n" result_msg += f"链接:https://tieba.baidu.com/p/{item['url']}\n" result_msg += f"日期:{item['date']}\n\n" return_data["data"] = result_msg return await self._request_api( path="/tieba/random", params= {"server": server,"tags": tags,"limit": limit,"token": self.token,}, processor=processor, template="" ) async def fubengjilu(self, server:str, name: str ) -> Dict[str, Any]: """副本记录""" async def processor(data: Any, return_data: Dict[str, Any]) -> None: return_data["data"]["list"] = data return await self._request_api( path="/raid/records", params= {"server": server,"name": name,"token": self.token,}, processor=processor, template="fubenjilu.html" )