项目概述

这是一个 B 站直播间弹幕联动系统,支持:

  • 实时监听直播间弹幕,识别指令关键词
  • 点歌功能(集成网易云音乐 pyncm)
  • 向指定用户批量发送私信
  • PySide6 GUI 界面

私信发送接口逆向

B 站私信发送使用 api.vc.bilibili.com(独立于主 API 域名):

import uuid, json, time, requests

def send_message(cookie: str, receiver_uid: int, content: str) -> bool:
    bili_jct = extract_cookie(cookie, 'bili_jct')  # CSRF token
    sender_uid = get_self_uid(cookie)
    dev_id = str(uuid.uuid4()).upper()

    payload = {
        'msg[sender_uid]': sender_uid,
        'msg[receiver_id]': receiver_uid,
        'msg[receiver_type]': 1,   # 1=用户 2=粉丝团
        'msg[msg_type]': 1,        # 1=文字 2=图片
        'msg[dev_id]': dev_id,
        'msg[timestamp]': int(time.time()),
        'msg[content]': json.dumps({'content': content}),
        'csrf_token': bili_jct,
        'csrf': bili_jct,
        'build': 0,
        'mobi_app': 'web',
    }
    r = requests.post(
        'https://api.vc.bilibili.com/web_im/v1/web_im/send_msg',
        data=payload,
        headers={'Cookie': cookie, 'Referer': 'https://message.bilibili.com/'}
    )
    return r.json()['code'] == 0

弹幕监听

B 站直播弹幕使用 WebSocket 协议,连接 broadcastlv.chat.bilibili.com

import asyncio, websockets, struct, json, zlib

DANMU_WS = 'wss://broadcastlv.chat.bilibili.com/sub'

async def listen_danmu(room_id: int, callback):
    async with websockets.connect(DANMU_WS) as ws:
        # 发送进入房间包
        await ws.send(build_join_packet(room_id))

        async for msg in ws:
            packets = parse_packet(msg)
            for pkt in packets:
                if pkt['op'] == 5:  # SEND_MSG_REPLY
                    data = json.loads(pkt['body'])
                    if data.get('cmd') == 'DANMU_MSG':
                        text = data['info'][1]
                        uid = data['info'][2][0]
                        await callback(uid, text)

弹幕数据包格式

Header (16 bytes):
  [0:4]  = 数据包总长度 (big-endian uint32)
  [4:6]  = 头部长度,固定 16
  [6:8]  = 协议版本 (0=JSON, 2=zlib压缩)
  [8:12] = 操作码 (2=心跳, 3=心跳回应, 5=通知, 7=进房, 8=进房回应)
  [12:16] = 序列号
Body: JSON 或 zlib(JSON)

点歌功能(pyncm 集成)

import pyncm
from pyncm import apis as ncm_apis

def search_and_play(keyword: str):
    # 搜索歌曲
    result = ncm_apis.cloudsearch.GetSearchResult(keyword, limit=1)
    songs = result['result']['songs']
    if not songs:
        return None
    song = songs[0]
    song_id = song['id']

    # 获取下载链接
    url_result = ncm_apis.track.GetTrackAudio([song_id], bitrate=320000)
    url = url_result['data'][0]['url']

    # pygame 播放
    pygame.mixer.music.load(url)
    pygame.mixer.music.play()
    return song['name']

弹幕规则引擎

通过正则规则匹配弹幕指令,触发对应动作:

[
  {"pattern": "点歌 (.+)",    "action": "song",    "group": 1},
  {"pattern": "私信我$",       "action": "sendmsg", "template": "您好!欢迎关注!"},
  {"pattern": "跳过$",         "action": "skip"}
]

规则配置存入 danmu_rules.json,运行时热重载,无需重启服务。