第二章:基础插件编写指南第三节———会说话就多说点
本节中,将会学习 Message 的基本概念,以及 CQ码
、MessageSegment
及 call_api
的基本用法。
Message
Message是 nonebot 中 OneBot v11 协议 Message 适配。简单来说,就是你能放进输入框的东西理论上都能用Message进行表示,例如普通的文字、图片或者表情等。我们今天要了解的 MessageSegment
本质上就是Message,和CQ码一样,是方便我们更方便构筑Message的一个工具。
Message不光可以对上述内容进行转义或表达,也可以对其进行拼接,例如
1 | from nonebot.adapters.onebot.v11 import Message, MessageSegment |
CQ码 和 MessageSegment
简单来说,CQ码
和 MessageSegment
均是用于辅助开发者更方便的发送非文本类消息的构造方法,例如图片、语音和at等。
经历过酷Q时代的开发者应该还记得CQ码,在nonebot和gocqhttp中cq码依旧可以使用,而且cq收到的非文本类消息也大多会使用CQ码传递给nonebot,而mirai及其他非QQ客户端的协议是没有CQ码的概念的,并且gocqhttp的CQ码在版本更迭的时候CQ码的表达方式也可能会产生变化,因此目前官方和社区的主流意见是尽量避免直接使用CQ码而转而使用MessageSegment的。
但是,MessageSegment也并非万能。其一是在gocqhttp传回的数据中,大部分依旧是使用cq码构造的,这也就要求我们要响应这些数据的时候需要对cq码进行解析而无法使用MessageSegment。其二是在部分情况下使用MessageSegment发送部分内容的情况下gocqhttp会显示“消息为空”而无法发送,但使用cq码就可以发送的奇怪的bug,而且除我之外也有其他开发者遇到过这个问题,但由于此bug不可稳定复现,仍不清楚其成因以及是否解决。
总而言之,个人给出的建议是优先使用MessageSegment进行发送,在发送失败的情况下可以尝试cq码进行发送。(你问解析?解析不就只有CQ码可以解析吗ԅ(¯﹃¯ԅ))
使用CQ码
首先我们应该知道cq码的构造方法,一般情况下是 [CQ:type,key=value]
这种构造形式,具体的某个CQ码我们可以在gocqhttp的官方文档的 CQ code 板块进行查询。
同时,由于cq码中存在例如 []
、:
、=
等符号,因此需要对其进行转义才能够正常使用,方法也很简单,只需要用 Message()
即可转义,例如:
1 | from nonebot.adapters.onebot.v11 import Message |
这样就可以是这个CQ码正常的被解析成一个@,而不是直接把CQ码原文发出去了。
使用MessageSegment
截止至2022.3.31日,在nonebot官方文档中并没有对onebot协议中的MessageSegment进行介绍,因此在这里将会结合源码和编辑器的提示进行讲解
MessageSegment的使用方法实际上非常简单,基本的用法就是 MessageSegment.xxx()
,并且正如上文所说,MessageSegment本质上是Message类,所以我们不需要用 Message()
对其进行转义。
首先我们先输入 MessageSegment.
然后查看编辑器的提示或转到源码,就能看到MessageSegment提供的方法了:
我们这里用image进行举例:
1 | from nonebot.adapters.onebot.v11 import MessageSegment |
这样setu001就是一个Message类的涩图了,理论上和 Message('[CQ:image,file=file:///D:/learning_materials/setu/001.jpg]')
是等效的。
MessageSegment由于功能很多,因此不在此一一演示了,想要用好MessageSegment,需要需要多加利用编辑器的自动补全和语法提示,这样就不必翻源码即可使用了。
call_api
call_api相对于前面介绍的功能更强大,且用法也不复杂,而且覆盖面更广。但之所以call_api并不是我们开发过程中的首选,因为它在一般情况下相对我们正常使用的方法来说,也是稍显复杂的,一般体现在需要填写更多的参数上和没有流程控制的能力。
目前call_api最主要的应用是用于补充nonebot无法原生支持的功能,例如获取用户昵称、同意好友请求或上传群文件这种比较不常见的功能。
个人理解其为类似“瑞士军刀”的存在,什么都能干但并不如专业工具,更何况某些情况下我们需要的功能也只能使用call_api进行实现呢(笑)。
使用方法
首先我们需要知道我们对接的客户端有什么样的api,这样我们才能对其发起请求。我们使用的gocqhttp的官方文档中对API有详细的介绍。
call_api的写法目前有两种,bot.call_api('xxx', **{key:value})
和bot.xxx(key=value)
两种仅写法不同,实质并无影响,可根据自身喜好进行调整。
这里我们以“获取群信息”为例进行写法一的演示。
我们需要提供两个数据,其中no_cache为选填字段(是否为选填字段需要自行结合描述和实践进行判断),group_id为必填字段。
1 | from nonebot.adapters.onebot.v11 import Bot |
这样我们就获得了data这个json格式的返回值,然后进行简单的转义就可以读取了。
这里我们再演示一下和“发送消息”,并使用第二种方法进行演示。
1 | from nonebot.adapters.onebot.v11 import Bot, Event |
由此可见,call_api是依赖于bot对象的,因此在一些特殊的响应器(例如aps)中,我们需要手动获取bot对象,这些就留到用到的时候再讲吧。