✔❤大更新!

This commit is contained in:
2024-07-18 03:22:33 +08:00
parent 93ced26e07
commit 1116d033d0
35 changed files with 953 additions and 443 deletions

View File

@ -4,8 +4,8 @@ from git import Repo
from src.utils.base.config import get_config
remote_urls = [
"https://github.com/LiteyukiStudio/LiteyukiBot.git",
"https://gitee.com/snowykami/LiteyukiBot.git"
"https://github.com/TriM-Organization/LiteyukiBot-TriM.git",
"https://github.com/TriM-Organization/LiteyukiBot-TriM.git"
]

View File

@ -31,6 +31,20 @@ driver = get_driver()
markdown_image = common_db.where_one(StoredConfig(), default=StoredConfig()).config.get("markdown_image", False)
@on_alconna(
command=Alconna(
"ryounecho",
Args["text", str, ""],
),
permission=SUPERUSER
).handle()
# Satori OK
async def _(bot: T_Bot, matcher: Matcher, result: Arparma):
if result.main_args.get("text"):
await matcher.finish(Message(unescape(result.main_args.get("text"))))
else:
await matcher.finish(f"君安!灵温向你问好~\n此机 {bot.self_id}")
@on_alconna(
command=Alconna(
"liteecho",
@ -43,13 +57,13 @@ async def _(bot: T_Bot, matcher: Matcher, result: Arparma):
if result.main_args.get("text"):
await matcher.finish(Message(unescape(result.main_args.get("text"))))
else:
await matcher.finish(f"Hello, Liteyuki!\nBot {bot.self_id}")
await matcher.finish(f"Hello! TriM-Liteyuki!\nRyBot {bot.self_id}")
@on_alconna(
aliases={"更新轻雪"},
aliases={"更新灵温"},
command=Alconna(
"update-liteyuki"
"update-ryoun"
),
permission=SUPERUSER
).handle()
@ -59,7 +73,7 @@ async def _(bot: T_Bot, event: T_MessageEvent):
ulang = get_user_lang(str(event.user.id if isinstance(event, satori.event.Event) else event.user_id))
success, logs = update_liteyuki()
reply = "Liteyuki updated!\n"
reply = "尹灵温 更新完成!\n"
reply += f"```\n{logs}\n```\n"
btn_restart = md.btn_cmd(ulang.get("liteyuki.restart_now"), "reload-liteyuki")
pip.main(["install", "-r", "requirements.txt"])
@ -68,15 +82,15 @@ async def _(bot: T_Bot, event: T_MessageEvent):
@on_alconna(
aliases={"重启轻雪"},
aliases={"重启灵温","重启尹灵温", "重载灵温"},
command=Alconna(
"reload-liteyuki"
"reload-ryoun",
),
permission=SUPERUSER
).handle()
# Satori OK
async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
await matcher.send("Liteyuki reloading")
await matcher.send("尹灵温 正在重载")
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
temp_data.data.update(
@ -179,15 +193,15 @@ async def _(event: T_MessageEvent, matcher: Matcher):
ulang.get("liteyuki.image_mode_on" if stored_config.config["markdown_image"] else "liteyuki.image_mode_off"))
@on_alconna(
command=Alconna(
"liteyuki-docs",
),
aliases={"轻雪文档"},
).handle()
# Satori OK
async def _(matcher: Matcher):
await matcher.finish("https://bot.liteyuki.icu/usage")
# @on_alconna(
# command=Alconna(
# "liteyuki-docs",
# ),
# aliases={"轻雪文档"},
# ).handle()
# # Satori OK
# async def _(matcher: Matcher):
# await matcher.finish("https://bot.liteyuki.icu/usage")
@on_alconna(
@ -350,7 +364,7 @@ async def _(bot: T_Bot):
if isinstance(bot, satori.Bot):
await bot.send_message(
channel_id=reload_session_id,
message="Liteyuki reloaded in %.2f s" % delta_time
message="灵温 重载耗时 %.2f " % delta_time
)
else:
await bot.call_api(
@ -358,7 +372,7 @@ async def _(bot: T_Bot):
message_type=reload_session_type,
user_id=reload_session_id,
group_id=reload_session_id,
message="Liteyuki reloaded in %.2f s" % delta_time
message="灵温 重载耗时 %.2f " % delta_time
)
@ -369,8 +383,8 @@ async def every_day_update():
result, logs = update_liteyuki()
pip.main(["install", "-r", "requirements.txt"])
if result:
await broadcast_to_superusers(f"Liteyuki updated: ```\n{logs}\n```")
nonebot.logger.info(f"Liteyuki updated: {logs}")
await broadcast_to_superusers(f"灵温已更新: ```\n{logs}\n```")
nonebot.logger.info(f"灵温已更新: {logs}")
Reloader.reload(5)
else:
nonebot.logger.info(logs)

View File

@ -1,18 +0,0 @@
from nonebot.plugin import PluginMetadata
from .monitors import *
from .matchers import *
__author__ = "snowykami"
__plugin_meta__ = PluginMetadata(
name="轻雪智障回复",
description="",
usage="",
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki": True,
"toggleable" : True,
"default_enable" : True,
}
)

View File

@ -1,106 +0,0 @@
import asyncio
import random
import nonebot
from nonebot import Bot, on_message, get_driver, require
from nonebot.internal.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from nonebot.typing import T_State
from src.utils.base.ly_typing import T_MessageEvent
from .utils import get_keywords
from src.utils.base.word_bank import get_reply
from src.utils.event import get_message_type
from src.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
from src.utils.base.data_manager import group_db, Group
require("nonebot_plugin_alconna")
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma
nicknames = set()
driver = get_driver()
group_reply_probability: dict[str, float] = {
}
default_reply_probability = 0.05
cut_probability = 0.4 # 分几句话的概率
@on_alconna(
Alconna(
"set-reply-probability",
Args["probability", float, default_reply_probability],
),
aliases={"设置回复概率"},
permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER,
).handle()
async def _(result: Arparma, event: T_MessageEvent, matcher: Matcher):
# 修改内存和数据库的概率值
if get_message_type(event) == "group":
group_id = event.group_id
probability = result.main_args.get("probability")
# 保存到数据库
group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=str(group_id)))
group.config["reply_probability"] = probability
group_db.save(group)
await matcher.send(f"已将群组{group_id}的回复概率设置为{probability}")
return
@group_db.on_save
def _(model: Group):
"""
在数据库更新时,更新内存中的回复概率
Args:
model:
Returns:
"""
group_reply_probability[model.group_id] = model.config.get("reply_probability", default_reply_probability)
@driver.on_bot_connect
async def _(bot: Bot):
global nicknames
nicknames.update(bot.config.nickname)
# 从数据库加载群组的回复概率
groups = group_db.where_all(Group(), default=[])
for group in groups:
group_reply_probability[group.group_id] = group.config.get("reply_probability", default_reply_probability)
@on_message(priority=100).handle()
async def _(event: T_MessageEvent, bot: Bot, state: T_State, matcher: Matcher):
kws = await get_keywords(event.message.extract_plain_text())
tome = False
if await to_me()(event=event, bot=bot, state=state):
tome = True
else:
for kw in kws:
if kw in nicknames:
tome = True
break
# 回复概率
message_type = get_message_type(event)
if tome or message_type == "private":
p = 1.0
else:
p = group_reply_probability.get(event.group_id, default_reply_probability)
if random.random() < p:
if reply := get_reply(kws):
if random.random() < cut_probability:
reply = reply.replace("", "||").replace("", "||").replace("", "||").replace("", "||")
replies = reply.split("||")
for r in replies:
if r: # 防止空字符串
await asyncio.sleep(random.random() * 2)
await matcher.send(r)
else:
await asyncio.sleep(random.random() * 3)
await matcher.send(reply)
return

View File

@ -1,13 +0,0 @@
from jieba import lcut
from nonebot.utils import run_sync
@run_sync
def get_keywords(text: str) -> list[str, ...]:
"""
获取关键词
Args:
text: 文本
Returns:
"""
return lcut(text)

View File

@ -8,22 +8,22 @@ __plugin_meta__ = PluginMetadata(
name="统计信息",
description="统计机器人的信息,包括消息、群聊等,支持排名、图表等功能",
usage=(
"```\nstatistic message 查看统计消息\n"
"可选参数:\n"
" -g|--group [group_id] 指定群聊\n"
" -u|--user [user_id] 指定用户\n"
" -d|--duration [duration] 指定时长\n"
" -p|--period [period] 指定次数统计周期\n"
" -b|--bot [bot_id] 指定机器人\n"
"命令别名:\n"
" statistic|stat message|msg|m\n"
"```"
"```\nstatistic message 查看统计消息\n"
"可选参数:\n"
" -g|--group [group_id] 指定群聊\n"
" -u|--user [user_id] 指定用户\n"
" -d|--duration [duration] 指定时长\n"
" -p|--period [period] 指定次数统计周期\n"
" -b|--bot [bot_id] 指定机器人\n"
"命令别名:\n"
" statistic|stat message|msg|m\n"
"```"
),
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki" : True,
"toggleable" : False,
"default_enable": True,
}
"liteyuki": True,
"toggleable": False,
"default_enable": True,
},
)

