diff --git a/.gitignore b/.gitignore index d9da460..af9d78f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ docs/.vuepress/dist/ prompt.txt # js -**/echarts.js \ No newline at end of file +**/echarts.js +.env diff --git a/liteyuki/liteyuki_main/core.py b/liteyuki/liteyuki_main/core.py index d387545..ae0c70d 100644 --- a/liteyuki/liteyuki_main/core.py +++ b/liteyuki/liteyuki_main/core.py @@ -5,6 +5,7 @@ from typing import Any import nonebot import pip from nonebot import Bot, get_driver, require +from nonebot.adapters import satori from nonebot.adapters.onebot.v11 import Message, escape, unescape from nonebot.exception import MockApiException from nonebot.internal.matcher import Matcher @@ -16,6 +17,7 @@ from liteyuki.utils.base.language import get_user_lang from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent from liteyuki.utils.message.message import MarkdownMessage as md, broadcast_to_superusers from liteyuki.utils.base.reloader import Reloader +from liteyuki.utils import satori_utils from .api import update_liteyuki require("nonebot_plugin_alconna") @@ -35,6 +37,7 @@ markdown_image = common_db.where_one(StoredConfig(), default=StoredConfig()).con ), 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")))) @@ -49,9 +52,11 @@ async def _(bot: T_Bot, matcher: Matcher, result: Arparma): ), permission=SUPERUSER ).handle() +# Satori OK async def _(bot: T_Bot, event: T_MessageEvent): # 使用git pull更新 - ulang = get_user_lang(str(event.user_id)) + + 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 += f"```\n{logs}\n```\n" @@ -68,18 +73,19 @@ async def _(bot: T_Bot, event: T_MessageEvent): ), permission=SUPERUSER ).handle() +# Satori OK async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent): await matcher.send("Liteyuki reloading") temp_data = common_db.where_one(TempConfig(), default=TempConfig()) temp_data.data.update( { - "reload" : True, - "reload_time" : time.time(), - "reload_bot_id" : bot.self_id, - "reload_session_type": event.message_type, - "reload_session_id" : event.group_id if event.message_type == "group" else event.user_id, - "delta_time" : 0 + "reload": True, + "reload_time": time.time(), + "reload_bot_id": bot.self_id, + "reload_session_type": satori_utils.get_message_type(event), + "reload_session_id": (event.group_id if event.message_type == "group" else event.user_id) if not isinstance(event,satori.event.Event) else event.channel.id, + "delta_time": 0 } ) @@ -110,8 +116,9 @@ async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent): ), permission=SUPERUSER ).handle() +# Satori OK async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot, matcher: Matcher): - ulang = get_user_lang(str(event.user_id)) + ulang = get_user_lang(str(satori_utils.get_user_id(event))) stored_config: StoredConfig = common_db.where_one(StoredConfig(), default=StoredConfig()) if result.subcommands.get("set"): key, value = result.subcommands.get("set").args.get("key"), result.subcommands.get("set").args.get("value") @@ -157,15 +164,17 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot, matcher: Matcher ), permission=SUPERUSER ).handle() +# Satori OK async def _(event: T_MessageEvent, matcher: Matcher): global markdown_image # 切换图片模式,False以图片形式发送,True以markdown形式发送 - ulang = get_user_lang(str(event.user_id)) + ulang = get_user_lang(str(satori_utils.get_user_id(event))) stored_config: StoredConfig = common_db.where_one(StoredConfig(), default=StoredConfig()) stored_config.config["markdown_image"] = not stored_config.config.get("markdown_image", False) markdown_image = stored_config.config["markdown_image"] common_db.save(stored_config) - await matcher.finish(ulang.get("liteyuki.image_mode_on" if stored_config.config["markdown_image"] else "liteyuki.image_mode_off")) + await matcher.finish( + ulang.get("liteyuki.image_mode_on" if stored_config.config["markdown_image"] else "liteyuki.image_mode_off")) @on_alconna( @@ -174,6 +183,7 @@ async def _(event: T_MessageEvent, matcher: Matcher): ), aliases={"轻雪文档"}, ).handle() +# Satori OK async def _(matcher: Matcher): await matcher.finish("https://bot.liteyuki.icu/usage") @@ -226,7 +236,8 @@ async def _(result: Arparma, bot: T_Bot, event: T_MessageEvent, matcher: Matcher @Bot.on_calling_api # 图片模式检测 async def test_for_md_image(bot: T_Bot, api: str, data: dict): # 截获大图发送,转换为markdown发送 - if api in ["send_msg", "send_private_msg", "send_group_msg"] and markdown_image and data.get("user_id") != bot.self_id: + if api in ["send_msg", "send_private_msg", "send_group_msg"] and markdown_image and data.get( + "user_id") != bot.self_id: if api == "send_msg" and data.get("message_type") == "private" or api == "send_private_msg": session_type = "private" session_id = data.get("user_id") @@ -239,10 +250,12 @@ async def test_for_md_image(bot: T_Bot, api: str, data: dict): file: str = data["message"][0].data.get("file") # file:// http:// base64:// if file.startswith("http"): - result = await md.send_md(await md.image_async(file), bot, message_type=session_type, session_id=session_id) + result = await md.send_md(await md.image_async(file), bot, message_type=session_type, + session_id=session_id) elif file.startswith("file"): file = file.replace("file://", "") - result = await md.send_image(open(file, "rb").read(), bot, message_type=session_type, session_id=session_id) + result = await md.send_image(open(file, "rb").read(), bot, message_type=session_type, + session_id=session_id) elif file.startswith("base64"): file_bytes = base64.b64decode(file.replace("base64://", "")) result = await md.send_image(file_bytes, bot, message_type=session_type, session_id=session_id) @@ -269,6 +282,8 @@ async def on_shutdown(): @driver.on_bot_connect async def _(bot: T_Bot): temp_data = common_db.where_one(TempConfig(), default=TempConfig()) + if isinstance(bot, satori.Bot): + await satori_utils.user_infos.load_friends(bot) # 用于重启计时 if temp_data.data.get("reload", False): temp_data.data["reload"] = False @@ -279,13 +294,19 @@ async def _(bot: T_Bot): reload_session_id = temp_data.data.get("reload_session_id", 0) delta_time = temp_data.data.get("delta_time", 0) common_db.save(temp_data) # 更新数据 - await bot.call_api( - "send_msg", - message_type=reload_session_type, - user_id=reload_session_id, - group_id=reload_session_id, - message="Liteyuki reloaded in %.2f s" % delta_time - ) + if isinstance(bot,satori.Bot): + await bot.send_message( + channel_id=reload_session_id, + message="Liteyuki reloaded in %.2f s" % delta_time + ) + else: + await bot.call_api( + "send_msg", + message_type=reload_session_type, + user_id=reload_session_id, + group_id=reload_session_id, + message="Liteyuki reloaded in %.2f s" % delta_time + ) # 每天4点更新 @@ -304,21 +325,21 @@ async def every_day_update(): # 安全的需要用户id的api need_user_id = ( - "send_private_msg", - "send_msg", - "set_group_card", - "set_group_special_title", - "get_stranger_info", - "get_group_member_info" + "send_private_msg", + "send_msg", + "set_group_card", + "set_group_special_title", + "get_stranger_info", + "get_group_member_info" ) need_group_id = ( - "send_group_msg", - "send_msg", - "set_group_card", - "set_group_name", - "set_group_special_title", - "get_group_member_info", - "get_group_member_list", - "get_group_honor_info" + "send_group_msg", + "send_msg", + "set_group_card", + "set_group_name", + "set_group_special_title", + "get_group_member_info", + "get_group_member_list", + "get_group_honor_info" ) diff --git a/liteyuki/plugins/liteyuki_pacman/common.py b/liteyuki/plugins/liteyuki_pacman/common.py index 1db3b33..519a0cf 100644 --- a/liteyuki/plugins/liteyuki_pacman/common.py +++ b/liteyuki/plugins/liteyuki_pacman/common.py @@ -3,7 +3,9 @@ from typing import Optional import aiofiles import nonebot.plugin +from nonebot.adapters import satori +from liteyuki.utils import satori_utils from liteyuki.utils.base.data import LiteModel from liteyuki.utils.base.data_manager import GlobalPlugin, Group, User, group_db, plugin_db, user_db from liteyuki.utils.base.ly_typing import T_MessageEvent @@ -95,16 +97,23 @@ def get_plugin_session_enable(event: T_MessageEvent, plugin_name: str) -> bool: Returns: bool: 插件当前状态 """ - if event.message_type == "group": - group_id = str(event.group_id) + if isinstance(event, satori.event.Event): + if event.guild is not None: + message_type = "group" + else: + message_type = "private" + else: + message_type = event.message_type + if message_type == "group": + group_id = str(event.guild.id if isinstance(event, satori.event.Event) else event.group_id) if group_id not in __group_data: group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=group_id)) - __group_data[str(event.group_id)] = group + __group_data[str(group_id)] = group session = __group_data[group_id] else: # session: User = user_db.first(User(), "user_id = ?", event.user_id, default=User(user_id=str(event.user_id))) - user_id = str(event.user_id) + user_id = str(event.user.id if isinstance(event, satori.event.Event) else event.user_id) if user_id not in __user_data: user: User = user_db.where_one(User(), "user_id = ?", user_id, default=User(user_id=user_id)) __user_data[user_id] = user @@ -131,10 +140,12 @@ def set_plugin_session_enable(event: T_MessageEvent, plugin_name: str, enable: b Returns: """ - if event.message_type == "group": - session = group_db.where_one(Group(), "group_id = ?", str(event.group_id), default=Group(group_id=str(event.group_id))) + if satori_utils.get_message_type(event) == "group": + session = group_db.where_one(Group(), "group_id = ?", str(satori_utils.get_group_id(event)), + default=Group(group_id=str(satori_utils.get_group_id(event)))) else: - session = user_db.where_one(User(), "user_id = ?", str(event.user_id), default=User(user_id=str(event.user_id))) + session = user_db.where_one(User(), "user_id = ?", str(satori_utils.get_user_id(event)), + default=User(user_id=str(satori_utils.get_user_id(event)))) default_enable = get_plugin_default_enable(plugin_name) if default_enable: if enable: @@ -147,12 +158,12 @@ def set_plugin_session_enable(event: T_MessageEvent, plugin_name: str, enable: b else: session.enabled_plugins.remove(plugin_name) - if event.message_type == "group": - __group_data[str(event.group_id)] = session + if satori_utils.get_message_type(event) == "group": + __group_data[str(satori_utils.get_group_id(event))] = session print(session) group_db.save(session) else: - __user_data[str(event.user_id)] = session + __user_data[str(satori_utils.get_user_id(event))] = session user_db.save(session) diff --git a/liteyuki/plugins/liteyuki_satori_user_info/__init__.py b/liteyuki/plugins/liteyuki_satori_user_info/__init__.py new file mode 100644 index 0000000..5960e12 --- /dev/null +++ b/liteyuki/plugins/liteyuki_satori_user_info/__init__.py @@ -0,0 +1,16 @@ +from nonebot.plugin import PluginMetadata +from .auto_update import * + +__author__ = "expliyh" +__plugin_meta__ = PluginMetadata( + name="Satori 用户数据自动更新(临时措施)", + description="", + usage="", + type="application", + homepage="https://github.com/snowykami/LiteyukiBot", + extra={ + "liteyuki": True, + "toggleable" : True, + "default_enable" : True, + } +) diff --git a/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py b/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py new file mode 100644 index 0000000..08080f4 --- /dev/null +++ b/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py @@ -0,0 +1,22 @@ +from liteyuki.utils import satori_utils +from nonebot.message import event_preprocessor +# from nonebot_plugin_alconna.typings import Event +from liteyuki.utils.base.ly_typing import T_MessageEvent +from liteyuki.utils import satori_utils +from nonebot.adapters import satori +from nonebot_plugin_alconna.typings import Event +from liteyuki.plugins.liteyuki_status.counter_for_satori import satori_counter + + +@event_preprocessor +async def pre_handle(event: Event): + print("UPDATE_USER") + print(event.__dict__) + if isinstance(event, satori.MessageEvent): + if event.user.id == event.self_id: + satori_counter.msg_sent += 1 + else: + satori_counter.msg_received += 1 + if event.user.name is not None: + await satori_utils.user_infos.put(event.user) + print(event.user) diff --git a/liteyuki/plugins/liteyuki_statistics/stat_api.py b/liteyuki/plugins/liteyuki_statistics/stat_api.py index e6531ce..9c3c600 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_api.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_api.py @@ -9,7 +9,21 @@ from liteyuki.utils.message.npl import convert_seconds_to_time from contextvars import ContextVar -async def get_stat_msg_image(duration: int, period: int, group_id: str = None, bot_id: str = None, ulang: Language = Language()) -> bytes: +async def count_msg_by_bot_id(bot_id: str) -> int: + condition = " AND bot_id = ?" + condition_args = [bot_id] + + msg_rows = msg_db.where_all( + MessageEventModel(), + condition, + *condition_args + ) + + return len(msg_rows) + + +async def get_stat_msg_image(duration: int, period: int, group_id: str = None, bot_id: str = None, + ulang: Language = Language()) -> bytes: """ 获取统计消息 Args: @@ -58,15 +72,15 @@ async def get_stat_msg_image(duration: int, period: int, group_id: str = None, b msg_count[index] += 1 templates = { - "data": [ - { - "name" : ulang.get("stat.message") - + f" Period {convert_seconds_to_time(period)}" + f" Duration {convert_seconds_to_time(duration)}" - + (f" Group {group_id}" if group_id else "") + (f" Bot {bot_id}" if bot_id else ""), - "times" : timestamps, - "counts": msg_count - } - ] + "data": [ + { + "name": ulang.get("stat.message") + + f" Period {convert_seconds_to_time(period)}" + f" Duration {convert_seconds_to_time(duration)}" + + (f" Group {group_id}" if group_id else "") + (f" Bot {bot_id}" if bot_id else ""), + "times": timestamps, + "counts": msg_count + } + ] } return await template2image(get_path("templates/stat_msg.html"), templates, debug=True) diff --git a/liteyuki/plugins/liteyuki_statistics/stat_matchers.py b/liteyuki/plugins/liteyuki_statistics/stat_matchers.py index cbe87b7..582043a 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_matchers.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_matchers.py @@ -1,6 +1,7 @@ from nonebot import Bot, require from liteyuki.utils.message.npl import convert_duration, convert_time_to_seconds from .stat_api import * +from ...utils import satori_utils from ...utils.base.language import Language from ...utils.base.ly_typing import T_MessageEvent @@ -44,7 +45,7 @@ stat_msg = on_alconna( @stat_msg.assign("message") async def _(result: Arparma, event: T_MessageEvent, bot: Bot): - ulang = Language(event.user_id) + ulang = Language(satori_utils.get_user_id(event)) try: duration = convert_time_to_seconds(result.other_args.get("duration", "2d")) # 秒数 @@ -57,7 +58,7 @@ async def _(result: Arparma, event: T_MessageEvent, bot: Bot): bot_id = result.other_args.get("bot_id") if group_id in ["current", "c"]: - group_id = str(event.group_id) + group_id = str(satori_utils.get_group_id(event)) if group_id in ["all", "a"]: group_id = "all" diff --git a/liteyuki/plugins/liteyuki_statistics/stat_monitors.py b/liteyuki/plugins/liteyuki_statistics/stat_monitors.py index b6c2720..48ae005 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_monitors.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_monitors.py @@ -4,17 +4,24 @@ from nonebot import require from nonebot.message import event_postprocessor from liteyuki.utils.base.data import Database, LiteModel -from liteyuki.utils.base.ly_typing import v11 +from liteyuki.utils.base.ly_typing import v11, satori + +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent from .common import MessageEventModel, msg_db +from ...utils import satori_utils require("nonebot_plugin_alconna") - - - @event_postprocessor +async def general_event_monitor(bot: T_Bot, event: T_MessageEvent): + if isinstance(bot, satori.Bot): + return await satori_event_monitor(bot, event) + else: + return await onebot_v11_event_monitor(bot, event) + + async def onebot_v11_event_monitor(bot: v11.Bot, event: v11.MessageEvent): if event.message_type == "group": event: v11.GroupMessageEvent @@ -36,3 +43,26 @@ async def onebot_v11_event_monitor(bot: v11.Bot, event: v11.MessageEvent): message_type=event.message_type, ) msg_db.save(mem) + + +async def satori_event_monitor(bot: satori.Bot, event: satori.MessageEvent): + if event.guild is not None: + event: satori.MessageEvent + group_id = str(event.guild.id) + else: + group_id = "" + + mem = MessageEventModel( + time=int(time.time()), + bot_id=bot.self_id, + adapter="satori", + group_id=group_id, + user_id=str(event.user.id), + + message_id=str(event.message.id), + + message=event.message, + message_text=event.message.content, + message_type=satori_utils.get_message_type(event), + ) + msg_db.save(mem) diff --git a/liteyuki/plugins/liteyuki_status/api.py b/liteyuki/plugins/liteyuki_status/api.py index 5222451..a5894ac 100644 --- a/liteyuki/plugins/liteyuki_status/api.py +++ b/liteyuki/plugins/liteyuki_status/api.py @@ -5,23 +5,27 @@ import nonebot import psutil from cpuinfo import cpuinfo from nonebot import require +from nonebot.adapters import satori + from liteyuki.utils import __NAME__, __VERSION__ from liteyuki.utils.base.config import get_config from liteyuki.utils.base.data_manager import TempConfig, common_db from liteyuki.utils.base.language import Language from liteyuki.utils.base.resource import get_loaded_resource_packs, get_path from liteyuki.utils.message.html_tool import template2image +from liteyuki.utils import satori_utils +from .counter_for_satori import satori_counter require("nonebot_plugin_apscheduler") from nonebot_plugin_apscheduler import scheduler protocol_names = { - 0: "iPad", - 1: "Android Phone", - 2: "Android Watch", - 3: "Mac", - 5: "iPad", - 6: "Android Pad", + 0: "iPad", + 1: "Android Phone", + 2: "Android Watch", + 3: "Mac", + 5: "iPad", + 6: "Android Pad", } """ @@ -77,17 +81,18 @@ async def refresh_status_card(): ) -async def generate_status_card(bot: dict, hardware: dict, liteyuki: dict, lang="zh-CN", bot_id="0", use_cache=False) -> bytes: +async def generate_status_card(bot: dict, hardware: dict, liteyuki: dict, lang="zh-CN", bot_id="0", + use_cache=False) -> bytes: if not use_cache: return await template2image( get_path("templates/status.html", abs_path=True), { - "data": { - "bot" : bot, - "hardware" : hardware, - "liteyuki" : liteyuki, - "localization": get_local_data(lang) - } + "data": { + "bot": bot, + "hardware": hardware, + "liteyuki": liteyuki, + "localization": get_local_data(lang) + } }, debug=True ) @@ -100,32 +105,32 @@ async def generate_status_card(bot: dict, hardware: dict, liteyuki: dict, lang=" def get_local_data(lang_code) -> dict: lang = Language(lang_code) return { - "friends" : lang.get("status.friends"), - "groups" : lang.get("status.groups"), - "plugins" : lang.get("status.plugins"), - "bots" : lang.get("status.bots"), - "message_sent" : lang.get("status.message_sent"), - "message_received": lang.get("status.message_received"), - "cpu" : lang.get("status.cpu"), - "memory" : lang.get("status.memory"), - "swap" : lang.get("status.swap"), - "disk" : lang.get("status.disk"), + "friends": lang.get("status.friends"), + "groups": lang.get("status.groups"), + "plugins": lang.get("status.plugins"), + "bots": lang.get("status.bots"), + "message_sent": lang.get("status.message_sent"), + "message_received": lang.get("status.message_received"), + "cpu": lang.get("status.cpu"), + "memory": lang.get("status.memory"), + "swap": lang.get("status.swap"), + "disk": lang.get("status.disk"), - "usage" : lang.get("status.usage"), - "total" : lang.get("status.total"), - "used" : lang.get("status.used"), - "free" : lang.get("status.free"), + "usage": lang.get("status.usage"), + "total": lang.get("status.total"), + "used": lang.get("status.used"), + "free": lang.get("status.free"), - "days" : lang.get("status.days"), - "hours" : lang.get("status.hours"), - "minutes" : lang.get("status.minutes"), - "seconds" : lang.get("status.seconds"), - "runtime" : lang.get("status.runtime"), - "threads" : lang.get("status.threads"), - "cores" : lang.get("status.cores"), - "process" : lang.get("status.process"), - "resources" : lang.get("status.resources"), - "description" : lang.get("status.description"), + "days": lang.get("status.days"), + "hours": lang.get("status.hours"), + "minutes": lang.get("status.minutes"), + "seconds": lang.get("status.seconds"), + "runtime": lang.get("status.runtime"), + "threads": lang.get("status.threads"), + "cores": lang.get("status.cores"), + "process": lang.get("status.process"), + "resources": lang.get("status.resources"), + "description": lang.get("status.description"), } @@ -134,8 +139,8 @@ async def get_bots_data(self_id: str = "0") -> dict: Returns: """ result = { - "self_id": self_id, - "bots" : [], + "self_id": self_id, + "bots": [], } for bot_id, bot in nonebot.get_bots().items(): groups = 0 @@ -143,32 +148,45 @@ async def get_bots_data(self_id: str = "0") -> dict: status = {} bot_name = bot_id version_info = {} - try: - # API fetch - bot_name = (await bot.get_login_info())["nickname"] - groups = len(await bot.get_group_list()) - friends = len(await bot.get_friend_list()) - status = await bot.get_status() - version_info = await bot.get_version_info() - except Exception: - pass + if isinstance(bot, satori.Bot): + try: + bot_name = (await satori_utils.user_infos.get(bot.self_id)).name + groups = str(await satori_utils.count_groups(bot)) + friends = str(await satori_utils.count_friends(bot)) + status = {} + version_info = await bot.get_version_info() + except Exception: + pass + else: + try: + # API fetch + bot_name = (await bot.get_login_info())["nickname"] + groups = len(await bot.get_group_list()) + friends = len(await bot.get_friend_list()) + status = await bot.get_status() + version_info = await bot.get_version_info() + except Exception: + pass statistics = status.get("stat", {}) app_name = version_info.get("app_name", "UnknownImplementation") if app_name in ["Lagrange.OneBot", "LLOneBot", "Shamrock"]: icon = f"https://q.qlogo.cn/g?b=qq&nk={bot_id}&s=640" + elif isinstance(bot, satori.Bot): + app_name = "Satori" + icon = (await bot.login_get()).user.avatar else: icon = None bot_data = { - "name" : bot_name, - "icon" : icon, - "id" : bot_id, - "protocol_name" : protocol_names.get(version_info.get("protocol_name"), "Online"), - "groups" : groups, - "friends" : friends, - "message_sent" : statistics.get("message_sent", 0), - "message_received": statistics.get("message_received", 0), - "app_name" : app_name + "name": bot_name, + "icon": icon, + "id": bot_id, + "protocol_name": protocol_names.get(version_info.get("protocol_name"), "Online"), + "groups": groups, + "friends": friends, + "message_sent": satori_counter.msg_sent if isinstance(bot, satori.Bot) else statistics.get("message_sent", 0), + "message_received": satori_counter.msg_received if isinstance(bot, satori.Bot) else statistics.get("message_received", 0), + "app_name": app_name } result["bots"].append(bot_data) @@ -200,27 +218,27 @@ async def get_hardware_data() -> dict: else: brand = "Unknown" result = { - "cpu" : { - "percent": psutil.cpu_percent(), - "name" : f"{brand} {cpuinfo.get_cpu_info().get('arch', 'Unknown')}", - "cores" : psutil.cpu_count(logical=False), - "threads": psutil.cpu_count(logical=True), - "freq" : psutil.cpu_freq().current # MHz - }, - "memory": { - "percent" : mem.percent, - "total" : mem.total, - "used" : mem.used, - "free" : mem.free, - "usedProcess": mem_used_process, - }, - "swap" : { - "percent": swap.percent, - "total" : swap.total, - "used" : swap.used, - "free" : swap.free - }, - "disk" : [], + "cpu": { + "percent": psutil.cpu_percent(), + "name": f"{brand} {cpuinfo.get_cpu_info().get('arch', 'Unknown')}", + "cores": psutil.cpu_count(logical=False), + "threads": psutil.cpu_count(logical=True), + "freq": psutil.cpu_freq().current # MHz + }, + "memory": { + "percent": mem.percent, + "total": mem.total, + "used": mem.used, + "free": mem.free, + "usedProcess": mem_used_process, + }, + "swap": { + "percent": swap.percent, + "total": swap.total, + "used": swap.used, + "free": swap.free + }, + "disk": [], } for disk in psutil.disk_partitions(all=True): @@ -229,11 +247,11 @@ async def get_hardware_data() -> dict: if disk_usage.total == 0: continue # 虚拟磁盘 result["disk"].append({ - "name" : disk.mountpoint, - "percent": disk_usage.percent, - "total" : disk_usage.total, - "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: pass @@ -244,14 +262,14 @@ async def get_hardware_data() -> dict: async def get_liteyuki_data() -> dict: temp_data: TempConfig = common_db.where_one(TempConfig(), default=TempConfig()) result = { - "name" : list(get_config("nickname", [__NAME__]))[0], - "version" : __VERSION__, - "plugins" : len(nonebot.get_loaded_plugins()), - "resources": len(get_loaded_resource_packs()), - "nonebot" : f"{nonebot.__version__}", - "python" : f"{platform.python_implementation()} {platform.python_version()}", - "system" : f"{platform.system()} {platform.release()}", - "runtime" : time.time() - temp_data.data.get("start_time", time.time()), # 运行时间秒数 - "bots" : len(nonebot.get_bots()) + "name": list(get_config("nickname", [__NAME__]))[0], + "version": __VERSION__, + "plugins": len(nonebot.get_loaded_plugins()), + "resources": len(get_loaded_resource_packs()), + "nonebot": f"{nonebot.__version__}", + "python": f"{platform.python_implementation()} {platform.python_version()}", + "system": f"{platform.system()} {platform.release()}", + "runtime": time.time() - temp_data.data.get("start_time", time.time()), # 运行时间秒数 + "bots": len(nonebot.get_bots()) } return result diff --git a/liteyuki/plugins/liteyuki_status/counter_for_satori.py b/liteyuki/plugins/liteyuki_status/counter_for_satori.py new file mode 100644 index 0000000..7490730 --- /dev/null +++ b/liteyuki/plugins/liteyuki_status/counter_for_satori.py @@ -0,0 +1,10 @@ +class SatoriCounter: + msg_sent: int + msg_received: int + + def __init__(self): + self.msg_sent = 0 + self.msg_received = 0 + + +satori_counter = SatoriCounter() diff --git a/liteyuki/plugins/liteyuki_status/status.py b/liteyuki/plugins/liteyuki_status/status.py index 13f2500..23a43a0 100644 --- a/liteyuki/plugins/liteyuki_status/status.py +++ b/liteyuki/plugins/liteyuki_status/status.py @@ -4,6 +4,7 @@ from liteyuki.utils.base.resource import get_path from liteyuki.utils.message.html_tool import template2image from liteyuki.utils.base.language import get_user_lang from .api import * +from ...utils import satori_utils from ...utils.base.ly_typing import T_Bot, T_MessageEvent require("nonebot_plugin_alconna") @@ -27,7 +28,7 @@ status_alc = on_alconna( @status_alc.handle() async def _(event: T_MessageEvent, bot: T_Bot): - ulang = get_user_lang(event.user_id) + ulang = get_user_lang(satori_utils.get_user_id(event)) if ulang.lang_code in status_card_cache: image = status_card_cache[ulang.lang_code] else: diff --git a/liteyuki/plugins/liteyuki_uniblacklist/api.py b/liteyuki/plugins/liteyuki_uniblacklist/api.py index f5fb49e..52ca276 100644 --- a/liteyuki/plugins/liteyuki_uniblacklist/api.py +++ b/liteyuki/plugins/liteyuki_uniblacklist/api.py @@ -52,7 +52,6 @@ def get_uni_set() -> set: async def pre_handle(event: Event): try: user_id = str(event.get_user_id()) - except: return diff --git a/liteyuki/plugins/liteyuki_user/profile_manager.py b/liteyuki/plugins/liteyuki_user/profile_manager.py index 1ae6900..bb6c162 100644 --- a/liteyuki/plugins/liteyuki_user/profile_manager.py +++ b/liteyuki/plugins/liteyuki_user/profile_manager.py @@ -9,6 +9,7 @@ from liteyuki.utils.base.language import Language, change_user_lang, get_all_lan from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent from liteyuki.utils.message.message import MarkdownMessage as md from .const import representative_timezones_list +from ...utils import satori_utils require("nonebot_plugin_alconna") from nonebot_plugin_alconna import Alconna, Args, Arparma, Subcommand, on_alconna @@ -41,12 +42,13 @@ class Profile(LiteModel): @profile_alc.handle() async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot): - user: User = user_db.where_one(User(), "user_id = ?", event.user_id, default=User(user_id=str(event.user_id))) - ulang = get_user_lang(str(event.user_id)) + user: User = user_db.where_one(User(), "user_id = ?", satori_utils.get_user_id(event), + default=User(user_id=str(satori_utils.get_user_id(event)))) + ulang = get_user_lang(str(satori_utils.get_user_id(event))) if result.subcommands.get("set"): if result.subcommands["set"].args.get("value"): # 对合法性进行校验后设置 - r = set_profile(result.args["key"], result.args["value"], str(event.user_id)) + r = set_profile(result.args["key"], result.args["value"], str(satori_utils.get_user_id(event))) if r: user.profile[result.args["key"]] = result.args["value"] user_db.save(user) # 数据库保存 diff --git a/liteyuki/plugins/liteyuki_weather/qweather.py b/liteyuki/plugins/liteyuki_weather/qweather.py index 849b837..7d55f70 100644 --- a/liteyuki/plugins/liteyuki_weather/qweather.py +++ b/liteyuki/plugins/liteyuki_weather/qweather.py @@ -1,4 +1,5 @@ from nonebot import require, on_endswith +from nonebot.adapters import satori from nonebot.adapters.onebot.v11 import MessageSegment from nonebot.internal.matcher import Matcher @@ -10,6 +11,7 @@ from liteyuki.utils.base.data_manager import User, user_db from liteyuki.utils.base.language import Language, get_user_lang from liteyuki.utils.base.resource import get_path from liteyuki.utils.message.html_tool import template2image +from ...utils import satori_utils require("nonebot_plugin_alconna") from nonebot_plugin_alconna import on_alconna, Alconna, Args, MultiVar, Arparma @@ -26,7 +28,10 @@ async def _(result: Arparma, event: T_MessageEvent, matcher: Matcher): """await alconna.send("weather", city)""" kws = result.main_args.get("keywords") image = await get_weather_now_card(matcher, event, kws) - await matcher.finish(MessageSegment.image(image)) + if isinstance(event, satori.event.Event): + await matcher.finish(satori.MessageSegment.image(raw=image, mime="image/png")) + else: + await matcher.finish(MessageSegment.image(image)) @on_endswith(("天气", "weather")).handle() @@ -38,11 +43,11 @@ async def _(event: T_MessageEvent, matcher: Matcher): async def get_weather_now_card(matcher: Matcher, event: T_MessageEvent, keyword: list[str], tip: bool = True): - ulang = get_user_lang(event.user_id) + ulang = get_user_lang(satori_utils.get_user_id(event)) qw_lang = get_qw_lang(ulang.lang_code) key = get_config("weather_key") is_dev = get_memory_data("weather.is_dev", True) - user: User = user_db.where_one(User(), "user_id = ?", event.user_id, default=User()) + user: User = user_db.where_one(User(), "user_id = ?", satori_utils.get_user_id(event), default=User()) # params unit = user.profile.get("unit", "m") stored_location = user.profile.get("location", None) @@ -76,18 +81,18 @@ async def get_weather_now_card(matcher: Matcher, event: T_MessageEvent, keyword: image = await template2image( template=get_path("templates/weather_now.html", abs_path=True), templates={ - "data": { - "params" : { - "unit": unit, - "lang": ulang.lang_code, - }, - "weatherNow" : weather_now, - "weatherDaily" : weather_daily, - "weatherHourly": weather_hourly, - "aqi" : aqi, - "location" : location_data.dump(), - "localization" : get_local_data(ulang.lang_code) - } + "data": { + "params": { + "unit": unit, + "lang": ulang.lang_code, + }, + "weatherNow": weather_now, + "weatherDaily": weather_daily, + "weatherHourly": weather_hourly, + "aqi": aqi, + "location": location_data.dump(), + "localization": get_local_data(ulang.lang_code) + } }, debug=True, wait=1 diff --git a/liteyuki/utils/base/ly_typing.py b/liteyuki/utils/base/ly_typing.py index 4a16433..c67b7d5 100644 --- a/liteyuki/utils/base/ly_typing.py +++ b/liteyuki/utils/base/ly_typing.py @@ -1,7 +1,8 @@ from nonebot.adapters.onebot import v11, v12 +from nonebot.adapters import satori -T_Bot = v11.Bot | v12.Bot -T_GroupMessageEvent = v11.GroupMessageEvent | v12.GroupMessageEvent -T_PrivateMessageEvent = v11.PrivateMessageEvent | v12.PrivateMessageEvent -T_MessageEvent = v11.MessageEvent | v12.MessageEvent -T_Message = v11.Message | v12.Message +T_Bot = v11.Bot | v12.Bot | satori.Bot +T_GroupMessageEvent = v11.GroupMessageEvent | v12.GroupMessageEvent | satori.MessageEvent +T_PrivateMessageEvent = v11.PrivateMessageEvent | v12.PrivateMessageEvent | satori.MessageEvent +T_MessageEvent = v11.MessageEvent | v12.MessageEvent | satori.MessageEvent +T_Message = v11.Message | v12.Message | satori.Message diff --git a/liteyuki/utils/message/message.py b/liteyuki/utils/message/message.py index 32388cd..1ef1163 100644 --- a/liteyuki/utils/message/message.py +++ b/liteyuki/utils/message/message.py @@ -7,6 +7,7 @@ from PIL import Image import aiohttp import nonebot from nonebot import require +from nonebot.adapters import satori from nonebot.adapters.onebot import v11 from typing import Any, Type @@ -65,28 +66,37 @@ class MarkdownMessage: """ formatted_md = v11.unescape(markdown).replace("\n", r"\n").replace('"', r'\\\"') if event is not None and message_type is None: - message_type = event.message_type - session_id = event.user_id if event.message_type == "private" else event.group_id + if isinstance(event, satori.event.Event): + message_type = "private" if event.guild is None else "group" + group_id = event.guild.id if event.guild is not None else None + else: + assert event is not None + message_type = event.message_type + 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( "send_private_forward_msg", messages=[ - { - "type": "node", - "data": { - "content": [ - { - "data": { - "content": "{\"content\":\"%s\"}" % formatted_md, - }, - "type": "markdown" - } - ], - "name" : "[]", - "uin" : bot.self_id + { + "type": "node", + "data": { + "content": [ + { + "data": { + "content": "{\"content\":\"%s\"}" % formatted_md, + }, + "type": "markdown" } + ], + "name": "[]", + "uin": bot.self_id } + } ], user_id=bot.self_id @@ -96,12 +106,12 @@ class MarkdownMessage: group_id=session_id, message_type=message_type, message=[ - { - "type": "longmsg", - "data": { - "id": forward_id - } - }, + { + "type": "longmsg", + "data": { + "id": forward_id + } + }, ], **kwargs ) @@ -117,12 +127,19 @@ class MarkdownMessage: width=540, device_scale_factor=4 ) - data = await bot.send_msg( - message_type=message_type, - group_id=session_id, - user_id=session_id, - message=v11.MessageSegment.image(md_image_bytes), - ) + if isinstance(bot, satori.Bot): + msg_seg = satori.MessageSegment.image(raw=md_image_bytes,mime="image/png") + data = await bot.send( + event=event, + message=msg_seg + ) + else: + data = await bot.send_msg( + message_type=message_type, + group_id=session_id, + user_id=session_id, + message=v11.MessageSegment.image(md_image_bytes), + ) return data @staticmethod @@ -164,7 +181,8 @@ class MarkdownMessage: if method == 2: base64_string = base64.b64encode(image).decode("utf-8") data = await bot.call_api("upload_image", file=f"base64://{base64_string}") - await MarkdownMessage.send_md(MarkdownMessage.image(data, Image.open(io.BytesIO(image)).size), bot, event=event, message_type=message_type, + await MarkdownMessage.send_md(MarkdownMessage.image(data, Image.open(io.BytesIO(image)).size), bot, + event=event, message_type=message_type, session_id=session_id, **kwargs) # 其他实现端方案 @@ -172,13 +190,14 @@ class MarkdownMessage: image_message_id = (await bot.send_private_msg( user_id=bot.self_id, message=[ - v11.MessageSegment.image(file=image) + v11.MessageSegment.image(file=image) ] ))["message_id"] image_url = (await bot.get_msg(message_id=image_message_id))["message"][0]["data"]["url"] image_size = Image.open(io.BytesIO(image)).size image_md = MarkdownMessage.image(image_url, image_size) - return await MarkdownMessage.send_md(image_md, bot, message_type=message_type, session_id=session_id, event=event, **kwargs) + return await MarkdownMessage.send_md(image_md, bot, message_type=message_type, session_id=session_id, + event=event, **kwargs) if data is None: data = await bot.send_msg( diff --git a/liteyuki/utils/satori_utils/__init__.py b/liteyuki/utils/satori_utils/__init__.py new file mode 100644 index 0000000..b0f1550 --- /dev/null +++ b/liteyuki/utils/satori_utils/__init__.py @@ -0,0 +1,5 @@ +from .user_info import user_infos +from .get_message_type import get_message_type +from .event_tools import * +from .count_friends import count_friends +from .count_groups import count_groups diff --git a/liteyuki/utils/satori_utils/count_friends.py b/liteyuki/utils/satori_utils/count_friends.py new file mode 100644 index 0000000..3f7b18e --- /dev/null +++ b/liteyuki/utils/satori_utils/count_friends.py @@ -0,0 +1,13 @@ +from nonebot.adapters import satori + + +async def count_friends(bot: satori.Bot) -> int: + cnt: int = 0 + + friend_response = await bot.friend_list() + while friend_response.next is not None: + cnt += len(friend_response.data) + friend_response = await bot.friend_list(next_token=friend_response.next) + + cnt += len(friend_response.data) + return cnt - 1 diff --git a/liteyuki/utils/satori_utils/count_groups.py b/liteyuki/utils/satori_utils/count_groups.py new file mode 100644 index 0000000..789a40b --- /dev/null +++ b/liteyuki/utils/satori_utils/count_groups.py @@ -0,0 +1,13 @@ +from nonebot.adapters import satori + + +async def count_groups(bot: satori.Bot) -> int: + cnt: int = 0 + + group_response = await bot.guild_list() + while group_response.next is not None: + cnt += len(group_response.data) + group_response = await bot.friend_list(next_token=group_response.next) + + cnt += len(group_response.data) + return cnt - 1 diff --git a/liteyuki/utils/satori_utils/event_tools.py b/liteyuki/utils/satori_utils/event_tools.py new file mode 100644 index 0000000..dbc9423 --- /dev/null +++ b/liteyuki/utils/satori_utils/event_tools.py @@ -0,0 +1,17 @@ +from nonebot.adapters import satori + +from liteyuki.utils.base.ly_typing import T_MessageEvent + + +def get_user_id(event: T_MessageEvent): + if isinstance(event, satori.event.Event): + return event.user.id + else: + return event.user_id + + +def get_group_id(event: T_MessageEvent): + if isinstance(event, satori.event.Event): + return event.guild.id + else: + return event.group_id diff --git a/liteyuki/utils/satori_utils/get_message_type.py b/liteyuki/utils/satori_utils/get_message_type.py new file mode 100644 index 0000000..df5ab60 --- /dev/null +++ b/liteyuki/utils/satori_utils/get_message_type.py @@ -0,0 +1,10 @@ +from nonebot.adapters import satori + +from liteyuki.utils.base.ly_typing import T_MessageEvent + + +def get_message_type(event: T_MessageEvent) -> str: + if isinstance(event, satori.event.Event): + return "private" if event.guild is None else "group" + else: + return event.message_type diff --git a/liteyuki/utils/satori_utils/user_info.py b/liteyuki/utils/satori_utils/user_info.py new file mode 100644 index 0000000..f4b9b4b --- /dev/null +++ b/liteyuki/utils/satori_utils/user_info.py @@ -0,0 +1,38 @@ +import nonebot + +from nonebot.adapters import satori +from nonebot.adapters.satori.models import User + + +class UserInfo: + user_infos: dict = {} + + async def load_friends(self, bot: satori.Bot): + nonebot.logger.info("Update user info from friends") + friend_response = await bot.friend_list() + while friend_response.next is not None: + for i in friend_response.data: + i: User = i + self.user_infos[str(i.id)] = i + friend_response = await bot.friend_list(next_token=friend_response.next) + + for i in friend_response.data: + i: User = i + self.user_infos[str(i.id)] = i + + nonebot.logger.info("Finish update user info") + + async def get(self, uid: int | str) -> User | None: + try: + return self.user_infos[str(uid)] + except KeyError: + return None + + async def put(self, user: User): + self.user_infos[str(user.id)] = user + + def __init__(self): + pass + + +user_infos = UserInfo() diff --git a/main.py b/main.py index c78799c..7265f6c 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ import nonebot from nonebot.adapters.onebot import v11, v12 +from nonebot.adapters import satori from liteyuki.utils import init from liteyuki.utils.base.config import load_from_yaml from liteyuki.utils.base.data_manager import StoredConfig, common_db @@ -11,7 +12,10 @@ if __name__ == "__mp_main__": static_config = load_from_yaml("config.yml") store_config.update(static_config) nonebot.init(**store_config) - adapters = [v11.Adapter, v12.Adapter] + if not store_config['enable_satori']: + adapters = [v11.Adapter, v12.Adapter] + else: + adapters = [v11.Adapter, v12.Adapter, satori.Adapter] driver = nonebot.get_driver() for adapter in adapters: diff --git a/requirements.txt b/requirements.txt index 53c6f06..960afaa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ nonebot-plugin-htmlrender~=0.3.1 nonebot-adapter-onebot~=2.4.3 nonebot-plugin-alconna~=0.43.0 nonebot_plugin_apscheduler~=0.4.0 +nonebot-adapter-satori~=0.11.5 packaging~=23.1 psutil~=5.9.8 py-cpuinfo~=9.0.0