diff --git a/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py b/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py index b5f2a1a..08080f4 100644 --- a/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py +++ b/liteyuki/plugins/liteyuki_satori_user_info/auto_update.py @@ -5,12 +5,18 @@ 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_monitors.py b/liteyuki/plugins/liteyuki_statistics/stat_monitors.py index f9a1abc..48ae005 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_monitors.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_monitors.py @@ -6,15 +6,22 @@ from nonebot.message import event_postprocessor from liteyuki.utils.base.data import Database, LiteModel 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 @@ -56,6 +63,6 @@ async def satori_event_monitor(bot: satori.Bot, event: satori.MessageEvent): message=event.message, message_text=event.message.content, - message_type=event.message_type, + 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/utils/satori_utils/__init__.py b/liteyuki/utils/satori_utils/__init__.py index 64f569e..b0f1550 100644 --- a/liteyuki/utils/satori_utils/__init__.py +++ b/liteyuki/utils/satori_utils/__init__.py @@ -1,3 +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