小范围优化,综合性改动

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

View File

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

View File

@@ -4,16 +4,16 @@ import time
import nonebot
import psutil
from cpuinfo import cpuinfo
from nonebot import require
from nonebot.adapters import satori
from src.utils import __NAME__
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.data_manager import TempConfig, common_db
from src.utils.base.language import Language
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 .counter_for_satori import satori_counter
from git import Repo
@@ -32,6 +32,7 @@ protocol_names = {
6: "安卓平板",
}
"""
Universal Interface
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参数的一部分了不需要保留但为了“兼容性”……
async def generate_status_card(
@@ -95,8 +297,9 @@ async def generate_status_card(
liteyuki: dict,
lang="zh-CN",
motto={"text": "风朗气清", "source": "成语一则"},
bot_id="0",
bot_id="0", # 兼容性
) -> bytes:
# print(get_config("status_acknowledgement"))
return await template2image(
get_path("templates/status.html", abs_path=True),
{
@@ -104,15 +307,17 @@ async def generate_status_card(
"bot": bot,
"hardware": hardware,
"liteyuki": liteyuki,
"localization": get_local_data(lang),
"localization": await get_local_data(lang),
"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)
bin_forcase = lang.get("status.unit.binary_middile")
return {
"friends": lang.get("status.friends"),
"groups": lang.get("status.groups"),
@@ -138,6 +343,18 @@ def get_local_data(lang_code) -> dict:
"process": lang.get("status.process"),
"resources": lang.get("status.resources"),
"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))
friends = str(await satori_utils.count_friends(bot))
status = {}
version_info = await bot.get_version_info()
version_info = await bot.get_version_info() # type: ignore
except Exception:
pass
else:
@@ -210,7 +427,8 @@ async def get_bots_data(self_id: str = "0") -> dict:
return result
async def get_hardware_data() -> dict:
async def get_hardware_data(lang_code) -> dict:
lang = Language(lang_code)
mem = psutil.virtual_memory()
all_processes = psutil.Process().children(recursive=True)
all_processes.append(psutil.Process())
@@ -227,30 +445,27 @@ async def get_hardware_data() -> dict:
except Exception:
pass
swap = psutil.swap_memory()
cpu_brand_raw = cpuinfo.get_cpu_info().get("brand_raw", "未知处理器")
if "amd" in cpu_brand_raw.lower():
brand = "AMD"
elif "intel" in cpu_brand_raw.lower():
brand = "英特尔"
elif "apple" in cpu_brand_raw.lower():
brand = "苹果"
elif "qualcomm" in cpu_brand_raw.lower():
brand = "高通"
elif "mediatek" in cpu_brand_raw.lower():
brand = "联发科"
elif "samsung" in cpu_brand_raw.lower():
brand = "三星"
elif "nvidia" in cpu_brand_raw.lower():
brand = "英伟达"
cpu_infos = cpuinfo.get_cpu_info()
cpu_brand_raw = cpu_infos.get(
"hardware_raw",
cpu_infos.get("brand_raw", "未知处理器"), # 此处之汉文不会被直接使用
).lower()
if cpu_brand_selected := for_in(
("amd", "intel", "apple", "qualcomm", "mediatek", "samsung", "nvidia"),
cpu_brand_raw,
):
brand = lang.get("status.cpubrand." + cpu_brand_selected[0])
else:
brand = "未知处理器"
brand = lang.get("status.cpubrand.unknown")
result = {
"cpu": {
"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),
"threads": psutil.cpu_count(logical=True),
"freq": psutil.cpu_freq().current, # MHz
"freq": psutil.cpu_freq().current, # 单位 MHz
},
"memory": {
"percent": mem.percent,
@@ -268,25 +483,39 @@ async def get_hardware_data() -> dict:
"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):
try:
disk_usage = psutil.disk_usage(disk.mountpoint)
if disk_usage.total == 0 or disk.mountpoint.startswith(
("/var", "/boot", "/run", "/proc", "/sys", "/dev", "/tmp", "/snap")
):
continue # 虚拟磁盘
result["disk"].append(
{
"name": disk.mountpoint,
"percent": disk_usage.percent,
"total": disk_usage.total,
"used": disk_usage.used,
"free": disk_usage.free,
}
)
other_disk["percent"] = (other_disk["percent"] + disk_usage.percent) / 2
other_disk["total"] += disk_usage.total
other_disk["used"] += disk_usage.used
other_disk["free"] += disk_usage.free
else:
result["disk"].append(
{
"name": disk.mountpoint,
"percent": disk_usage.percent,
"total": disk_usage.total,
"used": disk_usage.used,
"free": disk_usage.free,
}
)
except:
pass
if other_disk["total"] > 0: # 避免除零错误
result["disk"].append(other_disk)
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 zhDateTime
from nonebot import require
from src.utils import event as event_utils
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", "刷新"},
action=store_true,
),
Option(
"-t|-md|--markdown",
default=False,
# alias={"refr", "r", "刷新"},
action=store_true,
),
Subcommand(
"memory",
alias={"mem", "m", "内存"},
@@ -72,7 +79,7 @@ yanlun_path = "https://nd.liteyuki.icu/api/v3/share/content/Xpue?path=null"
# 每天4点更新
@scheduler.scheduled_job("cron", hour=4)
async def every_day_update():
ulang = Language(get_default_lang_code(), "zh-WY")
ulang = Language(get_default_lang_code(), "zh-CN")
nonebot.logger.success(
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)
yanlun_texts = (await resp.text()).strip("\n").split("\n")
except (ConnectionError, aiohttp.ClientError, aiohttp.WebSocketError) as err:
nonebot.logger.warning("读取言·论信息发生 客户端或通道 错误:\n{}".format(err))
nonebot.logger.warning("读取言·论信息发生 连接 错误:\n{}".format(err))
yanlun_texts = ["以梦想为驱使 创造属于自己的未来"]
# noinspection PyBroadException
except BaseException as err:
@@ -117,14 +124,22 @@ async def _():
yanlun_seqs = yanlun_texts = ["金羿ELS 生日快乐~", "Happy Birthday, Eilles!"]
elif solar_date == (8, 6):
yanlun_seqs = yanlun_texts = [
"诸葛亮与八卦阵 生日快乐~",
"Happy Birthday, bgArray~!",
"玉衡 生日快乐~",
"Happy Birthday, Alioth~!",
]
elif solar_date == (8, 16):
yanlun_seqs = yanlun_texts = [
"鱼旧梦 生日快乐~",
"Happy Birthday, ElapsingDreams~!",
]
elif lunar_date == (1, 1):
yanlun_seqs = yanlun_texts = [
"新春快乐~",
"千门万户曈曈日,总把新桃换旧符\t——王安石《元日》",
"爆竹声中一岁除,春风送暖入屠苏\t——王安石《元日》",
"半盏屠苏犹未举,灯前小草写桃符\t—— 陆游《除夜雪》",
"愿得长如此,年年物候新\t—— 卢照邻《元日述怀》",
]
else:
await update_yanlun()
@@ -163,13 +178,25 @@ async def _(
)
):
status_card_cache[ulang.lang_code] = (
await generate_status_card(
bot=await get_bots_data(),
hardware=await get_hardware_data(),
liteyuki=await get_liteyuki_data(),
lang=ulang.lang_code,
motto=dict(zip(["text", "source"], random_yanlun())),
bot_id=bot.self_id,
(
await generate_status_card_markdown(
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())),
)
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(),
)

View File

@@ -53,6 +53,7 @@ from .msctexec import (
add_memory_to_temporary,
read_memory_from_temporary,
get_stored_path,
get_user_lang,
)
from .utils import hanzi_timeid
@@ -116,6 +117,7 @@ async def _(
nonebot.logger.info(result.options)
usr_id = event.get_user_id()
ulang = get_user_lang(usr_id)
superuser_permission = await SUPERUSER(bot, event)
@@ -124,9 +126,10 @@ async def _(
):
await mspv_sync.finish(
UniMessage.text(
"转换点数不足当前剩余⌊p⌋≈{:.2f}|{}".format(
qres[1],
configdict["maxPersonConvert"]["music"],
ulang.get(
"convet.not_enough_point",
NOW=qres[1],
TOTAL=configdict["maxPersonConvert"]["music"],
)
),
at_sender=True,
@@ -168,12 +171,18 @@ async def _(
)
):
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]:
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 [
@@ -182,7 +191,11 @@ async def _(
]:
await mspv_sync.finish(
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")))
else:
await mspv_sync.finish(
UniMessage.text("乐器对照表 {} 不存在".format(_args["pitched-note-table"]))
ulang.get(
"convert.something_not_exist",
WHAT="乐音乐器对照表",
NAME=_args["pitched-note-table"],
)
)
return
@@ -240,7 +257,11 @@ async def _(
else:
await mspv_sync.finish(
UniMessage.text(
"乐器对照表 {} 不存在".format(_args["percussion-note-table"])
ulang.get(
"convert.something_not_exist",
WHAT="打击乐器对照表",
NAME=_args["percussion-note-table"],
)
)
)
return
@@ -257,7 +278,11 @@ async def _(
else:
await mspv_sync.finish(
UniMessage.text(
"音量处理曲线 {} 不存在".format(_args["volume-processing-function"])
ulang.get(
"convert.something_not_exist",
WHAT="音量处理曲线",
NAME=_args["volume-processing-function"],
)
)
)
return
@@ -274,10 +299,10 @@ async def _(
random.random() % 1.6 + 1.3,
)
if not res:
buffer.write("中途退出,转换点不足:{}\n".format(pnt))
buffer.write(ulang.get("convert.break.not_enough_point", NOW=pnt))
return res
await mspv_sync.send(UniMessage.text("转换开始……"))
await mspv_sync.send(UniMessage.text(ulang.get("convert.start")))
try: