跳到主要内容

消息适配器

  • 本篇中,标题对应文件中的函数,同时也是消息格式中的接收、发送的函数、类型
  • 每个平台的机制为四项消息测试中的测试结果汇总,处理为对应的函数逻辑

请求统一处理

  • 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
    • 机制
      1. 普通消息
      • 表情中,emoji 表情会以文本类解析;超级表情单发和与跟文本混合发送无区别
      • 引用消息时会自动@某人,但可以删掉,不必须
      • 转发单条消息会变成普通消息(即使原消息有引用)
      • 商城表情即使添加到收藏表情,也是解析成商城表情
      • 图片消息由拍照和上传图片产生,且与 LR232 文件名是一致的
      • 视频消息需要长按拍照产生,否则是文件
      • 视频消息可以自动预览播放,文件需要下载
      • 卡片消息中 data.data 值包含双引号,在处理时解析
      • LR5921 @ 时会自动加一个空格,解析到文字里;由于没有涉及到群聊 @ 才能触发的指令,故不用处理
      1. 临时消息
      • 临时消息的 sender 字段无昵称,多了 temp_source 和 group_id 字段
      • 不能主动向其他用户发送临时消息,其他用户创建临时消息会话后可以发送临时消息,所以临时消息的处理逻辑与正常消息相同,发送 API 相同,二者统一处理
      • 系统处理后两个消息相同
      1. 撤回消息
      • 从消息池中获取
      • 撤回消息无消息 id,即消息池中没有消息(没接收过/超过一天)则无法找到原消息(与日常行为一致,没看过原消息则不知道是什么)
      1. 好友添加
      • 设置任何人可添加时,会产生两条消息,请求添加为好友的文字消息和好友添加的事件
      • 只处理第二条
      • 没有消息序号
      1. 戳戳消息
      • 分为原始戳一戳(手机加号中的戳一戳类型、电脑窗口抖动)和新戳一戳(双击头像)
      • 其中前者并入消息接收类型中的 poke 类型,后者为私聊/群聊戳戳类型
      • 前者除了第一个外,其他的均显示为文本“[xxx]请使用最新版本手机QQ查看。”,右边口袋中的内容无法解析
      1. 群聊回应
      • 回应只能显示一个表情且数量固定为 1
      • 回应只能接收对自己表态的,且无法获取对应的消息序号
      1. 精华消息
      • 自己设置自己为精华则 sender_id 与 user_id 均为 0
      • 无法接收移出精华消息
      • 没有对应消息 id(很奇怪)
      1. 群名片更改
      • 只有更改后发了消息才能获取到
      1. 其他消息
      • 无法接收
        • QQ 电话
        • 动态点赞
        • 编辑群介绍
        • 好友删除
        • 群待办
    • 函数
      • 过滤掉 meta_event,message_sent,request 事件
      • 过滤掉不在群列表中的消息(减少消息日志)
      • 处理 message 事件
        • 跳过空消息
        • 过滤 LR232 接收的消息(变为系统消息)
        • 转发消息使用原消息替换消息 id
        • 卡片消息解析字符串为 json 格式
        • 回复消息使用原消息替换 reply 段中的 id
      • 处理 notice 事件
        • 进行事件分类
        • 忽略群聊文件、群聊删除、群聊管理、群聊禁言、群名片更改
        • 处理私聊/群聊添加、私聊/群聊撤回、私聊/群聊戳戳、群聊回应、群聊设精
        • 从消息池中寻找撤回消息段作为消息内容
        • 处理消息提醒
          • 忽略输入状态、头衔消息、群名称修改、私聊点赞
          • 处理戳戳,整理戳戳文字
  • LR232
    • 机制
      1. 普通消息
      • 会以文本类型解析 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=">,而附件里有三个文件,无法确认哪个是动画表情
        • 只能采取折中方案:
          • 当动画表情字段数与附件数相等时,将附件里的信息加入动画表情字段中,保留动画表情在消息内容中的顺序
          • 当动画表情字段与附件数不相等时,删除内容中的动画表情,保留附件,将所有动画表情当成图片
      1. 回调配置
      • 回调配置与消息接收使用同一端口
      • 回调配置的 op 码为 13,消息接收为 0
      1. 附件
      • LR232 的图片/语音/视频/文件在 attachments 字段里面
      1. 重复推送
      • 网络原因,QQ 可能会在 5 秒内多次推送同一消息
      1. 事件消息
      • 非接收类的消息,需要根据 event_id 来回复,接受类根据 msg_id 来回复
      • 删除事件不能通过 event_id 来回复
      1. 快捷面板
      • 使用快捷面板触发的指令,会在末尾加一个空格,使用@并选择 LR232,会在 @ 和文字之间加一个空格。此时,对于完全匹配的指令如"/帮助"则会失效,故需要 strip 掉空格
    • 函数
      • 根据 op 码分类回调配置和消息处理
      • 设置 5 秒消息去重
      • 进行消息事件分类
        • 处理事件消息
          • 处理私聊添加,不处理群聊添加、群聊删除、私聊删除
        • 处理普通消息
          • 提取表情
            • 提取骰子和猜拳
            • 提取并使用 base64 和 json 解析普通和商城表情
              • 能提取到 text 则解析成功
          • 提取文字
            • 去除空格
          • 提取附件
            • 分离图片语音视频文件
          • 进行动画表情和文件消息的合并
  • WECHAT
    • 机制
      1. 回调配置
      • 回调配置使用 get 方法,消息使用 post
      1. 普通消息
      • 无法接收上传表情/收藏表情
      • 以文本类型解析 emoji 表情
      • 图片消息是相册中发送的
      • 收藏中的合并转发消息无法接收
      • 音频消息长按语音输入
      • qq 音乐分享无法接收
      • 无法解析文件消息
      • 可分享推文/链接,需要先收藏
      1. 事件消息
      • 事件消息没有 seq
      • 点击菜单事件无法回复
      1. 重复推送
      • 消息没有回复则 5s 后重新发送一次,共三次
    • 函数
      • 设置 15 秒回复的超时时间(可以回复第一条消息)
      • 处理事件消息
        • 处理私聊添加,不处理私聊删除、菜单点击
        • 消息 seq 设置为接收时间+两位随机数(本身无序号)
      • 处理普通消息
        • 去除重复消息(通过 seq)
        • 分离文本、图片、语音、视频、卡片消息
      • 表情处理
        • 在微信的文字消息中,表情字段唯一且以'/:'开头或者被'[]'包裹
        • 为了解决 /::) 123 的匹配情况(实际消息为:[微笑] 123)
        • 代码中先提取出 wechat_emojis 中所有的键
        • 用 | 连接,构造一个 a|b|c……的正则表达式
        • 对文字消息中的表情进行逐一匹配
  • BILI
    • 机制
      1. 普通消息
      • emoji 与表情中的颜文字表情均以文字形式解析
      • 图片消息只能单发
      1. 重复发送
      • 重复发送同一消息过多会触发 B 站的机制,无法接收
      • 后续发送不同的消息会把之前没有接收到的消息一起收到
      1. 撤回消息会导致 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

    • 机制
      1. 优先级
      • 卡片>文件>视频>语音>其他,前面的会覆盖掉后面的
      1. 发送
      • 无法发送空的消息及 0B 的文本
    • 函数
      • 将转发消息、转发节点消息与戳戳的 API 合并进消息发送中
        • 默认转发消息只有一项,即[转发:id],之后的项不考虑
        • 默认节点消息只有一项,即[节点:id|用户|消息组],之后的项不考虑
        • 戳戳消息私聊时只有一个参数,采用 111 占位
      • 返回消息序号
  • LR232

    • 机制
      1. 添加发送
      • 接收时,将“接收”与“添加”区分开来,“添加”事件的消息序号需要以 event_id 字段名来回复,故在 LR232 发送时多了一种类型“添加发送”来回复此类消息
      1. 额外参数
      • 回复存在有效时间,私聊 60 分钟,群聊 5 分钟,且最多回复 5 次,需要记录 order 来应对多次回复的情况,使用同一 order 回复同一消息会失败。若是一条消息在消息发送中进行拆分,order 自动递增;若以多条消息回复同一条消息,需要自己设置 order 递增
    • 函数
      • 私聊和群聊调用不同的 url
      • 发生和添加发送使用不同的 tag(但值都是 user)
      • 将消息段分为文字+表情包和图片,文字统一发送,图片分开发送(不合并发送图文,会使逻辑更复杂
      • 文字发送时处理网址,先找到白名单里的网址,然后处理从上一个白名单之后到下一个白名单之前的内容中的网址,替换为[网址]
      • 若需要发送网址需要在平台和代码里同步添加白名单
      • 图片发送时调用图片上传
      • 自动递增 order(没有添加记录值,需要自行判断有没有 >5
      • 返回消息序号列表
  • WECHAT

    • 机制
      1. 发送表情
      • 若发送的内容匹配到了某个表情,则在发送后被替换成该表情
      • 如文字发送 [doge_金箍] 或者 /::) 会被 B 站和微信自动解析成金箍表情和微笑
      1. 发送
      • 只能回复当前消息,故只能发送一条消息,需要合并图文
      • 采用 future 变量作为推送消息(接收)请求的回应值,超过 20s 会超时
      • 发送换行符时,使用/u2028 电脑能解析但手机不能,使用/n二者均不能解析。故统一将/n替换成图片格式
      • 同样存在“添加发送”
      • 大约最多 550 个字
    • 函数
      • 取消息段中第一条消息,分离音频、视频、卡片类型
      • 剩下的为图文
        • 若存在图片及文字
          • 拼接图片和文字(合并文字在最上方,图片在下方)
          • 延时删除
        • 若只存在文字
          • 合并文字消息
          • 若存在换行,生成图片
          • 若不存在,直接发送
        • 若只存在图片
          • 一张直接发送
          • 多张合并后发送,延时删除
      • 拼接消息体
  • BILI

    • 机制
      1. 发送表情
      • 同 WECHAT
      • BILI 可以伪造表情,即根据发送机制,使用[xxx]时,主观意愿是接收/发送表情,解析也为表情:xx,省去了检索 B 站表情包(添加几百个表情到中途放弃了)的精力
      1. 发送
      • 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
    • 机制
      1. 上传限制
      • 文件有效期 1h
      • 图片 20MB
      • 视频 9.99MB(9.999 不行,9.98 可以)
      • 音频 mp3 自动转换为 silk(silk 比较小,没测大小限制)
      1. 文件 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
  • WECHAT

撤回

  • 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
    • 群聊头衔