Compare commits

...
29 changed files with 188 additions and 36 deletions
+11 -9
View File
@@ -68,7 +68,7 @@
### 1. 体验一下?
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 napcat 或拉格朗日等直接连接用于体验与测试
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 [napcat](https://github.com/NapNeko/NapCatQQ) 或 [拉格朗日](https://github.com/LagrangeDev/Lagrange.Core) 以及 [matcha](https://github.com/A-kirami/matcha) 等直接连接用于体验与测试
(球球了测试君!)
```
@@ -95,13 +95,14 @@ AccessToken: PUBLIC_ZHENXUN_TEST
<details>
<summary> <strong> WebUI </strong>后台示例图 </summary>
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui1.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui2.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui3.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui4.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui5.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui6.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui7.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui00.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui01.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui02.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui03.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui04.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui05.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui06.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui07.png)
</details>
@@ -319,7 +320,7 @@ python bot.py
<details>
<summary>爱发电 以及 感谢投喂 </summary>
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
<img width="365px" height="450px" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/afd.jpg">
### 感谢名单
@@ -369,6 +370,7 @@ python bot.py
[哇](https://afdian.net/u/9b266244f23911eca19052540025c377)
[yajiwa](https://github.com/yajiwa)
[爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)
...
</details>
+1 -1
View File
@@ -1 +1 @@
__version__: v0.2.4-fix1
__version__: v0.2.4-fix2
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

@@ -235,7 +235,10 @@ class AuthChecker:
return
if plugin := await PluginInfo.get_or_none(module_path=module_path):
if plugin.plugin_type == PluginType.HIDDEN:
logger.debug("插件为HIDDEN,已跳过...")
logger.debug(
f"插件: {plugin.name}:{plugin.module} "
"为HIDDEN,已跳过权限检查..."
)
return
try:
cost_gold = await self.auth_cost(user, plugin, session)
+1 -1
View File
@@ -32,7 +32,7 @@ async def _(
if plugin := matcher.plugin:
if metadata := plugin.metadata:
extra = metadata.extra
if extra.get("plugin_type") in [PluginType.HIDDEN, PluginType.DEPENDANT]:
if extra.get("plugin_type") in [PluginType.HIDDEN]:
return
user_id = session.id1
group_id = session.id3 or session.id2
@@ -0,0 +1,23 @@
from typing import Any
from nonebot.adapters import Bot
from zhenxun.services.log import logger
from zhenxun.utils.manager.message_manager import MessageManager
@Bot.on_called_api
async def handle_api_result(
bot: Bot, exception: Exception | None, api: str, data: dict[str, Any], result: Any
):
if not exception and api == "send_msg":
try:
if (uid := data.get("user_id")) and (msg_id := result.get("message_id")):
MessageManager.add(str(uid), str(msg_id))
logger.debug(
f"收集消息id,user_id: {uid}, msg_id: {msg_id}", "msg_hook"
)
except Exception as e:
logger.warning(
f"收集消息id发生错误...data: {data}, result: {result}", "msg_hook", e=e
)
@@ -113,7 +113,7 @@ class GroupManager:
@classmethod
async def add_bot(
cls, bot: Bot, operator_id: str, group_id: str, group: GroupConsole | None
cls, bot: Bot, operator_id: str, group_id: str, group: GroupConsole
):
"""拉入bot
@@ -123,7 +123,11 @@ class GroupManager:
group_id: 群组id
group: GroupConsole
"""
if base_config.get("flag") and operator_id not in bot.config.superusers:
if (
base_config.get("flag")
and operator_id not in bot.config.superusers
and group.group_flag != 1
):
"""退出群组"""
try:
if result_msg := base_config.get("message"):
+1 -1
View File
@@ -184,7 +184,7 @@ async def _(
elif isinstance(result, UniMessage):
await result.finish(reply_to=True)
except GoodsNotFound:
await MessageUtils.build_message(f"没有找到道具 {name} 或道具数量不足...").send(
await MessageUtils.build_message(f"没有找到道具 {name.result} 或道具数量不足...").send(
reply_to=True
)
+61
View File
@@ -0,0 +1,61 @@
from nonebot.rule import Rule
from nonebot.adapters import Bot, Event
from nonebot_plugin_uninfo import Uninfo
from nonebot.plugin import PluginMetadata
from nonebot_plugin_alconna.uniseg.tools import reply_fetch
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
from zhenxun.services.log import logger
from zhenxun.utils.message import MessageUtils
from zhenxun.utils.platform import PlatformUtils
from zhenxun.configs.utils import PluginExtraData
from zhenxun.utils.manager.message_manager import MessageManager
__plugin_meta__ = PluginMetadata(
name="消息撤回",
description="撤回自己触发的消息撤回,不允许撤回其他人触发消息的撤回哦",
usage="""
引用消息 撤回
""".strip(),
extra=PluginExtraData(author="HibiKier", version="0.1", menu_type="其他").dict(),
)
def reply_check() -> Rule:
"""
检查是否存在回复消息
返回:
Rule: Rule
"""
async def _rule(bot: Bot, event: Event, session: Uninfo):
if event.get_type() == "message":
return (
bool(await reply_fetch(event, bot))
and PlatformUtils.get_platform(session) == "qq"
)
return False
return Rule(_rule)
_matcher = on_alconna(Alconna("撤回"), priority=5, block=True, rule=reply_check())
@_matcher.handle()
async def _(bot: Bot, event: Event, session: Uninfo, arparma: Arparma):
if reply := await reply_fetch(event, bot):
if (
MessageManager.check(session.user.id, reply.id)
or session.user.id in bot.config.superusers
):
try:
await bot.delete_msg(message_id=reply.id)
logger.info("撤回消息", arparma.header_result, session=session)
except Exception:
await MessageUtils.build_message("撤回失败,可能消息已过期...").send()
else:
await MessageUtils.build_message(
"权限不足,不是你触发的消息不要胡乱撤回哦..."
).send()
+6 -13
View File
@@ -288,13 +288,6 @@ class ConfigsManager:
config.value = value
config.default_value = default_value
else:
_module = None
if ":" in module:
module_split = module.split(":")
if len(module_split) < 2:
raise ValueError(f"module: {module} 填写错误")
_module = module_split[-1]
module = module_split[0]
key = key.upper()
if not self._data.get(module):
self._data[module] = ConfigGroup(module=module)
@@ -311,7 +304,6 @@ class ConfigsManager:
key: str,
value: Any,
auto_save: bool = False,
save_simple_data: bool = True,
):
"""设置配置值
@@ -320,15 +312,16 @@ class ConfigsManager:
key: 配置名称
value: 值
auto_save: 自动保存.
save_simple_data: 保存至config.yaml.
"""
key = key.upper()
if module in self._data:
data = self._data[module].configs.get(key)
if data and data != value:
if self._data[module].configs.get(key):
self._data[module].configs[key].value = value
self._simple_data[module][key] = value
else:
self.add_plugin_config(module, key, value)
self._simple_data[module][key] = value
if auto_save:
self.save(save_simple_data=save_simple_data)
self.save(save_simple_data=True)
def get_config(self, module: str, key: str, default: Any = None) -> Any:
"""获取指定配置值
+4 -6
View File
@@ -10,7 +10,6 @@ from ._build_image import BuildImage
class RowStyle(BaseModel):
font: FreeTypeFont | str | Path | None = "HYWenHei-85W.ttf"
"""字体"""
font_size: int = 20
@@ -23,7 +22,6 @@ class RowStyle(BaseModel):
class ImageTemplate:
color_list = ["#C2CEFE", "#FFA94C", "#3FE6A0", "#D1D4F5"] # noqa: RUF012
@classmethod
@@ -88,7 +86,7 @@ class ImageTemplate:
head_text: str,
tip_text: str | None,
column_name: list[str],
data_list: list[list[str | tuple[Path | BuildImage, int, int]]],
data_list: list[list[str | int | tuple[Path | BuildImage, int, int]]],
row_space: int = 35,
column_space: int = 30,
padding: int = 5,
@@ -137,7 +135,7 @@ class ImageTemplate:
async def table(
cls,
column_name: list[str],
data_list: list[list[str | tuple[Path | BuildImage, int, int]]],
data_list: list[list[str | int | tuple[Path | BuildImage, int, int]]],
row_space: int = 25,
column_space: int = 10,
padding: int = 5,
@@ -163,7 +161,7 @@ class ImageTemplate:
c = []
for lst in data_list:
if len(lst) > i:
c.append(lst[i])
c.append(str(lst[i]))
else:
c.append("")
column_data.append(c)
@@ -176,7 +174,7 @@ class ImageTemplate:
if isinstance(s, tuple):
w = s[1]
else:
w, _ = BuildImage.get_text_size(s, font)
w, _ = BuildImage.get_text_size(str(s), font)
if w > _temp["width"]:
_temp["width"] = w
build_data_list.append(_temp)
+27
View File
@@ -0,0 +1,27 @@
from typing import ClassVar
class MessageManager:
data: ClassVar[dict[str, list[str]]] = {}
@classmethod
def add(cls, uid: str, msg_id: str):
if uid not in cls.data:
cls.data[uid] = []
cls.data[uid].append(msg_id)
cls.remove_check(uid)
@classmethod
def check(cls, uid: str, msg_id: str) -> bool:
return msg_id in cls.data.get(uid, [])
@classmethod
def remove_check(cls, uid: str):
if len(cls.data[uid]) > 200:
cls.data[uid] = cls.data[uid][100:]
@classmethod
def get(cls, uid: str) -> list[str]:
if uid in cls.data:
return cls.data[uid]
return []
+42 -2
View File
@@ -4,7 +4,17 @@ from pathlib import Path
import nonebot
from pydantic import BaseModel
from nonebot.adapters.onebot.v11 import Message, MessageSegment
from nonebot_plugin_alconna import At, Text, AtAll, Image, Video, Voice, UniMessage
from nonebot_plugin_alconna import (
At,
Text,
AtAll,
Image,
Video,
Voice,
Reference,
CustomNode,
UniMessage,
)
from zhenxun.services.log import logger
from zhenxun.configs.config import BotConfig
@@ -89,6 +99,36 @@ class MessageUtils:
message_list += cls.__build_message(_data) # type: ignore
return UniMessage(message_list)
@classmethod
def alc_forward_msg(
cls,
msg_list: list,
uin: str,
name: str,
) -> UniMessage:
"""生成自定义合并消息
参数:
msg_list: 消息列表
uin: 发送者 QQ
name: 自定义名称
返回:
list[dict]: 转发消息
"""
node_list = []
for _message in msg_list:
if isinstance(_message, list):
for i in range(len(_message.copy())):
if isinstance(_message[i], Path):
_message[i] = Image(
raw=BuildImage.open(_message[i]).pic2bytes()
)
node_list.append(
CustomNode(uid=uin, name=name, content=UniMessage(_message))
)
return UniMessage(Reference(nodes=node_list))
@classmethod
def custom_forward_msg(
cls,
@@ -138,7 +178,7 @@ class MessageUtils:
if isinstance(r, Text):
s += str(r)
elif isinstance(r, Image):
if v := r.url or r.path:
if v := r.url or r.path or r.raw:
s += MessageSegment.image(v)
elif isinstance(r_list, Image):
if v := r_list.url or r_list.path:
+1
View File
@@ -189,6 +189,7 @@ def change_pixiv_image_links(
url = (
url.replace("i.pximg.net", nginx_url)
.replace("i.pixiv.cat", nginx_url)
.replace("i.pixiv.re", nginx_url)
.replace("_webp", "")
)
return url