refactor: restructure plugins per MTSS standard, consolidate assets to res/

Per docs/plugin-audit-report.md (plugins normalized to
Trigger(handlers) → Service(services) → Model(repository/models) + utils):

- Split monolithic __init__.py into handlers/services/utils across
  dailywife, deer_pipe, dice, galgame_card, helldivers_tools,
  huoziyinshua, learning_chat, makeaquote, mc_server_status,
  ncm_saying, picfinder_take, picstatus, random_jm_code, regif,
  steam_info, video_analysis, group_tools
- Move static assets under res/: deer_pipe font/img, makeaquote font,
  helldivers img/templates, huoziyinshua HuoZiYinShua
- Add config.py + register_config_items to ncm_saying, random_jm_code,
  group_tools; learning_chat unified config bridge
- Remove deprecated: voice_trans plugin, bf_bot/test.py, dead code in
  dailywife/deer_pipe, empty dirs, debug scripts under helldivers temp
- Disable brash_general_supercredits_tools (stub comment only)
- bot.py: optional stdout/stderr redirect to log file for Web log viewer,
  force ANSI colorize on non-TTY sinks
- Move runtime data (jm_code.json) out of plugin dir into hexi/data
- Docs: plugin-audit-report.md; README reflects removed plugins

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-03 00:44:38 +08:00
co-authored by Claude
parent 25bc30611f
commit 9371a28e35
2389 changed files with 5100 additions and 10127 deletions
@@ -23,6 +23,9 @@ except Exception: # pragma: no cover
_MODULE_START = time.time()
# 网络速率采样:记录上一次累计计数与时间,用于计算实时 bytes/s 用量
_NET_LAST: dict = {"time": None, "sent": None, "recv": None}
async def _collect_cpu() -> dict:
try:
@@ -91,6 +94,95 @@ async def _collect_process() -> dict:
return info
async def _collect_network() -> dict:
"""采集网络流量累计值 + 实时速率(bytes/s)。"""
global _NET_LAST
now = time.time()
try:
io = psutil.net_io_counters(pernic=False)
except Exception:
return {
"sent": 0,
"recv": 0,
"sent_rate": 0,
"recv_rate": 0,
"packets_sent": 0,
"packets_recv": 0,
"interfaces": [],
}
sent = int(io.bytes_sent)
recv = int(io.bytes_recv)
sent_rate = recv_rate = 0.0
last = _NET_LAST
if last["time"] is not None and last["sent"] is not None:
dt = max(0.001, now - float(last["time"]))
sent_rate = max(0.0, (sent - int(last["sent"])) / dt)
recv_rate = max(0.0, (recv - int(last["recv"])) / dt)
_NET_LAST = {"time": now, "sent": sent, "recv": recv}
# 逐网卡明细(含 IP / 友好名称)
interfaces: list[dict] = []
try:
pernic = psutil.net_io_counters(pernic=True)
addrs = psutil.net_if_addrs()
stats = psutil.net_if_stats()
for name, cnt in pernic.items():
if not cnt.bytes_sent and not cnt.bytes_recv:
continue
ips = []
for addr in addrs.get(name, []):
ip = (addr.address or "").strip()
# 只保留 IPv4(带点分十进制),忽略 MAC / IPv6
if ip and ":" not in ip and ip.count(".") >= 3:
ips.append(ip)
up = bool(stats.get(name).isup) if name in stats else True
interfaces.append({
"name": name,
"up": up,
"sent": int(cnt.bytes_sent),
"recv": int(cnt.bytes_recv),
"ip": ", ".join(ips) if ips else "",
})
except Exception:
interfaces = []
return {
"sent": sent,
"recv": recv,
"sent_rate": round(sent_rate, 1),
"recv_rate": round(recv_rate, 1),
"packets_sent": int(io.packets_sent),
"packets_recv": int(io.packets_recv),
"interfaces": interfaces,
}
async def _collect_backend() -> dict:
"""BOT 后端信息:NoneBot 版本 / 驱动方式 / 装载插件数。"""
from nonebot import get_loaded_plugins
try:
plugin_count = len(get_loaded_plugins())
except Exception:
plugin_count = 0
info: dict = {
"nonebot_version": _nonebot_version(),
"plugin_count": plugin_count,
"python": f"{platform.python_implementation()} {platform.python_version()}",
"driver_type": "",
"driver": "",
}
try:
from nonebot import get_driver
driver = get_driver()
info["driver_type"] = getattr(driver, "type", "") or ""
info["driver"] = getattr(driver.config, "driver", "") or ""
except Exception:
pass
return info
async def _collect_system() -> dict:
boot = psutil.boot_time()
now = time.time()
@@ -180,13 +272,15 @@ async def _collect_bots() -> list:
async def collect_dashboard() -> dict:
"""聚合采集,失败字段降级,不阻塞整体返回。"""
cpu, memory, process, system, disk, bots = await asyncio.gather(
cpu, memory, process, system, disk, bots, network, backend = await asyncio.gather(
_collect_cpu(),
_collect_memory(),
_collect_process(),
_collect_system(),
_collect_disk(),
_collect_bots(),
_collect_network(),
_collect_backend(),
)
return {
"bots": bots,
@@ -195,4 +289,6 @@ async def collect_dashboard() -> dict:
"memory": memory,
"process": process,
"disk": disk,
"network": network,
"backend": backend,
}