mirror of
https://github.com/LiteyukiStudio/LiteyukiBot.git
synced 2024-11-22 19:07:39 +08:00
✨ 添加对主流框架的消息io支持
This commit is contained in:
parent
237789e0d4
commit
0c942d9806
@ -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",
|
||||||
// },
|
// },
|
||||||
// ],
|
// ],
|
||||||
// },
|
// },
|
||||||
|
@ -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. 优化了通道的性能
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
|
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
插件作者
|
插件作者
|
||||||
|
@ -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())
|
||||||
|
24
src/liteyuki_plugins/hello_liteyuki.py
Normal file
24
src/liteyuki_plugins/hello_liteyuki.py
Normal 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("你好呀")
|
@ -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启动器",
|
||||||
|
@ -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(
|
||||||
|
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
40
src/nonebot_plugins/to_liteyuki.py
Normal file
40
src/nonebot_plugins/to_liteyuki.py
Normal 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"])
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type_ {{
|
* @type {{
|
||||||
* results: Array<{
|
* results: Array<{
|
||||||
* abstracts: string,
|
* abstracts: string,
|
||||||
* createdDt: string,
|
* createdDt: string,
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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()
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user