11
This commit is contained in:
+255
-66
@@ -23,23 +23,24 @@ EVENT_NAMES = {
|
||||
1001: "奇遇触发",
|
||||
1002: "马驹刷新",
|
||||
1003: "马驹捕获",
|
||||
1004: "扶摇预告",
|
||||
1005: "扶摇开启",
|
||||
1006: "扶摇点名",
|
||||
1008: "的卢每日",
|
||||
1007: "烟花报时",
|
||||
1008: "的卢预告",
|
||||
1009: "的卢刷新",
|
||||
1010: "的卢捕获",
|
||||
1011: "的卢拍卖",
|
||||
1012: "副本掉落 / 私货",
|
||||
1012: "玄晶报时",
|
||||
1013: "阵营拍卖",
|
||||
1014: "诛恶事件",
|
||||
1015: "追魂点名",
|
||||
1017: "阵营祭祀",
|
||||
1018: "关隘首领",
|
||||
1016: "阵营祭天预告",
|
||||
1017: "阵营祭天终点",
|
||||
1101: "领地宣战·开始",
|
||||
1102: "领地宣战·结束",
|
||||
1103: "帮会宣战·开始",
|
||||
1104: "帮会宣战·结束",
|
||||
1105: "帮会约战·完胜",
|
||||
1108: "帮会野外宣战·开始",
|
||||
1109: "帮会野外宣战·结束",
|
||||
1111: "抢占粮仓",
|
||||
1112: "大旗重置",
|
||||
1113: "大旗被夺",
|
||||
@@ -52,16 +53,237 @@ EVENT_NAMES = {
|
||||
1120: "小攻防分红",
|
||||
1121: "大攻防分红",
|
||||
1122: "大攻防分红(含指挥)",
|
||||
1201: "微博更新",
|
||||
2001: "开服状态",
|
||||
2002: "官方新闻",
|
||||
2003: "版本更新",
|
||||
2004: "八卦速报",
|
||||
2005: "关隘首领",
|
||||
2006: "云从预告",
|
||||
2006: "云丛预告",
|
||||
}
|
||||
EVENT_ACTIONS = tuple(EVENT_NAMES)
|
||||
|
||||
SERVER_FIELDS = (
|
||||
("大区", "zone", "text"),
|
||||
("服务器", "server", "text"),
|
||||
)
|
||||
EVENT_FIELDS = {
|
||||
1001: SERVER_FIELDS + (
|
||||
("角色", "name", "text"),
|
||||
("奇遇", "event", "text"),
|
||||
("等级", "level", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1002: SERVER_FIELDS + (
|
||||
("地图", "map_name", "text"),
|
||||
("刷新时间", "time", "time"),
|
||||
),
|
||||
1003: SERVER_FIELDS + (
|
||||
("名称", "name", "text"),
|
||||
("地图", "map_name", "text"),
|
||||
("马驹", "horse", "text"),
|
||||
("等级", "level", "text"),
|
||||
("捕获时间", "time", "time"),
|
||||
),
|
||||
1004: SERVER_FIELDS + (("预告时间", "time", "time"),),
|
||||
1005: SERVER_FIELDS + (("开启时间", "time", "time"),),
|
||||
1006: SERVER_FIELDS + (
|
||||
("点名角色", "name", "list"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1007: SERVER_FIELDS + (
|
||||
("燃放者", "sender", "text"),
|
||||
("接收者", "receiver", "text"),
|
||||
("烟花", "firework", "text"),
|
||||
("地图", "map_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1008: SERVER_FIELDS + (
|
||||
("马驹", "name", "text"),
|
||||
("地图", "map_name", "text"),
|
||||
("预告时间", "time", "time"),
|
||||
),
|
||||
1009: SERVER_FIELDS + (
|
||||
("马驹", "name", "text"),
|
||||
("地图", "map_name", "text"),
|
||||
("刷新时间", "refresh_time", "time"),
|
||||
),
|
||||
1010: SERVER_FIELDS + (
|
||||
("马驹", "name", "text"),
|
||||
("地图", "map_name", "text"),
|
||||
("捕获角色", "capture_role_name", "text"),
|
||||
("角色阵营", "capture_camp_name", "text"),
|
||||
("捕获时间", "capture_time", "time"),
|
||||
),
|
||||
1011: SERVER_FIELDS + (
|
||||
("马驹", "name", "text"),
|
||||
("竞拍角色", "auction_role_name", "text"),
|
||||
("角色阵营", "auction_camp_name", "text"),
|
||||
("成交金额", "auction_amount", "text"),
|
||||
("拍卖时间", "auction_time", "time"),
|
||||
),
|
||||
1012: SERVER_FIELDS + (
|
||||
("角色", "role_name", "text"),
|
||||
("副本", "map_name", "text"),
|
||||
("物品", "item_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1013: SERVER_FIELDS + (
|
||||
("竞拍角色", "role_name", "text"),
|
||||
("阵营", "camp_name", "text"),
|
||||
("物品", "item_name", "text"),
|
||||
("成交金额", "item_amount", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1014: SERVER_FIELDS + (
|
||||
("地图", "map_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1015: SERVER_FIELDS + (
|
||||
("角色所在服", "role_server", "text"),
|
||||
("点名角色", "role_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1016: SERVER_FIELDS + (("预告时间", "time", "time"),),
|
||||
1017: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("帮会", "tong_name", "text"),
|
||||
("角色", "role_name", "text"),
|
||||
("据点", "castle_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1101: SERVER_FIELDS + (
|
||||
("战场类型", "battlefield_type", "text"),
|
||||
("宣战帮会", "declaring_tong_name", "text"),
|
||||
("应战帮会", "accepting_tong_name", "text"),
|
||||
("领地帮会", "battlefield_tong_name", "text"),
|
||||
("开始时间", "start_time", "time"),
|
||||
),
|
||||
1102: SERVER_FIELDS + (
|
||||
("战场类型", "battlefield_type", "text"),
|
||||
("宣战帮会", "declaring_tong_name", "text"),
|
||||
("应战帮会", "accepting_tong_name", "text"),
|
||||
("领地帮会", "battlefield_tong_name", "text"),
|
||||
("获胜帮会", "victory_tong_name", "text"),
|
||||
("获胜积分", "victory_score", "text"),
|
||||
("结束时间", "end_time", "time"),
|
||||
),
|
||||
1108: SERVER_FIELDS + (
|
||||
("战场类型", "battlefield_type", "text"),
|
||||
("宣战帮会", "declaring_tong_name", "text"),
|
||||
("应战帮会", "accepting_tong_name", "text"),
|
||||
("持续时长(小时)", "duration_hours", "text"),
|
||||
("开始时间", "start_time", "time"),
|
||||
),
|
||||
1109: SERVER_FIELDS + (
|
||||
("战场类型", "battlefield_type", "text"),
|
||||
("宣战帮会", "declaring_tong_name", "text"),
|
||||
("应战帮会", "accepting_tong_name", "text"),
|
||||
("结束时间", "end_time", "time"),
|
||||
),
|
||||
1111: SERVER_FIELDS + (
|
||||
("据点", "castle_name", "text"),
|
||||
("阵营", "camp_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1112: SERVER_FIELDS + (
|
||||
("据点", "castle_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1113: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("地图", "map_name", "text"),
|
||||
("据点", "castle_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1114: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("帮会", "tong_name", "text"),
|
||||
("据点", "castle_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1115: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("据点", "castle_name", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1116: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("贡献帮会", "tong_name", "list"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1117: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("贡献帮会", "tong_name", "list"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1118: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("贡献帮会", "tong_name", "list"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1119: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("竞拍角色", "role_name", "text"),
|
||||
("物品", "item_name", "text"),
|
||||
("成交金额", "item_amount", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1120: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("分红帮会", "tong_name", "list"),
|
||||
("分红金额", "split_amount", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1121: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("分红帮会", "tong_name", "list"),
|
||||
("分红金额", "split_amount", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
1122: SERVER_FIELDS + (
|
||||
("阵营", "camp_name", "text"),
|
||||
("指挥帮会", "chief_tong_name", "text"),
|
||||
("分红帮会", "tong_name", "list"),
|
||||
("分红金额", "split_amount", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
2001: SERVER_FIELDS + (
|
||||
("状态", "status", "status"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
2002: (
|
||||
("类型", "type", "text"),
|
||||
("标题", "title", "text"),
|
||||
("日期", "date", "text"),
|
||||
("链接", "url", "text"),
|
||||
),
|
||||
2003: (
|
||||
("当前版本", "now_version", "text"),
|
||||
("最新版本", "new_version", "text"),
|
||||
("更新包数量", "package_num", "text"),
|
||||
("更新大小", "package_size", "text"),
|
||||
),
|
||||
2004: (
|
||||
("分类", "tags", "text"),
|
||||
("服务器", "server", "text"),
|
||||
("发布者", "name", "text"),
|
||||
("标题", "title", "text"),
|
||||
("日期", "date", "text"),
|
||||
("链接", "url", "text"),
|
||||
),
|
||||
2005: (
|
||||
("服务器", "server", "text"),
|
||||
("关卡", "stage", "text"),
|
||||
("开始时间", "start", "time"),
|
||||
),
|
||||
2006: (
|
||||
("事件", "name", "text"),
|
||||
("地点", "site", "text"),
|
||||
("说明", "desc", "text"),
|
||||
("时间", "time", "time"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class EventPushService:
|
||||
"""JX3API WebSocket 事件接收、会话订阅与消息分发。"""
|
||||
@@ -424,63 +646,30 @@ class EventPushService:
|
||||
return str(value or "未知")
|
||||
|
||||
def _format_event(self, action: int, detail: dict[str, Any]) -> str:
|
||||
if action == 2001:
|
||||
raw_status = detail.get("status")
|
||||
server_status = {0: "维护", 1: "开服", "0": "维护", "1": "开服"}.get(
|
||||
raw_status,
|
||||
str(raw_status or "未知"),
|
||||
)
|
||||
return (
|
||||
"【开服状态】\n"
|
||||
f"大区:{detail.get('zone', '未知')}\n"
|
||||
f"服务器:{detail.get('server', '未知')}\n"
|
||||
f"状态:{server_status}\n"
|
||||
f"时间:{self._format_timestamp(detail.get('time'))}"
|
||||
)
|
||||
if action == 2002:
|
||||
return (
|
||||
"【官方新闻】\n"
|
||||
f"类型:{detail.get('type', '未知')}\n"
|
||||
f"标题:{detail.get('title', '未知')}\n"
|
||||
f"日期:{detail.get('date', '未知')}\n"
|
||||
f"链接:{detail.get('url', '无')}"
|
||||
)
|
||||
if action == 2003:
|
||||
return (
|
||||
"【版本更新】\n"
|
||||
f"当前版本:{detail.get('now_version', '未知')}\n"
|
||||
f"最新版本:{detail.get('new_version', '未知')}\n"
|
||||
f"更新包数量:{detail.get('package_num', '未知')}\n"
|
||||
f"更新大小:{detail.get('package_size', '未知')}"
|
||||
)
|
||||
if action == 2004:
|
||||
return (
|
||||
"【八卦速报】\n"
|
||||
f"分类:{detail.get('tags', '未知')}\n"
|
||||
f"区服:{detail.get('zone', '未知')} / {detail.get('server', '未知')}\n"
|
||||
f"来源:{detail.get('tieba', '未知')}\n"
|
||||
f"标题:{detail.get('title', '未知')}\n"
|
||||
f"日期:{detail.get('date', '未知')}\n"
|
||||
f"链接:{detail.get('url', '无')}"
|
||||
)
|
||||
if action == 2005:
|
||||
return (
|
||||
"【关隘首领】\n"
|
||||
f"服务器:{detail.get('server', '未知')}\n"
|
||||
f"关卡:{detail.get('stage', '未知')}\n"
|
||||
f"开始时间:{self._format_timestamp(detail.get('start'))}"
|
||||
)
|
||||
if action == 2006:
|
||||
return (
|
||||
"【云从预告】\n"
|
||||
f"事件:{detail.get('name', '未知')}\n"
|
||||
f"地点:{detail.get('site', '未知')}\n"
|
||||
f"说明:{detail.get('desc', '无')}\n"
|
||||
f"时间:{self._format_timestamp(detail.get('time'))}"
|
||||
)
|
||||
fields = EVENT_FIELDS.get(action)
|
||||
if not fields:
|
||||
detail_text = json.dumps(detail, ensure_ascii=False, indent=2)
|
||||
return f"【事件推送 · {action}】\n{detail_text}"
|
||||
|
||||
detail_text = json.dumps(detail, ensure_ascii=False, indent=2)
|
||||
return f"【事件推送 · {action} {EVENT_NAMES[action]}】\n{detail_text}"
|
||||
lines = [f"【{EVENT_NAMES[action]}】"]
|
||||
for label, key, value_type in fields:
|
||||
lines.append(f"{label}:{self._format_field(detail.get(key), value_type)}")
|
||||
return "\n".join(lines)
|
||||
|
||||
def _format_field(self, value: Any, value_type: str) -> str:
|
||||
if value_type == "time":
|
||||
return self._format_timestamp(value)
|
||||
if value_type == "status":
|
||||
if value in (0, "0"):
|
||||
return "维护"
|
||||
if value in (1, "1"):
|
||||
return "开服"
|
||||
return str(value if value is not None and value != "" else "未知")
|
||||
if value_type == "list":
|
||||
if isinstance(value, (list, tuple)):
|
||||
values = [str(item).strip() for item in value if str(item).strip()]
|
||||
return "、".join(values) if values else "无"
|
||||
return str(value if value is not None and value != "" else "未知")
|
||||
|
||||
@staticmethod
|
||||
def _usage_text() -> str:
|
||||
@@ -503,4 +692,4 @@ class EventPushService:
|
||||
for action in EVENT_ACTIONS
|
||||
if action not in FREE_EVENT_ACTIONS
|
||||
)
|
||||
return f"免费事件:\n{free}\n\n事件版事件:\n{paid}"
|
||||
return f"免费事件:\n{free}\n\n令牌事件:\n{paid}"
|
||||
|
||||
+56
-4
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
import html
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, Optional, List, Union
|
||||
from inspect import isawaitable
|
||||
from typing import Any, Awaitable, Callable, Dict, Optional
|
||||
@@ -19,15 +19,13 @@ from .fun_basic import load_template,gold_to_parts,week_to_num,compare_date_str,
|
||||
|
||||
|
||||
class JX3APIService:
|
||||
def __init__(self, config: AstrBotConfig, sqlite: AsyncSQLiteDB, cache_sqlite: Optional[AsyncSQLiteDB] = None):
|
||||
def __init__(self, config: AstrBotConfig, sqlite: AsyncSQLiteDB):
|
||||
# 实例化 API Client
|
||||
self._api: APIClient = APIClient()
|
||||
# 引用插件配置文件
|
||||
self._config = config
|
||||
# 引用sqlite
|
||||
self._sql_db = sqlite
|
||||
self._cache_db = cache_sqlite or sqlite
|
||||
|
||||
# 获取配置中的 Token
|
||||
self.token = self._config.get("jx3api_token", "")
|
||||
if self.token == "":
|
||||
@@ -1067,6 +1065,60 @@ class JX3APIService:
|
||||
)
|
||||
|
||||
|
||||
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:
|
||||
|
||||
+82
-266
@@ -14,30 +14,6 @@ from .request import APIClient
|
||||
from .sqlite import AsyncSQLiteDB
|
||||
from .fun_basic import load_template,gold_to_parts,week_to_num,compare_date_str,format_time,format_remaining
|
||||
|
||||
ACHIEVEMENT_CHOICES = [
|
||||
(0, None, "资历总览"),
|
||||
(1, "1", "杂闻总览"),
|
||||
(2, "2", "武学总览"),
|
||||
(3, "3", "修为总览"),
|
||||
(4, "4", "装备总览"),
|
||||
(5, "5", "技艺总览"),
|
||||
(6, "6", "阅读总览"),
|
||||
(7, "7", "任务总览"),
|
||||
(8, "8", "足迹总览"),
|
||||
(9, "9", "战斗总览"),
|
||||
(10, "10", "声望总览"),
|
||||
(11, "11", "秘境总览"),
|
||||
(12, "12", "帮会总览"),
|
||||
(13, "13", "阵营总览"),
|
||||
(14, "15", "节日总览"),
|
||||
(15, "16", "活动总览"),
|
||||
(16, "17", "风雨江湖路总览"),
|
||||
(17, "40", "家园总览"),
|
||||
(18, "41", "剑侠录总览"),
|
||||
]
|
||||
|
||||
ACHIEVEMENT_CHOICE_MAP = {index: (menu_id, title) for index, menu_id, title in ACHIEVEMENT_CHOICES}
|
||||
|
||||
JX3BOX_API_BASE_URLS = {
|
||||
"node": "https://node.jx3box.com",
|
||||
"next2": "https://next2.jx3box.com",
|
||||
@@ -226,11 +202,8 @@ class JX3BOXService:
|
||||
return return_data
|
||||
|
||||
|
||||
async def hong1(self, name: str) -> Dict[str, Any]:
|
||||
"""宏 心法"""
|
||||
return_data = self._init_return_data()
|
||||
|
||||
# 数据库查询数据
|
||||
async def _macro_posts(self, name: str) -> Optional[List[Dict[str, Any]]]:
|
||||
"""按心法查询宏帖子,并保留接口热度排序。"""
|
||||
result = await self._sql_db.select_one(
|
||||
"kungfu",
|
||||
"name=? OR name1=? OR name2=? OR name3=? OR name4=? OR name5=?",
|
||||
@@ -238,52 +211,91 @@ class JX3BOXService:
|
||||
)
|
||||
|
||||
if result is None:
|
||||
return_data["msg"] = "未找到该心法"
|
||||
return return_data
|
||||
return None
|
||||
|
||||
kungfu = result.get("name", None)
|
||||
if kungfu is None:
|
||||
return_data["msg"] = "未找到该心法"
|
||||
return return_data
|
||||
return None
|
||||
|
||||
logger.debug(f"查询到数据:{kungfu}")
|
||||
|
||||
# 1. 构造请求参数
|
||||
params = {"subtype": kungfu}
|
||||
|
||||
# 2. 调用基础请求
|
||||
data: Optional[Dict[str, Any]] = await self._base_request(
|
||||
"cms",
|
||||
"/api/cms/posts",
|
||||
params=params,
|
||||
params={"subtype": kungfu},
|
||||
)
|
||||
if not isinstance(data, dict):
|
||||
return None
|
||||
|
||||
if not data:
|
||||
return_data["msg"] = "未找到该心法一键宏"
|
||||
return return_data
|
||||
return [
|
||||
item
|
||||
for item in data.get("list", [])
|
||||
if isinstance(item, dict) and item.get("ID")
|
||||
]
|
||||
|
||||
|
||||
async def hong1(self, name: str) -> Dict[str, str]:
|
||||
"""宏首轮:返回“序号 -> 显示内容”的选择数据。"""
|
||||
posts = await self._macro_posts(name)
|
||||
|
||||
if not posts:
|
||||
raise ValueError("未找到该心法一键宏")
|
||||
|
||||
# 提取ID
|
||||
pid_list = [0]
|
||||
msg = "按照热度排列\n"
|
||||
n = 1
|
||||
try:
|
||||
for m in data.get('list',[]):
|
||||
msg += f"{n}、{m['author']}\t{m['post_title']}\n"
|
||||
pid_list.append(m["ID"])
|
||||
n += 1
|
||||
|
||||
return_data["msg"] = msg
|
||||
return_data["data"]["list"] = pid_list
|
||||
return_data["data"]["num"] = n
|
||||
options = {
|
||||
str(index): f"{post.get('author', '')}\t{post.get('post_title', '')}"
|
||||
for index, post in enumerate(posts, start=1)
|
||||
}
|
||||
|
||||
if not options:
|
||||
raise ValueError("未找到该心法一键宏")
|
||||
|
||||
except Exception as e:
|
||||
logger.exception("处理返回数据失败")
|
||||
return_data["msg"] = "处理返回数据失败"
|
||||
return return_data
|
||||
|
||||
return_data["code"] = 200
|
||||
if isinstance(e, ValueError):
|
||||
raise
|
||||
raise RuntimeError("处理返回数据失败") from e
|
||||
|
||||
return return_data
|
||||
return options
|
||||
|
||||
|
||||
async def hong_select(self,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
|
||||
|
||||
choice, label = next(iter(selected.items()))
|
||||
posts = await self._macro_posts(name)
|
||||
if not posts:
|
||||
return_data = self._init_return_data()
|
||||
return_data["msg"] = "未找到该心法一键宏"
|
||||
return return_data
|
||||
|
||||
selected_post = next(
|
||||
(
|
||||
post
|
||||
for post in posts
|
||||
if f"{post.get('author', '')}\t{post.get('post_title', '')}"
|
||||
== str(label)
|
||||
),
|
||||
None,
|
||||
)
|
||||
if selected_post is None:
|
||||
try:
|
||||
selected_post = posts[int(choice) - 1]
|
||||
except (TypeError, ValueError, IndexError):
|
||||
return_data = self._init_return_data()
|
||||
return_data["msg"] = "无效宏序号"
|
||||
return return_data
|
||||
|
||||
pid = str(selected_post.get("ID") or "").strip()
|
||||
if not pid:
|
||||
return_data = self._init_return_data()
|
||||
return_data["msg"] = "宏帖子 ID 无效"
|
||||
return return_data
|
||||
|
||||
return await self.hong2(pid)
|
||||
|
||||
|
||||
async def hong2(self, pid: str) -> Dict[str, Any]:
|
||||
@@ -328,12 +340,12 @@ class JX3BOXService:
|
||||
return return_data
|
||||
|
||||
|
||||
async def _load_achievement_cache(self, key: str) -> tuple[Optional[Any], bool]:
|
||||
"""读取资历基础数据缓存,返回数据和是否已过期"""
|
||||
async def _load_trade_cache(self, key: str) -> tuple[Optional[Any], bool]:
|
||||
"""读取交易行基础数据缓存,返回数据和是否已过期。"""
|
||||
try:
|
||||
row = await self._cache_db.select_one("achievement_cache", "key=?", (key,))
|
||||
row = await self._cache_db.select_one("trade_item_cache", "key=?", (key,))
|
||||
except Exception as e:
|
||||
logger.error(f"读取资历缓存失败: {e}")
|
||||
logger.error(f"读取交易行缓存失败: {e}")
|
||||
return None, True
|
||||
|
||||
if not row:
|
||||
@@ -345,16 +357,16 @@ class JX3BOXService:
|
||||
expired = datetime.now() - updated_at > timedelta(days=30)
|
||||
return payload, expired
|
||||
except Exception as e:
|
||||
logger.error(f"解析资历缓存失败: {e}")
|
||||
logger.error(f"解析交易行缓存失败: {e}")
|
||||
return None, True
|
||||
|
||||
|
||||
async def _save_achievement_cache(self, key: str, payload: Any):
|
||||
"""写入资历基础数据缓存"""
|
||||
async def _save_trade_cache(self, key: str, payload: Any):
|
||||
"""写入交易行基础数据缓存。"""
|
||||
try:
|
||||
await self._cache_db.execute(
|
||||
"""
|
||||
INSERT INTO achievement_cache (key, content, updated_at)
|
||||
INSERT INTO trade_item_cache (key, content, updated_at)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(key) DO UPDATE SET
|
||||
content=excluded.content,
|
||||
@@ -367,31 +379,13 @@ class JX3BOXService:
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"写入资历缓存失败: {e}")
|
||||
|
||||
|
||||
async def _get_achievement_base_data(self, cache_key: str, api_path: str) -> Optional[Dict[str, Any]]:
|
||||
"""获取资历菜单或点数数据,优先使用未过期缓存"""
|
||||
cached, expired = await self._load_achievement_cache(cache_key)
|
||||
if cached and not expired:
|
||||
return cached
|
||||
|
||||
data: Optional[Dict[str, Any]] = await self._base_request("node", api_path)
|
||||
if data and isinstance(data, dict):
|
||||
await self._save_achievement_cache(cache_key, data)
|
||||
return data
|
||||
|
||||
if cached:
|
||||
logger.warning(f"资历基础数据接口失败,使用旧缓存: {cache_key}")
|
||||
return cached
|
||||
|
||||
return None
|
||||
logger.error(f"写入交易行缓存失败: {e}")
|
||||
|
||||
|
||||
async def _get_trade_item_groups(self) -> Optional[List[Dict[str, Any]]]:
|
||||
"""获取交易行物品库,优先使用未过期缓存"""
|
||||
cache_key = "trade_item_groups"
|
||||
cached, expired = await self._load_achievement_cache(cache_key)
|
||||
cached, expired = await self._load_trade_cache(cache_key)
|
||||
if isinstance(cached, list) and not expired:
|
||||
return cached
|
||||
|
||||
@@ -402,7 +396,7 @@ class JX3BOXService:
|
||||
params={"client": "std"},
|
||||
)
|
||||
if isinstance(data, list) and data:
|
||||
await self._save_achievement_cache(cache_key, data)
|
||||
await self._save_trade_cache(cache_key, data)
|
||||
return data
|
||||
|
||||
if isinstance(cached, list) and cached:
|
||||
@@ -461,184 +455,6 @@ class JX3BOXService:
|
||||
return [row[3] for row in matched[:limit]]
|
||||
|
||||
|
||||
def _flatten_achievement_ids(self, values: Any) -> list[int]:
|
||||
"""展开菜单中的单个资历 ID 和数组资历 ID"""
|
||||
result = []
|
||||
|
||||
if isinstance(values, list):
|
||||
for item in values:
|
||||
result.extend(self._flatten_achievement_ids(item))
|
||||
return result
|
||||
|
||||
try:
|
||||
result.append(int(values))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _category_achievement_ids(self, category: Dict[str, Any]) -> list[int]:
|
||||
"""提取分类及其子分类包含的资历 ID"""
|
||||
ids = self._flatten_achievement_ids(category.get("achievements", []))
|
||||
for child in category.get("children", []) or []:
|
||||
if isinstance(child, dict):
|
||||
ids.extend(self._flatten_achievement_ids(child.get("achievements", [])))
|
||||
return ids
|
||||
|
||||
|
||||
def _build_achievement_progress(
|
||||
self,
|
||||
name: str,
|
||||
achievement_ids: list[int],
|
||||
point_map: Dict[str, Any],
|
||||
completed_ids: set[int],
|
||||
) -> Dict[str, Any]:
|
||||
"""按资历点数计算完成进度"""
|
||||
unique_ids = set(achievement_ids)
|
||||
total_points = 0
|
||||
completed_points = 0
|
||||
completed_count = 0
|
||||
|
||||
for achievement_id in unique_ids:
|
||||
try:
|
||||
point = int(point_map.get(str(achievement_id), 0) or 0)
|
||||
except (TypeError, ValueError):
|
||||
point = 0
|
||||
|
||||
total_points += point
|
||||
if achievement_id in completed_ids:
|
||||
completed_count += 1
|
||||
completed_points += point
|
||||
|
||||
percent = round(completed_points / total_points * 100, 2) if total_points else 0
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"total_points": total_points,
|
||||
"completed_points": completed_points,
|
||||
"percent": percent,
|
||||
"percent_text": f"{percent:.2f}%",
|
||||
"achievement_count": len(unique_ids),
|
||||
"completed_count": completed_count,
|
||||
}
|
||||
|
||||
|
||||
async def zili(self, name: str, server: str, choice: int) -> Dict[str, Any]:
|
||||
"""角色资历"""
|
||||
return_data = self._init_return_data()
|
||||
|
||||
if choice not in ACHIEVEMENT_CHOICE_MAP:
|
||||
return_data["msg"] = "无效序号,结束会话"
|
||||
return return_data
|
||||
|
||||
role_params = {"server": server, "name": name, "token": self.token}
|
||||
api_url = "https://www.jx3api.com/role/detail"
|
||||
role_data: Optional[Dict[str, Any]] = await self._api.get(api_url, params=role_params, out_key="data")
|
||||
|
||||
if not role_data or not isinstance(role_data, dict):
|
||||
return_data["msg"] = "未查询到角色"
|
||||
return return_data
|
||||
|
||||
global_id = role_data.get("globalId")
|
||||
if not global_id:
|
||||
return_data["msg"] = "无法获取角色全区 ID"
|
||||
return return_data
|
||||
|
||||
achievement_data = await self._base_request(
|
||||
"next2",
|
||||
"/api/next2/user-achievements",
|
||||
params={"jx3id": global_id},
|
||||
)
|
||||
if not achievement_data or not isinstance(achievement_data, dict):
|
||||
return_data["msg"] = "未查询到资历数据"
|
||||
return return_data
|
||||
|
||||
completed_ids = set()
|
||||
achievements = achievement_data.get("achievements") or ""
|
||||
if isinstance(achievements, str):
|
||||
for item in achievements.split(","):
|
||||
try:
|
||||
completed_ids.add(int(item.strip()))
|
||||
except ValueError:
|
||||
continue
|
||||
elif isinstance(achievements, list):
|
||||
completed_ids = set(self._flatten_achievement_ids(achievements))
|
||||
|
||||
menu_payload = await self._get_achievement_base_data(
|
||||
"achievement_menus",
|
||||
"/api/node/achievement/menus",
|
||||
)
|
||||
point_payload = await self._get_achievement_base_data(
|
||||
"achievement_points",
|
||||
"/api/node/achievement/points",
|
||||
)
|
||||
if not menu_payload or not point_payload:
|
||||
return_data["msg"] = "基础资历数据获取失败"
|
||||
return return_data
|
||||
|
||||
menus = menu_payload.get("menus", {})
|
||||
points = point_payload.get("points", {})
|
||||
if not isinstance(menus, dict) or not isinstance(points, dict):
|
||||
return_data["msg"] = "基础资历数据格式异常"
|
||||
return return_data
|
||||
|
||||
selected_menu_id, selected_title = ACHIEVEMENT_CHOICE_MAP[choice]
|
||||
items = []
|
||||
|
||||
if choice == 0:
|
||||
total_ids = []
|
||||
for _, menu_id, title in ACHIEVEMENT_CHOICES[1:]:
|
||||
category = menus.get(str(menu_id), {})
|
||||
if not isinstance(category, dict):
|
||||
continue
|
||||
category_ids = self._category_achievement_ids(category)
|
||||
total_ids.extend(category_ids)
|
||||
items.append(
|
||||
self._build_achievement_progress(title, category_ids, points, completed_ids)
|
||||
)
|
||||
summary = self._build_achievement_progress(selected_title, total_ids, points, completed_ids)
|
||||
else:
|
||||
category = menus.get(str(selected_menu_id), {})
|
||||
if not isinstance(category, dict) or not category:
|
||||
return_data["msg"] = "未找到该资历分类"
|
||||
return return_data
|
||||
|
||||
category_ids = self._category_achievement_ids(category)
|
||||
summary = self._build_achievement_progress(selected_title, category_ids, points, completed_ids)
|
||||
for child in category.get("children", []) or []:
|
||||
if not isinstance(child, dict):
|
||||
continue
|
||||
child_ids = self._flatten_achievement_ids(child.get("achievements", []))
|
||||
items.append(
|
||||
self._build_achievement_progress(child.get("name", "未命名"), child_ids, points, completed_ids)
|
||||
)
|
||||
|
||||
try:
|
||||
return_data["temp"] = await load_template("zili.html")
|
||||
except FileNotFoundError as e:
|
||||
logger.error(f"加载模板失败: {e}")
|
||||
return_data["msg"] = "系统错误:模板文件不存在"
|
||||
return return_data
|
||||
|
||||
return_data["data"] = {
|
||||
"title": selected_title,
|
||||
"summary": summary,
|
||||
"items": items,
|
||||
"role_name": role_data.get("roleName", name),
|
||||
"server": role_data.get("serverName", server),
|
||||
"zone": role_data.get("zoneName", ""),
|
||||
"force_name": role_data.get("forceName", "无"),
|
||||
"camp_name": role_data.get("campName", "无"),
|
||||
"tong_name": role_data.get("tongName", "无"),
|
||||
"updated_at": achievement_data.get("updated_at", ""),
|
||||
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
return_data["code"] = 200
|
||||
|
||||
return return_data
|
||||
|
||||
|
||||
async def jiaoyihang(self, name: str , server: str) -> Dict[str, Any]:
|
||||
"""区服交易行"""
|
||||
return_data = self._init_return_data()
|
||||
|
||||
+79
-126
@@ -1,3 +1,5 @@
|
||||
from typing import Any
|
||||
|
||||
from astrbot.core import html_renderer
|
||||
from astrbot.api import logger
|
||||
from astrbot.api.event import AstrMessageEvent, MessageChain
|
||||
@@ -14,29 +16,6 @@ from .bilei_data import BiLeidata
|
||||
|
||||
class MessageBuilder:
|
||||
"""回复消息构建"""
|
||||
ZILI_MENU_TEXT = (
|
||||
"请选择资历查询类型:\n"
|
||||
"0:资历总览\n"
|
||||
"1:杂闻总览\n"
|
||||
"2:武学总览\n"
|
||||
"3:修为总览\n"
|
||||
"4:装备总览\n"
|
||||
"5:技艺总览\n"
|
||||
"6:阅读总览\n"
|
||||
"7:任务总览\n"
|
||||
"8:足迹总览\n"
|
||||
"9:战斗总览\n"
|
||||
"10:声望总览\n"
|
||||
"11:秘境总览\n"
|
||||
"12:帮会总览\n"
|
||||
"13:阵营总览\n"
|
||||
"14:节日总览\n"
|
||||
"15:活动总览\n"
|
||||
"16:风雨江湖路总览\n"
|
||||
"17:家园总览\n"
|
||||
"18:剑侠录总览"
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
jx3api: JX3APIService,
|
||||
jx3box: JX3BOXService,
|
||||
@@ -138,94 +117,64 @@ class MessageBuilder:
|
||||
await event.send(event.plain_result("猪脑过载,请稍后再试"))
|
||||
|
||||
|
||||
async def handler_plain_image_msg(self, event: AstrMessageEvent, action1, action2):
|
||||
"""两轮会话消息发送通用,先文本列表等反馈序号在发送图片"""
|
||||
# 会话触发
|
||||
async def plain_image_msg(self, event: AstrMessageEvent, action):
|
||||
"""发送正文文本,并把可选 HTML 正文渲染为附图。"""
|
||||
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"未搜索到相关内容"))
|
||||
data = await action()
|
||||
if data.get("code") != 200:
|
||||
await event.send(
|
||||
event.plain_result(data.get("msg") or "获取详细数据失败")
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
chain = MessageChain()
|
||||
if data.get("data"):
|
||||
chain.message(str(data["data"]))
|
||||
if data.get("temp"):
|
||||
url = await self.html_render(data["temp"], {}, options={})
|
||||
chain.url_image(url)
|
||||
await event.send(chain)
|
||||
except Exception as e:
|
||||
logger.error(f"功能函数执行错误: {e}")
|
||||
await event.send(event.plain_result("猪脑过载,请稍后再试"))
|
||||
|
||||
|
||||
async def handler_zili_msg(self, event: AstrMessageEvent, name: str, server: str):
|
||||
"""资历查询专用两轮会话,第一轮文本菜单,第二轮图片"""
|
||||
async def handler_plain_image_msg(self, event: AstrMessageEvent, action1, action2, result_handler=None, timeout: int = 10):
|
||||
"""通用两轮会话:首轮数字键值对裁剪后交给次轮函数。"""
|
||||
try:
|
||||
await event.send(event.plain_result(self.ZILI_MENU_TEXT))
|
||||
user_id = event.get_sender_id()
|
||||
option_map = await action1()
|
||||
if not isinstance(option_map, dict) or not option_map:
|
||||
await event.send(event.plain_result("未搜索到可选内容"))
|
||||
return
|
||||
|
||||
@session_waiter(timeout=30)
|
||||
async def zili_select_waiter(controller: SessionController, new_event: AstrMessageEvent):
|
||||
options = {str(key): value for key, value in option_map.items()}
|
||||
if not all(key.isdigit() for key in options):
|
||||
await event.send(event.plain_result("选项序号格式异常"))
|
||||
return
|
||||
|
||||
menu_lines = ["请选择序号"]
|
||||
menu_lines.extend(
|
||||
f"{key}、{label}"
|
||||
for key, label in options.items()
|
||||
)
|
||||
await event.send(event.plain_result("\n".join(menu_lines)))
|
||||
user_id = event.get_sender_id()
|
||||
send_result = result_handler or self.T2I_image_msg
|
||||
|
||||
async def send_selected(
|
||||
target_event: AstrMessageEvent,
|
||||
selected: dict[str, Any],
|
||||
):
|
||||
await send_result(
|
||||
target_event,
|
||||
lambda: action2(selected),
|
||||
)
|
||||
|
||||
@session_waiter(timeout=timeout)
|
||||
async def option_select_waiter(
|
||||
controller: SessionController,
|
||||
new_event: AstrMessageEvent,
|
||||
):
|
||||
if new_event.get_sender_id() != user_id:
|
||||
return
|
||||
|
||||
@@ -236,43 +185,38 @@ class MessageBuilder:
|
||||
return
|
||||
|
||||
choice = int(msg)
|
||||
if choice < 0 or choice > 18:
|
||||
choice_key = str(choice)
|
||||
if choice_key not in options:
|
||||
await new_event.send(MessageChain().message("无效序号,结束会话"))
|
||||
controller.stop()
|
||||
return
|
||||
|
||||
try:
|
||||
data = await self.jx3box.zili(name, server, choice)
|
||||
if data["code"] != 200:
|
||||
await new_event.send(MessageChain().message(data.get("msg", "获取资历数据失败")))
|
||||
controller.stop()
|
||||
return
|
||||
|
||||
options = {
|
||||
"quality": 100,
|
||||
"device_scale_factor_level": "normal",
|
||||
"full_page": True,
|
||||
"omit_background": False,
|
||||
"type": "jpeg"
|
||||
}
|
||||
data["data"]["icons"] = self.icons
|
||||
url = await self.html_render(data["temp"], data["data"], options=options)
|
||||
await new_event.send(new_event.image_result(url))
|
||||
await send_selected(
|
||||
new_event,
|
||||
{choice_key: options[choice_key]},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"资历查询执行错误: {e}")
|
||||
logger.error(f"二轮查询执行错误: {e}")
|
||||
await new_event.send(MessageChain().message("猪脑过载,请稍后再试"))
|
||||
|
||||
controller.stop()
|
||||
|
||||
try:
|
||||
await zili_select_waiter(event)
|
||||
await option_select_waiter(event)
|
||||
except TimeoutError:
|
||||
await event.send(event.plain_result("选择超时,已结束会话"))
|
||||
first_key = next(iter(options))
|
||||
await send_selected(
|
||||
event,
|
||||
{first_key: options[first_key]},
|
||||
)
|
||||
except Exception:
|
||||
logger.error("资历选择发生异常", exc_info=True)
|
||||
logger.error("二轮选择发生异常", exc_info=True)
|
||||
|
||||
except (ValueError, RuntimeError) as e:
|
||||
await event.send(event.plain_result(str(e) or "未搜索到可选内容"))
|
||||
except Exception as e:
|
||||
logger.error(f"资历会话执行错误: {e}")
|
||||
logger.error(f"二轮会话执行错误: {e}")
|
||||
await event.send(event.plain_result("猪脑过载,请稍后再试"))
|
||||
|
||||
|
||||
@@ -666,11 +610,20 @@ class MessageBuilder:
|
||||
|
||||
async def hong(self, event: AstrMessageEvent,name: str):
|
||||
""" 宏 心法"""
|
||||
return await self.handler_plain_image_msg(event, lambda: self.jx3box.hong1(name), self.jx3box.hong2)
|
||||
return await self.handler_plain_image_msg(
|
||||
event,
|
||||
lambda: self.jx3box.hong1(name),
|
||||
lambda selected: self.jx3box.hong_select(name, selected),
|
||||
result_handler=self.plain_image_msg,
|
||||
)
|
||||
|
||||
async def zili(self, event: AstrMessageEvent, server: str, name: str):
|
||||
""" 资历 角色名称 服务器"""
|
||||
return await self.handler_zili_msg(event, name, server)
|
||||
return await self.handler_plain_image_msg(
|
||||
event,
|
||||
lambda: self.jx3api.zili_menu(),
|
||||
lambda selected: self.jx3api.zili(server, name, selected),
|
||||
)
|
||||
|
||||
async def jiaoyihang(self, event: AstrMessageEvent,server: str, Name: str):
|
||||
""" 交易行 物品名称 服务器"""
|
||||
|
||||
@@ -8,6 +8,8 @@ from .sqlite import AsyncSQLiteDB
|
||||
class ServerBindingService:
|
||||
"""维护会话区服绑定、区服别名与指令解析所需的区服目录。"""
|
||||
|
||||
ALL_SERVERS_KEYWORD = "全区"
|
||||
|
||||
def __init__(self, sqlite: AsyncSQLiteDB, seed_path: Path):
|
||||
self.sql = sqlite
|
||||
self.seed_path = seed_path
|
||||
@@ -103,6 +105,16 @@ class ServerBindingService:
|
||||
server = self._clean(value)
|
||||
return self._server_lookup.get(self._key(server), server)
|
||||
|
||||
def is_all_servers_query(self, value: Any) -> bool:
|
||||
"""判断指令中的区服参数是否要求查询全区。"""
|
||||
return self._key(value) == self._key(self.ALL_SERVERS_KEYWORD)
|
||||
|
||||
def resolve_query_server(self, value: Any) -> str:
|
||||
"""解析查询区服;“全区”作为保留值转换为接口所需的空字符串。"""
|
||||
if self.is_all_servers_query(value):
|
||||
return ""
|
||||
return self.resolve_server(value)
|
||||
|
||||
async def get_binding(self, session_id: str) -> str:
|
||||
row = await self.sql.select_one(
|
||||
"session_server_bindings",
|
||||
|
||||
Reference in New Issue
Block a user