diff --git a/README.md b/README.md index 9063140..f416691 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,19 @@ ## 简介 -仿照剑网三主流的机器人写了个插件,主要是自用。 +仿照剑网三主流的机器人写了个插件,主要是自用,没有群管理相关的功能,在任何群聊都是使用的一套数据。 -插件功能绝大部分都是用AI写的,又进行了调试。 +插件功能绝大部分都是用AI写的,自己进行了调试。 -目前此插件能够完成部分的功能查询,其他功能有空再说。 +目前此插件查询功能还没做完,后续会继续完善。 -此插件的所有数据几乎全部依赖jx3api提供的API接口,所以进阶功能需要向其购买token才可使用。普通功能是免token的。 -部分进阶功能除了购买token以外还需要自己去抓包推栏app,获得推栏app的token才可正常使用。 +此插件大部分数据依赖jx3api提供的接口,只有进阶功能需要向其购买token才可使用。其他功能是免token的。 +部分进阶功能除了购买token以外还需要自己去抓包推栏app,获得推栏app的ticket才可正常使用。 ## 更新记录 +version: 1.1.0:部分代码功能重写。 + version: 1.0.0:大部分重要功能已经实现 ## 功能特点 @@ -35,10 +37,10 @@ version: 1.0.0:大部分重要功能已经实现 使用进阶的功能必须配置,购买在https://www.jx3api.com。 -**推栏标识** +**推栏ticket** -在进阶功能中,有部分功能依赖推栏APP的数据,所以需要自己抓包推栏的token。 -大致操作下载一个抓包工具,打开推栏APP,做一些查询操作。去抓包工具看看发送的请求,参数里面就有token。 +在进阶功能中,有部分功能依赖推栏APP的数据,所以需要自己抓包推栏的ticket。 +大致操作下载一个抓包工具,打开推栏APP,做一些查询操作。去抓包工具看看发送的请求,参数里面就有ticket。 **推送功能** diff --git a/_conf_schema.json b/_conf_schema.json index 74dc6bf..37c8763 100644 --- a/_conf_schema.json +++ b/_conf_schema.json @@ -35,7 +35,7 @@ "default": "", "hint": "通过抓包推栏APP账号登录信息获取推栏标识" }, - "kfjk": { + "kfts": { "description": "开服监控配置", "type": "object", "items": { @@ -63,7 +63,7 @@ } } }, - "xwzx": { + "xwts": { "description": "新闻资讯推送", "type": "object", "items": { @@ -91,7 +91,7 @@ } } }, - "smxx": { + "smts": { "description": "刷马消息推送", "type": "object", "items": { @@ -119,7 +119,7 @@ } } }, - "ctxx": { + "ctts": { "description": "赤兔消息推送", "type": "object", "items": { diff --git a/core/async_task.py b/core/async_task.py index 9ed596e..acfe77f 100644 --- a/core/async_task.py +++ b/core/async_task.py @@ -11,70 +11,67 @@ from astrbot.api.star import Context, Star, register, StarTools from astrbot.api import logger from astrbot.api import AstrBotConfig -from .jx3_data import JX3Service +from .jx3_data import JX3Service +from .sqlite import AsyncSQLiteDB class AsyncTask: """ 基于 APScheduler 的后台异步监控任务管理类 """ - def __init__(self, context: Context, config: AstrBotConfig, jx3fun: JX3Service): + def __init__(self, context: Context, config: AstrBotConfig, jx3api: JX3Service, sqlite: AsyncSQLiteDB): self.context = context self.conf = config - self.jx3fun = jx3fun + self.jx3fun = jx3api + self.sql = sqlite self.server = self.conf.get("server", "梦江南") - self.file_path = StarTools.get_data_dir("astrbot_plugin_jx3") / "local_async.json" - self._file_lock = asyncio.Lock() self.scheduler = AsyncIOScheduler() - self.tasks = {} # 存储 task_id 对应的状态信息 + self.tasks = {} - logger.info(f"获取后台数据缓存文件路径成功:{self.file_path}") + logger.info(f"初始化推送功能成功") """===================== 本地读写 =====================""" async def set_local_data(self, key: str, value): - async with self._file_lock: - try: - self.file_path.parent.mkdir(parents=True, exist_ok=True) + try: + allowed = {"kfts", "xwts", "smts", "ctts"} + if key not in allowed: + raise ValueError("非法字段") + + await self.sql.update( + "tuishong", + { + key: value, + }, + "id=?", + (1,) + ) + except Exception as e: + logger.error(f"数据写入失败:{e}") - if not self.file_path.exists(): - local_data = {} - else: - async with aiofiles.open(self.file_path, "r", encoding="utf-8") as f: - content = await f.read() - local_data = json.loads(content) if content else {} - local_data[key] = value - - async with aiofiles.open(self.file_path, "w", encoding="utf-8") as f: - await f.write( - json.dumps(local_data, ensure_ascii=False, indent=4) - ) - - except (OSError, json.JSONDecodeError) as e: - logger.error(f"数据写入文件失败:{e}") - - async def get_local_data(self, key: str, default=None): - async with self._file_lock: - try: - if not self.file_path.exists(): - return default - - async with aiofiles.open(self.file_path, "r", encoding="utf-8") as f: - content = await f.read() - if not content: - return default - local_data = json.loads(content) - - return local_data.get(key, default) - - except (OSError, json.JSONDecodeError) as e: - logger.error(f"读取数据文件失败:{e}") + async def get_local_data(self, key: str, default: int=0): + try: + allowed = {"kfts", "xwts", "smts", "ctts"} + if key not in allowed: return default + + data = await self.sql.select_one( + "tuishong", + "id=?", + (1,) + ) + if data: + return data.get(key, default) + else: + return default + except Exception as e: + logger.error(f"数据读取失败:{e}") + """===================== 通用后台任务 =====================""" @@ -112,10 +109,10 @@ class AsyncTask: async def init_tasks(self): settings = [ - ("kfjk", "开服监控", lambda: self.jx3fun.kaifu(self.server)), - ("xwzx", "新闻资讯", lambda: self.jx3fun.xinwen(1)), - ("smxx", "刷马消息", lambda: self.jx3fun.shuamamsg(self.server,type="horse",subtype="foreshow")), - ("ctxx", "赤兔消息", lambda: self.jx3fun.shuamamsg(self.server,type="chitu-horse",subtype="share_msg")), + ("kfts", "开服监控", lambda: self.jx3fun.kaifu(self.server)), + ("xwts", "新闻资讯", lambda: self.jx3fun.xinwen(1)), + ("smts", "刷马消息", lambda: self.jx3fun.shuamamsg(self.server,type="horse",subtype="foreshow")), + ("ctts", "赤兔消息", lambda: self.jx3fun.shuamamsg(self.server,type="chitu-horse",subtype="share_msg")), ] for key, name, fetch in settings: @@ -131,7 +128,10 @@ class AsyncTask: } if self.tasks[key]["enable"]: - self._add_scheduler(key, name, fetch) + if self.tasks[key]["umos"]: + self._add_scheduler(key, name, fetch) + else: + logger.warning(f"{name} 推送对象为空,任务未启动") if not self.scheduler.running: self.scheduler.start() diff --git a/core/jx3_data.py b/core/jx3_data.py index a6575c4..93b2cd7 100644 --- a/core/jx3_data.py +++ b/core/jx3_data.py @@ -1,9 +1,4 @@ - -# pyright: reportArgumentType=false -# pyright: reportAttributeAccessIssue=false -# pyright: reportIndexIssue=false -# pyright: reportOptionalMemberAccess=false - +import json from datetime import datetime from typing import Dict, Any, Optional, List, Union @@ -15,10 +10,16 @@ from .sqlite import AsyncSQLiteDB from .fun_basic import load_template,gold_to_string,week_to_num,compare_date_str class JX3Service: - def __init__(self, api_config, config:AstrBotConfig, sqlite:AsyncSQLiteDB): - self._api = APIClient() - # 引用API配置文件 - self._api_config = api_config + def __init__(self, api_data_path: str, config: AstrBotConfig, sqlite: AsyncSQLiteDB): + # 加载API配置文件 + try: + with open(api_data_path, 'r', encoding='utf-8') as f: + self._api_config = json.load(f) + except FileNotFoundError as e: + logger.error(f"加载API配置文件失败: {e}") + self._api_config = {} + # 实例化 API Client + self._api: APIClient = APIClient() # 引用插件配置文件 self._config = config # 引用sqlite @@ -27,13 +28,13 @@ class JX3Service: # 获取配置中的 Token self.token = self._config.get("jx3api_token", "") if self.token == "": - logger.info("获取配置token失败,请正确填写token,否则部分功能无法正常使用") + logger.warning("获取配置token失败,请正确填写token,否则部分功能无法正常使用") else: logger.debug(f"获取配置token成功。{self.token}") # 获取配置中的 ticket self.ticket = self._config.get("jx3api_ticket", "") if self.ticket == "": - logger.info("获取配置ticket失败,请正确填写ticket,否则部分功能无法正常使用") + logger.warning("获取配置ticket失败,请正确填写ticket,否则部分功能无法正常使用") else: logger.debug(f"获取配置ticket成功。{self.ticket}") @@ -42,7 +43,6 @@ class JX3Service: """释放底层 APIClient 资源""" if self._api: await self._api.close() - self._api = None def _init_return_data(self) -> Dict[str, Any]: @@ -72,12 +72,15 @@ class JX3Service: :return: 成功时返回提取后的数据,失败时返回 None。 """ try: + if not self._api: + logger.error("API client is not initialized") + return None + api_config = self._api_config.get(config_key) if not api_config: logger.error(f"配置文件中未找到 key: {config_key}") return None - # 复制 params,避免修改原始配置模板 request_params = api_config.get("params", {}).copy() if params: request_params.update(params) @@ -185,7 +188,7 @@ class JX3Service: # 3. 处理返回数据 try: items = [] - num_richang = week_to_num(data["data"][0]["week"]) + num_richang = week_to_num(data["data"][0]["week"]) or 0 # 空白数据 for _ in range(num_richang): items.append({ @@ -271,7 +274,7 @@ class JX3Service: params = {"subject": subject, "limit": limit} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[List[Dict[str, Any]]] = await self._base_request( "jx3_keju", "GET", params=params ) if not data: @@ -511,7 +514,7 @@ class JX3Service: return_data = self._init_return_data() - data: Optional[Dict[str, Any]] = await self._base_request("jx3_zhuangtai", "GET") + data: Optional[List[Dict[str, Any]]] = await self._base_request("jx3_zhuangtai", "GET") if not data: return_data["msg"] = "获取接口信息失败" @@ -621,8 +624,8 @@ class JX3Service: return_data = self._init_return_data() params = {"server": server, "type": type, "subtype": subtype} - # 提取字段可能返回列表 - data: Optional[List[Dict[str, Any]]] = await self._base_request( + # 提取字段可能返回字典 + data: Optional[Dict[str, Any]] = await self._base_request( "jx3box_shuamamsg", "GET", params=params) if not data: @@ -631,7 +634,7 @@ class JX3Service: try: # - new_msg = data.get("list")[0] + new_msg = data.get("list",[])[0] return_data["status"] = new_msg.get('id') result_msg = f"{server}\n" @@ -653,18 +656,14 @@ class JX3Service: """区服金价""" return_data = self._init_return_data() - # 获取配置中的 Token - token = self._config.get("jx3api_token", "") - if token == "": - return_data["msg"] = "系统未配置API访问Token" - return return_data - params = {"server": server, "limit": limit, "token": token} + params = {"server": server, "limit": limit, "token": self.token} data_list: Optional[List[Dict[str, Any]]] = await self._base_request("jx3_jinjia", "GET", params=params) if not data_list or not isinstance(data_list, list): return_data["msg"] = "获取接口信息失败或数据格式错误" return return_data + # 加载模板 try: return_data["temp"] = await load_template("jinjia.html") @@ -772,7 +771,7 @@ class JX3Service: params = {"server": server, "name": name,"token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[List[Dict[str, Any]]] = await self._base_request( "jx3_jiaoyihang", "GET", params=params ) @@ -785,18 +784,19 @@ class JX3Service: try: for item in data: - inner_list = item.get("data", []) - first = inner_list[0] if inner_list else {} - new_item = { - "name": item.get("name"), - "icon": f"https://icon.jx3box.com/icon/{item.get('icon')}.png", - "sever": first.get("server"), - "count": len(inner_list), - "unit_price": gold_to_string(first.get("unit_price")), - "created": datetime.fromtimestamp(first.get("created")).strftime("%Y-%m-%d %H:%M:%S"), - } - result.append(new_item) - return_data["data"]["list"] = result + if isinstance(item, dict): + inner_list = item.get("data", []) + first = inner_list[0] if inner_list else {} + new_item = { + "name": item.get("name"), + "icon": f"https://icon.jx3box.com/icon/{item.get('icon')}.png", + "sever": first.get("server"), + "count": len(inner_list), + "unit_price": gold_to_string(first.get("unit_price")), + "created": datetime.fromtimestamp(first.get("created", "")).strftime("%Y-%m-%d %H:%M:%S"), + } + result.append(new_item) + return_data["data"]["list"] = result except Exception as e: logger.error(f"处理交易行数据失败: {e}") return_data["msg"] = "处理交易行数据失败" @@ -868,7 +868,7 @@ class JX3Service: params = {"server": server, "name": name,"token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[List[Dict[str, Any]]] = await self._base_request( "jx3_yanhuachaxun", "GET", params=params ) @@ -879,12 +879,12 @@ class JX3Service: # 3. 处理返回数据 try: for item in data: - timestamp = item.get("time") - if timestamp and isinstance(timestamp, (int, float)): - # 修复时间戳:原代码显示这里是毫秒级,除以 1000 - item["time"] = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") - else: - item["time"] = "未知时间" # 确保即使 time 字段缺失也不会报错 + if isinstance(item, dict): + timestamp = item.get("time") + if timestamp and isinstance(timestamp, (int, float)): + item["time"] = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") + else: + item["time"] = "未知时间" return_data["data"]["list"] = data except Exception as e: @@ -913,7 +913,7 @@ class JX3Service: params = {"server": server, "token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[List[Dict[str, Any]]] = await self._base_request( "jx3_dilujilu", "GET", params=params ) @@ -927,7 +927,7 @@ class JX3Service: item["refresh_time"] = datetime.fromtimestamp(item["refresh_time"]).strftime("%Y-%m-%d %H:%M:%S") item["capture_time"] = datetime.fromtimestamp(item["capture_time"]).strftime("%Y-%m-%d %H:%M:%S") item["auction_time"] = datetime.fromtimestamp(item["auction_time"]).strftime("%Y-%m-%d %H:%M:%S") - return_data["data"]["list"] = data + return_data["data"]["list"] = data except Exception as e: logger.error(f"数据处理时出错: {e}") return_data["msg"] = "处理接口返回信息时出错" @@ -1034,7 +1034,7 @@ class JX3Service: params = {"server": server, "name": name, "token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[List[Dict[str, Any]]] = await self._base_request( "jx3_qiyu", "GET", params=params ) @@ -1082,7 +1082,7 @@ class JX3Service: params = {"server": server, "name": name, "token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[List[Dict[str, Any]]] = await self._base_request( "jx3_zhengyingpaimai", "GET", params=params ) @@ -1122,7 +1122,7 @@ class JX3Service: params = {"server": server, "token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[list[Dict[str, Any]]] = await self._base_request( "jx3_fuyaojiutian", "GET", params=params ) @@ -1240,7 +1240,7 @@ class JX3Service: params = {"class": type, "limit": "5", "token": self.token} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[list[Dict[str, Any]]] = await self._base_request( "jx3_bagua", "GET", params=params ) @@ -1277,7 +1277,7 @@ class JX3Service: params = {"name": name} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[list[Dict[str, Any]]] = await self._base_request( "jx3box_qiyugonglue", "GET", params=params, out_key="list" ) @@ -1290,11 +1290,10 @@ class JX3Service: url = f"https://node.jx3box.com/serendipity/{dwID}/achievement" logger.debug(f"获取ID接口地址:{url}") - # 3. 获取奇遇攻略 - # 获取achievement_id data1 = await self._api.get(url) url1 = f"https://cms.jx3box.com/api/cms/wiki/post/type/achievement/source/{data1['achievement_id']}" logger.debug(f"获取攻略接口地址:{url1}") + # 获取奇遇攻略 data2 = await self._api.get(url1, out_key="data") if not data2: @@ -1327,8 +1326,12 @@ class JX3Service: (name, name, name, name, name, name) ) - kungfu = result.get("name",None) - if kungfu == None: + if result is None: + return_data["msg"] = "未找到该心法" + return return_data + + kungfu = result.get("name", None) + if kungfu is None: return_data["msg"] = "未找到该心法" return return_data @@ -1338,7 +1341,7 @@ class JX3Service: params = {"kungfu": kungfu} # 2. 调用基础请求 - data: Optional[Dict[str, Any]] = await self._base_request( + data: Optional[list[Dict[str, Any]]] = await self._base_request( "jx3box_hong", "GET", params=params, out_key="" ) logger.debug(data) @@ -1377,6 +1380,7 @@ class JX3Service: # 发起请求 url = f"https://cms.jx3box.com/api/cms/post/{pid}" logger.debug(f"获取宏接口地址:{url}") + data = await self._api.get(url, out_key="data") # 验证数据 if not data: @@ -1414,9 +1418,13 @@ class JX3Service: "name=? OR name1=? OR name2=? OR name3=? OR name4=? OR name5=?", (name, name, name, name, name, name) ) - - mount = result.get("pzid",None) - if mount == None: + logger.debug(result) + if result is None: + return_data["msg"] = "未找到该心法" + return return_data + + mount = result.get("pzid", None) + if not mount: return_data["msg"] = "未找到该心法" return return_data diff --git a/core/message.py b/core/message.py new file mode 100644 index 0000000..88318c3 --- /dev/null +++ b/core/message.py @@ -0,0 +1,379 @@ +from astrbot.core import html_renderer +from astrbot.api import logger +from astrbot.api.event import AstrMessageEvent, MessageChain +from astrbot.core.utils.session_waiter import ( + SessionController, + session_waiter, +) + +from .jx3_data import JX3Service +from .async_task import AsyncTask +from .bilei_data import BiLeidata + + +class MessageBuilder: + """回复消息构建""" + def __init__(self, server: str, jx3api: JX3Service, bilei: BiLeidata, jx3at: AsyncTask): + self.server = server + self.jx3api = jx3api + self.bilei = bilei + self.jx3at = jx3at + + + async def html_render( + self, + tmpl: str, + data: dict, + return_url=True, + options: dict | None = None, + ) -> str: + """渲染 HTML""" + return await html_renderer.render_custom_template( + tmpl, + data, + return_url=return_url, + options=options, + ) + + + def serverdefault(self,server) -> str: + """加载配置默认服务器""" + if server == "": + return self.server + return server + + + async def plain_msg(self, event: AstrMessageEvent, action): + """最终将数据整理成文本发送""" + data= await action() + try: + if data["code"] == 200: + await event.send( event.plain_result(data["data"])) + else: + await event.send(event.plain_result(data["msg"])) + except Exception as e: + logger.error(f"功能函数执行错误: {e}") + await event.send(event.plain_result("猪脑过载,请稍后再试")) + + + async def T2I_image_msg(self, event: AstrMessageEvent, action): + """最终将数据渲染成图片发送""" + data = await action() + try: + if data["code"] == 200: + url = await self.html_render(data["temp"], data["data"], options={}) + await event.send(event.image_result(url)) + else: + await event.send(event.plain_result(data["msg"])) + + except Exception as e: + logger.error(f"功能函数执行错误: {e}") + await event.send(event.plain_result("猪脑过载,请稍后再试")) + + + async def image_msg(self, event: AstrMessageEvent, action): + """最终将数据整理成图片发送""" + data = await action() + try: + if data["code"] == 200: + await event.send(event.image_result(data["data"])) + else: + await event.send(event.plain_result(data["msg"])) + + except Exception as e: + logger.error(f"功能函数执行错误: {e}") + await event.send(event.plain_result("猪脑过载,请稍后再试")) + + + async def handler_plain_image_msg(self, event: AstrMessageEvent, action1, action2): + """两轮会话消息发送通用,先文本列表等反馈序号在发送图片""" + # 会话触发 + try: + # 获取一轮数据 + data = await action1() + if data["code"] == 200: + # 发送一轮消息 + await event.send(event.plain_result(data["msg"])) + # 获取触发用户ID + user_id = event.get_sender_id() + + # 二轮会话流程 + @session_waiter(timeout=30) + async def macro_select_waiter(controller: SessionController,new_event: AstrMessageEvent): + # 跳过非触发用户消息 + if new_event.get_sender_id() != user_id: + return + # 获取用户消息 + msg = new_event.get_message_str().strip() + # 判断消息是否为数字 + if not msg.isdigit(): + await new_event.send( + MessageChain().message("输入异常,结束会话") + ) + controller.stop() + return + # 判断数字是否在有效值内 + num = int(msg) + if num < 1 or num > data["data"]["num"]: + await new_event.send( + MessageChain().message("无效序号,结束会话") + ) + controller.stop() + return + + # 获取二轮数据 + try: + data1 = await action2(data["data"]["list"][num]) + if data1["code"] != 200: + await new_event.send( + MessageChain().message("获取详细数据失败") + ) + controller.stop() + return + + # 消息拼接发送 + chain = MessageChain() + msg_text = data1["data"] + chain.message(msg_text) + if data1["temp"] != "": + url = await self.html_render(data1["temp"], {}, options={}) + chain.url_image(url) + await new_event.send(chain) + + except Exception as e: + logger.error(f"功能函数执行错误: {e}") + await new_event.send( + MessageChain().message("猪脑过载,请稍后再试") + ) + + controller.stop() + + # 二轮会话激活 + try: + await macro_select_waiter(event) + except TimeoutError: + await event.send(event.plain_result("选择超时,已结束会话")) + except Exception: + logger.error("宏选择发生异常", exc_info=True) + + else: + await event.send(event.plain_result(f"未搜索到相关内容")) + return + + except Exception as e: + logger.error(f"功能函数执行错误: {e}") + await event.send(event.plain_result("猪脑过载,请稍后再试")) + + + async def jx3_helps(self, event: AstrMessageEvent): + """剑三 功能""" + return await self.T2I_image_msg(event, self.jx3api.helps) + + + async def jx3_richang(self, event: AstrMessageEvent,server: str = "" ,num: int = 0): + """剑三 日常 服务器 天数""" + return await self.plain_msg(event, lambda: self.jx3api.richang(self.serverdefault(server),num)) + + + async def jx3_richangyuche(self, event: AstrMessageEvent): + """剑三 日常预测""" + return await self.T2I_image_msg(event, self.jx3api.richangyuche) + + + async def jx3_xingxiashijian(self, event: AstrMessageEvent,name: str = "穹野卫"): + """剑三 名望""" + return await self.T2I_image_msg(event, lambda: self.jx3api.xingxiashijian(name)) + + + async def jx3_kaifu(self, event: AstrMessageEvent,server: str = ""): + """剑三 开服 服务器""" + return await self.plain_msg(event, lambda: self.jx3api.kaifu(self.serverdefault(server))) + + + async def jx3_zhuangtai(self, event: AstrMessageEvent): + """剑三 状态""" + return await self.T2I_image_msg(event, self.jx3api.zhuangtai) + + + async def jx3_shaohua(self, event: AstrMessageEvent,): + """剑三 骚话""" + return await self.plain_msg(event, self.jx3api.shaohua) + + + async def jx3_jigai(self, event: AstrMessageEvent,): + """剑三 技改""" + return await self.plain_msg(event, self.jx3api.jigai) + + + async def jx3_xinwen(self, event: AstrMessageEvent,num:int = 5): + """剑三 新闻""" + return await self.plain_msg(event, lambda: self.jx3api.xinwen(num)) + + + async def jx3_keju(self, event: AstrMessageEvent,subject: str, limit: int = 5): + """剑三 科举""" + return await self.plain_msg(event, lambda: self.jx3api.keju(subject,limit)) + + + async def jx3_huajia(self, event: AstrMessageEvent, name: str= "", server: str = "", map: str= ""): + """剑三 花价 名称 服务器 地图""" + return await self.T2I_image_msg(event, lambda: self.jx3api.huajia(self.serverdefault(server),name,map)) + + + async def jx3_zhuangshi(self, event: AstrMessageEvent, name: str): + """剑三 装饰 名称""" + return await self.T2I_image_msg(event, lambda: self.jx3api.zhuangshi(name)) + + + async def jx3_qiwu(self, event: AstrMessageEvent, name: str): + """剑三 器物 地图名称""" + return await self.T2I_image_msg(event, lambda: self.jx3api.qiwu(name)) + + + async def jx3_shapan(self, event: AstrMessageEvent,server: str = ""): + """剑三 沙盘 服务器""" + return await self.image_msg(event, lambda: self.jx3api.shapan(self.serverdefault(server))) + + + async def jx3_qufuqiyu(self, event: AstrMessageEvent,adventureName: str = "阴阳两界", server: str = ""): + """剑三 奇遇统计 奇遇名称 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.qiyu(adventureName,self.serverdefault(server))) + + + async def jx3_qiyugonglue(self, event: AstrMessageEvent,name: str): + """剑三 奇遇攻略 奇遇名称""" + return await self.T2I_image_msg(event, lambda: self.jx3api.qiyugonglue(name)) + + + async def jx3_hong(self, event: AstrMessageEvent,name: str = "易筋经"): + """剑三 宏 心法""" + return await self.handler_plain_image_msg(event, lambda: self.jx3api.hong1(name), self.jx3api.hong2) + + + async def jx3_peizhuang(self, event: AstrMessageEvent,name: str = "易筋经", tags: str = ""): + """剑三 配装 心法""" + return await self.plain_msg(event, lambda: self.jx3api.peizhuang( name,tags)) + + + async def jx3_jinjia(self, event: AstrMessageEvent,server: str = "", limit:str = "15"): + """剑三 金价 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.jinjia( self.serverdefault(server),limit)) + + + async def jx3_wujia(self, event: AstrMessageEvent,Name: str = "秃盒", server: str = ""): + """剑三 物价 外观名称""" + return await self.T2I_image_msg(event, lambda: self.jx3api.wujia(Name, self.serverdefault(server))) + + + async def jx3_jiaoyihang(self, event: AstrMessageEvent,Name: str = "守缺式",server: str = ""): + """剑三 交易行 物品名称 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.jiaoyihang(Name, self.serverdefault(server))) + + + async def jx3_jueshemingpian(self, event: AstrMessageEvent, name: str = "飞翔大野猪", server: str = ""): + """剑三 名片 角色 服务器""" + return await self.image_msg(event, lambda: self.jx3api.jueshemingpian( self.serverdefault(server),name)) + + + async def jx3_shuijimingpian(self, event: AstrMessageEvent,force: str = "万花", body: str = "萝莉", server: str = ""): + """剑三 随机名片 职业 体型 服务器""" + return await self.image_msg(event, lambda: self.jx3api.shuijimingpian(force,body, self.serverdefault(server))) + + + async def jx3_yanhuachaxun(self, event: AstrMessageEvent,name: str = "飞翔大野猪", server: str = ""): + """剑三 烟花 角色 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.yanhuachaxun( self.serverdefault(server),name)) + + + async def jx3_dilujilu(self, event: AstrMessageEvent,server: str = ""): + """剑三 的卢 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.dilujilu( self.serverdefault(server))) + + + async def jx3_tuanduizhaomu(self, event: AstrMessageEvent,keyword: str = "25人普通会战弓月城", server: str = ""): + """剑三 招募 副本 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.tuanduizhaomu( self.serverdefault(server),keyword)) + + + async def jx3_zhanji(self, event: AstrMessageEvent,name: str = "飞翔大野猪", server: str = "", mode:str = "33"): + """剑三 战绩 角色 服务器 类型""" + return await self.T2I_image_msg(event, lambda: self.jx3api.zhanji(name, self.serverdefault(server),mode)) + + + async def jx3_qiyu(self, event: AstrMessageEvent,name: str = "飞翔大野猪", server: str = ""): + """剑三 奇遇 角色名称 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.juesheqiyu(name, self.serverdefault(server))) + + + async def jx3_zhengyingpaimai(self, event: AstrMessageEvent,name: str = "玄晶", server: str = ""): + """剑三 阵营拍卖 物品名称 服务器""" + return await self.T2I_image_msg(event, lambda: self.jx3api.zhengyingpaimai( self.serverdefault(server), name)) + + + async def jx3_fuyaojjiutian(self, event: AstrMessageEvent,server: str = ""): + """剑三 扶摇九天 服务器""" + return await self.plain_msg(event, lambda: self.jx3api.fuyaojjiutian( self.serverdefault(server))) + + + async def jx3_shuma(self, event: AstrMessageEvent,server: str = ""): + """剑三 刷马 服务器""" + return await self.plain_msg(event, lambda: self.jx3api.shuma( self.serverdefault(server))) + + + async def jx3_pianzhi(self, event: AstrMessageEvent,qq: str): + """剑三 骗子 QQ""" + return await self.plain_msg(event, lambda: self.jx3api.pianzhi(qq)) + + + async def jx3_bagua(self, event: AstrMessageEvent,name: str = "818"): + """剑三 八卦 类型""" + return await self.plain_msg(event, lambda: self.jx3api.bagua(name)) + + + async def bilei_add(self, event: AstrMessageEvent,name: str, text: str): + """避雷添加 名称 备注""" + return await self.plain_msg(event, lambda: self.bilei.add(name,text,event.get_sender_name())) + + + async def bilei_all(self, event: AstrMessageEvent): + """避雷查看""" + return await self.T2I_image_msg(event, self.bilei.all) + + + async def bilei_select(self, event: AstrMessageEvent, name:str): + """避雷查询""" + return await self.T2I_image_msg(event, lambda: self.bilei.select(name)) + + + async def bilei_update(self, event: AstrMessageEvent, id:int, name: str, text: str): + """避雷修改 ID 名称 备注""" + return await self.plain_msg(event, lambda: self.bilei.update(id,name,text,event.get_sender_name())) + + + async def bilei_delete(self, event: AstrMessageEvent, id:int): + """避雷删除 ID""" + return await self.plain_msg(event, lambda: self.bilei.delete(id)) + + + async def jx3_kaifhujiank(self, event: AstrMessageEvent): + """剑三 开服监控""" + return_msg = await self.jx3at.get_task_info("kfts") + await event.send(event.plain_result(return_msg)) + + + async def jx3_xinwenzhixun(self, event: AstrMessageEvent): + """剑三 新闻推送""" + return_msg = await self.jx3at.get_task_info("xwts") + await event.send(event.plain_result(return_msg)) + + + async def jx3_shuamamsg(self, event: AstrMessageEvent): + """剑三 刷马推送""" + return_msg = await self.jx3at.get_task_info("smts") + await event.send(event.plain_result(return_msg)) + + + async def jx3_chitusg(self, event: AstrMessageEvent): + """剑三 赤兔推送""" + return_msg = await self.jx3at.get_task_info("ctts") + await event.send(event.plain_result(return_msg)) diff --git a/core/sqlite.py b/core/sqlite.py index 5d6a718..419574e 100644 --- a/core/sqlite.py +++ b/core/sqlite.py @@ -8,10 +8,18 @@ class AsyncSQLiteDB: def __init__(self, db_path: str = "data.db"): self.db_path = db_path self.conn: Optional[aiosqlite.Connection] = None + # ====================== # 生命周期 # ====================== + + async def __aenter__(self): + await self.connect() + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.close() async def connect(self): self.conn = await aiosqlite.connect(self.db_path) diff --git a/data/local_async.json b/data/local_async.json deleted file mode 100644 index 04568f3..0000000 --- a/data/local_async.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "kfjk": true, - "xwzx": 3174, - "smxx": 0, - "ctxx": 0 -} \ No newline at end of file diff --git a/data/sqlite.db b/data/plugin_data.db similarity index 97% rename from data/sqlite.db rename to data/plugin_data.db index 12df262..2b77b2e 100644 Binary files a/data/sqlite.db and b/data/plugin_data.db differ diff --git a/main.py b/main.py index d6117e9..137da81 100644 --- a/main.py +++ b/main.py @@ -1,73 +1,45 @@ -# pyright: reportOptionalMemberAccess=false - -import json -import shutil -import pathlib -import asyncio import inspect from pathlib import Path -from typing import Union -from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult, MessageChain +from astrbot.api.event import filter, AstrMessageEvent from astrbot.api.star import Context, Star, register, StarTools from astrbot.api import logger from astrbot.api import AstrBotConfig -from astrbot.core.utils.session_waiter import ( - SessionController, - session_waiter, -) from .core.sqlite import AsyncSQLiteDB from .core.jx3_data import JX3Service from .core.async_task import AsyncTask from .core.bilei_data import BiLeidata +from .core.message import MessageBuilder @register("astrbot_plugin_jx3", "fxdyz", - "通过接口调用剑网三API接口获取游戏数据,整理发送。", - "1.0.0", - "https://github.com/qsc20001102/astrbot_plugin_jx3api.git" + "通过调用剑网三API接口获取游戏数据,处理发送。", + "1.1.0", + "https://github.com/qsc20001102/astrbot_plugin_jx3api" ) class Jx3ApiPlugin(Star): def __init__(self, context: Context, config: AstrBotConfig): super().__init__(context) - #获取配置 + # 获取插件配置 self.conf = config - # 本地数据存储路径 - self.local_data_dir = StarTools.get_data_dir("astrbot_plugin_jx3") - # 插件数据存储路径 - self.data_file_path = Path(__file__).parent / "data" - - # SQLite本地路径 - self.sqlite_path = Path(self.local_data_dir) /"sqlite.db" - logger.info(f"本地数据文件路径:{self.sqlite_path}") - - # SQLite插件路径 - self.sqlite_plugin = Path(self.data_file_path) /"sqlite.db" - logger.info(f"插件数据文件路径:{self.sqlite_plugin}") - - # 读取API配置文件 - self.api_file_path = self.data_file_path / "api_config.json" - with open(self.api_file_path, 'r', encoding='utf-8') as f: - self.api_config = json.load(f) - - - # 初始化数据 - # 指令前缀功能 - self.prefix_en = self.conf.get("prefix").get("enable") - self.prefix_text = self.conf.get("prefix").get("text") - if not self.prefix_text: - self.prefix_text = "剑三" - if self.prefix_en: - logger.info(f"已启用指令前缀功能,前缀为:{self.prefix_text}") + # 指令前缀 + self.prefix = self.conf.get("prefix",{}) + if self.prefix.get("enable"): + logger.info(f"已启用指令前缀功能,前缀为:{self.prefix.get('text')}") else: logger.info(f"未启用指令前缀功能。") # 默认服务器 - self.server = self.conf.get("server", "梦江南") + self.server = self.conf.get("server","梦江南") logger.info(f"配置加载默认服务器:{self.server}") + # 获取数据文件路径 + self.get_data_path() + # 构造所有类 + self.create_all() + # 声明指令集 self.command_map = {} @@ -76,50 +48,21 @@ class Jx3ApiPlugin(Star): async def initialize(self): """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" - # --- 调用函数完成检查和复制 --- try: - loop = asyncio.get_running_loop() - self.file_local_data = await loop.run_in_executor( - None, - self.check_and_copy_db, - self.local_data_dir, - "local_async.json", - self.data_file_path - ) - except FileNotFoundError as e: - logger.critical(f"插件初始化失败:{e}") - raise + # 数据库初始化 + await self.init_bilei_data() + await self.init_tuishong_data() - try: - # sqlite 实例化 - self.sql_db = AsyncSQLiteDB(self.sqlite_path) # pyright: ignore[reportArgumentType] - await self.sql_db.connect() - await self.sql_db.execute(""" - CREATE TABLE IF NOT EXISTS bilei( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT, - text TEXT, - time TEXT, - user TEXT - ) - """) - self.sql_db_plugin = AsyncSQLiteDB(self.sqlite_plugin) # pyright: ignore[reportArgumentType] - await self.sql_db_plugin.connect() + # 连接插件数据 + await self.plugin_sql_db.connect() - # 避雷功能 实例化 - self.bilei = BiLeidata(self.sql_db) - - # 剑三功能 实例化 - self.jx3fun = JX3Service(self.api_config, self.conf, self.sql_db_plugin) - - # 后台推送 实例化 - self.at = AsyncTask(self.context, self.conf, self.jx3fun) - await self.at.init_tasks() + # 开启后台推送 + await self.jx3at.init_tasks() except Exception as e: - if hasattr(self, "at"): - await self.at.destroy() - logger.error(f"功能模块初始化失败: {e}") + if self.jx3at is not None: + await self.jx3at.destroy() + logger.exception("功能模块初始化失败") raise # 指令集 @@ -130,49 +73,135 @@ class Jx3ApiPlugin(Star): async def terminate(self): """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" - if self.at: - await self.at.destroy() - self.at = None - - if self.jx3fun: - await self.jx3fun.close() - self.jx3fun = None - - if self.sql_db: - await self.sql_db.close() - self.sql_db = None - - if self.sql_db_plugin: - await self.sql_db_plugin.close() - self.sql_db_plugin = None + + if self.jx3at: + await self.jx3at.destroy() + if self.jx3api: + await self.jx3api.close() + + if self.local_sql_db: + await self.local_sql_db.close() + + if self.plugin_sql_db: + await self.plugin_sql_db.close() + logger.info("jx3api插件已卸载/停用") - def check_and_copy_db(self, local_data_dir: Union[str, Path], db_filename: str, default_db_dir: Union[str, Path]) -> pathlib.Path: - """ - 检查本地数据目录中是否存在指定的数据库文件。 - 如果不存在,则从默认目录复制该文件。 - """ - # 目标路径 - target_dir = pathlib.Path(local_data_dir) - target_file_path = target_dir / db_filename - # 源文件路径 - source_file_path = pathlib.Path(default_db_dir) / db_filename - # 假设默认文件名为 local_data.db - if not target_file_path.exists(): - logger.warning(f"本地数据库文件 {target_file_path.name} 不存在,正在从默认位置复制...") - # 1. 确保目标文件夹存在 - target_dir.mkdir(parents=True, exist_ok=True) - # 2. 检查源文件是否存在 - if not source_file_path.exists(): - raise FileNotFoundError(f"默认数据库源文件未找到!请检查路径: {source_file_path}") - # 3. 复制文件 - shutil.copy(source_file_path, target_file_path) - logger.info(f"数据库文件已成功复制到: {target_file_path}") - else: - logger.info(f"本地数据库文件 {target_file_path} 已存在,跳过复制。") - return target_file_path + def get_data_path(self): + """获取数据文件路径""" + # 本地数据存储路径 + self.local_data_dir = StarTools.get_data_dir("astrbot_plugin_jx3") + # 插件数据存储路径 + self.plugin_data_dir = Path(__file__).parent / "data" + + # SQLite本地路径 + self.local_data_path = self.local_data_dir / "local_data.db" + # SQLite插件路径 + self.plugin_data_path = self.plugin_data_dir /"plugin_data.db" + # API配置文件路径 + self.api_data_path = self.plugin_data_dir / "api_config.json" + + # 数据路径打印 + logger.debug(f"本地数据路径: {self.local_data_path}") + logger.debug(f"插件数据路径: {self.plugin_data_path}") + logger.debug(f"API配置文件路径: {self.api_data_path}") + + + def create_all(self): + """构造所有类""" + # 数据库实例化 + self.local_sql_db = AsyncSQLiteDB(str(self.local_data_path)) + self.plugin_sql_db = AsyncSQLiteDB(str(self.plugin_data_path)) + + # 剑网三功能实例化 + self.bilei = BiLeidata(self.local_sql_db) + self.jx3api = JX3Service(str(self.api_data_path), self.conf, self.plugin_sql_db) + self.jx3at = AsyncTask(self.context, self.conf, self.jx3api, self.local_sql_db) + self.jx3cmd = MessageBuilder(self.server, self.jx3api, self.bilei, self.jx3at) + + + async def init_bilei_data(self): + """初始化避雷数据表""" + # 连接本地数据 + await self.local_sql_db.connect() + # 创建bilei表 + await self.local_sql_db.execute(""" + CREATE TABLE IF NOT EXISTS bilei( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + text TEXT, + time TEXT, + user TEXT + ) + """) + + + async def init_tuishong_data(self): + """初始化推送数据表""" + # 创建tuishong表 + await self.local_sql_db.execute(""" + CREATE TABLE IF NOT EXISTS tuishong ( + id INTEGER PRIMARY KEY CHECK (id = 1), + kfts INTEGER DEFAULT 1, + xwts INTEGER DEFAULT 0, + smts INTEGER DEFAULT 0, + ctts INTEGER DEFAULT 0 + ) + """) + await self.local_sql_db.execute(""" + INSERT OR IGNORE INTO tuishong (id) + VALUES (1) + """) + + + def ini_command_map(self): + """初始化指令集""" + self.command_map = { + "功能": self.jx3cmd.jx3_helps, + "日常": self.jx3cmd.jx3_richang, + "日常预测": self.jx3cmd.jx3_richangyuche, + "名望": self.jx3cmd.jx3_xingxiashijian, + "开服": self.jx3cmd.jx3_kaifu, + "全服状态": self.jx3cmd.jx3_zhuangtai, + "骚话": self.jx3cmd.jx3_shaohua, + "技改": self.jx3cmd.jx3_jigai, + "公告": self.jx3cmd.jx3_xinwen, + "科举": self.jx3cmd.jx3_keju, + "花价": self.jx3cmd.jx3_huajia, + "装饰": self.jx3cmd.jx3_zhuangshi, + "器物": self.jx3cmd.jx3_qiwu, + "沙盘": self.jx3cmd.jx3_shapan, + "统计": self.jx3cmd.jx3_qufuqiyu, + "攻略": self.jx3cmd.jx3_qiyugonglue, + "宏": self.jx3cmd.jx3_hong, + "配装": self.jx3cmd.jx3_peizhuang, + "金价": self.jx3cmd.jx3_jinjia, + "物价": self.jx3cmd.jx3_wujia, + "交易行": self.jx3cmd.jx3_jiaoyihang, + "名片": self.jx3cmd.jx3_jueshemingpian, + "随机名片": self.jx3cmd.jx3_shuijimingpian, + "烟花": self.jx3cmd.jx3_yanhuachaxun, + "的卢": self.jx3cmd.jx3_dilujilu, + "招募": self.jx3cmd.jx3_tuanduizhaomu, + "战绩": self.jx3cmd.jx3_zhanji, + "奇遇": self.jx3cmd.jx3_qiyu, + "拍卖": self.jx3cmd.jx3_zhengyingpaimai, + "扶摇九天": self.jx3cmd.jx3_fuyaojjiutian, + "刷马": self.jx3cmd.jx3_shuma, + "骗子": self.jx3cmd.jx3_pianzhi, + "八卦": self.jx3cmd.jx3_bagua, + "开服推送": self.jx3cmd.jx3_kaifhujiank, + "新闻推送": self.jx3cmd.jx3_xinwenzhixun, + "刷马推送": self.jx3cmd.jx3_shuamamsg, + "赤兔推送": self.jx3cmd.jx3_chitusg, + "避雷添加": self.jx3cmd.bilei_add, + "避雷查看": self.jx3cmd.bilei_all, + "避雷查询": self.jx3cmd.bilei_select, + "避雷修改": self.jx3cmd.bilei_update, + "避雷删除": self.jx3cmd.bilei_delete, + } def parse_message(self, text: str) -> list[str] | None: @@ -182,8 +211,8 @@ class Jx3ApiPlugin(Star): return None # 前缀模式 - if self.prefix_en: - prefix = self.prefix_text + if self.prefix.get("enable"): + prefix = self.prefix.get("text") if text.startswith(prefix): text = text[len(prefix):].strip() else: @@ -237,6 +266,8 @@ class Jx3ApiPlugin(Star): if not self.command_map: logger.debug("插件尚未初始化完成,忽略消息") return + + # 获取消息 parts = self.parse_message(event.message_str) if not parts: logger.debug("未触发指令,忽略消息") @@ -258,394 +289,8 @@ class Jx3ApiPlugin(Star): yield event.plain_result("参数错误或执行失败") - def ini_command_map(self): - """初始化指令集""" - self.command_map = { - "功能": self.jx3_helps, - "日常": self.jx3_richang, - "日常预测": self.jx3_richangyuche, - "名望": self.jx3_xingxiashijian, - "开服": self.jx3_kaifu, - "全服状态": self.jx3_zhuangtai, - "骚话": self.jx3_shaohua, - "技改": self.jx3_jigai, - "公告": self.jx3_xinwen, - "科举": self.jx3_keju, - "花价": self.jx3_huajia, - "装饰": self.jx3_zhuangshi, - "器物": self.jx3_qiwu, - "沙盘": self.jx3_shapan, - "奇遇统计": self.jx3_qufuqiyu, - "奇遇攻略": self.jx3_qiyugonglue, - "宏": self.jx3_hong, - "配装": self.jx3_peizhuang, - "金价": self.jx3_jinjia, - "物价": self.jx3_wujia, - "交易行": self.jx3_jiaoyihang, - "名片": self.jx3_jueshemingpian, - "随机名片": self.jx3_shuijimingpian, - "烟花": self.jx3_yanhuachaxun, - "的卢": self.jx3_dilujilu, - "招募": self.jx3_tuanduizhaomu, - "战绩": self.jx3_zhanji, - "奇遇": self.jx3_qiyu, - "阵营拍卖": self.jx3_zhengyingpaimai, - "扶摇九天": self.jx3_fuyaojjiutian, - "刷马": self.jx3_shuma, - "骗子": self.jx3_pianzhi, - "八卦": self.jx3_bagua, - "避雷添加": self.bilei_add, - "避雷查看": self.bilei_all, - "避雷查询": self.bilei_select, - "避雷修改": self.bilei_update, - "避雷删除": self.bilei_delete, - "开服监控": self.jx3_kaifhujiank, - "新闻推送": self.jx3_xinwenzhixun, - "刷马推送": self.jx3_shuamamsg, - "赤兔推送": self.jx3_chitusg, - } - def serverdefault(self,server): - """加载配置默认服务器""" - if server == "": - return self.server - return server - async def plain_msg(self, event: AstrMessageEvent, action): - """最终将数据整理成文本发送""" - data= await action() - try: - if data["code"] == 200: - await event.send( event.plain_result(data["data"])) - else: - await event.send(event.plain_result(data["msg"])) - except Exception as e: - logger.error(f"功能函数执行错误: {e}") - await event.send(event.plain_result("猪脑过载,请稍后再试")) - - - async def T2I_image_msg(self, event: AstrMessageEvent, action): - """最终将数据渲染成图片发送""" - data = await action() - try: - if data["code"] == 200: - url = await self.html_render(data["temp"], data["data"], options={}) - await event.send(event.image_result(url)) - else: - await event.send(event.plain_result(data["msg"])) - - except Exception as e: - logger.error(f"功能函数执行错误: {e}") - await event.send(event.plain_result("猪脑过载,请稍后再试")) - - - async def image_msg(self, event: AstrMessageEvent, action): - """最终将数据整理成图片发送""" - data = await action() - try: - if data["code"] == 200: - await event.send(event.image_result(data["data"])) - else: - await event.send(event.plain_result(data["msg"])) - - except Exception as e: - logger.error(f"功能函数执行错误: {e}") - await event.send(event.plain_result("猪脑过载,请稍后再试")) - - - async def handler_plain_image_msg(self, event: AstrMessageEvent, action1, action2): - """两轮会话消息发送通用,先文本列表等反馈序号在发送图片""" - # 会话触发 - try: - # 获取一轮数据 - data = await action1() - if data["code"] == 200: - # 发送一轮消息 - await event.send(event.plain_result(data["msg"])) - # 获取触发用户ID - user_id = event.get_sender_id() - - # 二轮会话流程 - @session_waiter(timeout=30) - async def macro_select_waiter(controller: SessionController,new_event: AstrMessageEvent): - # 跳过非触发用户消息 - if new_event.get_sender_id() != user_id: - return - # 获取用户消息 - msg = new_event.get_message_str().strip() - # 判断消息是否为数字 - if not msg.isdigit(): - await new_event.send( - MessageChain().message("输入异常,结束会话") - ) - controller.stop() - return - # 判断数字是否在有效值内 - num = int(msg) - if num < 1 or num > data["data"]["num"]: - await new_event.send( - MessageChain().message("无效序号,结束会话") - ) - controller.stop() - return - - # 获取二轮数据 - try: - data1 = await action2(data["data"]["list"][num]) - if data1["code"] != 200: - await new_event.send( - MessageChain().message("获取详细数据失败") - ) - controller.stop() - return - - # 消息拼接发送 - chain = MessageChain() - msg_text = data1["data"] - chain.message(msg_text) - if data1["temp"] != "": - url = await self.html_render(data1["temp"], {}, options={}) - chain.url_image(url) - await new_event.send(chain) - - except Exception as e: - logger.error(f"功能函数执行错误: {e}") - await new_event.send( - MessageChain().message("猪脑过载,请稍后再试") - ) - - controller.stop() - - # 二轮会话激活 - try: - await macro_select_waiter(event) - except TimeoutError: - await event.send(event.plain_result("选择超时,已结束会话")) - except Exception: - logger.error("宏选择发生异常", exc_info=True) - - else: - await event.send(event.plain_result(f"未搜索到相关内容")) - return - - except Exception as e: - logger.error(f"功能函数执行错误: {e}") - await event.send(event.plain_result("猪脑过载,请稍后再试")) - - - async def jx3_helps(self, event: AstrMessageEvent): - """剑三 功能""" - return await self.T2I_image_msg(event, self.jx3fun.helps) - - - async def jx3_richang(self, event: AstrMessageEvent,server: str = "" ,num: int = 0): - """剑三 日常 服务器 天数""" - return await self.plain_msg(event, lambda: self.jx3fun.richang(self.serverdefault(server),num)) - - - async def jx3_richangyuche(self, event: AstrMessageEvent): - """剑三 日常预测""" - return await self.T2I_image_msg(event, self.jx3fun.richangyuche) - - - async def jx3_xingxiashijian(self, event: AstrMessageEvent,name: str = "穹野卫"): - """剑三 名望""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.xingxiashijian(name)) - - - async def jx3_kaifu(self, event: AstrMessageEvent,server: str = ""): - """剑三 开服 服务器""" - return await self.plain_msg(event, lambda: self.jx3fun.kaifu(self.serverdefault(server))) - - - async def jx3_zhuangtai(self, event: AstrMessageEvent): - """剑三 状态""" - return await self.T2I_image_msg(event, self.jx3fun.zhuangtai) - - - async def jx3_shaohua(self, event: AstrMessageEvent,): - """剑三 骚话""" - return await self.plain_msg(event, self.jx3fun.shaohua) - - - async def jx3_jigai(self, event: AstrMessageEvent,): - """剑三 技改""" - return await self.plain_msg(event, self.jx3fun.jigai) - - - async def jx3_xinwen(self, event: AstrMessageEvent,num:int = 5): - """剑三 新闻""" - return await self.plain_msg(event, lambda: self.jx3fun.xinwen(num)) - - - async def jx3_keju(self, event: AstrMessageEvent,subject: str, limit: int = 5): - """剑三 科举""" - return await self.plain_msg(event, lambda: self.jx3fun.keju(subject,limit)) - - - async def jx3_huajia(self, event: AstrMessageEvent, name: str= "", server: str = "", map: str= ""): - """剑三 花价 名称 服务器 地图""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.huajia(self.serverdefault(server),name,map)) - - - async def jx3_zhuangshi(self, event: AstrMessageEvent, name: str): - """剑三 装饰 名称""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.zhuangshi(name)) - - - async def jx3_qiwu(self, event: AstrMessageEvent, name: str): - """剑三 器物 地图名称""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.qiwu(name)) - - - async def jx3_shapan(self, event: AstrMessageEvent,server: str = ""): - """剑三 沙盘 服务器""" - return await self.image_msg(event, lambda: self.jx3fun.shapan(self.serverdefault(server))) - - - async def jx3_qufuqiyu(self, event: AstrMessageEvent,adventureName: str = "阴阳两界", server: str = ""): - """剑三 奇遇统计 奇遇名称 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.qiyu(adventureName,self.serverdefault(server))) - - - async def jx3_qiyugonglue(self, event: AstrMessageEvent,name: str): - """剑三 奇遇攻略 奇遇名称""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.qiyugonglue(name)) - - - async def jx3_hong(self, event: AstrMessageEvent,name: str = "易筋经"): - """剑三 宏 心法""" - return await self.handler_plain_image_msg(event, lambda: self.jx3fun.hong1(name), self.jx3fun.hong2) - - - async def jx3_peizhuang(self, event: AstrMessageEvent,name: str = "易筋经", tags: str = ""): - """剑三 配装 心法""" - return await self.plain_msg(event, lambda: self.jx3fun.peizhuang( name,tags)) - - - async def jx3_jinjia(self, event: AstrMessageEvent,server: str = "", limit:str = "15"): - """剑三 金价 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.jinjia( self.serverdefault(server),limit)) - - - async def jx3_wujia(self, event: AstrMessageEvent,Name: str = "秃盒", server: str = ""): - """剑三 物价 外观名称""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.wujia(Name, self.serverdefault(server))) - - - async def jx3_jiaoyihang(self, event: AstrMessageEvent,Name: str = "守缺式",server: str = ""): - """剑三 交易行 物品名称 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.jiaoyihang(Name, self.serverdefault(server))) - - - async def jx3_jueshemingpian(self, event: AstrMessageEvent, name: str = "飞翔大野猪", server: str = ""): - """剑三 名片 角色 服务器""" - return await self.image_msg(event, lambda: self.jx3fun.jueshemingpian( self.serverdefault(server),name)) - - - async def jx3_shuijimingpian(self, event: AstrMessageEvent,force: str = "万花", body: str = "萝莉", server: str = ""): - """剑三 随机名片 职业 体型 服务器""" - return await self.image_msg(event, lambda: self.jx3fun.shuijimingpian(force,body, self.serverdefault(server))) - - - async def jx3_yanhuachaxun(self, event: AstrMessageEvent,name: str = "飞翔大野猪", server: str = ""): - """剑三 烟花 角色 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.yanhuachaxun( self.serverdefault(server),name)) - - - async def jx3_dilujilu(self, event: AstrMessageEvent,server: str = ""): - """剑三 的卢 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.dilujilu( self.serverdefault(server))) - - - async def jx3_tuanduizhaomu(self, event: AstrMessageEvent,keyword: str = "25人普通会战弓月城", server: str = ""): - """剑三 招募 副本 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.tuanduizhaomu( self.serverdefault(server),keyword)) - - - async def jx3_zhanji(self, event: AstrMessageEvent,name: str = "飞翔大野猪", server: str = "", mode:str = "33"): - """剑三 战绩 角色 服务器 类型""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.zhanji(name, self.serverdefault(server),mode)) - - - async def jx3_qiyu(self, event: AstrMessageEvent,name: str = "飞翔大野猪", server: str = ""): - """剑三 奇遇 角色名称 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.juesheqiyu(name, self.serverdefault(server))) - - - async def jx3_zhengyingpaimai(self, event: AstrMessageEvent,name: str = "玄晶", server: str = ""): - """剑三 阵营拍卖 物品名称 服务器""" - return await self.T2I_image_msg(event, lambda: self.jx3fun.zhengyingpaimai( self.serverdefault(server), name)) - - - async def jx3_fuyaojjiutian(self, event: AstrMessageEvent,server: str = ""): - """剑三 扶摇九天 服务器""" - return await self.plain_msg(event, lambda: self.jx3fun.fuyaojjiutian( self.serverdefault(server))) - - - async def jx3_shuma(self, event: AstrMessageEvent,server: str = ""): - """剑三 刷马 服务器""" - return await self.plain_msg(event, lambda: self.jx3fun.shuma( self.serverdefault(server))) - - - async def jx3_pianzhi(self, event: AstrMessageEvent,qq: str): - """剑三 骗子 QQ""" - return await self.plain_msg(event, lambda: self.jx3fun.pianzhi(qq)) - - - async def jx3_bagua(self, event: AstrMessageEvent,name: str = "818"): - """剑三 八卦 类型""" - return await self.plain_msg(event, lambda: self.jx3fun.bagua(name)) - - - async def bilei_add(self, event: AstrMessageEvent,name: str, text: str): - """避雷添加 名称 备注""" - return await self.plain_msg(event, lambda: self.bilei.add(name,text,event.get_sender_name())) - - - async def bilei_all(self, event: AstrMessageEvent): - """避雷查看""" - return await self.T2I_image_msg(event, self.bilei.all) - - - async def bilei_select(self, event: AstrMessageEvent, name:str): - """避雷查询""" - return await self.T2I_image_msg(event, lambda: self.bilei.select(name)) - - - async def bilei_update(self, event: AstrMessageEvent, id:int, name: str, text: str): - """避雷修改 ID 名称 备注""" - return await self.plain_msg(event, lambda: self.bilei.update(id,name,text,event.get_sender_name())) - - - async def bilei_delete(self, event: AstrMessageEvent, id:int): - """避雷删除 ID""" - return await self.plain_msg(event, lambda: self.bilei.delete(id)) - - - async def jx3_kaifhujiank(self, event: AstrMessageEvent): - """剑三 开服监控""" - return_msg = await self.at.get_task_info("kfjk") - await event.send(event.plain_result(return_msg)) - - - async def jx3_xinwenzhixun(self, event: AstrMessageEvent): - """剑三 新闻推送""" - return_msg = await self.at.get_task_info("xwzx") - await event.send(event.plain_result(return_msg)) - - - async def jx3_shuamamsg(self, event: AstrMessageEvent): - """剑三 刷马推送""" - return_msg = await self.at.get_task_info("smxx") - await event.send(event.plain_result(return_msg)) - - - async def jx3_chitusg(self, event: AstrMessageEvent): - """剑三 赤兔推送""" - return_msg = await self.at.get_task_info("ctxx") - await event.send(event.plain_result(return_msg)) - diff --git a/metadata.yaml b/metadata.yaml index 4711280..ddfac92 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -1,6 +1,6 @@ name: astrbot_plugin_jx3 display_name: 剑网三游戏数据查询工具 -desc: 通过接口调用剑网三API接口获取游戏数据 -version: v1.0.0 +desc: 通过接口调用剑网三API接口获取游戏数据,处理发送。 +version: v1.1.0 author: 飞翔大野猪 repo: https://github.com/qsc20001102/astrbot_plugin_jx3 diff --git a/templates/helps.html b/templates/helps.html index a57ec1f..90d8406 100644 --- a/templates/helps.html +++ b/templates/helps.html @@ -1,127 +1,118 @@ - - 剑三插件功能 - +@media (max-width: 900px) { + .command { + grid-template-columns: 1fr; + gap: 10px; + } +} + @@ -132,76 +123,88 @@

