小范围优化,综合性改动

This commit is contained in:
EillesWan 2024-12-13 15:07:17 +08:00
parent b44ac220df
commit f6941b534d
19 changed files with 748 additions and 151 deletions

View File

@ -7,7 +7,7 @@ import inspect
import multiprocessing import multiprocessing
import threading import threading
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Coroutine from typing import Any, Callable, Coroutine, Sequence
from liteyuki.log import logger from liteyuki.log import logger
@ -104,3 +104,23 @@ def async_wrapper(func: Callable[..., Any]) -> Callable[..., Coroutine]:
wrapper.__signature__ = inspect.signature(func) wrapper.__signature__ = inspect.signature(func)
return wrapper return wrapper
def for_in(
elements: Sequence,
test_list: Sequence,
):
"""
判断元素是否在列表中
Args:
elements: 元素列表
test_list: 测试列表
Returns:
List 在列表中的元素
"""
return [element for element in elements if element in test_list]
# for element in elements:
# if element in test_list:
# return True
# return False

View File

@ -3,18 +3,18 @@ from .status import *
__author__ = "神羽SnowyKami & 金羿Eilles" __author__ = "神羽SnowyKami & 金羿Eilles"
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="状态查看", name="灵温状态查看",
description="", description="",
usage=( usage=(
"MARKDOWN### 状态查看器\n" "MARKDOWN### 状态查看器\n"
"查看机器人的状态\n" "查看机器人的状态\n"
"### 用法\n" "### 用法\n"
"- `/status` 查看基本情况\n" "- `/status` 查看基本情况\n"
"- `/status memory` 查看内存使用情况\n" "- `/status -r` 强制刷新状态情况\n"
"- `/status process` 查看进程情况\n" "- `/status -d` 使用简化markdown渲染状态\n"
), ),
type="application", type="application",
homepage="https://github.com/snowykami/LiteyukiBot", homepage="https://gitee.com/TriM-Organization/LiteyukiBot-TriM",
extra={ extra={
"liteyuki": True, "liteyuki": True,
"toggleable": False, "toggleable": False,

View File

@ -4,16 +4,16 @@ import time
import nonebot import nonebot
import psutil import psutil
from cpuinfo import cpuinfo from cpuinfo import cpuinfo
from nonebot import require
from nonebot.adapters import satori from nonebot.adapters import satori
from src.utils import __NAME__
from liteyuki import __version__ from liteyuki import __version__
from liteyuki.utils import for_in
from src.utils import __NAME__
from src.utils.base.config import get_config from src.utils.base.config import get_config
from src.utils.base.data_manager import TempConfig, common_db from src.utils.base.data_manager import TempConfig, common_db
from src.utils.base.language import Language from src.utils.base.language import Language
from src.utils.base.resource import get_loaded_resource_packs, get_path from src.utils.base.resource import get_loaded_resource_packs, get_path
from src.utils.message.html_tool import template2image from src.utils.message.html_tool import template2image, md_to_pic
from src.utils import satori_utils from src.utils import satori_utils
from .counter_for_satori import satori_counter from .counter_for_satori import satori_counter
from git import Repo from git import Repo
@ -32,6 +32,7 @@ protocol_names = {
6: "安卓平板", 6: "安卓平板",
} }
""" """
Universal Interface Universal Interface
data data
@ -87,6 +88,207 @@ data
# ) # )
# 用markdown文字展示状态卡片
async def generate_status_card_markdown(
bot: dict,
hardware: dict,
liteyuki: dict,
lang="zh-CN",
motto={"text": "风朗气清", "source": "成语一则"},
) -> bytes:
from .md_status_utils import (
markdown_status_bot_card_text,
markdown_status_card_text,
markdown_status_disk_card_text,
convert_size,
seconds2texttime,
)
local_dt = await get_local_data(lang)
bytes_suffix = " X" + local_dt["units"]["Byte"]
bin_units = local_dt["units"]["Bin_Units"]
markdown_status_bot_card_text__ = (
markdown_status_bot_card_text.replace(
r"{local_groups}",
local_dt["groups"],
)
.replace(
r"{local_friends}",
local_dt["friends"],
)
.replace(
r"{local_message_sent}",
local_dt["message_sent"],
)
.replace(
r"{local_message_received}",
local_dt["message_received"],
)
)
markdown_status_disk_card_text__ = (
markdown_status_disk_card_text.replace(
r"{local_used}",
local_dt["used"],
)
.replace(
r"{local_free}",
local_dt["free"],
)
.replace(
r"{local_total}",
local_dt["total"],
)
)
fnl_text = markdown_status_card_text.format(
local_description=local_dt["description"],
liteyuki_name=liteyuki["name"],
liteyuki_version=liteyuki["version"],
liteyuki_nonebot=liteyuki["nonebot"],
liteyuki_system=liteyuki["system"],
liteyuki_python=liteyuki["python"],
local_plugins=local_dt["plugins"],
liteyuki_plugins=liteyuki["plugins"],
local_resources=local_dt["resources"],
liteyuki_resources=liteyuki["resources"],
local_bots=local_dt["bots"],
liteyuki_bots=liteyuki["bots"],
local_runtime=local_dt["runtime"],
liteyuki_runtime=seconds2texttime(
liteyuki["runtime"],
unit_days=local_dt["days"],
unit_hours=local_dt["hours"],
unit_minutes=local_dt["minutes"],
unit_seconds=local_dt["seconds"],
),
for_bots="\n".join(
[
markdown_status_bot_card_text__.format(
bot_name=s_bot["name"],
bot_icon=s_bot["icon"],
bot_app_name=s_bot["app_name"],
bot_protocol_name=s_bot["protocol_name"],
bot_groups=s_bot["groups"],
bot_friends=s_bot["friends"],
bot_message_sent=s_bot["message_sent"],
bot_message_received=s_bot["message_received"],
)
for s_bot in bot["bots"]
]
),
local_cpu=local_dt["cpu"],
hardware_cpu_percent=hardware["cpu"]["percent"],
hardware_cpu_name=hardware["cpu"]["name"],
hardware_cpu_cores=hardware["cpu"]["cores"],
local_cores=local_dt["cores"],
hardware_cpu_threads=hardware["cpu"]["threads"],
local_threads=local_dt["threads"],
hardware_cpu_freq=hardware["cpu"]["freq"] / 1000,
local_units_GHz=local_dt["units"]["GHz"],
local_memory=local_dt["memory"],
hardware_memory_percent=hardware["memory"]["percent"],
local_process=local_dt["process"],
hardware_memory_processmem=convert_size(
hardware["memory"]["usedProcess"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
local_used=local_dt["used"],
hardware_memory_usedmem=convert_size(
hardware["memory"]["used"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
local_free=local_dt["free"],
hardware_memory_freemem=convert_size(
hardware["memory"]["free"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
local_total=local_dt["total"],
hardware_memory_totalmem=convert_size(
hardware["memory"]["total"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
local_swap=local_dt["swap"],
hardware_swap_percent=hardware["swap"]["percent"],
hardware_swap_usedswap=convert_size(
hardware["swap"]["used"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
hardware_swap_freeswap=convert_size(
hardware["swap"]["free"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
hardware_swap_totalswap=convert_size(
hardware["swap"]["total"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
local_disk=local_dt["disk"],
for_disk="\n".join(
[
markdown_status_disk_card_text__.format(
hardware_disk_name=s_disk["name"],
hardware_disk_percent=s_disk["percent"],
hardware_disk_useddisk=convert_size(
s_disk["used"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
hardware_disk_freedisk=convert_size(
s_disk["free"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
hardware_disk_totaldisk=convert_size(
s_disk["total"],
precision=2,
is_unit_added=True,
suffix=bytes_suffix,
bin_units=bin_units,
),
)
for s_disk in hardware["disk"]
]
),
motto_text=motto["text"],
motto_source=motto["source"],
acknowledgement=get_config("status_acknowledgement"),
)
return await md_to_pic(fnl_text, width=540, device_scale_factor=4)
# def gogop(x):
# from rich.console import Console
# Console().print(x)
# return x
# 获取状态卡片 # 获取状态卡片
# bot_id 参数已经是bot参数的一部分了不需要保留但为了“兼容性”…… # bot_id 参数已经是bot参数的一部分了不需要保留但为了“兼容性”……
async def generate_status_card( async def generate_status_card(
@ -95,8 +297,9 @@ async def generate_status_card(
liteyuki: dict, liteyuki: dict,
lang="zh-CN", lang="zh-CN",
motto={"text": "风朗气清", "source": "成语一则"}, motto={"text": "风朗气清", "source": "成语一则"},
bot_id="0", bot_id="0", # 兼容性
) -> bytes: ) -> bytes:
# print(get_config("status_acknowledgement"))
return await template2image( return await template2image(
get_path("templates/status.html", abs_path=True), get_path("templates/status.html", abs_path=True),
{ {
@ -104,15 +307,17 @@ async def generate_status_card(
"bot": bot, "bot": bot,
"hardware": hardware, "hardware": hardware,
"liteyuki": liteyuki, "liteyuki": liteyuki,
"localization": get_local_data(lang), "localization": await get_local_data(lang),
"motto": motto, "motto": motto,
"acknowledgement": get_config("status_acknowledgement"),
} }
}, },
) )
def get_local_data(lang_code) -> dict: async def get_local_data(lang_code) -> dict:
lang = Language(lang_code) lang = Language(lang_code)
bin_forcase = lang.get("status.unit.binary_middile")
return { return {
"friends": lang.get("status.friends"), "friends": lang.get("status.friends"),
"groups": lang.get("status.groups"), "groups": lang.get("status.groups"),
@ -138,6 +343,18 @@ def get_local_data(lang_code) -> dict:
"process": lang.get("status.process"), "process": lang.get("status.process"),
"resources": lang.get("status.resources"), "resources": lang.get("status.resources"),
"description": lang.get("status.description"), "description": lang.get("status.description"),
"units": {
"GHz": lang.get("status.unit.GHz"),
"Byte": lang.get("status.unit.Byte"),
"Bin_Units": [
(
((bin_forcase + i) if "zh" in lang_code else (i + bin_forcase))
if i.strip()
else ""
)
for i in lang.get("status.unit.Bit_Units").split(";")
],
},
} }
@ -161,7 +378,7 @@ async def get_bots_data(self_id: str = "0") -> dict:
groups = str(await satori_utils.count_groups(bot)) groups = str(await satori_utils.count_groups(bot))
friends = str(await satori_utils.count_friends(bot)) friends = str(await satori_utils.count_friends(bot))
status = {} status = {}
version_info = await bot.get_version_info() version_info = await bot.get_version_info() # type: ignore
except Exception: except Exception:
pass pass
else: else:
@ -210,7 +427,8 @@ async def get_bots_data(self_id: str = "0") -> dict:
return result return result
async def get_hardware_data() -> dict: async def get_hardware_data(lang_code) -> dict:
lang = Language(lang_code)
mem = psutil.virtual_memory() mem = psutil.virtual_memory()
all_processes = psutil.Process().children(recursive=True) all_processes = psutil.Process().children(recursive=True)
all_processes.append(psutil.Process()) all_processes.append(psutil.Process())
@ -227,30 +445,27 @@ async def get_hardware_data() -> dict:
except Exception: except Exception:
pass pass
swap = psutil.swap_memory() swap = psutil.swap_memory()
cpu_brand_raw = cpuinfo.get_cpu_info().get("brand_raw", "未知处理器") cpu_infos = cpuinfo.get_cpu_info()
if "amd" in cpu_brand_raw.lower(): cpu_brand_raw = cpu_infos.get(
brand = "AMD" "hardware_raw",
elif "intel" in cpu_brand_raw.lower(): cpu_infos.get("brand_raw", "未知处理器"), # 此处之汉文不会被直接使用
brand = "英特尔" ).lower()
elif "apple" in cpu_brand_raw.lower(): if cpu_brand_selected := for_in(
brand = "苹果" ("amd", "intel", "apple", "qualcomm", "mediatek", "samsung", "nvidia"),
elif "qualcomm" in cpu_brand_raw.lower(): cpu_brand_raw,
brand = "高通" ):
elif "mediatek" in cpu_brand_raw.lower(): brand = lang.get("status.cpubrand." + cpu_brand_selected[0])
brand = "联发科"
elif "samsung" in cpu_brand_raw.lower():
brand = "三星"
elif "nvidia" in cpu_brand_raw.lower():
brand = "英伟达"
else: else:
brand = "未知处理器" brand = lang.get("status.cpubrand.unknown")
result = { result = {
"cpu": { "cpu": {
"percent": psutil.cpu_percent(), "percent": psutil.cpu_percent(),
"name": f"{brand} {cpuinfo.get_cpu_info().get('arch', '未知架构')}", "name": "{} {}".format(
brand, cpu_infos.get("arch_string_raw", lang.get("status.arch.unknown"))
),
"cores": psutil.cpu_count(logical=False), "cores": psutil.cpu_count(logical=False),
"threads": psutil.cpu_count(logical=True), "threads": psutil.cpu_count(logical=True),
"freq": psutil.cpu_freq().current, # MHz "freq": psutil.cpu_freq().current, # 单位 MHz
}, },
"memory": { "memory": {
"percent": mem.percent, "percent": mem.percent,
@ -268,25 +483,39 @@ async def get_hardware_data() -> dict:
"disk": [], "disk": [],
} }
other_disk = {
"name": lang.get("status.disk.other"),
"percent": 0,
"total": 0,
"used": 0,
"free": 0,
}
for disk in psutil.disk_partitions(all=True): for disk in psutil.disk_partitions(all=True):
try: try:
disk_usage = psutil.disk_usage(disk.mountpoint) disk_usage = psutil.disk_usage(disk.mountpoint)
if disk_usage.total == 0 or disk.mountpoint.startswith( if disk_usage.total == 0 or disk.mountpoint.startswith(
("/var", "/boot", "/run", "/proc", "/sys", "/dev", "/tmp", "/snap") ("/var", "/boot", "/run", "/proc", "/sys", "/dev", "/tmp", "/snap")
): ):
continue # 虚拟磁盘 other_disk["percent"] = (other_disk["percent"] + disk_usage.percent) / 2
result["disk"].append( other_disk["total"] += disk_usage.total
{ other_disk["used"] += disk_usage.used
"name": disk.mountpoint, other_disk["free"] += disk_usage.free
"percent": disk_usage.percent, else:
"total": disk_usage.total, result["disk"].append(
"used": disk_usage.used, {
"free": disk_usage.free, "name": disk.mountpoint,
} "percent": disk_usage.percent,
) "total": disk_usage.total,
"used": disk_usage.used,
"free": disk_usage.free,
}
)
except: except:
pass pass
if other_disk["total"] > 0: # 避免除零错误
result["disk"].append(other_disk)
return result return result

View File

@ -0,0 +1,123 @@
markdown_status_bot_card_text = """
### **{bot_name} &nbsp;|&nbsp; <img src="{bot_icon}" width="40">**
- {bot_app_name} : {bot_protocol_name}
- {local_groups}{bot_groups} | {local_friends}{bot_friends} | {local_message_sent}{bot_message_sent} | {local_message_received}{bot_message_received}
"""
markdown_status_disk_card_text = """ - {hardware_disk_name}
\t{local_used} {hardware_disk_useddisk} {hardware_disk_percent}% | {local_free} {hardware_disk_freedisk} | {local_total} {hardware_disk_totaldisk}"""
markdown_status_card_text = """
<h1 style="text-align: center;"> {local_description} </h1>
<h2> <img src="https://p.qlogo.cn/gh/861684859/861684859/" width="50" alt="bot-icon"> &nbsp; {liteyuki_name} - 睿乐 </h2>
- 灵温 {liteyuki_version} | Nonebot {liteyuki_nonebot}
- {liteyuki_system} {liteyuki_python}
- {local_plugins}{liteyuki_plugins} | {local_resources}{liteyuki_resources} | {local_bots}{liteyuki_bots}
- {local_runtime}{liteyuki_runtime}
{for_bots}
## {local_cpu} : {hardware_cpu_percent}%
- {hardware_cpu_name} | {hardware_cpu_cores}{local_cores} {hardware_cpu_threads}{local_threads} | {hardware_cpu_freq}{local_units_GHz}
## {local_memory} : {hardware_memory_percent}%
- {local_process} {hardware_memory_processmem}
- {local_used} {hardware_memory_usedmem}
- {local_free} {hardware_memory_freemem}
- {local_total} {hardware_memory_totalmem}
## {local_swap} : {hardware_swap_percent}%
- {local_used} {hardware_swap_usedswap}
- {local_free} {hardware_swap_freeswap}
- {local_total} {hardware_swap_totalswap}
## {local_disk}
{for_disk}
-----------------------
### {motto_text}
<div align="right">{motto_source}</div>
#### <div align="center">{acknowledgement}</div>
#### <div align="center">该页样式由 <img src="https://q.qlogo.cn/g?b=qq&nk=3657522512&s=640" width=40>金羿Eilles 设计</div>
"""
def convert_size(
size: int | float,
precision: int = 2,
is_unit_added: bool = True,
suffix: str = " X字节",
bin_units: list[str] = ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"],
):
"""
将字节转换为带单位的大小
:param size: 要转换的字节大小
:param precision: 保留小数位数
:param is_unit_added: 是否添加单位
:param suffix: 单位后缀
:param bin_units: 单位列表
:return: 转换后的大小字符串
"""
is_negative = size < 0
size = abs(size)
# let units = ["", "千", "兆", "吉", "太", "拍", "艾", "泽"];
unit = ""
for sg_unit in bin_units:
if size < 1024:
unit = sg_unit
break
size /= 1024
if is_negative:
size = -size
if is_unit_added:
return ("{" + ":.{}f".format(precision) + "}").format(size) + suffix.replace(
"X", unit
)
else:
return size
def seconds2texttime(
seconds: int,
unit_days: str = "",
unit_hours: str = "",
unit_minutes: str = "",
unit_seconds: str = "",
):
"""
将秒数转换为时间文本
:param seconds: 要转换的秒数
:param unit_days: 天的单位
:param unit_hours: 小时的单位
:param unit_minutes: 分钟的单位
:param unit_seconds: 秒的单位
:return: 转换后的时间文本
"""
return "{dt}{ld} {ht}{lh} {mt}{lm} {st}{ls}".format(
dt=seconds // 86400,
ld=unit_days,
ht=(seconds % 86400) // 3600,
lh=unit_hours,
mt=(seconds % 3600) // 60,
lm=unit_minutes,
st=seconds % 60,
ls=unit_seconds,
)

View File

@ -2,6 +2,7 @@ import random
import aiohttp import aiohttp
import zhDateTime import zhDateTime
from nonebot import require
from src.utils import event as event_utils from src.utils import event as event_utils
from src.utils.base.language import get_user_lang, get_default_lang_code, Language from src.utils.base.language import get_user_lang, get_default_lang_code, Language
@ -35,6 +36,12 @@ status_alc = on_alconna(
alias={"refr", "r", "刷新"}, alias={"refr", "r", "刷新"},
action=store_true, action=store_true,
), ),
Option(
"-t|-md|--markdown",
default=False,
# alias={"refr", "r", "刷新"},
action=store_true,
),
Subcommand( Subcommand(
"memory", "memory",
alias={"mem", "m", "内存"}, alias={"mem", "m", "内存"},
@ -72,7 +79,7 @@ yanlun_path = "https://nd.liteyuki.icu/api/v3/share/content/Xpue?path=null"
# 每天4点更新 # 每天4点更新
@scheduler.scheduled_job("cron", hour=4) @scheduler.scheduled_job("cron", hour=4)
async def every_day_update(): async def every_day_update():
ulang = Language(get_default_lang_code(), "zh-WY") ulang = Language(get_default_lang_code(), "zh-CN")
nonebot.logger.success( nonebot.logger.success(
ulang.get("yanlun.refresh.success", COUNT=await update_yanlun()) ulang.get("yanlun.refresh.success", COUNT=await update_yanlun())
) )
@ -88,7 +95,7 @@ async def update_yanlun():
resp = await client.get(yanlun_path, timeout=15) resp = await client.get(yanlun_path, timeout=15)
yanlun_texts = (await resp.text()).strip("\n").split("\n") yanlun_texts = (await resp.text()).strip("\n").split("\n")
except (ConnectionError, aiohttp.ClientError, aiohttp.WebSocketError) as err: except (ConnectionError, aiohttp.ClientError, aiohttp.WebSocketError) as err:
nonebot.logger.warning("读取言·论信息发生 客户端或通道 错误:\n{}".format(err)) nonebot.logger.warning("读取言·论信息发生 连接 错误:\n{}".format(err))
yanlun_texts = ["以梦想为驱使 创造属于自己的未来"] yanlun_texts = ["以梦想为驱使 创造属于自己的未来"]
# noinspection PyBroadException # noinspection PyBroadException
except BaseException as err: except BaseException as err:
@ -117,14 +124,22 @@ async def _():
yanlun_seqs = yanlun_texts = ["金羿ELS 生日快乐~", "Happy Birthday, Eilles!"] yanlun_seqs = yanlun_texts = ["金羿ELS 生日快乐~", "Happy Birthday, Eilles!"]
elif solar_date == (8, 6): elif solar_date == (8, 6):
yanlun_seqs = yanlun_texts = [ yanlun_seqs = yanlun_texts = [
"诸葛亮与八卦阵 生日快乐~", "玉衡 生日快乐~",
"Happy Birthday, bgArray~!", "Happy Birthday, Alioth~!",
] ]
elif solar_date == (8, 16): elif solar_date == (8, 16):
yanlun_seqs = yanlun_texts = [ yanlun_seqs = yanlun_texts = [
"鱼旧梦 生日快乐~", "鱼旧梦 生日快乐~",
"Happy Birthday, ElapsingDreams~!", "Happy Birthday, ElapsingDreams~!",
] ]
elif lunar_date == (1, 1):
yanlun_seqs = yanlun_texts = [
"新春快乐~",
"千门万户曈曈日,总把新桃换旧符\t——王安石《元日》",
"爆竹声中一岁除,春风送暖入屠苏\t——王安石《元日》",
"半盏屠苏犹未举,灯前小草写桃符\t—— 陆游《除夜雪》",
"愿得长如此,年年物候新\t—— 卢照邻《元日述怀》",
]
else: else:
await update_yanlun() await update_yanlun()
@ -163,13 +178,25 @@ async def _(
) )
): ):
status_card_cache[ulang.lang_code] = ( status_card_cache[ulang.lang_code] = (
await generate_status_card( (
bot=await get_bots_data(), await generate_status_card_markdown(
hardware=await get_hardware_data(), bot=await get_bots_data(),
liteyuki=await get_liteyuki_data(), hardware=await get_hardware_data(ulang.lang_code),
lang=ulang.lang_code, liteyuki=await get_liteyuki_data(),
motto=dict(zip(["text", "source"], random_yanlun())), lang=ulang.lang_code,
bot_id=bot.self_id, motto=dict(zip(["text", "source"], random_yanlun())),
)
if result.options["markdown"].value
else (
await generate_status_card(
bot=await get_bots_data(),
hardware=await get_hardware_data(ulang.lang_code),
liteyuki=await get_liteyuki_data(),
lang=ulang.lang_code,
motto=dict(zip(["text", "source"], random_yanlun())),
bot_id=bot.self_id,
)
)
), ),
time.time(), time.time(),
) )

View File

@ -53,6 +53,7 @@ from .msctexec import (
add_memory_to_temporary, add_memory_to_temporary,
read_memory_from_temporary, read_memory_from_temporary,
get_stored_path, get_stored_path,
get_user_lang,
) )
from .utils import hanzi_timeid from .utils import hanzi_timeid
@ -116,6 +117,7 @@ async def _(
nonebot.logger.info(result.options) nonebot.logger.info(result.options)
usr_id = event.get_user_id() usr_id = event.get_user_id()
ulang = get_user_lang(usr_id)
superuser_permission = await SUPERUSER(bot, event) superuser_permission = await SUPERUSER(bot, event)
@ -124,9 +126,10 @@ async def _(
): ):
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text( UniMessage.text(
"转换点数不足当前剩余⌊p⌋≈{:.2f}|{}".format( ulang.get(
qres[1], "convet.not_enough_point",
configdict["maxPersonConvert"]["music"], NOW=qres[1],
TOTAL=configdict["maxPersonConvert"]["music"],
) )
), ),
at_sender=True, at_sender=True,
@ -168,12 +171,18 @@ async def _(
) )
): ):
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text("服务器内未存入你的任何文件请先上传midi文件吧") UniMessage.text(ulang.get("convert.no_file", TYPE="midi"))
) )
if _args["mode"] not in [0, 1, 2, 3, 4]: if _args["mode"] not in [0, 1, 2, 3, 4]:
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text("模式 {} 不存在,请详阅文档。".format(_args["mode"])) UniMessage.text(
ulang.get(
"convert.something_not_exist",
WHAT="模式",
NAME=_args["mode"],
)
)
) )
if _args["get-value-method"] not in [ if _args["get-value-method"] not in [
@ -182,7 +191,11 @@ async def _(
]: ]:
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text( UniMessage.text(
"取值法 {} 不存在,请详阅文档。".format(_args["get-value-method"]) ulang.get(
"convert.something_not_exist",
WHAT="取值法",
NAME=_args["get-value-method"],
)
) )
) )
@ -212,7 +225,11 @@ async def _(
pitched_notechart.update(json.load(_ppnt.open("r"))) pitched_notechart.update(json.load(_ppnt.open("r")))
else: else:
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text("乐器对照表 {} 不存在".format(_args["pitched-note-table"])) ulang.get(
"convert.something_not_exist",
WHAT="乐音乐器对照表",
NAME=_args["pitched-note-table"],
)
) )
return return
@ -240,7 +257,11 @@ async def _(
else: else:
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text( UniMessage.text(
"乐器对照表 {} 不存在".format(_args["percussion-note-table"]) ulang.get(
"convert.something_not_exist",
WHAT="打击乐器对照表",
NAME=_args["percussion-note-table"],
)
) )
) )
return return
@ -257,7 +278,11 @@ async def _(
else: else:
await mspv_sync.finish( await mspv_sync.finish(
UniMessage.text( UniMessage.text(
"音量处理曲线 {} 不存在".format(_args["volume-processing-function"]) ulang.get(
"convert.something_not_exist",
WHAT="音量处理曲线",
NAME=_args["volume-processing-function"],
)
) )
) )
return return
@ -274,10 +299,10 @@ async def _(
random.random() % 1.6 + 1.3, random.random() % 1.6 + 1.3,
) )
if not res: if not res:
buffer.write("中途退出,转换点不足:{}\n".format(pnt)) buffer.write(ulang.get("convert.break.not_enough_point", NOW=pnt))
return res return res
await mspv_sync.send(UniMessage.text("转换开始……")) await mspv_sync.send(UniMessage.text(ulang.get("convert.start")))
try: try:

View File

@ -12,7 +12,7 @@ writefile.write_success=文件{NAME}已写入{SIZE}字节
convet.not_enough_point=转换点数不足当前剩余⌊p⌋≈{NOW:.2f}|{TOTAL} convet.not_enough_point=转换点数不足当前剩余⌊p⌋≈{NOW:.2f}|{TOTAL}
convert.break.not_enough_point=中途退出,转换点不足:{NOW} convert.break.not_enough_point=中途退出,转换点不足:{NOW}
convert.no_file=服务器内未存入你的任何文件,请先上传{TYPE}文件吧 convert.no_file=服务器内未存入你的任何文件,请先上传{TYPE}文件吧
convert.something_not_exist={WHAT} {NAME} 不存在 convert.something_not_exist={WHAT} {NAME} 不存在,请详阅文档。
convert.start=转换开始…… convert.start=转换开始……
cmd2struct.axis_wrong=生成结构的生成方向格式错误输入数据应符合“轴正负”如x+、z-)的格式。 cmd2struct.axis_wrong=生成结构的生成方向格式错误输入数据应符合“轴正负”如x+、z-)的格式。

View File

@ -13,6 +13,6 @@ convet.not_enough_point=点阙,余{NOW:.2f},满{TOTAL}
convert.break.not_enough_point=点阙而不可继,现{NOW} convert.break.not_enough_point=点阙而不可继,现{NOW}
convert.no_file=无案机内,先传之{TYPE} convert.no_file=无案机内,先传之{TYPE}
convert.table_not_exist={WHAT}曰 {NAME} 者虚 convert.table_not_exist={WHAT}曰 {NAME} 者虚
convert.start=始…… convert.start=始变之……
cmd2struct.axis_wrong=产型误指应合此法曰“轴正负”类x+、z-。 cmd2struct.axis_wrong=产型误指应合此法曰“轴正负”类x+、z-。

View File

@ -30,8 +30,8 @@ liteyuki.list_resources=Resource Pack List
liteyuki.reload_resources_success=Resource reload successful, {NUM} resource packs in total liteyuki.reload_resources_success=Resource reload successful, {NUM} resource packs in total
liteyuki.loaded_resources={NUM} resource packs loaded, sorted by priority liteyuki.loaded_resources={NUM} resource packs loaded, sorted by priority
liteyuki.unloaded_resources=Unloaded resource packs liteyuki.unloaded_resources=Unloaded resource packs
liteyuki.load_resource_success=Resource pack {NAME} loaded successfully liteyuki.load_resource_success=Resource pack {NAME} successfully loaded
liteyuki.unload_resource_success=Resource pack {NAME} unloaded successfully liteyuki.unload_resource_success=Resource pack {NAME} successfully unloaded
liteyuki.load_resource_failed=Failed to load resource pack {NAME} liteyuki.load_resource_failed=Failed to load resource pack {NAME}
liteyuki.unload_resource_failed=Failed to unload resource pack {NAME} liteyuki.unload_resource_failed=Failed to unload resource pack {NAME}
liteyuki.resource_not_found=Resource pack {NAME} does not exist or is not operable liteyuki.resource_not_found=Resource pack {NAME} does not exist or is not operable
@ -39,12 +39,12 @@ liteyuki.resource_already_loaded=Resource pack {NAME} already loaded, do not rep
liteyuki.resource_already_unloaded=Resource pack {NAME} already unloaded, do not repeat operation liteyuki.resource_already_unloaded=Resource pack {NAME} already unloaded, do not repeat operation
liteyuki.need_reload=Please {BTN} reload to apply these updates liteyuki.need_reload=Please {BTN} reload to apply these updates
liteyuki.dont_repeat=Do not repeat operation liteyuki.dont_repeat=Do not repeat operation
liteyuki.change_priority_success=Resource pack {NAME} priority changed successfully liteyuki.change_priority_success=Resource pack {NAME} priority successfully changed
liteyuki.change_priority_failed=Failed to change priority of resource pack {NAME} liteyuki.change_priority_failed=Failed to change priority of resource pack {NAME}
liteyuki.group_already=Group {GROUP} is already {STATUS}, no need to repeat operation liteyuki.group_already=Group {GROUP} is already {STATUS}, no need to repeat operation
liteyuki.group_success=Group {GROUP} {STATUS} successful liteyuki.group_success=Group {GROUP} {STATUS} successful
liteyuki.permission_denied=Permission denied liteyuki.permission_denied=Permission denied
liteyuki.config_remove_success=Configuration {KEY} removed successfully liteyuki.config_remove_success=Configuration {KEY} successfully removed
main.current_language=Current configuration language is: {LANG} main.current_language=Current configuration language is: {LANG}
main.enable_webdash=Web monitoring panel enabled: {URL} main.enable_webdash=Web monitoring panel enabled: {URL}
@ -75,14 +75,14 @@ npm.uninstall=Uninstall
npm.installing=Installing {NAME} npm.installing=Installing {NAME}
npm.cannot_uninstall=Cannot Uninstall npm.cannot_uninstall=Cannot Uninstall
npm.no_description=No Description npm.no_description=No Description
npm.store_update_success=Plugin store data updated successfully npm.store_update_success=Plugin store data successfully updated
npm.store_update_failed=Plugin store data update failed npm.store_update_failed=Plugin store data update failed
npm.search_result=Search Result npm.search_result=Search Result
npm.search_no_result=No search result npm.search_no_result=No search result
npm.too_many_results=Too many items, {HIDE_NUM} items hidden, please limit the keyword search npm.too_many_results=Too many items, {HIDE_NUM} items hidden, please limit the keyword search
npm.install_success={NAME} installed successfully npm.install_success={NAME} has been successfully installed
npm.install_failed={NAME} installation failed, please check the log for detailed information. If you cannot resolve it, visit {HOMEPAGE} for help npm.install_failed={NAME} installation failed, please check the log for detailed information. If you cannot resolve it, visit {HOMEPAGE} for help
npm.uninstall_success={NAME} uninstalled successfully, effective next restart npm.uninstall_success={NAME} successfully uninstalled, effective after next restart
npm.uninstall_failed={NAME} uninstallation failed npm.uninstall_failed={NAME} uninstallation failed
npm.load_failed={NAME} loading failed, please check the console for detailed information, check if dependencies or configurations are correct, if cannot resolve, visit {HOMEPAGE} for help npm.load_failed={NAME} loading failed, please check the console for detailed information, check if dependencies or configurations are correct, if cannot resolve, visit {HOMEPAGE} for help
npm.plugin_not_found={NAME} not found in the store, please try updating the store information or checking the spelling npm.plugin_not_found={NAME} not found in the store, please try updating the store information or checking the spelling
@ -122,7 +122,7 @@ user.profile.location.desc=Set user location information
user.profile.nickname=Nickname user.profile.nickname=Nickname
user.profile.nickname.desc=Set how the bot calls the user user.profile.nickname.desc=Set how the bot calls the user
user.profile.input_value=Please enter the value of {ATTR} user.profile.input_value=Please enter the value of {ATTR}
user.profile.set_success={ATTR} set to {VALUE} successfully user.profile.set_success={ATTR} has been successfully set to {VALUE}
user.profile.set_failed=Failed to set {ATTR}, please check the input legality user.profile.set_failed=Failed to set {ATTR}, please check the input legality
rpm.move_up=Move Up rpm.move_up=Move Up
@ -157,3 +157,31 @@ status.cores=Core(s)
status.threads=Thread(s) status.threads=Thread(s)
status.process=Processe(s) status.process=Processe(s)
status.description=Liteyuki Dashboard status.description=Liteyuki Dashboard
status.cpubrand.amd=AMD
status.cpubrand.intel=Intel
status.cpubrand.apple=Apple
status.cpubrand.qualcomm=Qualcomm
status.cpubrand.mediatek=MediaTeK
status.cpubrand.samsung=SamSung
status.cpubrand.nvidia=NVidia
status.cpubrand.huawei=Huawei
status.cpubrand.unknown=Unknown
status.arch.unknown=??
status.disk.other=Virtual and Other Disk
status.unit.GHz=GHz
status.unit.Byte=B
status.unit.binary_middile=i
status.unit.Bit_Units= ;K;M;G;T;P;E;Z;Y;R;Q
yanlun.refresh.success=Yanlun cuccessfully updated to {COUNT} pieces now.
yanlun.refresh.failed=Error {ERR} occured in updating Yanlun with code {ERRCODE}
yanlun.errtype.net=Connection Error
yanlun.errtype.unknown=Unknown Error
yanlun.count.head=FromtttCount(Percentage)
yanlun.count.tail=...({NUM} in Total)
yanlun.length.toolong=Too many Yanlun to display
yanlun.length.tooshort=Too few Yanlun to display
yanlun.length.float=The number of Yanlun must be an integer, not a float

View File

@ -155,15 +155,33 @@ status.minutes=分
status.seconds=秒 status.seconds=秒
status.cores=核心 status.cores=核心
status.threads=线程 status.threads=线程
status.process=进程 status.process=进程占用
status.description=轻雪机器人状态面板 status.description=轻雪机器人状态面板
status.cpubrand.amd=超微
status.cpubrand.intel=英特尔
status.cpubrand.apple=苹果
status.cpubrand.qualcomm=高通
status.cpubrand.mediatek=联发科
status.cpubrand.samsung=三星
status.cpubrand.nvidia=英伟达
status.cpubrand.huawei=华为
status.cpubrand.unknown=未知处理器
status.arch.unknown=未知架构
status.disk.other=虚拟磁盘及其他
status.unit.GHz=吉赫兹
status.unit.Byte=字节
status.unit.binary_middile=二幂
status.unit.Bit_Units= ;千;兆;吉;太;拍;艾;泽;尧;容;昆
yanlun.refresh.success=言·论 更新成功,共 {COUNT} 条 yanlun.refresh.success=言·论 更新成功,共 {COUNT} 条
yanlun.refresh.failed=更新 言·论 信息发生 {ERR} 错误:{ERRCODE} yanlun.refresh.failed=更新 言·论 信息发生 {ERR} 错误:{ERRCODE}
yanlun.errtype.net=互联网连接 yanlun.errtype.net=互联网连接
yanlun.errtype.unknown=未知 yanlun.errtype.unknown=未知
yanlun.count.head=出处ttt数量(占比) yanlun.count.head=出处ttt数量(占比)
yanlun.count.tail=...(共 {NUM} 条) yanlun.count.tail=...(共 {NUM} 条)
yanlun.length.toolong=言·论过长 yanlun.length.toolong=言·论过
yanlun.length.tooshort=言·论过短 yanlun.length.tooshort=言·论过
yanlun.length.float=言·论不可是非整数长度 yanlun.length.float=言·论数量不可为非整数

View File

@ -155,4 +155,33 @@ status.minutes=分鐘
status.seconds=秒 status.seconds=秒
status.cores=核心 status.cores=核心
status.threads=線程 status.threads=線程
status.process=進程 status.process=進程所占用
status.description=轻雪 Bot 狀態面板
status.cpubrand.amd=超威
status.cpubrand.intel=英特爾
status.cpubrand.apple=蘋果
status.cpubrand.qualcomm=高通
status.cpubrand.mediatek=聯發科
status.cpubrand.samsung=三星
status.cpubrand.nvidia=英偉達
status.cpubrand.huawei=華為
status.cpubrand.unknown=未知處理器
status.arch.unknown=未知架構
status.disk.other=虛擬磁碟和其他
status.unit.GHz=吉赫茲
status.unit.Byte=位元組
status.unit.binary_middile=二進
status.unit.Bit_Units= ;千;百萬;吉;兆;拍;艾;皆;佑;羅;昆
yanlun.refresh.success=言·論 成功更新得 {COUNT} 條
yanlun.refresh.failed=言·論因 {ERR} 其 {ERRCODE} 而無法更新
yanlun.errtype.net=網際網路連結
yanlun.errtype.unknown=不可知
yanlun.count.head=出處ttt數目(比例)
yanlun.count.tail=...(縂 {NUM} 條)
yanlun.length.toolong=言·論數目不可過多
yanlun.length.tooshort=言·論數目不可為無或負
yanlun.length.float=言·論數目不可謂為小數

View File

@ -148,14 +148,14 @@ status.usage=计用
status.total=合 status.total=合
status.used=占 status.used=占
status.free=余 status.free=余
status.runtime=所启时分 status.runtime=运期
status.days=日 status.days=日
status.hours=小时 status.hours=小时
status.minutes=分 status.minutes=分
status.seconds=秒 status.seconds=秒
status.cores= status.cores=核
status.threads=线 status.threads=线
status.process=行轨 status.process=进程占
status.description=轻雪灵机台 status.description=轻雪灵机台
yanlun.refresh.success=言·论 方新,合{COUNT}条 yanlun.refresh.success=言·论 方新,合{COUNT}条

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 KiB

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

@ -1,9 +1,12 @@
const data = JSON.parse(document.getElementById("data").innerText); const data = JSON.parse(document.getElementById("data").innerText);
const bot_data = data["bot"]; // 机器人数据 const bot_data = data["bot"]; // 机器人数据
const hardwareData = data["hardware"]; // 硬件数据 const hardware_data = data["hardware"]; // 硬件数据
const liteyukiData = data["liteyuki"]; // LiteYuki数据 const liteyuki_data = data["liteyuki"]; // LiteYuki数据
const localData = data["localization"]; // 本地化语言数据 const local_data = data["localization"]; // 本地化语言数据
const motto_ = data["motto"]; // 言论数据 const motto_ = data["motto"]; // 言论数据
const acknowledgement = data["acknowledgement"]; // 鸣谢内容数据
const o_units = local_data["units"]; // 单位的翻译
const bin_units = o_units["Bin_Units"]; // 字节单位(千、兆…)
/** /**
* 创建CPU/内存/交换饼图 * 创建CPU/内存/交换饼图
@ -64,15 +67,20 @@ function createPieChartOption(title, data) {
}; };
} }
function convertSize(size, precision = 2, addUnit = true, suffix = " X字节") { function convertSize(
size,
precision = 2,
addUnit = true,
suffix = ` X${o_units["Byte"]}`
) {
let isNegative = size < 0; let isNegative = size < 0;
size = Math.abs(size); size = Math.abs(size);
let units = ["", "千", "兆", "吉", "太", "拍", "艾", "泽"]; // let units = ["", "千", "兆", "吉", "太", "拍", "艾", "泽"];
let unit = ""; let unit = "";
for (let i = 0; i < units.length; i++) { for (let i = 0; i < bin_units.length; i++) {
if (size < 1024) { if (size < 1024) {
unit = units[i]; unit = bin_units[i];
break; break;
} }
size /= 1024; size /= 1024;
@ -125,7 +133,7 @@ function secondsToTextTime(seconds) {
let hours = Math.floor((seconds % 86400) / 3600); let hours = Math.floor((seconds % 86400) / 3600);
let minutes = Math.floor((seconds % 3600) / 60); let minutes = Math.floor((seconds % 3600) / 60);
let seconds_ = Math.floor(seconds % 60); let seconds_ = Math.floor(seconds % 60);
return `${days}${localData["days"]} ${hours}${localData["hours"]} ${minutes}${localData["minutes"]} ${seconds_}${localData["seconds"]}`; return `${days}${local_data["days"]} ${hours}${local_data["hours"]} ${minutes}${local_data["minutes"]} ${seconds_}${local_data["seconds"]}`;
} }
// 主函数 // 主函数
@ -140,15 +148,17 @@ function main() {
// 设置机器人信息 // 设置机器人信息
botInfoDiv.className = "info-box bot-info"; botInfoDiv.className = "info-box bot-info";
botInfoDiv.querySelector(".bot-icon-img").setAttribute("src", bot["icon"]); botInfoDiv
.querySelector(".bot-icon-img")
.setAttribute("src", bot["icon"]);
botInfoDiv.querySelector(".bot-name").innerText = bot["name"]; botInfoDiv.querySelector(".bot-name").innerText = bot["name"];
let tagArray = [ let tagArray = [
bot["protocol_name"], bot["protocol_name"],
`${bot["app_name"]}`, `${bot["app_name"]}`,
`${localData["groups"]}${bot["groups"]}`, `${local_data["groups"]}${bot["groups"]}`,
`${localData["friends"]}${bot["friends"]}`, `${local_data["friends"]}${bot["friends"]}`,
`${localData["message_sent"]}${bot["message_sent"]}`, `${local_data["message_sent"]}${bot["message_sent"]}`,
`${localData["message_received"]}${bot["message_received"]}`, `${local_data["message_received"]}${bot["message_received"]}`,
]; ];
// 添加一些标签 // 添加一些标签
tagArray.forEach((tag, index) => { tagArray.forEach((tag, index) => {
@ -156,7 +166,10 @@ function main() {
tagSpan.className = "bot-tag"; tagSpan.className = "bot-tag";
tagSpan.innerText = tag; tagSpan.innerText = tag;
// 给最后一个标签不添加后缀 // 给最后一个标签不添加后缀
tagSpan.setAttribute("suffix", index === 0 || tag[0] == "\n" ? "0" : "1"); tagSpan.setAttribute(
"suffix",
index === 0 || tag[0] == "\n" ? "0" : "1"
);
botInfoDiv.querySelector(".bot-tags").appendChild(tagSpan); botInfoDiv.querySelector(".bot-tags").appendChild(tagSpan);
}); });
document.body.insertBefore( document.body.insertBefore(
@ -176,24 +189,27 @@ function main() {
.setAttribute("src", "./img/litetrimo.png"); .setAttribute("src", "./img/litetrimo.png");
liteyukiInfoDiv.querySelector( liteyukiInfoDiv.querySelector(
".bot-name" ".bot-name"
).innerText = `${liteyukiData["name"]} - 睿乐`; ).innerText = `${liteyuki_data["name"]} - 睿乐`;
let tagArray = [ let tagArray = [
`灵温 ${liteyukiData["version"]}`, `灵温 ${liteyuki_data["version"]}`,
`Nonebot ${liteyukiData["nonebot"]}`, `Nonebot ${liteyuki_data["nonebot"]}`,
`${liteyukiData["python"]}`, `${liteyuki_data["python"]}`,
liteyukiData["system"], liteyuki_data["system"],
`${localData["plugins"]}${liteyukiData["plugins"]}`, `${local_data["plugins"]}${liteyuki_data["plugins"]}`,
`${localData["resources"]}${liteyukiData["resources"]}`, `${local_data["resources"]}${liteyuki_data["resources"]}`,
`${localData["bots"]}${liteyukiData["bots"]}`, `${local_data["bots"]}${liteyuki_data["bots"]}`,
`${localData["runtime"]} ${secondsToTextTime(liteyukiData["runtime"])}`, `${local_data["runtime"]} ${secondsToTextTime(liteyuki_data["runtime"])}`,
]; ];
tagArray.forEach((tag, index) => { tagArray.forEach((tag, index) => {
let tagSpan = document.createElement("span"); let tagSpan = document.createElement("span");
tagSpan.className = "bot-tag"; tagSpan.className = "bot-tag";
tagSpan.innerText = tag; tagSpan.innerText = tag;
// 给最后一个标签不添加后缀 // 给最后一个标签不添加后缀
tagSpan.setAttribute("suffix", index === 0 || tag[0] == "\n" ? "0" : "1"); tagSpan.setAttribute(
"suffix",
index === 0 || tag[0] == "\n" ? "0" : "1"
);
liteyukiInfoDiv.querySelector(".bot-tags").appendChild(tagSpan); liteyukiInfoDiv.querySelector(".bot-tags").appendChild(tagSpan);
}); });
document.body.insertBefore( document.body.insertBefore(
@ -202,27 +218,27 @@ function main() {
); // 插入对象 ); // 插入对象
// 添加硬件信息 // 添加硬件信息
const cpuData = hardwareData["cpu"]; const cpuData = hardware_data["cpu"];
const memData = hardwareData["memory"]; const memData = hardware_data["memory"];
const swapData = hardwareData["swap"]; const swapData = hardware_data["swap"];
const cpuTagArray = [ const cpuTagArray = [
cpuData["name"], cpuData["name"],
`${cpuData["cores"]}${localData["cores"]} ${cpuData["threads"]}${localData["threads"]}`, `${cpuData["cores"]}${local_data["cores"]} ${cpuData["threads"]}${local_data["threads"]}`,
`${(cpuData["freq"] / 1000).toFixed(2)}吉赫兹`, `${(cpuData["freq"] / 1000).toFixed(2)}${o_units["GHz"]}`,
]; ];
const memTagArray = [ const memTagArray = [
`${localData["process"]} ${convertSize(memData["usedProcess"])}`, `${local_data["process"]} ${convertSize(memData["usedProcess"])}`,
`${localData["used"]} ${convertSize(memData["used"])}`, `${local_data["used"]} ${convertSize(memData["used"])}`,
`${localData["free"]} ${convertSize(memData["free"])}`, `${local_data["free"]} ${convertSize(memData["free"])}`,
`${localData["total"]} ${convertSize(memData["total"])}`, `${local_data["total"]} ${convertSize(memData["total"])}`,
]; ];
const swapTagArray = [ const swapTagArray = [
`${localData["used"]} ${convertSize(swapData["used"])}`, `${local_data["used"]} ${convertSize(swapData["used"])}`,
`${localData["free"]} ${convertSize(swapData["free"])}`, `${local_data["free"]} ${convertSize(swapData["free"])}`,
`${localData["total"]} ${convertSize(swapData["total"])}`, `${local_data["total"]} ${convertSize(swapData["total"])}`,
]; ];
let cpuDeviceInfoDiv = document.importNode( let cpuDeviceInfoDiv = document.importNode(
document.getElementById("device-info").content, document.getElementById("device-info").content,
@ -237,8 +253,12 @@ function main() {
true true
); );
cpuDeviceInfoDiv.querySelector(".device-info").setAttribute("id", "cpu-info"); cpuDeviceInfoDiv
memDeviceInfoDiv.querySelector(".device-info").setAttribute("id", "mem-info"); .querySelector(".device-info")
.setAttribute("id", "cpu-info");
memDeviceInfoDiv
.querySelector(".device-info")
.setAttribute("id", "mem-info");
swapDeviceInfoDiv swapDeviceInfoDiv
.querySelector(".device-info") .querySelector(".device-info")
.setAttribute("id", "swap-info"); .setAttribute("id", "swap-info");
@ -276,7 +296,10 @@ function main() {
tagDiv.className = "device-tag"; tagDiv.className = "device-tag";
tagDiv.innerText = tag; tagDiv.innerText = tag;
// 给最后一个标签不添加后缀 // 给最后一个标签不添加后缀
tagDiv.setAttribute("suffix", index === tagArray.length - 1 ? "0" : "1"); tagDiv.setAttribute(
"suffix",
index === tagArray.length - 1 ? "0" : "1"
);
devices[device].querySelector(".device-tags").appendChild(tagDiv); devices[device].querySelector(".device-tags").appendChild(tagDiv);
}); });
} }
@ -292,7 +315,7 @@ function main() {
cpuChart.setOption( cpuChart.setOption(
createPieChartOption( createPieChartOption(
`${localData["cpu"]}\n${cpuData["percent"].toFixed(1)}%`, `${local_data["cpu"]}\n${cpuData["percent"].toFixed(1)}%`,
[ [
{ name: "used", value: cpuData["percent"] }, { name: "used", value: cpuData["percent"] },
{ name: "free", value: 100 - cpuData["percent"] }, { name: "free", value: 100 - cpuData["percent"] },
@ -302,10 +325,13 @@ function main() {
memChart.setOption( memChart.setOption(
createPieChartOption( createPieChartOption(
`${localData["memory"]}\n${memData["percent"].toFixed(1)}%`, `${local_data["memory"]}\n${memData["percent"].toFixed(1)}%`,
[ [
{ name: "process", value: memData["usedProcess"] }, { name: "process", value: memData["usedProcess"] },
{ name: "used", value: memData["used"] - memData["usedProcess"] }, {
name: "used",
value: memData["used"] - memData["usedProcess"],
},
{ name: "free", value: memData["free"] }, { name: "free", value: memData["free"] },
] ]
) )
@ -313,7 +339,7 @@ function main() {
swapChart.setOption( swapChart.setOption(
createPieChartOption( createPieChartOption(
`${localData["swap"]}\n${swapData["percent"].toFixed(1)}%`, `${local_data["swap"]}\n${swapData["percent"].toFixed(1)}%`,
[ [
{ name: "used", value: swapData["used"] }, { name: "used", value: swapData["used"] },
{ name: "free", value: swapData["free"] }, { name: "free", value: swapData["free"] },
@ -322,24 +348,28 @@ function main() {
); );
// 磁盘信息 // 磁盘信息
const diskData = hardwareData["disk"]; const diskData = hardware_data["disk"];
diskData.forEach((disk) => { diskData.forEach((disk) => {
let diskTitle = `${localData['free']} ${convertSize(disk['free'])} ${localData['total']} ${convertSize(disk['total'])}`; let diskTitle = `${local_data["free"]} ${convertSize(disk["free"])} ${
let diskDiv = createBarChart(diskTitle, disk['percent'], disk['name']); local_data["total"]
} ${convertSize(disk["total"])}`;
let diskDiv = createBarChart(diskTitle, disk["percent"], disk["name"]);
// 最后一个把margin-bottom去掉 // 最后一个把margin-bottom去掉
if (disk === diskData[diskData.length - 1]) { if (disk === diskData[diskData.length - 1]) {
diskDiv.style.marginBottom = "0"; diskDiv.style.marginBottom = "0";
} }
document.getElementById('disk-info').appendChild(diskDiv); document.getElementById("disk-info").appendChild(diskDiv);
}); });
// 随机一言 // 随机一言
let mottoText = motto_["text"]; // let mottoText = ;
let mottoFrom = motto_["source"]; // let mottoFrom = ;
document.getElementById("motto-text").innerText = mottoText; document.getElementById("motto-text").innerText = motto_["text"];
document.getElementById("motto-from").innerText = mottoFrom; document.getElementById("motto-from").innerText = motto_["source"];
// 致谢 // 致谢
document.getElementById("addition-info").innerText = if (acknowledgement.length > 0) {
"感谢 锅炉 云裳工作室 提供服务器支持"; document.getElementById("addition-info").innerText = acknowledgement;
// "感谢 锅炉 云裳工作室 提供服务器支持";
}
} }
main(); main();

View File

@ -0,0 +1,50 @@
<h1 style="text-align: center;"> {local_description} </h1>
<h2> <img src="./img/litetrimo.png" width="50"> &nbsp; {liteyuki_name} - 睿乐 </h2>
- 灵温 {liteyuki_version} | Nonebot {liteyuki_nonebot}
- {liteyuki_system} {liteyuki_python}
- {local_plugins}{liteyuki_plugins} | {local_resources}{liteyuki_resources}
- {local_bots}{liteyuki_bots}
- {local_runtime}{liteyuki_runtime}
### **{bot_name} &nbsp;|&nbsp; <img src="{bot_icon}" width="40">**
- {bot_app_name} : {bot_protocol_name}
- {local_groups}{bot_groups} | {local_friends}{bot_friends} | {local_message_sent}{bot_message_sent} | {local_message_received}{bot_message_received}
## {local_cpu} : {hardware_cpu_percent}%
- {hardware_cpu_name} | {hardware_cpu_cores}{local_cores} {hardware_cpu_threads}{local_threads} | {hardware_cpu_freq}{local_units_GHz}
## {local_memory} : {hardware_memory_percent}%
- {local_process} {hardware_memory_processmem}
- {local_used} {hardware_memory_usedmem}
- {local_free} {hardware_memory_freemem}
- {local_total} {hardware_memory_totalmem}
## {local_swap} : {hardware_swap_percent}%
- {local_used} {hardware_swap_usedswap}
- {local_free} {hardware_swap_freeswap}
- {local_total} {hardware_swap_totalswap}
## {local_disk}
- {hardware_disk_name} - {local_used} {hardware_disk_useddisk} | {hardware_disk_freedisk} | {local_total} {hardware_disk_totaldisk}
-----------------------
<div align="right">END.</div>
### {motto_text}
<div align="right">——{motto_source}</div>
#### <div align="center">{acknowledgement}</div>
#### <div align="center">该页样式由 <img src="https://q.qlogo.cn/g?b=qq&nk=3657522512&s=640" width=40>金羿Eilles 设计</div>

View File

@ -32,6 +32,7 @@ class BasicConfig(BaseModel):
command_start: list[str] = ["/", ""] command_start: list[str] = ["/", ""]
nickname: list[str] = [f"灵温-{random_hex_string(6)}"] nickname: list[str] = [f"灵温-{random_hex_string(6)}"]
default_language: str = "zh-WY" default_language: str = "zh-WY"
default_interact_language: str = "zh-CN"
satori: SatoriConfig = SatoriConfig() satori: SatoriConfig = SatoriConfig()
data_path: str = "data/liteyuki" data_path: str = "data/liteyuki"
chromium_path: str = ( chromium_path: str = (
@ -43,6 +44,7 @@ class BasicConfig(BaseModel):
else "/usr/bin/chromium-browser" else "/usr/bin/chromium-browser"
) )
) )
status_acknowledgement: str = ""
def load_from_yaml(file_: str) -> dict: def load_from_yaml(file_: str) -> dict:

View File

@ -104,7 +104,7 @@ def load_from_dict(data: dict, lang_code: str):
class Language: class Language:
# 三重fallback # 三重fallback
# 用户语言 > 默认语言/系统语言 > zh-CN # 用户语言 > 默认语言/系统语言 > zh-CN | en
def __init__(self, lang_code: str = None, fallback_lang_code: str = None): def __init__(self, lang_code: str = None, fallback_lang_code: str = None):
self.lang_code = lang_code self.lang_code = lang_code
@ -117,6 +117,12 @@ class Language:
"default_language", get_system_lang_code() "default_language", get_system_lang_code()
) )
self.__fallback_list = (
self.lang_code,
self.fallback_lang_code,
"en" if "en" in self.lang_code else "zh-CN",
)
def _get(self, item: str, *args, **kwargs) -> str | Any: def _get(self, item: str, *args, **kwargs) -> str | Any:
""" """
获取当前语言文本kwargs中的default参数为默认文本 获取当前语言文本kwargs中的default参数为默认文本
@ -133,15 +139,14 @@ class Language:
""" """
default = kwargs.pop("default", None) default = kwargs.pop("default", None)
fallback = (self.lang_code, self.fallback_lang_code, "zh-CN")
for lang_code in fallback: for lang_code in self.__fallback_list:
if lang_code in _language_data and item in _language_data[lang_code]: if lang_code in _language_data and item in _language_data[lang_code]:
trans: str = _language_data[lang_code][item] trans: str = _language_data[lang_code][item]
try: try:
return trans.format(*args, **kwargs) return trans.format(*args, **kwargs)
except Exception as e: except Exception as e:
nonebot.logger.warning(f"Failed to format language data: {e}") nonebot.logger.warning("{} 无法格式化本地化数据".format(e))
return trans return trans
return default or item return default or item
@ -203,7 +208,7 @@ def get_user_lang(user_id: str) -> Language:
user_id, user_id,
default=User(user_id=user_id, username="Unknown"), default=User(user_id=user_id, username="Unknown"),
) )
lang_code = user.profile.get("lang", get_default_lang_code()) lang_code = user.profile.get("lang", get_default_user_lang_code())
_user_lang[user_id] = lang_code _user_lang[user_id] = lang_code
return Language(_user_lang[user_id]) return Language(_user_lang[user_id])
@ -225,6 +230,13 @@ def get_default_lang_code() -> str:
return get_config("default_language", default=get_system_lang_code()) return get_config("default_language", default=get_system_lang_code())
def get_default_user_lang_code() -> str:
"""
获取默认用户语言代码和上面的默认语言不同此处为显示给用户的语言
"""
return get_config("default_interact_language", default=get_default_lang_code())
def get_all_lang() -> dict[str, str]: def get_all_lang() -> dict[str, str]:
""" """
获取所有语言 获取所有语言

View File

@ -20,18 +20,18 @@ def default_filter(record: "Record"):
# DEBUG日志格式 # DEBUG日志格式
debug_format: str = ( debug_format: str = (
"<c>{time:YYYY-MM-DD HH:mm:ss}</c> " "<c>{time:YYYY-MM-DD HH:mm:ss}</c> "
"<lvl>[{level.icon}]</lvl> " "<lvl>[{level.icon}]</lvl> "
"<c><{name}.{module}.{function}:{line}></c> " "<c><{name}.{module}.{function}:{line}></c> "
"{message}" "{message}"
) )
# 默认日志格式 # 默认日志格式
default_format: str = ( default_format: str = (
"<c>{time:MM-DD HH:mm:ss}</c> " "<c>{time:MM-DD HH:mm:ss}</c> "
"<lvl>[{level.icon}]</lvl> " "<lvl>[{level.icon}]</lvl> "
"<c><{name}></c> " "<c><{name}></c> "
"{message}" "{message}"
) )
@ -74,6 +74,10 @@ def init_log():
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="<normal>", 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(
logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}{warning}") "SUCCESS", color="<green>", icon=f"{'' if show_icon else ''}{success}"
)
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}")