This commit is contained in:
qsc
2026-02-07 19:58:25 +08:00
parent bfb40c9160
commit f8205fdf61
22 changed files with 1085 additions and 910 deletions
-300
View File
@@ -1,300 +0,0 @@
from datetime import datetime
import base64
from astrbot.api import logger
from .request import APIClient
from .async_mysql import AsyncMySQL
from .function_basic import load_template,extract_fields
class WZRYFunction:
def __init__(self, api_config,db: AsyncMySQL ):
self.__api = APIClient()
self.__db = db
self.__api_config = api_config
async def _SELECT_ID(self,name: str):
"""
查询ID
"""
sql = "SELECT id FROM wzydid WHERE name = %s or id = %s"
sqlid = await self.__db.fetch_one(sql, (name,name))
return sqlid["id"] if sqlid else None
async def all_user(self):
"""
查询所有用户
"""
sql = "SELECT id,name FROM wzydid"
sqlid = await self.__db.fetch_all(sql)
return_data = "营地ID\t\t昵称\n"
for m in sqlid:
return_data += f"{m['id']}\t{m['name']}\n"
return return_data
async def add_user(self,id: str ,name: str):
"""
添加用户
"""
self_id = await self._SELECT_ID(id)
if self_id is not None:
return "该用户已存在,无需重复添加"
sql = "INSERT INTO wzydid (id,name) VALUES (%s, %s)"
rowcount = await self.__db.execute(sql, (id,name))
if rowcount > 0:
return f"id:{id}昵称:{name}\n添加成功"
else:
return f"id:{id}昵称:{name}\n添加失败,请稍后再试"
async def update_user(self,id: str ,name: str):
"""
更新用户
"""
self_id = await self._SELECT_ID(id)
if self_id is None:
return "该用户不存在,请先添加用户"
sql = "UPDATE wzydid SET name = %s WHERE id = %s"
rowcount = await self.__db.execute(sql, (name,id))
if rowcount > 0:
return f"id:{id}昵称:{name}\n更新成功"
else:
return f"id:{id}昵称:{name}\n更新失败,请稍后再试"
async def delete_user(self,id: str ):
"""
删除用户
"""
self_id = await self._SELECT_ID(id)
if self_id is None:
return "该用户不存在,无需删除"
sql = "DELETE FROM wzydid WHERE id = %s"
rowcount = await self.__db.execute(sql, (id,))
if rowcount > 0:
return f"id:{id}\n删除成功"
else:
return f"id:{id}\n删除失败,请稍后再试"
async def zhanji(self,name: str ,option: str):
"""
战绩查询
"""
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
#在配置文件中获取接口配置
api_config = self.__api_config["wzry_zhanji"]
# ID查询
sql_id = await self._SELECT_ID(name)
if sql_id is None:
return_data["msg"] = "未查询到该用户,请确认输入正确的昵称或营地ID"
return return_data
#更新参数
api_config["params"]["id"] = sql_id
api_config["params"]["option"] = option
# 需要提取的字段
fields = ["gametime","killcnt","deadcnt","assistcnt","gameresult","mvpcnt","losemvp","mapName",
"oldMasterMatchScore","newMasterMatchScore","usedTime","winNum","failNum","roleJobName","stars","desc",
"gradeGame","heroIcon","godLikeCnt", "firstBlood","hero1TripleKillCnt","hero1UltraKillCnt","hero1RampageCnt","evaluateUrlV3","mvpUrlV3"]
# 处理返回数据
try:
# 获取数据
data = await self.__api.get(api_config["url"],api_config["params"],"data")
if not data:
return_data["msg"] = "获取接口信息失败"
return return_data
# 提取字段
result = extract_fields(data["list"], fields)
result = result[:25]
# 数据处理
for m in result:
minutes = m["usedTime"] // 60
seconds = m["usedTime"] % 60
m["time_str"] = f"{minutes}:{seconds:02d}"
return_data["data"] = result
except Exception as e:
logger.error(f"处理数据时出错: {e}")
return_data["msg"] = "处理接口返回信息时出错"
# 加载模板
try:
return_data["temp"] = load_template("wangzhezhanji.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
async def ziliao(self, name: str):
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
# 查询 ID
sql_id = await self._SELECT_ID(name)
if sql_id is None:
return_data["msg"] = "未查询到该用户,请确认输入正确的昵称或营地ID"
return return_data
api_config = self.__api_config["wzry_ziliao"]
api_config["params"]["id"] = sql_id
try:
data = await self.__api.get(api_config["url"], api_config["params"])
# 转 base64
return_data["data"]["img_base64"] = base64.b64encode(data).decode("utf-8")
return_data["code"] = 200
except Exception as e:
logger.error(f"处理数据时出错: {e}")
return_data["msg"] = "处理接口返回信息时出错"
# 加载模板
try:
return_data["temp"] = load_template("wzry_zl.html")
except FileNotFoundError:
logger.error(f"加载模板失败")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
async def bilei_all(self):
"""
查询仇人列表
"""
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
# 查询所有
try:
sql = "SELECT * FROM wzrybl"
sqlid = await self.__db.fetch_all(sql)
except Exception as e:
logger.error(f"SQL执行错误: {e}")
return_data["msg"] = "处理数据库信息时出错"
return return_data
# 加载模板
try:
return_data["temp"] = load_template("bilei.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["data"]["lists"] = sqlid
return_data["code"] = 200
return return_data
async def bilei_add(self,name:str, text:str, user:str):
"""
仇人 添加
"""
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
# 获取系统时间
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 插入数据
try:
sql = "INSERT INTO wzrybl (name, text, time, user) VALUES (%s, %s, %s, %s)"
await self.__db.execute(sql, (name, text, now, user))
except Exception as e:
logger.error(f"SQL执行错误: {e}")
return_data["msg"] = "处理数据库信息时出错"
return return_data
return_data["msg"] = "添加成功\n"
return_data["msg"] += "仇人名称:"+name+"\n"
return_data["msg"] += "仇人备注:"+text+"\n"
return_data["msg"] += "添加时间:"+now+"\n"
return_data["msg"] += "记录人:"+user+"\n"
return_data["code"] = 200
return return_data
async def bilei_select(self,name:str):
"""
仇人 查找
"""
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
# 查询数据
try:
sql = "SELECT * FROM wzrybl WHERE name LIKE %s"
sqlid = await self.__db.fetch_all(sql, ("%"+name+"%",))
except Exception as e:
logger.error(f"SQL执行错误: {e}")
return_data["msg"] = "处理数据库信息时出错"
return return_data
# 加载模板
try:
return_data["temp"] = load_template("bilei.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["data"]["lists"] = sqlid
return_data["code"] = 200
return return_data
async def bilei_update(self, id:int, name:str, text:str, user:str):
"""
仇人 修改 ID 名称 备注
"""
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
# 获取系统时间
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 查询数据
try:
sql = "UPDATE wzrybl SET name = %s, text = %s, time = %s, user = %s WHERE id = %s"
rowcount = await self.__db.execute(sql, (name, text, now, user, id))
if rowcount > 0:
return_data["msg"] = "修改成功\n"
return_data["msg"] += "仇人名称:"+name+"\n"
return_data["msg"] += "仇人备注:"+text+"\n"
return_data["msg"] += "修改时间:"+now+"\n"
return_data["msg"] += "记录人:"+user+"\n"
return_data["code"] = 200
else:
return_data["msg"] = "修改失败,未找到对应记录"
except Exception as e:
logger.error(f"SQL执行错误: {e}")
return_data["msg"] = "处理数据库信息时出错"
return return_data
return return_data
async def bilei_delete(self, id:int):
"""
仇人 删除 ID
"""
return_data = {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
# 查询数据
try:
sql = "DELETE FROM wzrybl WHERE id = %s"
rowcount = await self.__db.execute(sql, (id,))
if rowcount > 0:
return_data["msg"] = "删除成功\n"
return_data["code"] = 200
else:
return_data["msg"] = "删除失败,未找到对应记录"
except Exception as e:
logger.error(f"SQL执行错误: {e}")
return_data["msg"] = "处理数据库信息时出错"
return return_data
return return_data
Binary file not shown.
Binary file not shown.
-90
View File
@@ -1,90 +0,0 @@
import aiomysql
class AsyncMySQL:
def __init__(self, db_config: dict):
self.db_config = db_config
self.pool = None
async def init_pool(self):
"""初始化连接池"""
if self.pool is None:
self.pool = await aiomysql.create_pool(**self.db_config)
async def close_pool(self):
"""关闭连接池"""
if self.pool:
self.pool.close()
await self.pool.wait_closed()
self.pool = None
async def fetch_one(self, sql: str, params=None):
"""查询单条数据"""
await self.init_pool()
async with self.pool.acquire() as conn: # type: ignore
async with conn.cursor(aiomysql.DictCursor) as cursor:
await cursor.execute(sql, params or ())
return await cursor.fetchone()
async def fetch_all(self, sql: str, params=None):
"""查询多条数据"""
await self.init_pool()
async with self.pool.acquire() as conn: # type: ignore
async with conn.cursor(aiomysql.DictCursor) as cursor:
await cursor.execute(sql, params or ())
return await cursor.fetchall()
async def execute(self, sql: str, params=None):
"""执行 SQLinsert/update/delete"""
await self.init_pool()
async with self.pool.acquire() as conn: # type: ignore
async with conn.cursor() as cursor:
await cursor.execute(sql, params or ())
await conn.commit()
return cursor.rowcount
async def executemany(self, sql: str, params_list):
"""批量执行 SQL"""
await self.init_pool()
async with self.pool.acquire() as conn: # type: ignore
async with conn.cursor() as cursor:
await cursor.executemany(sql, params_list)
await conn.commit()
return cursor.rowcount
async def truncate_table(self, table_name: str):
"""清空指定表"""
await self.init_pool()
async with self.pool.acquire() as conn: # type: ignore
async with conn.cursor() as cursor:
sql = f"TRUNCATE TABLE `{table_name}`"
await cursor.execute(sql)
await conn.commit()
return True
# ----------------------------------------------------------------------
# 新增:自动生成 SQL 的增删改功能
# ----------------------------------------------------------------------
async def insert_record(self, table: str, data: dict):
"""插入记录:data 是 dict"""
keys = ", ".join(f"`{k}`" for k in data.keys())
placeholders = ", ".join(["%s"] * len(data))
sql = f"INSERT INTO `{table}` ({keys}) VALUES ({placeholders})"
return await self.execute(sql, tuple(data.values()))
async def update_record(self, table: str, data: dict, where: dict):
"""更新记录:data、where 都是 dict"""
set_clause = ", ".join(f"`{k}`=%s" for k in data.keys())
where_clause = " AND ".join(f"`{k}`=%s" for k in where.keys())
sql = f"UPDATE `{table}` SET {set_clause} WHERE {where_clause}"
params = tuple(data.values()) + tuple(where.values())
return await self.execute(sql, params)
async def delete_record(self, table: str, where: dict):
"""删除记录:where 是 dict"""
where_clause = " AND ".join(f"`{k}`=%s" for k in where.keys())
sql = f"DELETE FROM `{table}` WHERE {where_clause}"
return await self.execute(sql, tuple(where.values()))
+41
View File
@@ -0,0 +1,41 @@
from pathlib import Path
import aiofiles
async def load_template(template_name: str) -> str:
"""
异步加载模板内容(非阻塞)
"""
plugin_dir = Path(__file__).parent.parent
template_path = plugin_dir / "templates" / template_name
if not template_path.exists():
raise FileNotFoundError(f"模板文件不存在: {template_path}")
async with aiofiles.open(template_path, "r", encoding="utf-8") as f:
return await f.read()
def extract_fields(data_list, fields):
"""
从字典列表中提取多个字段
Args:
data_list (list[dict]): 包含字典的列表
fields (list[str]): 要提取的字段名列表
Returns:
list[dict]: 只包含指定字段的新字典列表
"""
result = []
try:
for item in data_list:
extracted = {field: item.get(field) for field in fields}
result.append(extracted)
except Exception as e:
print(f"提取字段时出错: {e}")
return []
return result
-167
View File
@@ -1,167 +0,0 @@
import os
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from io import BytesIO
import base64
def load_template(template_name):
"""
从模板文件加载模板内容
Args:
template_name: 模板文件名(不带路径)
Returns:
str: 模板内容
"""
# 获取模板文件路径
plugin_dir = Path(__file__).parent.parent
template_path = plugin_dir / "templates" / template_name
# 检查文件是否存在
if not template_path.exists():
raise FileNotFoundError(f"模板文件不存在: {template_path}")
# 读取模板内容
with open(template_path, 'r', encoding='utf-8') as f:
return f.read()
def flatten_field(data_list, field_name):
"""
提取并扁平化指定字段的值
从一个字典列表中,收集指定字段的所有值。
如果字段的值是列表,则会被展开(扁平化)加入结果;
如果字段的值是单个元素,则直接加入结果。
Args:
data_list (list[dict]): 数据列表,每个元素是字典
field_name (str): 要提取的字段名
Returns:
list: 扁平化后的字段值列表
"""
extracted_data = []
for item in data_list:
if field_name in item and item[field_name]:
# 如果是 list,展开
if isinstance(item[field_name], list):
extracted_data.extend(item[field_name])
else:
extracted_data.append(item[field_name])
return extracted_data
def extract_fields(data_list, fields):
"""
从字典列表中提取多个字段
Args:
data_list (list[dict]): 包含字典的列表
fields (list[str]): 要提取的字段名列表
Returns:
list[dict]: 只包含指定字段的新字典列表
"""
result = []
try:
for item in data_list:
extracted = {field: item.get(field) for field in fields}
result.append(extracted)
except Exception as e:
print(f"提取字段时出错: {e}")
return []
return result
def extract_field(data_list, field_name):
"""
从列表中的字典提取指定字段的所有值
Args:
data_list (list): 数据列表,每个元素是 dict
field_name (str): 要提取的字段名
Returns:
list: 提取出来的字段值列表
"""
return [item[field_name] for item in data_list if field_name in item]
def gold_to_string(gold_amount):
"""
将金钱数值转换为字符串表示形式
Args:
gold_amount (int): 金钱数值,单位为铜币
Returns:
str: 格式化后的金钱字符串,例如 "1金2银3铜"
"""
if not gold_amount:
return "无价格"
parts = []
started = False # 标记是否已经遇到第一个非零位
bricks = gold_amount // 100000000
gold = (gold_amount % 100000000) // 10000
silver = (gold_amount % 10000) // 100
copper = gold_amount % 100
for value, unit in [(bricks, ""), (gold, ""), (silver, ""), (copper, "")]:
if value != 0:
started = True
if started:
parts.append(f"{value}{unit}")
return "".join(parts)
def plot_line_chart_base64(data, x_field, y_field, title=None, reverse_x=False):
"""
根据列表数据绘制折线图,返回 base64 图片字符串。
:param data: list[dict] 数据列表
:param x_field: str X轴字段
:param y_field: str Y轴字段
:param title: str 图表标题(可选)
:param reverse_x: bool 是否反转 X 轴方向(默认 False:从左往右;True:从右往左)
:return: str base64 图片字符串,可直接放到 <img src="..."> 中
"""
if not data:
raise ValueError("数据列表不能为空")
# 字体设置(支持中文)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 提取 X / Y 数据
x_values = [str(item.get(x_field, "")) for item in data]
y_values = [float(item.get(y_field, 0)) for item in data]
# 创建画布
plt.figure(figsize=(8, 5))
plt.plot(x_values, y_values, marker='o', color='#4a90e2', linewidth=2)
# 反转 X 轴
if reverse_x:
plt.gca().invert_xaxis()
# 标题与标签
if title is None:
title = f"{y_field} 折线图"
plt.grid(True, linestyle='--', alpha=0.5)
plt.xticks(rotation=30)
plt.tight_layout()
# 转 Base64
buffer = BytesIO()
plt.savefig(buffer, format='png', dpi=150)
plt.close()
img_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
return f"data:image/png;base64,{img_base64}"
+110
View File
@@ -0,0 +1,110 @@
# pyright: reportArgumentType=false
# pyright: reportAttributeAccessIssue=false
# pyright: reportIndexIssue=false
# pyright: reportOptionalMemberAccess=false
import json
import shutil
import pathlib
import inspect
from pathlib import Path
from typing import Union
import asyncio
from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult, MessageChain
from astrbot.api.star import Context, Star, register, StarTools
from astrbot.api import logger
from astrbot.api import AstrBotConfig
import astrbot.api.message_components as Comp
from astrbot.core.utils.session_waiter import (
SessionController,
session_waiter,
)
from .gok_data import GOKServer
class GOKCommands(Star):
def __init__(self, gok_data:GOKServer):
self.gokfun = gok_data
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 gok_helps(self, event: AstrMessageEvent):
"""王者功能"""
return await self.T2I_image_msg(event, self.gokfun.helps)
async def gok_zhanji(self, event: AstrMessageEvent,name: str,option:str = 0):
"""王者战绩"""
return await self.T2I_image_msg(event, lambda: self.gokfun.zhanji(name ,option))
async def gok_ziliao(self, event: AstrMessageEvent,name: str):
"""王者资料"""
return await self.T2I_image_msg(event, lambda: self.gokfun.ziliao(name))
async def gok_user_all(self, event: AstrMessageEvent):
"""角色查看"""
return await self.T2I_image_msg(event, self.gokfun.all)
async def gok_user_add(self, event: AstrMessageEvent, gokid: int, name: str):
"""角色添加 王者营地ID 名称"""
return await self.plain_msg(event, lambda: self.gokfun.add(gokid,name))
async def gok_user_update(self, event: AstrMessageEvent, gokid: int, name: str):
"""角色修改 王者营地ID 名称"""
return await self.plain_msg(event, lambda: self.gokfun.update(gokid,name))
async def gok_user_delete(self, event: AstrMessageEvent, gokid:int):
"""角色删除 王者营地ID"""
return await self.plain_msg(event, lambda: self.gokfun.delete(gokid))
async def gok_user_select(self, event: AstrMessageEvent, gokid):
"""角色查询 王者营地ID"""
return await self.T2I_image_msg(event, lambda: self.gokfun.select(gokid))
+448
View File
@@ -0,0 +1,448 @@
# pyright: reportArgumentType=false
# pyright: reportAttributeAccessIssue=false
# pyright: reportIndexIssue=false
# pyright: reportOptionalMemberAccess=false
# pyright: reportCallIssue=false
from datetime import datetime
from typing import Dict, Any, Optional, List, Union
import base64
from astrbot.api import logger
from astrbot.api import AstrBotConfig
from .request import APIClient
from .sqlite import AsyncSQLiteDB
from .fun_basic import load_template,extract_fields
class GOKServer:
def __init__(self, api_config, config:AstrBotConfig, sqlite:AsyncSQLiteDB ):
self._api = APIClient()
# 引用API配置文件
self._api_config = api_config
# 引用插件配置文件
self._config = config
# 引用数据库类
self._sql_db = sqlite
# 获取配置中的 Token
self.token = self._config.get("ytapi_token", "")
if self.token == "":
logger.info("获取配置token失败,请正确填写token,否则部分功能无法正常使用")
else:
logger.debug(f"获取配置token成功。{self.token}")
async def close(self):
"""释放底层 APIClient 资源"""
if self._api:
await self._api.close()
self._api = None
def _init_return_data(self) -> Dict[str, Any]:
"""初始化标准的返回数据结构"""
return {
"code": 0,
"msg": "功能函数未执行",
"data": {}
}
async def _base_request(
self,
config_key: str,
method: str,
params: Optional[Dict[str, Any]] = None,
out_key: Optional[str] = "data"
) -> Optional[Any]:
"""
基础请求封装,处理配置获取和API调用。
:param config_key: 配置字典中对应 API 的键名。
:param method: HTTP方法 ('GET''POST')。
:param params: 请求参数或 Body 数据。
:param out_key: 响应数据中需要提取的字段。
:return: 成功时返回提取后的数据,失败时返回 None。
"""
try:
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)
url = api_config.get("url", "")
if not url:
logger.error(f"API配置缺少 URL: {config_key}")
return None
if method.upper() == 'POST':
data = await self._api.post(url, data=request_params, out_key=out_key)
else: # 默认为 GET
data = await self._api.get(url, params=request_params, out_key=out_key)
if not data:
logger.warning(f"获取接口信息失败或返回空数据: {config_key}")
return data
except Exception as e:
logger.error(f"基础请求调用出错 ({config_key}): {e}")
return None
# --- 业务功能函数 ---
async def helps(self) -> Dict[str, Any]:
"""功能"""
return_data = self._init_return_data()
# 加载模板
try:
return_data["temp"] = await load_template("helps.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
async def add(self,gokid: int, name: str) -> Dict[str, Any]:
"""角色添加 王者营地ID 角色"""
return_data = self._init_return_data()
# 添加数据
try:
await self._sql_db.insert(
"users",
{
"gokid": gokid,
"name": name,
}
)
except FileNotFoundError as e:
logger.error(f"添加角色失败: {e}")
return_data["msg"] = "添加角色失败"
return return_data
return_data["data"] = (
"角色添加成功\n"
f"王者营地ID{gokid}\n"
f"角色名称:{name}\n"
)
return_data["code"] = 200
return return_data
async def all(self) -> Dict[str, Any]:
"""角色查看"""
return_data = self._init_return_data()
# 查询数据
try:
data = await self._sql_db.select_all("users")
except FileNotFoundError as e:
logger.error(f"查看角色失败: {e}")
return_data["msg"] = "查看角色失败"
return return_data
if not data:
return_data["msg"] = "未找到角色数据"
return return_data
# 加载模板
try:
return_data["temp"] = await load_template("jueshe.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
# 数据处理
return_data["data"]["lists"] = data
return_data["code"] = 200
return return_data
async def select(self, name) -> Dict[str, Any]:
"""角色查询 名称"""
return_data = self._init_return_data()
# 判断输入是否为整数
try:
int(name)
if int(name) >=100000000:
like = "gokid LIKE ?"
else:
raise Exception("id数据异常")
except (ValueError, TypeError, Exception):
like = "name LIKE ?"
# 模糊拼接
like_name = f"%{name}%"
# 查询数据
try:
data = await self._sql_db.select_all(
"users",
like,
(like_name,)
)
except FileNotFoundError as e:
logger.error(f"查询角色失败: {e}")
return_data["msg"] = "查询角色失败"
return return_data
if not data:
return_data["msg"] = "未查询到角色数据"
return return_data
# 加载模板
try:
return_data["temp"] = await load_template("jueshe.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
# 数据处理
return_data["data"]["lists"] = data
return_data["code"] = 200
return return_data
async def update(self, gokid:int, name: str) -> Dict[str, Any]:
"""角色修改 王者营地ID 角色"""
return_data = self._init_return_data()
data = await self._sql_db.select_one(
"users",
"gokid=?",
(gokid,)
)
if not data:
return_data["msg"] = "没有当前ID"
return return_data
# 修改数据
try:
await self._sql_db.update(
"users",
{
"name": name,
},
"gokid=?",
(gokid,)
)
except FileNotFoundError as e:
logger.error(f"避雷修改失败: {e}")
return_data["msg"] = "避雷修改失败"
return return_data
return_data["data"] = (
"角色修改成功\n"
f"王者营地ID{gokid}\n"
f"角色名称:{name}\n"
)
return_data["code"] = 200
return return_data
async def delete(self, gokid:int) -> Dict[str, Any]:
"""角色删除 王者营地ID"""
return_data = self._init_return_data()
data = await self._sql_db.select_one(
"users",
"gokid=?",
(gokid,)
)
if not data:
return_data["msg"] = "没有当前ID"
return return_data
# 删除
try:
await self._sql_db.delete(
"users",
"gokid=?",
(gokid,)
)
except FileNotFoundError as e:
logger.error(f"角色删除失败: {e}")
return_data["msg"] = "角色删除失败"
return return_data
return_data["data"] = f"角色删除成功。王者营地ID{gokid}"
return_data["code"] = 200
return return_data
async def get_gokid(self,name: str):
# 判断输入是否为整数
try:
# 直接返回输入
int(name)
if int(name) >=100000000:
gokid = name
return gokid
else:
raise Exception("输入不是ID")
except (ValueError, TypeError, Exception):
# 查询数据
try:
data = await self._sql_db.select_one(
"users",
"name=?",
(name,)
)
if not data:
gokid = None
return gokid
gokid = data['gokid']
return gokid
except FileNotFoundError as e:
logger.error(f"查询角色失败: {e}")
gokid = None
return gokid
async def zhanji(self,name: str ,option: str):
"""
战绩查询
"""
return_data = self._init_return_data()
# 获取配置中的 Token
token = self._config.get("ytapi_token", "")
if token == "":
return_data["msg"] = "系统未配置API访问Token"
return return_data
# ID查询
gokid = await self.get_gokid(name)
if not gokid :
return_data["msg"] = "未查询到该用户,请确认输入正确的角色或营地ID"
return return_data
#更新参数
params = {"id": gokid, "option": option, "key": token}
# 需要提取的字段
fields = ["gametime","killcnt","deadcnt","assistcnt","gameresult","mvpcnt","losemvp","mapName",
"oldMasterMatchScore","newMasterMatchScore","usedTime","winNum","failNum","roleJobName","stars","desc",
"gradeGame","heroIcon","godLikeCnt", "firstBlood","hero1TripleKillCnt","hero1UltraKillCnt","hero1RampageCnt","evaluateUrlV3","mvpUrlV3"]
# 获取数据
data: Optional[List[Dict[str, Any]]] = await self._base_request("gok_zhanji", "GET", params=params)
if not data:
return_data["msg"] = "获取接口信息失败"
return return_data
# 处理返回数据
try:
# 提取字段
result = extract_fields(data['list'], fields)
result = result[:25]
# 数据处理
for m in result:
minutes = m["usedTime"] // 60
seconds = m["usedTime"] % 60
m["time_str"] = f"{minutes}:{seconds:02d}"
return_data["data"]["data"] = result
except Exception as e:
logger.error(f"处理数据时出错: {e}")
return_data["msg"] = "处理接口返回信息时出错"
return return_data
# 加载模板
try:
return_data["temp"] = await load_template("wangzhezhanji.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
async def ziliao(self, name: str):
return_data = self._init_return_data()
# 获取配置中的 Token
token = self._config.get("ytapi_token", "")
if token == "":
return_data["msg"] = "系统未配置API访问Token"
return return_data
# ID查询
gokid = await self.get_gokid(name)
if not gokid :
return_data["msg"] = "未查询到该用户,请确认输入正确的角色或营地ID"
return return_data
#更新参数
params = {"id": gokid, "key": token}
# 获取数据
data: Optional[List[Dict[str, Any]]] = await self._base_request("gok_ziliao", "GET", params=params, out_key="")
logger.debug(data)
if not data:
return_data["msg"] = "获取接口信息失败"
return return_data
try:
# 转 base64
return_data["data"]["img_base64"] = base64.b64encode(data).decode("utf-8")
except Exception as e:
logger.error(f"处理数据时出错: {e}")
return_data["msg"] = "处理接口返回信息时出错"
return return_data
# 加载模板
try:
return_data["temp"] = await load_template("wzry_zl.html")
except FileNotFoundError:
logger.error(f"加载模板失败")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
+6 -7
View File
@@ -1,9 +1,10 @@
# core/request.py
import json
import aiohttp
import asyncio
from typing import Optional, Dict, Any, Union, List
from aiohttp import ClientTimeout, ClientSession
from astrbot.api import logger
class APIClient:
@@ -32,6 +33,7 @@ class APIClient:
"""关闭 Session"""
if self._session and not self._session.closed:
await self._session.close()
self._session = None
async def __aenter__(self):
await self.get_session()
@@ -74,23 +76,20 @@ class APIClient:
"""处理响应:自动识别二进制或JSON"""
try:
logger.debug(f"响应状态: {response.status}")
response.raise_for_status() # 如果是 4xx/5xx 直接抛出异常
response.raise_for_status()
content_type = response.headers.get('Content-Type', '').lower()
# 处理二进制流 (图片、文件等)
if 'image' in content_type or 'octet-stream' in content_type:
return await response.read()
# 处理 JSON
# 优先尝试标准 json 解析
try:
data = await response.json()
except Exception:
# 容错:有些 API 返回 text/html 但内容是 JSON
text = await response.text()
try:
data = json.loads(text)
loop = asyncio.get_running_loop()
data = await loop.run_in_executor(None, json.loads, text)
except json.JSONDecodeError:
logger.error(f"无法解析响应为 JSON。原始内容: {text[:100]}...")
return None
+71
View File
@@ -0,0 +1,71 @@
# pyright: reportOptionalMemberAccess=false
import aiosqlite
from typing import Any, Dict, List, Optional, Tuple
class AsyncSQLiteDB:
def __init__(self, db_path: str = "data.db"):
self.db_path = db_path
self.conn: Optional[aiosqlite.Connection] = None
# ======================
# 生命周期
# ======================
async def connect(self):
self.conn = await aiosqlite.connect(self.db_path)
self.conn.row_factory = aiosqlite.Row
async def close(self):
if self.conn:
await self.conn.close()
# ======================
# 基础执行
# ======================
async def execute(self, sql: str, params: Tuple = ()):
async with self.conn.execute(sql, params):
await self.conn.commit()
async def fetch_one(self, sql: str, params: Tuple = ()) -> Optional[Dict[str, Any]]:
async with self.conn.execute(sql, params) as cursor:
row = await cursor.fetchone()
return dict(row) if row else None
async def fetch_all(self, sql: str, params: Tuple = ()) -> List[Dict[str, Any]]:
async with self.conn.execute(sql, params) as cursor:
rows = await cursor.fetchall()
return [dict(r) for r in rows]
# ======================
# CRUD
# ======================
async def insert(self, table: str, data: Dict[str, Any]):
keys = ", ".join(data.keys())
placeholders = ", ".join(["?"] * len(data))
sql = f"INSERT INTO {table} ({keys}) VALUES ({placeholders})"
await self.execute(sql, tuple(data.values()))
async def update(self, table: str, data: Dict[str, Any], where: str, params: Tuple):
set_clause = ", ".join([f"{k}=?" for k in data.keys()])
sql = f"UPDATE {table} SET {set_clause} WHERE {where}"
await self.execute(sql, tuple(data.values()) + params)
async def delete(self, table: str, where: str, params: Tuple):
sql = f"DELETE FROM {table} WHERE {where}"
await self.execute(sql, params)
async def select_one(self, table: str, where: str = "", params: Tuple = ()):
sql = f"SELECT * FROM {table}"
if where:
sql += f" WHERE {where}"
return await self.fetch_one(sql, params)
async def select_all(self, table: str, where: str = "", params: Tuple = ()):
sql = f"SELECT * FROM {table}"
if where:
sql += f" WHERE {where}"
return await self.fetch_all(sql, params)
-14
View File
@@ -1,14 +0,0 @@
import http.client
conn = http.client.HTTPSConnection("api.t1qq.com")
payload = ''
headers = {
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
'Accept': '*/*',
'Host': 'api.t1qq.com',
'Connection': 'keep-alive'
}
conn.request("GET", "/api/tool/wzrr/ydtp?key=vBpEzoiC9z5A9c9Nn83IhLn6M9&id=489048724", payload, headers)
res = conn.getresponse()
data = res.read()
print(data)