消息适配器
请求统一处理
- LR5921
- 为视频设置 60s 超时,其他 15s
- 自动拼接 url
- 除了网络异常和状态码异常外,LR5921 返回中存在状态 status 为 ok 或者 failed
- LR232
- 为文件设置 60s 超时,其他 15s
- 输出日志时缩略文件数据(其他平台都是 file 参数与 data 参数分开,只有 LR232 在 data 中包含 file 的 base64 数据)
- 撤回为 delete 方法,其他为 post
- LR232 直接使用 status_code 代表错误码,且错误码大概率不在文档里
- WECHAT
- 为文件设置 60s 超时,其中 15s
- 自动拼接 url
- 存在非 json 回复
- 除了网络异常和状态码异常外,json 回复中失败存在 errcode 字段
- BILI
- 根据是否是直播相关 API 分为两种请求头
- 存在 get 方法和 post 方法,请求参数不同,但均用 params 传入
- 除了网络异常和状态码异常外,BILI 返回中存在错误码 code,不为 0 代表错误
接收
- LR5921
- 机制
- 普通消息
- 表情中,emoji 表情会以文本类解析;超级表情单发和与跟文本混合发送无区别
- 引用消息时会自动@某人,但可以删掉,不必须
- 转发单条消息会变成普通消息(即使原消息有引用)
- 商城表情即使添加到收藏表情,也是解析成商城表情
- 图片消息由拍照和上传图片产生,且与 LR232 文件名是一致的
- 视频消息需要长按拍照产生,否则是文件
- 视频消息可以自动预览播放,文件需要下载
- 卡片消息中 data.data 值包含双引号,在处理时解析
- LR5921 @ 时会自动加一个空格,解析到文字里;由于没有涉及到群聊 @ 才能触发的指令,故不用处理
- 临时消息
- 临时消息的 sender 字段无昵称,多了 temp_source 和 group_id 字段
- 不能主动向其他用户发送临时消息,其他用户创建临时消息会话后可以发送临时消息,所以临时消息的处理逻辑与正常消息相同,发送 API 相同,二者统一处理
- 系统处理后两个消息相同
- 撤回消息
- 从消息池中获取
- 撤回消息无消息 id,即消息池中没有消息(没接收过/超过一天)则无法找到原消息(与日常行为一致,没看过原消息则不知道是什么)
- 好友添加
- 设置任何人可添加时,会产生两条消息,请求添加为好友的文字消息和好友添加的事件
- 只处理第二条
- 没有消息序号
- 戳戳消息
- 分为原始戳一戳(手机加号中的戳一戳类型、电脑窗口抖动)和新戳一戳(双击头像)
- 其中前者并入消息接收类型中的 poke 类型,后者为私聊/群聊戳戳类型
- 前者除了第一个外,其他的均显示为文本“[xxx]请使用最新版本手机QQ查看。”,右边口袋中的内容无法解析
- 群聊回应
- 回应只能显示一个表情且数量固定为 1
- 回应只能接收对自己表态的,且无法获取对应的消息序号
- 精华消息
- 自己设置自己为精华则 sender_id 与 user_id 均为 0
- 无法接收移出精华消息
- 没有对应消息 id(很奇怪)
- 群名片更改
- 只有更改后发了消息才能获取到
- 其他消息
- 无法接收
- QQ 电话
- 动态点赞
- 编辑群介绍
- 好友删除
- 群待办
- 函数
- 过滤掉 meta_event,message_sent,request 事件
- 过滤掉不在群列表中的消息(减少消息日志)
- 处理 message 事件
- 跳过空消息
- 过滤 LR232 接收的消息(变为系统消息)
- 转发消息使用原消息替换消息 id
- 卡片消息解析字符串为 json 格式
- 回复消息使用原消息替换 reply 段中的 id
- 处理 notice 事件
- 进行事件分类
- 忽略群聊文件、群聊删除、群聊管理、群聊禁言、群名片更改
- 处理私聊/群聊添加、私聊/群聊撤回、私聊/群聊戳戳、群聊回应、群聊设精
- 从消息池中寻找撤回消息段作为消息内容
- 处理消息提醒
- 忽略输入状态、头衔消息、群名称修改、私聊点赞
- 处理戳戳,整理戳戳文字
- 机制
- LR232
- 机制
- 普通消息
- 会以文本类型解析 emoji 表情
- 卡片消息(像推荐好友等)、猜拳骰子、转发消息无法解析
- at 消息、回复消息字段无法接收
- 商城表情即使添加到收藏表情,也是解析成商城表情
- 可以接收所有类型文件(与文档不符)
- 商城表情和动画表情的 ext 字段使用 base64 解析
- 商城表情和动画表情解析重复
- 之前动画表情
<faceType=6,faceId="0",ext="eyJ0ZXh0IjoiIn0=">无法解析文件下载,只能解析 ext 为动画表情 - 9 月更新中 qq 将表情加入了附件中提供下载链接
- 即动画表情会出现两次,一次在 content 里,一次在 attachment 里
- 可以把 attachment 里的 fileid,url,height 和 width 属性整合到内容里
- 但由于动画表情没有 id 或其他特征信息,假设出现:
图片+动画表情+图片消息,content 字段只有<faceType=6,faceId="0",ext="eyJ0ZXh0IjoiIn0=">,而附件里有三个文件,无法确认哪个是动画表情 - 只能采取折中方案:
- 当动画表情字段数与附件数相等时,将附件里的信息加入动画表情字段中,保留动画表情在消息内容中的顺序
- 当动画表情字段与附件数不相等时,删除内容中的动画表情,保留附件,将所有动画表情当成图片
- 之前动画表情
- 回调配置
- 回调配置与消息接收使用同一端口
- 回调配置的 op 码为 13,消息接收为 0
- 附件
- LR232 的图片/语音/视频/文件在 attachments 字段里面
- 重复推送
- 网络原因,QQ 可能会在 5 秒内多次推送同一消息
- 事件消息
- 非接收类的消息,需要根据 event_id 来回复,接受类根据 msg_id 来回复
- 删除事件不能通过 event_id 来回复
- 快捷面板
- 使用快捷面板触发的指令,会在末尾加一个空格,使用@并选择 LR232,会在 @ 和文字之间加一个空格。此时,对于完全匹配的指令如"/帮助"则会失效,故需要 strip 掉空格
- 函数
- 根据 op 码分类回调配置和消息处理
- 设置 5 秒消息去重
- 进行消息事件分类
- 处理事件消息
- 处理私聊添加,不处理群聊添加、群聊删除、私聊删除
- 处理普通消息
- 提取表情
- 提取骰子和猜拳
- 提取并使用 base64 和 json 解析普通和商城表情
- 能提取到 text 则解析成功
- 提取文字
- 去除空格
- 提取附件
- 分离图片语音视频文件
- 进行动画表情和文件消息的合并
- 提取表情
- 处理事件消息
- 机制
- WECHAT
- 机制
- 回调配置
- 回调配置使用 get 方法,消息使用 post
- 普通消息
- 无法接收上传表情/收藏表情
- 以文本类型解析 emoji 表情
- 图片消息是相册中发送的
- 收藏中的合并转发消息无法接收
- 音频消息长按语音输入
- qq 音乐分享无法接收
- 无法解析文件消息
- 可分享推文/链接,需要先收藏
- 事件消息
- 事件消息没有 seq
- 点击菜单事件无法回复
- 重复推送
- 消息没有回复则 5s 后重新发送一次,共三次
- 函数
- 设置 15 秒回复的超时时间(可以回复第一条消息)
- 处理事件消息
- 处理私聊添加,不处理私聊删除、菜单点击
- 消息 seq 设置为接收时间+两位随机数(本身无序号)
- 处理普通消息
- 去除重复消息(通过 seq)
- 分离文本、图片、语音、视频、卡片消息
- 表情处理
- 在微信的文字消息中,表情字段唯一且以'/:'开头或者被'[]'包裹
- 为了解决 /::) 123 的匹配情况(实际消息为:[微笑] 123)
- 代码中先提取出 wechat_emojis 中所有的键
- 用 | 连接,构造一个 a|b|c……的正则表达式
- 对文字消息中的表情进行逐一匹配
- 机制
- BILI
- 机制
- 普通消息
- emoji 与表情中的颜文字表情均以文字形式解析
- 图片消息只能单发
- 重复发送
- 重复发送同一消息过多会触发 B 站的机制,无法接收
- 后续发送不同的消息会把之前没有接收到的消息一起收到
- 撤回消息会导致 unreadcount 与实际不符
- 如果不考虑撤回消息,可以在 unread_count 为 0,1,2 时分别处理,0 跳过,1 直接用 msg_deal 解析 last_msg,2 使用消息获取解析消息列表
- 考虑撤回消息时,在传入 interval 后获取的 unread_count 为聊天内可以看到的消息,撤回的消息不算
- 所以会出现 unread_count=0 的情况(消息全部撤回),故不管 unread_count 为几,只要对话出现在对话列表里就要调用 bili_msg_get 来获取消息
- 存在一个问题,无法获取到系统启动前就撤回的消息。可以遍历消息列表来获取,但耗时长且没有必要
- 函数
- 定时任务中,调用 bili_receive 获取未读消息列表
- 初始调用时通过 first_called 变量把 interval 设置为 0,获取所有未读消息
- 之后每隔 interval 秒调用一次,添加 begin_ts 参数获取间隔中的未读消息列表
- 获取消息后不管 unread_count 是不是 0,获取最后已读消息序号 ack_seqno
- 设置消息已读
- 根据 ack_seqno 获取会话列表中该用户 ack_seqno 之后的消息
- 有时拿不到 ack_seqno,直接获取全部消息根据 unread_count 截取
- 重新排序消息列表,使撤回的原消息比撤回消息先进入消息池
- 对消息进行处理,分离文字、图片、表情、撤回和卡片
- 卡片消息中,在 json 格式消息中通过 type 来区分系统消息、图片/视频分享等
- 同样可以伪造表情,见发送
- 颜文字和 emoji 表情均属于文本消息
- 机制
发送
-
LR5921
- 机制
- 优先级
- 卡片>文件>视频>语音>其他,前面的会覆盖掉后面的
- 发送
- 无法发送空的消息及 0B 的文本
- 函数
- 将转发消息、转发节点消息与戳戳的 API 合并进消息发送中
- 默认转发消息只有一项,即[转发:id],之后的项不考虑
- 默认节点消息只有一项,即[节点:id|用户|消息组],之后的项不考虑
- 戳戳消息私聊时只有一个参数,采用 111 占位
- 返回消息序号
- 将转发消息、转发节点消息与戳戳的 API 合并进消息发送中
- 机制
-
LR232
- 机制
- 添加发送
- 接收时,将“接收”与“添加”区分开来,“添加”事件的消息序号需要以 event_id 字段名来回复,故在 LR232 发送时多了一种类型“添加发送”来回复此类消息
- 额外参数
- 回复存在有效时间,私聊 60 分钟,群聊 5 分钟,且最多回复 5 次,需要记录 order 来应对多次回复的情况,使用同一 order 回复同一消息会失败。若是一条消息在消息发送中进行拆分,order 自动递增;若以多条消息回复同一条消息,需要自己设置 order 递增
- 函数
- 私聊和群聊调用不同的 url
- 发生和添加发送使用不同的 tag(但值都是 user)
- 将消息段分为文字+表情包和图片,文字统一发送,图片分开发送(不合并发送图文,会使逻辑更复杂)
- 文字发送时处理网址,先找到白名单里的网址,然后处理从上一个白名单之后到下一个白名单之前的内容中的网址,替换为[网址]
- 若需要发送网址需要在平台和代码里同步添加白名单
- 图片发送时调用图片上传
- 自动递增 order(没有添加记录值,需要自行判断有没有 >5)
- 返回消息序号列表
- 机制
-
WECHAT
- 机制
- 发送表情
- 若发送的内容匹配到了某个表情,则在发送后被替换成该表情
- 如文字发送
[doge_金箍]或者/::)会被 B 站和微信自动解析成金箍表情和微笑
- 发送
- 只能回复当前消息,故只能发送一条消息,需要合并图文
- 采用 future 变量作为推送消息(接收)请求的回应值,超过 20s 会超时
- 发送换行符时,使用
/u2028电脑能解析但手机不能,使用/n二者均不能解析。故统一将/n替换成图片格式 - 同样存在“添加发送”
- 大约最多 550 个字
- 函数
- 取消息段中第一条消息,分离音频、视频、卡片类型
- 剩下的为图文
- 若存在图片及文字
- 拼接图片和文字(合并文字在最上方,图片在下方)
- 延时删除
- 若只存在文字
- 合并文字消息
- 若存在换行,生成图片
- 若不存在,直接发送
- 若只存在图片
- 一张直接发送
- 多张合并后发送,延时删除
- 若存在图片及文字
- 拼接消息体
- 机制
-
BILI
- 机制
- 发送表情
- 同 WECHAT
- BILI 可以伪造表情,即根据发送机制,使用[xxx]时,主观意愿是接收/发送表情,解析也为表情:xx,省去了检索 B 站表情包(添加几百个表情到中途放弃了)的精力
- 发送
- BILI 发送时,电脑端第一次可能会解析不出来,刷新一下即可
- 大约最多 400 个字
- 函数
- 将消息段分为
文字+表情包和图片,文字统一发送,图片分开发送 - 返回消息序号列表
- 可以正常发送换行、emoji 表情
- 将消息段分为
- 机制
消息获取
- LR5921
- 机制
- 无法获取不在群聊内的群聊消息 id
- 函数
- 获取到的是消息列表,仍然需要转换 json 格式消息
- 如果为回复消息,继续调用本函数获取内层(存在无限递归风险,但两条消息能互相引用吗???)
- 机制
- BILI
- 机制
- 指定用户和开始序号,获取指定序号后的消息列表
- 函数
- 根据 talker_id,begin_seqno 获取指定用户指定序号后的会话列表
- 由于数量限制了 20,所以在刷新间隔内发送超过 20 条消息会遗漏部分消息
- 机制
文件上传
- 存储机制
- 当 record=True 时
- 三个平台均根据有效性将 media 值存入数据库,使用时先根据文件路径寻找数据库中未过期的 id
- LR232 存入 json 字段,有效性 1h
- WECHAT 存入 media_id,有效期 3d
- BILI 存入 json 字段(url,height,width),有效期永久
- 由于 BILI 和 WECHAT 的有效期较长,存入后若本地资源发生变化,会优先使用已上传的值。所以本地资源修改后,建议直接删除对应的行
- LR232
- 机制
- 上传限制
- 文件有效期 1h
- 图片 20MB
- 视频 9.99MB(9.999 不行,9.98 可以)
- 音频 mp3 自动转换为 silk(silk 比较小,没测大小限制)
- 文件 id
- 多次上传同一文件 id 不同
- media_id 可在不同地方复用(私聊/群聊/不同用户)
- 函数
- 根据后缀判断类型,目前支持 png,jpeg,gif,jpg,mp4,silk,mp3
- 机制
- WECHAT
- 机制
- 有效期 3d
- 图片 10MB
- 视频 10MB
- 音频 2MB,60s
- 缩略图 64KB
- 函数
- 分离格式,压缩后上传
- 返回值缩略图为 thumb_media_id,其他都是 media_id
- 机制
- BILI
- 机制
- 只能上传图片,根据 mime_type 判断文件类型
- 链接有效期永久(暂未发现过期)
- 机制
文件下载
- LR5921
- 机制
- 文件类消息不直接提供 url 而是 file_id
- 机制
撤回
- LR5921
- 机制
- 撤回时间最多 123s
- 函数
- 根据序号撤回
- 机制
- LR232
- 机制
- 撤回时最多 118s
- 函数
- 根据序号、用户撤回
- 机制
- BILI
- 机制
- 撤回时最多 120s
- 函数
- 根据序号撤回
- 机制
签名
- LR5921
- BILI
- 机制
- 签名需要审核,过一段时间才能成功
- 机制
昵称
- LR5921
- BILI
直播相关
- BILI
- 机制
- 电脑开播只能通过直播姬,调用 API 选择网页版需要进行加密
- 参考项目对于请求参数进行加密后可以正常开播
- 除了开播,其他 API 不需要加密
- 请求附带直播请求头
- 函数
- 开启直播,返回推流地址、推流码
- 设置直播标题和封面(封面可选,使用'|'分割)
- 更新直播间公告
- 关闭直播
- 机制
用户视频相关
- BILI
- 机制
- 获取用户合集的 API 必须加上 page_num 和 page_size,否则会请求失败
- 函数
- 获取用户视频
- 获取用户合集
- 搜索,type 可为 bili_user(用户)
- 视频下载,获取 dash 视频下载链接
- cid,av 或 bv 号获取 cid
- 机制
粉丝获取
- BILI
- 机制
- 通过定期获取粉丝列表进行比较来获取新粉丝
- 生成“私聊添加”类型消息(没有消息序号)
- 函数
- 获取粉丝列表(最新若干粉丝)
- 查找数据库中拥有"fan"状态的用户
- 寻找粉丝列表中该用户
- 对于该用户之前的用户生成“私聊添加”消息
- 对于粉丝列表中第一位添加"fan"状态
- 机制
状态
-LR5921
- 机制
- 状态设置失败也会返回成功
- 自定义表情有可能设置成其他表情
- 函数
- 合并了设置状态和设置自定义状态的 API
群聊相关
- LR5921
- 群聊成员
- 返回群成员列表,QQ 号及昵称
- 群聊签到
- 群聊回应
- 群聊精华
- 合并了设置与删除精华的 API
- 群聊头衔
- 群聊成员