This commit is contained in:
EillesWan 2024-08-23 17:58:49 +08:00
commit e8ec2ee28a
16 changed files with 209 additions and 40 deletions

3
.gitignore vendored
View File

@ -53,4 +53,5 @@ dist
doc doc
mkdoc2.py mkdoc2.py
result.json

View File

@ -2,6 +2,9 @@
<div class="item-card"> <div class="item-card">
<div class="item-name">{{ props.item.name }}</div> <div class="item-name">{{ props.item.name }}</div>
<div class="item-description">{{ props.item.desc }}</div> <div class="item-description">{{ props.item.desc }}</div>
<div class="tags">
<span class="tag" v-for="tag in props.item.tags" :key="tag" :style=getTagStyle(tag.color)>{{ tag.label }}</span>
</div>
<div class="item-bar"> <div class="item-bar">
<!-- 三个可点击svg一个github一个下载一个可点击"https://github.com/{{ username }}.png?size=80"个人头像配上id--> <!-- 三个可点击svg一个github一个下载一个可点击"https://github.com/{{ username }}.png?size=80"个人头像配上id-->
<a :href=props.item.homepage class="btn"> <a :href=props.item.homepage class="btn">
@ -45,6 +48,21 @@ const copyToClipboard = () => {
}) })
} }
const getTagStyle = (backgroundColor: string) => {
// RGB
const rgb = backgroundColor.replace(/^#/, '');
const [r, g, b] = rgb.match(/.{2}/g).map(x => parseInt(x, 16));
//
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
//
return {
backgroundColor: backgroundColor,
color: brightness > 128 ? '#000' : '#fff'
};
};
// //
</script> </script>
@ -123,4 +141,12 @@ button {
justify-content: space-between; justify-content: space-between;
color: #00000055; color: #00000055;
} }
.tag {
display: inline-block;
padding: 2px 5px;
margin-right: 5px;
border-radius: 5px;
font-size: 12px;
}
</style> </style>

View File

@ -3,12 +3,12 @@
"module_name": "liteyukibot-plugin-nonebot", "module_name": "liteyukibot-plugin-nonebot",
"project_link": "liteyukibot-plugin-nonebot", "project_link": "liteyukibot-plugin-nonebot",
"name": "NoneBot插件", "name": "NoneBot插件",
"desc": "在轻雪中使用NoneBot为NoneBot开发者提供了更多便捷功能(已内置)", "desc": "在轻雪中使用NoneBot内置轻雪--NoneBot会话控制器插件为NoneBot开发者提供了更多便捷功能(已内置)",
"author": "snowykami", "author": "snowykami",
"homepage": "https://github.com/LiteyukiStudio/liteyukibot-plugin-nonebot", "homepage": "https://github.com/LiteyukiStudio/liteyukibot-plugin-nonebot",
"tags": [ "tags": [
{ {
"label": "server", "label": "app",
"color": "#aeeaa8" "color": "#aeeaa8"
} }
], ],
@ -16,5 +16,27 @@
"type": "application", "type": "application",
"valid": true, "valid": true,
"version": "rolling" "version": "rolling"
},
{
"module_name": "liteyukibot-plugin-antidislink",
"project_link": "liteyukibot-plugin-antidislink",
"name": "防断联插件",
"desc": "防止你的群友断联化",
"author": "snowykami",
"homepage": "https://github.com/snowykami/liteyukibot-plugin-antidislink",
"tags": [
{
"label": "app",
"color": "#aeeaa8"
},
{
"label": "dislink",
"color": "#d0e9ff"
}
],
"is_official": true,
"type": "application",
"valid": true,
"version": "rolling"
} }
] ]

View File

@ -33,7 +33,9 @@ __all__ = [
"logger", "logger",
] ]
__version__ = "6.3.8" # 测试版本号 __version__ = "6.3.9" # 测试版本号
# 6.3.9
# 更改了on语法
# 6.3.8 # 6.3.8
# 1. 初步添加对聊天的支持 # 1. 初步添加对聊天的支持

View File

