diff --git a/CHANGELOG.md b/CHANGELOG.md index 05caa30..d8c94d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ ## 更新记录 +### version: 3.4.4(2026-09-05): + +烟花查询在角色名称后新增可选的“条数”参数,默认展示前 50 条,支持指定正整数条数;沿用已绑定会话省略服务器的用法,并同步更新功能帮助和 README。上游接口未提供条数参数,查询结果在本地截取后生成图片。 + +修复绑定区服后,省略服务器并填写后续可选参数时被误判为显式服务器的问题;例如 `战绩 晏卿卿 22` 现在会正确补齐绑定区服,并按角色“晏卿卿”、模式“22”查询。 + +修复名剑战绩模板固定读取 `performance['3v3']`,导致 `22` 和 `55` 模式渲染失败的问题;现在会按查询模式分别使用 `2v2`、`3v3`、`5v5` 表现数据。 + +名剑战绩的对战记录按胜负统一整行文本颜色,胜利显示绿色,失败显示红色。 + +名剑排行榜的门派列复用名剑统计的图标样式,在门派名称前显示对应门派图标。 + +心法别名接入全局指令参数解析:试炼排行、阵眼、配装、技能、奇穴、小药和宏会在调用业务接口前将标准名称或别名统一转换为标准心法名;WebUI 保存或恢复别名后会立即刷新解析缓存,门派筛选参数保持原义。 + ### version: 3.4.3(2026-09-05): 接入 JX3API `POST /token/stats` 令牌统计接口,使用插件配置的 `jx3api_token` 查询等级、已用次数、剩余次数和有效状态;WebUI 顶部恢复为四项令牌统计,接口不可用或未配置令牌时显示未获取状态且不影响其他管理数据。 diff --git a/README.md b/README.md index 23e72e8..1e22ae4 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ JX3API Token 可从 [JX3API](https://www.jx3api.com/) 获取。推栏 Ticket 通 - 缺少必填参数、数字转换失败或执行异常时,入口层统一回复 `参数错误或执行失败`。 - 未绑定区服时按指令表提供标准参数。绑定后可以省略 `server` 参数;显式填写完整参数时仍优先使用本次输入的区服。在区服参数位置填写 `全区` 时,会忽略会话绑定并向接口传入空区服以查询全区数据。 - 标准区服名和 WebUI 中配置的别名都可用于查询。对于区服后的可选参数,分发器通过当前有效区服目录和别名判断首个参数是显式区服还是后续参数。 +- 心法类指令会在入口层把标准心法名或 WebUI 配置的心法别名统一解析为标准名称;当前适用于试炼排行、阵眼、配装、技能、奇穴、小药和宏。门派筛选参数不参与心法别名解析。 ### 会话区服绑定 @@ -154,7 +155,7 @@ JX3API Token 可从 [JX3API](https://www.jx3api.com/) 获取。推栏 Ticket 通 | `关隘` | 查询关隘首领状态;图片 | Token | | `赤兔`、`本周赤兔` | 查询当日或本周赤兔记录;文本 | Token | | `阵营奉献 [阵营]` | 查询阵营奉献事件,固定最多 50 条;图片 | Token | -| `烟花 服务器 [角色]` | 查询指定服务器的烟花记录;已绑定会话可省略服务器;图片 | Token | +| `烟花 服务器 角色 [条数]` | 查询指定服务器的烟花记录;条数默认为 50,须为正整数,填写时放在角色名称后;已绑定会话可省略服务器;图片 | Token | | `刷马 服务器` | 查询刷马聊天情报;文本 | Token | | `马场 服务器` | 查询未过期马场记录;文本 | Token | @@ -162,7 +163,7 @@ JX3API Token 可从 [JX3API](https://www.jx3api.com/) 获取。推栏 Ticket 通 | 指令 | 说明与输出 | 凭据 | | --- | --- | --- | -| `战绩 服务器 角色 [模式]` | 角色名剑战绩,模式默认 `33`;图片 | Token + Ticket | +| `战绩 服务器 角色 [模式]` | 角色名剑战绩,模式可选 `22`、`33`、`55`,默认 `33`;图片 | Token + Ticket | | `名剑排行 [模式] [数量]` | 名剑大会排行,默认 `33`、50 条;图片 | Token + Ticket | | `名剑统计 [模式]` | 名剑门派统计,模式默认 `33`;图片 | Token + Ticket | | `帮会排行 服务器` | 回复序号选择神兵宝甲或爱心帮会榜单,最多保留前 50 条;图片 | Token | @@ -348,8 +349,9 @@ flowchart LR 1. `parse_message()` 检查前缀并使用 `str.split()` 切分消息。 2. 第一段作为指令,其余段作为位置参数。 3. `command_map` 将中文触发词映射到 `MessageBuilder` 方法。 -4. `_call_with_auto_args()` 通过 `inspect.signature()` 读取参数签名,按注解转换 `int` 和 `float`。 -5. 找不到指令时忽略消息;找到指令后停止事件继续传播并调用处理器。 +4. `_prepare_server_args()` 和 `_prepare_kungfu_args()` 根据处理器参数名统一补齐区服绑定并解析区服、心法别名。 +5. `_call_with_auto_args()` 通过 `inspect.signature()` 读取参数签名,按注解转换 `int` 和 `float`。 +6. 找不到指令时忽略消息;找到指令后停止事件继续传播并调用处理器。 分发器不会检查多余参数,多出的参数会被忽略。缺少必填参数会抛出异常并返回统一错误提示。 @@ -474,7 +476,7 @@ astrbot_plugin_jx3/ │ ├── session_control.py # 全部会话、白名单与黑名单访问策略 │ ├── webui.py # 插件管理页路由、数据聚合与请求处理 │ ├── server_binding.py # 会话区服绑定、别名与区服目录 -│ ├── kungfu_alias.py # 本地心法目录初始化、校验与 WebUI 写入 +│ ├── kungfu_alias.py # 本地心法目录初始化、全局别名解析、校验与 WebUI 写入 │ ├── bilei_data.py # 避雷数据增删改查 │ ├── sqlite.py # aiosqlite 通用封装 │ ├── fun_basic.py # 图标、时间和货币格式化工具 @@ -520,7 +522,7 @@ git diff --check ## 当前版本状态 -以下内容是对 v3.4.3 当前源码的静态核对结果,部署和二次开发前应注意: +以下内容是对 v3.4.4 当前源码的静态核对结果,部署和二次开发前应注意: 1. 查询图片使用浅色高对比主题和放大的内容区域;渲染清晰度、JPEG/PNG 格式及 JPEG 质量由 `image_render_quality` 配置组控制,提高清晰度或使用 PNG 会增加图片体积与渲染耗时。 2. `帮会排行`、`阵营排行`、`其他排行` 使用固定的“数字序号 → 榜单名称”首轮菜单,次轮查询统一截取接口返回的前 50 条;取得有效选择后会先停止超时计时器,避免渲染期间重复输出。 diff --git a/core/jx3api_data.py b/core/jx3api_data.py index 845316a..4bf0cb6 100644 --- a/core/jx3api_data.py +++ b/core/jx3api_data.py @@ -451,10 +451,11 @@ class JX3APIService: ) - async def yanhuachaxun(self, server: str, name:str ) -> Dict[str, Any]: + 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")) @@ -511,7 +512,13 @@ class JX3APIService: async def zhanji(self, name: str, server:str, mode:str) -> Dict[str, Any]: """战绩""" # 数据处理 - async def processor(data: Any, return_data: Dict[str, Any]) -> None: + 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( diff --git a/core/kungfu_alias.py b/core/kungfu_alias.py index b113b99..1536427 100644 --- a/core/kungfu_alias.py +++ b/core/kungfu_alias.py @@ -13,6 +13,7 @@ class KungfuAliasService: def __init__(self, sqlite: AsyncSQLiteDB, seed_path: Path): self.sql = sqlite self.seed_path = seed_path + self._kungfu_lookup: dict[str, str] = {} async def initialize(self): await self.sql.execute( @@ -29,6 +30,7 @@ class KungfuAliasService: """ ) await self._seed_defaults() + await self._reload_cache() async def _seed_defaults(self): records = self._load_seed_defaults() @@ -84,6 +86,7 @@ class KungfuAliasService: for values in records ) await self.sql.execute_transaction(statements) + await self._reload_cache() return len(records) async def list_kungfu(self) -> list[dict[str, Any]]: @@ -141,6 +144,36 @@ class KungfuAliasService: """, (*values, normalized_pzid), ) + await self._reload_cache() + + async def _reload_cache(self): + """Refresh the canonical kungfu name and alias lookup cache. + + Returns: + None. + """ + rows = await self.list_kungfu() + lookup = { + self._key(row["name"]): row["name"] + for row in rows + if row["name"] + } + for row in rows: + for alias in row["aliases"]: + lookup.setdefault(self._key(alias), row["name"]) + self._kungfu_lookup = lookup + + def resolve_kungfu(self, value: Any) -> str: + """Resolve a canonical kungfu name or alias to its canonical name. + + Args: + value: Canonical kungfu name or configured alias. + + Returns: + Canonical kungfu name when matched; otherwise the cleaned input. + """ + kungfu = self._clean(value) + return self._kungfu_lookup.get(self._key(kungfu), kungfu) def _normalize_aliases(self, name: str, aliases: Iterable[Any]) -> list[str]: result: list[str] = [] diff --git a/core/message.py b/core/message.py index 5d933e2..de0cc6f 100644 --- a/core/message.py +++ b/core/message.py @@ -321,9 +321,13 @@ class MessageBuilder: """ 阵营事件 阵营""" return await self.T2I_image_msg(event, lambda: self.jx3api.zhenyingevent(name,50)) - async def yanhuachaxun(self, event: AstrMessageEvent,server: str,name: str = "" ): - """ 烟花 服务器 角色""" - return await self.T2I_image_msg(event, lambda: self.jx3api.yanhuachaxun(server,name)) + async def yanhuachaxun(self, event: AstrMessageEvent, server: str, name: str = "", limit: int = 50): + """ 烟花 服务器 角色 条数""" + if limit <= 0: + return event.plain_result("条数必须为正整数") + return await self.T2I_image_msg( + event, lambda: self.jx3api.yanhuachaxun(server, name, limit) + ) async def shuma(self, event: AstrMessageEvent,server: str ): """ 刷马 服务器""" @@ -369,9 +373,9 @@ class MessageBuilder: lambda selected: self.jx3api.rank_statistical_select(server,selected,), ) - async def shilianpaixing(self, event: AstrMessageEvent, server: str , name: str): + async def shilianpaixing(self, event: AstrMessageEvent, server: str , kungfu: str): """ 试炼排行 服务器 心法 """ - return await self.T2I_image_msg(event, lambda: self.jx3api.shilianpaixing(name, server)) + return await self.T2I_image_msg(event, lambda: self.jx3api.shilianpaixing(kungfu, server)) async def zhengyingpaimai(self, event: AstrMessageEvent,server: str , name: str = "", limit: int = 50 ): """ 阵营拍卖 物品名称 服务器""" @@ -465,25 +469,25 @@ class MessageBuilder: """ 角色 服务器 名称 """ return await self.plain_msg(event, lambda: self.jx3api.jueshe(server, name, 1)) - async def zhenyan(self, event: AstrMessageEvent, name: str): + async def zhenyan(self, event: AstrMessageEvent, kungfu: str): """ 阵眼 心法""" - return await self.plain_msg(event, lambda: self.jx3api.zhenyan(name)) + return await self.plain_msg(event, lambda: self.jx3api.zhenyan(kungfu)) - async def peizhuang(self, event: AstrMessageEvent,name: str, tags: str = ""): + async def peizhuang(self, event: AstrMessageEvent, kungfu: str, tags: str = ""): """ 配装 心法 类型""" - return await self.plain_msg(event, lambda: self.jx3box.peizhuang(name,tags)) + return await self.plain_msg(event, lambda: self.jx3box.peizhuang(kungfu,tags)) async def zilipaixing(self, event: AstrMessageEvent, server: str = "", school: str = ""): """ 资历排行 服务器 门派 """ return await self.T2I_image_msg(event, lambda: self.jx3api.zilipaixing(server, school)) - async def jineng(self, event: AstrMessageEvent, name: str): + async def jineng(self, event: AstrMessageEvent, kungfu: str): """ 技能 心法""" - return await self.T2I_image_msg(event, lambda: self.jx3api.jineng(name,0)) + return await self.T2I_image_msg(event, lambda: self.jx3api.jineng(kungfu,0)) - async def qixue(self, event: AstrMessageEvent, name: str): + async def qixue(self, event: AstrMessageEvent, kungfu: str): """ 奇穴 心法""" - return await self.T2I_image_msg(event, lambda: self.jx3api.qixue(name,0)) + return await self.T2I_image_msg(event, lambda: self.jx3api.qixue(kungfu,0)) async def liaotian(self, event: AstrMessageEvent, server:str, name: str, limit:int = 20, page:int = 1): """ 发言 服务器 角色 条数 页数""" @@ -493,9 +497,9 @@ class MessageBuilder: """ 统战 服务器""" return await self.plain_msg(event, lambda: self.jx3api.tongzhanyy(server)) - async def xiaoyao(self, event: AstrMessageEvent, name:str = ""): + async def xiaoyao(self, event: AstrMessageEvent, kungfu:str = ""): """ 小药 心法""" - return await self.T2I_image_msg(event, lambda: self.jx3api.xiaoyao(name)) + return await self.T2I_image_msg(event, lambda: self.jx3api.xiaoyao(kungfu)) async def pianzhi(self, event: AstrMessageEvent, uid: str, server:str = ""): """ 骗子 uid 服务器""" @@ -618,12 +622,12 @@ class MessageBuilder: return await self.T2I_image_msg(event, lambda: self.jx3api.diaoluo(name, server, limit)) - async def hong(self, event: AstrMessageEvent,name: str): + async def hong(self, event: AstrMessageEvent, kungfu: str): """ 宏 心法""" return await self.handler_plain_image_msg( event, - lambda: self.jx3box.hong1(name), - lambda selected: self.jx3box.hong_select(name, selected), + lambda: self.jx3box.hong1(kungfu), + lambda selected: self.jx3box.hong_select(kungfu, selected), result_handler=self.plain_image_msg, ) diff --git a/main.py b/main.py index 98f5c74..4073b23 100644 --- a/main.py +++ b/main.py @@ -25,7 +25,7 @@ PLUGIN_NAME = "astrbot_plugin_jx3" @register("astrbot_plugin_jx3", "fxdyz", "聚合剑网三游戏数据,提供查询、图片渲染、本地避雷和实时事件推送。", - "3.4.3", + "3.4.4", "https://github.com/qsc20001102/astrbot_plugin_jx3" ) class Jx3ApiPlugin(Star): @@ -407,14 +407,6 @@ class Jx3ApiPlugin(Star): has_server_arg = server_index < len(prepared) if bound_server: - required_count = sum( - parameter.default is inspect.Parameter.empty - for parameter in params - ) - has_required_parameter_after_server = any( - parameter.default is inspect.Parameter.empty - for parameter in params[server_index + 1:] - ) explicit_server = ( has_server_arg and ( @@ -422,11 +414,6 @@ class Jx3ApiPlugin(Star): prepared[server_index] ) or self.server_binding.is_known_server(prepared[server_index]) - or len(prepared) >= len(params) - or ( - has_required_parameter_after_server - and len(prepared) >= required_count - ) ) ) if explicit_server: @@ -442,6 +429,34 @@ class Jx3ApiPlugin(Star): return prepared + def _prepare_kungfu_args(self, handler, args: list[str]) -> list[str]: + """Resolve the kungfu parameter through the global alias catalog. + + Args: + handler: Command handler whose signature defines argument positions. + args: Positional command arguments after server preparation. + + Returns: + Arguments with a recognized kungfu alias replaced by its canonical name. + """ + params = [ + parameter + for parameter in inspect.signature(handler).parameters.values() + if parameter.name not in {"self", "event"} + ] + kungfu_index = next( + (index for index, parameter in enumerate(params) if parameter.name == "kungfu"), + None, + ) + if kungfu_index is None or kungfu_index >= len(args): + return args + + prepared = list(args) + prepared[kungfu_index] = self.kungfu_alias.resolve_kungfu( + prepared[kungfu_index] + ) + return prepared + async def _call_with_auto_args(self, handler, event: AstrMessageEvent, args: list[str]): """指令执行函数""" @@ -511,6 +526,7 @@ class Jx3ApiPlugin(Star): try: args = await self._prepare_server_args(handler, event, args) + args = self._prepare_kungfu_args(handler, args) ret = await self._call_with_auto_args(handler, event, args) if ret is not None: yield ret diff --git a/metadata.yaml b/metadata.yaml index 612b11c..760b859 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -1,7 +1,7 @@ name: astrbot_plugin_jx3 display_name: 剑网三游戏数据查询工具 desc: 聚合剑网三游戏数据,提供查询、图片渲染、本地避雷和实时事件推送。 -version: 3.4.3 +version: 3.4.4 author: 飞翔大野猪 repo: https://github.com/qsc20001102/astrbot_plugin_jx3 astrbot_version: ">=4.24.1" diff --git a/templates/pages/helps.html b/templates/pages/helps.html index 995398e..167444d 100644 --- a/templates/pages/helps.html +++ b/templates/pages/helps.html @@ -24,7 +24,7 @@
关隘赤兔本周赤兔阵营奉献 [阵营]烟花 服务器 角色烟花 服务器 [角色] [条数]刷马 服务器马场 服务器