Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75abe23896 | ||
|
|
ad7a3e6261 | ||
|
|
f1e359c666 | ||
|
|
0bfd71295e | ||
|
|
379ad77791 | ||
|
|
236bc40153 | ||
|
|
c2a54a8164 | ||
|
|
4dbab21853 | ||
|
|
3063c5bc02 |
@@ -1,15 +0,0 @@
|
||||
.devcontainer/
|
||||
.github/
|
||||
.vscode/
|
||||
assets/
|
||||
k8s/
|
||||
tests/
|
||||
.dockerignore
|
||||
.editorconfig
|
||||
.gitignore
|
||||
.pre-commit-config.yaml
|
||||
.prettier*
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
LICENSE
|
||||
*.md
|
||||
@@ -10,52 +10,7 @@ NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"]
|
||||
|
||||
SESSION_EXPIRE_TIMEOUT=30
|
||||
|
||||
# 全局图片统一使用bytes发送,当真寻与协议端不在同一服务器上时为True
|
||||
IMAGE_TO_BYTES = False
|
||||
|
||||
PLATFORM_SUPERUSERS = '
|
||||
{
|
||||
"qq": [""],
|
||||
"dodo": [""]
|
||||
}
|
||||
'
|
||||
|
||||
DRIVER=~fastapi+~httpx+~websockets
|
||||
|
||||
# kook adapter toekn
|
||||
# kaiheila_bots =[{"token": ""}]
|
||||
|
||||
# # discode adapter
|
||||
# DISCORD_BOTS='
|
||||
# [
|
||||
# {
|
||||
# "token": "",
|
||||
# "intent": {
|
||||
# "guild_messages": true,
|
||||
# "direct_messages": true
|
||||
# },
|
||||
# "application_commands": {"*": ["*"]}
|
||||
# }
|
||||
# ]
|
||||
# '
|
||||
# DISCORD_PROXY=''
|
||||
|
||||
# # dodo adapter
|
||||
# DODO_BOTS='
|
||||
# [
|
||||
# {
|
||||
# "client_id": "",
|
||||
# "token": ""
|
||||
# }
|
||||
# ]
|
||||
# '
|
||||
|
||||
# application_commands的{"*": ["*"]}代表将全部应用命令注册为全局应用命令
|
||||
# {"admin": ["123", "456"]}则代表将admin命令注册为id是123、456服务器的局部命令,其余命令不注册
|
||||
|
||||
# LOG_LEVEL=DEBUG
|
||||
DEBUG=False
|
||||
# 服务器和端口
|
||||
HOST = 127.0.0.1
|
||||
PORT = 8080
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
name: Issue template
|
||||
about: " issue template's purpose here."
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### 系统版本:Ubuntu 20.04
|
||||
### 真寻版本:0.1.5.3
|
||||
|
||||
### 错误截图
|
||||
|
||||
[img]
|
||||
|
||||
### 日志截图
|
||||
|
||||
[img]
|
||||
|
||||
### 错误说明
|
||||
|
||||
发生了xx错误...
|
||||
@@ -1,9 +0,0 @@
|
||||
### 系统版本:Ubuntu 20.04
|
||||
### 真寻版本:0.1.5.3
|
||||
|
||||
### 错误截图
|
||||
|
||||
[img]
|
||||
|
||||
### 错误说明
|
||||
发生了xx错误...
|
||||
@@ -138,47 +138,10 @@ dmypy.json
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
demo.py
|
||||
test.py
|
||||
server_ip.py
|
||||
server.py
|
||||
member_activity_handle.py
|
||||
Yu-Gi-Oh/
|
||||
search_image/
|
||||
black_word/
|
||||
csgo/
|
||||
fantasy_card/
|
||||
data/
|
||||
log/
|
||||
backup/
|
||||
extensive_plugin/
|
||||
test/
|
||||
bot.py
|
||||
data/
|
||||
.env
|
||||
.env.dev
|
||||
/resources/text/
|
||||
# /resources/image/
|
||||
/resources/temp/
|
||||
/resources/image/genshin/
|
||||
/resources/image/draw_card/
|
||||
/resources/image/card/
|
||||
/resources/image/temp/
|
||||
/resources/image/sign/today_card/
|
||||
/resources/image/image_management/
|
||||
/resources/image/bilibili_sub/
|
||||
/resources/image/other/
|
||||
/resources/image/_setu/
|
||||
/resources/image/_r18/
|
||||
/resources/image/csgo_cases/
|
||||
!/resources/image/csgo_cases/_background/
|
||||
/resources/image/superuser_help.png
|
||||
/resources/image/update_img_help.png
|
||||
/resources/image/prts/
|
||||
/configs/config.py
|
||||
configs/config.yaml
|
||||
./.env
|
||||
./.env.dev
|
||||
plugins/csgo_server/
|
||||
plugins/activity/
|
||||
!/resources/image/genshin/alc/back.png
|
||||
!/data/genshin_alc/
|
||||
.vscode/launch.json
|
||||
/resources/template/my_info
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"C_Cpp.errorSquiggles": "enabled",
|
||||
"terminal.integrated.env.linux": {
|
||||
"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"aiofiles",
|
||||
"Alconna",
|
||||
"arclet",
|
||||
"Arparma",
|
||||
"displayname",
|
||||
"flmt",
|
||||
"getbbox",
|
||||
"hibiapi",
|
||||
"httpx",
|
||||
"kaiheila",
|
||||
"lolicon",
|
||||
"nonebot",
|
||||
"onebot",
|
||||
"pixiv",
|
||||
"Setu",
|
||||
"tobytes",
|
||||
"ujson",
|
||||
"unban",
|
||||
"userinfo",
|
||||
"zhenxun"
|
||||
],
|
||||
"python.analysis.autoImportCompletions": true
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR /app/zhenxun
|
||||
|
||||
COPY . /app/zhenxun
|
||||
|
||||
RUN pip install poetry -i https://mirrors.aliyun.com/pypi/simple/
|
||||
|
||||
RUN poetry install
|
||||
|
||||
VOLUME /app/zhenxun/data /app/zhenxun/data
|
||||
|
||||
VOLUME /app/zhenxun/resources /app/zhenxun/resources
|
||||
|
||||
RUN poetry run playwright install --with-deps chromium
|
||||
|
||||
CMD ["poetry", "run", "python", "bot.py"]
|
||||
@@ -1 +1 @@
|
||||
__version__: v0.2
|
||||
__version__: v0.0.8.1
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"admin_bot_manage:custom_welcome_message",
|
||||
"SET_GROUP_WELCOME_MESSAGE_LEVEL [LEVEL]",
|
||||
2,
|
||||
name="群管理员操作",
|
||||
help_="设置群欢迎消息权限",
|
||||
default_value=2,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"admin_bot_manage:switch_rule",
|
||||
"CHANGE_GROUP_SWITCH_LEVEL [LEVEL]",
|
||||
2,
|
||||
help_="开关群功能权限",
|
||||
default_value=2,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"admin_bot_manage",
|
||||
"ADMIN_DEFAULT_AUTH",
|
||||
5,
|
||||
help_="默认群管理员权限",
|
||||
default_value=5
|
||||
)
|
||||
|
||||
nonebot.load_plugins("basic_plugins/admin_bot_manage")
|
||||
@@ -0,0 +1,38 @@
|
||||
from nonebot import on_notice
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.level_user import LevelUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
admin_notice = on_notice(priority=5)
|
||||
|
||||
|
||||
@admin_notice.handle()
|
||||
async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
|
||||
try:
|
||||
nickname = (
|
||||
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
|
||||
).user_name
|
||||
except AttributeError:
|
||||
nickname = event.user_id
|
||||
if event.sub_type == "set":
|
||||
await LevelUser.set_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||
)
|
||||
logger.info(
|
||||
f"为新晋管理员 {nickname}({event.user_id}) "
|
||||
f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}"
|
||||
)
|
||||
elif event.sub_type == "unset":
|
||||
await LevelUser.delete_level(event.user_id, event.group_id)
|
||||
logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
|
||||
@@ -0,0 +1,51 @@
|
||||
from nonebot import on_command
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import custom_group_welcome
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "自定义进群欢迎消息 [Admin]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
指令:
|
||||
自定义进群欢迎消息 ?[文本] ?[图片]
|
||||
示例:自定义进群欢迎消息 欢迎新人![图片]
|
||||
Note:可以通过[at]来确认是否艾特新成员
|
||||
示例:自定义进群欢迎消息 欢迎你[at]
|
||||
""".strip()
|
||||
__plugin_des__ = '简易的自定义群欢迎消息'
|
||||
__plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]']
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
__plugin_settings__ = {
|
||||
"admin_level": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
|
||||
}
|
||||
|
||||
custom_welcome = on_command(
|
||||
"自定义进群欢迎消息",
|
||||
aliases={"自定义欢迎消息", "自定义群欢迎消息", "设置群欢迎消息"},
|
||||
permission=GROUP,
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
|
||||
|
||||
@custom_welcome.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
try:
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_imgs(event.json())
|
||||
if not msg and not imgs:
|
||||
await custom_welcome.finish(__plugin_usage__)
|
||||
await custom_welcome.send(
|
||||
await custom_group_welcome(msg, imgs, event.user_id, event.group_id),
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
|
||||
except Exception as e:
|
||||
logger.error(f"自定义进群欢迎消息发生错误 {type(e)}:{e}")
|
||||
await custom_welcome.send("发生了一些未知错误...")
|
||||
@@ -0,0 +1,319 @@
|
||||
from typing import List
|
||||
from nonebot.adapters.cqhttp.message import MessageSegment
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_local_proxy, get_bot
|
||||
from pathlib import Path
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def group_current_status(group_id: int) -> str:
|
||||
"""
|
||||
获取当前所有通知的开关
|
||||
:param group_id: 群号
|
||||
"""
|
||||
rst = "[被动技能 状态]\n"
|
||||
_data = group_manager.get_task_data()
|
||||
for task in _data.keys():
|
||||
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
return rst.strip()
|
||||
|
||||
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
|
||||
|
||||
async def custom_group_welcome(
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
) -> str:
|
||||
"""
|
||||
替换群欢迎消息
|
||||
:param msg: 欢迎消息文本
|
||||
:param imgs: 欢迎消息图片,只取第一张
|
||||
:param user_id: 用户id,用于log记录
|
||||
:param group_id: 群号
|
||||
"""
|
||||
img_result = ""
|
||||
img = imgs[0] if imgs else ""
|
||||
result = ""
|
||||
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"):
|
||||
os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
if not custom_welcome_msg_json.exists():
|
||||
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = {}
|
||||
else:
|
||||
try:
|
||||
data = json.load(open(custom_welcome_msg_json, "r"))
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
try:
|
||||
if msg:
|
||||
data[str(group_id)] = str(msg)
|
||||
json.dump(
|
||||
data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False
|
||||
)
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
|
||||
result += msg
|
||||
if img:
|
||||
await AsyncHttpx.download_file(
|
||||
img, DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"
|
||||
)
|
||||
img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
|
||||
return "替换群消息失败.."
|
||||
return f"替换群欢迎消息成功:\n{result}" + img_result
|
||||
|
||||
|
||||
task_data = None
|
||||
|
||||
|
||||
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
global task_data
|
||||
"""
|
||||
修改群功能状态
|
||||
:param cmd: 功能名称
|
||||
:param group_id: 群号
|
||||
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
type_ = "plugin"
|
||||
modules = plugins2settings_manager.get_plugin_module(cmd, True)
|
||||
if cmd == "全部被动":
|
||||
for task in task_data:
|
||||
if status == "开启":
|
||||
if not await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.open_group_task(group_id, task)
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd == "全部功能":
|
||||
for f in plugins2settings_manager.get_data():
|
||||
if status == "开启":
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
if status == "开启":
|
||||
if type_ == "task":
|
||||
if await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
|
||||
await group_manager.open_group_task(group_id, module)
|
||||
else:
|
||||
if group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于开启状态!不要重复开启."
|
||||
group_manager.unblock_plugin(module, group_id)
|
||||
else:
|
||||
if type_ == "task":
|
||||
if not await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
|
||||
await group_manager.close_group_task(group_id, module)
|
||||
else:
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
group_manager.block_plugin(module, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if is_super:
|
||||
for file in os.listdir(Path(DATA_PATH) / "group_help"):
|
||||
file = Path(DATA_PATH) / "group_help" / file
|
||||
file.unlink()
|
||||
else:
|
||||
_help_image = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
|
||||
if _help_image.exists():
|
||||
_help_image.unlink()
|
||||
return f"{status} {cmd} 功能!"
|
||||
|
||||
|
||||
def set_plugin_status(cmd: str, block_type: str = "all"):
|
||||
"""
|
||||
设置插件功能状态(超级用户使用)
|
||||
:param cmd: 功能名称
|
||||
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
|
||||
"""
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
module = plugins2settings_manager.get_plugin_module(cmd)
|
||||
if status == "开启":
|
||||
plugins_manager.unblock_plugin(module)
|
||||
else:
|
||||
plugins_manager.block_plugin(module, block_type=block_type)
|
||||
for file in os.listdir(Path(DATA_PATH) / "group_help"):
|
||||
file = Path(DATA_PATH) / "group_help" / file
|
||||
file.unlink()
|
||||
|
||||
|
||||
async def get_plugin_status():
|
||||
"""
|
||||
获取功能状态
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status)
|
||||
|
||||
|
||||
def _get_plugin_status() -> MessageSegment:
|
||||
"""
|
||||
合成功能状态图片
|
||||
"""
|
||||
rst = "\t功能\n"
|
||||
flag_str = "状态".rjust(4) + "\n"
|
||||
for module in plugins_manager.get_data():
|
||||
flag = plugins_manager.get_plugin_block_type(module)
|
||||
flag = flag.upper() + " CLOSE" if flag else "OPEN"
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
if (
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
):
|
||||
continue
|
||||
rst += f"{plugin_name}"
|
||||
except KeyError:
|
||||
rst += f"{module}"
|
||||
if plugins_manager.get(module)["error"]:
|
||||
rst += "[ERROR]"
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
height = len(rst.split("\n")) * 24
|
||||
a = BuildImage(250, height, font_size=20)
|
||||
a.text((10, 10), rst)
|
||||
b = BuildImage(200, height, font_size=20)
|
||||
b.text((10, 10), flag_str)
|
||||
A = BuildImage(500, height)
|
||||
A.paste(a)
|
||||
A.paste(b, (270, 0))
|
||||
return image(b64=A.pic2bs4())
|
||||
|
||||
|
||||
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
|
||||
"""
|
||||
更新群成员信息
|
||||
:param group_id: 群号
|
||||
:param remind_superuser: 失败信息提醒超级用户
|
||||
"""
|
||||
bot = get_bot()
|
||||
_group_user_list = await bot.get_group_member_list(group_id=group_id)
|
||||
_error_member_list = []
|
||||
_exist_member_list = []
|
||||
# try:
|
||||
for user_info in _group_user_list:
|
||||
if user_info["card"] == "":
|
||||
nickname = user_info["nickname"]
|
||||
else:
|
||||
nickname = user_info["card"]
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if (
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||
)
|
||||
if str(user_info["user_id"]) in bot.config.superusers:
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"], user_info["group_id"], 9
|
||||
)
|
||||
user = await GroupInfoUser.get_member_info(
|
||||
user_info["user_id"], user_info["group_id"]
|
||||
)
|
||||
if user:
|
||||
if user.user_name != nickname:
|
||||
await user.update(user_name=nickname).apply()
|
||||
logger.info(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
|
||||
)
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
continue
|
||||
join_time = datetime.strptime(
|
||||
time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
|
||||
),
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
):
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
_error_member_list.append(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
|
||||
)
|
||||
_del_member_list = list(
|
||||
set(_exist_member_list).difference(
|
||||
set(await GroupInfoUser.get_group_member_id_list(group_id))
|
||||
)
|
||||
)
|
||||
if _del_member_list:
|
||||
for del_user in _del_member_list:
|
||||
if await GroupInfoUser.delete_member_info(del_user, group_id):
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
|
||||
else:
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
|
||||
if _error_member_list and remind_superuser:
|
||||
result = ""
|
||||
for error_user in _error_member_list:
|
||||
result += error_user
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def set_group_bot_status(group_id: int, status: bool) -> str:
|
||||
"""
|
||||
设置群聊bot开关状态
|
||||
:param group_id: 群号
|
||||
:param status: 状态
|
||||
"""
|
||||
if status:
|
||||
if group_manager.check_group_bot_status(group_id):
|
||||
return "我还醒着呢!"
|
||||
group_manager.turn_on_group_bot_status(group_id)
|
||||
return "呜..醒来了..."
|
||||
else:
|
||||
group_manager.shutdown_group_bot_status(group_id)
|
||||
# for x in group_manager.get_task_data():
|
||||
# group_manager.close_group_task(group_id, x)
|
||||
return "那我先睡觉了..."
|
||||
@@ -0,0 +1,42 @@
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from utils.manager import group_manager, plugins2settings_manager
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
|
||||
cmd = []
|
||||
|
||||
|
||||
def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
|
||||
"""
|
||||
检测文本是否是关闭功能命令
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
:param state: pass
|
||||
"""
|
||||
global cmd
|
||||
try:
|
||||
if not cmd:
|
||||
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
|
||||
_data = group_manager.get_task_data()
|
||||
for key in _data:
|
||||
cmd.append(f"开启{_data[key]}")
|
||||
cmd.append(f"关闭{_data[key]}")
|
||||
cmd.append(f"开启 {_data[key]}")
|
||||
cmd.append(f"关闭 {_data[key]}")
|
||||
_data = plugins2settings_manager.get_data()
|
||||
for key in _data:
|
||||
try:
|
||||
for x in _data[key]["cmd"]:
|
||||
cmd.append(f"开启{x}")
|
||||
cmd.append(f"关闭{x}")
|
||||
cmd.append(f"开启 {x}")
|
||||
cmd.append(f"关闭 {x}")
|
||||
except KeyError:
|
||||
pass
|
||||
msg = get_message_text(event.json()).split()
|
||||
msg = msg[0] if msg else ""
|
||||
return msg in cmd
|
||||
except Exception as e:
|
||||
logger.error(f"检测是否为功能开关命令发生错误 {type(e)}: {e}")
|
||||
return False
|
||||
@@ -0,0 +1,125 @@
|
||||
from nonebot import on_command, on_message, on_regex
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
|
||||
from .data_source import (
|
||||
change_group_switch,
|
||||
set_plugin_status,
|
||||
get_plugin_status,
|
||||
group_current_status,
|
||||
set_group_bot_status
|
||||
)
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.permission import SUPERUSER
|
||||
from .rule import switch_rule
|
||||
import re
|
||||
|
||||
|
||||
__zx_plugin_name__ = "群功能开关 [Admin]"
|
||||
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
群内功能与被动技能开关
|
||||
指令:
|
||||
开启/关闭[功能]
|
||||
群被动状态
|
||||
开启全部被动
|
||||
关闭全部被动
|
||||
醒来/休息吧
|
||||
示例:开启/关闭色图
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
功能总开关与指定群禁用
|
||||
指令:
|
||||
功能状态
|
||||
开启/关闭[功能] [group]
|
||||
开启/关闭[功能] ['private'/'group']
|
||||
""".strip()
|
||||
__plugin_des__ = "群内功能开关"
|
||||
__plugin_cmd__ = [
|
||||
"开启/关闭[功能]",
|
||||
"群被动状态",
|
||||
"开启全部被动",
|
||||
"关闭全部被动",
|
||||
"醒来/休息吧",
|
||||
"功能状态 [_superuser]",
|
||||
"开启/关闭[功能] [group] [_superuser]",
|
||||
"开启/关闭[功能] ['private'/'group'] [_superuser]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"admin_level": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"),
|
||||
"cmd": ["开启功能", "关闭功能", "开关"]
|
||||
}
|
||||
|
||||
switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True)
|
||||
|
||||
plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, block=True)
|
||||
|
||||
group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True)
|
||||
|
||||
group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, block=True)
|
||||
|
||||
|
||||
@switch_rule_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
_cmd = get_message_text(event.json()).split()[0]
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id))
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}")
|
||||
else:
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
block_type = " ".join(get_message_text(event.json()).split()[1:])
|
||||
block_type = block_type if block_type else "a"
|
||||
if is_number(block_type):
|
||||
if not int(block_type) in [
|
||||
g["group_id"]
|
||||
for g in await bot.get_group_list(self_id=int(bot.self_id))
|
||||
]:
|
||||
await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}")
|
||||
await change_group_switch(_cmd, int(block_type), True)
|
||||
group_name = (await bot.get_group_info(group_id=int(block_type)))[
|
||||
"group_name"
|
||||
]
|
||||
await switch_rule_matcher.send(
|
||||
f"已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能"
|
||||
)
|
||||
elif block_type in ["all", "private", "group", "a", "p", "g"]:
|
||||
block_type = "all" if block_type == "a" else block_type
|
||||
block_type = "private" if block_type == "p" else block_type
|
||||
block_type = "group" if block_type == "g" else block_type
|
||||
set_plugin_status(_cmd, block_type)
|
||||
if block_type == "all":
|
||||
await switch_rule_matcher.send(f"已{_cmd[:2]}功能:{_cmd[2:]}")
|
||||
elif block_type == "private":
|
||||
await switch_rule_matcher.send(f"已在私聊中{_cmd[:2]}功能:{_cmd[2:]}")
|
||||
else:
|
||||
await switch_rule_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}")
|
||||
else:
|
||||
await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]")
|
||||
logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}")
|
||||
|
||||
|
||||
@plugins_status.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await plugins_status.send(await get_plugin_status())
|
||||
|
||||
|
||||
@group_task_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await group_task_status.send(await group_current_status(event.group_id))
|
||||
|
||||
|
||||
@group_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
r = re.search("^(休息吧|醒来)$", get_message_text(event.json()))
|
||||
if r:
|
||||
if r.group(1) == "休息吧":
|
||||
msg = set_group_bot_status(event.group_id, False)
|
||||
else:
|
||||
msg = set_group_bot_status(event.group_id, True)
|
||||
await group_status.send(msg)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{r.group(1)}")
|
||||
@@ -0,0 +1,51 @@
|
||||
from utils.utils import scheduler, get_bot
|
||||
from .data_source import update_member_info
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
|
||||
|
||||
|
||||
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
|
||||
__plugin_usage__ = '无'
|
||||
__plugin_des__ = '成员信息和管理权限的定时更新'
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
|
||||
|
||||
# 自动更新群员信息
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=2,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
bot = get_bot()
|
||||
if bot:
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
try:
|
||||
await update_member_info(g)
|
||||
logger.info(f"更新群组 g:{g} 成功")
|
||||
except Exception as e:
|
||||
logger.error(f"更新群组错误 g:{g} e:{e}")
|
||||
|
||||
|
||||
# 快速更新群员信息以及管理员权限
|
||||
@scheduler.scheduled_job(
|
||||
"interval",
|
||||
minutes=5,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
bot = get_bot()
|
||||
if bot:
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
|
||||
for g in gl:
|
||||
if g not in all_group:
|
||||
await update_member_info(g, False)
|
||||
logger.info(f"快速更新群信息以及权限:{g}")
|
||||
except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError):
|
||||
pass
|
||||
@@ -0,0 +1,41 @@
|
||||
from nonebot import on_command, on_notice
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
||||
from .data_source import update_member_info
|
||||
|
||||
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
更新群组成员的基本信息
|
||||
指令:
|
||||
更新群组成员列表/更新群组成员信息
|
||||
""".strip()
|
||||
__plugin_des__ = '更新群组成员列表'
|
||||
__plugin_cmd__ = ['更新群组成员列表']
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
__plugin_settings__ = {
|
||||
"admin_level": 1,
|
||||
}
|
||||
|
||||
|
||||
refresh_member_group = on_command(
|
||||
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@refresh_member_group.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if await update_member_info(event.group_id):
|
||||
await refresh_member_group.finish("更新群员信息成功!", at_sender=True)
|
||||
else:
|
||||
await refresh_member_group.finish("更新群员信息失败!", at_sender=True)
|
||||
|
||||
|
||||
group_increase_handle = on_notice(priority=1, block=False)
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
if event.user_id == int(bot.self_id):
|
||||
await update_member_info(event.group_id)
|
||||
@@ -0,0 +1,27 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_image, admin_help_image
|
||||
|
||||
|
||||
__zx_plugin_name__ = '管理帮助 [Admin]'
|
||||
__plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”'
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
__plugin_settings__ = {
|
||||
"admin_level": 1,
|
||||
}
|
||||
|
||||
admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
|
||||
|
||||
if admin_help_image.exists():
|
||||
admin_help_image.unlink()
|
||||
|
||||
|
||||
@admin_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if not admin_help_image.exists():
|
||||
await create_help_image()
|
||||
await admin_help.send(image('admin_help_img.png'))
|
||||
@@ -0,0 +1,94 @@
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from utils.manager import group_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from pathlib import Path
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
|
||||
admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png'
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def init_task(bot: Bot = None):
|
||||
if not group_manager.get_task_data():
|
||||
await group_manager.init_group_task()
|
||||
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
|
||||
|
||||
|
||||
async def create_help_image():
|
||||
"""
|
||||
创建管理员帮助图片
|
||||
"""
|
||||
await asyncio.get_event_loop().run_in_executor(
|
||||
None, _create_help_image
|
||||
)
|
||||
|
||||
|
||||
def _create_help_image():
|
||||
"""
|
||||
创建管理员帮助图片
|
||||
"""
|
||||
_matchers = get_matchers()
|
||||
_plugin_name_list = []
|
||||
width = 0
|
||||
_plugin_level = {}
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
continue
|
||||
try:
|
||||
if (
|
||||
"[admin]" in plugin_name.lower()
|
||||
and plugin_name not in _plugin_name_list
|
||||
and plugin_name != "管理帮助 [Admin]"
|
||||
):
|
||||
_plugin_name_list.append(plugin_name)
|
||||
plugin_settings = _module.__getattribute__("__plugin_settings__")
|
||||
plugin_des = _module.__getattribute__("__plugin_des__")
|
||||
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
|
||||
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
|
||||
admin_level = int(plugin_settings["admin_level"])
|
||||
if _plugin_level.get(admin_level):
|
||||
_plugin_level[admin_level].append(
|
||||
f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)
|
||||
)
|
||||
else:
|
||||
_plugin_level[admin_level] = [
|
||||
f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)
|
||||
]
|
||||
x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23
|
||||
width = width if width > x else x
|
||||
except AttributeError:
|
||||
logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...")
|
||||
help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \
|
||||
"[权限等级] 管理员帮助:\n\n"
|
||||
x = list(_plugin_level.keys())
|
||||
x.sort()
|
||||
for level in x:
|
||||
for help_ in _plugin_level[level]:
|
||||
help_str += f"\t{help_}\n\n"
|
||||
help_str += '-----[被动技能开关]-----\n\n'
|
||||
task_data = group_manager.get_task_data()
|
||||
for i, x in enumerate(task_data.keys()):
|
||||
help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n'
|
||||
height = len(help_str.split("\n")) * 33
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
_background = BuildImage(width, height, background=background)
|
||||
A.text((150, 110), help_str)
|
||||
A.paste(_background, alpha=True)
|
||||
A.save(admin_help_image)
|
||||
logger.info(f'已成功加载 {len(_plugin_name_list)} 条管理员命令')
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
from utils.message_builder import image
|
||||
from utils.utils import scheduler, get_bot
|
||||
from nonebot import on_message
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from models.friend_user import FriendUser
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.manager import group_manager
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
__zx_plugin_name__ = "定时任务相关 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {'zwa': '早晚安'}
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_ZWA",
|
||||
True,
|
||||
help_="被动 早晚安 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_backup",
|
||||
"BACKUP_FLAG",
|
||||
True,
|
||||
help_="是否开启文件备份",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_backup",
|
||||
"BACKUP_DIR_OR_FILE",
|
||||
['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
|
||||
name="文件备份",
|
||||
help_="备份的文件夹或文件",
|
||||
default_value=[]
|
||||
)
|
||||
|
||||
|
||||
cx = on_message(priority=9, block=False)
|
||||
|
||||
|
||||
# 早上好
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=6,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, 'zwa'):
|
||||
result = image("zao.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(group_id=g, message="早上好" + result)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
|
||||
# 睡觉了
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=23,
|
||||
minute=59,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, 'zwa'):
|
||||
result = image("sleep.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(
|
||||
group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
|
||||
# 自动更新群组信息
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=3,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
group_info = await bot.get_group_info(group_id=g)
|
||||
await GroupInfo.add_group_info(
|
||||
group_info["group_id"],
|
||||
group_info["group_name"],
|
||||
group_info["max_member_count"],
|
||||
group_info["member_count"],
|
||||
)
|
||||
logger.info(f"自动更新群组 {g} 信息成功")
|
||||
except Exception as e:
|
||||
logger.error(f"自动更新群组信息错误 e:{e}")
|
||||
|
||||
|
||||
# 自动更新好友信息
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=3,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
bot = get_bot()
|
||||
fl = await bot.get_friend_list()
|
||||
for f in fl:
|
||||
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
|
||||
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
|
||||
else:
|
||||
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
|
||||
except Exception as e:
|
||||
logger.error(f"自动更新群组信息错误 e:{e}")
|
||||
|
||||
|
||||
# 自动备份
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=3,
|
||||
minute=25,
|
||||
)
|
||||
async def _():
|
||||
if Config.get_config("_backup", "BACKUP_FLAG"):
|
||||
_backup_path = Path() / 'backup'
|
||||
_backup_path.mkdir(exist_ok=True, parents=True)
|
||||
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
|
||||
try:
|
||||
path = Path(x)
|
||||
_p = _backup_path / x
|
||||
if path.exists():
|
||||
if path.is_dir():
|
||||
if _p.exists():
|
||||
shutil.rmtree(_p, ignore_errors=True)
|
||||
shutil.copytree(x, _p)
|
||||
else:
|
||||
if _p.exists():
|
||||
_p.unlink()
|
||||
shutil.copy(x, _p)
|
||||
logger.info(f'已完成自动备份:{x}')
|
||||
except Exception as e:
|
||||
logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
# 一次性任务
|
||||
# 固定时间触发,仅触发一次:
|
||||
#
|
||||
# from datetime import datetime
|
||||
#
|
||||
# @nonebot.scheduler.scheduled_job(
|
||||
# 'date',
|
||||
# run_date=datetime(2021, 1, 1, 0, 0),
|
||||
# # timezone=None,
|
||||
# )
|
||||
# async def _():
|
||||
# await bot.send_group_msg(group_id=123456,
|
||||
# message="2021,新年快乐!")
|
||||
|
||||
# 定期任务
|
||||
# 从 start_date 开始到 end_date 结束,根据类似 Cron
|
||||
#
|
||||
# 的规则触发任务:
|
||||
#
|
||||
# @nonebot.scheduler.scheduled_job(
|
||||
# 'cron',
|
||||
# # year=None,
|
||||
# # month=None,
|
||||
# # day=None,
|
||||
# # week=None,
|
||||
# day_of_week="mon,tue,wed,thu,fri",
|
||||
# hour=7,
|
||||
# # minute=None,
|
||||
# # second=None,
|
||||
# # start_date=None,
|
||||
# # end_date=None,
|
||||
# # timezone=None,
|
||||
# )
|
||||
# async def _():
|
||||
# await bot.send_group_msg(group_id=123456,
|
||||
# message="起床啦!")
|
||||
|
||||
# 间隔任务
|
||||
#
|
||||
# interval 触发器
|
||||
#
|
||||
# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束:
|
||||
#
|
||||
# @nonebot.scheduler.scheduled_job(
|
||||
# 'interval',
|
||||
# # weeks=0,
|
||||
# # days=0,
|
||||
# # hours=0,
|
||||
# minutes=5,
|
||||
# # seconds=0,
|
||||
# # start_date=time.now(),
|
||||
# # end_date=None,
|
||||
# )
|
||||
# async def _():
|
||||
# has_new_item = check_new_item()
|
||||
# if has_new_item:
|
||||
# await bot.send_group_msg(group_id=123456,
|
||||
# message="XX有更新啦!")
|
||||
|
||||
|
||||
# 动态的计划任务
|
||||
# import datetime
|
||||
#
|
||||
# from apscheduler.triggers.date import DateTrigger # 一次性触发器
|
||||
# # from apscheduler.triggers.cron import CronTrigger # 定期触发器
|
||||
# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器
|
||||
# from nonebot import on_command, scheduler
|
||||
#
|
||||
# @on_command('赖床')
|
||||
# async def _(session: CommandSession):
|
||||
# await session.send('我会在5分钟后再喊你')
|
||||
#
|
||||
# # 制作一个“5分钟后”触发器
|
||||
# delta = datetime.timedelta(minutes=5)
|
||||
# trigger = DateTrigger(
|
||||
# run_date=datetime.datetime.now() + delta
|
||||
# )
|
||||
#
|
||||
# # 添加任务
|
||||
# scheduler.add_job(
|
||||
# func=session.send, # 要添加任务的函数,不要带参数
|
||||
# trigger=trigger, # 触发器
|
||||
# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号
|
||||
# # kwargs=None,
|
||||
# misfire_grace_time=60, # 允许的误差时间,建议不要省略
|
||||
# # jobstore='default', # 任务储存库,在下一小节中说明
|
||||
# )
|
||||
@@ -0,0 +1,207 @@
|
||||
from nonebot import on_command
|
||||
from models.ban_user import BanUser
|
||||
from models.level_user import LevelUser
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent, MessageEvent
|
||||
from utils.utils import get_message_at, get_message_text, is_number
|
||||
from configs.config import NICKNAME, Config
|
||||
from nonebot.permission import SUPERUSER
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "封禁Ban用户 [Admin]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
将用户拉入或拉出黑名单
|
||||
指令:
|
||||
.ban [at] ?[小时] ?[分钟]
|
||||
.unban
|
||||
示例:.ban @user
|
||||
示例:.ban @user 6
|
||||
示例:.ban @user 3 10
|
||||
示例:.unban @user
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
b了=屏蔽用户消息,相当于最上级.ban
|
||||
跨群ban以及跨群b了
|
||||
指令:
|
||||
b了 [at/qq]
|
||||
.ban [user_id] ?[小时] ?[分钟]
|
||||
示例:b了 @user
|
||||
示例:b了 1234567
|
||||
示例:.ban 12345567
|
||||
""".strip()
|
||||
__plugin_des__ = '你被逮捕了!丢进小黑屋!'
|
||||
__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]']
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
__plugin_settings__ = {
|
||||
"admin_level": Config.get_config("ban", "BAN_LEVEL"),
|
||||
"cmd": ['.ban', '.unban', 'ban', 'unban']
|
||||
}
|
||||
__plugin_configs__ = {
|
||||
"BAN_LEVEL [LEVEL]": {
|
||||
"value": 5,
|
||||
"help": "ban/unban所需要的管理员权限等级",
|
||||
"default_value": 5
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ban = on_command(
|
||||
".ban",
|
||||
aliases={".unban", "/ban", "/unban"},
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
|
||||
super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
|
||||
|
||||
|
||||
@ban.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
result = ""
|
||||
qq = get_message_at(event.json())
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
|
||||
user_name = user_name['card'] if user_name['card'] else user_name['nickname']
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
msg = msg.split()
|
||||
if len(msg) == 2:
|
||||
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
|
||||
await ban.finish("参数必须是数字!", at_sender=True)
|
||||
time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60
|
||||
else:
|
||||
if not is_number(msg[0].strip()):
|
||||
await ban.finish("参数必须是数字!", at_sender=True)
|
||||
time = int(msg[0]) * 60 * 60
|
||||
else:
|
||||
time = -1
|
||||
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
|
||||
if (
|
||||
await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
<= await LevelUser.get_user_level(qq, event.group_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await ban.finish(
|
||||
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
|
||||
at_sender=True,
|
||||
)
|
||||
if await BanUser.ban(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id), time
|
||||
):
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
|
||||
)
|
||||
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time/60} 分钟后解封"
|
||||
else:
|
||||
time = await BanUser.check_ban_time(qq)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
else:
|
||||
time += " 分钟"
|
||||
result = f"{user_name} 已在黑名单!预计 {time}后解封"
|
||||
else:
|
||||
if (
|
||||
await BanUser.check_ban_level(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await ban.finish(
|
||||
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
|
||||
)
|
||||
if await BanUser.unban(qq):
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
|
||||
)
|
||||
result = f"已经把 {user_name} 从黑名单中删除了!"
|
||||
else:
|
||||
result = f"{user_name} 不在黑名单!"
|
||||
else:
|
||||
await ban.finish("艾特人了吗??", at_sender=True)
|
||||
await ban.finish(result, at_sender=True)
|
||||
|
||||
|
||||
@ban.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
msg = get_message_text(event.json())
|
||||
msg = msg.split()
|
||||
if is_number(msg[0]):
|
||||
qq = int(msg[0])
|
||||
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
|
||||
hour = 0
|
||||
minute = 0
|
||||
if len(msg) > 1 and is_number(msg[1]):
|
||||
hour = int(msg[1])
|
||||
if len(msg) > 2 and is_number(msg[2]):
|
||||
minute = int(msg[2])
|
||||
time = hour * 60 * 60 + minute * 60
|
||||
time = time if time else -1
|
||||
if await BanUser.ban(
|
||||
qq, 9, time
|
||||
):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
|
||||
)
|
||||
result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time/60} 分钟后解封"
|
||||
else:
|
||||
result += f"将在 ∞ 分钟后解封"
|
||||
await ban.send(result)
|
||||
else:
|
||||
time = await BanUser.check_ban_time(qq)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
else:
|
||||
time += " 分钟"
|
||||
await ban.send(f"{qq} 已在黑名单!预计 {time}后解封")
|
||||
else:
|
||||
if await BanUser.unban(qq):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 解禁"
|
||||
)
|
||||
result = f"已经把 {qq} 从黑名单中删除了!"
|
||||
else:
|
||||
result = f"{qq} 不在黑名单!"
|
||||
await ban.send(result)
|
||||
else:
|
||||
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
|
||||
|
||||
|
||||
@super_ban.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
qq = get_message_at(event.json())
|
||||
else:
|
||||
qq = get_message_text(event.json())
|
||||
if not is_number(qq):
|
||||
await super_ban.finish("对象qq必须为纯数字...")
|
||||
qq = [qq]
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
|
||||
user_name = user['card'] if user['card'] else user['nickname']
|
||||
if not await BanUser.ban(qq, 10, 99999999):
|
||||
await BanUser.unban(qq)
|
||||
await BanUser.ban(qq, 10, 99999999)
|
||||
await ban.send(f"已将 {user_name} 拉入黑名单!")
|
||||
else:
|
||||
await super_ban.send('需要艾特被super ban的对象..')
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.permission import SUPERUSER
|
||||
import asyncio
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from services.log import logger
|
||||
from utils.message_builder import image
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
|
||||
__zx_plugin_name__ = "广播 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
指令:
|
||||
广播- ?[消息] ?[图片]
|
||||
示例:广播- 你们好!
|
||||
""".strip()
|
||||
__plugin_des__ = "昭告天下!"
|
||||
__plugin_cmd__ = ["广播-"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"broadcast": "广播"}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_BROADCAST",
|
||||
True,
|
||||
help_="被动 广播 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@broadcast.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_imgs(event.json())
|
||||
rst = ""
|
||||
for img in imgs:
|
||||
rst += image(img)
|
||||
sid = bot.self_id
|
||||
gl = await bot.get_group_list(self_id=sid)
|
||||
gl = [
|
||||
g["group_id"]
|
||||
for g in gl
|
||||
if await group_manager.check_group_task_status(g["group_id"], "broadcast")
|
||||
]
|
||||
g_cnt = len(gl)
|
||||
cnt = 0
|
||||
error = ""
|
||||
x = 0.25
|
||||
for g in gl:
|
||||
cnt += 1
|
||||
if cnt / g_cnt > x:
|
||||
await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊")
|
||||
x += 0.25
|
||||
try:
|
||||
await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst)
|
||||
logger.info(f"GROUP {g} 投递广播成功")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {g} 投递广播失败:{type(e)}")
|
||||
error += f"GROUP {g} 投递广播失败:{type(e)}\n"
|
||||
await asyncio.sleep(0.5)
|
||||
await broadcast.send(f"已播报至 100% 的群聊")
|
||||
if error:
|
||||
await broadcast.send(f"播报时错误:{error}")
|
||||
@@ -0,0 +1,200 @@
|
||||
from nonebot import on_notice, on_request
|
||||
from configs.path_config import IMAGE_PATH, DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
GroupIncreaseNoticeEvent,
|
||||
GroupDecreaseNoticeEvent,
|
||||
)
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from utils.manager import group_manager, plugins2settings_manager, requests_manager
|
||||
from configs.config import NICKNAME
|
||||
from models.group_info import GroupInfo
|
||||
from utils.utils import FreqLimiter
|
||||
from configs.config import Config
|
||||
from pathlib import Path
|
||||
import random
|
||||
import os
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
__zx_plugin_name__ = "群事件处理 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"}
|
||||
Config.add_plugin_config(
|
||||
"invite_manager", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"invite_manager", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_GROUP_WELCOME",
|
||||
True,
|
||||
help_="被动 进群欢迎 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_REFUND_GROUP_REMIND",
|
||||
True,
|
||||
help_="被动 退群提醒 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd"))
|
||||
|
||||
|
||||
# 群员增加处理
|
||||
group_increase_handle = on_notice(priority=1, block=False)
|
||||
# 群员减少处理
|
||||
group_decrease_handle = on_notice(priority=1, block=False)
|
||||
# (群管理)加群同意请求
|
||||
add_group = on_request(priority=1, block=False)
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
if event.user_id == int(bot.self_id):
|
||||
group = await GroupInfo.get_group_info(event.group_id)
|
||||
# 群聊不存在或被强制拉群,退出该群
|
||||
if (not group or group.group_flag == 0) and Config.get_config(
|
||||
"invite_manager", "flag"
|
||||
):
|
||||
try:
|
||||
msg = Config.get_config("invite_manager", "message")
|
||||
if msg:
|
||||
await bot.send_group_msg(group_id=event.group_id, message=msg)
|
||||
await bot.set_group_leave(group_id=event.group_id)
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..",
|
||||
)
|
||||
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功")
|
||||
requests_manager.remove_request("group", event.group_id)
|
||||
except Exception as e:
|
||||
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}")
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..",
|
||||
)
|
||||
# 默认群功能开关
|
||||
elif event.group_id not in group_manager["group_manager"].keys():
|
||||
data = plugins2settings_manager.get_data()
|
||||
for plugin in data.keys():
|
||||
if not data[plugin]["default_status"]:
|
||||
group_manager.block_plugin(plugin, event.group_id)
|
||||
else:
|
||||
join_time = datetime.now()
|
||||
user_info = await bot.get_group_member_info(
|
||||
group_id=event.group_id, user_id=event.user_id
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
user_info["nickname"],
|
||||
join_time,
|
||||
):
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
|
||||
|
||||
# 群欢迎消息
|
||||
if await group_manager.check_group_task_status(
|
||||
event.group_id, "group_welcome"
|
||||
) and _flmt.check(event.group_id):
|
||||
_flmt.start_cd(event.group_id)
|
||||
msg = ""
|
||||
img = ""
|
||||
at_flag = False
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
if custom_welcome_msg_json.exists():
|
||||
data = json.load(open(custom_welcome_msg_json, "r"))
|
||||
if data.get(str(event.group_id)):
|
||||
msg = data[str(event.group_id)]
|
||||
if msg.find("[at]") != -1:
|
||||
msg = msg.replace("[at]", "")
|
||||
at_flag = True
|
||||
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
|
||||
img = image(
|
||||
abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"
|
||||
)
|
||||
if msg or img:
|
||||
await group_increase_handle.send(
|
||||
"\n" + msg.strip() + img, at_sender=at_flag
|
||||
)
|
||||
else:
|
||||
await group_increase_handle.send(
|
||||
"新人快跑啊!!本群现状↓(快使用自定义!)"
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
|
||||
)
|
||||
|
||||
|
||||
@group_decrease_handle.handle()
|
||||
async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
|
||||
# 被踢出群
|
||||
if event.sub_type == "kick_me":
|
||||
group_id = event.group_id
|
||||
operator_id = event.operator_id
|
||||
try:
|
||||
operator_name = (
|
||||
await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
|
||||
).user_name
|
||||
except AttributeError:
|
||||
operator_name = "None"
|
||||
group = await GroupInfo.get_group_info(group_id)
|
||||
group_name = group.group_name if group else ""
|
||||
coffee = int(list(bot.config.superusers)[0])
|
||||
await bot.send_private_msg(
|
||||
user_id=coffee,
|
||||
message=f"****呜..一份踢出报告****\n"
|
||||
f"我被 {operator_name}({operator_id})\n"
|
||||
f"踢出了 {group_name}({group_id})\n"
|
||||
f"日期:{str(datetime.now()).split('.')[0]}",
|
||||
)
|
||||
return
|
||||
if event.user_id == int(bot.self_id):
|
||||
group_manager.delete_group(event.group_id)
|
||||
return
|
||||
try:
|
||||
user_name = (
|
||||
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
|
||||
).user_name
|
||||
except AttributeError:
|
||||
user_name = str(event.user_id)
|
||||
if await GroupInfoUser.delete_member_info(event.user_id, event.group_id):
|
||||
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功")
|
||||
else:
|
||||
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
|
||||
if await group_manager.check_group_task_status(
|
||||
event.group_id, "refund_group_remind"
|
||||
):
|
||||
rst = ""
|
||||
if event.sub_type == "leave":
|
||||
rst = f"{user_name}离开了我们..."
|
||||
if event.sub_type == "kick":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=event.operator_id, group_id=event.group_id
|
||||
)
|
||||
operator_name = (
|
||||
operator["card"] if operator["card"] else operator["nickname"]
|
||||
)
|
||||
rst = f"{user_name} 被 {operator_name} 送走了."
|
||||
try:
|
||||
await group_decrease_handle.send(f"{rst}")
|
||||
except ActionFailed:
|
||||
return
|
||||
@@ -0,0 +1,73 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from configs.path_config import IMAGE_PATH, DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_img, get_plugin_help
|
||||
from utils.utils import get_message_text
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "帮助"
|
||||
|
||||
group_help_path = Path(DATA_PATH) / "group_help"
|
||||
help_image = Path(IMAGE_PATH) / "help.png"
|
||||
simple_help_image = Path(IMAGE_PATH) / "simple_help.png"
|
||||
if help_image.exists():
|
||||
help_image.unlink()
|
||||
if simple_help_image.exists():
|
||||
simple_help_image.unlink()
|
||||
group_help_path.mkdir(exist_ok=True, parents=True)
|
||||
for x in os.listdir(group_help_path):
|
||||
group_help_image = group_help_path / x
|
||||
group_help_image.unlink()
|
||||
|
||||
_help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True)
|
||||
simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
|
||||
|
||||
|
||||
@_help.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not help_image.exists():
|
||||
if help_image.exists():
|
||||
help_image.unlink()
|
||||
if simple_help_image.exists():
|
||||
simple_help_image.unlink()
|
||||
await create_help_img(None, help_image, simple_help_image)
|
||||
await _help.finish(image("help.png"))
|
||||
|
||||
|
||||
@simple_help.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
is_super = False
|
||||
if msg:
|
||||
if '-super' in msg:
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
is_super = True
|
||||
msg = msg.replace('-super', '').strip()
|
||||
msg = get_plugin_help(msg, is_super)
|
||||
if msg:
|
||||
await _help.send(image(b64=msg))
|
||||
else:
|
||||
await _help.send("没有此功能的帮助信息...")
|
||||
else:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
_image_path = group_help_path / f"{event.group_id}.png"
|
||||
if not _image_path.exists():
|
||||
await create_help_img(event.group_id, help_image, _image_path)
|
||||
await simple_help.send(image(_image_path))
|
||||
else:
|
||||
if not simple_help_image.exists():
|
||||
if help_image.exists():
|
||||
help_image.unlink()
|
||||
if simple_help_image.exists():
|
||||
simple_help_image.unlink()
|
||||
await create_help_img(None, help_image, simple_help_image)
|
||||
await _help.finish(image("simple_help.png"))
|
||||
@@ -0,0 +1,367 @@
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
admin_manager,
|
||||
plugins_manager,
|
||||
group_manager,
|
||||
)
|
||||
from typing import Optional
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from utils.utils import get_matchers
|
||||
import random
|
||||
import asyncio
|
||||
import nonebot
|
||||
import os
|
||||
|
||||
|
||||
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
|
||||
|
||||
async def create_help_img(
|
||||
group_id: Optional[int], help_image: Path, simple_help_image: Path
|
||||
):
|
||||
"""
|
||||
生成帮助图片
|
||||
:param group_id: 群号
|
||||
:param help_image: 图片路径
|
||||
:param simple_help_image: 简易帮助图片路径
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None, _create_help_img, group_id, help_image, simple_help_image
|
||||
)
|
||||
|
||||
|
||||
def _create_help_img(
|
||||
group_id: Optional[int], help_image: Path, simple_help_image: Path
|
||||
):
|
||||
"""
|
||||
生成帮助图片
|
||||
:param group_id: 群号
|
||||
:param help_image: 图片路径
|
||||
:param simple_help_image: 简易帮助图片路径
|
||||
"""
|
||||
_matchers = get_matchers()
|
||||
width = 0
|
||||
matchers_data = {}
|
||||
_des_tmp = {}
|
||||
_plugin_name_tmp = []
|
||||
_tmp = []
|
||||
tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
|
||||
font_height = tmp_img.h
|
||||
# 插件分类
|
||||
for matcher in _matchers:
|
||||
plugin_name = None
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
try:
|
||||
plugin_des = _module.__getattribute__("__plugin_des__")
|
||||
except AttributeError:
|
||||
plugin_des = "_"
|
||||
if (
|
||||
"[hidden]" in plugin_name.lower()
|
||||
or "[admin]" in plugin_name.lower()
|
||||
or "[superuser]" in plugin_name.lower()
|
||||
or plugin_name in _plugin_name_tmp
|
||||
or plugin_name == "帮助"
|
||||
):
|
||||
continue
|
||||
plugin_type = ("normal",)
|
||||
text_type = 0
|
||||
if plugins2settings_manager.get(
|
||||
matcher.module
|
||||
) and plugins2settings_manager[matcher.module].get("plugin_type"):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(matcher.module)[
|
||||
"plugin_type"
|
||||
]
|
||||
)
|
||||
else:
|
||||
try:
|
||||
plugin_type = _module.__getattribute__("__plugin_type__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if len(plugin_type) > 1:
|
||||
try:
|
||||
text_type = int(plugin_type[1])
|
||||
except ValueError as e:
|
||||
logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}")
|
||||
plugin_type = plugin_type[0]
|
||||
else:
|
||||
plugin_type = plugin_type[0]
|
||||
try:
|
||||
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
|
||||
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
|
||||
except AttributeError:
|
||||
plugin_cmd = []
|
||||
if plugin_type not in matchers_data.keys():
|
||||
matchers_data[plugin_type] = {}
|
||||
if plugin_des in _des_tmp.keys():
|
||||
try:
|
||||
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = (
|
||||
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"]
|
||||
+ plugin_cmd
|
||||
)
|
||||
except KeyError as e:
|
||||
logger.warning(f"{type(e)}: {e}")
|
||||
else:
|
||||
matchers_data[plugin_type][plugin_name] = {
|
||||
"module": matcher.module,
|
||||
"des": plugin_des,
|
||||
"cmd": plugin_cmd,
|
||||
"text_type": text_type,
|
||||
}
|
||||
try:
|
||||
if text_type == 0:
|
||||
x = tmp_img.getsize(
|
||||
f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
|
||||
+ " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
|
||||
)[0]
|
||||
width = width if width > x else x
|
||||
except KeyError:
|
||||
pass
|
||||
if plugin_des not in _des_tmp:
|
||||
_des_tmp[plugin_des] = plugin_name
|
||||
except AttributeError as e:
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}")
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
_plugin_name_tmp.append(plugin_name)
|
||||
help_img_list = []
|
||||
simple_help_img_list = []
|
||||
types = list(matchers_data.keys())
|
||||
types.sort()
|
||||
ix = 0
|
||||
# 详细帮助
|
||||
for type_ in types:
|
||||
keys = list(matchers_data[type_].keys())
|
||||
keys.sort()
|
||||
help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
|
||||
simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
|
||||
for i, k in enumerate(keys):
|
||||
# 禁用flag
|
||||
flag = True
|
||||
if plugins_manager.get_plugin_status(
|
||||
matchers_data[type_][k]["module"], "all"
|
||||
):
|
||||
flag = False
|
||||
if group_id:
|
||||
flag = flag and plugins_manager.get_plugin_status(
|
||||
matchers_data[type_][k]["module"], "group"
|
||||
)
|
||||
simple_help_str += (
|
||||
f"{i+1}.{k}<|_|~|>"
|
||||
f"{group_manager.get_plugin_status(matchers_data[type_][k]['module'], group_id) if group_id else '_'}|"
|
||||
f"{flag}\n"
|
||||
)
|
||||
if matchers_data[type_][k]["text_type"] == 1:
|
||||
_x = tmp_img.getsize(
|
||||
f"{i+1}".rjust(5)
|
||||
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
|
||||
)[0]
|
||||
_str = (
|
||||
f"{i+1}".rjust(5)
|
||||
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
|
||||
)
|
||||
_str += matchers_data[type_][k]["cmd"][0] + "\n"
|
||||
for c in matchers_data[type_][k]["cmd"][1:]:
|
||||
_str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n"
|
||||
help_str += _str
|
||||
else:
|
||||
help_str += (
|
||||
f"{i+1}".rjust(5)
|
||||
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
|
||||
+ " / ".join(matchers_data[type_][k]["cmd"])
|
||||
+ "\n"
|
||||
)
|
||||
height = len(help_str.split("\n")) * (font_height + 5)
|
||||
simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
|
||||
A = BuildImage(
|
||||
width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
|
||||
)
|
||||
A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
|
||||
# 生成各个分类的插件简易帮助图片
|
||||
simple_width = 0
|
||||
for x in [
|
||||
tmp_img.getsize(x.split("<|_|~|>")[0])[0]
|
||||
for x in simple_help_str.split("\n")
|
||||
]:
|
||||
simple_width = simple_width if simple_width > x else x
|
||||
bk = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED")
|
||||
B = BuildImage(
|
||||
simple_width + 20,
|
||||
simple_height,
|
||||
font_size=24,
|
||||
color="white" if not ix % 2 else "black",
|
||||
)
|
||||
# 切分,判断插件开关状态
|
||||
_s_height = 10
|
||||
for _s in simple_help_str.split("\n"):
|
||||
text_color = (255, 255, 255) if ix % 2 else (0, 0, 0)
|
||||
_line_flag = False
|
||||
if "<|_|~|>" in _s:
|
||||
_x = _s.split("<|_|~|>")
|
||||
_flag_sp = _x[-1].split("|")
|
||||
if group_id:
|
||||
if _flag_sp[0].lower() != "true":
|
||||
text_color = (252, 75, 13)
|
||||
if _flag_sp[1].lower() == "true":
|
||||
_line_flag = True
|
||||
_s = _x[0]
|
||||
B.text((10, _s_height), _s, text_color)
|
||||
if _line_flag:
|
||||
B.line(
|
||||
(
|
||||
7,
|
||||
_s_height + int(B.getsize(_s)[1] / 2) + 2,
|
||||
B.getsize(_s)[0] + 11,
|
||||
_s_height + int(B.getsize(_s)[1] / 2) + 2,
|
||||
),
|
||||
(236, 66, 7),
|
||||
3,
|
||||
)
|
||||
_s_height += B.getsize("1")[1] + 5
|
||||
# B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
|
||||
bk.paste(B, center_type="center")
|
||||
bk.transparent(2)
|
||||
ix += 1
|
||||
help_img_list.append(A)
|
||||
simple_help_img_list.append(bk)
|
||||
height = 0
|
||||
for img in help_img_list:
|
||||
height += img.h
|
||||
if not group_id:
|
||||
A = BuildImage(width + 150, height + 50, font_size=24)
|
||||
A.text(
|
||||
(10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n'
|
||||
)
|
||||
current_height = 50
|
||||
for img in help_img_list:
|
||||
A.paste(img, (0, current_height))
|
||||
current_height += img.h
|
||||
A.save(help_image)
|
||||
# 详细帮助生成完毕
|
||||
# 简易帮助图片合成
|
||||
height = 0
|
||||
width = 0
|
||||
for img in simple_help_img_list:
|
||||
if img.h > height:
|
||||
height = img.h
|
||||
width += img.w + 10
|
||||
B = BuildImage(width + 100, height + 250, font_size=24)
|
||||
width, _ = get_max_width_or_paste(simple_help_img_list, B)
|
||||
bk = None
|
||||
random_bk = os.listdir(random_bk_path)
|
||||
if random_bk:
|
||||
bk = random.choice(random_bk)
|
||||
x = max(width + 50, height + 250)
|
||||
B = BuildImage(
|
||||
x,
|
||||
x,
|
||||
font_size=24,
|
||||
color="#FFEFD5",
|
||||
background=random_bk_path / bk,
|
||||
)
|
||||
B.filter("GaussianBlur", 10)
|
||||
_, B = get_max_width_or_paste(simple_help_img_list, B, True)
|
||||
w = 10
|
||||
h = 10
|
||||
for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
|
||||
text = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=msg,
|
||||
font_size=24,
|
||||
font="yuanshen.ttf",
|
||||
)
|
||||
B.paste(text, (w, h), True)
|
||||
h += 50
|
||||
if msg == "目前支持的功能列表:":
|
||||
w += 50
|
||||
B.paste(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
|
||||
font_size=24,
|
||||
font="yuanshen.ttf",
|
||||
font_color=(231, 74, 57)
|
||||
),
|
||||
(300, 10),
|
||||
True,
|
||||
)
|
||||
B.save(simple_help_image)
|
||||
|
||||
|
||||
def get_max_width_or_paste(
|
||||
simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False
|
||||
) -> "int, BuildImage":
|
||||
"""
|
||||
获取最大宽度,或直接贴图
|
||||
:param simple_help_img_list: 简单帮助图片列表
|
||||
:param B: 背景图
|
||||
:param is_paste: 是否直接贴图
|
||||
"""
|
||||
current_width = 50
|
||||
current_height = 180
|
||||
max_width = simple_help_img_list[0].w
|
||||
for i in range(len(simple_help_img_list)):
|
||||
try:
|
||||
if is_paste and B:
|
||||
B.paste(simple_help_img_list[i], (current_width, current_height), True)
|
||||
current_height += simple_help_img_list[i].h + 40
|
||||
if current_height + simple_help_img_list[i + 1].h > B.h - 10:
|
||||
current_height = 180
|
||||
current_width += max_width + 30
|
||||
max_width = 0
|
||||
elif simple_help_img_list[i].w > max_width:
|
||||
max_width = simple_help_img_list[i].w
|
||||
except IndexError:
|
||||
pass
|
||||
if current_width > simple_help_img_list[0].w + 50:
|
||||
current_width += simple_help_img_list[-1].w
|
||||
return current_width, B
|
||||
|
||||
|
||||
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
||||
"""
|
||||
获取功能的帮助信息
|
||||
:param msg: 功能cmd
|
||||
:param is_super: 是否为超级用户
|
||||
"""
|
||||
module = plugins2settings_manager.get_plugin_module(msg)
|
||||
if not module:
|
||||
module = admin_manager.get_plugin_module(msg)
|
||||
if module:
|
||||
try:
|
||||
plugin = nonebot.plugin.get_plugin(module)
|
||||
if plugin:
|
||||
if is_super:
|
||||
result = plugin.module.__getattribute__(
|
||||
"__plugin_superuser_usage__"
|
||||
)
|
||||
else:
|
||||
result = plugin.module.__getattribute__("__plugin_usage__")
|
||||
if result:
|
||||
width = 0
|
||||
for x in result.split("\n"):
|
||||
_width = len(x) * 24
|
||||
width = width if width > _width else _width
|
||||
height = len(result.split("\n")) * 45
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
bk = BuildImage(
|
||||
width,
|
||||
height,
|
||||
background=Path(IMAGE_PATH) / "background" / "1.png",
|
||||
)
|
||||
A.paste(bk, alpha=True)
|
||||
A.text((int(width * 0.048), int(height * 0.21)), result)
|
||||
return A.pic2bs4()
|
||||
except AttributeError:
|
||||
pass
|
||||
return None
|
||||
@@ -0,0 +1,36 @@
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"CHECK_NOTICE_INFO_CD",
|
||||
300,
|
||||
name="基础hook配置",
|
||||
help_="群检测,个人权限检测等各种检测提示信息cd",
|
||||
default_value=300
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"MALICIOUS_BAN_TIME",
|
||||
30,
|
||||
help_="恶意命令触发检测触发后ban的时长(分钟)",
|
||||
default_value=30
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"MALICIOUS_CHECK_TIME",
|
||||
5,
|
||||
help_="恶意命令触发检测规定时间内(秒)",
|
||||
default_value=5
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"MALICIOUS_BAN_COUNT",
|
||||
6,
|
||||
help_="恶意命令触发检测最大触发次数",
|
||||
default_value=6
|
||||
)
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
admin_manager,
|
||||
group_manager,
|
||||
plugins_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager
|
||||
)
|
||||
from .utils import set_block_limit_false, status_message_manager
|
||||
from nonebot.typing import T_State
|
||||
from typing import Optional
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent,
|
||||
PrivateMessageEvent,
|
||||
Message,
|
||||
Event
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import FreqLimiter
|
||||
from utils.message_builder import at
|
||||
from models.level_user import LevelUser
|
||||
import nonebot
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
|
||||
# 权限检测
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
module = matcher.module
|
||||
plugins2info_dict = plugins2settings_manager.get_data()
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
cost_gold = 0
|
||||
if isinstance(event, GroupMessageEvent) and plugins2settings_manager.get_plugin_data(module).get('cost_gold'):
|
||||
cost_gold = plugins2settings_manager.get_plugin_data(module).get('cost_gold')
|
||||
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
|
||||
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
|
||||
raise IgnoredException(f"{module} 金币限制...")
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if str(event.user_id) in bot.config.superusers and not plugins2info_dict[module]["limit_superuser"]:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
try:
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 超级用户命令
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(module)
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 群黑名单检测 群总开关检测
|
||||
if isinstance(event, GroupMessageEvent) or matcher.module == "poke":
|
||||
try:
|
||||
if group_manager.get_group_level(event.group_id) < 0:
|
||||
raise IgnoredException("群黑名单")
|
||||
if not group_manager.check_group_bot_status(event.group_id):
|
||||
try:
|
||||
if str(event.get_message()) != "醒来":
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except ValueError:
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except AttributeError:
|
||||
pass
|
||||
if module in admin_manager.keys() and matcher.priority not in [1, 9]:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
if (
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(module),
|
||||
)
|
||||
and admin_manager.get_plugin_level(module) > 0
|
||||
):
|
||||
try:
|
||||
if _flmt.check(event.user_id):
|
||||
_flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
set_block_limit_false(event, module)
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
raise IgnoredException("权限不足")
|
||||
else:
|
||||
if not await LevelUser.check_level(
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
):
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
set_block_limit_false(event, module)
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.user_id)
|
||||
raise IgnoredException("权限不足")
|
||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
||||
# 戳一戳单独判断
|
||||
if isinstance(event, GroupMessageEvent) or (
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
):
|
||||
if status_message_manager.get(event.group_id) is None:
|
||||
status_message_manager.delete(event.group_id)
|
||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||
event.group_id
|
||||
):
|
||||
try:
|
||||
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
||||
_flmt_g.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="群权限不足..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("群权限不足")
|
||||
# 插件状态
|
||||
if not group_manager.get_plugin_status(module, event.group_id):
|
||||
try:
|
||||
if module not in ignore_rst_module and _flmt_s.check(
|
||||
event.group_id
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="该群未开启此功能.."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("未开启此功能...")
|
||||
# 管理员禁用
|
||||
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
|
||||
try:
|
||||
if (
|
||||
_flmt_s.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="管理员禁用了此群该功能..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("管理员禁用了此群该功能...")
|
||||
# 群聊禁用
|
||||
if not plugins_manager.get_plugin_status(module, block_type="group"):
|
||||
try:
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="该功能在群聊中已被禁用..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("该插件在群聊中已被禁用...")
|
||||
else:
|
||||
# 私聊禁用
|
||||
if not plugins_manager.get_plugin_status(module, block_type="private"):
|
||||
try:
|
||||
if _flmt_c.check(event.user_id):
|
||||
_flmt_c.start_cd(event.user_id)
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id, message="该功能在私聊中已被禁用..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.user_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("该插件在私聊中已被禁用...")
|
||||
# 维护
|
||||
if not plugins_manager.get_plugin_status(module, block_type="all"):
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
) and group_manager.check_group_is_white(event.group_id):
|
||||
return
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="此功能正在维护..."
|
||||
)
|
||||
else:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id, message="此功能正在维护..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
id_ = (
|
||||
event.group_id
|
||||
if isinstance(event, GroupMessageEvent)
|
||||
else event.user_id
|
||||
)
|
||||
status_message_manager.add(id_)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("此功能正在维护...")
|
||||
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
module = matcher.module
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and status_message_manager.get(event.group_id) is None
|
||||
):
|
||||
status_message_manager.delete(event.group_id)
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, module):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
rst = plugin_count_data["rst"]
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(module, count_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(module, count_type_)
|
||||
# 功能花费的金币 #######################################
|
||||
# 功能花费的金币 #######################################
|
||||
if cost_gold:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
|
||||
|
||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
发送信息
|
||||
:param rst: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
rst = await init_rst(rst, event)
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||
except ActionFailed:
|
||||
pass
|
||||
|
||||
|
||||
# 解除命令block阻塞
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
rst = rst.replace("[nickname]", nickname)
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import is_number, static_flmt, FreqLimiter
|
||||
from utils.message_builder import at
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"BAN_RESULT",
|
||||
"才不会给你发消息.",
|
||||
help_="对被ban用户发送的消息",
|
||||
)
|
||||
|
||||
_flmt = FreqLimiter(300)
|
||||
|
||||
|
||||
# 检查是否被ban
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
try:
|
||||
if (
|
||||
await BanUser.is_super_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("用户处于超级黑名单中")
|
||||
except AttributeError:
|
||||
pass
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.priority not in [1, 9]:
|
||||
if (
|
||||
await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
time = await BanUser.check_ban_time(event.user_id)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
else:
|
||||
time = str(time) + " 分钟"
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if not static_flmt.check(event.user_id):
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
static_flmt.start_cd(event.user_id)
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if ban_result and _flmt.check(event.user_id):
|
||||
_flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=at(event.user_id)
|
||||
+ ban_result
|
||||
+ f" 在..在 {time} 后才会理你喔",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
else:
|
||||
if not static_flmt.check(event.user_id):
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
static_flmt.start_cd(event.user_id)
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if ban_result:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=at(event.user_id)
|
||||
+ ban_result
|
||||
+ f" 在..在 {time}后才会理你喔",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
@@ -0,0 +1,54 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import BanCheckLimiter
|
||||
from utils.message_builder import at
|
||||
from services.log import logger
|
||||
|
||||
|
||||
_blmt = BanCheckLimiter(
|
||||
Config.get_config("hook", "MALICIOUS_CHECK_TIME"),
|
||||
Config.get_config("hook", "MALICIOUS_BAN_COUNT"),
|
||||
)
|
||||
|
||||
|
||||
# 恶意触发命令检测
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.priority not in [1, 9]:
|
||||
if state["_prefix"]["raw_command"]:
|
||||
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
|
||||
if await BanUser.ban(
|
||||
event.user_id,
|
||||
9,
|
||||
Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
|
||||
):
|
||||
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
try:
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
raise IgnoredException("检测到恶意触发命令")
|
||||
_blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}')
|
||||
@@ -0,0 +1,41 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.typing import T_State
|
||||
from .utils import status_message_manager
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
PrivateMessageEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
|
||||
|
||||
# 为什么AI会自己和自己聊天
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if event.user_id == int(bot.self_id):
|
||||
raise IgnoredException("为什么AI会自己和自己聊天")
|
||||
|
||||
|
||||
# 有命令就别说话了
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.module == "ai":
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and not status_message_manager.check(event.group_id)
|
||||
):
|
||||
status_message_manager.delete(event.group_id)
|
||||
raise IgnoredException("有命令就别说话了")
|
||||
elif (
|
||||
isinstance(event, PrivateMessageEvent)
|
||||
and not status_message_manager.check(event.user_id)
|
||||
):
|
||||
print(status_message_manager)
|
||||
status_message_manager.delete(event.user_id)
|
||||
raise IgnoredException("有命令就别说话了")
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
|
||||
from utils.manager import plugins2block_manager, StaticData
|
||||
import time
|
||||
|
||||
|
||||
class StatusMessageManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
def add(self, id_: int):
|
||||
self._data[id_] = time.time()
|
||||
|
||||
def delete(self, id_: int):
|
||||
if self._data.get(id_):
|
||||
del self._data[id_]
|
||||
|
||||
def check(self, id_: int, t: int = 30) -> bool:
|
||||
if self._data.get(id_):
|
||||
if time.time() - self._data[id_] > t:
|
||||
del self._data[id_]
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
status_message_manager = StatusMessageManager()
|
||||
|
||||
|
||||
def set_block_limit_false(event, module):
|
||||
"""
|
||||
设置用户block为false
|
||||
:param event: event
|
||||
:param module: 插件模块
|
||||
"""
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
if not (
|
||||
(isinstance(event, GroupMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
plugins2block_manager.set_false(block_type_, module)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_postprocessor
|
||||
from typing import Optional
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from utils.manager import withdraw_message_manager
|
||||
import asyncio
|
||||
|
||||
|
||||
# 消息撤回
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
tasks = []
|
||||
for id_, time in withdraw_message_manager.data:
|
||||
tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time)))
|
||||
withdraw_message_manager.remove((id_, time))
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
async def _withdraw_message(bot: Bot, id_: int, time: int):
|
||||
await asyncio.sleep(time)
|
||||
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id))
|
||||
@@ -0,0 +1,61 @@
|
||||
from .init_group_manager import init_group_manager, group_manager
|
||||
from .init_plugins_config import init_plugins_config
|
||||
from .init_plugins_data import init_plugins_data, plugins_manager
|
||||
from .init_none_plugin_count_manager import init_none_plugin_count_manager
|
||||
from .init_plugins_resources import init_plugins_resources
|
||||
from .init_plugins_settings import init_plugins_settings
|
||||
from .init_plugins_limit import (
|
||||
init_plugins_block_limit,
|
||||
init_plugins_count_limit,
|
||||
init_plugins_cd_limit,
|
||||
)
|
||||
from .init import init
|
||||
from .check_plugin_status import check_plugin_status
|
||||
from utils.manager import admin_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from configs.path_config import DATA_PATH
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from nonebot import Driver
|
||||
import nonebot
|
||||
|
||||
|
||||
__zx_plugin_name__ = "初始化插件数据 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
def _():
|
||||
"""
|
||||
初始化数据
|
||||
"""
|
||||
_flag = False
|
||||
config_file = Path(DATA_PATH) / "configs" / "plugins2config.yaml"
|
||||
if not config_file.exists():
|
||||
_flag = True
|
||||
init()
|
||||
init_plugins_settings(DATA_PATH)
|
||||
init_plugins_cd_limit(DATA_PATH)
|
||||
init_plugins_block_limit(DATA_PATH)
|
||||
init_plugins_count_limit(DATA_PATH)
|
||||
init_plugins_data(DATA_PATH)
|
||||
init_plugins_config(DATA_PATH)
|
||||
init_plugins_resources()
|
||||
init_none_plugin_count_manager()
|
||||
x = group_manager.get_super_old_data()
|
||||
if x:
|
||||
for key in x.keys():
|
||||
plugins_manager.block_plugin(key, block_type=x[key])
|
||||
if _flag:
|
||||
raise Exception("首次运行,已在configs目录下生成配置文件config.yaml,修改后重启即可...")
|
||||
logger.info("初始化数据完成...")
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _(bot: Bot):
|
||||
await init_group_manager()
|
||||
await check_plugin_status(bot)
|
||||
@@ -0,0 +1,18 @@
|
||||
from utils.manager import plugins_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
|
||||
|
||||
async def check_plugin_status(bot: Bot):
|
||||
"""
|
||||
遍历查看插件加载情况
|
||||
"""
|
||||
rst = ""
|
||||
for plugin in plugins_manager.keys():
|
||||
data = plugins_manager.get(plugin)
|
||||
if data.get("error") or data.get("error") is None:
|
||||
rst += f'{plugin}:{data["plugin_name"]}\n'
|
||||
if rst:
|
||||
rst = "以下插件加载失败..\n" + rst
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=rst[:-1]
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
from utils.manager import plugins2settings_manager
|
||||
|
||||
|
||||
def init():
|
||||
if plugins2settings_manager.get("update_pic"):
|
||||
plugins2settings_manager["update_picture"] = plugins2settings_manager["update_pic"]
|
||||
plugins2settings_manager.delete("update_pic")
|
||||
if plugins2settings_manager.get("white2black_img"):
|
||||
plugins2settings_manager["white2black_image"] = plugins2settings_manager["white2black_img"]
|
||||
plugins2settings_manager.delete("white2black_img")
|
||||
if plugins2settings_manager.get("send_img"):
|
||||
plugins2settings_manager["send_image"] = plugins2settings_manager["send_img"]
|
||||
plugins2settings_manager.delete("send_img")
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
from pathlib import Path
|
||||
from utils.manager import group_manager
|
||||
from services.db_context import db
|
||||
from asyncpg.exceptions import DuplicateColumnError
|
||||
from services.log import logger
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
try:
|
||||
from models.group_remind import GroupRemind
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
async def init_group_manager():
|
||||
"""
|
||||
旧数据格式替换为新格式
|
||||
初始化数据
|
||||
"""
|
||||
old_group_level_file = Path() / "data" / "manager" / "group_level.json"
|
||||
old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json"
|
||||
if old_group_level_file.exists():
|
||||
data = json.load(open(old_group_level_file, "r", encoding="utf8"))
|
||||
for key in data.keys():
|
||||
group = key
|
||||
level = data[key]
|
||||
group_manager.set_group_level(group, level)
|
||||
old_group_level_file.unlink()
|
||||
group_manager.save()
|
||||
|
||||
if old_plugin_list_file.exists():
|
||||
data = json.load(open(old_plugin_list_file, "r", encoding="utf8"))
|
||||
for plugin in data.keys():
|
||||
for group in data[plugin].keys():
|
||||
if group == "default" and not data[plugin]["default"]:
|
||||
group_manager.block_plugin(plugin)
|
||||
elif not data[plugin][group]:
|
||||
group_manager.block_plugin(plugin, group)
|
||||
old_plugin_list_file.unlink()
|
||||
old_data_table = Path() / "models" / "group_remind.py"
|
||||
try:
|
||||
if old_data_table.exists():
|
||||
b = {
|
||||
"hy": "group_welcome",
|
||||
"kxcz": "open_case_reset_remind",
|
||||
"zwa": "zwa",
|
||||
"blpar": "bilibili_parse",
|
||||
"epic": "epic_free_game",
|
||||
"pa": "pa",
|
||||
"almanac": "genshin_alc",
|
||||
}
|
||||
for group in group_manager.get_data()["group_manager"]:
|
||||
for remind in b:
|
||||
try:
|
||||
status = await GroupRemind.get_status(int(group), remind)
|
||||
if status is not None:
|
||||
if status:
|
||||
await group_manager.open_group_task(group, b[remind])
|
||||
logger.info(f"读取旧数据-->{group} 开启 {b[remind]}")
|
||||
else:
|
||||
await group_manager.close_group_task(group, b[remind])
|
||||
logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}")
|
||||
except Exception as e:
|
||||
pass
|
||||
query = db.text("DROP TABLE group_reminds;")
|
||||
await db.first(query)
|
||||
old_data_table.unlink()
|
||||
logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...")
|
||||
except (ModuleNotFoundError, DuplicateColumnError):
|
||||
pass
|
||||
group_manager.save()
|
||||
@@ -0,0 +1,45 @@
|
||||
from utils.manager import (
|
||||
none_plugin_count_manager,
|
||||
plugins2count_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2settings_manager,
|
||||
plugins2block_manager,
|
||||
plugins_manager,
|
||||
resources_manager
|
||||
)
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
def init_none_plugin_count_manager():
|
||||
"""
|
||||
清除已删除插件数据
|
||||
"""
|
||||
modules = [x.module for x in get_matchers()]
|
||||
for module in none_plugin_count_manager.keys():
|
||||
if module not in modules:
|
||||
none_plugin_count_manager.add_count(module)
|
||||
else:
|
||||
none_plugin_count_manager.reset(module)
|
||||
if none_plugin_count_manager.check(module):
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
except (AttributeError, KeyError):
|
||||
plugin_name = ""
|
||||
try:
|
||||
plugins2settings_manager.delete(module)
|
||||
plugins2count_manager.delete(module)
|
||||
plugins2cd_manager.delete(module)
|
||||
plugins2block_manager.delete(module)
|
||||
plugins_manager.delete(module)
|
||||
resources_manager.remove_resource(module)
|
||||
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
|
||||
)
|
||||
@@ -0,0 +1,150 @@
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
||||
from utils.manager import admin_manager, plugins_manager
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from ruamel import yaml
|
||||
import nonebot
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_config(data_path):
|
||||
"""
|
||||
初始化插件数据配置
|
||||
"""
|
||||
plugins2config_file = Path(data_path) / "configs" / "plugins2config.yaml"
|
||||
plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
_data = {}
|
||||
if plugins2config_file.exists():
|
||||
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
continue
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
plugin_version = None
|
||||
try:
|
||||
plugin_configs = _module.__getattribute__("__plugin_configs__")
|
||||
except AttributeError:
|
||||
continue
|
||||
# 插件配置版本更新或为Version为None或不在存储配置内
|
||||
if (
|
||||
plugin_version is None
|
||||
or (
|
||||
_data.get(matcher.module)
|
||||
and _data[matcher.module].keys() != plugin_configs.keys()
|
||||
)
|
||||
or plugin_version > plugins_manager.get(matcher.module)["version"]
|
||||
or matcher.module not in _data.keys()
|
||||
):
|
||||
for key in plugin_configs:
|
||||
if isinstance(plugin_configs[key], dict):
|
||||
Config.add_plugin_config(
|
||||
matcher.module,
|
||||
key,
|
||||
plugin_configs[key].get("value"),
|
||||
help_=plugin_configs[key].get("help"),
|
||||
default_value=plugin_configs[key].get("default_value"),
|
||||
_override=True,
|
||||
)
|
||||
else:
|
||||
Config.add_plugin_config(matcher.module, key, plugin_configs[key])
|
||||
else:
|
||||
plugin_configs = _data[matcher.module]
|
||||
for key in plugin_configs:
|
||||
Config.add_plugin_config(
|
||||
matcher.module,
|
||||
key,
|
||||
plugin_configs[key]["value"],
|
||||
help_=plugin_configs[key]["help"],
|
||||
default_value=plugin_configs[key]["default_value"],
|
||||
_override=True,
|
||||
)
|
||||
if not Config.is_empty():
|
||||
Config.save()
|
||||
_data = round_trip_load(open(plugins2config_file, encoding="utf8"))
|
||||
for plugin in _data.keys():
|
||||
try:
|
||||
plugin_name = plugins_manager.get(plugin)["plugin_name"]
|
||||
except (AttributeError, TypeError):
|
||||
plugin_name = plugin
|
||||
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
|
||||
# 初始化未设置的管理员权限等级
|
||||
for k, v in Config.get_admin_level_data():
|
||||
admin_manager.set_admin_level(k, v)
|
||||
# 存完插件基本设置
|
||||
with open(plugins2config_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(
|
||||
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
# 再开始读取用户配置
|
||||
user_config_file = Path() / "configs" / "config.yaml"
|
||||
_data = {}
|
||||
_tmp_data = {}
|
||||
if user_config_file.exists():
|
||||
with open(user_config_file, "r", encoding="utf8") as f:
|
||||
_data = _yaml.load(f)
|
||||
# 数据替换
|
||||
for plugin in Config.keys():
|
||||
_tmp_data[plugin] = {}
|
||||
for k in Config[plugin].keys():
|
||||
if _data.get(plugin) and k in _data[plugin].keys():
|
||||
Config.set_config(plugin, k, _data[plugin][k])
|
||||
if level2module := Config.get_level2module(plugin, k):
|
||||
admin_manager.set_admin_level(level2module, _data[plugin][k])
|
||||
_tmp_data[plugin][k] = Config.get_config(plugin, k)
|
||||
Config.save()
|
||||
temp_file = Path() / "configs" / "temp_config.yaml"
|
||||
try:
|
||||
with open(temp_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(
|
||||
_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
with open(temp_file, "r", encoding="utf8") as rf:
|
||||
_data = round_trip_load(rf)
|
||||
# 添加注释
|
||||
for plugin in _data.keys():
|
||||
rst = ""
|
||||
plugin_name = None
|
||||
try:
|
||||
plugin_data = Config.get(plugin)
|
||||
for x in list(Config.get(plugin).keys()):
|
||||
try:
|
||||
_x = plugin_data[x].get("name")
|
||||
if _x:
|
||||
plugin_name = _x
|
||||
except AttributeError:
|
||||
pass
|
||||
except (KeyError, AttributeError):
|
||||
plugin_name = None
|
||||
if not plugin_name:
|
||||
try:
|
||||
plugin_name = plugins_manager.get(plugin)["plugin_name"]
|
||||
except (AttributeError, TypeError):
|
||||
plugin_name = plugin
|
||||
plugin_name = (
|
||||
plugin_name.replace("[Hidden]", "")
|
||||
.replace("[Superuser]", "")
|
||||
.replace("[Admin]", "")
|
||||
.strip()
|
||||
)
|
||||
rst += plugin_name + "\n"
|
||||
for k in _data[plugin].keys():
|
||||
rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
|
||||
_data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
|
||||
with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
|
||||
round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
|
||||
if temp_file.exists():
|
||||
temp_file.unlink()
|
||||
@@ -0,0 +1,82 @@
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from utils.manager import plugins_manager
|
||||
from utils.utils import get_matchers
|
||||
import nonebot
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_data(data_path):
|
||||
"""
|
||||
初始化插件数据信息
|
||||
"""
|
||||
plugin2data_file = Path(data_path) / "manager" / "plugin_manager.json"
|
||||
plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
_data = {}
|
||||
if plugin2data_file.exists():
|
||||
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
if matcher.module not in _data.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.module, matcher.module, error=True
|
||||
)
|
||||
else:
|
||||
plugins_manager.set_module_data(matcher.module, "error", True)
|
||||
plugin_data = plugins_manager.get(matcher.module)
|
||||
if plugin_data:
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "version", plugin_data.get("version")
|
||||
)
|
||||
else:
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
plugin_version = None
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.module
|
||||
try:
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
except AttributeError:
|
||||
plugin_author = None
|
||||
if matcher.module in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.module, "error", False)
|
||||
if matcher.module not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.module,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
version=plugin_version,
|
||||
)
|
||||
elif plugins_manager[matcher.module]["version"] is None or (
|
||||
plugin_version is not None
|
||||
and plugin_version > plugins_manager[matcher.module]["version"]
|
||||
):
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "plugin_name", plugin_name
|
||||
)
|
||||
plugins_manager.set_module_data(matcher.module, "author", plugin_author)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "version", plugin_version
|
||||
)
|
||||
if matcher.module in _data.keys():
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "error", _data[matcher.module]["error"]
|
||||
)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "plugin_name", _data[matcher.module]["plugin_name"]
|
||||
)
|
||||
plugins_manager.save()
|
||||
@@ -0,0 +1,157 @@
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
||||
from utils.manager import (
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from utils.utils import get_matchers
|
||||
from ruamel import yaml
|
||||
import nonebot
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_cd_limit(data_path):
|
||||
"""
|
||||
加载 cd 限制
|
||||
"""
|
||||
plugins2cd_file = Path(data_path) / "configs" / "plugins2cd.yaml"
|
||||
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2cd_manager.get_plugin_cd_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
|
||||
plugins2cd_manager.add_cd_limit(
|
||||
matcher.module, data_dict=plugin_cd_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
if not plugins2cd_manager.keys():
|
||||
plugins2cd_manager.add_cd_limit(
|
||||
"这是一个示例"
|
||||
)
|
||||
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
|
||||
with open(plugins2cd_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
|
||||
_data["PluginCdLimit"].yaml_set_start_comment(
|
||||
"""# 需要cd的功能
|
||||
# 自定义的功能需要cd也可以在此配置
|
||||
# key:模块名称
|
||||
# cd:cd 时长(秒)
|
||||
# status:此限制的开关状态
|
||||
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(plugins2cd_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2cd_manager.reload_cd_limit()
|
||||
|
||||
|
||||
def init_plugins_block_limit(data_path):
|
||||
"""
|
||||
加载阻塞限制
|
||||
"""
|
||||
plugins2block_file = Path(data_path) / "configs" / "plugins2block.yaml"
|
||||
plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2block_manager.get_plugin_block_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
|
||||
plugins2block_manager.add_block_limit(
|
||||
matcher.module, data_dict=plugin_block_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
if not plugins2block_manager.keys():
|
||||
plugins2block_manager.add_block_limit(
|
||||
"这是一个示例"
|
||||
)
|
||||
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
|
||||
with open(plugins2block_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2block_file, encoding="utf8"))
|
||||
_data["PluginBlockLimit"].yaml_set_start_comment(
|
||||
"""# 用户调用阻塞
|
||||
# 即 当用户调用此功能还未结束时
|
||||
# 用发送消息阻止用户重复调用此命令直到该命令结束
|
||||
# key:模块名称
|
||||
# status:此限制的开关状态
|
||||
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':阻塞用户,'group':阻塞群聊
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(plugins2block_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2block_manager.reload_block_limit()
|
||||
|
||||
|
||||
def init_plugins_count_limit(data_path):
|
||||
"""
|
||||
加载次数限制
|
||||
"""
|
||||
plugins2count_file = Path(data_path) / "configs" / "plugins2count.yaml"
|
||||
plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2count_manager.get_plugin_count_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
|
||||
plugins2count_manager.add_count_limit(
|
||||
matcher.module, data_dict=plugin_count_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
if not plugins2count_manager.keys():
|
||||
plugins2count_manager.add_count_limit(
|
||||
"这是一个示例"
|
||||
)
|
||||
_tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()}
|
||||
with open(plugins2count_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2count_file, encoding="utf8"))
|
||||
_data["PluginCountLimit"].yaml_set_start_comment(
|
||||
"""# 命令每日次数限制
|
||||
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
|
||||
# 每日调用直到 00:00 刷新
|
||||
# key:模块名称
|
||||
# max_count: 每日调用上限
|
||||
# status:此限制的开关状态
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':用户上限,'group':群聊上限
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(plugins2count_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2count_manager.reload_count_limit()
|
||||
@@ -0,0 +1,43 @@
|
||||
from utils.manager import resources_manager
|
||||
from utils.utils import get_matchers
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
import nonebot
|
||||
|
||||
|
||||
def init_plugins_resources():
|
||||
"""
|
||||
资源文件路径的移动
|
||||
"""
|
||||
_tmp = []
|
||||
for matcher in get_matchers():
|
||||
if matcher.module not in _tmp:
|
||||
_tmp.append(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...")
|
||||
else:
|
||||
try:
|
||||
resources = _module.__getattribute__("__plugin_resources__")
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
path = Path(_module.__getattribute__("__file__")).parent
|
||||
for resource in resources.keys():
|
||||
resources_manager.add_resource(matcher.module, (path / resource).absolute(), resources[resource])
|
||||
resources_manager.save()
|
||||
resources_manager.start_move()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
||||
from utils.manager import plugins2settings_manager, admin_manager
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from ruamel import yaml
|
||||
import nonebot
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_settings(data_path: str):
|
||||
"""
|
||||
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
|
||||
"""
|
||||
plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml"
|
||||
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_matchers = get_matchers()
|
||||
_tmp_module = {}
|
||||
_tmp = []
|
||||
for x in plugins2settings_manager.keys():
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(x)
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
_tmp_module[x] = plugin_name
|
||||
except (KeyError, AttributeError) as e:
|
||||
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||
_tmp_module[x] = ""
|
||||
for matcher in _matchers:
|
||||
if matcher.module not in plugins2settings_manager.keys():
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
logger.warning(f"插件 {matcher.module} 加载失败...,插件控制未加载.")
|
||||
else:
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if "[admin]" in plugin_name.lower():
|
||||
try:
|
||||
admin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
level = admin_settings["admin_level"]
|
||||
cmd = admin_settings.get("cmd")
|
||||
except (AttributeError, KeyError):
|
||||
level = 5
|
||||
cmd = None
|
||||
if level is None:
|
||||
level = 5
|
||||
admin_manager.add_admin_plugin_settings(
|
||||
matcher.module, cmd, level
|
||||
)
|
||||
if (
|
||||
"[hidden]" in plugin_name.lower()
|
||||
or "[admin]" in plugin_name.lower()
|
||||
or "[superuser]" in plugin_name.lower()
|
||||
or matcher.module in plugins2settings_manager.keys()
|
||||
):
|
||||
continue
|
||||
except AttributeError:
|
||||
if matcher.module not in _tmp:
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
else:
|
||||
try:
|
||||
_tmp_module[matcher.module] = plugin_name
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
if plugin_settings.get('cost_gold') is None:
|
||||
plugin_settings['cost_gold'] = 0
|
||||
if (
|
||||
plugin_settings["cmd"] is not None
|
||||
and plugin_name not in plugin_settings["cmd"]
|
||||
):
|
||||
plugin_settings["cmd"].append(plugin_name)
|
||||
if plugins2settings_manager.get(
|
||||
matcher.module
|
||||
) and plugins2settings_manager[matcher.module].get(
|
||||
"plugin_type"
|
||||
):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(
|
||||
matcher.module
|
||||
)["plugin_type"]
|
||||
)
|
||||
else:
|
||||
try:
|
||||
plugin_type = _module.__getattribute__(
|
||||
"__plugin_type__"
|
||||
)
|
||||
except AttributeError:
|
||||
plugin_type = ("normal",)
|
||||
if plugin_settings and matcher.module:
|
||||
plugins2settings_manager.add_plugin_settings(
|
||||
matcher.module,
|
||||
plugin_type=plugin_type,
|
||||
**plugin_settings,
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
_tmp.append(matcher.module)
|
||||
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2settings_file, encoding="utf8"))
|
||||
_data["PluginSettings"].yaml_set_start_comment(
|
||||
"""# 模块与对应命令和对应群权限
|
||||
# 用于生成帮助图片 和 开关功能
|
||||
# key:模块名称
|
||||
# level:需要的群等级
|
||||
# default_status:加入群时功能的默认开关状态
|
||||
# limit_superuser: 功能状态是否限制超级用户
|
||||
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
|
||||
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
|
||||
indent=2,
|
||||
)
|
||||
for plugin in _data["PluginSettings"].keys():
|
||||
_data["PluginSettings"][plugin].yaml_set_start_comment(
|
||||
f"{plugin}:{_tmp_module[plugin]}", indent=2
|
||||
)
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
|
||||
@@ -0,0 +1,149 @@
|
||||
from nonebot import on_request, on_message
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
FriendRequestEvent,
|
||||
GroupRequestEvent,
|
||||
MessageEvent,
|
||||
)
|
||||
from models.friend_user import FriendUser
|
||||
from datetime import datetime
|
||||
from configs.config import NICKNAME, Config
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from utils.manager import requests_manager
|
||||
from models.group_info import GroupInfo
|
||||
from utils.utils import scheduler
|
||||
import asyncio
|
||||
import time
|
||||
import re
|
||||
|
||||
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False}
|
||||
}
|
||||
|
||||
friend_req = on_request(priority=5, block=True)
|
||||
group_req = on_request(priority=5, block=True)
|
||||
x = on_message(priority=9, block=False)
|
||||
|
||||
exists_data = {"private": {}, "group": {}}
|
||||
|
||||
|
||||
@friend_req.handle()
|
||||
async def _(bot: Bot, event: FriendRequestEvent, state: dict):
|
||||
global exists_data
|
||||
if exists_data["private"].get(event.user_id):
|
||||
if time.time() - exists_data["private"][event.user_id] < 60 * 5:
|
||||
return
|
||||
exists_data["private"][event.user_id] = time.time()
|
||||
user = await bot.get_stranger_info(user_id=event.user_id)
|
||||
nickname = user["nickname"]
|
||||
sex = user["sex"]
|
||||
age = str(user["age"])
|
||||
comment = event.comment
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"*****一份好友申请*****\n"
|
||||
f"昵称:{nickname}({event.user_id})\n"
|
||||
f"自动同意:{'√' if Config.get_config('invite_manager', 'AUTO_ADD_FRIEND') else '×'}\n"
|
||||
f"日期:{str(datetime.now()).split('.')[0]}\n"
|
||||
f"备注:{event.comment}",
|
||||
)
|
||||
if Config.get_config("invite_manager", "AUTO_ADD_FRIEND"):
|
||||
await bot.set_friend_add_request(flag=event.flag, approve=True)
|
||||
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
|
||||
else:
|
||||
requests_manager.add_request(
|
||||
event.user_id,
|
||||
"private",
|
||||
event.flag,
|
||||
nickname=nickname,
|
||||
sex=sex,
|
||||
age=age,
|
||||
comment=comment,
|
||||
)
|
||||
|
||||
|
||||
@group_req.handle()
|
||||
async def _(bot: Bot, event: GroupRequestEvent, state: dict):
|
||||
global exists_data
|
||||
if event.sub_type == "invite":
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
try:
|
||||
if await GroupInfo.get_group_info(event.group_id):
|
||||
await GroupInfo.set_group_flag(event.group_id, 1)
|
||||
else:
|
||||
group_info = await bot.get_group_info(group_id=event.group_id)
|
||||
await GroupInfo.add_group_info(
|
||||
group_info["group_id"],
|
||||
group_info["group_name"],
|
||||
group_info["max_member_count"],
|
||||
group_info["member_count"],
|
||||
1,
|
||||
)
|
||||
await bot.set_group_add_request(
|
||||
flag=event.flag, sub_type="invite", approve=True
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
else:
|
||||
user = await bot.get_stranger_info(user_id=event.user_id)
|
||||
sex = user["sex"]
|
||||
age = str(user["age"])
|
||||
if exists_data["group"].get(f"{event.user_id}:{event.group_id}"):
|
||||
if (
|
||||
time.time()
|
||||
- exists_data["group"][f"{event.user_id}:{event.group_id}"]
|
||||
< 60 * 5
|
||||
):
|
||||
return
|
||||
exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time()
|
||||
nickname = await FriendUser.get_user_name(event.user_id)
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"*****一份入群申请*****\n"
|
||||
f"申请人:{nickname}({event.user_id})\n"
|
||||
f"群聊:{event.group_id}\n"
|
||||
f"邀请日期:{str(datetime.now()).split('.')[0]}",
|
||||
)
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
|
||||
"请确保已经群主或群管理沟通过!\n"
|
||||
"等待管理员处理吧!",
|
||||
)
|
||||
requests_manager.add_request(
|
||||
event.user_id,
|
||||
"group",
|
||||
event.flag,
|
||||
invite_group=event.group_id,
|
||||
nickname=nickname,
|
||||
sex=sex,
|
||||
age=age,
|
||||
)
|
||||
|
||||
|
||||
@x.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
await asyncio.sleep(0.1)
|
||||
r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
|
||||
if r:
|
||||
group_id = int(r.group(1))
|
||||
else:
|
||||
return
|
||||
r = re.search(r'groupname="(.*?)"', str(event.get_message()))
|
||||
if r:
|
||||
group_name = r.group(1)
|
||||
else:
|
||||
group_name = "None"
|
||||
requests_manager.set_group_name(group_name, group_id)
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"interval",
|
||||
minutes=5,
|
||||
)
|
||||
async def _():
|
||||
global exists_data
|
||||
exists_data = {"private": {}, "group": {}}
|
||||
@@ -0,0 +1,201 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.friend_user import FriendUser
|
||||
import random
|
||||
from models.ban_user import BanUser
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME, Config
|
||||
|
||||
|
||||
__zx_plugin_name__ = "昵称系统"
|
||||
__plugin_usage__ = f"""
|
||||
usage:
|
||||
个人昵称系统,群聊 与 私聊 昵称相互独立
|
||||
指令:
|
||||
以后叫我 [昵称]
|
||||
{NICKNAME}我是谁
|
||||
""".strip()
|
||||
__plugin_des__ = "区区昵称,才不想叫呢!"
|
||||
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"BLACK_WORD": {
|
||||
"value": ["爸", "爹", "爷"],
|
||||
"help": "昵称所屏蔽的关键词,会被替换为 *",
|
||||
"default_value": None
|
||||
}
|
||||
}
|
||||
|
||||
nickname = on_command(
|
||||
"nickname",
|
||||
aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
|
||||
rule=to_me(),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
|
||||
my_nickname = on_command(
|
||||
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
|
||||
|
||||
|
||||
@nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if not msg:
|
||||
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
|
||||
if len(msg) > 10:
|
||||
await nickname.finish("昵称可不能超过10个字!", at_sender=True)
|
||||
if msg in bot.config.superusers:
|
||||
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
for x in msg:
|
||||
_tmp += "*" if x in black_word else x
|
||||
msg = _tmp
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if await GroupInfoUser.set_group_member_nickname(
|
||||
event.user_id, event.group_id, msg
|
||||
):
|
||||
if len(msg) < 5:
|
||||
if random.random() < 0.3:
|
||||
msg = "~".join(msg)
|
||||
await nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
||||
f"好..好.,那窝以后就叫你{msg}了.",
|
||||
]
|
||||
)
|
||||
)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
|
||||
else:
|
||||
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
|
||||
else:
|
||||
if await FriendUser.set_friend_nickname(event.user_id, msg):
|
||||
await nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
||||
f"好..好.,那窝以后就叫你{msg}了.",
|
||||
]
|
||||
)
|
||||
)
|
||||
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
|
||||
else:
|
||||
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
|
||||
|
||||
|
||||
@my_nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
try:
|
||||
nickname_ = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
except AttributeError:
|
||||
nickname_ = ""
|
||||
if nickname_:
|
||||
await my_nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"我肯定记得你啊,你是{nickname_}啊",
|
||||
f"我不会忘记你的,你也不要忘记我!{nickname_}",
|
||||
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
|
||||
f"嗯?你是失忆了嘛...{nickname_}..",
|
||||
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
|
||||
f"哎?{nickname_}..怎么了吗..突然这样问..",
|
||||
]
|
||||
)
|
||||
)
|
||||
else:
|
||||
nickname_ = event.sender.card if event.sender.card else event.sender.nickname
|
||||
await my_nickname.send(
|
||||
random.choice(
|
||||
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
|
||||
).format(nickname_)
|
||||
)
|
||||
|
||||
|
||||
@my_nickname.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if nickname_:
|
||||
await my_nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"我肯定记得你啊,你是{nickname_}啊",
|
||||
f"我不会忘记你的,你也不要忘记我!{nickname_}",
|
||||
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
|
||||
f"嗯?你是失忆了嘛...{nickname_}..",
|
||||
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
|
||||
f"哎?{nickname_}..怎么了吗..突然这样问..",
|
||||
]
|
||||
)
|
||||
)
|
||||
else:
|
||||
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
|
||||
await my_nickname.send(
|
||||
random.choice(
|
||||
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
|
||||
).format(nickname_)
|
||||
)
|
||||
|
||||
|
||||
@cancel_nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
nickname_ = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
if nickname_:
|
||||
await cancel_nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
|
||||
f"窝知道了..{nickname_}..",
|
||||
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
|
||||
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
|
||||
f"可..可恶!{nickname_}!太可恶了!呜",
|
||||
]
|
||||
)
|
||||
)
|
||||
await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
|
||||
await BanUser.ban(event.user_id, 9, 60)
|
||||
else:
|
||||
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
|
||||
|
||||
|
||||
@cancel_nickname.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if nickname_:
|
||||
await cancel_nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
|
||||
f"窝知道了..{nickname_}..",
|
||||
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
|
||||
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
|
||||
f"可..可恶!{nickname_}!太可恶了!呜",
|
||||
]
|
||||
)
|
||||
)
|
||||
await FriendUser.get_user_name(event.user_id)
|
||||
await BanUser.ban(event.user_id, 9, 60)
|
||||
else:
|
||||
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
|
||||
@@ -0,0 +1,115 @@
|
||||
from nonebot import Driver
|
||||
from services.db_context import db
|
||||
from asyncpg.exceptions import DuplicateColumnError
|
||||
from models.group_info import GroupInfo
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from services.log import logger
|
||||
from configs.path_config import TEXT_PATH
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import scheduler
|
||||
from pathlib import Path
|
||||
import nonebot
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def update_city():
|
||||
"""
|
||||
部分插件需要中国省份城市
|
||||
这里直接更新,避免插件内代码重复
|
||||
"""
|
||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||
data = {}
|
||||
if not china_city.exists():
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
"""
|
||||
数据库表结构变换
|
||||
"""
|
||||
sql_str = [
|
||||
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;" # group_info表添加一个group_flag
|
||||
]
|
||||
for sql in sql_str:
|
||||
try:
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
except DuplicateColumnError:
|
||||
pass
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _(bot: Bot):
|
||||
"""
|
||||
版本某些需要的变换
|
||||
"""
|
||||
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
|
||||
if not await GroupInfo.get_group_info(114514):
|
||||
# 标识符,该功能只需执行一次
|
||||
await GroupInfo.add_group_info(114514, "114514", 114514, 114514, 1)
|
||||
group_list = await bot.get_group_list()
|
||||
group_list = [g["group_id"] for g in group_list]
|
||||
_gl = [x.group_id for x in await GroupInfo.get_all_group()]
|
||||
if 114514 in _gl:
|
||||
_gl.remove(114514)
|
||||
for group_id in _gl:
|
||||
if group_id in group_list:
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 1)
|
||||
else:
|
||||
group_info = await bot.get_group_info(group_id=group_id)
|
||||
await GroupInfo.add_group_info(
|
||||
group_info["group_id"],
|
||||
group_info["group_name"],
|
||||
group_info["max_member_count"],
|
||||
group_info["member_count"],
|
||||
1,
|
||||
)
|
||||
logger.info(f"已将群聊 {group_id} 添加认证...")
|
||||
else:
|
||||
await GroupInfo.delete_group_info(group_id)
|
||||
logger.info(f"移除不存在的群聊信息:{group_id}")
|
||||
|
||||
|
||||
# 自动更新城市列表
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=6,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
await update_city()
|
||||
@@ -0,0 +1,14 @@
|
||||
import nonebot
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"shop",
|
||||
"IMPORT_DEFAULT_SHOP_GOODS",
|
||||
True,
|
||||
help_="导入商店自带的三个商品",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
|
||||
nonebot.load_plugins("basic_plugins/shop")
|
||||
@@ -0,0 +1,86 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from models.goods_info import GoodsInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
goods = None
|
||||
if get_message_text(event.json()) in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.buy_props(event.user_id, event.group_id, goods, num):
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
@@ -0,0 +1,52 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from utils.data_utils import init_rank
|
||||
from models.bag_user import BagUser
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_message_text, is_number
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的金币"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的金币
|
||||
指令:
|
||||
我的金币
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的金币"
|
||||
__plugin_cmd__ = ["我的金币"]
|
||||
__plugin_type__ = ("商店",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的金币"],
|
||||
}
|
||||
|
||||
|
||||
my_gold = on_command("我的金币", priority=5, block=True, permission=GROUP)
|
||||
|
||||
gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_gold.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await my_gold.finish(await BagUser.get_my_total_gold(event.user_id, event.group_id))
|
||||
|
||||
|
||||
@gold_rank.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
num = get_message_text(event.json())
|
||||
if is_number(num) and 51 > int(num) > 10:
|
||||
num = int(num)
|
||||
else:
|
||||
num = 10
|
||||
all_users = await BagUser.get_all_users(event.group_id)
|
||||
all_user_id = [user.user_qq for user in all_users]
|
||||
all_user_data = [user.gold for user in all_users]
|
||||
rank_image = await init_rank("金币排行", all_user_id, all_user_data, event.group_id, num)
|
||||
if rank_image:
|
||||
await gold_rank.finish(image(b64=rank_image.pic2bs4()))
|
||||
@@ -0,0 +1,52 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
pname_list = []
|
||||
pnum_list = []
|
||||
rst = ""
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p in pname_list:
|
||||
pnum_list[pname_list.index(p)] += 1
|
||||
else:
|
||||
pname_list.append(p)
|
||||
pnum_list.append(1)
|
||||
for i in range(len(pname_list)):
|
||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
@@ -0,0 +1,26 @@
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
@@ -0,0 +1,133 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, registered_goods, parse_goods_info
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
商店项目,这可不是奸商
|
||||
指令:
|
||||
商店
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
商品操作
|
||||
指令:
|
||||
添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)
|
||||
删除商品 [名称或序号]
|
||||
修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时]
|
||||
示例:添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||
示例:添加商品 name:可疑的药 price:5 des:效果未知
|
||||
示例:删除商品 2
|
||||
示例:修改商品 name:1 price:900 修改序号为1的商品的价格为900
|
||||
* 修改商品只需添加需要值即可 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店系统[金币回收计划]"
|
||||
__plugin_cmd__ = [
|
||||
"商店",
|
||||
"添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)) [_superuser]",
|
||||
"删除商品 [名称或序号] [_superuser]",
|
||||
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
|
||||
]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店"],
|
||||
}
|
||||
__plugin_block_limit__ = {
|
||||
"limit_type": "group"
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.registered_goods = registered_goods
|
||||
export.delete_goods = delete_goods
|
||||
export.update_goods = update_goods
|
||||
|
||||
shop_help = on_command("商店", priority=5, block=True)
|
||||
|
||||
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@shop_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await shop_help.send(image(b64=await create_shop_help()))
|
||||
|
||||
|
||||
@shop_add_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
await shop_add_goods.finish(data)
|
||||
if not data.get("name") or not data.get("price") or not data.get("des"):
|
||||
await shop_add_goods.finish("name:price:des 参数不可缺少!")
|
||||
if await registered_goods(**data):
|
||||
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
|
||||
f"名称:{data['name']}\n"
|
||||
f"价格:{data['price']}金币\n"
|
||||
f"简介:{data['des']}\n"
|
||||
f"折扣:{data.get('discount')}\n"
|
||||
f"限时:{data.get('limit_time')}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 添加商品 {msg} 成功")
|
||||
else:
|
||||
await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败")
|
||||
|
||||
|
||||
@shop_del_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
name = ""
|
||||
id_ = 0
|
||||
if is_number(msg):
|
||||
id_ = int(msg)
|
||||
else:
|
||||
name = msg
|
||||
rst, goods_name, code = await delete_goods(name, id_)
|
||||
if code == 200:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
|
||||
else:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
|
||||
|
||||
|
||||
@shop_update_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
await shop_add_goods.finish(data)
|
||||
if not data.get("name"):
|
||||
await shop_add_goods.finish("name 参数不可缺少!")
|
||||
flag, name, text = await update_goods(**data)
|
||||
if flag:
|
||||
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
|
||||
else:
|
||||
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Union
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from nonebot.plugin import require
|
||||
import nonebot
|
||||
import time
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
use = require("use")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def init_default_shop_goods():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
async def sign_card_1(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.1).apply()
|
||||
|
||||
async def sign_card_2(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.2).apply()
|
||||
|
||||
async def sign_card_3(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.3).apply()
|
||||
|
||||
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
|
||||
await registered_goods(
|
||||
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
|
||||
)
|
||||
use.registered_use("好感度双倍加持卡Ⅰ", sign_card_1)
|
||||
await registered_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
|
||||
use.registered_use("好感度双倍加持卡Ⅱ", sign_card_2)
|
||||
await registered_goods(
|
||||
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
|
||||
)
|
||||
use.registered_use("好感度双倍加持卡Ⅲ", sign_card_3)
|
||||
|
||||
|
||||
# 创建商店界面
|
||||
async def create_shop_help() -> str:
|
||||
"""
|
||||
制作商店图片
|
||||
:return: 图片base64
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
idx = 1
|
||||
_dc = {}
|
||||
font_h = BuildImage(0, 0).getsize("正")[1]
|
||||
h = 10
|
||||
_list = []
|
||||
for goods in goods_lst:
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
|
||||
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
|
||||
_list.append(goods)
|
||||
A = BuildImage(1000, h, color="#f9f6f2")
|
||||
current_h = 0
|
||||
for goods in _list:
|
||||
bk = BuildImage(
|
||||
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
goods_image = BuildImage(
|
||||
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
name_image = BuildImage(
|
||||
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
await name_image.atext(
|
||||
(15, 0), f"{idx}.{goods.goods_name}", center_type="by_height"
|
||||
)
|
||||
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.atext((390, 0), "售价:", center_type="by_height")
|
||||
await name_image.atext(
|
||||
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
|
||||
)
|
||||
await name_image.atext(
|
||||
(
|
||||
440
|
||||
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
|
||||
0,
|
||||
),
|
||||
" 金币",
|
||||
center_type="by_height",
|
||||
)
|
||||
await name_image.acircle_corner(5)
|
||||
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
|
||||
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||
await goods_image.acircle_corner(20)
|
||||
await bk.apaste(goods_image, alpha=True)
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png")
|
||||
await bk.apaste(_limit_time_logo, (600, 0), True)
|
||||
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True)
|
||||
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split()
|
||||
y_m_d = limit_time[0]
|
||||
_h_m = limit_time[1].split(":")
|
||||
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
|
||||
await bk.atext((605, 38), str(y_m_d))
|
||||
await bk.atext((615, 57), str(h_m))
|
||||
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
|
||||
idx += 1
|
||||
await A.apaste(bk, (0, current_h), True)
|
||||
current_h += 90
|
||||
w = 1000
|
||||
h = A.h + 230 + 100
|
||||
h = 1000 if h < 1000 else h
|
||||
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
shop.paste(A, (20, 230))
|
||||
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
|
||||
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
|
||||
await shop.apaste(zx_img, (780, 100))
|
||||
await shop.apaste(shop_logo, (450, 30), True)
|
||||
shop.text(
|
||||
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||
return shop.pic2bs4()
|
||||
|
||||
|
||||
async def registered_goods(
|
||||
name: str,
|
||||
price: int,
|
||||
des: str,
|
||||
discount: Optional[float] = 1,
|
||||
limit_time: Optional[int] = 0,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
添加商品
|
||||
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
|
||||
添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||
添加商品 name:可疑的药 price:5 des:效果未知
|
||||
:param name: 商品名称
|
||||
:param price: 商品价格
|
||||
:param des: 商品简介
|
||||
:param discount: 商品折扣
|
||||
:param limit_time: 商品限时销售时间,单位为小时
|
||||
:param kwargs: kwargs
|
||||
:return: 是否添加成功
|
||||
"""
|
||||
if kwargs:
|
||||
name = kwargs.get("name")
|
||||
price = kwargs.get("price")
|
||||
des = kwargs.get("des")
|
||||
discount = kwargs.get("discount")
|
||||
limit_time = kwargs.get("time_limit")
|
||||
limit_time = float(limit_time) if limit_time else limit_time
|
||||
discount = discount if discount is None else 1
|
||||
limit_time = int(time.time() + limit_time * 60 * 60) if limit_time is not None and limit_time != 0 else 0
|
||||
return await GoodsInfo.add_goods(
|
||||
name, int(price), des, float(discount), limit_time
|
||||
)
|
||||
|
||||
|
||||
# 删除商品
|
||||
async def delete_goods(name: str, id_: int) -> "str, str, int":
|
||||
"""
|
||||
删除商品
|
||||
:param name: 商品名称
|
||||
:param id_: 商品id
|
||||
:return: 删除状况
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if id_:
|
||||
if id_ < 1 or id_ > len(goods_lst):
|
||||
return "序号错误,没有该序号商品...", "", 999
|
||||
goods_name = goods_lst[id_ - 1].goods_name
|
||||
if await GoodsInfo.delete_goods(goods_name):
|
||||
return f"删除商品 {goods_name} 成功!", goods_name, 200
|
||||
else:
|
||||
return f"删除商品 {goods_name} 失败!", goods_name, 999
|
||||
if name:
|
||||
if await GoodsInfo.delete_goods(name):
|
||||
return f"删除商品 {name} 成功!", name, 200
|
||||
else:
|
||||
return f"删除商品 {name} 失败!", name, 999
|
||||
|
||||
|
||||
# 更新商品信息
|
||||
async def update_goods(**kwargs) -> "str, str, int":
|
||||
"""
|
||||
更新商品信息
|
||||
:param kwargs: kwargs
|
||||
:return: 更新状况
|
||||
"""
|
||||
if kwargs:
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if is_number(kwargs["name"]):
|
||||
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
|
||||
return "序号错误,没有该序号的商品...", "", 999
|
||||
goods = goods_lst[int(kwargs["name"]) - 1]
|
||||
else:
|
||||
goods = await GoodsInfo.get_goods_info(kwargs["name"])
|
||||
if not goods:
|
||||
return "名称错误,没有该名称的商品...", "", 999
|
||||
name = goods.goods_name
|
||||
price = goods.goods_price
|
||||
des = goods.goods_description
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
new_time = 0
|
||||
tmp = ""
|
||||
if kwargs.get("price"):
|
||||
tmp += f'价格:{price} --> {kwargs["price"]}\n'
|
||||
price = kwargs["price"]
|
||||
if kwargs.get("des"):
|
||||
tmp += f'描述:{des} --> {kwargs["des"]}\n'
|
||||
des = kwargs["des"]
|
||||
if kwargs.get("discount"):
|
||||
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
|
||||
discount = kwargs["discount"]
|
||||
if kwargs.get("limit_time"):
|
||||
new_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
time.localtime(time.time() + int(kwargs["limit_time"] * 60 * 60)),
|
||||
)
|
||||
tmp += f"折扣至: {new_time}\n"
|
||||
limit_time = kwargs["limit_time"]
|
||||
return (
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
int(price),
|
||||
des,
|
||||
float(discount),
|
||||
int(time.time() + limit_time * 60 * 60 if limit_time != 0 and new_time else 0),
|
||||
),
|
||||
name,
|
||||
tmp[:-1],
|
||||
)
|
||||
|
||||
|
||||
def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||
"""
|
||||
解析格式数据
|
||||
:param msg: 消息
|
||||
:return: 解析完毕的数据data
|
||||
"""
|
||||
if "name:" not in msg:
|
||||
return "必须指定修改的商品名称或序号!"
|
||||
data = {}
|
||||
for x in msg.split():
|
||||
sp = x.split(":", maxsplit=1)
|
||||
if str(sp[1]).strip():
|
||||
sp[1] = sp[1].strip()
|
||||
print(sp)
|
||||
if sp[0] == "name":
|
||||
data["name"] = sp[1]
|
||||
elif sp[0] == "price":
|
||||
if not is_number(sp[1]) or int(sp[1]) < 0:
|
||||
return "price参数不合法,必须大于等于0!"
|
||||
data["price"] = sp[1]
|
||||
elif sp[0] == "des":
|
||||
data["des"] = sp[1]
|
||||
elif sp[0] == "discount":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "discount参数不合法,必须大于0!"
|
||||
data["discount"] = sp[1]
|
||||
elif sp[0] == "limit_time":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "limit_time参数不合法,必须大于0!"
|
||||
data["limit_time"] = sp[1]
|
||||
return data
|
||||
@@ -0,0 +1,76 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import is_number, get_message_text
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.db_context import db
|
||||
from nonebot.plugin import export
|
||||
from .data_source import effect, registered_use
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
普通的使用道具
|
||||
指令:
|
||||
使用道具 [序号或道具名称]
|
||||
* 序号以 ”我的道具“ 为准 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 使用道具"
|
||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.registered_use = registered_use
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg in ["", "帮助"]:
|
||||
await use_props.finish(__plugin_usage__)
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
async with db.transaction():
|
||||
pname_list = []
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p not in pname_list:
|
||||
pname_list.append(p)
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(pname_list):
|
||||
name = pname_list[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if msg not in pname_list:
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
if await BagUser.del_props(
|
||||
event.user_id, event.group_id, name
|
||||
) and await effect(event.user_id, event.group_id, name):
|
||||
await use_props.send(f"使用道具 {name} 成功!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 成功"
|
||||
)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} 失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 失败"
|
||||
)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
@@ -0,0 +1,45 @@
|
||||
import asyncio
|
||||
from services.log import logger
|
||||
|
||||
_use_func_data = {}
|
||||
|
||||
|
||||
async def effect(user_id: int, group_id: int, goods_name: str) -> bool:
|
||||
"""
|
||||
商品生效
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param goods_name: 商品名称
|
||||
:return: 使用是否成功
|
||||
"""
|
||||
# 优先使用注册的商品插件
|
||||
try:
|
||||
if _use_func_data.get(goods_name):
|
||||
_kwargs = _use_func_data[goods_name]["kwargs"]
|
||||
_kwargs["goods_name"] = goods_name
|
||||
_kwargs["user_id"] = user_id
|
||||
_kwargs["group_id"] = group_id
|
||||
if asyncio.iscoroutinefunction(_use_func_data[goods_name]["func"]):
|
||||
await _use_func_data[goods_name]["func"](
|
||||
**_kwargs,
|
||||
)
|
||||
else:
|
||||
_use_func_data[goods_name]["func"](
|
||||
**_kwargs,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
|
||||
def registered_use(goods_name: str, func, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
:param goods_name: 商品名称
|
||||
:param func: 使用函数
|
||||
:param kwargs: kwargs
|
||||
"""
|
||||
if goods_name in _use_func_data.keys():
|
||||
raise ValueError("该商品使用函数已被注册!")
|
||||
_use_func_data[goods_name] = {"func": func, "kwargs": kwargs}
|
||||
@@ -0,0 +1,10 @@
|
||||
import nonebot
|
||||
|
||||
|
||||
nonebot.load_plugins('basic_plugins/super_cmd')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.manager import requests_manager
|
||||
from utils.message_builder import image
|
||||
from models.group_info import GroupInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
显示所有好友群组
|
||||
指令:
|
||||
查看所有好友/查看所有群组
|
||||
同意好友请求 [id]
|
||||
拒绝好友请求 [id]
|
||||
同意群聊请求 [id]
|
||||
拒绝群聊请求 [id]
|
||||
查看所有请求
|
||||
清空所有请求
|
||||
""".strip()
|
||||
__plugin_des__ = "显示所有好友群组"
|
||||
__plugin_cmd__ = [
|
||||
"查看所有好友/查看所有群组",
|
||||
"同意好友请求 [id]",
|
||||
"拒绝好友请求 [id]",
|
||||
"同意群聊请求 [id]",
|
||||
"拒绝群聊请求 [id]",
|
||||
"查看所有请求",
|
||||
"清空所有请求",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
cls_group = on_command(
|
||||
"查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
cls_friend = on_command(
|
||||
"查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
friend_handle = on_command(
|
||||
"同意好友请求", aliases={"拒绝好友请求"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
group_handle = on_command(
|
||||
"同意群聊请求", aliases={"拒绝群聊请求"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
clear_request = on_command("清空所有请求", permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@cls_group.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
gl = await bot.get_group_list(self_id=int(bot.self_id))
|
||||
msg = ["{group_id} {group_name}".format_map(g) for g in gl]
|
||||
msg = "\n".join(msg)
|
||||
msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg
|
||||
await bot.send_private_msg(
|
||||
self_id=int(bot.self_id),
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=msg,
|
||||
)
|
||||
|
||||
|
||||
@cls_friend.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
gl = await bot.get_friend_list(self_id=int(bot.self_id))
|
||||
msg = ["{user_id} {nickname}".format_map(g) for g in gl]
|
||||
msg = "\n".join(msg)
|
||||
msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
|
||||
await bot.send_private_msg(
|
||||
self_id=int(bot.self_id),
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=msg,
|
||||
)
|
||||
|
||||
|
||||
@friend_handle.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = get_message_text(event.json())
|
||||
if is_number(id_):
|
||||
id_ = int(id_)
|
||||
if state["_prefix"]["raw_command"][:2] == "同意":
|
||||
if await requests_manager.approve(bot, id_, "private"):
|
||||
await friend_handle.send("同意好友请求成功..")
|
||||
else:
|
||||
await friend_handle.send("同意好友请求失败,可能是未找到此id的请求..")
|
||||
else:
|
||||
if await requests_manager.refused(bot, id_, "private"):
|
||||
await friend_handle.send("拒绝好友请求成功..")
|
||||
else:
|
||||
await friend_handle.send("拒绝好友请求失败,可能是未找到此id的请求..")
|
||||
else:
|
||||
await friend_handle.send("id必须为纯数字!")
|
||||
|
||||
|
||||
@group_handle.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = get_message_text(event.json())
|
||||
if is_number(id_):
|
||||
id_ = int(id_)
|
||||
if state["_prefix"]["raw_command"][:2] == "同意":
|
||||
rid = await requests_manager.approve(bot, id_, "group")
|
||||
if rid:
|
||||
await friend_handle.send("同意群聊请求成功..")
|
||||
if await GroupInfo.get_group_info(rid):
|
||||
await GroupInfo.set_group_flag(rid, 1)
|
||||
else:
|
||||
group_info = await bot.get_group_info(group_id=rid)
|
||||
await GroupInfo.add_group_info(
|
||||
rid,
|
||||
group_info["group_name"],
|
||||
group_info["max_member_count"],
|
||||
group_info["member_count"],
|
||||
1
|
||||
)
|
||||
else:
|
||||
await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..")
|
||||
else:
|
||||
if await requests_manager.refused(bot, id_, "group"):
|
||||
await friend_handle.send("拒绝群聊请求成功..")
|
||||
else:
|
||||
await friend_handle.send("拒绝群聊请求失败,可能是未找到此id的请求..")
|
||||
else:
|
||||
await friend_handle.send("id必须为纯数字!")
|
||||
|
||||
|
||||
@cls_request.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
_str = ""
|
||||
for type_ in ["private", "group"]:
|
||||
msg = await requests_manager.show(type_)
|
||||
if msg:
|
||||
_str += image(b64=msg)
|
||||
else:
|
||||
_str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
|
||||
if type_ == "private":
|
||||
_str += '\n--------------------\n'
|
||||
await cls_request.send(Message(_str))
|
||||
|
||||
|
||||
@clear_request.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
requests_manager.clear()
|
||||
await cls_request.send("已清空所有好友/群聊请求..")
|
||||
@@ -0,0 +1,67 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from configs.path_config import TEMP_PATH
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import scheduler
|
||||
from services.log import logger
|
||||
from utils.manager import resources_manager
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
|
||||
__zx_plugin_name__ = "清理临时数据 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
清理临时数据
|
||||
指令:
|
||||
清理临时数据
|
||||
""".strip()
|
||||
__plugin_des__ = "清理临时数据"
|
||||
__plugin_cmd__ = [
|
||||
"清理临时数据",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
clear_data = on_command(
|
||||
"清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
|
||||
resources_manager.add_temp_dir(TEMP_PATH)
|
||||
|
||||
|
||||
@clear_data.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await clear_data.send("开始清理临时数据....")
|
||||
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
|
||||
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
|
||||
|
||||
|
||||
def _clear_data() -> float:
|
||||
size = 0
|
||||
for dir_ in resources_manager.get_temp_data_dir():
|
||||
if dir_.exists():
|
||||
for file in os.listdir(dir_):
|
||||
file = dir_ / file
|
||||
try:
|
||||
if time.time() - os.path.getatime(file) > 300:
|
||||
file_size = os.path.getsize(file)
|
||||
file.unlink()
|
||||
size += file_size
|
||||
except Exception as e:
|
||||
logger.error(f"清理临时数据错误...{type(e)}:{e}")
|
||||
return float(size)
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=1,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
|
||||
logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
|
||||
# async def open_remind(group: int, name: str) -> str:
|
||||
# _name = ""
|
||||
# if name == "zwa":
|
||||
# _name = "早晚安"
|
||||
# if name == "dz":
|
||||
# _name = "地震播报"
|
||||
# if name == "hy":
|
||||
# _name = "群欢迎"
|
||||
# if name == "kxcz":
|
||||
# _name = "开箱重置提醒"
|
||||
# if name == "gb":
|
||||
# _name = "广播"
|
||||
# if await GroupRemind.get_status(group, name):
|
||||
# return f"该群已经开启过 {_name} 通知,请勿重复开启!"
|
||||
# if await GroupRemind.set_status(group, name, True):
|
||||
# return f"成功开启 {_name} 通知!0v0"
|
||||
# else:
|
||||
# return f"开启 {_name} 通知失败了..."
|
||||
#
|
||||
#
|
||||
# async def close_remind(group: int, name: str) -> str:
|
||||
# _name = ""
|
||||
# if name == "zwa":
|
||||
# _name = "早晚安"
|
||||
# if name == "dz":
|
||||
# _name = "地震播报"
|
||||
# if name == "hy":
|
||||
# _name = "群欢迎"
|
||||
# if name == "kxcz":
|
||||
# _name = "开箱重置提醒"
|
||||
# if name == "gb":
|
||||
# _name = "广播"
|
||||
# if not await GroupRemind.get_status(group, name):
|
||||
# return f"该群已经取消过 {_name} 通知,请勿重复取消!"
|
||||
# if await GroupRemind.set_status(group, name, False):
|
||||
# return f"成功关闭 {_name} 通知!0v0"
|
||||
# else:
|
||||
# return f"关闭 {_name} 通知失败了..."
|
||||
|
||||
|
||||
# cmd_list = ['总开关', '签到', '发送图片', '色图', '黑白草图', 'coser', '鸡汤/语录', '骂我', '开箱', '鲁迅说', '假消息', '商店系统',
|
||||
# '操作图片', '查询皮肤', '天气', '疫情', '识番', '搜番', '点歌', 'pixiv', 'rss', '方舟一井', '查干员', '骰子娘', '原神一井']
|
||||
#
|
||||
#
|
||||
# def check_group_switch_json(group_id):
|
||||
# if not os.path.exists(DATA_PATH + f'rule/group_switch/'):
|
||||
# os.mkdir(DATA_PATH + f'rule/group_switch/')
|
||||
# if not os.path.exists(DATA_PATH + f'rule/group_switch/{group_id}.json'):
|
||||
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as f:
|
||||
# data = {}
|
||||
# for cmd in cmd_list:
|
||||
# data[cmd] = True
|
||||
# f.write(json.dumps(data, ensure_ascii=False))
|
||||
# else:
|
||||
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'r', encoding='utf8') as f:
|
||||
# try:
|
||||
# data = json.load(f)
|
||||
# except ValueError:
|
||||
# data = {}
|
||||
# if len(data.keys()) - 1 != len(cmd_list):
|
||||
# for cmd in cmd_list:
|
||||
# if cmd not in data.keys():
|
||||
# data[cmd] = True
|
||||
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as wf:
|
||||
# wf.write(json.dumps(data, ensure_ascii=False))
|
||||
# reload(data)
|
||||
# for file in os.listdir(DATA_PATH + 'group_help'):
|
||||
# os.remove(DATA_PATH + f'group_help/{file}')
|
||||
|
||||
|
||||
def reload(data):
|
||||
static_group_dict = data
|
||||
@@ -0,0 +1,38 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from services.db_context import db
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "执行sql [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
执行一段sql语句
|
||||
指令:
|
||||
exec [sql语句]
|
||||
""".strip()
|
||||
__plugin_des__ = "执行一段sql语句"
|
||||
__plugin_cmd__ = [
|
||||
"exec [sql语句]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@exec_.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
sql = get_message_text(event.json())
|
||||
async with db.transaction():
|
||||
try:
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
await exec_.send("执行 sql 语句成功.")
|
||||
except Exception as e:
|
||||
await exec_.send(f"执行 sql 语句失败 {type(e)}:{e}")
|
||||
logger.error(f"执行 sql 语句失败 {type(e)}:{e}")
|
||||
@@ -0,0 +1,200 @@
|
||||
from nonebot import on_command, on_regex
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GROUP, GroupMessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.manager import group_manager, plugins2settings_manager
|
||||
from models.group_info import GroupInfo
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
|
||||
|
||||
__zx_plugin_name__ = "管理群操作 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
群权限 | 群白名单 | 退出群 操作
|
||||
指令:
|
||||
退群 [group_id]
|
||||
修改群权限 [group_id] [等级]
|
||||
添加群白名单 *[group_id]
|
||||
删除群白名单 *[group_id]
|
||||
添加群认证 *[group_id]
|
||||
删除群认证 *[group_id]
|
||||
查看群白名单
|
||||
""".strip()
|
||||
__plugin_des__ = "管理群操作"
|
||||
__plugin_cmd__ = [
|
||||
"退群 [group_id]",
|
||||
"修改群权限 [group_id] [等级]",
|
||||
"添加群白名单 *[group_id]",
|
||||
"删除群白名单 *[group_id]",
|
||||
"添加群认证 *[group_id]",
|
||||
"删除群认证 *[group_id]",
|
||||
"查看群白名单",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True)
|
||||
my_group_level = on_command(
|
||||
"查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True
|
||||
)
|
||||
what_up_group_level = on_regex(
|
||||
".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?",
|
||||
rule=to_me(),
|
||||
priority=5,
|
||||
permission=GROUP,
|
||||
block=True,
|
||||
)
|
||||
manager_group_whitelist = on_command(
|
||||
"添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True
|
||||
)
|
||||
|
||||
show_group_whitelist = on_command(
|
||||
"查看群白名单", priority=1, permission=SUPERUSER, block=True
|
||||
)
|
||||
|
||||
group_auth = on_command(
|
||||
"添加群认证", aliases={"删除群认证"}, priority=1, permission=SUPERUSER, block=True
|
||||
)
|
||||
|
||||
|
||||
@del_group.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_id = get_message_text(event.json())
|
||||
if group_id:
|
||||
if is_number(group_id):
|
||||
try:
|
||||
await bot.set_group_leave(group_id=int(group_id))
|
||||
logger.info(f"退出群聊 {group_id} 成功")
|
||||
await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True)
|
||||
group_manager.delete_group(int(group_id))
|
||||
await GroupInfo.delete_group_info(int(group_id))
|
||||
except Exception as e:
|
||||
logger.info(f"退出群聊 {group_id} 失败 e:{e}")
|
||||
else:
|
||||
await del_group.finish(f"请输入正确的群号", at_sender=True)
|
||||
else:
|
||||
await del_group.finish(f"请输入群号", at_sender=True)
|
||||
|
||||
|
||||
@add_group_level.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
group_id = 0
|
||||
level = 0
|
||||
if not msg:
|
||||
await add_group_level.finish("用法:修改群权限 [group] [level]")
|
||||
msg = msg.split(" ")
|
||||
if len(msg) < 2:
|
||||
await add_group_level.finish("参数不完全..[group] [level]")
|
||||
if is_number(msg[0]) and is_number(msg[1]):
|
||||
group_id = msg[0]
|
||||
level = int(msg[1])
|
||||
else:
|
||||
await add_group_level.finish("参数错误...group和level必须是数字..")
|
||||
old_level = group_manager.get_group_level(group_id)
|
||||
group_manager.set_group_level(group_id, level)
|
||||
await add_group_level.send("修改成功...", at_sender=True)
|
||||
if level > -1:
|
||||
await bot.send_group_msg(
|
||||
group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}"
|
||||
)
|
||||
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}")
|
||||
|
||||
|
||||
@my_group_level.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
level = group_manager.get_group_level(event.group_id)
|
||||
tmp = ""
|
||||
data = plugins2settings_manager.get_data()
|
||||
for module in data:
|
||||
if data[module]["level"] > level:
|
||||
plugin_name = data[module]["cmd"][0]
|
||||
if plugin_name == "pixiv":
|
||||
plugin_name = "搜图 p站排行"
|
||||
tmp += f"{plugin_name}\n"
|
||||
if tmp:
|
||||
tmp = "\n目前无法使用的功能:\n" + tmp
|
||||
await my_group_level.finish(f"当前群权限:{level}{tmp}")
|
||||
|
||||
|
||||
@what_up_group_level.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await what_up_group_level.finish(
|
||||
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
|
||||
)
|
||||
|
||||
|
||||
@manager_group_whitelist.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
all_group = [
|
||||
g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))
|
||||
]
|
||||
group_list = []
|
||||
for group in msg:
|
||||
if is_number(group) and int(group) in all_group:
|
||||
group_list.append(int(group))
|
||||
if group_list:
|
||||
for group in group_list:
|
||||
if state["_prefix"]["raw_command"] in ["添加群白名单"]:
|
||||
group_manager.add_group_white_list(group)
|
||||
else:
|
||||
group_manager.delete_group_white_list(group)
|
||||
group_list = [str(x) for x in group_list]
|
||||
await manager_group_whitelist.send(
|
||||
"已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"]
|
||||
)
|
||||
else:
|
||||
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
|
||||
|
||||
|
||||
@show_group_whitelist.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
x = group_manager.get_group_white_list()
|
||||
x = [str(g) for g in x]
|
||||
if x:
|
||||
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x))
|
||||
else:
|
||||
await show_group_whitelist.send("没有任何群在群白名单...")
|
||||
|
||||
|
||||
@group_auth.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
for group_id in msg:
|
||||
if not is_number(group_id):
|
||||
await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
|
||||
group_id = int(group_id)
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 1)
|
||||
else:
|
||||
try:
|
||||
group_info = await bot.get_group_info(group_id=group_id)
|
||||
except ActionFailed:
|
||||
group_info = {
|
||||
"group_id": group_id,
|
||||
"group_name": "_",
|
||||
"max_member_count": -1,
|
||||
"member_count": -1,
|
||||
}
|
||||
await GroupInfo.add_group_info(
|
||||
group_info["group_id"],
|
||||
group_info["group_name"],
|
||||
group_info["max_member_count"],
|
||||
group_info["member_count"],
|
||||
1,
|
||||
)
|
||||
else:
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 0)
|
||||
await group_auth.send(
|
||||
f'已为 {group_id} {state["_prefix"]["raw_command"][:2]}群认证..'
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.rule import to_me
|
||||
from utils.manager import (
|
||||
plugins2cd_manager,
|
||||
plugins2settings_manager,
|
||||
plugins2block_manager,
|
||||
group_manager,
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
|
||||
|
||||
__zx_plugin_name__ = "重载插件配置 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
重载插件配置
|
||||
plugins2settings,
|
||||
plugins2cd
|
||||
plugins2block
|
||||
group_manager
|
||||
指令:
|
||||
重载插件配置
|
||||
""".strip()
|
||||
__plugin_des__ = "重载插件配置"
|
||||
__plugin_cmd__ = [
|
||||
"重载插件配置",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
reload_plugins_manager = on_command(
|
||||
"重载配置", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
|
||||
@reload_plugins_manager.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
plugins2settings_manager.reload()
|
||||
plugins2cd_manager.reload()
|
||||
plugins2block_manager.reload()
|
||||
group_manager.reload()
|
||||
await reload_plugins_manager.send("重载完成...")
|
||||
@@ -0,0 +1,88 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from models.level_user import LevelUser
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message
|
||||
from utils.utils import get_message_at, get_message_text, is_number
|
||||
from services.log import logger
|
||||
from utils.message_builder import at
|
||||
|
||||
__zx_plugin_name__ = "用户权限管理 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
增删改用户的权限
|
||||
指令:
|
||||
添加权限 [at] [权限]
|
||||
添加权限 [qq] [group_id] [权限]
|
||||
删除权限 [at]
|
||||
""".strip()
|
||||
__plugin_des__ = "增删改用户的权限"
|
||||
__plugin_cmd__ = [
|
||||
"添加权限 [at] [权限]",
|
||||
"添加权限 [qq] [group_id] [权限]",
|
||||
"删除权限 [at]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
super_cmd = on_command(
|
||||
"添加管理",
|
||||
aliases={"删除管理", "添加权限", "删除权限"},
|
||||
priority=1,
|
||||
permission=SUPERUSER,
|
||||
block=True,
|
||||
)
|
||||
|
||||
|
||||
@super_cmd.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
group_id = -1
|
||||
level = 0
|
||||
try:
|
||||
args = get_message_text(event.json()).split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = -1
|
||||
if not qq:
|
||||
if len(args) > 2:
|
||||
if is_number(args[0]) and is_number(args[1]) and is_number(args[2]):
|
||||
qq = int(args[0])
|
||||
group_id = int(args[1])
|
||||
level = int(args[2])
|
||||
flag = 1
|
||||
else:
|
||||
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||
else:
|
||||
await super_cmd.finish(
|
||||
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
|
||||
"\n\t格式:添加/删除权限 [qq] [group_id] [level]",
|
||||
at_sender=True,
|
||||
)
|
||||
else:
|
||||
if not is_number(args[0]):
|
||||
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||
level = int(args[0])
|
||||
qq = qq[0]
|
||||
group_id = event.group_id
|
||||
flag = 2
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if await LevelUser.set_level(qq, group_id, level, 1):
|
||||
result = "添加管理成功, 权限: " + str(level)
|
||||
else:
|
||||
result = "管理已存在, 更新权限: " + str(level)
|
||||
else:
|
||||
if await LevelUser.delete_level(qq, event.group_id):
|
||||
result = "删除管理成功!"
|
||||
else:
|
||||
result = "该账号无管理权限!"
|
||||
if flag == 2:
|
||||
await super_cmd.send(result)
|
||||
elif flag == 1:
|
||||
await bot.send_group_msg(
|
||||
group_id=group_id,
|
||||
message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"),
|
||||
)
|
||||
await super_cmd.send("修改成功")
|
||||
except Exception as e:
|
||||
await super_cmd.send("执行指令失败!")
|
||||
logger.error(f"执行指令失败 e:{e}")
|
||||
@@ -0,0 +1,56 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from services.log import logger
|
||||
from utils.manager import group_manager
|
||||
|
||||
|
||||
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
超级用户被动开关
|
||||
指令:
|
||||
开启/关闭广播通知
|
||||
""".strip()
|
||||
__plugin_des__ = "超级用户被动开关"
|
||||
__plugin_cmd__ = [
|
||||
"开启/关闭广播通知",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
oc_gb = on_command(
|
||||
"开启广播通知",
|
||||
aliases={"关闭广播通知"},
|
||||
rule=to_me(),
|
||||
permission=SUPERUSER,
|
||||
priority=1,
|
||||
block=True,
|
||||
)
|
||||
|
||||
|
||||
@oc_gb.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group = get_message_text(event.json())
|
||||
if group:
|
||||
if is_number(group):
|
||||
group = int(group)
|
||||
for g in await bot.get_group_list():
|
||||
if g["group_id"] == group:
|
||||
break
|
||||
else:
|
||||
await oc_gb.finish("没有加入这个群...", at_sender=True)
|
||||
if state["_prefix"]["raw_command"] == "开启广播通知":
|
||||
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
|
||||
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
|
||||
else:
|
||||
logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
|
||||
await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
|
||||
else:
|
||||
await oc_gb.finish("请输入正确的群号", at_sender=True)
|
||||
else:
|
||||
await oc_gb.finish("请输入要关闭广播的群号", at_sender=True)
|
||||
@@ -0,0 +1,71 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_bot
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from models.friend_user import FriendUser
|
||||
|
||||
|
||||
__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
更新群/好友信息
|
||||
指令:
|
||||
更新群信息
|
||||
更新好友信息
|
||||
""".strip()
|
||||
__plugin_des__ = "更新群/好友信息"
|
||||
__plugin_cmd__ = [
|
||||
"更新群信息",
|
||||
"更新好友信息",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
update_group_info = on_command(
|
||||
"更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
update_friend_info = on_command(
|
||||
"更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
|
||||
@update_group_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
num = 0
|
||||
rst = ""
|
||||
for g in gl:
|
||||
group_info = await bot.get_group_info(group_id=g)
|
||||
if await GroupInfo.add_group_info(
|
||||
group_info["group_id"],
|
||||
group_info["group_name"],
|
||||
group_info["max_member_count"],
|
||||
group_info["member_count"],
|
||||
):
|
||||
num += 1
|
||||
logger.info(f"自动更新群组 {g} 信息成功")
|
||||
else:
|
||||
logger.info(f"自动更新群组 {g} 信息失败")
|
||||
rst += f"{g} 更新失败\n"
|
||||
await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
|
||||
|
||||
|
||||
@update_friend_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
num = 0
|
||||
rst = ""
|
||||
fl = await get_bot().get_friend_list()
|
||||
for f in fl:
|
||||
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
|
||||
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
|
||||
num += 1
|
||||
else:
|
||||
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
|
||||
rst += f'{f["user_id"]} 更新失败\n'
|
||||
await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
|
||||
@@ -0,0 +1,30 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.rule import to_me
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_image
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
|
||||
|
||||
|
||||
superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png'
|
||||
|
||||
if superuser_help_image.exists():
|
||||
superuser_help_image.unlink()
|
||||
|
||||
super_help = on_command(
|
||||
"超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
|
||||
)
|
||||
|
||||
|
||||
@super_help.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
if not superuser_help_image.exists():
|
||||
await create_help_image()
|
||||
x = image(superuser_help_image)
|
||||
await super_help.finish(x)
|
||||
@@ -0,0 +1,80 @@
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from pathlib import Path
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
|
||||
superuser_help_image = Path(IMAGE_PATH) / "superuser_help.png"
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def create_help_image(bot: Bot = None):
|
||||
"""
|
||||
创建超级用户帮助图片
|
||||
"""
|
||||
await asyncio.get_event_loop().run_in_executor(None, _create_help_image)
|
||||
|
||||
|
||||
def _create_help_image():
|
||||
"""
|
||||
创建管理员帮助图片
|
||||
"""
|
||||
_matchers = get_matchers()
|
||||
_plugin_name_list = []
|
||||
width = 0
|
||||
help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n"
|
||||
tmp_img = BuildImage(0, 0, plain_text='1', font_size=24)
|
||||
for matcher in _matchers:
|
||||
plugin_name = ""
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
continue
|
||||
is_superuser_usage = False
|
||||
try:
|
||||
_ = _module.__getattribute__("__plugin_superuser_usage__")
|
||||
is_superuser_usage = True
|
||||
except AttributeError:
|
||||
pass
|
||||
if (
|
||||
("[superuser]" in plugin_name.lower() or is_superuser_usage)
|
||||
and plugin_name != "超级用户帮助 [Superuser]"
|
||||
and plugin_name not in _plugin_name_list
|
||||
and "[hidden]" not in plugin_name.lower()
|
||||
):
|
||||
_plugin_name_list.append(plugin_name)
|
||||
try:
|
||||
plugin_des = _module.__getattribute__("__plugin_des__")
|
||||
except AttributeError:
|
||||
plugin_des = '_'
|
||||
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
|
||||
if is_superuser_usage:
|
||||
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" in x]
|
||||
plugin_cmd = " / ".join(plugin_cmd).replace('[_superuser]', '').strip()
|
||||
help_str += f"{plugin_des} -> {plugin_cmd}\n\n"
|
||||
x = tmp_img.getsize(f"{plugin_des} -> {plugin_cmd}")[0]
|
||||
width = width if width > x else x
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"获取超级用户插件 {matcher.module}: {plugin_name} 设置失败... {type(e)}:{e}"
|
||||
)
|
||||
height = len(help_str.split("\n")) * 33
|
||||
width += 500
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
_background = BuildImage(width, height, background=background)
|
||||
A.text((300, 140), help_str)
|
||||
A.paste(_background, alpha=True)
|
||||
A.save(superuser_help_image)
|
||||
logger.info(f"已成功加载 {len(_plugin_name_list)} 条超级用户命令")
|
||||
@@ -0,0 +1,35 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from utils.message_builder import image
|
||||
|
||||
|
||||
__zx_plugin_name__ = "更新信息"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
更新信息
|
||||
指令:
|
||||
更新信息
|
||||
""".strip()
|
||||
__plugin_des__ = "当前版本的更新信息"
|
||||
__plugin_cmd__ = ["更新信息"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["更新信息"],
|
||||
}
|
||||
|
||||
|
||||
update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
|
||||
|
||||
|
||||
@update_info.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
img = image("update_info.png")
|
||||
if img:
|
||||
await update_info.finish(image("update_info.png"))
|
||||
else:
|
||||
await update_info.finish("目前没有更新信息哦")
|
||||
@@ -1,26 +1,20 @@
|
||||
import nonebot
|
||||
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
|
||||
from services.db_context import init, disconnect
|
||||
|
||||
# from nonebot.adapters.discord import Adapter as DiscordAdapter
|
||||
from nonebot.adapters.dodo import Adapter as DoDoAdapter
|
||||
from nonebot.adapters.kaiheila import Adapter as KaiheilaAdapter
|
||||
from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter
|
||||
|
||||
from zhenxun.services.db_context import disconnect, init
|
||||
|
||||
nonebot.init()
|
||||
driver = nonebot.get_driver()
|
||||
driver.register_adapter(OneBotV11Adapter)
|
||||
driver.register_adapter(KaiheilaAdapter)
|
||||
driver.register_adapter(DoDoAdapter)
|
||||
# driver.register_adapter(DiscordAdapter)
|
||||
|
||||
|
||||
driver.register_adapter("cqhttp", CQHTTPBot)
|
||||
config = driver.config
|
||||
driver.on_startup(init)
|
||||
driver.on_shutdown(disconnect)
|
||||
|
||||
nonebot.load_builtin_plugins("echo") # 内置插件
|
||||
nonebot.load_plugins("zhenxun/builtin_plugins")
|
||||
nonebot.load_plugins("zhenxun/plugins")
|
||||
# 优先加载定时任务
|
||||
nonebot.load_plugin("nonebot_plugin_apscheduler")
|
||||
nonebot.load_plugins("basic_plugins")
|
||||
nonebot.load_plugins("plugins")
|
||||
# 最后加载权限控制
|
||||
nonebot.load_plugins("basic_plugins/hooks")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
import platform
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
from .utils import ConfigsManager
|
||||
|
||||
if platform.system() == "Linux":
|
||||
import os
|
||||
|
||||
hostip = (
|
||||
os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'")
|
||||
.read()
|
||||
.replace("\n", "")
|
||||
)
|
||||
|
||||
|
||||
# 回复消息名称
|
||||
NICKNAME: str = "小真寻"
|
||||
|
||||
# 数据库(必要)
|
||||
# 如果填写了bind就不需要再填写后面的字段了#)
|
||||
# 示例:"bind": "postgres://user:password@127.0.0.1:5432/database"
|
||||
# 示例:"bind": "postgresql://user:password@127.0.0.1:5432/database"
|
||||
bind: str = "" # 数据库连接链接
|
||||
sql_name: str = "postgres"
|
||||
sql_name: str = "postgresql"
|
||||
user: str = "" # 数据用户名
|
||||
password: str = "" # 数据库密码
|
||||
address: str = "" # 数据库地址
|
||||
@@ -28,8 +18,7 @@ port: str = "" # 数据库端口
|
||||
database: str = "" # 数据库名称
|
||||
|
||||
# 代理,例如 "http://127.0.0.1:7890"
|
||||
# 如果是WLS 可以 f"http://{hostip}:7890" 使用寄主机的代理
|
||||
SYSTEM_PROXY: str | None = None # 全局代理
|
||||
SYSTEM_PROXY: Optional[str] = None # 全局代理
|
||||
|
||||
|
||||
Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml")
|
||||
@@ -0,0 +1,41 @@
|
||||
from pathlib import Path
|
||||
|
||||
# 图片路径
|
||||
IMAGE_PATH = Path("resources/img/")
|
||||
# 音频路径
|
||||
VOICE_PATH = Path("resources/voice/")
|
||||
# 文本路径
|
||||
TEXT_PATH = Path("resources/txt/")
|
||||
# 日志路径
|
||||
LOG_PATH = Path("log/")
|
||||
# 字体路径
|
||||
FONT_PATH = Path("resources/ttf/")
|
||||
# 数据路径
|
||||
DATA_PATH = Path("data/")
|
||||
# 临时图片路径
|
||||
TEMP_PATH = Path("resources/img/temp/")
|
||||
|
||||
|
||||
def init_path():
|
||||
global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH
|
||||
IMAGE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
VOICE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEXT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
LOG_PATH.mkdir(parents=True, exist_ok=True)
|
||||
FONT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/'
|
||||
VOICE_PATH = str(VOICE_PATH.absolute()) + '/'
|
||||
TEXT_PATH = str(TEXT_PATH.absolute()) + '/'
|
||||
LOG_PATH = str(LOG_PATH.absolute()) + '/'
|
||||
FONT_PATH = str(FONT_PATH.absolute()) + '/'
|
||||
DATA_PATH = str(DATA_PATH.absolute()) + '/'
|
||||
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
|
||||
|
||||
|
||||
init_path()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
from typing import Optional, Any, Union
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
|
||||
|
||||
class ConfigsManager:
|
||||
"""
|
||||
插件配置 与 资源 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self._data: dict = {}
|
||||
self._admin_level_data = []
|
||||
if file:
|
||||
file.parent.mkdir(exist_ok=True, parents=True)
|
||||
self.file = file
|
||||
if file.exists():
|
||||
_yaml = YAML()
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = _yaml.load(f)
|
||||
|
||||
def add_plugin_config(
|
||||
self,
|
||||
module: str,
|
||||
key: str,
|
||||
value: Optional[Any],
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
help_: Optional[str] = None,
|
||||
default_value: Optional[str] = None,
|
||||
_override: bool = False,
|
||||
):
|
||||
"""
|
||||
为插件添加一个配置,不会被覆盖,只有第一个生效
|
||||
:param module: 模块
|
||||
:param key: 键
|
||||
:param value: 值
|
||||
:param name: 插件名称
|
||||
:param help_: 配置注解
|
||||
:param default_value: 默认值
|
||||
:param _override: 覆盖前值
|
||||
"""
|
||||
if (
|
||||
not (module in self._data.keys() and self._data[module].get(key))
|
||||
or _override
|
||||
):
|
||||
_module = None
|
||||
if ":" in module:
|
||||
module = module.split(":")
|
||||
_module = module[-1]
|
||||
module = module[0]
|
||||
if "[LEVEL]" in key and _module:
|
||||
key = key.replace("[LEVEL]", "").strip()
|
||||
self._admin_level_data.append((_module, value))
|
||||
if self._data.get(module) is None:
|
||||
self._data[module] = {}
|
||||
key = key.upper()
|
||||
self._data[module][key] = {
|
||||
"value": value,
|
||||
"name": name.strip() if isinstance(name, str) else name,
|
||||
"help": help_.strip() if isinstance(help_, str) else help_,
|
||||
"default_value": default_value,
|
||||
"level_module": _module,
|
||||
}
|
||||
|
||||
def remove_plugin_config(self, module: str):
|
||||
"""
|
||||
为插件删除一个配置
|
||||
:param module: 模块名
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
del self._data[module]
|
||||
|
||||
def set_config(self, module: str, key: str, value: str):
|
||||
"""
|
||||
设置配置值
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param value: 值
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if self._data[module].get(key) is not None:
|
||||
self._data[module][key]["value"] = value
|
||||
|
||||
def set_help(self, module: str, key: str, help_: str):
|
||||
"""
|
||||
设置配置注释
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param help_: 注释文本
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if self._data[module].get(key) is not None:
|
||||
self._data[module][key]["help"] = help_
|
||||
|
||||
def set_default_value(self, module: str, key: str, value: str):
|
||||
"""
|
||||
设置配置默认值
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param value: 值
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if self._data[module].get(key) is not None:
|
||||
self._data[module][key]["default_value"] = value
|
||||
|
||||
def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
|
||||
"""
|
||||
获取指定配置值
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param default: 没有key值内容的默认返回值
|
||||
"""
|
||||
key = key.upper()
|
||||
if module in self._data.keys():
|
||||
for key in [key, f"{key} [LEVEL]"]:
|
||||
if self._data[module].get(key) is not None:
|
||||
if self._data[module][key]["value"] is None:
|
||||
return self._data[module][key]["default_value"]
|
||||
return self._data[module][key]["value"]
|
||||
if default is not None:
|
||||
return default
|
||||
return None
|
||||
|
||||
def get_level2module(self, module: str, key: str) -> Optional[str]:
|
||||
"""
|
||||
获取指定key所绑定的module,一般为权限等级
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:return:
|
||||
"""
|
||||
if self._data.get(module) is not None:
|
||||
if self._data[module].get(key) is not None:
|
||||
return self._data[module][key].get("level_module")
|
||||
|
||||
def get(self, key: str):
|
||||
"""
|
||||
获取插件配置数据
|
||||
:param key: 名称
|
||||
"""
|
||||
if key in self._data.keys():
|
||||
return self._data[key]
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
"""
|
||||
保存数据
|
||||
:param path: 路径
|
||||
"""
|
||||
path = path if path else self.file
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump(
|
||||
self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def get_admin_level_data(self):
|
||||
"""
|
||||
获取管理插件等级
|
||||
"""
|
||||
return self._admin_level_data
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
return not bool(self._data)
|
||||
|
||||
def keys(self):
|
||||
return self._data.keys()
|
||||
|
||||
def __str__(self):
|
||||
return str(self._data)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._data[key] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[key]
|
||||
@@ -1,66 +0,0 @@
|
||||
{
|
||||
"抽卡":{
|
||||
"buff": ["欧气满满,十连出金","出金不歪"],
|
||||
"debuff": ["武器大师","保底出金","金色会是痛苦大剑"]
|
||||
},
|
||||
"刷世界boss":{
|
||||
"buff": ["双攻双爆角斗士"],
|
||||
"debuff": ["只有保底材料","贪生怕死角斗士"]
|
||||
},
|
||||
"刷风本":{
|
||||
"buff": ["会有极品猎人套","会掉真正的少女心","治疗加成少女头"],
|
||||
"debuff": ["勇往直前少女心","少女飘摇的杀意","少女暴怒的容颜"]
|
||||
},
|
||||
"刷火本":{
|
||||
"buff": ["魔女帽子火伤杯","暴伤魔女帽!","火伤魔女心!"],
|
||||
"debuff": ["幡 然 醒 悟","这么阴间的地方真的会有魔女套吗?","不务正业火魔女","会匹配到3个卢姥爷"]
|
||||
},
|
||||
"刷岩本":{
|
||||
"buff": ["悠久的磐岩伴你左右","岩神的庇护常在"],
|
||||
"debuff": ["防御流星杯,你值得拥有"]
|
||||
},
|
||||
"刷宗室":{
|
||||
"buff": ["物理伤害骑士道,元素精通宗室套"],
|
||||
"debuff": ["贪生怕死骑士道,物理伤害宗室杯"]
|
||||
},
|
||||
"刷冰本":{
|
||||
"buff": ["双暴词条概率up"],
|
||||
"debuff": ["防御力船帽,无人可及"]
|
||||
},
|
||||
"刷雷本":{
|
||||
"buff": ["愿雷鸟伴你左右"],
|
||||
"debuff": ["来表演一个只掉平雷套的绝活","风神忽悠雷凶兆"]
|
||||
},
|
||||
"锄大地":{
|
||||
"buff": ["会掉一大堆紫色材料"],
|
||||
"debuff": ["深渊法师爱你哟","会被冰水法控到死"]
|
||||
},
|
||||
"挖矿":{
|
||||
"buff": ["开矿出双材料"],
|
||||
"debuff": ["去别人世界会被拒"]
|
||||
},
|
||||
"刷天赋本":{
|
||||
"buff": ["金色!我看到了金色的书!"],
|
||||
"debuff": ["2蓝2绿不会变"]
|
||||
},
|
||||
"刷突破材料":{
|
||||
"buff": ["金色!我看到了金色的材料!"],
|
||||
"debuff": ["2蓝2绿不会变"]
|
||||
},
|
||||
"升级圣遗物":{
|
||||
"buff": ["稀有词条跳跳跳","会双爆拉满"],
|
||||
"debuff": ["女 仆 狂 喜","无中生有防御力","生命拉满","完美避开双爆"]
|
||||
},
|
||||
"打风魔龙":{
|
||||
"buff": ["看我一箭一个风魔鸡","今天特瓦林可以给想要的突破材料","5金加原胚!"],
|
||||
"debuff": ["会不小心掉下平台","不小心被地板烫死了"]
|
||||
},
|
||||
"打狼王":{
|
||||
"buff": ["今天安德琉斯的心情不错,可以py一下","5金加原胚!"],
|
||||
"debuff": ["狼尾巴*1"]
|
||||
},
|
||||
"打公子":{
|
||||
"buff": ["今天可以和公子py想要的突破材料","5金加原胚!"],
|
||||
"debuff": ["要角没有!要命一条!"]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 772 KiB |
|
Before Width: | Height: | Size: 799 KiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 694 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 326 KiB After Width: | Height: | Size: 694 KiB |
@@ -0,0 +1,241 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
__tablename__ = "bag_users"
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
gold = db.Column(db.Integer(), default=100)
|
||||
props = db.Column(db.TEXT(), nullable=False, default="")
|
||||
spend_total_gold = db.Column(db.Integer(), default=0)
|
||||
get_total_gold = db.Column(db.Integer(), default=0)
|
||||
get_today_gold = db.Column(db.Integer(), default=0)
|
||||
spend_today_gold = db.Column(db.Integer(), default=0)
|
||||
|
||||
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_my_total_gold(cls, user_qq: int, belonging_group: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取金币概况
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
user = await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
return (
|
||||
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
|
||||
f"\n今日收益:{user.get_today_gold - user.spend_today_gold}"
|
||||
f"\n总赚取金币:{user.get_total_gold}\n总花费金币:{user.spend_total_gold}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_gold(cls, user_qq: int, belonging_group: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取当前金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.gold
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
return 100
|
||||
|
||||
@classmethod
|
||||
async def get_props(cls, user_qq: int, belonging_group: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取当前道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.props
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
)
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
增加金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param num: 金币数量
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
花费金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param num: 金币数量
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str):
|
||||
"""
|
||||
说明:
|
||||
增加道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param name: 道具名称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
使用道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param name: 道具名称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def buy_props(
|
||||
cls, user_qq: int, belonging_group: int, goods: "GoodsInfo", goods_num: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
购买道具
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param belonging_group: 所在群聊
|
||||
:param goods: 商品
|
||||
:param goods_num: 商品数量
|
||||
"""
|
||||
try:
|
||||
# 折扣后金币
|
||||
spend_gold = goods.goods_discount * goods.goods_price * goods_num
|
||||
await BagUser.spend_gold(user_qq, belonging_group, spend_gold)
|
||||
for _ in range(goods_num):
|
||||
await BagUser.add_props(user_qq, belonging_group, goods.goods_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"buy_props 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取所有用户数据
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
query = await cls.query.gino.all()
|
||||
else:
|
||||
query = await cls.query.where((cls.belonging_group == group_id)).gino.all()
|
||||
return query
|
||||
@@ -0,0 +1,119 @@
|
||||
from services.db_context import db
|
||||
import time
|
||||
|
||||
|
||||
class BanUser(db.Model):
|
||||
__tablename__ = "ban_users"
|
||||
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
|
||||
ban_level = db.Column(db.Integer(), nullable=False)
|
||||
ban_time = db.Column(db.BigInteger())
|
||||
duration = db.Column(db.BigInteger())
|
||||
|
||||
_idx1 = db.Index("ban_group_users_idx1", "user_qq", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测ban掉目标的用户与unban用户的权限等级大小
|
||||
参数:
|
||||
:param user_qq: unban用户的qq号
|
||||
:param level: ban掉目标用户的权限等级
|
||||
"""
|
||||
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
|
||||
if not user:
|
||||
return False
|
||||
if user.ban_level > level:
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def check_ban_time(cls, user_qq: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
检测用户被ban时长
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
return ""
|
||||
if time.time() - (user.ban_time + user.duration) > 0 and user.duration != -1:
|
||||
return ""
|
||||
if user.duration == -1:
|
||||
return "∞"
|
||||
return time.time() - user.ban_time - user.duration
|
||||
|
||||
@classmethod
|
||||
async def is_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
if await cls.check_ban_time(user_qq):
|
||||
return True
|
||||
else:
|
||||
await cls.unban(user_qq)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def is_super_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
|
||||
if not user:
|
||||
return False
|
||||
if user.ban_level == 10:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
ban掉目标用户
|
||||
参数:
|
||||
:param user_qq: 目标用户qq号
|
||||
:param ban_level: 使用ban命令用户的权限
|
||||
:param duration: ban时长,秒
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if not await cls.check_ban_time(user_qq):
|
||||
await cls.unban(user_qq)
|
||||
user = None
|
||||
if user is None:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
ban_level=ban_level,
|
||||
ban_time=time.time(),
|
||||
duration=duration,
|
||||
)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def unban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
unban用户
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
return False
|
||||
else:
|
||||
await cls.delete.where((cls.user_qq == user_qq)).gino.status()
|
||||
return True
|
||||
@@ -0,0 +1,115 @@
|
||||
from services.db_context import db
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
class FriendUser(db.Model):
|
||||
__tablename__ = "friend_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_id = db.Column(db.BigInteger(), nullable=False)
|
||||
user_name = db.Column(db.Unicode(), nullable=False, default="")
|
||||
nickname = db.Column(db.Unicode())
|
||||
|
||||
_idx1 = db.Index("friend_users_idx1", "user_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_user_name(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取好友用户名称
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.user_name
|
||||
else:
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加好友信息
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param user_name: 用户名称
|
||||
"""
|
||||
try:
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if not user:
|
||||
await cls.create(
|
||||
user_id=user_id,
|
||||
user_name=user_name,
|
||||
)
|
||||
else:
|
||||
await user.update(
|
||||
user_name=user_name,
|
||||
).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_friend_info(cls, user_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除好友信息
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
try:
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if user:
|
||||
await user.delete()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_friend_nickname(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取用户昵称
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if user.nickname:
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
if black_word:
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
return _tmp
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置用户昵称
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
try:
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if not user:
|
||||
await cls.create(
|
||||
user_id=user_id,
|
||||
nickname=nickname,
|
||||
)
|
||||
else:
|
||||
await user.update(
|
||||
nickname=nickname,
|
||||
).apply()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
@@ -0,0 +1,133 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class GoodsInfo(db.Model):
|
||||
__tablename__ = "goods_info"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
goods_name = db.Column(db.TEXT(), nullable=False) # 名称
|
||||
goods_price = db.Column(db.Integer(), nullable=False) # 价格
|
||||
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
|
||||
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
|
||||
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
|
||||
|
||||
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_goods(
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: int,
|
||||
goods_description: str,
|
||||
goods_discount: float = 1,
|
||||
goods_limit_time: int = 0,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加商品
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时
|
||||
"""
|
||||
try:
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除商品
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
query = (
|
||||
await cls.query.where(cls.goods_name == goods_name)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
await query.delete()
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def update_goods(
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: Optional[int] = None,
|
||||
goods_description: Optional[str] = None,
|
||||
goods_discount: Optional[float] = None,
|
||||
goods_limit_time: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
更新商品信息
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时时间
|
||||
"""
|
||||
try:
|
||||
query = (
|
||||
await cls.query.where(cls.goods_name == goods_name)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
if goods_price:
|
||||
await query.update(goods_price=goods_price).apply()
|
||||
if goods_description:
|
||||
await query.update(goods_description=goods_description).apply()
|
||||
if goods_discount:
|
||||
await query.update(goods_discount=goods_discount).apply()
|
||||
if goods_limit_time:
|
||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
|
||||
"""
|
||||
说明:
|
||||
获取商品对象
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
query = await cls.query.where(cls.goods_name == goods_name).gino.first()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def get_all_goods(cls) -> List["GoodsInfo"]:
|
||||
"""
|
||||
说明:
|
||||
获得全部有序商品对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
id_lst = [x.id for x in query]
|
||||
goods_lst = []
|
||||
for _ in range(len(query)):
|
||||
min_id = min(id_lst)
|
||||
goods_lst.append([x for x in query if x.id == min_id][0])
|
||||
id_lst.remove(min_id)
|
||||
return goods_lst
|
||||
@@ -0,0 +1,111 @@
|
||||
from services.db_context import db
|
||||
from services.log import logger
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class GroupInfo(db.Model):
|
||||
__tablename__ = "group_info"
|
||||
|
||||
group_id = db.Column(db.BigInteger(), nullable=False, primary_key=True)
|
||||
group_name = db.Column(db.Unicode(), nullable=False, default="")
|
||||
max_member_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
member_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||
group_flag = db.Column(db.Integer(), nullable=False, default=0)
|
||||
|
||||
_idx1 = db.Index("group_info_idx1", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_group_info(cls, group_id: int) -> "GroupInfo":
|
||||
"""
|
||||
说明:
|
||||
获取群信息
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(cls.group_id == group_id)
|
||||
return await query.gino.first()
|
||||
|
||||
@classmethod
|
||||
async def add_group_info(
|
||||
cls,
|
||||
group_id: int,
|
||||
group_name: str,
|
||||
max_member_count: int,
|
||||
member_count: int,
|
||||
group_flag: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加群信息
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param group_name: 群名称
|
||||
:param max_member_count: 群员最大数量
|
||||
:param member_count: 群员数量
|
||||
:param group_flag: 群认证,0为未认证,1为认证
|
||||
"""
|
||||
try:
|
||||
group = (
|
||||
await cls.query.where(cls.group_id == group_id)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if group:
|
||||
await group.update(
|
||||
group_name=group_name,
|
||||
max_member_count=max_member_count,
|
||||
member_count=member_count,
|
||||
).apply()
|
||||
if group_flag is not None:
|
||||
await group.update(group_flag=group_flag).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
group_id=group_id,
|
||||
group_name=group_name,
|
||||
max_member_count=max_member_count,
|
||||
member_count=member_count,
|
||||
group_flag=group_flag,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.info(f"GroupInfo 调用 add_group_info 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_group_info(cls, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
删除群信息
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
await cls.delete.where(cls.group_id == group_id).gino.status()
|
||||
|
||||
@classmethod
|
||||
async def get_all_group(cls) -> List["GroupInfo"]:
|
||||
"""
|
||||
说明:
|
||||
获取所有群对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def set_group_flag(cls, group_id: int, group_flag: int) -> bool:
|
||||
"""
|
||||
设置群认证
|
||||
:param group_id: 群号
|
||||
:param group_flag: 群认证,0为未认证,1为认证
|
||||
"""
|
||||
group = (
|
||||
await cls.query.where(cls.group_id == group_id)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if group:
|
||||
if group.group_flag != group_flag:
|
||||
await group.update(
|
||||
group_flag=group_flag,
|
||||
).apply()
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,193 @@
|
||||
from datetime import datetime
|
||||
from configs.config import Config
|
||||
from services.db_context import db
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class GroupInfoUser(db.Model):
|
||||
__tablename__ = "group_info_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
user_name = db.Column(db.Unicode(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
user_join_time = db.Column(db.DateTime(), nullable=False)
|
||||
nickname = db.Column(db.Unicode())
|
||||
uid = db.Column(db.BigInteger())
|
||||
|
||||
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_member_info(
|
||||
cls,
|
||||
user_qq: int,
|
||||
belonging_group: int,
|
||||
user_name: str,
|
||||
user_join_time: datetime,
|
||||
uid: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
添加群内用户信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param user_name: 用户名称
|
||||
:param user_join_time: 入群时间
|
||||
:param uid: 用户唯一 id(自动生成)
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
try:
|
||||
if not await query.gino.first():
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
user_name=user_name,
|
||||
belonging_group=belonging_group,
|
||||
user_join_time=user_join_time,
|
||||
uid=uid
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_member_info(
|
||||
cls, user_qq: int, belonging_group: int
|
||||
) -> "GroupInfoUser":
|
||||
"""
|
||||
说明:
|
||||
查询群员信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
return await query.gino.first()
|
||||
|
||||
@classmethod
|
||||
async def delete_member_info(cls, user_qq: int, belonging_group: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除群员信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user is None:
|
||||
return True
|
||||
else:
|
||||
await cls.delete.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
).gino.status()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_id_list(cls, belonging_group: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户qq
|
||||
参数:
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
member_list = []
|
||||
query = cls.query.where((cls.belonging_group == belonging_group))
|
||||
for user in await query.gino.all():
|
||||
member_list.append(user.user_qq)
|
||||
return member_list
|
||||
|
||||
@classmethod
|
||||
async def set_group_member_nickname(
|
||||
cls, user_qq: int, belonging_group: int, nickname: str
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置群员在该群内的昵称
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if user:
|
||||
await user.update(nickname=nickname).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
||||
"""
|
||||
获取该用户所在的所有群聊
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||
if query:
|
||||
query = [x.belonging_group for x in query]
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取用户在该群的昵称
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if user.nickname:
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
if black_word:
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
return _tmp
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]:
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update()
|
||||
_max_uid_user = await _max_uid.gino.first()
|
||||
_max_uid = _max_uid_user.uid
|
||||
if not user or not user.uid:
|
||||
all_user = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||
for x in all_user:
|
||||
if x.uid:
|
||||
return x.uid
|
||||
else:
|
||||
if not user:
|
||||
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min)
|
||||
user = await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
).gino.first()
|
||||
await user.update(
|
||||
uid=_max_uid + 1,
|
||||
).apply()
|
||||
await _max_uid_user.update(
|
||||
uid=_max_uid + 1,
|
||||
).apply()
|
||||
|
||||
return user.uid if user and user.uid else None
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class LevelUser(db.Model):
|
||||
__tablename__ = "level_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
user_level = db.Column(db.BigInteger(), nullable=False)
|
||||
group_flag = db.Column(db.Integer(), nullable=False, default=0)
|
||||
|
||||
_idx1 = db.Index("level_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取用户在群内的等级
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.user_level
|
||||
else:
|
||||
return -1
|
||||
|
||||
@classmethod
|
||||
async def set_level(
|
||||
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置用户在群内的权限
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
:param group_flag: 是否被自动更新刷新权限 0:是,1:否
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
user_level=level,
|
||||
group_flag=group_flag,
|
||||
)
|
||||
return True
|
||||
else:
|
||||
await user.update(user_level=level, group_flag=group_flag).apply()
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除用户权限
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
return False
|
||||
else:
|
||||
await user.delete()
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检查用户权限等级是否大于 level
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
"""
|
||||
if group_id != 0:
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user is None:
|
||||
return False
|
||||
user_level = user.user_level
|
||||
else:
|
||||
query = cls.query.where(cls.user_qq == user_qq)
|
||||
highest_level = 0
|
||||
for user in await query.gino.all():
|
||||
if user.user_level > highest_level:
|
||||
highest_level = user.user_level
|
||||
user_level = highest_level
|
||||
if user_level >= level:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测是否会被自动更新刷新权限
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
user = await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
).gino.first()
|
||||
if not user:
|
||||
return False
|
||||
if user.group_flag == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -0,0 +1,100 @@
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class SignGroupUser(db.Model):
|
||||
__tablename__ = "sign_group_users"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
|
||||
checkin_count = db.Column(db.Integer(), nullable=False)
|
||||
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
|
||||
add_probability = db.Column(
|
||||
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
||||
)
|
||||
specify_probability = db.Column(
|
||||
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
||||
)
|
||||
|
||||
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def ensure(
|
||||
cls, user_qq: int, belonging_group: int, for_update: bool = False
|
||||
) -> "SignGroupUser":
|
||||
"""
|
||||
说明:
|
||||
获取签到用户
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param belonging_group: 所在群聊
|
||||
:param for_update: 是否存在修改数据
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
if for_update:
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
return user or await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
checkin_count=0,
|
||||
checkin_time_last=datetime.min, # 从未签到过
|
||||
impression=0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_user_all_data(cls, user_qq: int) -> List["SignGroupUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取某用户所有数据
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = cls.query.where(cls.user_qq == user_qq)
|
||||
query = query.with_for_update()
|
||||
return await query.gino.all()
|
||||
|
||||
@classmethod
|
||||
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
|
||||
"""
|
||||
说明:
|
||||
签到
|
||||
说明:
|
||||
:param user: 用户
|
||||
:param impression: 增加的好感度
|
||||
:param checkin_time_last: 签到时间
|
||||
"""
|
||||
await user.update(
|
||||
checkin_count=user.checkin_count + 1,
|
||||
checkin_time_last=checkin_time_last,
|
||||
impression=user.impression + impression,
|
||||
add_probability=0,
|
||||
specify_probability=0,
|
||||
).apply()
|
||||
|
||||
@classmethod
|
||||
async def get_all_impression(cls, belonging_group: int) -> "list, list, list":
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户 id 及对应 好感度
|
||||
参数:
|
||||
:param belonging_group: 群号
|
||||
"""
|
||||
impression_list = []
|
||||
user_qq_list = []
|
||||
user_group = []
|
||||
if belonging_group:
|
||||
query = cls.query.where(cls.belonging_group == belonging_group)
|
||||
else:
|
||||
query = cls.query
|
||||
for user in await query.gino.all():
|
||||
impression_list.append(user.impression)
|
||||
user_qq_list.append(user.user_qq)
|
||||
user_group.append(user.belonging_group)
|
||||
return user_qq_list, impression_list, user_group
|
||||
@@ -0,0 +1,45 @@
|
||||
from nonebot import on_regex
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__zx_plugin_name__ = "关于"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
想要更加了解真寻吗
|
||||
指令:
|
||||
关于
|
||||
""".strip()
|
||||
__plugin_des__ = "想要更加了解真寻吗"
|
||||
__plugin_cmd__ = ["关于"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 1,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["关于"],
|
||||
}
|
||||
|
||||
|
||||
about = on_regex("^关于$", priority=5, block=True, rule=to_me())
|
||||
|
||||
|
||||
@about.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
ver_file = Path() / '__version__'
|
||||
version = None
|
||||
if ver_file.exists():
|
||||
with open(ver_file, 'r', encoding='utf8') as f:
|
||||
version = f.read().split(':')[-1].strip()
|
||||
msg = f"""
|
||||
『绪山真寻Bot』
|
||||
版本:{version}
|
||||
简介:基于Nonebot2与go-cqhttp开发,是一个非常可爱的Bot呀,希望与大家要好好相处
|
||||
项目地址:https://github.com/HibiKier/zhenxun_bot
|
||||
文档地址:https://hibikier.github.io/zhenxun_bot/
|
||||
""".strip()
|
||||
await about.send(msg)
|
||||
@@ -0,0 +1,62 @@
|
||||
import random
|
||||
from nonebot import on_keyword
|
||||
import os
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from nonebot import on_command
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from utils.utils import FreqLimiter
|
||||
from configs.config import NICKNAME
|
||||
|
||||
|
||||
__zx_plugin_name__ = "基本设置 [Hidden]"
|
||||
__plugin_usage__ = "用法: 无"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
|
||||
|
||||
_flmt = FreqLimiter(300)
|
||||
|
||||
|
||||
config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block=True)
|
||||
|
||||
|
||||
@config_play_game.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if not _flmt.check(event.group_id):
|
||||
return
|
||||
_flmt.start_cd(event.group_id)
|
||||
await config_play_game.finish(
|
||||
image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi")
|
||||
)
|
||||
|
||||
|
||||
self_introduction = on_command(
|
||||
"自我介绍", aliases={"介绍", "你是谁", "你叫什么"}, rule=to_me(), priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@self_introduction.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if NICKNAME.find('真寻') != -1:
|
||||
result = (
|
||||
"我叫绪山真寻\n"
|
||||
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
|
||||
"年龄的话我还是个**岁初中生(至少现在是)\n"
|
||||
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
|
||||
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
|
||||
"最好的朋友是椛!\n" + image("zhenxun")
|
||||
)
|
||||
await self_introduction.finish(result)
|
||||
|
||||
|
||||
my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
|
||||
|
||||
|
||||
@my_wife.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await my_wife.finish(image("laopo.jpg", "other"))
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
GroupMessageEvent,
|
||||
Message,
|
||||
MessageEvent,
|
||||
)
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from services.log import logger
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from .data_source import get_chat_result, hello, no_result
|
||||
from configs.config import NICKNAME, Config
|
||||
|
||||
__zx_plugin_name__ = "AI"
|
||||
__plugin_usage__ = f"""
|
||||
usage:
|
||||
与{NICKNAME}普普通通的对话吧!
|
||||
"""
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"cmd": ["Ai", "ai", "AI", "aI"],
|
||||
}
|
||||
__plugin_configs__ = {
|
||||
"TL_KEY": {
|
||||
"value": [],
|
||||
"help": "图灵Key"
|
||||
},
|
||||
"ALAPI_AI_CHECK": {
|
||||
"value": False,
|
||||
"help": "是否检测青云客骂娘回复",
|
||||
"default_value": False
|
||||
}
|
||||
}
|
||||
Config.add_plugin_config(
|
||||
"alapi",
|
||||
"ALAPI_TOKEN",
|
||||
None,
|
||||
help_="在https://admin.alapi.cn/user/login登录后获取token"
|
||||
)
|
||||
|
||||
ai = on_message(rule=to_me(), priority=8)
|
||||
|
||||
|
||||
@ai.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_imgs(event.json())
|
||||
if "CQ:xml" in str(event.get_message()):
|
||||
return
|
||||
# 打招呼
|
||||
if (not msg and not imgs) or msg in [
|
||||
"你好啊",
|
||||
"你好",
|
||||
"在吗",
|
||||
"在不在",
|
||||
"您好",
|
||||
"您好啊",
|
||||
"你好",
|
||||
"在",
|
||||
]:
|
||||
await ai.finish(hello())
|
||||
img = imgs[0] if imgs else ""
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if not nickname:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
else:
|
||||
nickname = event.sender.nickname
|
||||
result = await get_chat_result(msg, img, event.user_id, nickname)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else ''} "
|
||||
f"问题:{msg} ---- 回答:{result}"
|
||||
)
|
||||
if result:
|
||||
await ai.finish(Message(result))
|
||||
else:
|
||||
await ai.finish(no_result())
|
||||
@@ -0,0 +1,215 @@
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.path_config import IMAGE_PATH, DATA_PATH
|
||||
from services.log import logger
|
||||
from utils.message_builder import image, face
|
||||
from configs.config import Config, NICKNAME
|
||||
from .utils import ai_message_manager
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
url = "http://openapi.tuling123.com/openapi/api/v2"
|
||||
|
||||
check_url = "https://v2.alapi.cn/api/censor/text"
|
||||
|
||||
index = 0
|
||||
|
||||
anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8"))
|
||||
|
||||
|
||||
async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str:
|
||||
"""
|
||||
获取 AI 返回值,顺序: 特殊回复 -> 图灵 -> 青云客
|
||||
:param text: 问题
|
||||
:param img_url: 图片链接
|
||||
:param user_id: 用户id
|
||||
:param nickname: 用户昵称
|
||||
:return: 回答
|
||||
"""
|
||||
global index
|
||||
ai_message_manager.add_message(user_id, text)
|
||||
special_rst = await ai_message_manager.get_result(user_id, nickname)
|
||||
if special_rst:
|
||||
ai_message_manager.add_result(user_id, special_rst)
|
||||
return special_rst
|
||||
if index == 5:
|
||||
index = 0
|
||||
if len(text) < 6 and random.random() < 0.6:
|
||||
keys = anime_data.keys()
|
||||
for key in keys:
|
||||
if text.find(key) != -1:
|
||||
return random.choice(anime_data[key]).replace("你", nickname)
|
||||
rst = await tu_ling(text, img_url, user_id)
|
||||
if not rst:
|
||||
rst = await xie_ai(text)
|
||||
if not rst:
|
||||
return no_result()
|
||||
if nickname:
|
||||
if len(nickname) < 5:
|
||||
if random.random() < 0.5:
|
||||
nickname = "~".join(nickname) + "~"
|
||||
if random.random() < 0.2:
|
||||
if nickname.find("大人") == -1:
|
||||
nickname += "大~人~"
|
||||
rst = rst.replace("小主人", nickname).replace("小朋友", nickname)
|
||||
ai_message_manager.add_result(user_id, rst)
|
||||
return rst
|
||||
|
||||
|
||||
# 图灵接口
|
||||
async def tu_ling(text: str, img_url: str, user_id: int) -> str:
|
||||
"""
|
||||
获取图灵接口的回复
|
||||
:param text: 问题
|
||||
:param img_url: 图片链接
|
||||
:param user_id: 用户id
|
||||
:return: 图灵回复
|
||||
"""
|
||||
global index
|
||||
TL_KEY = Config.get_config("ai", "TL_KEY")
|
||||
req = None
|
||||
if not TL_KEY:
|
||||
return ""
|
||||
try:
|
||||
if text:
|
||||
req = {
|
||||
"perception": {
|
||||
"inputText": {"text": text},
|
||||
"selfInfo": {
|
||||
"location": {"city": "陨石坑", "province": "火星", "street": "第5坑位"}
|
||||
},
|
||||
},
|
||||
"userInfo": {"apiKey": TL_KEY[index], "userId": str(user_id)},
|
||||
}
|
||||
elif img_url:
|
||||
req = {
|
||||
"reqType": 1,
|
||||
"perception": {
|
||||
"inputImage": {"url": img_url},
|
||||
"selfInfo": {
|
||||
"location": {"city": "陨石坑", "province": "火星", "street": "第5坑位"}
|
||||
},
|
||||
},
|
||||
"userInfo": {"apiKey": TL_KEY[index], "userId": str(user_id)},
|
||||
}
|
||||
except IndexError:
|
||||
index = 0
|
||||
return ""
|
||||
text = ""
|
||||
response = await AsyncHttpx.post(url, json=req)
|
||||
if response.status_code != 200:
|
||||
return no_result()
|
||||
resp_payload = json.loads(response.text)
|
||||
if int(resp_payload["intent"]["code"]) in [4003]:
|
||||
return ""
|
||||
if resp_payload["results"]:
|
||||
for result in resp_payload["results"]:
|
||||
if result["resultType"] == "text":
|
||||
text = result["values"]["text"]
|
||||
if "请求次数超过" in text:
|
||||
text = ""
|
||||
return text
|
||||
|
||||
|
||||
# 屑 AI
|
||||
async def xie_ai(text: str) -> str:
|
||||
"""
|
||||
获取青云客回复
|
||||
:param text: 问题
|
||||
:return: 青云可回复
|
||||
"""
|
||||
res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
|
||||
content = ""
|
||||
data = json.loads(res.text)
|
||||
if data["result"] == 0:
|
||||
content = data["content"]
|
||||
if "菲菲" in content:
|
||||
content = content.replace("菲菲", NICKNAME)
|
||||
if "艳儿" in content:
|
||||
content = content.replace("艳儿", NICKNAME)
|
||||
if "公众号" in content:
|
||||
content = ""
|
||||
if "{br}" in content:
|
||||
content = content.replace("{br}", "\n")
|
||||
if "提示" in content:
|
||||
content = content[: content.find("提示")]
|
||||
if "淘宝" in content:
|
||||
return ""
|
||||
while True:
|
||||
r = re.search("{face:(.*)}", content)
|
||||
if r:
|
||||
id_ = r.group(1)
|
||||
content = content.replace(
|
||||
"{" + f"face:{id_}" + "}", str(face(int(id_)))
|
||||
)
|
||||
else:
|
||||
break
|
||||
return (
|
||||
content
|
||||
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
|
||||
else await check_text(content)
|
||||
)
|
||||
|
||||
|
||||
def hello() -> str:
|
||||
"""
|
||||
一些打招呼的内容
|
||||
"""
|
||||
result = random.choice(
|
||||
(
|
||||
"哦豁?!",
|
||||
"你好!Ov<",
|
||||
f"库库库,呼唤{NICKNAME}做什么呢",
|
||||
"我在呢!",
|
||||
"呼呼,叫俺干嘛",
|
||||
)
|
||||
)
|
||||
img = random.choice(os.listdir(IMAGE_PATH + "zai/"))
|
||||
if img[-4:] == ".gif":
|
||||
result += image(img, "zai")
|
||||
else:
|
||||
result += image(img, "zai")
|
||||
return result
|
||||
|
||||
|
||||
# 没有回答时回复内容
|
||||
def no_result() -> str:
|
||||
"""
|
||||
没有回答时的回复
|
||||
"""
|
||||
return (
|
||||
random.choice(
|
||||
[
|
||||
"你在说啥子?",
|
||||
f"纯洁的{NICKNAME}没听懂",
|
||||
"下次再告诉你(下次一定)",
|
||||
"你觉得我听懂了吗?嗯?",
|
||||
"我!不!知!道!",
|
||||
]
|
||||
)
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH + "noresult/")), "noresult")
|
||||
)
|
||||
|
||||
|
||||
async def check_text(text: str) -> str:
|
||||
"""
|
||||
ALAPI文本检测,主要针对青云客API,检测为恶俗文本改为无回复的回答
|
||||
:param text: 回复
|
||||
"""
|
||||
if not Config.get_config("alapi", "ALAPI_TOKEN"):
|
||||
return text
|
||||
params = {"token": Config.get_config("alapi", "ALAPI_TOKEN"), "text": text}
|
||||
try:
|
||||
data = (await AsyncHttpx.get(check_url, timeout=2, params=params)).json()
|
||||
if data["code"] == 200:
|
||||
if data["data"]["conclusion_type"] == 2:
|
||||
return ""
|
||||
except Exception as e:
|
||||
logger.error(f"检测违规文本错误...{type(e)}:{e}")
|
||||
return text
|
||||