@ -38,7 +38,7 @@ class Channel(Generic[T]):
有两种接收工作方式但是只能选择一种主动接收和被动接收主动接收使用 `receive` 方法被动接收使用 `on_receive` 装饰器 有两种接收工作方式但是只能选择一种主动接收和被动接收主动接收使用 `receive` 方法被动接收使用 `on_receive` 装饰器
""" """
def __init__(self, _id: str, type_check: Optional[bool] = None): def __init__(self, _id: str = "", type_check: Optional[bool] = None):
""" """
初始化通道 初始化通道
Args: Args:
@ -217,16 +217,6 @@ class Channel(Generic[T]):
data = self.conn_recv.recv() data = self.conn_recv.recv()
self._run_on_sub_receive_funcs(data) self._run_on_sub_receive_funcs(data)
def __iter__(self):
return self
def __next__(self) -> Any:
return self.receive()
def __del__(self):
self.close()
logger.debug(f"Channel {self.name} deleted.")
"""子进程可用的主动和被动通道""" """子进程可用的主动和被动通道"""
active_channel: Optional["Channel"] = None active_channel: Optional["Channel"] = None

View File

@ -8,7 +8,7 @@ from typing import Any, Coroutine, Optional, TypeAlias, Callable
from liteyuki.comm import channel from liteyuki.comm import channel
from liteyuki.comm.channel import Channel, ON_RECEIVE_FUNC, ASYNC_ON_RECEIVE_FUNC from liteyuki.comm.channel import Channel, ON_RECEIVE_FUNC, ASYNC_ON_RECEIVE_FUNC
from liteyuki.utils import IS_MAIN_PROCESS, is_coroutine_callable, run_coroutine from liteyuki.utils import IS_MAIN_PROCESS, is_coroutine_callable, run_coroutine, run_coroutine_in_thread
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
_locks = {} _locks = {}
@ -220,10 +220,10 @@ class KeyValueStore:
""" """
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
if channel_ in _on_main_subscriber_receive_funcs and _on_main_subscriber_receive_funcs[channel_]: if channel_ in _on_main_subscriber_receive_funcs and _on_main_subscriber_receive_funcs[channel_]:
run_coroutine(*[func(data) for func in _on_main_subscriber_receive_funcs[channel_]]) run_coroutine_in_thread(*[func(data) for func in _on_main_subscriber_receive_funcs[channel_]])
else: else:
if channel_ in _on_sub_subscriber_receive_funcs and _on_sub_subscriber_receive_funcs[channel_]: if channel_ in _on_sub_subscriber_receive_funcs and _on_sub_subscriber_receive_funcs[channel_]:
run_coroutine(*[func(data) for func in _on_sub_subscriber_receive_funcs[channel_]]) run_coroutine_in_thread(*[func(data) for func in _on_sub_subscriber_receive_funcs[channel_]])
def _start_receive_loop(self): def _start_receive_loop(self):
""" """

View File

@ -34,16 +34,17 @@ class Matcher:
def __str__(self): def __str__(self):
return f"Matcher(rule={self.rule}, priority={self.priority}, block={self.block})" return f"Matcher(rule={self.rule}, priority={self.priority}, block={self.block})"
def handle(self, handler: EventHandler) -> EventHandler: def handle(self) -> Callable[[EventHandler], EventHandler]:
""" """
添加处理函数装饰器 添加处理函数装饰器
Args:
handler:
Returns: Returns:
EventHandler 装饰器 handler
""" """
self.handlers.append(handler) def decorator(handler: EventHandler) -> EventHandler:
return handler self.handlers.append(handler)
return handler
return decorator
async def run(self, event: MessageEvent) -> None: async def run(self, event: MessageEvent) -> None:
""" """

View File

