Files
astrbot_plugin_jx3/core/services/calendar.py
T
2026-07-26 17:57:44 +08:00

697 lines
22 KiB
Python

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