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


该插件涉及知识点:读取加群退群信息,数据库操作
插件合集: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'))

model.py

import sqlite3
import os

# 数据库文件的路径
db_path = os.path.split(os.path.realpath(__file__))[0] + '/data/join_and_leave.db'


# 如果不存在的话,创建数据库,并且创建数据表
def create_db():
    conn = sqlite3.connect(db_path)
    try:
        create_tb_cmd = '''
            CREATE TABLE IF NOT EXISTS leave_record
            (user_id INT8,
            group_id INT8,
            leave INT);
            '''
        conn.execute(create_tb_cmd)
    except:
        pass
    conn.commit()
    conn.close()


# 查询指定人退群次数,返回退群次数
def get_exist_data(user_id, group_id):
    conn = sqlite3.connect(db_path)
    insert_cmd = f'SELECT leave from leave_record where user_id == {user_id} and group_id = {group_id}'
    cursor = list(conn.execute(insert_cmd))
    conn.close()
    # 如果不存在,则返回空列表
    # 否则返回退群次数
    return cursor


# 添加退群用户
def add_data(user_id, group_id):
    leave = get_exist_data(user_id, group_id)
    # 如果用户数据还不存在
    if not leave:
        cmd = f'INSERT INTO leave_record (user_id,group_id,leave) VALUES ({user_id}, {group_id}, {1});'
    # 否则计数+1
    else:
        cmd = f'UPDATE leave_record SET leave = {leave[0][0]+1} WHERE user_id == {user_id} and group_id = {group_id};'

    conn = sqlite3.connect(db_path)
    conn.execute(cmd)
    conn.commit()
    conn.close()


# 返回该群退群次数最高的人,返回用户qq号与退群次数
def search_most_leave(group_id):
    conn = sqlite3.connect(db_path)
    insert_cmd = f'SELECT user_id,leave from leave_record WHERE group_id = {group_id} order by -leave limit 5'
    cursor = list(conn.execute(insert_cmd))
    conn.close()
    return cursor

5. 插件配图

揣手手.jpg
请添加图片描述

踢人.jpg
请添加图片描述

退群.png
请添加图片描述

震撼.jpg
请添加图片描述

6. 实际效果

请添加图片描述

7. 下一个插件

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

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
微信官方Flutter支付插件是为了方便开发者在Flutter应用中集成微信支付功能而提供的工具。通过使用这个插件,开发者可以轻松地在自己的应用中实现微信支付的功能。 微信支付是一种在移动端广泛使用的支付方式,可以方便快捷地完成支付操作。它支持多种支付场景,包括线上购物、线下扫码支付和小程序支付等。用户只需要在手机上安装了微信应用,并绑定了银行卡或其他支付方式,就可以在应用中使用微信支付进行交易。 使用微信官方Flutter支付插件,开发者只需要在Flutter应用的代码中引入相应的库,并调用相应的函数接口,传入需要支付的订单信息,就可以在应用中显示微信支付界面,并通过微信支付完成支付操作。开发者还可以根据自己的需求,自定义支付界面的样式和行为,以及处理支付结果的回调。 这个插件是由微信官方团队开发和维护的,因此可以保证其稳定性和安全性。开发者可以通过官方文档和示例代码,了解插件的使用方法和相关注意事项,并在开发过程中遇到问题时,可以及时向官方团队寻求帮助和支持。 总之,微信官方Flutter支付插件为开发者提供了一种简单便捷的集成微信支付功能的方式,使得开发者可以更加轻松地为自己的应用添加支付功能,提高用户的支付体验,促进应用的发展。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值