View File

@ -93,6 +93,7 @@ async def generate_status_card(
hardware: dict,
liteyuki: dict,
lang="zh-CN",
motto={"text":"风朗气清","source":"成语一则"},
bot_id="0",
) -> bytes:
return await template2image(
@ -103,6 +104,7 @@ async def generate_status_card(
"hardware": hardware,
"liteyuki": liteyuki,
"localization": get_local_data(lang),
"motto": motto,
}
},
)

View File

@ -1,15 +1,33 @@
import zhDateTime
import requests
import random
from src.utils import event as event_utils
from src.utils.base.language import get_user_lang
from src.utils.base.language import get_user_lang, get_default_lang_code, Language
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
from .api import *
require("nonebot_plugin_alconna")
from nonebot_plugin_alconna import on_alconna, Alconna, Subcommand, UniMessage
from nonebot_plugin_alconna import (
on_alconna,
Alconna,
Subcommand,
UniMessage,
Option,
store_true,
AlconnaQuery,
Query,
Arparma,
)
require("nonebot_plugin_apscheduler")
from nonebot_plugin_apscheduler import scheduler
status_alc = on_alconna(
aliases={"状态"},
command=Alconna(
"status",
Option("-r|--refresh", alias={"refr", "r", "刷新"}, action=store_true),
Subcommand(
"memory",
alias={"mem", "m", "内存"},
@ -18,23 +36,95 @@ status_alc = on_alconna(
"process",
alias={"proc", "p", "进程"},
),
Subcommand(
"refresh",
alias={"refr", "r", "刷新"},
),
# Subcommand(
# "refresh",
# alias={"refr", "r", "刷新"},
# ),
),
)
yanlun = on_alconna(
aliases={"yanlun", "言·论", "yan_lun"},
command=Alconna(
"言论",
Option(
"-r|--refresh",
default=False,
alias={"刷新", "更新", "update"},
action=store_true,
),
Option("-c|--count", default=False, alias={"统计"}, action=store_true),
),
)
# 每天4点更新
@scheduler.scheduled_job("cron", hour=4)
async def every_day_update():
ulang = Language(get_default_lang_code(), "zh-WY")
nonebot.logger.success(ulang.get("yanlun.refresh.success", COUNT=update_yanlun()))
def update_yanlun():
global yanlun_texts
solar_datetime = zhDateTime.DateTime.now()
lunar_datetime = solar_datetime.to_lunar()
solar_date = (solar_datetime.month, solar_datetime.day)
lunar_date = (lunar_datetime.lunar_month, lunar_datetime.lunar_day)
if solar_date == (4, 3):
yanlun_texts = ["金羿ELS 生日快乐~"]
elif solar_date == (8, 6):
yanlun_texts = ["诸葛八卦 生日快乐~"]
else:
try:
yanlun_texts = (
requests.get(
"https://gitee.com/TriM-Organization/LinglunStudio/raw/master/resources/myWords.txt",
)
.text.strip("\n")
.split("\n")
)
except (ConnectionError, requests.HTTPError, requests.RequestException) as E:
nonebot.logger.warning(f"读取言·论信息发生 互联网连接 错误:\n{E}")
yanlun_texts = ["以梦想为驱使 创造属于自己的未来"]
# noinspection PyBroadException
except BaseException as E:
nonebot.logger.warning(f"读取言·论信息发生 未知 错误:\n{E}")
yanlun_texts = ["灵光焕发 深艺献心"]
return len(yanlun_texts)
update_yanlun()
def random_yanlun() -> tuple:
seq = random.choice(yanlun_texts).replace(" ", "\t").split("\t——", 1)
return seq[0], "" if len(seq) == 1 else seq[1]
status_card_cache = {} # lang -> bytes
@status_alc.handle()
async def _(event: T_MessageEvent, bot: T_Bot):
ulang = get_user_lang(event_utils.get_user_id(event))
async def _(
result: Arparma,
event: T_MessageEvent,
bot: T_Bot,
# refresh: Query[bool] = AlconnaQuery("refresh.value", False),
):
ulang = get_user_lang(event_utils.get_user_id(event)) # type: ignore
global status_card_cache
if ulang.lang_code not in status_card_cache.keys() or (
ulang.lang_code in status_card_cache.keys()
and time.time() - status_card_cache[ulang.lang_code][1] > 60
if (
result.options["refresh"].value
or ulang.lang_code not in status_card_cache.keys()
or (
ulang.lang_code in status_card_cache.keys()
and time.time() - status_card_cache[ulang.lang_code][1] > 60
)
):
status_card_cache[ulang.lang_code] = (
await generate_status_card(
@ -42,6 +132,7 @@ async def _(event: T_MessageEvent, bot: T_Bot):
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,
),
time.time(),
@ -58,3 +149,100 @@ async def _():
@status_alc.assign("process")
async def _():
print("process")
@yanlun.handle()
async def _(
result: Arparma,
event: T_MessageEvent,
bot: T_Bot,
# refresh: Query[bool] = AlconnaQuery("refresh.value", False),
# count: Query[bool] = AlconnaQuery("count.value", False),
):
# print(result.options)
if result.options["refresh"].value:
ulang = get_user_lang(event_utils.get_user_id(event)) # type: ignore
global yanlun_texts
try:
yanlun_texts = (
requests.get(
"https://gitee.com/TriM-Organization/LinglunStudio/raw/master/resources/myWords.txt",
)
.text.strip("\n")
.split("\n")
)
await yanlun.send(
UniMessage.text(
ulang.get("yanlun.refresh.success", COUNT=len(yanlun_texts))
)
)
except (ConnectionError, requests.HTTPError, requests.RequestException) as E:
await yanlun.send(
UniMessage.text(
ulang.get(
"yanlun.refresh.failed",
ERR=ulang.get("yanlun.errtype.net"),
ERRCODE=f"\n{E}",
)
)
)
yanlun_texts = ["以梦想为驱使 创造属于自己的未来"]
# noinspection PyBroadException
except BaseException as E:
await yanlun.send(
UniMessage.text(
ulang.get(
"yanlun.refresh.failed",
ERR=ulang.get("yanlun.errtype.unknown"),
ERRCODE=f"\n{E}",
)
)
)
yanlun_texts = ["灵光焕发 深艺献心"]
if result.options["count"].value:
ulang = get_user_lang(event_utils.get_user_id(event)) # type: ignore
authors = [
(
("B站")
if ("\t——B站" in i.upper() or " ——B站" in i.upper())
else (
i.split("\t——")[1].replace(" ", "")
if "\t——" in i
else (
i.split(" ——")[1].replace(" ", "")
if " ——" in i
else ("MYH")
)
)
)
for i in yanlun_texts
]
total = len(yanlun_texts)
chart = sorted(
[(i, authors.count(i)) for i in set(authors)],
key=lambda x: x[1],
reverse=True,
)
await yanlun.send(
UniMessage.text(
ulang.get("yanlun.count.head").replace("ttt", "\t")
+ "\n"
+ "".join(
[
(
"{}\t{}({}%)\n".format(
aut, cnt, int(cnt * 10000 / total + 0.5) / 100
)
if cnt * 100 / total >= chart[10][1] * 100 / total
else ""
)
for aut, cnt in chart
]
)
+ ulang.get("yanlun.count.tail", NUM=total)
)
)
await yanlun.finish(UniMessage.text(random.choice(yanlun_texts)))

View File

@ -1,4 +1,12 @@
.sign-chart {
height: 400px;
background-color: rgba(255, 255, 255, 0.7);
}
#addition-info {
font-size: 36px;
word-wrap: break-word;
color: var(--main-text-color);
text-align: center;
margin: 30px 0 10px 0;
}

View File

@ -0,0 +1,7 @@
#addition-info {
font-size: 36px;
word-wrap: break-word;
color: var(--main-text-color);
text-align: center;
margin: 30px 0 10px 0;
}

View File

@ -51,4 +51,7 @@ function timestampToTime(timestamp) {
let m = date.getMinutes() + ':'
let s = date.getSeconds()
return M + D + h + m + s
}
}
document.getElementById('addition-info').innerText = '感谢 锅炉 云裳工作室 提供服务器支持'

View File

@ -23,3 +23,5 @@ data["ranking"].forEach((item) => {
document.body.appendChild(row)
})
document.getElementById('addition-info').innerText = '感谢 锅炉 云裳工作室 提供服务器支持'

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Liteyuki Stats Message</title>
@ -10,13 +11,15 @@
<body>
<template id="sign-chart-template">
<div class="info-box sign-chart">
</div>
</template>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<template id="sign-chart-template">
<div class="info-box sign-chart">
</div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_msg.js"></script>
<script src="./js/card.js"></script>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="addition-info"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_msg.js"></script>
<script src="./js/card.js"></script>
</body>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Liteyuki Stats Message</title>
@ -15,19 +16,19 @@
margin-bottom: 10px;
padding-right: 10px;
}
.row-name {
font-size: 40px;
align-content: center;
width: 100px;
text-align: left;
}
.row-icon {
border-radius: 50%;
margin-right: auto;
}
.row-count {
align-content: center;
font-size: 40px;
@ -39,16 +40,18 @@
<body>
<template id="row-template">
<div class="row">
<img src="./img/arrow-up.svg" alt="up" class="row-icon">
<div class="row-name"></div>
<div class="row-count"></div>
</div>
</template>
<template id="row-template">
<div class="row">
<img src="./img/arrow-up.svg" alt="up" class="row-icon">
<div class="row-name"></div>
<div class="row-count"></div>
</div>
</template>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_rank.js"></script>
<script src="./js/card.js"></script>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="addition-info"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_rank.js"></script>
<script src="./js/card.js"></script>
</body>

View File

@ -156,4 +156,11 @@ status.seconds=秒
status.cores=核心
status.threads=线程
status.process=进程
status.description=轻雪机器人状态面板
status.description=轻雪机器人状态面板
yanlun.refresh.success=言·论 更新成功,共 {COUNT} 条
yanlun.refresh.failed=更新 言·论 信息发生 {ERR} 错误:{ERRCODE}
yanlun.errtype.net=互联网连接
yanlun.errtype.unknown=未知
yanlun.count.head=出处ttt数量(占比)
yanlun.count.tail=...(共 {NUM} 条)

View File

@ -156,4 +156,11 @@ status.seconds=秒
status.cores=轮核
status.threads=程线
status.process=行轨
status.description=轻雪灵机台
status.description=轻雪灵机台
yanlun.refresh.success=言·论 方新,合{COUNT}条
yanlun.refresh.failed=言·论 因{ERR}而无以新:{ERRCODE}
yanlun.errtype.net=遥讯不得
yanlun.errtype.unknown=无名之亏
yanlun.count.head=所缘ttt几何(比率)
yanlun.count.tail=...(合{NUM}条)

View File

@ -125,3 +125,10 @@
text-align: right;
}
#addition-info {
font-size: 36px;
word-wrap: break-word;
color: var(--main-text-color);
text-align: center;
margin: 30px 0 10px 0;
}

