nonebot2聊天机器人插件5:加群退群通报与退群次数记录join_and_leave

nonebot2聊天机器人插件5:加群退群通报与退群次数记录join_and_leave

  • 1. 插件用途
  • 2. 目录结构
  • 3. 实现难点与解决方案
    • 3.1 读取加群退群信息
    • 3.2 数据库操作
  • 4. 代码实现
  • 5. 插件配图
  • 6. 实际效果
  • 7. 下一个插件

该插件涉及知识点:读取加群退群信息,数据库操作
插件合集:nonebot2聊天机器人插件

该系列为用于QQ群聊天机器人的nonebot2相关插件,不保证完全符合标准规范写法,如有差错和改进余地,欢迎大佬指点修正。
前端:nonebot2
后端:go-cqhttp
插件所用语言:python3
前置环境安装过程建议参考零基础2分钟教你搭建QQ机器人——基于nonebot2,但是请注意该教程中的后端版本过旧导致私聊发图异常,需要手动更新go-cqhttp版本。

1. 插件用途

在有用户加群时,自动发送欢迎信息并艾特加群的新人~
在有用户退群时,发送退群通报,让不是管理员的群友也能得知对方退群的时间点。
在有曾经退过群的用户再次加群时,发出通报提示该用户曾经退出过多少次这个群!没错我就是要对那些反复横跳的人进行公开处刑!
bot管理员能够查看指定用户在该群的退群记录,或者把该群历史退群人数最多的用户列出一个排行榜!再次公开处刑!

2. 目录结构

在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为程序启动位置。

3. 实现难点与解决方案

3.1 读取加群退群信息

与上一章中读取戳一戳信息类似,加群和退群同样是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库转换为字典后就很容易处理。

3.2 数据库操作

为了方便起见,使用轻量的sqlite数据库进行操作,无需登录用户名与密码,只需要移动一个db文件就可以转移数据库。
python3自带sqlite数据库,如何使用SQL语句访问和操作数据库在此不再赘述,如果需要了解可以很容易搜索到相关的教程。
文件目录中的db文件不需要自己创建,只需要新建好空文件夹,代码运行后如果不存在数据库,会自动新建数据库文件!

4. 代码实现

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'))

5. 插件配图

揣手手.jpg
nonebot2聊天机器人插件5:加群退群通报与退群次数记录join_and_leave_第1张图片

踢人.jpg
nonebot2聊天机器人插件5:加群退群通报与退群次数记录join_and_leave_第2张图片

退群.png
nonebot2聊天机器人插件5:加群退群通报与退群次数记录join_and_leave_第3张图片

震撼.jpg
nonebot2聊天机器人插件5:加群退群通报与退群次数记录join_and_leave_第4张图片

6. 实际效果

7. 下一个插件

nonebot2聊天机器人插件6:复读机博弈论ban_copyer

你可能感兴趣的:(nonebot2聊天机器人插件,python)