feat:更新MaiZone插件配置版本至2.1.0,移除不必要的HTTP端口和主机配置,优化QZone管理器的初始化逻辑,增强从适配器API获取Cookie的功能和异常处理。

This commit is contained in:
minecraft1024a
2025-08-12 18:53:25 +08:00
parent 7c0efafd50
commit e9a59d4015
5 changed files with 49 additions and 115 deletions

View File

@@ -106,68 +106,8 @@ class MaiZoneConfigLoader:
self.config_file_path = self.plugin_dir / config_filename
self.config_data: Dict[str, Any] = {}
self.config_specs: Dict[str, ConfigSectionSpec] = {}
self.config_version = "2.0.0"
self.config_version = "2.1.0"
# 初始化配置规格
self._init_config_specs()
def _init_config_specs(self):
"""初始化配置规格定义"""
# 插件基础配置节
plugin_section = ConfigSectionSpec("plugin", "插件基础配置")
plugin_section.add_field(ConfigFieldSpec("enable", bool, True, "是否启用插件"))
plugin_section.add_field(ConfigFieldSpec("config_version", str, "2.0.0", "配置文件版本"))
plugin_section.add_field(ConfigFieldSpec("http_port", str, "3000", "NapCat HTTP服务器端口号"))
plugin_section.add_field(ConfigFieldSpec("http_host", str, "127.0.0.1", "NapCat HTTP服务器地址"))
self.config_specs["plugin"] = plugin_section
# 模型相关配置节
models_section = ConfigSectionSpec("models", "模型相关配置")
models_section.add_field(ConfigFieldSpec("text_model", str, "replyer_1", "生成文本的模型名称"))
models_section.add_field(ConfigFieldSpec("siliconflow_apikey", str, "", "硅基流动AI生图API密钥"))
self.config_specs["models"] = models_section
# 发送说说配置节
send_section = ConfigSectionSpec("send", "发送说说配置")
send_section.add_field(ConfigFieldSpec("permission", list, ["2488036428"], "发送权限QQ号列表"))
send_section.add_field(ConfigFieldSpec("permission_type", str, "whitelist", "权限类型",
choices=["whitelist", "blacklist"]))
send_section.add_field(ConfigFieldSpec("enable_image", bool, False, "是否启用说说配图"))
send_section.add_field(ConfigFieldSpec("enable_ai_image", bool, False, "是否启用AI生成配图"))
send_section.add_field(ConfigFieldSpec("enable_reply", bool, True, "生成完成时是否发出回复"))
send_section.add_field(ConfigFieldSpec("ai_image_number", int, 1, "AI生成图片数量",
min_value=1, max_value=4))
send_section.add_field(ConfigFieldSpec("image_directory", str, "./plugins/built_in/Maizone/images",
"图片存储目录"))
self.config_specs["send"] = send_section
# 阅读说说配置节
read_section = ConfigSectionSpec("read", "阅读说说配置")
read_section.add_field(ConfigFieldSpec("permission", list, [], "阅读权限QQ号列表"))
read_section.add_field(ConfigFieldSpec("permission_type", str, "blacklist", "权限类型",
choices=["whitelist", "blacklist"]))
read_section.add_field(ConfigFieldSpec("read_number", int, 5, "一次读取的说说数量",
min_value=1, max_value=20))
read_section.add_field(ConfigFieldSpec("like_possibility", float, 1.0, "点赞概率",
min_value=0.0, max_value=1.0))
read_section.add_field(ConfigFieldSpec("comment_possibility", float, 0.3, "评论概率",
min_value=0.0, max_value=1.0))
self.config_specs["read"] = read_section
# 自动监控配置节
monitor_section = ConfigSectionSpec("monitor", "自动监控配置")
monitor_section.add_field(ConfigFieldSpec("enable_auto_monitor", bool, False, "是否启用自动监控好友说说"))
monitor_section.add_field(ConfigFieldSpec("interval_minutes", int, 10, "监控间隔时间(分钟)",
min_value=1, max_value=1440))
self.config_specs["monitor"] = monitor_section
# 定时发送配置节
schedule_section = ConfigSectionSpec("schedule", "定时发送配置")
schedule_section.add_field(ConfigFieldSpec("enable_schedule", bool, False, "是否启用定时发送说说"))
schedule_section.add_field(ConfigFieldSpec("schedules", dict,
{"08:00": "早安", "22:00": "晚安"},
"定时发送任务列表, 格式为 {\"时间\": \"主题\"}"))
self.config_specs["schedule"] = schedule_section
def load_config(self) -> bool:
"""

View File

@@ -83,14 +83,12 @@ class MonitorManager:
try:
# 获取配置
qq_account = config_api.get_global_config("bot.qq_account", "")
port = str(self.plugin.get_config("plugin.http_port", "3000"))
host = str(self.plugin.get_config("plugin.http_host", "127.0.0.1"))
read_num = 10 # 监控时读取较少的说说数量
logger.info("监控任务: 开始检查好友说说")
# 创建QZone管理器
qzone_manager = QZoneManager(port, host)
# 创建QZone管理器 (监控模式不需要stream_id)
qzone_manager = QZoneManager()
# 获取监控说说列表
feeds_list = await qzone_manager.monitor_read_feed(qq_account, read_num)

View File

@@ -200,14 +200,15 @@ class SendFeedCommand(BaseCommand):
"""发送说说到QQ空间"""
try:
# 获取配置
port = str(self.get_config("plugin.http_port", "3000"))
host = str(self.get_config("plugin.http_host", "127.0.0.1"))
qq_account = config_api.get_global_config("bot.qq_account", "")
enable_image = bool(self.get_config("send.enable_image", False))
image_dir = str(self.get_config("send.image_directory", "./plugins/Maizone/images"))
# 获取聊天流ID
stream_id = self.message.chat_stream.stream_id if self.message and self.message.chat_stream else None
# 创建QZone管理器并发送
qzone_manager = QZoneManager(port, host)
qzone_manager = QZoneManager(stream_id)
success = await qzone_manager.send_feed(story, image_dir, qq_account, enable_image)
return success
@@ -407,14 +408,15 @@ class SendFeedAction(BaseAction):
"""发送说说到QQ空间"""
try:
# 获取配置
port = str(self.get_config("plugin.http_port", "3000"))
host = str(self.get_config("plugin.http_host", "127.0.0.1"))
qq_account = config_api.get_global_config("bot.qq_account", "")
enable_image = bool(self.get_config("send.enable_image", False))
image_dir = str(self.get_config("send.image_directory", "./plugins/Maizone/images"))
# 获取聊天流ID
stream_id = self.chat_stream.stream_id if self.chat_stream else None
# 创建QZone管理器并发送
qzone_manager = QZoneManager(port, host)
qzone_manager = QZoneManager(stream_id)
success = await qzone_manager.send_feed(story, image_dir, qq_account, enable_image)
return success
@@ -540,8 +542,6 @@ class ReadFeedAction(BaseAction):
"""读取并处理说说"""
try:
# 获取配置
port = str(self.get_config("plugin.http_port", "3000"))
host = str(self.get_config("plugin.http_host", "127.0.0.1"))
qq_account = config_api.get_global_config("bot.qq_account", "")
num_raw = self.get_config("read.read_number", 5)
num = int(num_raw if num_raw is not None else 5)
@@ -550,8 +550,11 @@ class ReadFeedAction(BaseAction):
comment_raw = self.get_config("read.comment_possibility", 1.0)
comment_possibility = float(comment_raw if comment_raw is not None else 1.0)
# 获取聊天流ID
stream_id = self.chat_stream.stream_id if self.chat_stream else None
# 创建QZone管理器并读取说说
qzone_manager = QZoneManager(port, host)
qzone_manager = QZoneManager(stream_id)
feeds_list = await qzone_manager.read_feed(qq_account, target_qq, num)
# 处理错误情况
@@ -709,9 +712,7 @@ class MaiZonePlugin(BasePlugin):
config_schema: dict = {
"plugin": {
"enable": ConfigField(type=bool, default=True, description="是否启用插件"),
"config_version": ConfigField(type=str, default="2.0.0", description="配置文件版本"),
"http_port": ConfigField(type=str, default='3000', description="NapCat HTTP服务器端口号"),
"http_host": ConfigField(type=str, default='127.0.0.1', description="NapCat HTTP服务器地址"),
"config_version": ConfigField(type=str, default="2.1.0", description="配置文件版本"),
},
"models": {
"text_model": ConfigField(type=str, default="replyer_1", description="生成文本的模型名称"),

View File

@@ -16,7 +16,7 @@ import json5
from src.chat.utils.utils_image import get_image_manager
from src.common.logger import get_logger
from src.plugin_system.apis import llm_api, config_api, emoji_api
from src.plugin_system.apis import llm_api, config_api, emoji_api, send_api
# 获取日志记录器
logger = get_logger('MaiZone-Utils')
@@ -62,45 +62,43 @@ class CookieManager:
raise ValueError("无法从Cookie字符串中提取UIN")
@staticmethod
async def fetch_cookies(domain: str, port: str, host: str) -> Dict[str, Any]:
"""从NapCat获取Cookie"""
url = f"http://{host}:{port}/get_cookies?domain={domain}"
logger.info(f"正在从NapCat获取CookieURL: {url}")
async def fetch_cookies(domain: str, stream_id: Optional[str] = None) -> Dict[str, Any]:
"""通过适配器API从NapCat获取Cookie"""
logger.info(f"正在通过适配器API获取Cookie域名: {domain}")
try:
async with httpx.AsyncClient(timeout=20.0, trust_env=False) as client:
logger.debug(f"发送GET请求到: {url}")
resp = await client.get(url)
logger.debug(f"响应状态码: {resp.status_code}")
# 使用适配器命令API获取cookie
response = await send_api.adapter_command_to_stream(
action="get_cookies",
params={"domain": domain},
stream_id=stream_id,
timeout=40.0,
storage_message=False
)
logger.info(f"适配器响应: {response}")
if response.get("status") == "ok":
data = response.get("data", {})
if "cookies" in data:
logger.info("成功通过适配器API获取Cookie")
return data
else:
raise RuntimeError(f"适配器返回的数据中缺少cookies字段: {data}")
else:
error_msg = response.get("message", "未知错误")
raise RuntimeError(f"适配器API获取Cookie失败: {error_msg}")
resp.raise_for_status()
data = resp.json()
logger.info(f"响应数据: {data}")
if data.get("status") != "ok" or "cookies" not in data.get("data", {}):
raise RuntimeError(f"获取Cookie失败: {data}")
logger.info("成功从NapCat获取Cookie")
return data["data"]
except httpx.ConnectError as e:
logger.error(f"无法连接到NapCat服务器 {host}:{port} - 请检查NapCat是否运行: {str(e)}")
raise
except httpx.TimeoutException as e:
logger.error(f"连接NapCat超时: {str(e)}")
raise
except httpx.HTTPStatusError as e:
logger.error(f"NapCat返回错误状态码 {e.response.status_code}: {e.response.text}")
raise
except Exception as e:
logger.error(f"从NapCat获取Cookie失败: {str(e)}")
logger.error(f"通过适配器API获取Cookie失败: {str(e)}")
raise
@staticmethod
async def renew_cookies(port: str, host: str) -> bool:
async def renew_cookies(stream_id: Optional[str] = None) -> bool:
"""更新Cookie文件"""
try:
domain = "user.qzone.qq.com"
cookie_data = await CookieManager.fetch_cookies(domain, port, host)
cookie_data = await CookieManager.fetch_cookies(domain, stream_id)
cookie_str = cookie_data["cookies"]
parsed_cookies = CookieManager.parse_cookie_string(cookie_str)
uin = CookieManager.extract_uin_from_cookie(cookie_str)
@@ -755,17 +753,16 @@ class QZoneAPI:
class QZoneManager:
"""QQ空间管理器 - 高级封装类"""
def __init__(self, port: str, host: str):
def __init__(self, stream_id: Optional[str] = None):
"""初始化QZone管理器"""
self.port = port
self.host = host
self.stream_id = stream_id
self.cookie_manager = CookieManager()
async def _get_qzone_api(self, qq_account: str) -> Optional[QZoneAPI]:
"""获取QZone API实例"""
try:
# 更新Cookie
await self.cookie_manager.renew_cookies(self.port, self.host)
await self.cookie_manager.renew_cookies(self.stream_id)
# 加载Cookie
cookies = self.cookie_manager.load_cookies(qq_account)

View File

@@ -233,14 +233,12 @@ class ScheduleManager:
"""发送定时说说"""
try:
# 获取配置
port = str(self.plugin.get_config("plugin.http_port", "3000"))
host = self.plugin.get_config("plugin.http_host", "127.0.0.1")
qq_account = config_api.get_global_config("bot.qq_account", "")
enable_image = self.plugin.get_config("send.enable_image", False)
image_dir = str(self.plugin.get_config("send.image_directory", "./plugins/Maizone/images"))
# 创建QZone管理器并发送
qzone_manager = QZoneManager(port, host)
# 创建QZone管理器并发送 (定时任务不需要stream_id)
qzone_manager = QZoneManager()
success = await qzone_manager.send_feed(story, image_dir, qq_account, enable_image)
if success: