forked from bot/app
feat: 新的资源包加载逻辑
feat: 主题商店支持
This commit is contained in:
parent
be0b5e6de1
commit
a76bc3de92
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
data/
|
data/
|
||||||
db/
|
db/
|
||||||
|
/resources/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
@ -11,5 +11,10 @@ export default navbar([
|
|||||||
text: "使用手册",
|
text: "使用手册",
|
||||||
link: "/usage/",
|
link: "/usage/",
|
||||||
prefix: "usage/",
|
prefix: "usage/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "主题商店",
|
||||||
|
link: "/store/",
|
||||||
|
prefix: "store/",
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -19,6 +19,10 @@ actions:
|
|||||||
- text: 使用手册
|
- text: 使用手册
|
||||||
icon: book
|
icon: book
|
||||||
link: ./usage/basic_command.html
|
link: ./usage/basic_command.html
|
||||||
|
|
||||||
|
- text: 主题商店
|
||||||
|
icon: paint-brush
|
||||||
|
link: ./theme/theme_store.html
|
||||||
|
|
||||||
#1. 安装 `Git` 和 `Python3.10+` 环境
|
#1. 安装 `Git` 和 `Python3.10+` 环境
|
||||||
#2. 克隆项目 `git clone https://github.com/snowykami/LiteyukiBot` (无法连接可以用`https://gitee.com/snowykami/LiteyukiBot`)
|
#2. 克隆项目 `git clone https://github.com/snowykami/LiteyukiBot` (无法连接可以用`https://gitee.com/snowykami/LiteyukiBot`)
|
||||||
|
27
docs/store/README.md
Normal file
27
docs/store/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
home: true
|
||||||
|
icon: paint-brush
|
||||||
|
heroText: Liteyuki Theme Store
|
||||||
|
tagline: 轻雪主题/资源商店
|
||||||
|
|
||||||
|
highlights:
|
||||||
|
- header: 所有资源包
|
||||||
|
bgImage: https://theme-hope-assets.vuejs.press/bg/2-light.svg
|
||||||
|
bgImageDark: https://theme-hope-assets.vuejs.press/bg/2-dark.svg
|
||||||
|
bgImageStyle:
|
||||||
|
background-repeat: repeat
|
||||||
|
background-size: initial
|
||||||
|
features:
|
||||||
|
- title: Kawaii-Status
|
||||||
|
icon: paint-brush
|
||||||
|
details: 可爱的状态卡片,模仿的Koishi
|
||||||
|
link: https://cdn.liteyuki.icu/static/lrp/KawaiiStatus.zip
|
||||||
|
- title: MiSans字体包
|
||||||
|
icon: paint-brush
|
||||||
|
details: 标准字体包,适用于大多数主题,简约大方
|
||||||
|
link: https://cdn.liteyuki.icu/static/lrp/MiSansFonts.zip
|
||||||
|
- title: MapleMono字体包
|
||||||
|
icon: paint-brush
|
||||||
|
details: 适用于标准主题的MapleMono字体包
|
||||||
|
link: https://cdn.liteyuki.icu/static/lrp/MapleMonoFonts.zip
|
||||||
|
---
|
@ -17,10 +17,11 @@ category: 使用手册
|
|||||||
[S]liteecho # 查看当前bot
|
[S]liteecho # 查看当前bot
|
||||||
[S]config set <key> value # 添加配置项,若存在则会覆盖,输入值会被执行,以便于转换为正确的值,"10"和10是不一样的
|
[S]config set <key> value # 添加配置项,若存在则会覆盖,输入值会被执行,以便于转换为正确的值,"10"和10是不一样的
|
||||||
[S]config get [key] # 查询配置项,不带key返回配置项列表,推荐私聊使用
|
[S]config get [key] # 查询配置项,不带key返回配置项列表,推荐私聊使用
|
||||||
|
[S]reload-resources # 重载资源
|
||||||
[S]switch-image-mode # 切换图片模式,该功能需要commit:505468b及以后的Lagrange.OneBot,在普通图片和Markdown图片之间切换,后者更大但有失败的可能
|
[S]switch-image-mode # 切换图片模式,该功能需要commit:505468b及以后的Lagrange.OneBot,在普通图片和Markdown图片之间切换,后者更大但有失败的可能
|
||||||
# 上述两个命令修改的配置项在数据库中保存,但是优先级低于配置文件,如果配置文件中存在相同的配置项,将会使用配置文件中的配置
|
# 上述两个命令修改的配置项在数据库中保存,但是优先级低于配置文件,如果配置文件中存在相同的配置项,将会使用配置文件中的配置
|
||||||
------
|
------
|
||||||
别名: reload-liteyuki 重启轻雪, update-liteyuki 更新轻雪, config 配置, set 设置, get 查询
|
别名: reload-liteyuki 重启轻雪, update-liteyuki 更新轻雪, reload-resources 重载资源, config 配置, set 设置, get 查询
|
||||||
```
|
```
|
||||||
|
|
||||||
### 轻雪Nonebot插件管理 `liteyuki_npm`
|
### 轻雪Nonebot插件管理 `liteyuki_npm`
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata
|
||||||
|
|
||||||
from liteyuki.utils.language import get_default_lang
|
|
||||||
from .core import *
|
from .core import *
|
||||||
from .loader import *
|
from .loader import *
|
||||||
from .runtime import *
|
from .runtime import *
|
||||||
|
@ -14,6 +14,7 @@ from liteyuki.utils.language import get_user_lang
|
|||||||
from liteyuki.utils.ly_typing import T_Bot, T_MessageEvent
|
from liteyuki.utils.ly_typing import T_Bot, T_MessageEvent
|
||||||
from liteyuki.utils.message import Markdown as md
|
from liteyuki.utils.message import Markdown as md
|
||||||
from liteyuki.utils.reloader import Reloader
|
from liteyuki.utils.reloader import Reloader
|
||||||
|
from liteyuki.utils.resource import get_loaded_resource_packs, load_resources
|
||||||
|
|
||||||
require("nonebot_plugin_alconna"), require("nonebot_plugin_htmlrender")
|
require("nonebot_plugin_alconna"), require("nonebot_plugin_htmlrender")
|
||||||
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma
|
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma
|
||||||
@ -45,6 +46,14 @@ reload_liteyuki = on_alconna(
|
|||||||
permission=SUPERUSER
|
permission=SUPERUSER
|
||||||
)
|
)
|
||||||
|
|
||||||
|
reload_resources = on_alconna(
|
||||||
|
aliases={"重载资源"},
|
||||||
|
command=Alconna(
|
||||||
|
"reload-resources"
|
||||||
|
),
|
||||||
|
permission=SUPERUSER
|
||||||
|
)
|
||||||
|
|
||||||
cmd_config = on_alconna(
|
cmd_config = on_alconna(
|
||||||
aliases={"配置"},
|
aliases={"配置"},
|
||||||
command=Alconna(
|
command=Alconna(
|
||||||
@ -153,6 +162,17 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot):
|
|||||||
await md.send_md(reply, bot, event=event)
|
await md.send_md(reply, bot, event=event)
|
||||||
|
|
||||||
|
|
||||||
|
@reload_resources.handle()
|
||||||
|
async def _(event: T_MessageEvent):
|
||||||
|
ulang = get_user_lang(str(event.user_id))
|
||||||
|
load_resources()
|
||||||
|
await reload_resources.finish(
|
||||||
|
ulang.get("liteyuki.reload_resources_success",
|
||||||
|
NUM=len(get_loaded_resource_packs())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@switch_image_mode.handle()
|
@switch_image_mode.handle()
|
||||||
async def _(bot: T_Bot, event: T_MessageEvent):
|
async def _(bot: T_Bot, event: T_MessageEvent):
|
||||||
global markdown_image
|
global markdown_image
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
import os.path
|
import os.path
|
||||||
|
import shutil
|
||||||
|
|
||||||
import nonebot.plugin
|
import nonebot.plugin
|
||||||
|
|
||||||
from liteyuki.utils import init_log
|
from liteyuki.utils import init_log
|
||||||
from liteyuki.utils.data_manager import InstalledPlugin, plugin_db
|
from liteyuki.utils.data_manager import InstalledPlugin, plugin_db
|
||||||
from liteyuki.utils.resource import load_resource_from_dir
|
from liteyuki.utils.resource import load_resource_from_dir, load_resources
|
||||||
from liteyuki.utils.tools import check_for_package
|
from liteyuki.utils.tools import check_for_package
|
||||||
|
|
||||||
# 加载默认资源和语言
|
load_resources()
|
||||||
RESOURCE_PATH = "liteyuki/resources"
|
|
||||||
load_resource_from_dir(RESOURCE_PATH)
|
|
||||||
init_log()
|
init_log()
|
||||||
# 加载其他资源包
|
|
||||||
if os.path.exists("resources"):
|
|
||||||
for resource in os.listdir("resources"):
|
|
||||||
load_resource_from_dir(os.path.join("resources", resource))
|
|
||||||
|
|
||||||
nonebot.plugin.load_plugins("liteyuki/plugins")
|
nonebot.plugin.load_plugins("liteyuki/plugins")
|
||||||
nonebot.plugin.load_plugins("plugins")
|
nonebot.plugin.load_plugins("plugins")
|
||||||
|
@ -144,10 +144,13 @@ async def get_stats_data(self_id: str = None, lang: str = None) -> dict:
|
|||||||
if disk_usage.total > 0:
|
if disk_usage.total > 0:
|
||||||
disk_data.append(
|
disk_data.append(
|
||||||
{
|
{
|
||||||
"name" : disk.device,
|
"name" : disk.device,
|
||||||
"total" : disk_total_show,
|
"total" : disk_total_show,
|
||||||
"free" : disk_free_show,
|
"free" : disk_free_show,
|
||||||
"percent": disk_usage.percent,
|
"percent" : disk_usage.percent,
|
||||||
|
"usedValue" : disk_usage.used,
|
||||||
|
"freeValue" : disk_usage.free,
|
||||||
|
"totalValue": disk_usage.total,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -164,14 +167,17 @@ async def get_stats_data(self_id: str = None, lang: str = None) -> dict:
|
|||||||
|
|
||||||
cpu_info = get_cpu_info()
|
cpu_info = get_cpu_info()
|
||||||
templ = {
|
templ = {
|
||||||
|
"plugin" : len(nonebot.get_loaded_plugins()),
|
||||||
|
"version" : __VERSION__,
|
||||||
|
"system" : platform.platform(),
|
||||||
"cpu" : [
|
"cpu" : [
|
||||||
{
|
{
|
||||||
"name" : "USED",
|
"name" : "USED",
|
||||||
"value": psutil.cpu_percent(interval=1)
|
"value": psutil.cpu_percent()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name" : "FREE",
|
"name" : "FREE",
|
||||||
"value": 100 - psutil.cpu_percent(interval=1)
|
"value": 100 - psutil.cpu_percent()
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mem" : [
|
"mem" : [
|
||||||
@ -221,6 +227,7 @@ async def get_stats_data(self_id: str = None, lang: str = None) -> dict:
|
|||||||
"cpu_trans" : ulang.get("main.monitor.cpu"),
|
"cpu_trans" : ulang.get("main.monitor.cpu"),
|
||||||
"mem_trans" : ulang.get("main.monitor.memory"),
|
"mem_trans" : ulang.get("main.monitor.memory"),
|
||||||
"swap_trans" : ulang.get("main.monitor.swap"),
|
"swap_trans" : ulang.get("main.monitor.swap"),
|
||||||
|
"disk_trans" : ulang.get("main.monitor.disk"),
|
||||||
"used_trans" : ulang.get("main.monitor.used"),
|
"used_trans" : ulang.get("main.monitor.used"),
|
||||||
"free_trans" : ulang.get("main.monitor.free"),
|
"free_trans" : ulang.get("main.monitor.free"),
|
||||||
"total_trans": ulang.get("main.monitor.total"),
|
"total_trans": ulang.get("main.monitor.total"),
|
||||||
|
@ -2,6 +2,7 @@ from nonebot.plugin import PluginMetadata
|
|||||||
from .manager import *
|
from .manager import *
|
||||||
from .installer import *
|
from .installer import *
|
||||||
from .helper import *
|
from .helper import *
|
||||||
|
from .rpm import *
|
||||||
|
|
||||||
__author__ = "snowykami"
|
__author__ = "snowykami"
|
||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
18
liteyuki/plugins/liteyuki_npm/rpm.py
Normal file
18
liteyuki/plugins/liteyuki_npm/rpm.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# 轻雪资源包管理器
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma
|
||||||
|
|
||||||
|
from liteyuki.utils.ly_typing import T_Bot
|
||||||
|
|
||||||
|
list_rp = on_alconna(
|
||||||
|
aliases={"列出资源包", "资源包列表"},
|
||||||
|
command=Alconna(
|
||||||
|
"list",
|
||||||
|
Args["page", int, 1]["num", int, 10],
|
||||||
|
),
|
||||||
|
permission=SUPERUSER
|
||||||
|
)
|
||||||
|
|
||||||
|
@list_rp.handle()
|
||||||
|
async def _(bot: T_Bot):
|
||||||
|
pass
|
@ -98,4 +98,6 @@ liteyuki.image_mode_on=开启Markdown图片模式
|
|||||||
liteyuki.image_mode_off=关闭Markdown图片模式
|
liteyuki.image_mode_off=关闭Markdown图片模式
|
||||||
|
|
||||||
npm.page=第{PAGE}/{TOTAL}页
|
npm.page=第{PAGE}/{TOTAL}页
|
||||||
main.monitor.free=空闲
|
main.monitor.free=空闲
|
||||||
|
|
||||||
|
liteyuki.reload_resources_success=资源重载成功,共计{NUM}个资源包
|
@ -7,7 +7,6 @@
|
|||||||
<title>Liteyuki Stats</title>
|
<title>Liteyuki Stats</title>
|
||||||
<link rel="stylesheet" href="css/fonts.css">
|
<link rel="stylesheet" href="css/fonts.css">
|
||||||
<link rel="stylesheet" href="css/style.css">
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.pie-chart {
|
.pie-chart {
|
||||||
height: 240px;
|
height: 240px;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
import nonebot
|
import nonebot
|
||||||
import yaml
|
import yaml
|
||||||
@ -6,8 +7,8 @@ from typing import Any
|
|||||||
|
|
||||||
from liteyuki.utils.data import LiteModel
|
from liteyuki.utils.data import LiteModel
|
||||||
|
|
||||||
_resource_data = {}
|
_loaded_resource_packs: list["ResourceMetadata"] = [] # 按照加载顺序排序
|
||||||
_loaded_resource_packs = [] # 按照加载顺序排序
|
temp_resource_root = "data/liteyuki/resources"
|
||||||
|
|
||||||
|
|
||||||
class ResourceMetadata(LiteModel):
|
class ResourceMetadata(LiteModel):
|
||||||
@ -19,24 +20,21 @@ class ResourceMetadata(LiteModel):
|
|||||||
|
|
||||||
def load_resource_from_dir(path: str):
|
def load_resource_from_dir(path: str):
|
||||||
"""
|
"""
|
||||||
把资源包按照文件相对路径加载到资源包中,后加载的优先级更高,顺便加载语言
|
把资源包按照文件相对路径复制到运行临时文件夹data/liteyuki/resources
|
||||||
Args:
|
Args:
|
||||||
path: 资源文件夹
|
path: 资源文件夹
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for root, dirs, files in os.walk(path):
|
|
||||||
for file in files:
|
|
||||||
relative_path = os.path.relpath(os.path.join(root, file), path).replace("\\", "/")
|
|
||||||
abs_path = os.path.join(root, file).replace("\\", "/")
|
|
||||||
_resource_data[relative_path] = abs_path
|
|
||||||
if os.path.exists(os.path.join(path, "metadata.yml")):
|
if os.path.exists(os.path.join(path, "metadata.yml")):
|
||||||
with open(os.path.join(path, "metadata.yml"), "r", encoding="utf-8") as f:
|
with open(os.path.join(path, "metadata.yml"), "r", encoding="utf-8") as f:
|
||||||
metadata = yaml.safe_load(f)
|
metadata = yaml.safe_load(f)
|
||||||
else:
|
else:
|
||||||
# 没有metadata.yml文件,不是一个资源包
|
# 没有metadata.yml文件,不是一个资源包
|
||||||
return
|
return
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for file in files:
|
||||||
|
relative_path = os.path.relpath(os.path.join(root, file), path)
|
||||||
|
copy_file(os.path.join(root, file), os.path.join(temp_resource_root, relative_path))
|
||||||
metadata["path"] = path
|
metadata["path"] = path
|
||||||
if os.path.exists(os.path.join(path, "lang")):
|
if os.path.exists(os.path.join(path, "lang")):
|
||||||
from liteyuki.utils.language import load_from_dir
|
from liteyuki.utils.language import load_from_dir
|
||||||
@ -53,7 +51,11 @@ def get_path(path: str, abs_path: bool = False, default: Any = None) -> str | An
|
|||||||
path: 文件相对路径
|
path: 文件相对路径
|
||||||
Returns: 文件绝对路径
|
Returns: 文件绝对路径
|
||||||
"""
|
"""
|
||||||
return _resource_data.get(path, default) if not abs_path else os.path.abspath(_resource_data.get(path, default))
|
resource_relative_path = os.path.join(temp_resource_root, path)
|
||||||
|
if os.path.exists(resource_relative_path):
|
||||||
|
return os.path.abspath(resource_relative_path) if abs_path else resource_relative_path
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
def get_files(path: str, abs_path: bool = False) -> list[str]:
|
def get_files(path: str, abs_path: bool = False) -> list[str]:
|
||||||
@ -64,5 +66,46 @@ def get_files(path: str, abs_path: bool = False) -> list[str]:
|
|||||||
path: 文件夹相对路径
|
path: 文件夹相对路径
|
||||||
Returns: 文件绝对路径
|
Returns: 文件绝对路径
|
||||||
"""
|
"""
|
||||||
return [os.path.abspath(file) for file in _resource_data if file.startswith(path)] if abs_path else [
|
resource_relative_path = os.path.join(temp_resource_root, path)
|
||||||
file for file in _resource_data if file.startswith(path)]
|
if os.path.exists(resource_relative_path):
|
||||||
|
return [os.path.abspath(os.path.join(resource_relative_path, file)) if abs_path else os.path.join(resource_relative_path, file) for file in
|
||||||
|
os.listdir(resource_relative_path)]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def get_loaded_resource_packs() -> list[ResourceMetadata]:
|
||||||
|
"""
|
||||||
|
获取已加载的资源包
|
||||||
|
Returns: 资源包列表
|
||||||
|
"""
|
||||||
|
return _loaded_resource_packs
|
||||||
|
|
||||||
|
|
||||||
|
def copy_file(src, dst):
|
||||||
|
# 获取目标文件的目录
|
||||||
|
dst_dir = os.path.dirname(dst)
|
||||||
|
# 如果目标目录不存在,创建它
|
||||||
|
if not os.path.exists(dst_dir):
|
||||||
|
os.makedirs(dst_dir)
|
||||||
|
# 复制文件
|
||||||
|
shutil.copy(src, dst)
|
||||||
|
|
||||||
|
|
||||||
|
def load_resources():
|
||||||
|
"""用于外部主程序调用的资源加载函数
|
||||||
|
Returns:
|
||||||
|
"""
|
||||||
|
# 加载默认资源和语言
|
||||||
|
# 清空临时资源包路径data/liteyuki/resources
|
||||||
|
_loaded_resource_packs.clear()
|
||||||
|
if os.path.exists(temp_resource_root):
|
||||||
|
shutil.rmtree(temp_resource_root)
|
||||||
|
os.makedirs(temp_resource_root, exist_ok=True)
|
||||||
|
|
||||||
|
standard_resource_path = "liteyuki/resources"
|
||||||
|
load_resource_from_dir(standard_resource_path)
|
||||||
|
# 加载其他资源包
|
||||||
|
if os.path.exists("resources"):
|
||||||
|
for resource in os.listdir("resources"):
|
||||||
|
load_resource_from_dir(os.path.join("resources", resource))
|
||||||
|
Loading…
Reference in New Issue
Block a user