from collections.abc import Mapping, Sequence from datetime import datetime from typing import Any, Dict, List, Optional from astrbot.api import logger from ..fun_basic import compare_date_str, week_to_num from .base import DATA_PROCESSING_ERRORS, BaseDomainService def _text(value: Any, default: str = "无") -> str: if value is None: return default result = str(value).strip() return result or default def _format_items(value: Any) -> str: if value is None: return "无" if isinstance(value, str): items = [value.strip()] if value.strip() else [] elif isinstance(value, Sequence) and not isinstance(value, (bytes, bytearray)): items = [text for item in value if (text := _text(item, ""))] else: items = [] return "\n".join(f"• {item}" for item in items) if items else "无" class CalendarService(BaseDomainService): async def richang(self, server: str, num: int = 0) -> Dict[str, Any]: """日常活动""" params = {"server": server, "num": num} data: Optional[Dict[str, Any]] = await self.request( "jx3_richang", params=params ) if not isinstance(data, dict) or not data: return self.failure("获取接口信息失败") week = _text(data.get("week"), "未知") week_label = week if week.startswith("星期") else f"星期{week}" weekly = data.get("weekly") if isinstance(weekly, Mapping): weekly_conn = weekly.get("conn") weekly_raid = weekly.get("raid") else: weekly_conn = None weekly_raid = None lines = [ f"【{_text(server, '未知服务器')}】", f"{_text(data.get('date'), '未知日期')} {week_label}", "", "【今日活动】", f"大战:{_text(data.get('war'))}", f"战场:{_text(data.get('battle'))}", f"阵营:{_text(data.get('orecar'))}", f"宗门:{_text(data.get('school'))}", f"驰援:{_text(data.get('rescue'))}", "", "【画像】", _format_items(data.get("draw")), "", "【宠物福缘】", _format_items(data.get("lucky")), "", "【家园声望·加倍道具】", _format_items(data.get("card")), "", "【武林通鉴·公共任务】", _format_items(weekly_conn), "", "【武林通鉴·团队秘境】", _format_items(weekly_raid), ] return self.success("\n".join(lines)) async def richangyuche(self) -> Dict[str, Any]: """日常预测""" return_data = self.new_result() # 1. 构造请求参数 params = {"num": 30} # 2. 调用基础请求 data: Optional[Dict[str, Any]] = await self.request( "jx3_richangyuche", params=params ) if not data: return_data["msg"] = "获取接口信息失败" return return_data # 3. 处理返回数据 try: items = [] num_richang = week_to_num(data["data"][0]["week"]) or 0 # 空白数据 for _ in range(num_richang): items.append( {"en": False, "compare": "", "date": "", "war": "", "battle": ""} ) # 真实数据 for m in data["data"]: items.append( { "en": True, "compare": compare_date_str(m.get("date", "")), "date": m.get("date", ""), "war": m.get("war", ""), "battle": m.get("battle", ""), } ) return_data["data"]["items"] = items return_data["data"]["today"] = data["today"] except DATA_PROCESSING_ERRORS as e: logger.error(f"数据处理时出错: {e}") return_data["msg"] = "处理接口返回信息时出错" return return_data # 加载模板 if not await self.attach_template(return_data, "richangyuche.html"): return return_data return_data["code"] = 200 return return_data async def xingxiashijian(self, name: str) -> Dict[str, Any]: """行侠事件""" return_data = self.new_result() # 1. 构造请求参数 params = {"name": name} # 2. 调用基础请求 data: Optional[Dict[str, Any]] = await self.request( "jx3_xingxiashijian", params=params ) if not data: return_data["msg"] = "获取接口信息失败" return return_data # 3. 处理返回数据 try: return_data["data"]["items"] = data return_data["data"]["name"] = name except DATA_PROCESSING_ERRORS as e: logger.error(f"数据处理时出错: {e}") return_data["msg"] = "处理接口返回信息时出错" return return_data # 加载模板 if not await self.attach_template(return_data, "xingxiashijian.html"): return return_data return_data["code"] = 200 return return_data async def shaohua(self) -> Dict[str, Any]: """骚话""" return_data = self.new_result() # 因为没有参数,所以 params=None data: Optional[Dict[str, Any]] = await self.request("jx3_shaohua") if not data: return_data["msg"] = "获取接口信息失败" return return_data text = data.get("text") if text: return_data["data"] = text else: return_data["msg"] = "接口未返回文本" return return_data return_data["code"] = 200 return return_data async def jiemi(self) -> Dict[str, Any]: """解密""" return_data = self.new_result() params = {} data: Optional[Dict[str, Any]] = await self.request("jx3_jiemi", params=params) if not data or not isinstance(data, dict): return_data["msg"] = "未查询到解密信息" return return_data try: curr = data.get("curr", {}) next_data = data.get("next", {}) if not isinstance(curr, dict): curr = {} if not isinstance(next_data, dict): next_data = {} return_data["data"] = "\n".join( [ "解密", f"当前时间:{data.get('time', '')}", f"当前节点:{curr.get('node', '')}", f"当前结果:{curr.get('data', '')}", f"下轮节点:{next_data.get('node', '')}", f"下轮结果:{next_data.get('data', '')}", f"剩余时间:{data.get('cdtn', '')}", ] ) except DATA_PROCESSING_ERRORS as e: logger.error(f"处理解密数据失败: {e}") return_data["msg"] = "处理解密数据失败" return return_data return_data["code"] = 200 return return_data async def baizhan(self) -> Dict[str, Any]: """百战首领""" return_data = self.new_result() # 1. 构造请求参数 params = {} data: Optional[Dict[str, Any]] = await self.request( "jx3_baizhan", params=params ) if not data: return_data["msg"] = "获取接口信息失败" return return_data # 处理返回数据 try: return_data["data"] = data return_data["data"]["start"] = datetime.fromtimestamp( float(data["start"]) ).strftime("%Y-%m-%d %H:%M:%S") return_data["data"]["end"] = datetime.fromtimestamp( float(data["end"]) ).strftime("%Y-%m-%d %H:%M:%S") except DATA_PROCESSING_ERRORS as e: logger.error(f"数据处理时出错: {e}") return_data["msg"] = "处理接口返回信息时出错" # 加载模板 if not await self.attach_template(return_data, "baizhan.html"): return return_data return_data["code"] = 200 return return_data async def fuyaojjiutian(self, server: str) -> Dict[str, Any]: """扶摇九天""" return_data = self.new_result() # 1. 构造请求参数 params = {"server": server} # 2. 调用基础请求 data: Optional[list[Dict[str, Any]]] = await self.request( "jx3_fuyaojiutian", params=params ) if not data: return_data["msg"] = "获取接口信息失败" return return_data # 3. 处理返回数据 try: data_new = data[0] data_time = datetime.fromtimestamp(data_new["time"]).strftime( "%Y-%m-%d %H:%M:%S" ) result_msg = f"{server}\n" if data_new["status"] == 0: result_msg += "本轮扶摇九天尚未开启\n" if data_new["status"] == 1: result_msg += "本轮扶摇九天正在进行\n" if data_new["status"] == 2: result_msg += "本轮扶摇九天已经结束\n" result_msg += f"开启时间:{data_time}\n" return_data["data"] = result_msg except DATA_PROCESSING_ERRORS as e: logger.error(f"处理返回数据失败: {e}") return_data["msg"] = "处理返回数据失败" return return_data return_data["code"] = 200 return return_data async def zhueevent(self) -> Dict[str, Any]: """诛恶事件""" return_data = self.new_result() params = {} data: Optional[List[Dict[str, Any]]] = await self.request( "jx3_zhueevent", params=params ) if not data or not isinstance(data, list): return_data["msg"] = "未查询到诛恶事件信息" return return_data try: items = [] for item in data: if not isinstance(item, dict): continue event_time = item.get("time") if event_time: try: item["time"] = datetime.fromtimestamp(int(event_time)).strftime( "%Y-%m-%d %H:%M:%S" ) except (TypeError, ValueError, OSError): item["time"] = str(event_time) else: item["time"] = "" items.append(item) if not items: return_data["msg"] = "未查询到诛恶事件信息" return return_data return_data["data"] = { "items": items, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } except DATA_PROCESSING_ERRORS as e: logger.error(f"处理诛恶事件数据失败: {e}") return_data["msg"] = "处理诛恶事件数据失败" return return_data if not await self.attach_template(return_data, "zhueevent.html"): return return_data return_data["code"] = 200 return return_data async def benrichitu(self) -> Dict[str, Any]: """本日赤兔""" return_data = self.new_result() params = {} data: Optional[List[Dict[str, Any]]] = await self.request( "jx3_benrichitu", params=params ) def no_data() -> Dict[str, Any]: return_data["code"] = 200 return_data["data"] = "本日赤兔 暂无数据" return return_data if not data or not isinstance(data, list): return no_data() try: items = [] for item in data: if not isinstance(item, dict): continue date_value = item.get("date", "") if date_value: try: date_text = datetime.fromtimestamp(int(date_value)).strftime( "%Y-%m-%d %H:%M:%S" ) except (TypeError, ValueError, OSError): date_text = str(date_value) else: date_text = "" items.append( { "date": date_text, "server": item.get("server", ""), "map_name": item.get("map_name", ""), } ) if not items: return no_data() result_lines = ["本日赤兔"] for item in items: result_lines.extend( [ f"时间:{item['date']}", f"区服:{item['server']}", f"地图:{item['map_name']}", "", ] ) return_data["code"] = 200 return_data["data"] = "\n".join(result_lines).rstrip() except DATA_PROCESSING_ERRORS as e: logger.error(f"处理本日赤兔数据失败: {e}") return no_data() return return_data async def benzhouchitu(self) -> Dict[str, Any]: """本周赤兔""" return_data = self.new_result() params = {} data: Optional[List[Dict[str, Any]]] = await self.request( "jx3_benzhouchitu", params=params ) def no_data() -> Dict[str, Any]: return_data["code"] = 200 return_data["data"] = "本周赤兔 暂无数据" return return_data if not data or not isinstance(data, list): return no_data() try: items = [] for item in data: if not isinstance(item, dict): continue date_value = item.get("date", "") if date_value: try: date_text = datetime.fromtimestamp(int(date_value)).strftime( "%Y-%m-%d %H:%M:%S" ) except (TypeError, ValueError, OSError): date_text = str(date_value) else: date_text = "" items.append( { "date": date_text, "server": item.get("server", ""), "map_name": item.get("map_name", ""), } ) if not items: return no_data() result_lines = ["本周赤兔"] for item in items: result_lines.extend( [ f"时间:{item['date']}", f"区服:{item['server']}", f"地图:{item['map_name']}", "", ] ) return_data["code"] = 200 return_data["data"] = "\n".join(result_lines).rstrip() except DATA_PROCESSING_ERRORS as e: logger.error(f"处理本周赤兔数据失败: {e}") return no_data() return return_data async def zhenyingevent(self) -> Dict[str, Any]: """阵营事件""" return_data = self.new_result() params = {} data: Optional[List[Dict[str, Any]]] = await self.request( "jx3_zhenyingevent", params=params ) if not data or not isinstance(data, list): return_data["msg"] = "未查询到阵营事件信息" return return_data try: items = [] for item in data: if not isinstance(item, dict): continue seize_time = item.get("seize_time") if seize_time: try: item["seize_time"] = datetime.fromtimestamp( int(seize_time) ).strftime("%Y-%m-%d %H:%M:%S") except (TypeError, ValueError, OSError): item["seize_time"] = str(seize_time) else: item["seize_time"] = "" items.append(item) if not items: return_data["msg"] = "未查询到阵营事件信息" return return_data return_data["data"] = { "items": items, "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } except DATA_PROCESSING_ERRORS as e: logger.error(f"处理阵营事件数据失败: {e}") return_data["msg"] = "处理阵营事件数据失败" return return_data if not await self.attach_template(return_data, "zhenyingevent.html"): return return_data return_data["code"] = 200 return return_data async def guanaishouling(self) -> Dict[str, Any]: """关隘首领""" return_data = self.new_result() params = {} data: Optional[List[Dict[str, Any]]] = await self.request( "jx3_guanaishouling", params=params ) if not data or not isinstance(data, list): return_data["msg"] = "未查询到关隘首领信息" return return_data try: now_ts = int(datetime.now().timestamp()) def format_time(value: Any) -> str: if not value: return "" try: return datetime.fromtimestamp(int(value)).strftime( "%Y-%m-%d %H:%M:%S" ) except (TypeError, ValueError, OSError): return str(value) def format_remaining(end_time: Any) -> str: if not end_time: return "" try: seconds = max(0, int(end_time) - now_ts) except (TypeError, ValueError): return str(end_time) hours = seconds // 3600 minutes = (seconds % 3600) // 60 secs = seconds % 60 return f"{hours}时{minutes:02d}分{secs:02d}秒" groups = [] for group in data: if not isinstance(group, dict): continue records = group.get("data", []) if not isinstance(records, list) or not records: continue parsed_records = [] for item in records: if not isinstance(item, dict): continue end_time = item.get("end_time") parsed_records.append( { "camp_name": item.get("camp_name", ""), "castle": item.get("castle", ""), "str_status": item.get("str_status", ""), "start_time": format_time(item.get("start_time")), "end_time": format_time(end_time), "remaining_time": format_remaining(end_time), } ) if parsed_records: groups.append( { "server": group.get("server", ""), "records": parsed_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"), } except DATA_PROCESSING_ERRORS as e: logger.error(f"处理关隘首领数据失败: {e}") return_data["msg"] = "处理关隘首领数据失败" return return_data if not await self.attach_template(return_data, "guanaishouling.html"): return return_data return_data["code"] = 200 return return_data async def shuamamsg(self, server: str, type: str, subtype: str) -> Dict[str, Any]: """刷马消息""" return_data = self.new_result() params = {"server": server, "type": type, "subtype": subtype} # 提取字段可能返回字典 data: Optional[Dict[str, Any]] = await self.request( "jx3box_shuamamsg", params=params ) if not data: return_data["msg"] = "获取接口信息失败或数据格式错误" return return_data try: # new_msg = data.get("list", [])[0] return_data["status"] = new_msg.get("id") result_msg = f"{server}\n" result_msg += f"{new_msg.get('content')}\n" result_msg += f"{new_msg.get('created_at')}\n" return_data["data"] = result_msg except DATA_PROCESSING_ERRORS as e: logger.error(f"数据处理时出错: {e}") return_data["msg"] = "处理接口返回信息时出错" return return_data return_data["code"] = 200 return return_data async def shuma(self, server: str) -> Dict[str, Any]: """刷马""" return_data = self.new_result() # 1. 构造请求参数 params = {"server": server} # 2. 调用基础请求 data: Optional[Dict[str, Any]] = await self.request( "jx3_shuama", params=params, out_key="" ) if not data: return_data["msg"] = "获取接口信息失败" return return_data # 3. 处理返回数据 try: _data = data["data"]["data"] result_msg = f"{server}\n" result_msg += f"黑戈壁:\n{_data['黑戈壁'][0]}\n" result_msg += f"阴山大草原:\n{_data['阴山大草原'][0]}\n" result_msg += f"鲲鹏岛:\n{_data['鲲鹏岛'][0]}\n" result_msg += f"\n{data['data']['note']}" return_data["data"] = result_msg except DATA_PROCESSING_ERRORS as e: logger.error(f"处理返回数据失败: {e}") return_data["msg"] = "处理返回数据失败" return return_data return_data["code"] = 200 return return_data