diff --git a/core/aiosqlite.py b/core/aiosqlite.py index 11a4f5a..e1a6cb6 100644 --- a/core/aiosqlite.py +++ b/core/aiosqlite.py @@ -17,26 +17,26 @@ class AsyncSQLite: async def fetch_one(self, sql: str, params=None): await self.init() - async with self.conn.execute(sql, params or ()) as cursor: + async with self.conn.execute(sql, params or ()) as cursor: # type: ignore row = await cursor.fetchone() return dict(row) if row else None async def fetch_all(self, sql: str, params=None): await self.init() - async with self.conn.execute(sql, params or ()) as cursor: + async with self.conn.execute(sql, params or ()) as cursor: # type: ignore rows = await cursor.fetchall() return [dict(r) for r in rows] async def execute(self, sql: str, params=None): await self.init() - async with self.conn.execute(sql, params or ()): - await self.conn.commit() + async with self.conn.execute(sql, params or ()): # type: ignore + await self.conn.commit() # type: ignore return True async def executemany(self, sql: str, params_list): await self.init() - await self.conn.executemany(sql, params_list) - await self.conn.commit() + await self.conn.executemany(sql, params_list) # type: ignore + await self.conn.commit() # type: ignore return True async def insert_record(self, table: str, data: dict): @@ -56,3 +56,15 @@ class AsyncSQLite: where_clause = " AND ".join(f"`{k}`=?" for k in where.keys()) sql = f"DELETE FROM `{table}` WHERE {where_clause}" return await self.execute(sql, tuple(where.values())) + + async def clear_table(self, table: str): + """ + 清空指定表中的所有记录。 + Args: + table: 要清空的表名。 + Returns: + 如果操作成功则返回 True。 + """ + sql = f"DELETE FROM `{table}`" + # 使用 execute 函数执行 DELETE 语句 + return await self.execute(sql) \ No newline at end of file diff --git a/core/jx3_service.py b/core/jx3_service.py index aa04abe..a06bf56 100644 --- a/core/jx3_service.py +++ b/core/jx3_service.py @@ -4,11 +4,11 @@ from typing import Dict, Any, Optional, List, Union from astrbot.api import logger from .request import APIClient -from .async_mysql import AsyncMySQL +from .aiosqlite import AsyncSQLite from .function_basic import load_template,flatten_field,extract_fields,gold_to_string class JX3Service: - def __init__(self, api_config,db: AsyncMySQL ): + def __init__(self, api_config,db: AsyncSQLite ): self._api = APIClient() self._db = db self._api_config = api_config @@ -82,7 +82,7 @@ class JX3Service: data: Optional[Dict[str, Any]] = await self._base_request( "jx3_richang", "GET", params=params ) - + logger.info(f"richang 接口返回数据: {data}") if not data: return_data["msg"] = "获取接口信息失败" return return_data @@ -101,10 +101,10 @@ class JX3Service: ) # 安全地处理列表索引 - luck = data.get('luck', [None, None, None]) - luck_msg = f"[宠物福缘]:\n{luck[0] or '无'},{luck[1] or '无'},{luck[2] or '无'}\n" - card = data.get('card', [None, None, None]) - card_msg = f"[家园声望·加倍道具]:\n{card[0] or '无'},{card[1] or '无'},{card[2] or '无'}\n" + luck = data.get('luck', []) + luck_msg = f"[宠物福缘]:\n{', '.join(luck)}\n" + card = data.get('card', []) + card_msg = f"[家园声望·加倍道具]:\n{', '.join(card)}\n" team = data.get('team', [None, None, None]) team_msg = f"[武林通鉴·公共任务]:\n{team[0] or '无'}\n[武林通鉴·团队秘境]:\n{team[2] or '无'}\n" @@ -335,7 +335,7 @@ class JX3Service: sql = """ INSERT INTO searchdata (typeName, name, showName, picUrl, searchId, searchDescType) - VALUES (%s, %s, %s, %s, %s, %s) + VALUES (?, ?, ?, ?, ?, ?) """ # 增强数据提取的安全性 values_list = [ @@ -352,7 +352,7 @@ class JX3Service: # 插入数据 try: - await self._db.truncate_table("searchdata") + await self._db.clear_table("searchdata") await self._db.executemany(sql, values_list) except Exception as e: logger.error(f"数据插入失败: {e}") @@ -382,7 +382,7 @@ class JX3Service: # 进一步从 DB 查找 ID try: - sql = "SELECT searchId FROM searchdata WHERE showName=%s" + sql = "SELECT searchId FROM searchdata WHERE showName=?" sqldata = await self._db.fetch_one(sql, (showName,)) searchId = sqldata["searchId"] if sqldata else None except Exception as e: diff --git a/api_config.json b/data/api_config.json similarity index 100% rename from api_config.json rename to data/api_config.json diff --git a/data/local_data.db b/data/local_data.db index 5e2e853..b7d130c 100644 Binary files a/data/local_data.db and b/data/local_data.db differ diff --git a/main.py b/main.py index c8cce89..b670bbe 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,9 @@ import json +import shutil import asyncio +import pathlib from pathlib import Path +from typing import Union from datetime import datetime from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult, MessageChain @@ -8,7 +11,7 @@ from astrbot.api.star import Context, Star, register, StarTools from astrbot.api import logger from astrbot.api import AstrBotConfig -from .core.async_mysql import AsyncMySQL +from .core.aiosqlite import AsyncSQLite from .core.jx3_service import JX3Service @@ -25,10 +28,22 @@ class Jx3ApiPlugin(Star): #获取配置 self.conf = config # 本地数据存储路径 - self.local_data_dir = StarTools.get_data_dir("astrbot_plugin_jx3") - # api数据文件 - self.api_file_path = Path(__file__).parent / "api_config.json" - # 读取文件内容 + local_data_dir = StarTools.get_data_dir("astrbot_plugin_jx3") + # 插件数据文件路径 + data_file_path = Path(__file__).parent / "data" + # --- 调用函数完成检查和复制 --- + try: + self.file_local_data = self.check_and_copy_db( + local_data_dir=local_data_dir, + db_filename="local_data.db", + default_db_dir=data_file_path + ) + except FileNotFoundError as e: + # 处理默认文件丢失的严重错误 + logger.critical(f"插件初始化失败:{e}") + raise # 中断初始化 + # 读取配置文件 + self.api_file_path = Path(__file__).parent / "data" / "api_config.json" with open(self.api_file_path, 'r', encoding='utf-8') as f: self.api_config = json.load(f) # 初始化数据 @@ -38,25 +53,49 @@ class Jx3ApiPlugin(Star): async def initialize(self): - """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" - # 数据库配置 - db_config = { - 'host': '38.12.28.24', - 'port': 3306, - 'user': 'asrtbot', - 'password': 'qsc123456', - 'db': 'asrtbot', - 'charset': 'utf8mb4', - 'autocommit': True - } + """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" #创建类实例 - self.db = AsyncMySQL(db_config) + self.db = AsyncSQLite(str(self.file_local_data)) self.jx3fun = JX3Service(self.api_config,self.db) # 周期函数调用 - logger.info("jx3api插件创建实例完成") + + def check_and_copy_db(self, local_data_dir: Union[str, Path], db_filename: str, default_db_dir: Union[str, Path]) -> pathlib.Path: + """ + 检查本地数据目录中是否存在指定的数据库文件。 + 如果不存在,则从默认目录复制该文件。 + Args: + local_data_dir: 目标数据库文件所在的文件夹路径。 + db_filename: 数据库文件的名称 (例如: 'local_data.db')。 + default_db_dir: 默认/源数据库文件所在的文件夹路径。 + Returns: + 最终的数据库文件的完整 pathlib.Path 对象。 + Raises: + FileNotFoundError: 如果默认的源数据库文件不存在。 + """ + # 目标路径 + target_dir = pathlib.Path(local_data_dir) + target_file_path = target_dir / db_filename + # 源文件路径 + source_file_path = pathlib.Path(default_db_dir) / db_filename + # 假设默认文件名为 local_data.db + if not target_file_path.exists(): + logger.warning(f"本地数据库文件 {target_file_path.name} 不存在,正在从默认位置复制...") + # 1. 确保目标文件夹存在 + target_dir.mkdir(parents=True, exist_ok=True) + # 2. 检查源文件是否存在 + if not source_file_path.exists(): + raise FileNotFoundError(f"默认数据库源文件未找到!请检查路径: {source_file_path}") + # 3. 复制文件 + shutil.copy(source_file_path, target_file_path) + logger.info(f"数据库文件已成功复制到: {target_file_path}") + else: + logger.info(f"本地数据库文件 {target_file_path} 已存在,跳过复制。") + return target_file_path + + def inidata(self): """数据初始化""" self.test_server = False @@ -114,7 +153,7 @@ class Jx3ApiPlugin(Star): if data["code"] == 200: yield event.plain_result(data["data"]) else: - yield event.plain_result("msg") + yield event.plain_result(data["msg"]) return except Exception as e: logger.error(f"功能函数执行错误: {e}") @@ -129,7 +168,7 @@ class Jx3ApiPlugin(Star): if data["code"] == 200: yield event.plain_result(data["data"]) else: - yield event.plain_result("msg") + yield event.plain_result(data["msg"]) return except Exception as e: logger.error(f"功能函数执行错误: {e}") @@ -295,7 +334,7 @@ class Jx3ApiPlugin(Star): async def terminate(self): """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" - await self.db.close_pool() + await self.db.close() # 后台进程销毁 self.kf_task.cancel() logger.info("jx3api插件已卸载/停用") \ No newline at end of file