mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-14 13:42:56 +08:00
parent
4bcc5aeea5
commit
acfed0837a
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -29,6 +29,7 @@
|
|||||||
"unban",
|
"unban",
|
||||||
"Uninfo",
|
"Uninfo",
|
||||||
"userinfo",
|
"userinfo",
|
||||||
|
"webui",
|
||||||
"zhenxun"
|
"zhenxun"
|
||||||
],
|
],
|
||||||
"python.analysis.autoImportCompletions": true,
|
"python.analysis.autoImportCompletions": true,
|
||||||
|
|||||||
@ -13,7 +13,11 @@ from pytest_mock import MockerFixture
|
|||||||
from respx import MockRouter
|
from respx import MockRouter
|
||||||
|
|
||||||
from tests.config import BotId, GroupId, MessageId, UserId
|
from tests.config import BotId, GroupId, MessageId, UserId
|
||||||
from tests.utils import _v11_group_message_event, _v11_private_message_send
|
from tests.utils import (
|
||||||
|
_v11_group_message_event,
|
||||||
|
_v11_private_message_send,
|
||||||
|
get_reply_cq,
|
||||||
|
)
|
||||||
from tests.utils import get_response_json as _get_response_json
|
from tests.utils import get_response_json as _get_response_json
|
||||||
|
|
||||||
|
|
||||||
@ -311,6 +315,12 @@ async def test_check_update_release(
|
|||||||
to_me=True,
|
to_me=True,
|
||||||
)
|
)
|
||||||
ctx.receive_event(bot, event)
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(
|
||||||
|
event=event,
|
||||||
|
message=Message(f"{get_reply_cq(MessageId.MESSAGE_ID)}正在进行检查更新..."),
|
||||||
|
result=None,
|
||||||
|
bot=bot,
|
||||||
|
)
|
||||||
ctx.should_call_api(
|
ctx.should_call_api(
|
||||||
"send_msg",
|
"send_msg",
|
||||||
_v11_private_message_send(
|
_v11_private_message_send(
|
||||||
@ -401,6 +411,12 @@ async def test_check_update_main(
|
|||||||
to_me=True,
|
to_me=True,
|
||||||
)
|
)
|
||||||
ctx.receive_event(bot, event)
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(
|
||||||
|
event=event,
|
||||||
|
message=Message(f"{get_reply_cq(MessageId.MESSAGE_ID)}正在进行检查更新..."),
|
||||||
|
result=None,
|
||||||
|
bot=bot,
|
||||||
|
)
|
||||||
ctx.should_call_api(
|
ctx.should_call_api(
|
||||||
"send_msg",
|
"send_msg",
|
||||||
_v11_private_message_send(
|
_v11_private_message_send(
|
||||||
|
|||||||
@ -5,6 +5,10 @@ from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageSegme
|
|||||||
from nonebot.adapters.onebot.v11.event import Sender
|
from nonebot.adapters.onebot.v11.event import Sender
|
||||||
|
|
||||||
|
|
||||||
|
def get_reply_cq(uid: int | str) -> str:
|
||||||
|
return f"[CQ:reply,id={uid}]"
|
||||||
|
|
||||||
|
|
||||||
def get_response_json(base_path: Path, file: str) -> dict:
|
def get_response_json(base_path: Path, file: str) -> dict:
|
||||||
try:
|
try:
|
||||||
return json.loads(
|
return json.loads(
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from nonebot_plugin_alconna import (
|
|||||||
on_alconna,
|
on_alconna,
|
||||||
store_true,
|
store_true,
|
||||||
)
|
)
|
||||||
from nonebot_plugin_session import EventSession
|
from nonebot_plugin_uninfo import Uninfo
|
||||||
|
|
||||||
from zhenxun.configs.utils import PluginExtraData
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
@ -22,7 +22,7 @@ from zhenxun.utils.manager.resource_manager import (
|
|||||||
)
|
)
|
||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
|
||||||
from ._data_source import UpdateManage
|
from ._data_source import UpdateManager
|
||||||
|
|
||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
name="自动更新",
|
name="自动更新",
|
||||||
@ -32,16 +32,18 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
检查更新真寻最新版本,包括了自动更新
|
检查更新真寻最新版本,包括了自动更新
|
||||||
资源文件大小一般在130mb左右,除非必须更新一般仅更新代码文件
|
资源文件大小一般在130mb左右,除非必须更新一般仅更新代码文件
|
||||||
指令:
|
指令:
|
||||||
检查更新 [main|release|resource] ?[-r]
|
检查更新 [main|release|resource|webui] ?[-r]
|
||||||
main: main分支
|
main: main分支
|
||||||
release: 最新release
|
release: 最新release
|
||||||
resource: 资源文件
|
resource: 资源文件
|
||||||
|
webui: webui文件
|
||||||
-r: 下载资源文件,一般在更新main或release时使用
|
-r: 下载资源文件,一般在更新main或release时使用
|
||||||
示例:
|
示例:
|
||||||
检查更新 main
|
检查更新 main
|
||||||
检查更新 main -r
|
检查更新 main -r
|
||||||
检查更新 release -r
|
检查更新 release -r
|
||||||
检查更新 resource
|
检查更新 resource
|
||||||
|
检查更新 webui
|
||||||
""".strip(),
|
""".strip(),
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
@ -53,7 +55,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
_matcher = on_alconna(
|
_matcher = on_alconna(
|
||||||
Alconna(
|
Alconna(
|
||||||
"检查更新",
|
"检查更新",
|
||||||
Args["ver_type?", ["main", "release", "resource"]],
|
Args["ver_type?", ["main", "release", "resource", "webui"]],
|
||||||
Option("-r|--resource", action=store_true, help_text="下载资源文件"),
|
Option("-r|--resource", action=store_true, help_text="下载资源文件"),
|
||||||
),
|
),
|
||||||
priority=1,
|
priority=1,
|
||||||
@ -66,23 +68,24 @@ _matcher = on_alconna(
|
|||||||
@_matcher.handle()
|
@_matcher.handle()
|
||||||
async def _(
|
async def _(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
session: EventSession,
|
session: Uninfo,
|
||||||
ver_type: Match[str],
|
ver_type: Match[str],
|
||||||
resource: Query[bool] = Query("resource", False),
|
resource: Query[bool] = Query("resource", False),
|
||||||
):
|
):
|
||||||
if not session.id1:
|
|
||||||
await MessageUtils.build_message("用户id为空...").finish()
|
|
||||||
result = ""
|
result = ""
|
||||||
|
await MessageUtils.build_message("正在进行检查更新...").send(reply_to=True)
|
||||||
if ver_type.result in {"main", "release"}:
|
if ver_type.result in {"main", "release"}:
|
||||||
if not ver_type.available:
|
if not ver_type.available:
|
||||||
result = await UpdateManage.check_version()
|
result = await UpdateManager.check_version()
|
||||||
logger.info("查看当前版本...", "检查更新", session=session)
|
logger.info("查看当前版本...", "检查更新", session=session)
|
||||||
await MessageUtils.build_message(result).finish()
|
await MessageUtils.build_message(result).finish()
|
||||||
try:
|
try:
|
||||||
result = await UpdateManage.update(bot, session.id1, ver_type.result)
|
result = await UpdateManager.update(bot, session.user.id, ver_type.result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("版本更新失败...", "检查更新", session=session, e=e)
|
logger.error("版本更新失败...", "检查更新", session=session, e=e)
|
||||||
await MessageUtils.build_message(f"更新版本失败...e: {e}").finish()
|
await MessageUtils.build_message(f"更新版本失败...e: {e}").finish()
|
||||||
|
elif ver_type.result == "webui":
|
||||||
|
result = await UpdateManager.update_webui()
|
||||||
if resource.result or ver_type.result == "resource":
|
if resource.result or ver_type.result == "resource":
|
||||||
try:
|
try:
|
||||||
await ResourceManager.init_resources(True)
|
await ResourceManager.init_resources(True)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import zipfile
|
|||||||
from nonebot.adapters import Bot
|
from nonebot.adapters import Bot
|
||||||
from nonebot.utils import run_sync
|
from nonebot.utils import run_sync
|
||||||
|
|
||||||
|
from zhenxun.configs.path_config import DATA_PATH
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
from zhenxun.utils.github_utils import GithubUtils
|
from zhenxun.utils.github_utils import GithubUtils
|
||||||
from zhenxun.utils.github_utils.models import RepoInfo
|
from zhenxun.utils.github_utils.models import RepoInfo
|
||||||
@ -17,6 +18,7 @@ from .config import (
|
|||||||
BACKUP_PATH,
|
BACKUP_PATH,
|
||||||
BASE_PATH,
|
BASE_PATH,
|
||||||
BASE_PATH_STRING,
|
BASE_PATH_STRING,
|
||||||
|
COMMAND,
|
||||||
DEFAULT_GITHUB_URL,
|
DEFAULT_GITHUB_URL,
|
||||||
DOWNLOAD_GZ_FILE,
|
DOWNLOAD_GZ_FILE,
|
||||||
DOWNLOAD_ZIP_FILE,
|
DOWNLOAD_ZIP_FILE,
|
||||||
@ -38,7 +40,7 @@ def install_requirement():
|
|||||||
|
|
||||||
if not requirement_path.exists():
|
if not requirement_path.exists():
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"没有找到zhenxun的requirement.txt,目标路径为{requirement_path}", "插件管理"
|
f"没有找到zhenxun的requirement.txt,目标路径为{requirement_path}", COMMAND
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@ -48,9 +50,9 @@ def install_requirement():
|
|||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
logger.debug(f"成功安装真寻依赖,日志:\n{result.stdout}", "插件管理")
|
logger.debug(f"成功安装真寻依赖,日志:\n{result.stdout}", COMMAND)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
logger.error(f"安装真寻依赖失败,错误:\n{e.stderr}", "插件管理", e=e)
|
logger.error(f"安装真寻依赖失败,错误:\n{e.stderr}", COMMAND, e=e)
|
||||||
|
|
||||||
|
|
||||||
@run_sync
|
@run_sync
|
||||||
@ -61,7 +63,7 @@ def _file_handle(latest_version: str | None):
|
|||||||
latest_version: 版本号
|
latest_version: 版本号
|
||||||
"""
|
"""
|
||||||
BACKUP_PATH.mkdir(exist_ok=True, parents=True)
|
BACKUP_PATH.mkdir(exist_ok=True, parents=True)
|
||||||
logger.debug("开始解压文件压缩包...", "检查更新")
|
logger.debug("开始解压文件压缩包...", COMMAND)
|
||||||
download_file = DOWNLOAD_GZ_FILE
|
download_file = DOWNLOAD_GZ_FILE
|
||||||
if DOWNLOAD_GZ_FILE.exists():
|
if DOWNLOAD_GZ_FILE.exists():
|
||||||
tf = tarfile.open(DOWNLOAD_GZ_FILE)
|
tf = tarfile.open(DOWNLOAD_GZ_FILE)
|
||||||
@ -69,7 +71,7 @@ def _file_handle(latest_version: str | None):
|
|||||||
download_file = DOWNLOAD_ZIP_FILE
|
download_file = DOWNLOAD_ZIP_FILE
|
||||||
tf = zipfile.ZipFile(DOWNLOAD_ZIP_FILE)
|
tf = zipfile.ZipFile(DOWNLOAD_ZIP_FILE)
|
||||||
tf.extractall(TMP_PATH)
|
tf.extractall(TMP_PATH)
|
||||||
logger.debug("解压文件压缩包完成...", "检查更新")
|
logger.debug("解压文件压缩包完成...", COMMAND)
|
||||||
download_file_path = TMP_PATH / next(
|
download_file_path = TMP_PATH / next(
|
||||||
x for x in os.listdir(TMP_PATH) if (TMP_PATH / x).is_dir()
|
x for x in os.listdir(TMP_PATH) if (TMP_PATH / x).is_dir()
|
||||||
)
|
)
|
||||||
@ -79,52 +81,52 @@ def _file_handle(latest_version: str | None):
|
|||||||
extract_path = download_file_path / BASE_PATH_STRING
|
extract_path = download_file_path / BASE_PATH_STRING
|
||||||
target_path = BASE_PATH
|
target_path = BASE_PATH
|
||||||
if PYPROJECT_FILE.exists():
|
if PYPROJECT_FILE.exists():
|
||||||
logger.debug(f"移除备份文件: {PYPROJECT_FILE}", "检查更新")
|
logger.debug(f"移除备份文件: {PYPROJECT_FILE}", COMMAND)
|
||||||
shutil.move(PYPROJECT_FILE, BACKUP_PATH / PYPROJECT_FILE_STRING)
|
shutil.move(PYPROJECT_FILE, BACKUP_PATH / PYPROJECT_FILE_STRING)
|
||||||
if PYPROJECT_LOCK_FILE.exists():
|
if PYPROJECT_LOCK_FILE.exists():
|
||||||
logger.debug(f"移除备份文件: {PYPROJECT_LOCK_FILE}", "检查更新")
|
logger.debug(f"移除备份文件: {PYPROJECT_LOCK_FILE}", COMMAND)
|
||||||
shutil.move(PYPROJECT_LOCK_FILE, BACKUP_PATH / PYPROJECT_LOCK_FILE_STRING)
|
shutil.move(PYPROJECT_LOCK_FILE, BACKUP_PATH / PYPROJECT_LOCK_FILE_STRING)
|
||||||
if REQ_TXT_FILE.exists():
|
if REQ_TXT_FILE.exists():
|
||||||
logger.debug(f"移除备份文件: {REQ_TXT_FILE}", "检查更新")
|
logger.debug(f"移除备份文件: {REQ_TXT_FILE}", COMMAND)
|
||||||
shutil.move(REQ_TXT_FILE, BACKUP_PATH / REQ_TXT_FILE_STRING)
|
shutil.move(REQ_TXT_FILE, BACKUP_PATH / REQ_TXT_FILE_STRING)
|
||||||
if _pyproject.exists():
|
if _pyproject.exists():
|
||||||
logger.debug("移动文件: pyproject.toml", "检查更新")
|
logger.debug("移动文件: pyproject.toml", COMMAND)
|
||||||
shutil.move(_pyproject, PYPROJECT_FILE)
|
shutil.move(_pyproject, PYPROJECT_FILE)
|
||||||
if _lock_file.exists():
|
if _lock_file.exists():
|
||||||
logger.debug("移动文件: poetry.lock", "检查更新")
|
logger.debug("移动文件: poetry.lock", COMMAND)
|
||||||
shutil.move(_lock_file, PYPROJECT_LOCK_FILE)
|
shutil.move(_lock_file, PYPROJECT_LOCK_FILE)
|
||||||
if _req_file.exists():
|
if _req_file.exists():
|
||||||
logger.debug("移动文件: requirements.txt", "检查更新")
|
logger.debug("移动文件: requirements.txt", COMMAND)
|
||||||
shutil.move(_req_file, REQ_TXT_FILE)
|
shutil.move(_req_file, REQ_TXT_FILE)
|
||||||
for folder in REPLACE_FOLDERS:
|
for folder in REPLACE_FOLDERS:
|
||||||
"""移动指定文件夹"""
|
"""移动指定文件夹"""
|
||||||
_dir = BASE_PATH / folder
|
_dir = BASE_PATH / folder
|
||||||
_backup_dir = BACKUP_PATH / folder
|
_backup_dir = BACKUP_PATH / folder
|
||||||
if _backup_dir.exists():
|
if _backup_dir.exists():
|
||||||
logger.debug(f"删除备份文件夹 {_backup_dir}", "检查更新")
|
logger.debug(f"删除备份文件夹 {_backup_dir}", COMMAND)
|
||||||
shutil.rmtree(_backup_dir)
|
shutil.rmtree(_backup_dir)
|
||||||
if _dir.exists():
|
if _dir.exists():
|
||||||
logger.debug(f"移动旧文件夹 {_dir}", "检查更新")
|
logger.debug(f"移动旧文件夹 {_dir}", COMMAND)
|
||||||
shutil.move(_dir, _backup_dir)
|
shutil.move(_dir, _backup_dir)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"文件夹 {_dir} 不存在,跳过删除", "检查更新")
|
logger.warning(f"文件夹 {_dir} 不存在,跳过删除", COMMAND)
|
||||||
for folder in REPLACE_FOLDERS:
|
for folder in REPLACE_FOLDERS:
|
||||||
src_folder_path = extract_path / folder
|
src_folder_path = extract_path / folder
|
||||||
dest_folder_path = target_path / folder
|
dest_folder_path = target_path / folder
|
||||||
if src_folder_path.exists():
|
if src_folder_path.exists():
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"移动文件夹: {src_folder_path} -> {dest_folder_path}", "检查更新"
|
f"移动文件夹: {src_folder_path} -> {dest_folder_path}", COMMAND
|
||||||
)
|
)
|
||||||
shutil.move(src_folder_path, dest_folder_path)
|
shutil.move(src_folder_path, dest_folder_path)
|
||||||
else:
|
else:
|
||||||
logger.debug(f"源文件夹不存在: {src_folder_path}", "检查更新")
|
logger.debug(f"源文件夹不存在: {src_folder_path}", COMMAND)
|
||||||
if tf:
|
if tf:
|
||||||
tf.close()
|
tf.close()
|
||||||
if download_file.exists():
|
if download_file.exists():
|
||||||
logger.debug(f"删除下载文件: {download_file}", "检查更新")
|
logger.debug(f"删除下载文件: {download_file}", COMMAND)
|
||||||
download_file.unlink()
|
download_file.unlink()
|
||||||
if extract_path.exists():
|
if extract_path.exists():
|
||||||
logger.debug(f"删除解压文件夹: {extract_path}", "检查更新")
|
logger.debug(f"删除解压文件夹: {extract_path}", COMMAND)
|
||||||
shutil.rmtree(extract_path)
|
shutil.rmtree(extract_path)
|
||||||
if TMP_PATH.exists():
|
if TMP_PATH.exists():
|
||||||
shutil.rmtree(TMP_PATH)
|
shutil.rmtree(TMP_PATH)
|
||||||
@ -134,7 +136,35 @@ def _file_handle(latest_version: str | None):
|
|||||||
install_requirement()
|
install_requirement()
|
||||||
|
|
||||||
|
|
||||||
class UpdateManage:
|
class UpdateManager:
|
||||||
|
@classmethod
|
||||||
|
async def update_webui(cls) -> str:
|
||||||
|
from zhenxun.builtin_plugins.web_ui.public.data_source import (
|
||||||
|
update_webui_assets,
|
||||||
|
)
|
||||||
|
|
||||||
|
WEBUI_PATH = DATA_PATH / "web_ui" / "public"
|
||||||
|
BACKUP_PATH = DATA_PATH / "web_ui" / "backup_public"
|
||||||
|
if WEBUI_PATH.exists():
|
||||||
|
if BACKUP_PATH.exists():
|
||||||
|
logger.debug(f"删除旧的备份webui文件夹 {BACKUP_PATH}", COMMAND)
|
||||||
|
shutil.rmtree(BACKUP_PATH)
|
||||||
|
WEBUI_PATH.rename(BACKUP_PATH)
|
||||||
|
try:
|
||||||
|
await update_webui_assets()
|
||||||
|
logger.info("更新webui成功...", COMMAND)
|
||||||
|
if BACKUP_PATH.exists():
|
||||||
|
logger.debug(f"删除旧的webui文件夹 {BACKUP_PATH}", COMMAND)
|
||||||
|
shutil.rmtree(BACKUP_PATH)
|
||||||
|
return "Webui更新成功!"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("更新webui失败...", COMMAND, e=e)
|
||||||
|
if BACKUP_PATH.exists():
|
||||||
|
logger.debug(f"恢复旧的webui文件夹 {BACKUP_PATH}", COMMAND)
|
||||||
|
BACKUP_PATH.rename(WEBUI_PATH)
|
||||||
|
raise e
|
||||||
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_version(cls) -> str:
|
async def check_version(cls) -> str:
|
||||||
"""检查更新版本
|
"""检查更新版本
|
||||||
@ -166,7 +196,7 @@ class UpdateManage:
|
|||||||
返回:
|
返回:
|
||||||
str | None: 返回消息
|
str | None: 返回消息
|
||||||
"""
|
"""
|
||||||
logger.info("开始下载真寻最新版文件....", "检查更新")
|
logger.info("开始下载真寻最新版文件....", COMMAND)
|
||||||
cur_version = cls.__get_version()
|
cur_version = cls.__get_version()
|
||||||
url = None
|
url = None
|
||||||
new_version = None
|
new_version = None
|
||||||
@ -186,11 +216,11 @@ class UpdateManage:
|
|||||||
if not url:
|
if not url:
|
||||||
return "获取版本下载链接失败..."
|
return "获取版本下载链接失败..."
|
||||||
if TMP_PATH.exists():
|
if TMP_PATH.exists():
|
||||||
logger.debug(f"删除临时文件夹 {TMP_PATH}", "检查更新")
|
logger.debug(f"删除临时文件夹 {TMP_PATH}", COMMAND)
|
||||||
shutil.rmtree(TMP_PATH)
|
shutil.rmtree(TMP_PATH)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"开始更新版本:{cur_version} -> {new_version} | 下载链接:{url}",
|
f"开始更新版本:{cur_version} -> {new_version} | 下载链接:{url}",
|
||||||
"检查更新",
|
COMMAND,
|
||||||
)
|
)
|
||||||
await PlatformUtils.send_superuser(
|
await PlatformUtils.send_superuser(
|
||||||
bot,
|
bot,
|
||||||
@ -201,7 +231,7 @@ class UpdateManage:
|
|||||||
DOWNLOAD_GZ_FILE if version_type == "release" else DOWNLOAD_ZIP_FILE
|
DOWNLOAD_GZ_FILE if version_type == "release" else DOWNLOAD_ZIP_FILE
|
||||||
)
|
)
|
||||||
if await AsyncHttpx.download_file(url, download_file, stream=True):
|
if await AsyncHttpx.download_file(url, download_file, stream=True):
|
||||||
logger.debug("下载真寻最新版文件完成...", "检查更新")
|
logger.debug("下载真寻最新版文件完成...", COMMAND)
|
||||||
await _file_handle(new_version)
|
await _file_handle(new_version)
|
||||||
result = "版本更新完成"
|
result = "版本更新完成"
|
||||||
return (
|
return (
|
||||||
@ -210,7 +240,7 @@ class UpdateManage:
|
|||||||
"请重新启动真寻以完成更新!"
|
"请重新启动真寻以完成更新!"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.debug("下载真寻最新版文件失败...", "检查更新")
|
logger.debug("下载真寻最新版文件失败...", COMMAND)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@ -34,3 +34,5 @@ REPLACE_FOLDERS = [
|
|||||||
"models",
|
"models",
|
||||||
"configs",
|
"configs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
COMMAND = "检查更新"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user