feat: 新的资源包加载逻辑

feat: 主题商店支持
This commit is contained in:
远野千束 2024-04-06 08:48:21 +08:00
parent be0b5e6de1
commit a76bc3de92
14 changed files with 153 additions and 31 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
node_modules/ node_modules/
data/ data/
db/ db/
/resources/
__pycache__/ __pycache__/
*.pyc *.pyc
*.pyo *.pyo

View File

@ -11,5 +11,10 @@ export default navbar([
text: "使用手册", text: "使用手册",
link: "/usage/", link: "/usage/",
prefix: "usage/", prefix: "usage/",
},
{
text: "主题商店",
link: "/store/",
prefix: "store/",
} }
]); ]);

View File

@ -20,6 +20,10 @@ actions:
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`)
#3. 切换目录`cd LiteyukiBot` #3. 切换目录`cd LiteyukiBot`

27
docs/store/README.md Normal file
View 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
---

View File

@ -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`

View File

@ -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 *

View File

@ -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

View File

@ -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")

View File

@ -148,6 +148,9 @@ async def get_stats_data(self_id: str = None, lang: str = None) -> dict:
"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"),

View File

@ -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(

View 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

View File

@ -99,3 +99,5 @@ liteyuki.image_mode_off=关闭Markdown图片模式
npm.page=第{PAGE}/{TOTAL}页 npm.page=第{PAGE}/{TOTAL}页
main.monitor.free=空闲 main.monitor.free=空闲
liteyuki.reload_resources_success=资源重载成功,共计{NUM}个资源包

View File

@ -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;

View File

@ -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))