该系列为用于QQ群聊天机器人的nonebot2相关插件,不保证完全符合标准规范写法,如有差错和改进余地,欢迎大佬指点修正。
前端:nonebot2
后端:go-cqhttp
插件所用语言:python3
前置环境安装过程建议参考零基础2分钟教你搭建QQ机器人——基于nonebot2,但是请注意该教程中的后端版本过旧导致私聊发图异常,需要手动更新go-cqhttp版本。
在有用户加群时,自动发送欢迎信息并艾特加群的新人~
在有用户退群时,发送退群通报,让不是管理员的群友也能得知对方退群的时间点。
在有曾经退过群的用户再次加群时,发出通报提示该用户曾经退出过多少次这个群!没错我就是要对那些反复横跳的人进行公开处刑!
bot管理员能够查看指定用户在该群的退群记录,或者把该群历史退群人数最多的用户列出一个排行榜!再次公开处刑!
在plugins文件夹中新建一个文件夹join_and_leave
,文件夹内目录结构如下:
|-join_and_leave
|-data
|-join_and_leave.db
|-img
|-所有在信息发送中用到的图片
|-__init__.py
|-join_and_leave.py
|-config.py
|-model.py
其中img
为用于存储发送的图片文件的文件夹,data
为储存数据库文件的文件夹,join_and_leave.py
为程序主要代码的位置,config.py
用于存储配置项,model.py
用于封装与数据库交互的SQL语言操作,__init__.py
为程序启动位置。
与上一章中读取戳一戳信息类似,加群和退群同样是notice类型的信息,新建一个群,用小号加群和退群进行几次测试后,通过event.get_event_description()
就得到了通知信息的大致形式。
description: {
'time': 时间戳, 'self_id': 机器人QQ号, 'post_type': 'notice', 'notice_type': 'group_decrease', 'sub_type': 'leave', 'user_id': 退群者QQ号, 'group_id': 群号, 'operator_id': 退群者QQ号}
验证发现:
有人加群'notice_type': 'group_increase'
有人自己退群'notice_type': 'group_decrease', 'sub_type': 'leave'
有人被踢出群'notice_type': 'group_decrease', 'sub_type': 'kick'
以类似上一章的方式利用json库转换为字典后就很容易处理。
为了方便起见,使用轻量的sqlite数据库进行操作,无需登录用户名与密码,只需要移动一个db文件就可以转移数据库。
python3自带sqlite数据库,如何使用SQL语句访问和操作数据库在此不再赘述,如果需要了解可以很容易搜索到相关的教程。
文件目录中的db文件不需要自己创建,只需要新建好空文件夹,代码运行后如果不存在数据库,会自动新建数据库文件!
Config.py
class Config:
# 记录在哪些群组中使用
used_in_group = ["131551175"]
# 插件执行优先级
priority = 10
__init__.py
from .join_and_leave import *
join_and_leave.py
from nonebot import on_notice, on_command
from nonebot.typing import T_State
from nonebot.adapters import Bot, Event
from nonebot.adapters.cqhttp import MessageSegment
from nonebot.permission import SUPERUSER
import json
import os
from .config import Config
from .model import *
__plugin_name__ = 'join_and_leave'
__plugin_usage__ = '用法: 提示有人加群或者退群,并记录此人在该群的历史退群次数。'
# 创建数据库
create_db()
img_path = 'file:///' + os.path.split(os.path.realpath(__file__))[0] + '/img/'
# 发送图片时用到的函数, 返回发送图片所用的编码字符串
def send_img(img_name):
global img_path
return MessageSegment.image(img_path + img_name)
# 通报加群与退群
join_and_leave = on_notice(priority=Config.priority)
@join_and_leave.handle()
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
try:
ids = event.get_session_id()
except:
pass
# 如果读取正常没有出错,因为有些notice格式不支持session
else:
# 如果这是一条群聊信息
if ids.startswith("group"):
_, group_id, user_id = event.get_session_id().split("_")
# 只对列表中的群使用
if group_id in Config.used_in_group:
description = event.get_event_description()
values = json.loads(description.replace("'", '"'))
# 有新人加群
if values['notice_type'] == 'group_increase':
# 获取此人是否曾经退群
leave_record = get_exist_data(user_id, group_id)
print(leave_record)
if len(leave_record) == 0:
await join_and_leave.finish(
"一只新食材" + MessageSegment.at(values['user_id']) + '跳进了锅里~\n' + send_img("揣手手.jpg"))
# 如果此人之前曾经退群过,发出警告
else:
await join_and_leave.send(
"一只新食材" + MessageSegment.at(values['user_id']) + '跳进了锅里~\n' + send_img("揣手手.jpg"))
await join_and_leave.finish(
f"警告:记录表明这只新食材曾经退群过{
leave_record[0][0]}次!" + send_img("退群.png") + send_img("震撼.jpg"))
# 有人退群
elif values['notice_type'] == 'group_decrease':
add_data(user_id, group_id)
# 自己退群
if values['sub_type'] == 'leave':
infos = str(await bot.get_stranger_info(user_id=values['user_id']))
nickname = json.loads(infos.replace("'", '"'))['nickname'] + '(' + str(values['user_id']) + ')'
await join_and_leave.finish(
nickname + '在这一刻选择了离开我们。\n' + send_img("退群.png") + send_img("震撼.jpg"))
# 被踢出群
elif values['sub_type'] == 'kick':
infos = str(await bot.get_stranger_info(user_id=values['user_id']))
nickname = json.loads(infos.replace("'", '"'))['nickname'] + '(' + str(values['user_id']) + ')'
operator_infos = str(await bot.get_stranger_info(user_id=values['operator_id']))
operator_nickname = json.loads(operator_infos.replace("'", '"'))['nickname'] + '(' + str(
values['operator_id']) + ')'
await join_and_leave.finish('超级可爱的' + operator_nickname + '面无表情地把' + \
nickname + '一脚踢出了这个世界!\n' + send_img("踢人.jpg"))
# 管理员专属指令
# 查询命令
copyer_helper = on_command("退群帮助", priority=Config.priority)
@copyer_helper.handle()
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
await copyer_helper.finish('''退群指令仅限bot管理员使用:
退群次数查询 [QQ号]——查询指定用户在当前群的退群次数
退群次数排行——查询当前群的退群次数最多的人''')
get_leave_data = on_command("退群次数查询", permission=SUPERUSER, priority=Config.priority)
@get_leave_data.handle()
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
ids = event.get_session_id()
# 如果这是一条群聊信息
if ids.startswith("group"):
_, group_id, user_id = event.get_session_id().split("_")
if group_id in Config.used_in_group:
search_id = str(event.get_message()).strip()
leave_record = get_exist_data(search_id , group_id)
infos = str(await bot.get_stranger_info(user_id=search_id))
nickname = json.loads(infos.replace("'", '"'))['nickname'] + '(' + str(search_id) + ')'
if len(leave_record) == 0:
await join_and_leave.finish(nickname+"没有退出过该群。")
else:
await join_and_leave.finish(f"{
nickname}退出过该群{
leave_record[0][0]}次。")
get_most_leave_user = on_command("退群次数排行", permission=SUPERUSER, priority=Config.priority)
@get_most_leave_user.handle()
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
ids = event.get_session_id()
# 如果这是一条群聊信息
if ids.startswith("group"):
_, group_id, _ = event.get_session_id().split("_")
if group_id in Config.used_in_group:
leave_record = search_most_leave(group_id)
if len(leave_record) == 0:
await get_most_leave_user.finish("该群暂无退群数据")
else:
result = '前五位退群最多的人是:\n'
for user_id, leave in leave_record:
infos = str(await bot.get_stranger_info(user_id=user_id))
nickname = json.loads(infos.replace("'", '"'))['nickname'] + '(' + str(user_id) + ')'
result += nickname + f'\n退群:{
leave}次\n\n'
await get_most_leave_user.finish(result[:-1]+send_img('震撼.jpg'))
nonebot2聊天机器人插件6:复读机博弈论ban_copyer