astrbot_plugin_jx3 指令说明与使用示例

+
-
基础功能
-
-
日常活动
日常 [服务器] [天数]
-
日常预测
日常预测
-
名望事件
名望 [穹野卫]
-
开服查询
开服 [服务器]
-
全服状态
全服状态 [服务器]
-
随机骚话
骚话
-
最新技改
技改
-
官方公告
公告 [数量]
-
科举答题
科举 内容
-
家园鲜花
花价 名称 [服务器] [家园地图]
-
家园装饰
装饰 名称
-
器物图谱
器物 地图名称
-
阵营沙盘
沙盘 [服务器]
-
奇遇统计
奇遇统计 奇遇名称 [服务器]
-
奇遇攻略
奇遇攻略 奇遇名称
-
魔盒宏
宏 心法
-
魔盒配装
配装 心法 筛选
-
+
基础功能
+
+ +
日常活动
日常 [服务器] [天数]
天数:0今天 1明天 2后天
+
日常预测
日常预测
当前日期前后15天日常
+
名望事件
名望 [穹野卫]
楚天社 云从社 披风会 穹野卫
+
开服查询
开服 [服务器]
+
全服状态
全服状态 [服务器]
+
随机骚话
骚话
+
最新技改
技改
+
官方公告
公告 [数量]
获取最新官方公告,数量默认为5条
+
科举答题
科举 内容
+
家园鲜花
花价 名称 [服务器] [家园地图]
+
家园装饰
装饰 名称
+
器物图谱
器物 地图名称
+
阵营沙盘
沙盘 [服务器]
+
奇遇统计
统计 奇遇名称 [服务器]
统计指定奇遇触发次数
+
奇遇攻略
攻略 奇遇名称
+
魔盒宏
宏 心法
查询指定心法推荐宏设置
+
魔盒配装
配装 心法 [筛选]
PvP PvE
+ +
+
-
进阶功能
-
-
金价查询
金价 [服务器]
-
外观物价
物价 外观名称 [服务器]
-
交易行
交易行 物品名称 [服务器]
-
角色名片
名片 角色名 [服务器]
-
随机名片
随机名片 职业 体型 [服务器]
-
烟花记录
烟花 角色名 [服务器]
-
的卢记录
的卢 [服务器]
-
副本招募
招募 副本名称 [服务器]
-
角色战绩
战绩 角色名 [服务器]
-
角色奇遇
奇遇 角色名 [服务器]
-
阵营拍卖
阵营拍卖 物品名称 [服务器]
-
扶摇九天
扶摇九天 [服务器]
-
刷马
刷马 [服务器]
-
骗子查询
骗子 QQ号
-
八卦记录
八卦 类型
-
+
进阶功能
+
+ +
金价查询
金价 [服务器]
+
外观物价
物价 外观名称 [服务器]
+
交易行
交易行 物品名称 [服务器]
+
角色名片
名片 角色名 [服务器]
+
随机名片
随机名片 职业 体型 [服务器]
+
烟花记录
烟花 角色名 [服务器]
+
的卢记录
的卢 [服务器]
+
副本招募
招募 副本名称 [服务器]
+
角色战绩
战绩 角色名 [服务器]
33
+
角色奇遇
奇遇 角色名 [服务器]
+
阵营拍卖
拍卖 物品名称 [服务器]
+
扶摇九天
扶摇九天 [服务器]
+
刷马
刷马 [服务器]
+
骗子查询
骗子 QQ号
+
八卦记录
八卦 类型
818 616 避雷
+ +
+
-
推送功能
-
-
开服监控
开服监控
-
新闻推送
新闻推送
-
刷马推送
刷马推送
-
赤兔推送
赤兔推送
-
+
推送功能
+
+ +
开服推送
开服推送
+
新闻推送
新闻推送
+
刷马推送
刷马推送
+
赤兔推送
赤兔推送
+ +
+
-
避雷功能
-
-
避雷查看
避雷查看
-
避雷添加
避雷添加 名称 备注
-
避雷删除
避雷删除 ID
-
避雷修改
避雷修改 ID 名称 备注
-
避雷查询
避雷查询 名称
-
+
避雷功能
+
+ +
避雷查看
避雷查看
+
避雷添加
避雷添加 名称 备注
+
避雷删除
避雷删除 ID
+
避雷修改
避雷修改 ID 名称 备注
+
避雷查询
避雷查询 名称
+ +
- 使用提示:
- 1. 中括号参数为可选内容,不填写则使用程序默认值
- 2. 未填写服务器时将使用配置中的默认服务器
- 3. 基础指令无需 token 可直接使用 +使用提示:
+1. 中括号参数为可选内容,不填写则使用程序默认值
+2. 未填写服务器时将使用配置中的默认服务器
+3. 基础指令无需 token 可直接使用