添加对主流框架的消息io支持

This commit is contained in:
snowy 2024-08-20 06:20:41 +08:00
parent 237789e0d4
commit 0c942d9806
26 changed files with 267 additions and 192 deletions

View File

@ -163,23 +163,23 @@ export default hopeTheme({
// src: "/assets/icon/chrome-mask-512.png", // src: "/assets/icon/chrome-mask-512.png",
// sizes: "512x512", // sizes: "512x512",
// purpose: "maskable", // purpose: "maskable",
// type_: "image/png", // type: "image/png",
// }, // },
// { // {
// src: "/assets/icon/chrome-mask-192.png", // src: "/assets/icon/chrome-mask-192.png",
// sizes: "192x192", // sizes: "192x192",
// purpose: "maskable", // purpose: "maskable",
// type_: "image/png", // type: "image/png",
// }, // },
// { // {
// src: "/assets/icon/chrome-512.png", // src: "/assets/icon/chrome-512.png",
// sizes: "512x512", // sizes: "512x512",
// type_: "image/png", // type: "image/png",
// }, // },
// { // {
// src: "/assets/icon/chrome-192.png", // src: "/assets/icon/chrome-192.png",
// sizes: "192x192", // sizes: "192x192",
// type_: "image/png", // type: "image/png",
// }, // },
// ], // ],
// shortcuts: [ // shortcuts: [
@ -192,7 +192,7 @@ export default hopeTheme({
// src: "/assets/icon/guide-maskable.png", // src: "/assets/icon/guide-maskable.png",
// sizes: "192x192", // sizes: "192x192",
// purpose: "maskable", // purpose: "maskable",
// type_: "image/png", // type: "image/png",
// }, // },
// ], // ],
// }, // },

View File

@ -20,7 +20,6 @@ from liteyuki.log import (
logger logger
) )
__all__ = [ __all__ = [
"LiteyukiBot", "LiteyukiBot",
"get_bot", "get_bot",
@ -34,6 +33,8 @@ __all__ = [
"logger", "logger",
] ]
__version__ = "6.3.7" # 测试版本号 __version__ = "6.3.8" # 测试版本号
# 6.3.8
# 1. 初步添加对聊天的支持
# 2. 优化了通道的性能

View File

@ -10,6 +10,7 @@ from typing import Any, Optional
from liteyuki.bot.lifespan import (LIFESPAN_FUNC, Lifespan) from liteyuki.bot.lifespan import (LIFESPAN_FUNC, Lifespan)
from liteyuki.comm.channel import get_channel from liteyuki.comm.channel import get_channel
from liteyuki.comm.storage import shared_memory
from liteyuki.core.manager import ProcessManager from liteyuki.core.manager import ProcessManager
from liteyuki.log import init_log, logger from liteyuki.log import init_log, logger
from liteyuki.plugin import load_plugin from liteyuki.plugin import load_plugin

View File

@ -60,7 +60,7 @@ class Channel(Generic[T]):
elif type_check: elif type_check:
if self._get_generic_type() is None: if self._get_generic_type() is None:
raise TypeError("Type hint is required for enforcing type_ check.") raise TypeError("Type hint is required for enforcing type check.")
self.type_check = type_check self.type_check = type_check
def _get_generic_type(self) -> Optional[type]: def _get_generic_type(self) -> Optional[type]:
@ -158,7 +158,7 @@ class Channel(Generic[T]):
async def wrapper(data: T) -> Any: async def wrapper(data: T) -> Any:
if filter_func is not None: if filter_func is not None:
if is_coroutine_callable(filter_func): if is_coroutine_callable(filter_func):
if not (await filter_func(data)): # type_: ignore if not (await filter_func(data)): # type: ignore
return return
else: else:
if not filter_func(data): if not filter_func(data):

View File

@ -13,9 +13,9 @@ from liteyuki.utils import IS_MAIN_PROCESS, is_coroutine_callable, run_coroutine
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
_locks = {} _locks = {}
_on_main_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type_: ignore _on_main_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type: ignore
"""主进程订阅者接收函数""" """主进程订阅者接收函数"""
_on_sub_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type_: ignore _on_sub_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type: ignore
"""子进程订阅者接收函数""" """子进程订阅者接收函数"""
@ -169,7 +169,7 @@ class KeyValueStore:
( (
"publish", "publish",
{ {
"channel_": channel_, "channel": channel_,
"data" : data "data" : data
} }
) )
@ -234,7 +234,7 @@ class KeyValueStore:
data = self.active_chan.receive() data = self.active_chan.receive()
if data[0] == "publish": if data[0] == "publish":
# 运行主进程订阅函数 # 运行主进程订阅函数
self.run_subscriber_receive_funcs(data[1]["channel_"], data[1]["data"]) self.run_subscriber_receive_funcs(data[1]["channel"], data[1]["data"])
# 推送给子进程 # 推送给子进程
self.publish_channel.send(data) self.publish_channel.send(data)
else: else:
@ -242,7 +242,7 @@ class KeyValueStore:
data = self.publish_channel.receive() data = self.publish_channel.receive()
if data[0] == "publish": if data[0] == "publish":
# 运行子进程订阅函数 # 运行子进程订阅函数
self.run_subscriber_receive_funcs(data[1]["channel_"], data[1]["data"]) self.run_subscriber_receive_funcs(data[1]["channel"], data[1]["data"])
class GlobalKeyValueStore: class GlobalKeyValueStore:

View File

@ -8,9 +8,49 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@File : event.py @File : event.py
@Software: PyCharm @Software: PyCharm
""" """
from typing import Any
from liteyuki.comm.storage import shared_memory
class Event: class Event:
def __init__(self, type_: str, data: dict): def __init__(self, type: str, data: dict[str, Any], bot_id: str, session_id: str, session_type: str, receive_channel: str = "event_to_nonebot"):
self.type = type_ """
事件
Args:
type: 类型
data: 数据
bot_id: 机器人ID
session_id: 会话ID
session_type: 会话类型
receive_channel: 接收频道
"""
self.type = type
self.data = data self.data = data
self.bot_id = bot_id
self.session_id = session_id
self.session_type = session_type
self.receive_channel = receive_channel
def __str__(self):
return f"Event(type={self.type}, data={self.data}, bot_id={self.bot_id}, session_id={self.session_id}, session_type={self.session_type})"
def reply(self, message: str | dict[str, Any]):
"""
回复消息
Args:
message:
Returns:
"""
to_nonebot_event = Event(
type=self.session_type,
data={
"message": message
},
bot_id=self.bot_id,
session_id=self.session_id,
session_type=self.session_type,
receive_channel="_"
)
print(to_nonebot_event)
shared_memory.publish(self.receive_channel, to_nonebot_event)

View File

@ -8,7 +8,55 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@File : matcher.py @File : matcher.py
@Software: PyCharm @Software: PyCharm
""" """
import traceback
from typing import Any, TypeAlias, Callable, Coroutine
from liteyuki import Event
from liteyuki.message.rule import Rule
EventHandler: TypeAlias = Callable[[Event], Coroutine[None, None, Any]]
class Matcher: class Matcher:
pass def __init__(self, rule: Rule, priority: int, block: bool):
"""
匹配器
Args:
rule: 规则
priority: 优先级 >= 0
block: 是否阻断后续优先级更低的匹配器
"""
self.rule = rule
self.priority = priority
self.block = block
self.handlers: list[EventHandler] = []
def __str__(self):
return f"Matcher(rule={self.rule}, priority={self.priority}, block={self.block})"
def handle(self, handler: EventHandler) -> EventHandler:
"""
添加处理函数装饰器
Args:
handler:
Returns:
EventHandler
"""
self.handlers.append(handler)
return handler
async def run(self, event: Event) -> None:
"""
运行处理函数
Args:
event:
Returns:
"""
if not await self.rule(event):
return
for handler in self.handlers:
try:
await handler(event)
except Exception:
traceback.print_exc()

View File

@ -8,11 +8,40 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@File : on.py @File : on.py
@Software: PyCharm @Software: PyCharm
""" """
import threading
from queue import Queue
from liteyuki.comm.storage import shared_memory
from liteyuki.log import logger
from liteyuki.message.event import Event
from liteyuki.message.matcher import Matcher from liteyuki.message.matcher import Matcher
from liteyuki.message.rule import Rule
_matcher_list: list[Matcher] = [] _matcher_list: list[Matcher] = []
_queue: Queue = Queue()
def on_message(permission) -> Matcher: @shared_memory.on_subscriber_receive("event_to_liteyuki")
pass async def _(event: Event):
current_priority = -1
for i, matcher in enumerate(_matcher_list):
logger.info(f"Running matcher {matcher} for event: {event}")
await matcher.run(event)
# 同优先级不阻断,不同优先级阻断
if current_priority != matcher.priority:
current_priority = matcher.priority
if matcher.block:
break
def on_message(rule: Rule = Rule(), priority: int = 0, block: bool = True) -> Matcher:
matcher = Matcher(rule, priority, block)
# 按照优先级插入
for i, m in enumerate(_matcher_list):
if m.priority < matcher.priority:
_matcher_list.insert(i, matcher)
break
else:
_matcher_list.append(matcher)
return matcher

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/19 下午10:55
@Author : snowykami
@Email : snowykami@outlook.com
@File : permission.py
@Software: PyCharm
"""
from typing import Callable, Coroutine, TypeAlias
PERMISSION_HANDLER: TypeAlias = Callable[[str], bool | Coroutine[None, None, bool]]
class Permission:
def __init__(self, handler: PERMISSION_HANDLER):
self.handler = handler

View File

@ -8,3 +8,26 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@File : rule.py @File : rule.py
@Software: PyCharm @Software: PyCharm
""" """
from typing import Optional, TypeAlias, Callable, Coroutine
from liteyuki.message.event import Event
RuleHandler: TypeAlias = Callable[[Event], Coroutine[None, None, bool]]
"""规则函数签名"""
class Rule:
def __init__(self, handler: Optional[RuleHandler] = None):
self.handler = handler
def __or__(self, other: "Rule") -> "Rule":
return Rule(lambda event: self.handler(event) or other.handler(event))
def __and__(self, other: "Rule") -> "Rule":
return Rule(lambda event: self.handler(event) and other.handler(event))
async def __call__(self, event: Event) -> bool:
if self.handler is None:
return True
return await self.handler(event)

View File

@ -117,7 +117,7 @@ def format_display_name(display_name: str, plugin_type: PluginType) -> str:
match plugin_type: match plugin_type:
case PluginType.APPLICATION: case PluginType.APPLICATION:
color = "m" color = "m"
case PluginType.IMPLEMENTATION: case PluginType.TEST:
color = "g" color = "g"
case PluginType.MODULE: case PluginType.MODULE:
color = "e" color = "e"

View File

@ -25,15 +25,15 @@ class PluginType(Enum):
SERVICE = "service" SERVICE = "service"
"""服务端例如AI绘画后端""" """服务端例如AI绘画后端"""
IMPLEMENTATION = "implementation"
"""实现端:例如与聊天平台的协议实现"""
MODULE = "module" MODULE = "module"
"""模块:导出对象给其他插件使用""" """模块:导出对象给其他插件使用"""
UNCLASSIFIED = "unclassified" UNCLASSIFIED = "unclassified"
"""未分类:默认值""" """未分类:默认值"""
TEST = "test"
"""测试:测试插件"""
class PluginMetadata(BaseModel): class PluginMetadata(BaseModel):
""" """
@ -47,7 +47,7 @@ class PluginMetadata(BaseModel):
插件描述 插件描述
usage: str usage: str
插件使用方法 插件使用方法
type_: str type: str
插件类型 插件类型
author: str author: str
插件作者 插件作者

View File

@ -1,20 +1,21 @@
import base64
import time import time
from typing import Any, AnyStr from typing import AnyStr
import time
from typing import AnyStr
import nonebot import nonebot
import pip import pip
from nonebot import Bot, get_driver, require from nonebot import get_driver, require
from nonebot.adapters import onebot, satori from nonebot.adapters import onebot, satori
from nonebot.adapters.onebot.v11 import Message, unescape from nonebot.adapters.onebot.v11 import Message, unescape
from nonebot.exception import MockApiException
from nonebot.internal.matcher import Matcher from nonebot.internal.matcher import Matcher
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
# from src.liteyuki.core import Reloader # from src.liteyuki.core import Reloader
from src.utils import event as event_utils, satori_utils from src.utils import event as event_utils, satori_utils
from src.utils.base.config import get_config, load_from_yaml from src.utils.base.config import get_config
from src.utils.base.data_manager import StoredConfig, TempConfig, common_db from src.utils.base.data_manager import TempConfig, common_db
from src.utils.base.language import get_user_lang from src.utils.base.language import get_user_lang
from src.utils.base.ly_typing import T_Bot, T_MessageEvent from src.utils.base.ly_typing import T_Bot, T_MessageEvent
from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
@ -24,13 +25,11 @@ from ..utils.base.ly_function import get_function
require("nonebot_plugin_alconna") require("nonebot_plugin_alconna")
require("nonebot_plugin_apscheduler") require("nonebot_plugin_apscheduler")
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma, MultiVar from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma, MultiVar
from nonebot_plugin_apscheduler import scheduler from nonebot_plugin_apscheduler import scheduler
driver = get_driver() driver = get_driver()
markdown_image = common_db.where_one(StoredConfig(), default=StoredConfig()).config.get("markdown_image", False)
@on_alconna( @on_alconna(
command=Alconna( command=Alconna(
@ -96,90 +95,6 @@ async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
reload() reload()
@on_alconna(
aliases={"配置"},
command=Alconna(
"config",
Subcommand(
"set",
Args["key", str]["value", Any],
alias=["设置"],
),
Subcommand(
"get",
Args["key", str, None],
alias=["查询", "获取"]
),
Subcommand(
"remove",
Args["key", str],
alias=["删除"]
)
),
permission=SUPERUSER
).handle()
# Satori OK
async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot, matcher: Matcher):
ulang = get_user_lang(str(event_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")
try:
value = eval(value)
except:
pass
stored_config.config[key] = value
common_db.save(stored_config)
await matcher.finish(f"{ulang.get('liteyuki.config_set_success', KEY=key, VAL=value)}")
elif result.subcommands.get("get"):
key = result.subcommands.get("get").args.get("key")
file_config = load_from_yaml("config.yml")
reply = f"{ulang.get('liteyuki.current_config')}"
if key:
reply += f"```dotenv\n{key}={file_config.get(key, stored_config.config.get(key))}\n```"
else:
reply = f"{ulang.get('liteyuki.current_config')}"
reply += f"\n{ulang.get('liteyuki.static_config')}\n```dotenv"
for k, v in file_config.items():
reply += f"\n{k}={v}"
reply += "\n```"
if len(stored_config.config) > 0:
reply += f"\n{ulang.get('liteyuki.stored_config')}\n```dotenv"
for k, v in stored_config.config.items():
reply += f"\n{k}={v} {type(v)}"
reply += "\n```"
await md.send_md(reply, bot, event=event)
elif result.subcommands.get("remove"):
key = result.subcommands.get("remove").args.get("key")
if key in stored_config.config:
stored_config.config.pop(key)
common_db.save(stored_config)
await matcher.finish(f"{ulang.get('liteyuki.config_remove_success', KEY=key)}")
else:
await matcher.finish(f"{ulang.get('liteyuki.invalid_command', TEXT=key)}")
@on_alconna(
aliases={"切换图片模式"},
command=Alconna(
"switch-image-mode"
),
permission=SUPERUSER
).handle()
# Satori OK
async def _(event: T_MessageEvent, matcher: Matcher):
global markdown_image
# 切换图片模式False以图片形式发送True以markdown形式发送
ulang = get_user_lang(str(event_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"))
@on_alconna( @on_alconna(
command=Alconna( command=Alconna(
"liteyuki-docs", "liteyuki-docs",
@ -285,38 +200,6 @@ async def _(result: Arparma, bot: T_Bot, event: T_MessageEvent, matcher: Matcher
await matcher.finish(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}") await matcher.finish(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
# system hook
@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 == "send_msg" and data.get("message_type") == "private" or api == "send_private_msg":
session_type = "private"
session_id = data.get("user_id")
elif api == "send_msg" and data.get("message_type") == "group" or api == "send_group_msg":
session_type = "group"
session_id = data.get("group_id")
else:
return
if len(data.get("message", [])) == 1 and data["message"][0].get("type_") == "image":
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)
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)
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)
else:
return
raise MockApiException(result=result)
@driver.on_startup @driver.on_startup
async def on_startup(): async def on_startup():
temp_data = common_db.where_one(TempConfig(), default=TempConfig()) temp_data = common_db.where_one(TempConfig(), default=TempConfig())

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/20 上午5:12
@Author : snowykami
@Email : snowykami@outlook.com
@File : liteyuki_reply.py
@Software: PyCharm
"""
from liteyuki.plugin import PluginMetadata, PluginType
from liteyuki.message.on import on_message
from liteyuki.message.event import Event
__plugin_meta__ = PluginMetadata(
name="你好轻雪",
type=PluginType.TEST
)
@on_message().handle
async def _(event: Event):
if str(event.data["raw_message"]) == "你好轻雪":
event.reply("你好呀")

View File

@ -12,7 +12,7 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
import nonebot import nonebot
from liteyuki.utils import IS_MAIN_PROCESS from liteyuki.utils import IS_MAIN_PROCESS
from liteyuki.plugin import PluginMetadata, PluginType from liteyuki.plugin import PluginMetadata, PluginType
from .nb_utils import adapter_manager, driver_manager # type_: ignore from .nb_utils import adapter_manager, driver_manager # type: ignore
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="NoneBot2启动器", name="NoneBot2启动器",

View File

@ -1,8 +1,8 @@
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from liteyuki import get_bot from liteyuki import get_bot
from .crt_matchers import * # type_: ignore from .crt_matchers import * # type: ignore
from .rt_guide import * # type_: ignore from .rt_guide import * # type: ignore
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(

View File

@ -339,7 +339,7 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot, npm: Matcher):
await md.send_md(f"{info}\n\n" f"```\n{log}\n```", bot, event=event) await md.send_md(f"{info}\n\n" f"```\n{log}\n```", bot, event=event)
elif sc.get("uninstall") and perm_s: elif sc.get("uninstall") and perm_s:
plugin_name: str = result.subcommands["uninstall"].args.get("plugin_name") # type_: ignore plugin_name: str = result.subcommands["uninstall"].args.get("plugin_name") # type: ignore
found_installed_plugin: InstalledPlugin = plugin_db.where_one( found_installed_plugin: InstalledPlugin = plugin_db.where_one(
InstalledPlugin(), "module_name = ?", plugin_name InstalledPlugin(), "module_name = ?", plugin_name
) )

View File

@ -69,6 +69,8 @@ async def get_stat_msg_image(
condition, condition,
*condition_args *condition_args
) )
if not msg_rows:
msg_rows = []
timestamps = [] timestamps = []
msg_count = [] msg_count = []
msg_rows.sort(key=lambda x: x.time) msg_rows.sort(key=lambda x: x.time)

View File

@ -98,8 +98,10 @@ async def _(result: Arparma, event: T_MessageEvent, bot: Bot):
bot_id = result.other_args.get("bot_id") bot_id = result.other_args.get("bot_id")
user_id = result.other_args.get("user_id") user_id = result.other_args.get("user_id")
if group_id in ["current", "c"]: if group_id in ["current", "c"] and hasattr(event, "group_id"):
group_id = str(event_utils.get_group_id(event)) group_id = str(event_utils.get_group_id(event))
else:
group_id = "all"
if group_id in ["all", "a"]: if group_id in ["all", "a"]:
group_id = "all" group_id = "all"

View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/20 上午5:10
@Author : snowykami
@Email : snowykami@outlook.com
@File : to_liteyuki.py
@Software: PyCharm
"""
from nonebot import Bot, get_bot, on_message
from nonebot.plugin import PluginMetadata
from nonebot.adapters.onebot.v11 import MessageEvent, Bot
from liteyuki.comm.storage import shared_memory
from liteyuki.message.event import Event
__plugin_meta__ = PluginMetadata(
name="轻雪物流",
description="把消息事件传递给轻雪",
usage="无需使用",
)
@on_message().handle()
async def _(bot: Bot, event: MessageEvent):
liteyuki_event = Event(
type=event.message_type,
data=event.dict(),
bot_id=bot.self_id,
session_id=str(event.user_id if event.message_type == "private" else event.group_id),
session_type=event.message_type,
receive_channel="event_to_nonebot"
)
shared_memory.publish("event_to_liteyuki", liteyuki_event)
@shared_memory.on_subscriber_receive("event_to_nonebot")
async def _(event: Event):
bot: Bot = get_bot(event.bot_id)
await bot.send_msg(message_type=event.type, user_id=int(event.session_id), group_id=int(event.session_id), message=event.data["message"])

View File

@ -2,7 +2,7 @@
/** /**
* @type_ {{ * @type {{
* results: Array<{ * results: Array<{
* abstracts: string, * abstracts: string,
* createdDt: string, * createdDt: string,

View File

@ -12,7 +12,7 @@
* @property {Weather} weather - The weather data. * @property {Weather} weather - The weather data.
*/ */
/** @type_ {Data} */ /** @type {Data} */
let data = JSON.parse(document.getElementById("data").innerText) let data = JSON.parse(document.getElementById("data").innerText)

View File

@ -28,7 +28,7 @@ class Database:
os.makedirs(os.path.dirname(db_name)) os.makedirs(os.path.dirname(db_name))
self.db_name = db_name self.db_name = db_name
self.conn = sqlite3.connect(db_name) self.conn = sqlite3.connect(db_name, check_same_thread=False)
self.cursor = self.conn.cursor() self.cursor = self.conn.cursor()
self._on_save_callbacks = [] self._on_save_callbacks = []
@ -105,12 +105,12 @@ class Database:
return [model_type(**self._load(dict(zip(fields, result)))) for result in results] return [model_type(**self._load(dict(zip(fields, result)))) for result in results]
def save(self, *args: LiteModel): def save(self, *args: LiteModel):
"""增/改操作 self.returns_ = """增/改操作
Args: Args:
*args: *args:
Returns: Returns:
""" """
table_list = [item[0] for item in self.cursor.execute("SELECT name FROM sqlite_master WHERE type_='table'").fetchall()] table_list = [item[0] for item in self.cursor.execute("SELECT name FROM sqlite_master WHERE type ='table'").fetchall()]
for model in args: for model in args:
logger.debug(f"Upserting {model}") logger.debug(f"Upserting {model}")
if not model.TABLE_NAME: if not model.TABLE_NAME:

View File

@ -65,7 +65,7 @@ def auto_migrate():
user_db.auto_migrate(User()) user_db.auto_migrate(User())
group_db.auto_migrate(Group()) group_db.auto_migrate(Group())
plugin_db.auto_migrate(InstalledPlugin(), GlobalPlugin()) plugin_db.auto_migrate(InstalledPlugin(), GlobalPlugin())
common_db.auto_migrate(GlobalPlugin(), StoredConfig(), TempConfig()) common_db.auto_migrate(GlobalPlugin(), TempConfig())
auto_migrate() auto_migrate()

View File

@ -1,6 +1,6 @@
from nonebot.adapters import satori from nonebot.adapters import satori
from nonebot.adapters import onebot
from src.utils.base.ly_typing import T_MessageEvent from src.utils.base.ly_typing import T_MessageEvent, T_GroupMessageEvent
def get_user_id(event: T_MessageEvent): def get_user_id(event: T_MessageEvent):
@ -10,11 +10,13 @@ def get_user_id(event: T_MessageEvent):
return event.user_id return event.user_id
def get_group_id(event: T_MessageEvent): def get_group_id(event: T_GroupMessageEvent):
if isinstance(event, satori.event.Event): if isinstance(event, satori.event.Event):
return event.guild.id return event.guild.id
else: elif isinstance(event, onebot.v11.GroupMessageEvent):
return event.group_id return event.group_id
else:
return None
def get_message_type(event: T_MessageEvent) -> str: def get_message_type(event: T_MessageEvent) -> str:

View File

@ -83,14 +83,14 @@ class MarkdownMessage:
"send_private_forward_msg", "send_private_forward_msg",
messages=[ messages=[
{ {
"type_": "node", "type": "node",
"data": { "data": {
"content": [ "content": [
{ {
"data": { "data": {
"content": "{\"content\":\"%s\"}" % formatted_md, "content": "{\"content\":\"%s\"}" % formatted_md,
}, },
"type_": "markdown" "type": "markdown"
} }
], ],
"name": "[]", "name": "[]",
@ -107,7 +107,7 @@ class MarkdownMessage:
message_type=message_type, message_type=message_type,
message=[ message=[
{ {
"type_": "longmsg", "type": "longmsg",
"data": { "data": {
"id": forward_id "id": forward_id
} }
@ -156,7 +156,7 @@ class MarkdownMessage:
Args: Args:
image: 图片字节流或图片本地路径链接请使用Markdown.image_async方法获取后通过send_md发送 image: 图片字节流或图片本地路径链接请使用Markdown.image_async方法获取后通过send_md发送
bot: bot instance bot: bot instance
message_type: message type_ message_type: message type
session_id: session id session_id: session id
event: event event: event
kwargs: other arguments kwargs: other arguments