mirror of
https://github.com/LiteyukiStudio/LiteyukiBot.git
synced 2024-11-11 04:07:23 +08:00
feat: 优化了排版和渲染
This commit is contained in:
parent
14fb96fec2
commit
955d9f6d62
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@ _config.yml
|
||||
config.yml
|
||||
config.example.yml
|
||||
compile.bat
|
||||
liteyuki/resources/templates/latest-debug.html
|
||||
# vuepress
|
||||
.github
|
||||
|
||||
|
@ -39,7 +39,7 @@ category: 使用手册
|
||||
[SOA]disable <plugin_name> # 禁用插件
|
||||
[S]enable-global <plugin_name> # 全局启用插件
|
||||
[S]disable-global <plugin_name> # 全局禁用插件
|
||||
list-plugin # 列出所有插件
|
||||
list-plugin [page] [num] # 列出所有插件 page为页数,num为每页显示数量
|
||||
# 受限于Nonebot的钩子函数,目前只能阻断消息事件的传入,对于主动推送消息的插件,无法将其阻止
|
||||
------
|
||||
别名: enable 启用, disable 停用, enable-global 全局启用, disable-global 全局停用, list-plugin 列出插件/插件列表
|
||||
|
0
liteyuki/__init__.py
Normal file
0
liteyuki/__init__.py
Normal file
Binary file not shown.
@ -17,6 +17,18 @@ __plugin_meta__ = PluginMetadata(
|
||||
}
|
||||
)
|
||||
|
||||
print("\033[34m" + r"""
|
||||
__ ______ ________ ________ __ __ __ __ __ __ ______
|
||||
/ | / |/ |/ |/ \ / |/ | / |/ | / |/ |
|
||||
$$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/
|
||||
$$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ |
|
||||
$$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ |
|
||||
$$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ |
|
||||
$$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_
|
||||
$$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |
|
||||
$$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
|
||||
""" + "\033[0m")
|
||||
|
||||
sys_lang = get_default_lang()
|
||||
nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name")))
|
||||
nonebot.logger.info(sys_lang.get("main.enable_webdash", URL=f"http://127.0.0.1:{config.get('port', 20216)}"))
|
||||
|
@ -1,7 +1,6 @@
|
||||
import base64
|
||||
from typing import Any
|
||||
|
||||
import nonebot
|
||||
import pip
|
||||
from git import Repo
|
||||
from nonebot import Bot, require, get_driver
|
||||
@ -13,12 +12,10 @@ from liteyuki.utils.data_manager import StoredConfig, common_db
|
||||
from liteyuki.utils.language import get_user_lang
|
||||
from liteyuki.utils.ly_typing import T_Bot, T_MessageEvent
|
||||
from liteyuki.utils.message import Markdown as md
|
||||
from .reloader import Reloader
|
||||
from liteyuki.utils import htmlrender
|
||||
from liteyuki.utils.reloader import Reloader
|
||||
|
||||
require("nonebot_plugin_alconna"), require("nonebot_plugin_htmlrender")
|
||||
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma
|
||||
from nonebot_plugin_htmlrender import html_to_pic
|
||||
|
||||
driver = get_driver()
|
||||
|
||||
|
@ -127,7 +127,8 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
||||
image_bytes = await template2image(
|
||||
template=get_path("templates/stats.html", abs_path=True),
|
||||
templates=templ,
|
||||
scale_factor=4,
|
||||
scale_factor=1,
|
||||
debug=True
|
||||
)
|
||||
# await md.send_image(image_bytes, bot, event=event)
|
||||
await stats.finish(MessageSegment.image(image_bytes))
|
||||
|
@ -4,8 +4,7 @@ import nonebot.plugin
|
||||
from nonebot import require
|
||||
from nonebot.exception import FinishedException, IgnoredException
|
||||
from nonebot.internal.adapter import Event
|
||||
from nonebot.internal.matcher import Matcher, current_matcher
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.internal.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.plugin import Plugin
|
||||
@ -17,6 +16,7 @@ from liteyuki.utils.message import Markdown as md
|
||||
from liteyuki.utils.permission import GROUP_ADMIN, GROUP_OWNER
|
||||
from .common import get_plugin_can_be_toggle, get_plugin_default_enable, get_plugin_global_enable, get_plugin_session_enable
|
||||
from .installer import get_store_plugin, npm_update
|
||||
from ...utils.tools import clamp
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma
|
||||
@ -24,8 +24,9 @@ from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma
|
||||
list_plugins = on_alconna(
|
||||
Alconna(
|
||||
"list-plugin",
|
||||
Args["page", int, 1]["num", int, 10],
|
||||
),
|
||||
aliases={"列出插件", "插件列表", "菜单"}
|
||||
aliases={"列出插件", "插件列表"}
|
||||
)
|
||||
|
||||
toggle_plugin = on_alconna(
|
||||
@ -47,42 +48,48 @@ toggle_plugin_global = on_alconna(
|
||||
|
||||
|
||||
@list_plugins.handle()
|
||||
async def _(event: T_MessageEvent, bot: T_Bot):
|
||||
async def _(event: T_MessageEvent, bot: T_Bot, result: Arparma):
|
||||
lang = get_user_lang(str(event.user_id))
|
||||
if not os.path.exists("data/liteyuki/plugins.json"):
|
||||
await npm_update()
|
||||
lang = get_user_lang(str(event.user_id))
|
||||
reply = f"# {lang.get('npm.loaded_plugins')} | {lang.get('npm.total', TOTAL=len(nonebot.get_loaded_plugins()))} \n***\n"
|
||||
for plugin in nonebot.get_loaded_plugins():
|
||||
|
||||
loaded_plugin_list = sorted(nonebot.get_loaded_plugins(), key=lambda x: x.module_name)
|
||||
num_per_page = result.args.get("num")
|
||||
total = len(loaded_plugin_list) // num_per_page + (1 if len(loaded_plugin_list) % num_per_page else 0)
|
||||
|
||||
page = clamp(result.args.get("page"), 1, total)
|
||||
|
||||
# 已加载插件 | 总计10 | 第1/3页
|
||||
reply = (f"# {lang.get('npm.loaded_plugins')} | "
|
||||
f"{lang.get('npm.total', TOTAL=len(nonebot.get_loaded_plugins()))} | "
|
||||
f"{lang.get('npm.page', PAGE=page, TOTAL=total)} \n***\n")
|
||||
|
||||
for plugin in loaded_plugin_list[(page - 1) * num_per_page: min(page * num_per_page, len(loaded_plugin_list))]:
|
||||
# 检查是否有 metadata 属性
|
||||
# 添加帮助按钮
|
||||
btn_usage = md.button(lang.get("npm.usage"), f"help {plugin.module_name}", False)
|
||||
store_plugin = await get_store_plugin(plugin.module_name)
|
||||
|
||||
session_enable = get_plugin_session_enable(event, plugin.module_name)
|
||||
default_enable = get_plugin_default_enable(plugin.module_name)
|
||||
|
||||
if store_plugin:
|
||||
btn_homepage = md.link(lang.get("npm.homepage"), store_plugin.homepage)
|
||||
show_name = store_plugin.name
|
||||
show_desc = store_plugin.desc
|
||||
elif plugin.metadata:
|
||||
if plugin.metadata.extra.get("liteyuki"):
|
||||
btn_homepage = md.link(lang.get("npm.homepage"), "https://github.com/snowykami/LiteyukiBot")
|
||||
else:
|
||||
btn_homepage = lang.get("npm.homepage")
|
||||
show_name = plugin.metadata.name
|
||||
show_desc = plugin.metadata.description
|
||||
else:
|
||||
btn_homepage = lang.get("npm.homepage")
|
||||
show_name = plugin.name
|
||||
show_desc = lang.get("npm.no_description")
|
||||
lang.get("npm.no_description")
|
||||
|
||||
if plugin.metadata:
|
||||
reply += (f"\n**{md.escape(show_name)}**\n"
|
||||
f"\n > {md.escape(show_desc)}\n")
|
||||
reply += f"\n**{md.escape(show_name)}**\n"
|
||||
else:
|
||||
reply += (f"**{md.escape(show_name)}**\n"
|
||||
f"\n > {md.escape(show_desc)}\n")
|
||||
reply += f"**{md.escape(show_name)}**\n"
|
||||
|
||||
reply += f"\n > {btn_usage} {btn_homepage}"
|
||||
|
||||
@ -121,7 +128,7 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot):
|
||||
ulang = get_user_lang(str(event.user_id))
|
||||
plugin_module_name = result.args.get("plugin_name")
|
||||
# 支持对自定义command_start的判断
|
||||
toggle = result.header_result in [prefix+header for prefix in bot.config.command_start for header in ["enable-plugin", "启用"]] # 判断是启用还是停用
|
||||
toggle = result.header_result in [prefix + header for prefix in bot.config.command_start for header in ["enable-plugin", "启用"]] # 判断是启用还是停用
|
||||
|
||||
session_enable = get_plugin_session_enable(event, plugin_module_name) # 获取插件当前状态
|
||||
|
||||
|
@ -93,3 +93,8 @@ user.profile.nickname.desc=Spitzname des Bots für den Benutzer festlegen
|
||||
user.profile.input_value=Bitte geben Sie {ATTR} ein
|
||||
user.profile.set_success={ATTR} erfolgreich auf {VALUE} festgelegt
|
||||
user.profile.set_failed={ATTR} festlegen fehlgeschlagen. Bitte überprüfen Sie, ob die Eingabe gültig ist.
|
||||
|
||||
liteyuki.image_mode_on=Markdown-Bild
|
||||
liteyuki.image_mode_off=Markdown-Link
|
||||
|
||||
npm.page=Page {PAGE}/{TOTAL}
|
@ -93,3 +93,8 @@ user.profile.nickname.desc=Set Bot's nickname for the user
|
||||
user.profile.input_value=Please enter {ATTR}
|
||||
user.profile.set_success={ATTR} set successfully to {VALUE}
|
||||
user.profile.set_failed=Setting {ATTR} failed. Please check if the input is valid.
|
||||
|
||||
liteyuki.image_mode_on=Enable markdown image
|
||||
liteyuki.image_mode_off=Closed markdown image
|
||||
|
||||
npm.page=Page {PAGE}/{TOTAL}
|
@ -95,4 +95,6 @@ user.profile.set_success=成功将 {ATTR} 设置为 {VALUE}
|
||||
user.profile.set_failed=设置 {ATTR} 失败,请检查输入是否合法
|
||||
|
||||
liteyuki.image_mode_on=开启Markdown图片模式
|
||||
liteyuki.image_mode_off=关闭Markdown图片模式
|
||||
liteyuki.image_mode_off=关闭Markdown图片模式
|
||||
|
||||
npm.page=第{PAGE}/{TOTAL}页
|
@ -16,40 +16,44 @@
|
||||
background-image: url('img/bg1.jpg');
|
||||
color: white;
|
||||
// 上10px,左右10px,下0px
|
||||
margin: 10px 10px 0;
|
||||
margin: 24px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.info-box {
|
||||
border-radius: 10px;
|
||||
padding: 15px;
|
||||
border-radius: 30px;
|
||||
padding: 30px;
|
||||
backdrop-filter: blur(30px);
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
margin: 0 24px 24px;
|
||||
}
|
||||
|
||||
#cpu-chart, #mem-chart, #swap-chart {
|
||||
height: 150px;
|
||||
width: 100px;
|
||||
margin: -10px 15px;
|
||||
height: 240px;
|
||||
width: 240px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#cpu-info, #mem-info, #swap-info {
|
||||
margin: 0 40px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#bot-info {
|
||||
margin-top: 24px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#hardware-info {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#bot-icon {
|
||||
border-radius: 50%;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
#bot-name, #bot-tag {
|
||||
@ -57,28 +61,22 @@
|
||||
}
|
||||
|
||||
#bot-name {
|
||||
font-size: 22px;
|
||||
font-size: 42px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#bot-id {
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#bot-tag {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.chart-label {
|
||||
font-size: 15px;
|
||||
font-size: 30px;
|
||||
max-width: 240px;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 15px;
|
||||
font-size: 27px;
|
||||
}
|
||||
|
||||
.tag::after {
|
||||
@ -178,7 +176,7 @@
|
||||
textStyle: {
|
||||
//文字颜色
|
||||
color: '#fff',
|
||||
fontSize: 15
|
||||
fontSize: 30
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
@ -207,7 +205,7 @@
|
||||
label: {
|
||||
show: true,
|
||||
textStyle: {
|
||||
fontSize: '25',
|
||||
fontSize: '50',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}
|
||||
|
@ -61,17 +61,6 @@ def init():
|
||||
if not os.path.exists("data/liteyuki/liteyuki.json"):
|
||||
register_bot()
|
||||
|
||||
print("\033[34m" + r"""
|
||||
__ ______ ________ ________ __ __ __ __ __ __ ______
|
||||
/ | / |/ |/ |/ \ / |/ | / |/ | / |/ |
|
||||
$$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/
|
||||
$$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ |
|
||||
$$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ |
|
||||
$$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ |
|
||||
$$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_
|
||||
$$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |
|
||||
$$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
|
||||
""" + "\033[0m")
|
||||
nonebot.logger.info(
|
||||
f"Run Liteyuki with Python{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} "
|
||||
f"at {sys.executable}"
|
||||
|
@ -1,5 +1,8 @@
|
||||
import os.path
|
||||
import time
|
||||
from os import getcwd
|
||||
|
||||
import aiofiles
|
||||
from nonebot import require
|
||||
|
||||
require("nonebot_plugin_htmlrender")
|
||||
@ -31,25 +34,44 @@ from nonebot_plugin_htmlrender import *
|
||||
async def template2image(
|
||||
template: str,
|
||||
templates: dict,
|
||||
pages: dict | None = None,
|
||||
pages=None,
|
||||
wait: int = 0,
|
||||
scale_factor: float = 2,
|
||||
**kwargs
|
||||
scale_factor: float = 1,
|
||||
debug: bool = False,
|
||||
) -> bytes:
|
||||
"""
|
||||
template -> html -> image
|
||||
Args:
|
||||
debug: 输入渲染好的 html
|
||||
wait: 等待时间,单位秒
|
||||
pages: 页面参数
|
||||
template: str: 模板文件
|
||||
templates: dict: 模板参数
|
||||
scale_factor: 缩放因子,越高越清晰
|
||||
**kwargs: page 参数
|
||||
Returns:
|
||||
图片二进制数据
|
||||
"""
|
||||
if pages is None:
|
||||
pages = {
|
||||
"viewport": {
|
||||
"width" : 1080,
|
||||
"height": 10
|
||||
},
|
||||
"base_url": f"file://{getcwd()}",
|
||||
}
|
||||
template_path = os.path.dirname(template)
|
||||
template_name = os.path.basename(template)
|
||||
|
||||
if debug:
|
||||
raw_html = await template_to_html(
|
||||
template_name=template_name,
|
||||
template_path=template_path,
|
||||
**templates,
|
||||
)
|
||||
async with aiofiles.open(os.path.join(template_path, "latest-debug.html"), "w", encoding="utf-8") as f:
|
||||
await f.write(raw_html)
|
||||
nonebot.logger.info("Debug HTML: %s" % "latest-debug.html")
|
||||
|
||||
return await template_to_pic(
|
||||
template_name=template_name,
|
||||
template_path=template_path,
|
||||
|
@ -100,12 +100,15 @@ def load_from_dict(data: dict, lang_code: str):
|
||||
|
||||
|
||||
class Language:
|
||||
def __init__(self, lang_code: str = None, fallback_lang_code: str = "en"):
|
||||
def __init__(self, lang_code: str = None, fallback_lang_code: str = None):
|
||||
if lang_code is None:
|
||||
lang_code = get_system_lang_code()
|
||||
lang_code = config.get("default_language", get_default_lang())
|
||||
self.lang_code = lang_code
|
||||
self.fallback_lang_code = fallback_lang_code
|
||||
|
||||
if self.fallback_lang_code is None:
|
||||
self.fallback_lang_code = config.get("default_language", get_system_lang_code())
|
||||
|
||||
def get(self, item: str, *args, **kwargs) -> str | Any:
|
||||
"""
|
||||
获取当前语言文本
|
||||
@ -154,7 +157,7 @@ def get_user_lang(user_id: str) -> Language:
|
||||
username="Unknown"
|
||||
))
|
||||
|
||||
return Language(user.profile.get("lang", config.get("default_language", get_system_lang_code())))
|
||||
return Language(user.profile.get("lang", get_default_lang()))
|
||||
|
||||
|
||||
def get_system_lang_code() -> str:
|
||||
|
@ -2,7 +2,7 @@ import sys
|
||||
import loguru
|
||||
from typing import TYPE_CHECKING
|
||||
from .config import load_from_yaml
|
||||
from .language import Language, get_default_lang, get_system_lang_code
|
||||
from .language import Language, get_default_lang
|
||||
|
||||
logger = loguru.logger
|
||||
if TYPE_CHECKING:
|
||||
@ -59,7 +59,7 @@ def init_log():
|
||||
format=get_format(config.get("log_level", "INFO")),
|
||||
)
|
||||
show_icon = config.get("log_icon", True)
|
||||
lang = Language(config.get("default_language", get_system_lang_code()))
|
||||
lang = get_default_lang()
|
||||
|
||||
debug = lang.get("log.debug", default="==DEBUG")
|
||||
info = lang.get("log.info", default="===INFO")
|
||||
|
0
liteyuki/utils/plugin.py
Normal file
0
liteyuki/utils/plugin.py
Normal file
@ -3,11 +3,6 @@ from multiprocessing import get_context
|
||||
|
||||
import nonebot
|
||||
from nonebot import logger
|
||||
from typing import List, Optional
|
||||
|
||||
from nonebot import get_driver
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
reboot_grace_time_limit: int = 20
|
||||
|
||||
@ -60,7 +55,6 @@ def run(*args, **kwargs):
|
||||
elif process.is_alive():
|
||||
continue
|
||||
else:
|
||||
# Process stoped without setting event
|
||||
should_exit = True
|
||||
|
||||
|
@ -1,5 +1,18 @@
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
from urllib.parse import quote
|
||||
|
||||
|
||||
def clamp(value: float, min_value: float, max_value: float) -> float | int:
|
||||
"""将值限制在最小值和最大值之间
|
||||
|
||||
Args:
|
||||
value (float): 要限制的值
|
||||
min_value (float): 最小值
|
||||
max_value (float): 最大值
|
||||
|
||||
Returns:
|
||||
float: 限制后的值
|
||||
"""
|
||||
return max(min(value, max_value), min_value)
|
||||
|
||||
|
||||
def convert_size(size: int, precision: int = 2, add_unit: bool = True, suffix: str = "iB") -> str:
|
||||
|
Loading…
Reference in New Issue
Block a user