@ -15,7 +15,7 @@ from liteyuki.comm.storage import shared_memory
from liteyuki.log import logger from liteyuki.log import logger
from liteyuki.message.event import MessageEvent from liteyuki.message.event import MessageEvent
from liteyuki.message.matcher import Matcher from liteyuki.message.matcher import Matcher
from liteyuki.message.rule import Rule from liteyuki.message.rule import Rule, empty_rule
_matcher_list: list[Matcher] = [] _matcher_list: list[Matcher] = []
_queue: Queue = Queue() _queue: Queue = Queue()
@ -36,7 +36,7 @@ async def _(event: MessageEvent):
break break
def on_message(rule: Rule = Rule(), priority: int = 0, block: bool = True) -> Matcher: def on_message(rule: Rule = empty_rule, priority: int = 0, block: bool = False) -> Matcher:
matcher = Matcher(rule, priority, block) matcher = Matcher(rule, priority, block)
# 按照优先级插入 # 按照优先级插入
for i, m in enumerate(_matcher_list): for i, m in enumerate(_matcher_list):
@ -46,3 +46,10 @@ def on_message(rule: Rule = Rule(), priority: int = 0, block: bool = True) -> Ma
else: else:
_matcher_list.append(matcher) _matcher_list.append(matcher)
return matcher return matcher
def on_keywords(keywords: list[str], rule=empty_rule, priority: int = 0, block: bool = False) -> Matcher:
@Rule
async def on_keywords_rule(event: MessageEvent):
return any(keyword in event.raw_message for keyword in keywords)
return on_message(on_keywords_rule & rule, priority, block)

View File

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

View File

@ -209,13 +209,14 @@ def get_module_info_normal(file_path: str, ignore_private: bool = True) -> Modul
return module_info return module_info
def generate_markdown(module_info: ModuleInfo, front_matter=None) -> str: def generate_markdown(module_info: ModuleInfo, front_matter=None, lang: str = "zh-CN") -> str:
""" """
生成模块的Markdown 生成模块的Markdown
你可在此自定义生成的Markdown格式 你可在此自定义生成的Markdown格式
Args: Args:
module_info: 模块信息 module_info: 模块信息
front_matter: 自定义选项title, index, icon, category front_matter: 自定义选项title, index, icon, category
lang: 语言
Returns: Returns:
Markdown 字符串 Markdown 字符串
""" """
@ -261,7 +262,13 @@ def generate_markdown(module_info: ModuleInfo, front_matter=None) -> str:
method.docstring = method.docstring.replace("\n", "\n\n") method.docstring = method.docstring.replace("\n", "\n\n")
content += f"&emsp;{method.docstring}\n\n" content += f"&emsp;{method.docstring}\n\n"
# 函数源代码可展开区域 # 函数源代码可展开区域
content += f"<details>\n<summary>源代码</summary>\n\n```python\n{method.source_code}\n```\n</details>\n\n"
if lang == "zh-CN":
TEXT_SOURCE_CODE = "源代码"
else:
TEXT_SOURCE_CODE = "Source Code"
content += f"<details>\n<summary>{TEXT_SOURCE_CODE}</summary>\n\n```python\n{method.source_code}\n```\n</details>\n\n"
for attr in cls.attributes: for attr in cls.attributes:
content += f"### &emsp; ***attr*** `{attr.name}: {attr.type}`\n\n" content += f"### &emsp; ***attr*** `{attr.name}: {attr.type}`\n\n"
@ -278,7 +285,7 @@ def generate_markdown(module_info: ModuleInfo, front_matter=None) -> str:
return content return content
def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, ignored_paths=None): def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, lang: str = "zh-CN", ignored_paths=None):
""" """
生成文档 生成文档
Args: Args:
@ -286,6 +293,7 @@ def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, i
output_dir: 输出文件夹 output_dir: 输出文件夹
with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b True时例如docs/api/module/module_a.md docs/api/module/module_b.md with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b True时例如docs/api/module/module_a.md docs/api/module/module_b.md
ignored_paths: 忽略的路径 ignored_paths: 忽略的路径
lang: 语言
""" """
if ignored_paths is None: if ignored_paths is None:
ignored_paths = [] ignored_paths = []
@ -345,5 +353,5 @@ def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, i
# 入口脚本 # 入口脚本
if __name__ == '__main__': if __name__ == '__main__':
# 这里填入你的模块路径 # 这里填入你的模块路径
generate_docs('liteyuki', 'docs/dev/api', with_top=False, ignored_paths=["liteyuki/plugins"]) generate_docs('liteyuki', 'docs/dev/api', with_top=False, ignored_paths=["liteyuki/plugins"], lang="zh-CN")
generate_docs('liteyuki', 'docs/en/dev/api', with_top=False, ignored_paths=["liteyuki/plugins"]) generate_docs('liteyuki', 'docs/en/dev/api', with_top=False, ignored_paths=["liteyuki/plugins"], lang="en")

View File