View File

@ -3,7 +3,7 @@ body {
background-size: cover;
background-position: center;
color: white;
/ / 10px10px0px / / margin: 24 px;
/* // 上10px左右10px下0px // margin: 24 px; */
margin: 20px;
}
@ -55,7 +55,8 @@ body {
background-color: white;
}
.bot-name, .bot-tag {
.bot-name,
.bot-tag {
margin-left: 20px;
}
@ -98,4 +99,9 @@ body {
font-size: 30px;
font-style: italic;
color: #ccc;
}
.addition-info {
font-size: 36px;
color: #fff;
}

View File

@ -3,6 +3,7 @@ const bot_data = data['bot']; // 机器人数据
const hardwareData = data['hardware']; // 硬件数据
const liteyukiData = data['liteyuki']; // LiteYuki数据
const localData = data['localization']; // 本地化语言数据
const motto_ = data['motto']; // 言论数据
/**
* 创建CPU/内存/交换饼图
@ -61,10 +62,10 @@ function createPieChartOption(title, data) {
}
function convertSize(size, precision = 2, addUnit = true, suffix = " XiB") {
function convertSize(size, precision = 2, addUnit = true, suffix = " X字节") {
let isNegative = size < 0;
size = Math.abs(size);
let units = ["", "K", "M", "G", "T", "P", "E", "Z"];
let units = ["", "", "", "", "", "", "", ""];
let unit = "";
for (let i = 0; i < units.length; i++) {
@ -254,20 +255,20 @@ function main() {
cpuChart.setOption(createPieChartOption(`${localData['cpu']}\n${cpuData['percent'].toFixed(1)}%`, [
{name: 'used', value: cpuData['percent']},
{name: 'free', value: 100 - cpuData['percent']}
{ name: 'used', value: cpuData['percent'] },
{ name: 'free', value: 100 - cpuData['percent'] }
]))
memChart.setOption(createPieChartOption(`${localData['memory']}\n${memData['percent'].toFixed(1)}%`, [
{name: 'process', value: memData['usedProcess']},
{name: 'used', value: memData['used'] - memData['usedProcess']},
{name: 'free', value: memData['free']}
{ name: 'process', value: memData['usedProcess'] },
{ name: 'used', value: memData['used'] - memData['usedProcess'] },
{ name: 'free', value: memData['free'] }
]))
swapChart.setOption(createPieChartOption(`${localData['swap']}\n${swapData['percent'].toFixed(1)}%`, [
{name: 'used', value: swapData['used']},
{name: 'free', value: swapData['free']}
{ name: 'used', value: swapData['used'] },
{ name: 'free', value: swapData['free'] }
]))
@ -284,12 +285,12 @@ function main() {
document.getElementById('disk-info').appendChild(createBarChart(diskTitle, disk['percent']))
})
// 随机一言
let motto = mottos[Math.floor(Math.random() * mottos.length)]
let mottoText = motto['text']
let mottoFrom = `${motto['author']} ${motto['source']}`
let mottoText = motto_['text']
let mottoFrom = motto_['source']
document.getElementById('motto-text').innerText = mottoText
document.getElementById('motto-from').innerText = mottoFrom
// 致谢
document.getElementById('addition-info').innerText = '感谢 锅炉 云裳工作室 提供服务器支持'
}

View File

@ -103,7 +103,7 @@
)
// 从/js/motto.js中读取mottos{},随机选择一句
let motto = mottos[Math.floor(Math.random() * mottos.length)];
// let motto = mottos[Math.floor(Math.random() * mottos.length)];
// 正文在中间,作者和来源格式为--作者 来源,在右下方
let mottoDiv = document.getElementById('motto-info');
let mottoText = document.createElement('div');
@ -113,13 +113,13 @@
let mottoAuthor = document.createElement('div');
mottoAuthor.className = 'motto-author';
// motto.author和motto.source可能不存在为空所以要判断
if (!motto.author) {
motto.author = '';
}
// if (!motto.author) {
// motto.author = '';
// }
if (!motto.source) {
motto.source = '';
}
mottoAuthor.innerText = `\n--${motto.author} ${motto.source}`;
mottoAuthor.innerText = `\n${motto.source}`;
mottoAuthor.style.textAlign = 'right';
mottoDiv.appendChild(mottoAuthor);

View File

@ -10,31 +10,33 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
</div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
<div class="info-box" id="disks-info">
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
<div class="info-box" id="motto-info">
</div>
</div>
<div class="info-box" id="disks-info">
</div>
<div class="info-box" id="motto-info">
</div>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<script src="js/bg.js"></script>
<script src="js/motto.js"></script>
<script src="js/style.js"></script>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<script src="js/bg.js"></script>
<!-- <script src="js/motto.js"></script> -->
<script src="js/style.js"></script>
</body>
</html>
</html>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Liteyuki Status</title>
@ -8,43 +9,46 @@
<link rel="stylesheet" href="./css/fonts.css">
</head>
<body>
<template id="bot-template">
<div class="info-box bot-info">
<div class="bot-icon">
<img class="bot-icon-img" src="" alt="bot-icon">
</div>
<div class="bot-detail">
<div class="bot-name">
Liteyuki
<template id="bot-template">
<div class="info-box bot-info">
<div class="bot-icon">
<img class="bot-icon-img" src="" alt="bot-icon">
</div>
<hr>
<div class="bot-tags">
<!-- tag span-->
<div class="bot-detail">
<div class="bot-name">
TriM-Liteyuki
</div>
<hr>
<div class="bot-tags">
<!-- tag span-->
</div>
</div>
</div>
</div>
</template>
</template>
<template id="device-info">
<div class="device-info">
<div class="device-chart">
<template id="device-info">
<div class="device-info">
<div class="device-chart">
</div>
<div class="device-tags">
</div>
</div>
<div class="device-tags">
</div>
</div>
</template>
</template>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="hardware-info"></div>
<div class="info-box" id="disk-info"></div>
<div class="info-box" id="motto-info">
<div id="motto-text"></div>
<div id="motto-from"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/motto.js"></script>
<script src="./js/card.js"></script>
<script src="./js/status.js"></script>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="hardware-info"></div>
<div class="info-box" id="disk-info"></div>
<div class="info-box" id="motto-info">
<div id="motto-text"></div>
<div id="motto-from"></div>
</div>
<div class="info-box" id="addition-info"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<!-- <script src="./js/motto.js"></script> -->
<script src="./js/card.js"></script>
<script src="./js/status.js"></script>
</body>
</html>

View File

@ -49,7 +49,8 @@
background-color: white;
}
.bot-name, .bot-tag {
.bot-name,
.bot-tag {
margin-left: 20px;
}
@ -93,35 +94,36 @@
font-style: italic;
color: #ccc;
}
</style>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@4.3.0/dist/echarts.min.js"></script>
</head>
<body>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
</div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
<div class="info-box" id="disks-info">
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
<div class="info-box" id="motto-info">
</div>
</div>
<div class="info-box" id="disks-info">
</div>
<div class="info-box" id="motto-info">
</div>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<script src="js/motto.js"></script>
<script src="js/style.js"></script>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<!-- <script src="js/motto.js"></script> -->
<script src="js/style.js"></script>
</body>
</html>
</html>

View File

@ -1,23 +1,143 @@
import os.path
import time
# import time
from os import getcwd
import aiofiles
import nonebot
from nonebot_plugin_htmlrender import *
from .tools import random_hex_string
# import imgkit
# from typing import Any, Dict, Literal, Optional, Union
# import uuid
# import jinja2
# from pathlib import Path
# TEMPLATES_PATH = str(Path(__file__).parent / "templates")
# env = jinja2.Environment( # noqa: S701
# extensions=["jinja2.ext.loopcontrols"],
# loader=jinja2.FileSystemLoader(TEMPLATES_PATH),
# enable_async=True,
# )
# async def template_to_html(
# template_path: str,
# template_name: str,
# **kwargs,
# ) -> str:
# """使用jinja2模板引擎通过html生成图片
# Args:
# template_path (str): 模板路径
# template_name (str): 模板名
# **kwargs: 模板内容
# Returns:
# str: html
# """
# template_env = jinja2.Environment( # noqa: S701
# loader=jinja2.FileSystemLoader(template_path),
# enable_async=True,
# )
# template = template_env.get_template(template_name)
# return await template.render_async(**kwargs)
# async def template_to_pic(
# template_path: str,
# template_name: str,
# templates: Dict[Any, Any],
# pages: Optional[Dict[Any, Any]] = None,
# wait: int = 0,
# type: Literal["jpeg", "png"] = "png", # noqa: A002
# quality: Union[int, None] = None,
# device_scale_factor: float = 2,
# ) -> bytes:
# """使用jinja2模板引擎通过html生成图片
# Args:
# template_path (str): 模板路径
# template_name (str): 模板名
# templates (Dict[Any, Any]): 模板内参数 如: {"name": "abc"}
# pages (Optional[Dict[Any, Any]]): 网页参数 Defaults to
# {"base_url": f"file://{getcwd()}", "viewport": {"width": 500, "height": 10}}
# wait (int, optional): 网页载入等待时间. Defaults to 0.
# type (Literal["jpeg", "png"]): 图片类型, 默认 png
# quality (int, optional): 图片质量 0-100 当为`png`时无效
# device_scale_factor: 缩放比例,类型为float,值越大越清晰(真正想让图片清晰更优先请调整此选项)
# Returns:
# bytes: 图片 可直接发送
# """
# if pages is None:
# pages = {
# "viewport": {"width": 500, "height": 10},
# "base_url": f"file://{getcwd()}", # noqa: PTH109
# }
# template_env = jinja2.Environment( # noqa: S701
# loader=jinja2.FileSystemLoader(template_path),
# enable_async=True,
# )
# template = template_env.get_template(template_name)
# open(
# filename := os.path.join(
# template_path,
# str(uuid.uuid4())+".html",
# ),
# "w",
# ).write(await template.render_async(**templates))
# print(pages,filename)
# img = imgkit.from_file(
# filename,
# output_path=False,
# options={
# "format": type,
# "quality": quality if (quality and type == "jpeg") else 94,
# "allow": pages["base_url"],
# # "viewport-size": "{} {}".format(pages["viewport"]["width"],pages["viewport"]["height"]),
# "zoom": device_scale_factor,
# # "load-error-handling": "ignore",
# "enable-local-file-access": None,
# "no-stop-slow-scripts": None,
# "transparent": None,
# },
# ) # type: ignore
# # os.remove(filename)
# return img
# return await html_to_pic(
# template_path=f"file://{template_path}",
# html=await template.render_async(**templates),
# wait=wait,
# type=type,
# quality=quality,
# device_scale_factor=device_scale_factor,
# **pages,
# )
async def html2image(
html: str,
wait: int = 0,
html: str,
wait: int = 0,
):
pass
async def template2html(
template: str,
templates: dict,
template: str,
templates: dict,
) -> str:
"""
Args:
@ -32,12 +152,12 @@ async def template2html(
async def template2image(
template: str,
templates: dict,
pages=None,
wait: int = 0,
scale_factor: float = 1,
debug: bool = False,
template: str,
templates: dict,
pages=None,
wait: int = 0,
scale_factor: float = 1,
debug: bool = False,
) -> bytes:
"""
template -> html -> image
@ -53,11 +173,8 @@ async def template2image(
"""
if pages is None:
pages = {
"viewport": {
"width" : 1080,
"height": 10
},
"base_url": f"file://{getcwd()}",
"viewport": {"width": 1080, "height": 10},
"base_url": f"file://{getcwd()}",
}
template_path = os.path.dirname(template)
template_name = os.path.basename(template)
@ -70,7 +187,9 @@ async def template2image(
**templates,
)
random_file_name = f"debug-{random_hex_string(6)}.html"
async with aiofiles.open(os.path.join(template_path, random_file_name), "w", encoding="utf-8") as f:
async with aiofiles.open(
os.path.join(template_path, random_file_name), "w", encoding="utf-8"
) as f:
await f.write(raw_html)
nonebot.logger.info("Debug HTML: %s" % f"{random_file_name}")
@ -84,30 +203,30 @@ async def template2image(
)
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
)
# 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
# )

View File

@ -75,8 +75,8 @@ class MarkdownMessage:
group_id = event.group_id if message_type == "group" else None
user_id = event.user.id if isinstance(event, satori.event.Event) else event.user_id
session_id = user_id if message_type == "private" else group_id
else:
pass
try:
raise TencentBannedMarkdownError("Tencent banned markdown")
forward_id = await bot.call_api(