×

信息技术 学习 科技 教程 编程 Python Nonebot 机器人 QQ 日记 极客 程序

Nonebot实现自动撤回的功能

Shine_Light Shine_Light 发表于2022-03-16 20:32:27 浏览1307 评论0

抢沙发发表评论

前言

最近在研究Nonebot的时候想起了电报群里的机器人,里面的机器人可以在发出消息后定时撤回,打算给Nonebot也做一个这样的功能


分析

要实现这个功能,最大的问题就是怎么获取Bot发送出去的信息id,在翻看官方文档之后,我找到了一个方法

在Nonebot中发送信息都是使用 bot 的 call_api 方法调用的 go-cqhttp 的 API,在调用之后默认会执行 _called_api_hook 集合里存储的函数,并且会传入几个参数

bot: Bot, e: Exception, api: str, data: Dict[str, Any], result: Any

result 中就存储了机器人发送出去的信息id,这样我们最大的问题就解决了

接下来就是怎么处理信息,我的想法是使用一个字典将信息过期时间和信息id存储起来,再使用定时任务每秒执行一次来判断信息是否撤回


代码实现

导入一下需要到的模块

import datetime
import time
import nonebot

from typing import Any, Dict
from nonebot import require, on_command
from nonebot.adapters.onebot.v11 import Bot, Event


首先编写方法来处理数据

# 时间格式化
ft = "%Y%m%d%H%M%S"
# 存放信息的字典
msgs: dict = {}

# 保存需要撤回的信息
async def save_msg_id(bot: Bot, e: Exception, api: str, data: Dict[str, Any], result: Any) -> None:
        # 只保存发送出去的信息
        if api != "send_msg":
            return 
            
    # 时间处理,过期时间为10s
    time_now = datetime.datetime.now()
    time_last = time_now + datetime.timedelta(seconds=10)
    time_result: int = int(time_last.strftime(ft))
    
    # 信息ID
    mid: int = result["message_id"]
    
    # 更新撤回信息字典
    msgs.update({mid: time_result})

信息过期的时间使用datetime.timedelta来获取,获取后格式化并转换为 int 类型,方便判断


然后来写撤回信息的定时任务

# 撤回信息
scheduler = require("nonebot_plugin_apscheduler").scheduler
@scheduler.scheduled_job("cron", second="*/1", timezone="Asia/Shanghai")
async def _():
    time_now = int(time.strftime(ft, time.localtime()))
    bot = nonebot.get_bot()
    deleted: list = []
    # 若当前时间等于撤回时间则进行撤回
    for msg in msgs:
        if msgs[msg] == time_now:
            await bot.delete_msg(message_id=msg)
            deleted.append(msg)
    # 已撤回信息从字典中删除
    for key in deleted:
        msgs.pop(key)


把函数放进 _called_api_hook 集合中

# 在bot调用API后执行函数
Bot._called_api_hook.add(save_msg_id)


最后我们写个方法来试一下

# 测试用
test = on_command("测试", priority=8)
@test.handle()
async def _(bot: Bot, event: Event):
    await bot.send(event=event, message="测试信息,该消息将于 10 s后撤回")


成果


扩展

再此基础上我们可以继续扩展其他功能,如自定义过期时间,撤回指定群/人/类型的信息,这就交给各位来开发了

分享到:

群贤毕至

访客