mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 14:22:55 +08:00
feat(plugin_store): 添加搜索插件功能及更新配置URL
添加了一个新的搜索命令,允许用户根据插件名称或作者搜索插件。此外,更新了插件配置的URL列表,以使用新的API端点。还修复了requirements.txt处理中的日志记录问题,并对插件安装和删除流程进行了微调。
This commit is contained in:
parent
28b7415581
commit
e0f323fdeb
@ -1,12 +1,13 @@
|
|||||||
from nonebot.permission import SUPERUSER
|
from nonebot.permission import SUPERUSER # type: ignore
|
||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata # type: ignore
|
||||||
from nonebot_plugin_alconna import Alconna, Args, Subcommand, on_alconna
|
from nonebot_plugin_alconna import Alconna, Args, Subcommand, on_alconna # type: ignore
|
||||||
from nonebot_plugin_session import EventSession
|
from nonebot_plugin_session import EventSession # type: ignore
|
||||||
|
from nonebot.exception import FinishedException # type: ignore
|
||||||
|
|
||||||
from zhenxun.configs.utils import PluginExtraData
|
from zhenxun.configs.utils import PluginExtraData # type: ignore
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger # type: ignore
|
||||||
from zhenxun.utils.enum import PluginType
|
from zhenxun.utils.enum import PluginType # type: ignore
|
||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils # type: ignore
|
||||||
|
|
||||||
from .data_source import ShopManage
|
from .data_source import ShopManage
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
插件商店 : 查看当前的插件商店
|
插件商店 : 查看当前的插件商店
|
||||||
添加插件 id : 添加插件
|
添加插件 id : 添加插件
|
||||||
移除插件 id : 移除插件
|
移除插件 id : 移除插件
|
||||||
|
搜索插件 name or author : 搜索插件
|
||||||
""".strip(),
|
""".strip(),
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
@ -30,13 +32,13 @@ _matcher = on_alconna(
|
|||||||
"插件商店",
|
"插件商店",
|
||||||
Subcommand("add", Args["plugin_id", int]),
|
Subcommand("add", Args["plugin_id", int]),
|
||||||
Subcommand("remove", Args["plugin_id", int]),
|
Subcommand("remove", Args["plugin_id", int]),
|
||||||
|
Subcommand("search", Args["plugin_name_or_author", str]),
|
||||||
),
|
),
|
||||||
permission=SUPERUSER,
|
permission=SUPERUSER,
|
||||||
priority=1,
|
priority=1,
|
||||||
block=True,
|
block=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_matcher.shortcut(
|
_matcher.shortcut(
|
||||||
r"添加插件",
|
r"添加插件",
|
||||||
command="插件商店",
|
command="插件商店",
|
||||||
@ -51,6 +53,13 @@ _matcher.shortcut(
|
|||||||
prefix=True,
|
prefix=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_matcher.shortcut(
|
||||||
|
r"搜索插件",
|
||||||
|
command="插件商店",
|
||||||
|
arguments=["search", "{%0}"],
|
||||||
|
prefix=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@_matcher.assign("$main")
|
@_matcher.assign("$main")
|
||||||
async def _(session: EventSession):
|
async def _(session: EventSession):
|
||||||
@ -58,6 +67,8 @@ async def _(session: EventSession):
|
|||||||
result = await ShopManage.get_plugins_info()
|
result = await ShopManage.get_plugins_info()
|
||||||
logger.info("查看插件列表", "插件商店", session=session)
|
logger.info("查看插件列表", "插件商店", session=session)
|
||||||
await MessageUtils.build_message(result).finish()
|
await MessageUtils.build_message(result).finish()
|
||||||
|
except FinishedException:
|
||||||
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"查看插件列表失败 e: {e}", "插件商店", session=session, e=e)
|
logger.error(f"查看插件列表失败 e: {e}", "插件商店", session=session, e=e)
|
||||||
|
|
||||||
@ -66,6 +77,8 @@ async def _(session: EventSession):
|
|||||||
async def _(session: EventSession, plugin_id: int):
|
async def _(session: EventSession, plugin_id: int):
|
||||||
try:
|
try:
|
||||||
result = await ShopManage.add_plugin(plugin_id)
|
result = await ShopManage.add_plugin(plugin_id)
|
||||||
|
except FinishedException:
|
||||||
|
pass
|
||||||
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)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
@ -79,6 +92,8 @@ async def _(session: EventSession, plugin_id: int):
|
|||||||
async def _(session: EventSession, plugin_id: int):
|
async def _(session: EventSession, plugin_id: int):
|
||||||
try:
|
try:
|
||||||
result = await ShopManage.remove_plugin(plugin_id)
|
result = await ShopManage.remove_plugin(plugin_id)
|
||||||
|
except FinishedException:
|
||||||
|
pass
|
||||||
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)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
@ -86,3 +101,17 @@ 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).finish()
|
await MessageUtils.build_message(result).finish()
|
||||||
|
|
||||||
|
@_matcher.assign("search")
|
||||||
|
async def _(session: EventSession, plugin_name_or_author: str):
|
||||||
|
try:
|
||||||
|
result = await ShopManage.search_plugin(plugin_name_or_author)
|
||||||
|
except FinishedException:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"搜索插件 name: {plugin_name_or_author}失败", "插件商店", session=session, e=e)
|
||||||
|
await MessageUtils.build_message(
|
||||||
|
f"搜索插件 name: {plugin_name_or_author} 失败 e: {e}"
|
||||||
|
).finish()
|
||||||
|
logger.info(f"搜索插件 name: {plugin_name_or_author}", "插件商店", session=session)
|
||||||
|
await MessageUtils.build_message(result).finish()
|
||||||
|
|||||||
@ -4,12 +4,12 @@ BASE_PATH = Path() / "zhenxun"
|
|||||||
BASE_PATH.mkdir(parents=True, exist_ok=True)
|
BASE_PATH.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
CONFIG_URL = (
|
CONFIG_URL_LIST = [
|
||||||
"https://cdn.jsdelivr.net/gh/HibiKier/zhenxun_bot_plugins/plugins.json"
|
("https://cdn.jsdelivr.net/gh/HibiKier/zhenxun_bot_plugins/plugins.json",
|
||||||
)
|
"https://api.github.com/repos/HibiKier/zhenxun_bot_plugins/contents/{}?ref=main")
|
||||||
|
]
|
||||||
"""插件信息文件"""
|
"""插件信息文件"""
|
||||||
|
|
||||||
DOWNLOAD_URL = (
|
CONFIG_URL = CONFIG_URL_LIST[0][0]
|
||||||
"https://api.github.com/repos/HibiKier/zhenxun_bot_plugins/contents/{}?ref=main"
|
|
||||||
)
|
DOWNLOAD_URL = CONFIG_URL_LIST[0][1]
|
||||||
"""插件下载地址"""
|
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
|
||||||
|
|
||||||
import nonebot
|
import nonebot
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger # type: ignore
|
||||||
from zhenxun.utils.http_utils import AsyncHttpx
|
from zhenxun.utils.http_utils import AsyncHttpx # type: ignore
|
||||||
from zhenxun.utils.image_utils import BuildImage, ImageTemplate, RowStyle
|
from zhenxun.utils.image_utils import BuildImage, ImageTemplate, RowStyle # type: ignore
|
||||||
|
|
||||||
from .config import BASE_PATH, CONFIG_URL, DOWNLOAD_URL
|
from .config import BASE_PATH, CONFIG_URL, DOWNLOAD_URL
|
||||||
|
|
||||||
@ -87,16 +86,20 @@ async def download_file(url: str):
|
|||||||
|
|
||||||
def install_requirement(plugin_path: Path):
|
def install_requirement(plugin_path: Path):
|
||||||
requirement_path = plugin_path / "requirement.txt"
|
requirement_path = plugin_path / "requirement.txt"
|
||||||
|
|
||||||
if not requirement_path.exists():
|
if not requirement_path.exists():
|
||||||
logger.debug(f"No requirement.txt found for plugin: {plugin_path.name}", "插件管理")
|
logger.debug(
|
||||||
|
f"No requirement.txt found for plugin: {plugin_path.name}", "插件管理")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(["pip", "install", "-r", str(requirement_path)], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
result = subprocess.run(["pip", "install", "-r", str(requirement_path)],
|
||||||
logger.debug(f"Successfully installed dependencies for plugin: {plugin_path.name}. Output:\n{result.stdout}", "插件管理")
|
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
logger.debug(
|
||||||
|
f"Successfully installed dependencies for plugin: {plugin_path.name}. Output:\n{result.stdout}", "插件管理")
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
logger.error(f"Failed to install dependencies for plugin: {plugin_path.name}. Error:\n{e.stderr}")
|
logger.error(
|
||||||
|
f"Failed to install dependencies for plugin: {plugin_path.name}. Error:\n{e.stderr}")
|
||||||
|
|
||||||
|
|
||||||
class ShopManage:
|
class ShopManage:
|
||||||
@ -137,18 +140,19 @@ class ShopManage:
|
|||||||
for k in data.copy():
|
for k in data.copy():
|
||||||
if data[k]["plugin_type"]:
|
if data[k]["plugin_type"]:
|
||||||
data[k]["plugin_type"] = cls.type2name[data[k]["plugin_type"]]
|
data[k]["plugin_type"] = cls.type2name[data[k]["plugin_type"]]
|
||||||
suc_plugin = [p.name for p in nonebot.get_loaded_plugins()]
|
suc_plugin = [p.name for p in nonebot.get_loaded_plugins() # type: ignore
|
||||||
|
]
|
||||||
data_list = [
|
data_list = [
|
||||||
[
|
[
|
||||||
"已安装" if v[1]["module"] in suc_plugin else "",
|
"已安装" if plugin_info[1]["module"] in suc_plugin else "",
|
||||||
i,
|
id,
|
||||||
v[0],
|
plugin_info[0],
|
||||||
v[1]["description"],
|
plugin_info[1]["description"],
|
||||||
v[1]["author"],
|
plugin_info[1]["author"],
|
||||||
v[1]["version"],
|
plugin_info[1]["version"],
|
||||||
v[1]["plugin_type"],
|
plugin_info[1]["plugin_type"],
|
||||||
]
|
]
|
||||||
for i, v in enumerate(data.items())
|
for id, plugin_info in enumerate(data.items())
|
||||||
]
|
]
|
||||||
return await ImageTemplate.table_page(
|
return await ImageTemplate.table_page(
|
||||||
"插件列表",
|
"插件列表",
|
||||||
@ -187,11 +191,11 @@ class ShopManage:
|
|||||||
return "插件下载地址构建失败..."
|
return "插件下载地址构建失败..."
|
||||||
logger.debug(f"尝试下载插件 URL: {url_path}", "插件管理")
|
logger.debug(f"尝试下载插件 URL: {url_path}", "插件管理")
|
||||||
await download_file(DOWNLOAD_URL.format(url_path))
|
await download_file(DOWNLOAD_URL.format(url_path))
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
plugin_path = BASE_PATH / "/".join(module_path_split)
|
plugin_path = BASE_PATH / "/".join(module_path_split)
|
||||||
install_requirement(plugin_path)
|
install_requirement(plugin_path)
|
||||||
|
|
||||||
return f"插件 {plugin_key} 安装成功!"
|
return f"插件 {plugin_key} 安装成功!"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -214,3 +218,43 @@ class ShopManage:
|
|||||||
else:
|
else:
|
||||||
path.unlink()
|
path.unlink()
|
||||||
return f"插件 {plugin_key} 移除成功!"
|
return f"插件 {plugin_key} 移除成功!"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def search_plugin(cls, plugin_name_or_author: str) -> BuildImage | str:
|
||||||
|
data: dict = await cls.__get_data()
|
||||||
|
column_name = ["-", "ID", "名称", "简介", "作者", "版本", "类型"]
|
||||||
|
for k in data.copy():
|
||||||
|
if data[k]["plugin_type"]:
|
||||||
|
data[k]["plugin_type"] = cls.type2name[data[k]["plugin_type"]]
|
||||||
|
|
||||||
|
suc_plugin = [p.name for p in nonebot.get_loaded_plugins()] # type: ignore
|
||||||
|
filtered_data = [
|
||||||
|
(id, plugin_info)
|
||||||
|
for id, plugin_info in enumerate(data.items())
|
||||||
|
if plugin_name_or_author.lower() in plugin_info[0].lower() or
|
||||||
|
plugin_name_or_author.lower() in plugin_info[1]["author"].lower()
|
||||||
|
]
|
||||||
|
|
||||||
|
data_list = [
|
||||||
|
[
|
||||||
|
"已安装" if plugin_info[1]["module"] in suc_plugin else "",
|
||||||
|
id,
|
||||||
|
plugin_info[0],
|
||||||
|
plugin_info[1]["description"],
|
||||||
|
plugin_info[1]["author"],
|
||||||
|
plugin_info[1]["version"],
|
||||||
|
plugin_info[1]["plugin_type"],
|
||||||
|
]
|
||||||
|
for id, plugin_info in filtered_data
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(data_list) == 0:
|
||||||
|
return "未找到插件..."
|
||||||
|
|
||||||
|
return await ImageTemplate.table_page(
|
||||||
|
"插件列表",
|
||||||
|
f"通过安装/卸载插件 ID 来管理插件",
|
||||||
|
column_name,
|
||||||
|
data_list,
|
||||||
|
text_style=row_style,
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue
Block a user