@ -5,6 +5,7 @@
import asyncio import asyncio
import inspect import inspect
import multiprocessing import multiprocessing
import threading
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Coroutine from typing import Any, Callable, Coroutine
@ -61,6 +62,16 @@ def run_coroutine(*coro: Coroutine):
# 捕获其他异常,防止协程被重复等待 # 捕获其他异常,防止协程被重复等待
logger.error(f"Exception occurred: {e}") logger.error(f"Exception occurred: {e}")
def run_coroutine_in_thread(*coro: Coroutine):
"""
在新线程中运行协程
Args:
coro:
Returns:
"""
threading.Thread(target=run_coroutine, args=coro, daemon=True).start()
def path_to_module_name(path: Path) -> str: def path_to_module_name(path: Path) -> str:
""" """

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/22 上午9:06
@Author : snowykami
@Email : snowykami@outlook.com
@File : anti_dislink.py
@Software: PyCharm
"""
import random
from liteyuki.plugin import PluginMetadata, PluginType
from liteyuki.message.on import on_keywords
__plugin_meta__ = PluginMetadata(
name="严禁断联化",
type=PluginType.APPLICATION
)
@on_keywords(["看看你的", "看看j", "给我看看"]).handle()
async def _(event):
event.reply(random.choice(["No dislink", "严禁断联化"]))

View File

@ -14,11 +14,11 @@ from liteyuki.message.event import MessageEvent
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="你好轻雪", name="你好轻雪",
type=PluginType.TEST type=PluginType.APPLICATION
) )
@on_message().handle @on_message().handle()
async def _(event: MessageEvent): async def _(event: MessageEvent):
if str(event.raw_message) == "你好轻雪": if str(event.raw_message) == "你好轻雪":
event.reply("你好呀") event.reply("你好呀")

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/22 上午8:37
@Author : snowykami
@Email : snowykami@outlook.com
@File : ts_chan_main.py
@Software: PyCharm
"""
import asyncio
from liteyuki.comm import Channel, set_channel, get_channel
from liteyuki import get_bot
set_channel("chan-main", Channel("chan-main"))
set_channel("chan-sub", Channel("chan-sub"))
chan_main = get_channel("chan-main")
# @get_bot().on_after_start
# async def _():
# while True:
# chan_main.send("Hello, World!")
# await asyncio.sleep(5)

View File

@ -8,6 +8,8 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@File : to_liteyuki.py @File : to_liteyuki.py
@Software: PyCharm @Software: PyCharm
""" """
import asyncio
from nonebot import Bot, get_bot, on_message from nonebot import Bot, get_bot, on_message
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from nonebot.adapters.onebot.v11 import MessageEvent, Bot from nonebot.adapters.onebot.v11 import MessageEvent, Bot
@ -37,6 +39,9 @@ async def _(bot: Bot, event: MessageEvent):
@shared_memory.on_subscriber_receive("event_to_nonebot") @shared_memory.on_subscriber_receive("event_to_nonebot")
async def _(event: MessageEvent): async def _(event: LiteyukiMessageEvent):
bot: Bot = get_bot(event.bot_id) bot: Bot = get_bot(event.bot_id)
await bot.send_msg(message_type=event.message_type, user_id=int(event.session_id), group_id=int(event.session_id), message=event.data["message"]) if event.message_type == "private":
await bot.send_private_msg(user_id=int(event.session_id), message=event.data["message"])
elif event.message_type == "group":
await bot.send_group_msg(group_id=int(event.session_id), message=event.data["message"])

View File

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/22 上午8:39
@Author : snowykami
@Email : snowykami@outlook.com
@File : ts_chan_sub.py
@Software: PyCharm
"""
import asyncio
from liteyuki.comm import Channel, get_channel
from nonebot import get_bot
from nonebot.adapters.onebot.v11 import Bot
chan_main = get_channel("chan-main")
# @chan_main.on_receive()
# async def _(data: str):
# print("Received data from chan-main:", data)
# try:
# bot: Bot = get_bot("2443429204") # type: ignore
#
# def send_msg():
#
# bot.send_msg(message_type="private", user_id=2443429204, message=data)
#
# print("tsA")
# print("tsA1")
# await asyncio.ensure_future(c)
# print("tsB")
# except Exception as e:
# print(e)
# pass