mirror of
https://github.com/LiteyukiStudio/LiteyukiBot.git
synced 2024-11-22 20:17:39 +08:00
feat: 更多的字体
This commit is contained in:
parent
813f1c2ded
commit
c5d2c040fe
@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
import nonebot
|
import nonebot
|
||||||
@ -7,15 +8,17 @@ from nonebot import on_command
|
|||||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||||
from nonebot.permission import SUPERUSER
|
from nonebot.permission import SUPERUSER
|
||||||
|
|
||||||
from liteyuki.utils import __NAME__, __VERSION__
|
from liteyuki.utils import __NAME__, __VERSION__, load_from_yaml
|
||||||
from liteyuki.utils.htmlrender import template2image
|
from liteyuki.utils.htmlrender import template2image
|
||||||
from liteyuki.utils.language import get_user_lang
|
from liteyuki.utils.language import Language, get_default_lang, 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.resource import get_path
|
from liteyuki.utils.resource import get_path
|
||||||
from liteyuki.utils.tools import convert_size
|
from liteyuki.utils.tools import convert_size
|
||||||
|
|
||||||
stats = on_command("stats", aliases={"状态"}, priority=5, permission=SUPERUSER)
|
stats = on_command("stats", aliases={"状态"}, priority=5, permission=SUPERUSER)
|
||||||
|
|
||||||
|
config = load_from_yaml("config.yml")
|
||||||
|
|
||||||
protocol_names = {
|
protocol_names = {
|
||||||
0: "iPad",
|
0: "iPad",
|
||||||
1: "Android Phone",
|
1: "Android Phone",
|
||||||
@ -29,19 +32,108 @@ protocol_names = {
|
|||||||
@stats.handle()
|
@stats.handle()
|
||||||
async def _(bot: T_Bot, event: T_MessageEvent):
|
async def _(bot: T_Bot, event: T_MessageEvent):
|
||||||
ulang = get_user_lang(str(event.user_id))
|
ulang = get_user_lang(str(event.user_id))
|
||||||
fake_device_info: dict = bot.config.dict().get("fake_device_info", {})
|
image = await template2image(
|
||||||
mem_total = fake_device_info.get('mem', {}).get('total', psutil.virtual_memory().total)
|
get_path("templates/stats.html", abs_path=True),
|
||||||
|
{
|
||||||
|
"data": await get_stats_data(bot.self_id, ulang.lang_code)
|
||||||
|
},
|
||||||
|
debug=True
|
||||||
|
)
|
||||||
|
await stats.finish(MessageSegment.image(image))
|
||||||
|
|
||||||
|
|
||||||
|
async def get_bots_data(ulang: Language, self_id: "") -> list:
|
||||||
|
bots_data = []
|
||||||
|
for bot_id, bot in nonebot.get_bots().items():
|
||||||
|
groups = 0
|
||||||
|
friends = 0
|
||||||
|
status = {}
|
||||||
|
bot_name = bot_id
|
||||||
|
version_info = {}
|
||||||
|
try:
|
||||||
|
bot_name = (await bot.get_login_info())["nickname"]
|
||||||
|
groups = len(await bot.get_group_list())
|
||||||
|
friends = len(await bot.get_friend_list())
|
||||||
|
status = await bot.get_status()
|
||||||
|
version_info = await bot.get_version_info()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
statistics = status.get("stat", {})
|
||||||
|
app_name = version_info.get("app_name", "UnknownImplementation")
|
||||||
|
if app_name in ["Lagrange.OneBot", "LLOneBot", "Shamrock"]:
|
||||||
|
icon = f"https://q.qlogo.cn/g?b=qq&nk={bot_id}&s=640"
|
||||||
|
else:
|
||||||
|
icon = "./img/liteyuki.png"
|
||||||
|
bot_data = {
|
||||||
|
"name": bot_name,
|
||||||
|
"icon": icon,
|
||||||
|
"id" : bot_id,
|
||||||
|
"tags": [
|
||||||
|
protocol_names.get(version_info.get("protocol_name"), "Online"),
|
||||||
|
f"{ulang.get('liteyuki.stats.groups')} {groups}",
|
||||||
|
f"{ulang.get('liteyuki.stats.friends')} {friends}",
|
||||||
|
f"{ulang.get('liteyuki.stats.sent')} {statistics.get('message_sent', 0)}",
|
||||||
|
f"{ulang.get('liteyuki.stats.received')} {statistics.get('message_received', 0)}",
|
||||||
|
app_name,
|
||||||
|
|
||||||
|
],
|
||||||
|
"self": bot_id == self_id, # 判断是否是自己
|
||||||
|
}
|
||||||
|
bots_data.append(bot_data)
|
||||||
|
bots_data.append(
|
||||||
|
{
|
||||||
|
"name": "Liteyuki",
|
||||||
|
"icon": "./img/liteyuki.png",
|
||||||
|
"id" : "liteyuki",
|
||||||
|
"tags": [
|
||||||
|
f"{__NAME__} {__VERSION__}",
|
||||||
|
f"{ulang.get('liteyuki.stats.plugins')} {len(nonebot.get_loaded_plugins())}",
|
||||||
|
f"Nonebot {nonebot.__version__}",
|
||||||
|
f"{platform.python_implementation()} {platform.python_version()}",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return bots_data
|
||||||
|
|
||||||
|
|
||||||
|
async def get_stats_data(self_id: str = None, lang: str = None):
|
||||||
|
if self_id is None:
|
||||||
|
self_id = list(nonebot.get_bots().keys())[0] if len(nonebot.get_bots()) > 0 else "liteyuki"
|
||||||
|
if lang is None:
|
||||||
|
ulang = get_default_lang()
|
||||||
|
else:
|
||||||
|
ulang = Language(lang)
|
||||||
|
|
||||||
|
fake_device_info: dict = config.get("fake_device_info", {})
|
||||||
|
|
||||||
|
mem_info = psutil.virtual_memory()
|
||||||
|
mem_total = fake_device_info.get('mem', {}).get('total', mem_info.total)
|
||||||
|
|
||||||
|
convert_size(mem_total, 1, False)
|
||||||
|
mem_total_show = convert_size(mem_total, 1) # 格式化带单位
|
||||||
|
|
||||||
mem_used_bot = psutil.Process().memory_info().rss
|
mem_used_bot = psutil.Process().memory_info().rss
|
||||||
mem_used_other = psutil.virtual_memory().used - mem_used_bot
|
mem_used_bot_show = convert_size(mem_used_bot, 1)
|
||||||
mem_free = mem_total - mem_used_other - mem_used_bot
|
mem_used_other = mem_info.used - mem_used_bot
|
||||||
|
mem_free = mem_total - mem_info.used
|
||||||
|
mem_used_show = convert_size(mem_total - mem_used_bot - mem_used_other, 1) # 计算已用格式化带单位
|
||||||
|
|
||||||
groups = len(await bot.get_group_list())
|
swap_info = psutil.swap_memory()
|
||||||
friends = len(await bot.get_friend_list())
|
|
||||||
|
|
||||||
status = await bot.get_status()
|
disk_data = []
|
||||||
statistics = status.get("stat", {})
|
for disk in psutil.disk_partitions(all=True):
|
||||||
version_info = await bot.get_version_info()
|
disk_usage = psutil.disk_usage(disk.mountpoint)
|
||||||
|
disk_total_show = convert_size(disk_usage.total, 1)
|
||||||
|
disk_free_show = convert_size(disk_usage.free, 1)
|
||||||
|
disk_data.append(
|
||||||
|
{
|
||||||
|
"name" : disk.device,
|
||||||
|
"total" : disk_total_show,
|
||||||
|
"free" : disk_free_show,
|
||||||
|
"percent": disk_usage.percent,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
cpu_info = get_cpu_info()
|
cpu_info = get_cpu_info()
|
||||||
if "AMD" in cpu_info.get("brand_raw", ""):
|
if "AMD" in cpu_info.get("brand_raw", ""):
|
||||||
@ -56,7 +148,7 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
|||||||
|
|
||||||
cpu_info = get_cpu_info()
|
cpu_info = get_cpu_info()
|
||||||
templ = {
|
templ = {
|
||||||
"CPUDATA" : [
|
"cpu" : [
|
||||||
{
|
{
|
||||||
"name" : "USED",
|
"name" : "USED",
|
||||||
"value": psutil.cpu_percent(interval=1)
|
"value": psutil.cpu_percent(interval=1)
|
||||||
@ -66,7 +158,7 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
|||||||
"value": 100 - psutil.cpu_percent(interval=1)
|
"value": 100 - psutil.cpu_percent(interval=1)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"MEMDATA" : [
|
"mem" : [
|
||||||
|
|
||||||
{
|
{
|
||||||
"name" : "OTHER",
|
"name" : "OTHER",
|
||||||
@ -81,7 +173,7 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
|||||||
"value": mem_used_bot
|
"value": mem_used_bot
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"SWAPDATA" : [
|
"swap" : [
|
||||||
{
|
{
|
||||||
"name" : "USED",
|
"name" : "USED",
|
||||||
"value": psutil.swap_memory().used
|
"value": psutil.swap_memory().used
|
||||||
@ -91,44 +183,30 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
|||||||
"value": psutil.swap_memory().free
|
"value": psutil.swap_memory().free
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"BOT_ID" : bot.self_id,
|
"disk" : disk_data, # list[{"name":"C", "total":100, "used":50, "free":50}]
|
||||||
"BOT_NAME" : (await bot.get_login_info())["nickname"],
|
"bot" : await get_bots_data(ulang, self_id),
|
||||||
"BOT_TAGS" : [
|
"cpuTags" : [
|
||||||
protocol_names.get(version_info.get("protocol_name"), "Online"),
|
|
||||||
f"{ulang.get('liteyuki.stats.plugins')} {len(nonebot.get_loaded_plugins())}",
|
|
||||||
f"{ulang.get('liteyuki.stats.groups')} {groups}",
|
|
||||||
f"{ulang.get('liteyuki.stats.friends')} {friends}",
|
|
||||||
f"{ulang.get('liteyuki.stats.sent')} {statistics.get('message_sent', 0)}",
|
|
||||||
f"{ulang.get('liteyuki.stats.received')} {statistics.get('message_received', 0)}",
|
|
||||||
f"{__NAME__} {__VERSION__}",
|
|
||||||
f"Nonebot {nonebot.__version__}",
|
|
||||||
f"{platform.python_implementation()} {platform.python_version()}",
|
|
||||||
version_info.get("app_name"),
|
|
||||||
],
|
|
||||||
"CPU_TAGS" : [
|
|
||||||
f"{brand} {cpu_info.get('arch', 'Unknown')}",
|
f"{brand} {cpu_info.get('arch', 'Unknown')}",
|
||||||
f"{fake_device_info.get('cpu', {}).get('cores', psutil.cpu_count(logical=False))}C "
|
f"{fake_device_info.get('cpu', {}).get('cores', psutil.cpu_count(logical=False))}C "
|
||||||
f"{fake_device_info.get('cpu', {}).get('logical_cores', psutil.cpu_count(logical=True))}T",
|
f"{fake_device_info.get('cpu', {}).get('logical_cores', psutil.cpu_count(logical=True))}T",
|
||||||
f"{fake_device_info.get('cpu', {}).get('frequency', psutil.cpu_freq().current) / 1000}GHz"
|
f"{fake_device_info.get('cpu', {}).get('frequency', psutil.cpu_freq().current) / 1000}GHz"
|
||||||
],
|
],
|
||||||
"MEM_TAGS" : [
|
"memTags" : [
|
||||||
f"Bot {convert_size(mem_used_bot, 1)}",
|
f"Bot {mem_used_bot_show}",
|
||||||
f"{ulang.get('main.monitor.used')} {convert_size(mem_used_other + mem_used_bot, 1)}",
|
f"{ulang.get('main.monitor.used')} {mem_used_show}",
|
||||||
f"{ulang.get('main.monitor.total')} {convert_size(mem_total, 1)}",
|
f"{ulang.get('main.monitor.total')} {mem_total_show}",
|
||||||
|
f"{ulang.get('main.monitor.free')} {convert_size(mem_free, 1)}",
|
||||||
],
|
],
|
||||||
"SWAP_TAGS": [
|
"swapTags" : [
|
||||||
f"{ulang.get('main.monitor.used')} {convert_size(psutil.swap_memory().used, 1)}",
|
f"{ulang.get('main.monitor.used')} {convert_size(swap_info.used, 1)}",
|
||||||
f"{ulang.get('main.monitor.total')} {convert_size(psutil.swap_memory().total, 1)}",
|
f"{ulang.get('main.monitor.total')} {convert_size(swap_info.total, 1)}",
|
||||||
|
f"{ulang.get('main.monitor.free')} {convert_size(swap_info.free, 1)}",
|
||||||
],
|
],
|
||||||
"CPU" : ulang.get("main.monitor.cpu"),
|
"cpu_trans" : ulang.get("main.monitor.cpu"),
|
||||||
"MEM" : ulang.get("main.monitor.memory"),
|
"mem_trans" : ulang.get("main.monitor.memory"),
|
||||||
"SWAP" : ulang.get("main.monitor.swap"),
|
"swap_trans" : ulang.get("main.monitor.swap"),
|
||||||
|
"used_trans" : ulang.get("main.monitor.used"),
|
||||||
|
"free_trans" : ulang.get("main.monitor.free"),
|
||||||
|
"total_trans": ulang.get("main.monitor.total"),
|
||||||
}
|
}
|
||||||
image_bytes = await template2image(
|
return templ
|
||||||
template=get_path("templates/stats.html", abs_path=True),
|
|
||||||
templates=templ,
|
|
||||||
scale_factor=1,
|
|
||||||
debug=True
|
|
||||||
)
|
|
||||||
# await md.send_image(image_bytes, bot, event=event)
|
|
||||||
await stats.finish(MessageSegment.image(image_bytes))
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
from nonebot import on_command
|
||||||
from liteyuki.utils.data import LiteModel
|
from liteyuki.utils.data import LiteModel
|
||||||
|
|
||||||
|
|
||||||
@ -11,3 +11,30 @@ class WeatherNow(LiteModel):
|
|||||||
time: str = ""
|
time: str = ""
|
||||||
city: str = ""
|
city: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
weather = on_command("weather", aliases={"天气", "查天气", "天气预报", "查天气预报"})
|
||||||
|
weather_now = on_command("weather_now", aliases={"实时天气", "查实时天气", "实时天气预报", "查实时天气预报"})
|
||||||
|
weather_forecast = on_command("weather_forecast", aliases={"天气预报", "查天气预报", "未来天气", "查未来天气"})
|
||||||
|
weather_warning = on_command("weather_warning", aliases={"天气预警", "查天气预警", "天气警告", "查天气警告"})
|
||||||
|
weather_life = on_command("weather_life", aliases={"生活指数", "查生活指数", "生活指数预报", "查生活指数预报"})
|
||||||
|
weather_air = on_command("weather_air", aliases={"空气质量", "查空气质量", "空气质量预报", "查空气质量预报"})
|
||||||
|
weather_rain = on_command("weather_rain", aliases={"降雨预报", "查降雨预报", "降雨量", "查降雨量"})
|
||||||
|
weather_snow = on_command("weather_snow", aliases={"降雪预报", "查降雪预报", "降雪量", "查降雪量"})
|
||||||
|
|
||||||
|
|
||||||
|
@weather.handle()
|
||||||
|
async def handle_weather(bot, event):
|
||||||
|
args = str(event.get_message()).strip()
|
||||||
|
if not args:
|
||||||
|
await weather.finish("请输入要查询的城市")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@weather_now.handle()
|
||||||
|
async def handle_weather_now(bot, event):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@weather_forecast.handle()
|
||||||
|
async def handle_weather_forecast(bot, event):
|
||||||
|
pass
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -97,4 +97,5 @@ user.profile.set_failed={ATTR} festlegen fehlgeschlagen. Bitte überprüfen Sie,
|
|||||||
liteyuki.image_mode_on=Markdown-Bild
|
liteyuki.image_mode_on=Markdown-Bild
|
||||||
liteyuki.image_mode_off=Markdown-Link
|
liteyuki.image_mode_off=Markdown-Link
|
||||||
|
|
||||||
npm.page=Page {PAGE}/{TOTAL}
|
npm.page=Page {PAGE}/{TOTAL}
|
||||||
|
main.monitor.free=Free
|
@ -1,10 +1,10 @@
|
|||||||
language.name=English
|
language.name=English
|
||||||
|
|
||||||
log.debug=Debug
|
log.debug=DEBUG
|
||||||
log.info=Info
|
log.info=INFO
|
||||||
log.warning=Warning
|
log.warning=WARNING
|
||||||
log.error=Error
|
log.error=ERROR
|
||||||
log.success=Success
|
log.success=SUCCESS
|
||||||
|
|
||||||
liteyuki.restart=Restart
|
liteyuki.restart=Restart
|
||||||
liteyuki.restart_now=Restart Now
|
liteyuki.restart_now=Restart Now
|
||||||
@ -97,4 +97,5 @@ user.profile.set_failed=Setting {ATTR} failed. Please check if the input is vali
|
|||||||
liteyuki.image_mode_on=Enable markdown image
|
liteyuki.image_mode_on=Enable markdown image
|
||||||
liteyuki.image_mode_off=Closed markdown image
|
liteyuki.image_mode_off=Closed markdown image
|
||||||
|
|
||||||
npm.page=Page {PAGE}/{TOTAL}
|
npm.page=Page {PAGE}/{TOTAL}
|
||||||
|
main.monitor.free=Free
|
@ -92,4 +92,10 @@ user.profile.nickname.desc=Establecer el apodo del Bot para el usuario
|
|||||||
|
|
||||||
user.profile.input_value=Por favor ingresa {ATTR}
|
user.profile.input_value=Por favor ingresa {ATTR}
|
||||||
user.profile.set_success={ATTR} establecido correctamente a {VALUE}
|
user.profile.set_success={ATTR} establecido correctamente a {VALUE}
|
||||||
user.profile.set_failed=Fallo al establecer {ATTR}. Por favor, verifica si la entrada es válida.
|
user.profile.set_failed=Fallo al establecer {ATTR}. Por favor, verifica si la entrada es válida.
|
||||||
|
|
||||||
|
liteyuki.image_mode_on=Markdown de imagen abierta
|
||||||
|
liteyuki.image_mode_off=Markdown de imagen cerrada
|
||||||
|
|
||||||
|
npm.page=Página {PAGE}/{TOTAL}
|
||||||
|
main.monitor.free=Libre
|
@ -92,4 +92,7 @@ user.profile.nickname.desc=Définir le pseudo du Bot pour l'utilisateur
|
|||||||
|
|
||||||
user.profile.input_value=Veuillez entrer {ATTR}
|
user.profile.input_value=Veuillez entrer {ATTR}
|
||||||
user.profile.set_success={ATTR} défini avec succès sur {VALUE}
|
user.profile.set_success={ATTR} défini avec succès sur {VALUE}
|
||||||
user.profile.set_failed=Échec de la définition de {ATTR}. Veuillez vérifier si l'entrée est valide.
|
user.profile.set_failed=Échec de la définition de {ATTR}. Veuillez vérifier si l'entrée est valide.
|
||||||
|
|
||||||
|
liteyuki.image_mode_on=Ouvert markdown image
|
||||||
|
liteyuki.image_mode_off=Fermé markdown image
|
@ -97,4 +97,5 @@ user.profile.set_failed=设置 {ATTR} 失败,请检查输入是否合法
|
|||||||
liteyuki.image_mode_on=开启Markdown图片模式
|
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=空闲
|
@ -1,13 +1,54 @@
|
|||||||
|
/*MiSans*/
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'MiSans';
|
font-family: 'MiSans';
|
||||||
src: url('../../fonts/normal.ttf') format('truetype');
|
src: url('../fonts/MiSans/MiSans-Normal.woff2') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'MiSans';
|
font-family: 'MiSans';
|
||||||
src: url('../../fonts/bold.ttf') format('truetype');
|
src: url('../fonts/MiSans/MiSans-Bold.woff2') format('truetype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*MapleMono*/
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MapleMono';
|
||||||
|
src: url('../fonts/MapleMono/MapleMono-Light.woff2') format('truetype');
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MapleMono';
|
||||||
|
src: url('../fonts/MapleMono/MapleMono-LightItalic.woff2') format('truetype');
|
||||||
|
font-weight: 200;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MapleMono';
|
||||||
|
src: url('../fonts/MapleMono/MapleMono-Regular.woff2') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MapleMono';
|
||||||
|
src: url('../fonts/MapleMono/MapleMono-Italic.woff2') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MapleMono';
|
||||||
|
src: url('../fonts/MapleMono/MapleMono-Bold.woff2') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MapleMono';
|
||||||
|
src: url('../fonts/MapleMono/MapleMono-BoldItalic.woff2') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Bold.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Bold.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Demibold.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Demibold.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Heavy.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Heavy.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Light.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Light.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Medium.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Medium.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Normal.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Normal.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Regular.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Regular.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Semibold.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Semibold.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Thin.woff2
Normal file
BIN
liteyuki/resources/templates/fonts/MiSans/MiSans-Thin.woff2
Normal file
Binary file not shown.
BIN
liteyuki/resources/templates/img/bg2.jpg
Normal file
BIN
liteyuki/resources/templates/img/bg2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
BIN
liteyuki/resources/templates/img/bg3.jpg
Normal file
BIN
liteyuki/resources/templates/img/bg3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
BIN
liteyuki/resources/templates/img/bg4.jpg
Normal file
BIN
liteyuki/resources/templates/img/bg4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
BIN
liteyuki/resources/templates/img/liteyuki.png
Normal file
BIN
liteyuki/resources/templates/img/liteyuki.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
@ -1,13 +1,27 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="zh-CN">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=1080, initial-scale=1.0">
|
||||||
<title>Document</title>
|
<title>Liteyuki Stats</title>
|
||||||
<link rel="stylesheet" href="css/fonts.css">
|
<link rel="stylesheet" href="css/fonts.css">
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans';
|
||||||
|
src: url('fonts/normal.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans';
|
||||||
|
src: url('fonts/bold.ttf') format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'MiSans', serif;
|
font-family: 'MiSans', serif;
|
||||||
background-repeat: repeat-y;
|
background-repeat: repeat-y;
|
||||||
@ -16,7 +30,8 @@
|
|||||||
background-image: url('img/bg1.jpg');
|
background-image: url('img/bg1.jpg');
|
||||||
color: white;
|
color: white;
|
||||||
// 上10px,左右10px,下0px
|
// 上10px,左右10px,下0px
|
||||||
margin: 24px;
|
//margin: 24px;
|
||||||
|
margin: 20px;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -26,47 +41,54 @@
|
|||||||
padding: 30px;
|
padding: 30px;
|
||||||
backdrop-filter: blur(30px);
|
backdrop-filter: blur(30px);
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
display: flex;
|
margin-bottom: 20px;
|
||||||
margin: 0 24px 24px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#cpu-chart, #mem-chart, #swap-chart {
|
.pie-chart {
|
||||||
height: 240px;
|
height: 240px;
|
||||||
width: 240px;
|
width: 240px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#cpu-info, #mem-info, #swap-info {
|
.pie-info {
|
||||||
margin: 0 40px;
|
margin: 0 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bot-info {
|
.bot-info {
|
||||||
margin-top: 24px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#hardware-info {
|
#hardware-info {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bot-icon {
|
#disks-info {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bot-icon {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bot-name, #bot-tag {
|
.bot-name, .bot-tag {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bot-name {
|
.bot-name {
|
||||||
font-size: 42px;
|
font-size: 42px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#bot-tag {
|
.bot-tag {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,87 +98,67 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
font-size: 27px;
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag::after {
|
.tag[suffix="1"]::after {
|
||||||
content: "|";
|
content: " | ";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
line-height: 50%;
|
line-height: 50%;
|
||||||
color: #aaa;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@4.3.0/dist/echarts.min.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@4.3.0/dist/echarts.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="info-box" id="bot-info">
|
|
||||||
<span>
|
|
||||||
<img id="bot-icon" src="https://q.qlogo.cn/g?b=qq&nk={{BOT_ID}}}&s=640" alt="BotIcon">
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span id="bot-name">
|
|
||||||
{{ BOT_NAME }}
|
|
||||||
</span>
|
|
||||||
<div id="bot-tag"></div>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-box" id="hardware-info">
|
<div class="info-box" id="hardware-info">
|
||||||
<div id="cpu-info">
|
<div class="pie-info" id="cpu-info">
|
||||||
<div id="cpu-chart"></div>
|
<div class="pie-chart" id="cpu-chart"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mem-info">
|
<div class="pie-info" id="mem-info">
|
||||||
<div id="mem-chart"></div>
|
<div class="pie-chart" id="mem-chart"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="swap-info">
|
<div class="pie-info" id="swap-info">
|
||||||
<div id="swap-chart"></div>
|
<div class="pie-chart" id="swap-chart"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="cpuData" style="display: none;">{{ CPUDATA | tojson }}</div>
|
<div class="info-box" id="disks-info">
|
||||||
<div id="memData" style="display: none;">{{ MEMDATA | tojson }}</div>
|
</div>
|
||||||
<div id="swapData" style="display: none;">{{ SWAPDATA | tojson }}</div>
|
|
||||||
<div id="botTag" style="display: none;">{{ BOT_TAGS | tojson }}</div>
|
|
||||||
<div id="cpuTag" style="display: none;">{{ CPU_TAGS | tojson }}</div>
|
|
||||||
<div id="memTag" style="display: none;">{{ MEM_TAGS | tojson }}</div>
|
|
||||||
<div id="swapTag" style="display: none;">{{ SWAP_TAGS | tojson }}</div>
|
|
||||||
|
|
||||||
|
<!--储存数据div,不显示-->
|
||||||
|
<div id="data" style="display: none">{{ data | tojson }}</div>
|
||||||
<script>
|
<script>
|
||||||
// 环形图
|
|
||||||
{
|
{
|
||||||
let bgs = ["bg1.jpg"]
|
// 环形图
|
||||||
|
|
||||||
|
let bgs = ["bg1.jpg", "bg2.jpg", "bg3.jpg", "bg4.jpg"]
|
||||||
// 随机选择背景图片
|
// 随机选择背景图片
|
||||||
document.body.style.backgroundImage = `url(./img/${bgs[Math.floor(Math.random() * bgs.length)]})`;
|
document.body.style.backgroundImage = `url(./img/${bgs[Math.floor(Math.random() * bgs.length)]})`;
|
||||||
|
|
||||||
let botTags = JSON.parse(document.getElementById('botTag').innerText);
|
|
||||||
|
|
||||||
botTags.forEach(tag => {
|
|
||||||
let tagSpan = document.createElement('span');
|
|
||||||
tagSpan.innerText = tag;
|
|
||||||
tagSpan.className = 'tag';
|
|
||||||
document.getElementById('bot-tag').appendChild(tagSpan);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let cpuInfo = echarts.init(document.getElementById('cpu-chart'));
|
let cpuInfo = echarts.init(document.getElementById('cpu-chart'));
|
||||||
let memInfo = echarts.init(document.getElementById('mem-chart'));
|
let memInfo = echarts.init(document.getElementById('mem-chart'));
|
||||||
let swapInfo = echarts.init(document.getElementById('swap-chart'));
|
let swapInfo = echarts.init(document.getElementById('swap-chart'));
|
||||||
let cpuData = JSON.parse(document.getElementById('cpuData').innerText);
|
|
||||||
let memData = JSON.parse(document.getElementById('memData').innerText);
|
|
||||||
let swapData = JSON.parse(document.getElementById('swapData').innerText);
|
|
||||||
|
|
||||||
sub_tag_data = {
|
let data = JSON.parse(document.getElementById('data').innerText);
|
||||||
cpu: JSON.parse(document.getElementById('cpuTag').innerText),
|
|
||||||
mem: JSON.parse(document.getElementById('memTag').innerText),
|
let cpuData = data.cpu;
|
||||||
swap: JSON.parse(document.getElementById('swapTag').innerText)
|
let memData = data.mem;
|
||||||
|
let swapData = data.swap;
|
||||||
|
let diskData = data.disk;
|
||||||
|
let sub_tag_data = {
|
||||||
|
cpu: data.cpuTags,
|
||||||
|
mem: data.memTags,
|
||||||
|
swap: data.swapTags
|
||||||
}
|
}
|
||||||
// 遍历key和value,key是cpu,mem,swap,value是对应的tag数组,添加div标签class为chart-label
|
|
||||||
for (let key in sub_tag_data) {
|
for (let key in sub_tag_data) {
|
||||||
|
console.log(key, sub_tag_data[key])
|
||||||
let infoDiv = document.getElementById(key + '-info');
|
let infoDiv = document.getElementById(key + '-info');
|
||||||
sub_tag_data[key].forEach(tag => {
|
sub_tag_data[key].forEach(tag => {
|
||||||
let tagSpan = document.createElement('div');
|
let tagSpan = document.createElement('div');
|
||||||
@ -165,8 +167,84 @@
|
|||||||
infoDiv.appendChild(tagSpan);
|
infoDiv.appendChild(tagSpan);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
cpuInfo.setOption(getPieOption(data.cpu_trans, cpuData));
|
||||||
function getOption(title, data) {
|
memInfo.setOption(getPieOption(data.mem_trans, memData));
|
||||||
|
swapInfo.setOption(getPieOption(data.swap_trans, swapData));
|
||||||
|
|
||||||
|
|
||||||
|
// 在disks-info中插入每个disk的div,用横向柱状图表示用量,每一行div显示一个disk,不加info-box
|
||||||
|
diskData.forEach(disk => {
|
||||||
|
let diskDiv = document.createElement('div');
|
||||||
|
document.getElementById('disks-info').appendChild(diskDiv);
|
||||||
|
let diskChart = document.createElement('div');
|
||||||
|
diskChart.style.width = '100%';
|
||||||
|
diskChart.style.height = '100px';
|
||||||
|
diskDiv.appendChild(diskChart);
|
||||||
|
let diskInfo = echarts.init(diskChart);
|
||||||
|
// let diskTitle = disk.name + ' {{ FREE }} ' + disk.free + ' {{ TOTAL }} ' + disk.total;
|
||||||
|
let diskTitle = `${disk.name} ${data.free_trans} ${disk.free} ${data.total_trans} ${disk.total}`;
|
||||||
|
diskInfo.setOption(getBarOption(diskTitle, disk.percent));
|
||||||
|
});
|
||||||
|
|
||||||
|
let botData = data.bot;
|
||||||
|
// 清空bot-info
|
||||||
|
let botInfos = document.getElementsByClassName('bot-info');
|
||||||
|
while (botInfos.length > 0) {
|
||||||
|
botInfos[0].remove();
|
||||||
|
}
|
||||||
|
botData.forEach(bot => {
|
||||||
|
// 在hardware-info前面插入一个div
|
||||||
|
let botDiv = document.createElement('div');
|
||||||
|
botDiv.className = 'info-box bot-info';
|
||||||
|
// 在body内的hardware-info前面插入botDiv
|
||||||
|
document.body.insertBefore(botDiv, document.getElementById('hardware-info'));
|
||||||
|
|
||||||
|
let botIconBlock = document.createElement('div');
|
||||||
|
let botIcon = document.createElement('img');
|
||||||
|
botIcon.src = bot.icon;
|
||||||
|
botIcon.className = 'bot-icon';
|
||||||
|
botIconBlock.appendChild(botIcon);
|
||||||
|
botDiv.appendChild(botIconBlock);
|
||||||
|
|
||||||
|
let botDetail = document.createElement('div');
|
||||||
|
let botName = document.createElement('div');
|
||||||
|
botName.className = 'bot-name';
|
||||||
|
botName.innerText = bot.name;
|
||||||
|
if (bot.self) {
|
||||||
|
// 添加颜色
|
||||||
|
botName.style.color = '#d0e9ff';
|
||||||
|
}
|
||||||
|
botDetail.appendChild(botName);
|
||||||
|
|
||||||
|
let botTags = document.createElement('div');
|
||||||
|
botTags.className = 'bot-tag';
|
||||||
|
botDetail.appendChild(botTags)
|
||||||
|
|
||||||
|
bot.tags.forEach((tag, index) => {
|
||||||
|
if (!tag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tagSpan = document.createElement('span');
|
||||||
|
|
||||||
|
tagSpan.innerText = tag;
|
||||||
|
tagSpan.className = 'tag';
|
||||||
|
if (bot.self) {
|
||||||
|
// 添加颜色
|
||||||
|
tagSpan.style.color = '#a2d8f4';
|
||||||
|
}
|
||||||
|
botTags.appendChild(tagSpan);
|
||||||
|
if (index === bot.tags.length - 1) {
|
||||||
|
tagSpan.setAttribute("suffix", "0")
|
||||||
|
} else {
|
||||||
|
tagSpan.setAttribute("suffix", "1")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
botDiv.appendChild(botDetail);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function getPieOption(title, data) {
|
||||||
return {
|
return {
|
||||||
animation: false,
|
animation: false,
|
||||||
title: {
|
title: {
|
||||||
@ -216,10 +294,69 @@
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
cpuInfo.setOption(getOption("{{ CPU }}", cpuData));
|
function getBarOption(title, percent) {
|
||||||
memInfo.setOption(getOption('{{ MEM }}', memData));
|
// data为百分比,最大值为100
|
||||||
swapInfo.setOption(getOption('{{ SWAP }}', swapData));
|
return {
|
||||||
|
background: '#d0e9ff',
|
||||||
|
title: {
|
||||||
|
text: title,
|
||||||
|
left: '5%',
|
||||||
|
top: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: "item",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '0',
|
||||||
|
right: '0',
|
||||||
|
top: '10%',
|
||||||
|
bottom: '10%'
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'value',
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: [''],
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Used',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'total',
|
||||||
|
data: [percent],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#a2d8f4',
|
||||||
|
barBorderRadius: [50, 0, 0, 50]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Free',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'total',
|
||||||
|
data: [100 - percent],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#d0e9ff',
|
||||||
|
barBorderRadius: [0, 50, 50, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -31,6 +31,21 @@ from nonebot_plugin_htmlrender import *
|
|||||||
# """
|
# """
|
||||||
# return await html_to_pic(html, wait=wait, template_path=template_path, scale_factor=scale_factor)
|
# return await html_to_pic(html, wait=wait, template_path=template_path, scale_factor=scale_factor)
|
||||||
|
|
||||||
|
async def template2html(
|
||||||
|
template: str,
|
||||||
|
templates: dict,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
template: str: 模板文件
|
||||||
|
**templates: dict: 模板参数
|
||||||
|
Returns:
|
||||||
|
HTML 正文
|
||||||
|
"""
|
||||||
|
template_path = os.path.dirname(template)
|
||||||
|
template_name = os.path.basename(template)
|
||||||
|
return await template_to_html(template_path, template_name, **templates)
|
||||||
|
|
||||||
|
|
||||||
async def template2image(
|
async def template2image(
|
||||||
template: str,
|
template: str,
|
||||||
@ -81,3 +96,32 @@ async def template2image(
|
|||||||
wait=wait,
|
wait=wait,
|
||||||
device_scale_factor=scale_factor,
|
device_scale_factor=scale_factor,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def url2image(
|
||||||
|
url: str,
|
||||||
|
wait: int = 0,
|
||||||
|
scale_factor: float = 1,
|
||||||
|
type: str = "png",
|
||||||
|
quality: int = 100,
|
||||||
|
**kwargs
|
||||||
|
) -> bytes:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
quality:
|
||||||
|
type:
|
||||||
|
url: str: URL
|
||||||
|
wait: int: 等待时间
|
||||||
|
scale_factor: float: 缩放因子
|
||||||
|
**kwargs: page 参数
|
||||||
|
Returns:
|
||||||
|
图片二进制数据
|
||||||
|
"""
|
||||||
|
async with get_new_page(scale_factor) as page:
|
||||||
|
await page.goto(url)
|
||||||
|
await page.wait_for_timeout(wait)
|
||||||
|
return await page.screenshot(
|
||||||
|
full_page=True,
|
||||||
|
type=type,
|
||||||
|
quality=quality
|
||||||
|
)
|
||||||
|
@ -67,8 +67,8 @@ def init_log():
|
|||||||
warning = lang.get("log.warning", default="WARNING")
|
warning = lang.get("log.warning", default="WARNING")
|
||||||
error = lang.get("log.error", default="==ERROR")
|
error = lang.get("log.error", default="==ERROR")
|
||||||
|
|
||||||
logger.level("DEBUG", color="<blue>", icon=f"{'*️⃣' if show_icon else ''}{debug}")
|
logger.level("DEBUG", color="<blue>", icon=f"{'🐛' if show_icon else ''}{debug}")
|
||||||
logger.level("INFO", color="<white>", icon=f"{'ℹ️' if show_icon else ''}{info}")
|
logger.level("INFO", color="<normal>", icon=f"{'ℹ️' if show_icon else ''}{info}")
|
||||||
logger.level("SUCCESS", color="<green>", icon=f"{'✅' if show_icon else ''}{success}")
|
logger.level("SUCCESS", color="<green>", icon=f"{'✅' if show_icon else ''}{success}")
|
||||||
logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}{warning}")
|
logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}{warning}")
|
||||||
logger.level("ERROR", color="<red>", icon=f"{'⭕' if show_icon else ''}{error}")
|
logger.level("ERROR", color="<red>", icon=f"{'⭕' if show_icon else ''}{error}")
|
||||||
|
@ -15,13 +15,13 @@ def clamp(value: float, min_value: float, max_value: float) -> float | int:
|
|||||||
return max(min(value, max_value), min_value)
|
return max(min(value, max_value), min_value)
|
||||||
|
|
||||||
|
|
||||||
def convert_size(size: int, precision: int = 2, add_unit: bool = True, suffix: str = "iB") -> str:
|
def convert_size(size: int, precision: int = 2, add_unit: bool = True, suffix: str = " XiB") -> str | float:
|
||||||
"""把字节数转换为人类可读的字符串,计算正负
|
"""把字节数转换为人类可读的字符串,计算正负
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
||||||
add_unit: 是否添加单位,False后则suffix无效
|
add_unit: 是否添加单位,False后则suffix无效
|
||||||
suffix: iB或B
|
suffix: XiB或XB
|
||||||
precision: 浮点数的小数点位数
|
precision: 浮点数的小数点位数
|
||||||
size (int): 字节数
|
size (int): 字节数
|
||||||
|
|
||||||
@ -29,23 +29,18 @@ def convert_size(size: int, precision: int = 2, add_unit: bool = True, suffix: s
|
|||||||
|
|
||||||
str: The human-readable string, e.g. "1.23 GB".
|
str: The human-readable string, e.g. "1.23 GB".
|
||||||
"""
|
"""
|
||||||
is_negative = False
|
is_negative = size < 0
|
||||||
if size < 0:
|
size = abs(size)
|
||||||
is_negative = True
|
for unit in ("", "K", "M", "G", "T", "P", "E", "Z"):
|
||||||
size = -size
|
|
||||||
|
|
||||||
for unit in ["", "K", "M", "G", "T", "P", "E", "Z", "Y"]:
|
|
||||||
if size < 1024:
|
if size < 1024:
|
||||||
if add_unit:
|
break
|
||||||
result = f"{size:.{precision}f} {unit}" + suffix
|
|
||||||
return f"-{result}" if is_negative else result
|
|
||||||
else:
|
|
||||||
return f"{size:.{precision}f}"
|
|
||||||
size /= 1024
|
size /= 1024
|
||||||
|
if is_negative:
|
||||||
|
size = -size
|
||||||
if add_unit:
|
if add_unit:
|
||||||
return f"{size:.{precision}f} Y" + suffix
|
return f"{size:.{precision}f}{suffix.replace('X', unit)}"
|
||||||
else:
|
else:
|
||||||
return f"{size:.{precision}f}"
|
return size
|
||||||
|
|
||||||
|
|
||||||
def keywords_in_text(keywords: list[str], text: str, all_matched: bool) -> bool:
|
def keywords_in_text(keywords: list[str], text: str, all_matched: bool) -> bool:
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
aiohttp==3.9.3
|
aiohttp==3.9.3
|
||||||
aiofiles==23.2.1
|
aiofiles==23.2.1
|
||||||
arclet-alconna==1.8.5
|
|
||||||
arclet-alconna-tools==0.7.0
|
|
||||||
colored==2.2.4
|
colored==2.2.4
|
||||||
dash==2.16.1
|
dash==2.16.1
|
||||||
GitPython==3.1.42
|
GitPython==3.1.42
|
||||||
jinja2==3.1.3
|
nonebot2[fastapi,httpx,websockets]==2.2.1
|
||||||
markdown==3.3.6
|
nonebot-plugin-htmlrender==0.3.1
|
||||||
nonebot2[fastapi]==2.2.1
|
|
||||||
nonebot-adapter-onebot==2.4.3
|
nonebot-adapter-onebot==2.4.3
|
||||||
nonebot-plugin-alconna==0.41.0
|
nonebot-plugin-alconna==0.41.0
|
||||||
playwright==1.17.2
|
playwright==1.17.2
|
||||||
@ -16,13 +13,9 @@ py-cpuinfo==9.0.0
|
|||||||
pydantic==1.10.14
|
pydantic==1.10.14
|
||||||
Pygments==2.17.2
|
Pygments==2.17.2
|
||||||
pytz==2024.1
|
pytz==2024.1
|
||||||
python-markdown-math==0.8
|
|
||||||
pymdown-extensions==10.7.1
|
|
||||||
PyYAML~=6.0.1
|
PyYAML~=6.0.1
|
||||||
starlette~=0.36.3
|
starlette~=0.36.3
|
||||||
loguru==0.7.2
|
loguru==0.7.2
|
||||||
importlib_metadata==7.0.2
|
importlib_metadata==7.0.2
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
pillow==10.2.0
|
pillow==10.2.0
|
||||||
pyppeteer==2.0.0
|
|
||||||
weasyprint==61.2
|
|
||||||
|
Loading…
Reference in New Issue
Block a user