ddiu8081 / blive-message-listener

Bilibili live danmu listener with type. 类型友好的 Bilibili 直播间弹幕监听库。
https://npmjs.com/blive-message-listener
MIT License
143 stars 14 forks source link

监听弹幕时获取用户头像 #27

Open sunft1996 opened 1 year ago

sunft1996 commented 1 year ago

Clear and concise description of the problem

如题

Suggested solution

如题

Alternative

No response

Additional context

No response

Validations

ddiu8081 commented 1 year ago

目前原始弹幕消息中不包含头像数据,获取头像需要手动通过接口取,给框架添加此功能可能带来一些问题:

  1. 可能会引入额外依赖,目前仅读取 Websocket / TCP 流,如果读取 HTTP 接口可能还需要增加依赖库
  2. 弹幕密集时可能会被频控限制
  3. 浏览器环境存在跨域问题,无法获取

因此添加头像可能比较困难,目前建议是自行维护头像获取和频控逻辑。之后调研如果方便的话 会内置进来

micooz commented 1 year ago

也许能用隔壁的方案:https://github.com/xfgryujk/blivedm/commit/2b04284ae31b0b0e25e5a252fd87d0db76c68802

具体做法是在 DANMU_MSG.parser 中添加解析 dm_v2 字段的代码。

https://github.com/ddiu8081/blive-message-listener/blob/9976d7812ab1b1e76b01e807514515a117edde0e/src/parser/DANMU_MSG.ts#L31-L33

dm_v2 是一个经过 base64 编码的 protobuf 报文,里面包含用户头像字段,协议格式在上面的 blivedm/pb_models.py 中有实现。

echo -n "CiIxMmM2ZDg4MGQ5Yjc3Njc3NTI1NTA1NjFjYjY0YTJmYjU5EAEYGSDP2v8HKghkODU4ZWQ3MzIG5ZGc5ZGcOMHUk+WRMUjl2cv+AWIAaAFydwoG5ZGc5ZGcEm0KE3Jvb21fMTA0MTMwNTFfMzY5NDkSSmh0dHBzOi8vaTAuaGRzbGIuY29tL2Jmcy9nYXJiLzMxYjI4ZjRlZjQ0NmYxNmYzZDEyZGU3ZTYzMmFlNjBhMmE0NDAyZWIucG5nGAEgASgBMKIBOKIBigEAmgEQCghFRTQ5MzU1OBCd9oulBqIBpQEIwofiBBIP5biD5LiB55Wq6IyE6IyEIkpodHRwczovL2kwLmhkc2xiLmNvbS9iZnMvZmFjZS9mY2NjY2MxOTQ3N2M0YzYzMGE0MjMwMjliYmViYjk1N2NkZGFkOWMyLmpwZziQTkABWiMIERIJ54ix6I2U5LidIKS6ngYwpLqeBjikup4GQKS6ngZQAWIPCBUQ3q3iAhoGPjUwMDAwagByAHoCCB+qARoIt+vxwQQSDeiNlOaenVl1cmliaXUY+8f7BA==" | base64 -d | hexdump -C

可能还需要引入一个类似 pure-protobuf 的 decoder 来方便解析。

Tsuk1ko commented 12 months ago

可以使用 protobufjs,分享一个我自己测试可行的方案

import { length as b64len, decode as b64dec } from '@protobufjs/base64';
import { Type, Field } from 'protobufjs';

const decodeB64 = str => {
  const length = b64len(str);
  const buffer = new Uint8Array(length);
  b64dec(str, buffer, 0);
  return buffer;
};

const UserInfo = new Type('UserInfo').add(new Field('face', 4, 'string'));
const DanmakuMessageV2 = new Type('DanmakuMessageV2').add(UserInfo).add(new Field('user', 20, 'UserInfo'));

/**
 * @param {string} str
 * @returns {{ user: { face: string } }}
 */
export const decodeDmV2 = str => {
  const buffer = decodeB64(str);
  return DanmakuMessageV2.decode(buffer);
};