mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-19 11:10:10 +08:00
更新插件商店功能,支持通过模块名操作插件
- 扩展插件添加、移除和更新功能,支持使用插件ID或模块名 - 增加更新全部插件的功能 - 优化插件商店的命令使用说明 - 修复了一些与插件模块名相关的逻辑问题
This commit is contained in:
@@ -15,10 +15,11 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
description="插件商店",
|
description="插件商店",
|
||||||
usage="""
|
usage="""
|
||||||
插件商店 : 查看当前的插件商店
|
插件商店 : 查看当前的插件商店
|
||||||
添加插件 id : 添加插件
|
添加插件 id or module : 添加插件
|
||||||
移除插件 id : 移除插件
|
移除插件 id or module : 移除插件
|
||||||
搜索插件 name or author : 搜索插件
|
搜索插件 name or author : 搜索插件
|
||||||
更新插件 id : 更新插件
|
更新插件 id or module : 更新插件
|
||||||
|
更新全部插件 : 更新全部插件
|
||||||
""".strip(),
|
""".strip(),
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
@@ -30,10 +31,11 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
_matcher = on_alconna(
|
_matcher = on_alconna(
|
||||||
Alconna(
|
Alconna(
|
||||||
"插件商店",
|
"插件商店",
|
||||||
Subcommand("add", Args["plugin_id", int]),
|
Subcommand("add", Args["plugin_id", int | str]),
|
||||||
Subcommand("remove", Args["plugin_id", int]),
|
Subcommand("remove", Args["plugin_id", int | str]),
|
||||||
Subcommand("search", Args["plugin_name_or_author", str]),
|
Subcommand("search", Args["plugin_name_or_author", str]),
|
||||||
Subcommand("update", Args["plugin_id", int]),
|
Subcommand("update", Args["plugin_id", int | str]),
|
||||||
|
Subcommand("update_all"),
|
||||||
),
|
),
|
||||||
permission=SUPERUSER,
|
permission=SUPERUSER,
|
||||||
priority=1,
|
priority=1,
|
||||||
@@ -68,6 +70,13 @@ _matcher.shortcut(
|
|||||||
prefix=True,
|
prefix=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_matcher.shortcut(
|
||||||
|
r"更新全部插件",
|
||||||
|
command="插件商店",
|
||||||
|
arguments=["update_all"],
|
||||||
|
prefix=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@_matcher.assign("$main")
|
@_matcher.assign("$main")
|
||||||
async def _(session: EventSession):
|
async def _(session: EventSession):
|
||||||
@@ -81,9 +90,12 @@ async def _(session: EventSession):
|
|||||||
|
|
||||||
|
|
||||||
@_matcher.assign("add")
|
@_matcher.assign("add")
|
||||||
async def _(session: EventSession, plugin_id: int):
|
async def _(session: EventSession, plugin_id: int | str):
|
||||||
try:
|
try:
|
||||||
await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send()
|
if isinstance(plugin_id, str):
|
||||||
|
await MessageUtils.build_message(f"正在添加插件 Module: {plugin_id}").send()
|
||||||
|
else:
|
||||||
|
await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send()
|
||||||
result = await ShopManage.add_plugin(plugin_id)
|
result = await ShopManage.add_plugin(plugin_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"添加插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
|
logger.error(f"添加插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
|
||||||
@@ -95,7 +107,7 @@ async def _(session: EventSession, plugin_id: int):
|
|||||||
|
|
||||||
|
|
||||||
@_matcher.assign("remove")
|
@_matcher.assign("remove")
|
||||||
async def _(session: EventSession, plugin_id: int):
|
async def _(session: EventSession, plugin_id: int | str):
|
||||||
try:
|
try:
|
||||||
result = await ShopManage.remove_plugin(plugin_id)
|
result = await ShopManage.remove_plugin(plugin_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -126,9 +138,12 @@ async def _(session: EventSession, plugin_name_or_author: str):
|
|||||||
|
|
||||||
|
|
||||||
@_matcher.assign("update")
|
@_matcher.assign("update")
|
||||||
async def _(session: EventSession, plugin_id: int):
|
async def _(session: EventSession, plugin_id: int | str):
|
||||||
try:
|
try:
|
||||||
await MessageUtils.build_message(f"正在更新插件 Id: {plugin_id}").send()
|
if isinstance(plugin_id, str):
|
||||||
|
await MessageUtils.build_message(f"正在更新插件 Module: {plugin_id}").send()
|
||||||
|
else:
|
||||||
|
await MessageUtils.build_message(f"正在更新插件 Id: {plugin_id}").send()
|
||||||
result = await ShopManage.update_plugin(plugin_id)
|
result = await ShopManage.update_plugin(plugin_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"更新插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
|
logger.error(f"更新插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
|
||||||
@@ -137,3 +152,16 @@ async def _(session: EventSession, plugin_id: int):
|
|||||||
).finish()
|
).finish()
|
||||||
logger.info(f"更新插件 Id: {plugin_id}", "插件商店", session=session)
|
logger.info(f"更新插件 Id: {plugin_id}", "插件商店", session=session)
|
||||||
await MessageUtils.build_message(result).send()
|
await MessageUtils.build_message(result).send()
|
||||||
|
|
||||||
|
@_matcher.assign("update_all")
|
||||||
|
async def _(session: EventSession):
|
||||||
|
try:
|
||||||
|
await MessageUtils.build_message("正在更新全部插件").send()
|
||||||
|
result = await ShopManage.update_all_plugin()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"更新全部插件失败", "插件商店", session=session, e=e)
|
||||||
|
await MessageUtils.build_message(
|
||||||
|
f"更新全部插件失败 e: {e}"
|
||||||
|
).finish()
|
||||||
|
logger.info(f"更新全部插件", "插件商店", session=session)
|
||||||
|
await MessageUtils.build_message(result).send()
|
||||||
@@ -90,7 +90,8 @@ class ShopManage:
|
|||||||
|
|
||||||
# 检查请求结果
|
# 检查请求结果
|
||||||
if res.status_code != 200 or res2.status_code != 200:
|
if res.status_code != 200 or res2.status_code != 200:
|
||||||
raise ValueError(f"下载错误, code: {res.status_code}, {res2.status_code}")
|
raise ValueError(
|
||||||
|
f"下载错误, code: {res.status_code}, {res2.status_code}")
|
||||||
|
|
||||||
# 解析并合并返回的 JSON 数据
|
# 解析并合并返回的 JSON 数据
|
||||||
data1 = json.loads(res.text)
|
data1 = json.loads(res.text)
|
||||||
@@ -175,19 +176,22 @@ class ShopManage:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_plugin(cls, plugin_id: int) -> str:
|
async def add_plugin(cls, plugin_id: int | str) -> str:
|
||||||
"""添加插件
|
"""添加插件
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
plugin_id: 插件id
|
plugin_id: 插件id或模块名
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
str: 返回消息
|
str: 返回消息
|
||||||
"""
|
"""
|
||||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||||
if plugin_id < 0 or plugin_id >= len(data):
|
if isinstance(plugin_id, int) and (plugin_id < 0 or plugin_id >= len(data)):
|
||||||
return "插件ID不存在..."
|
return "插件ID不存在..."
|
||||||
plugin_key = list(data.keys())[plugin_id]
|
elif isinstance(plugin_id, str) and plugin_id not in [v.module for k, v in data.items()]:
|
||||||
|
return "插件Module不存在..."
|
||||||
|
plugin_key = list(data.keys())[plugin_id] if isinstance(plugin_id, int) else {
|
||||||
|
v.module: k for k, v in data.items()}[plugin_id]
|
||||||
plugin_list = await cls.get_loaded_plugins("module")
|
plugin_list = await cls.get_loaded_plugins("module")
|
||||||
plugin_info = data[plugin_key]
|
plugin_info = data[plugin_key]
|
||||||
if plugin_info.module in [p[0] for p in plugin_list]:
|
if plugin_info.module in [p[0] for p in plugin_list]:
|
||||||
@@ -229,7 +233,8 @@ class ShopManage:
|
|||||||
else:
|
else:
|
||||||
raise ValueError("所有API获取插件文件失败,请检查网络连接")
|
raise ValueError("所有API获取插件文件失败,请检查网络连接")
|
||||||
files = repo_api.get_files(
|
files = repo_api.get_files(
|
||||||
module_path=module_path.replace(".", "/") + ("" if is_dir else ".py"),
|
module_path=module_path.replace(
|
||||||
|
".", "/") + ("" if is_dir else ".py"),
|
||||||
is_dir=is_dir,
|
is_dir=is_dir,
|
||||||
)
|
)
|
||||||
download_urls = [await repo_info.get_raw_download_urls(file) for file in files]
|
download_urls = [await repo_info.get_raw_download_urls(file) for file in files]
|
||||||
@@ -249,7 +254,8 @@ class ShopManage:
|
|||||||
req_download_urls = [
|
req_download_urls = [
|
||||||
await repo_info.get_raw_download_urls(file) for file in req_files
|
await repo_info.get_raw_download_urls(file) for file in req_files
|
||||||
]
|
]
|
||||||
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
|
req_paths: list[Path | str] = [
|
||||||
|
plugin_path / file for file in req_files]
|
||||||
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
|
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
|
||||||
if req_files:
|
if req_files:
|
||||||
result = await AsyncHttpx.gather_download_file(
|
result = await AsyncHttpx.gather_download_file(
|
||||||
@@ -265,20 +271,23 @@ class ShopManage:
|
|||||||
raise Exception("插件下载失败")
|
raise Exception("插件下载失败")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def remove_plugin(cls, plugin_id: int) -> str:
|
async def remove_plugin(cls, plugin_id: int | str) -> str:
|
||||||
"""移除插件
|
"""移除插件
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
plugin_id: 插件id
|
plugin_id: 插件id或模块名
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
str: 返回消息
|
str: 返回消息
|
||||||
"""
|
"""
|
||||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||||
if plugin_id < 0 or plugin_id >= len(data):
|
if isinstance(plugin_id, int) and (plugin_id < 0 or plugin_id >= len(data)):
|
||||||
return "插件ID不存在..."
|
return "插件ID不存在..."
|
||||||
plugin_key = list(data.keys())[plugin_id]
|
elif isinstance(plugin_id, str) and plugin_id not in [v.module for k, v in data.items()]:
|
||||||
plugin_info = data[plugin_key] # type: ignore
|
return "插件Module不存在..."
|
||||||
|
plugin_key = list(data.keys())[plugin_id] if isinstance(plugin_id, int) else {
|
||||||
|
v.module: k for k, v in data.items()}[plugin_id]
|
||||||
|
plugin_info = data[plugin_key]
|
||||||
path = BASE_PATH
|
path = BASE_PATH
|
||||||
if plugin_info.github_url:
|
if plugin_info.github_url:
|
||||||
path = BASE_PATH / "plugins"
|
path = BASE_PATH / "plugins"
|
||||||
@@ -340,7 +349,7 @@ class ShopManage:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update_plugin(cls, plugin_id: int) -> str:
|
async def update_plugin(cls, plugin_id: int | str) -> str:
|
||||||
"""更新插件
|
"""更新插件
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
@@ -350,9 +359,12 @@ class ShopManage:
|
|||||||
str: 返回消息
|
str: 返回消息
|
||||||
"""
|
"""
|
||||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||||
if plugin_id < 0 or plugin_id >= len(data):
|
if isinstance(plugin_id, int) and (plugin_id < 0 or plugin_id >= len(data)):
|
||||||
return "插件ID不存在..."
|
return "插件ID不存在..."
|
||||||
plugin_key = list(data.keys())[plugin_id]
|
elif isinstance(plugin_id, str) and plugin_id not in [v.module for k, v in data.items()]:
|
||||||
|
return "插件Module不存在..."
|
||||||
|
plugin_key = list(data.keys())[plugin_id] if isinstance(plugin_id, int) else {
|
||||||
|
v.module: k for k, v in data.items()}[plugin_id]
|
||||||
logger.info(f"尝试更新插件 {plugin_key}", "插件管理")
|
logger.info(f"尝试更新插件 {plugin_key}", "插件管理")
|
||||||
plugin_info = data[plugin_key]
|
plugin_info = data[plugin_key]
|
||||||
plugin_list = await cls.get_loaded_plugins("module", "version")
|
plugin_list = await cls.get_loaded_plugins("module", "version")
|
||||||
@@ -373,3 +385,41 @@ class ShopManage:
|
|||||||
is_external,
|
is_external,
|
||||||
)
|
)
|
||||||
return f"插件 {plugin_key} 更新成功! 重启后生效"
|
return f"插件 {plugin_key} 更新成功! 重启后生效"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def update_all_plugin(cls) -> str:
|
||||||
|
"""更新插件
|
||||||
|
|
||||||
|
参数:
|
||||||
|
plugin_id: 插件id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
str: 返回消息
|
||||||
|
"""
|
||||||
|
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||||
|
plugin_list = list(data.keys())
|
||||||
|
update_list = []
|
||||||
|
logger.info(f"尝试更新全部插件 {plugin_list}", "插件管理")
|
||||||
|
for plugin_key in plugin_list:
|
||||||
|
plugin_info = data[plugin_key]
|
||||||
|
plugin_list = await cls.get_loaded_plugins("module", "version")
|
||||||
|
suc_plugin = {p[0]: (p[1] or "Unknown") for p in plugin_list}
|
||||||
|
if plugin_info.module not in [p[0] for p in plugin_list]:
|
||||||
|
logger.debug(f"插件 {plugin_key} 未安装,跳过", "插件管理")
|
||||||
|
continue
|
||||||
|
if cls.check_version_is_new(plugin_info, suc_plugin):
|
||||||
|
logger.debug(f"插件 {plugin_key} 已是最新版本,跳过", "插件管理")
|
||||||
|
continue
|
||||||
|
logger.info(f"正在更新插件 {plugin_key}", "插件管理")
|
||||||
|
is_external = True
|
||||||
|
if plugin_info.github_url is None:
|
||||||
|
plugin_info.github_url = DEFAULT_GITHUB_URL
|
||||||
|
is_external = False
|
||||||
|
await cls.install_plugin_with_repo(
|
||||||
|
plugin_info.github_url,
|
||||||
|
plugin_info.module_path,
|
||||||
|
plugin_info.is_dir,
|
||||||
|
is_external,
|
||||||
|
)
|
||||||
|
update_list.append(plugin_key)
|
||||||
|
return "已更新插件 {}\n共计{}个插件! 重启后生效".format('\n- '.join(update_list), len(update_list))
|
||||||
Reference in New Issue
Block a user