mirror of
https://github.com/xfgryujk/blivedm.git
synced 2024-12-26 12:50:13 +08:00
升级弹幕协议版本
This commit is contained in:
parent
7ac4966c92
commit
cfda838e01
@ -6,10 +6,10 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import ssl as ssl_
|
import ssl as ssl_
|
||||||
import struct
|
import struct
|
||||||
import zlib
|
|
||||||
from typing import *
|
from typing import *
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
import brotli
|
||||||
|
|
||||||
from . import handlers
|
from . import handlers
|
||||||
|
|
||||||
@ -423,9 +423,8 @@ class BLiveClient:
|
|||||||
auth_params = {
|
auth_params = {
|
||||||
'uid': self._uid,
|
'uid': self._uid,
|
||||||
'roomid': self._room_id,
|
'roomid': self._room_id,
|
||||||
'protover': 2,
|
'protover': 3,
|
||||||
'platform': 'web',
|
'platform': 'web',
|
||||||
'clientver': '1.14.3',
|
|
||||||
'type': 2
|
'type': 2
|
||||||
}
|
}
|
||||||
if self._host_server_token is not None:
|
if self._host_server_token is not None:
|
||||||
@ -531,9 +530,9 @@ class BLiveClient:
|
|||||||
"""
|
"""
|
||||||
if header.operation == Operation.SEND_MSG_REPLY:
|
if header.operation == Operation.SEND_MSG_REPLY:
|
||||||
# 业务消息
|
# 业务消息
|
||||||
if header.ver == ProtoVer.DEFLATE:
|
if header.ver == ProtoVer.BROTLI:
|
||||||
# 压缩过的先解压,为了避免阻塞网络线程,放在其他线程执行
|
# 压缩过的先解压,为了避免阻塞网络线程,放在其他线程执行
|
||||||
body = await self._loop.run_in_executor(None, zlib.decompress, body)
|
body = await self._loop.run_in_executor(None, brotli.decompress, body)
|
||||||
await self._parse_ws_message(body)
|
await self._parse_ws_message(body)
|
||||||
elif header.ver == ProtoVer.NORMAL:
|
elif header.ver == ProtoVer.NORMAL:
|
||||||
# 没压缩过的直接反序列化,因为有万恶的GIL,这里不能并行避免阻塞
|
# 没压缩过的直接反序列化,因为有万恶的GIL,这里不能并行避免阻塞
|
||||||
|
@ -14,26 +14,29 @@ logger = logging.getLogger('blivedm')
|
|||||||
|
|
||||||
# 常见可忽略的cmd
|
# 常见可忽略的cmd
|
||||||
IGNORED_CMDS = (
|
IGNORED_CMDS = (
|
||||||
'INTERACT_WORD',
|
|
||||||
'ROOM_BANNER',
|
|
||||||
'ROOM_REAL_TIME_MESSAGE_UPDATE',
|
|
||||||
'NOTICE_MSG',
|
|
||||||
'COMBO_SEND',
|
'COMBO_SEND',
|
||||||
'COMBO_END',
|
|
||||||
'ENTRY_EFFECT',
|
'ENTRY_EFFECT',
|
||||||
'WELCOME_GUARD',
|
'HOT_RANK_CHANGED',
|
||||||
'WELCOME',
|
'HOT_RANK_CHANGED_V2',
|
||||||
'ROOM_RANK',
|
'INTERACT_WORD',
|
||||||
'ACTIVITY_BANNER_UPDATE_V2',
|
|
||||||
'PANEL',
|
|
||||||
'SUPER_CHAT_MESSAGE_JPN',
|
|
||||||
'USER_TOAST_MSG',
|
|
||||||
'ROOM_BLOCK_MSG',
|
|
||||||
'LIVE',
|
'LIVE',
|
||||||
|
'LIVE_INTERACTIVE_GAME',
|
||||||
|
'NOTICE_MSG',
|
||||||
|
'ONLINE_RANK_COUNT',
|
||||||
|
'ONLINE_RANK_TOP3',
|
||||||
|
'ONLINE_RANK_V2',
|
||||||
|
'PK_BATTLE_END',
|
||||||
|
'PK_BATTLE_FINAL_PROCESS',
|
||||||
|
'PK_BATTLE_PROCESS',
|
||||||
|
'PK_BATTLE_PROCESS_NEW',
|
||||||
|
'PK_BATTLE_SETTLE',
|
||||||
|
'PK_BATTLE_SETTLE_USER',
|
||||||
|
'PK_BATTLE_SETTLE_V2',
|
||||||
'PREPARING',
|
'PREPARING',
|
||||||
'room_admin_entrance',
|
'ROOM_REAL_TIME_MESSAGE_UPDATE',
|
||||||
'ROOM_ADMINS',
|
'STOP_LIVE_ROOM_LIST',
|
||||||
'ROOM_CHANGE',
|
'SUPER_CHAT_MESSAGE_JPN',
|
||||||
|
'WIDGET_BANNER',
|
||||||
)
|
)
|
||||||
|
|
||||||
# 已打日志的未知cmd
|
# 已打日志的未知cmd
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import json
|
||||||
from typing import *
|
from typing import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -39,10 +40,14 @@ class DanmakuMessage:
|
|||||||
:param font_size: 字体尺寸
|
:param font_size: 字体尺寸
|
||||||
:param color: 颜色
|
:param color: 颜色
|
||||||
:param timestamp: 时间戳(毫秒)
|
:param timestamp: 时间戳(毫秒)
|
||||||
:param rnd: 随机数,可能是去重用的
|
:param rnd: 随机数,前端叫作弹幕ID,可能是去重用的
|
||||||
:param uid_crc32: 用户ID文本的CRC32
|
:param uid_crc32: 用户ID文本的CRC32
|
||||||
:param msg_type: 是否礼物弹幕(节奏风暴)
|
:param msg_type: 是否礼物弹幕(节奏风暴)
|
||||||
:param bubble: 右侧评论栏气泡
|
:param bubble: 右侧评论栏气泡
|
||||||
|
:param dm_type: 弹幕类型,0文本,1表情,2语音
|
||||||
|
:param emoticon_options: 表情参数
|
||||||
|
:param voice_config: 语音参数
|
||||||
|
:param mode_info: 一些附加参数
|
||||||
|
|
||||||
:param msg: 弹幕内容
|
:param msg: 弹幕内容
|
||||||
|
|
||||||
@ -82,6 +87,10 @@ class DanmakuMessage:
|
|||||||
uid_crc32: str = None,
|
uid_crc32: str = None,
|
||||||
msg_type: int = None,
|
msg_type: int = None,
|
||||||
bubble: int = None,
|
bubble: int = None,
|
||||||
|
dm_type: int = None,
|
||||||
|
emoticon_options: Union[dict, str] = None,
|
||||||
|
voice_config: Union[dict, str] = None,
|
||||||
|
mode_info: dict = None,
|
||||||
|
|
||||||
msg: str = None,
|
msg: str = None,
|
||||||
|
|
||||||
@ -118,6 +127,10 @@ class DanmakuMessage:
|
|||||||
self.uid_crc32: str = uid_crc32
|
self.uid_crc32: str = uid_crc32
|
||||||
self.msg_type: int = msg_type
|
self.msg_type: int = msg_type
|
||||||
self.bubble: int = bubble
|
self.bubble: int = bubble
|
||||||
|
self.dm_type: int = dm_type
|
||||||
|
self.emoticon_options: Union[dict, str] = emoticon_options
|
||||||
|
self.voice_config: Union[dict, str] = voice_config
|
||||||
|
self.mode_info: dict = mode_info
|
||||||
|
|
||||||
self.msg: str = msg
|
self.msg: str = msg
|
||||||
|
|
||||||
@ -172,6 +185,10 @@ class DanmakuMessage:
|
|||||||
uid_crc32=info[0][7],
|
uid_crc32=info[0][7],
|
||||||
msg_type=info[0][9],
|
msg_type=info[0][9],
|
||||||
bubble=info[0][10],
|
bubble=info[0][10],
|
||||||
|
dm_type=info[0][12],
|
||||||
|
emoticon_options=info[0][13],
|
||||||
|
voice_config=info[0][14],
|
||||||
|
mode_info=info[0][15],
|
||||||
|
|
||||||
msg=info[1],
|
msg=info[1],
|
||||||
|
|
||||||
@ -201,6 +218,37 @@ class DanmakuMessage:
|
|||||||
privilege_type=info[7],
|
privilege_type=info[7],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def emoticon_options_dict(self) -> dict:
|
||||||
|
"""
|
||||||
|
示例:
|
||||||
|
{'bulge_display': 0, 'emoticon_unique': 'official_13', 'height': 60, 'in_player_area': 1, 'is_dynamic': 1,
|
||||||
|
'url': 'https://i0.hdslb.com/bfs/live/a98e35996545509188fe4d24bd1a56518ea5af48.png', 'width': 183}
|
||||||
|
"""
|
||||||
|
if isinstance(self.emoticon_options, dict):
|
||||||
|
return self.emoticon_options
|
||||||
|
try:
|
||||||
|
return json.loads(self.emoticon_options)
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def voice_config_dict(self) -> dict:
|
||||||
|
"""
|
||||||
|
示例:
|
||||||
|
{'voice_url': 'https%3A%2F%2Fboss.hdslb.com%2Flive-dm-voice%2Fb5b26e48b556915cbf3312a59d3bb2561627725945.wav
|
||||||
|
%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3D2663ba902868f12f%252F20210731%252Fshjd%252Fs3%25
|
||||||
|
2Faws4_request%26X-Amz-Date%3D20210731T100545Z%26X-Amz-Expires%3D600000%26X-Amz-SignedHeaders%3Dhost%26
|
||||||
|
X-Amz-Signature%3D114e7cb5ac91c72e231c26d8ca211e53914722f36309b861a6409ffb20f07ab8',
|
||||||
|
'file_format': 'wav', 'text': '汤,下午好。', 'file_duration': 1}
|
||||||
|
"""
|
||||||
|
if isinstance(self.voice_config, dict):
|
||||||
|
return self.voice_config
|
||||||
|
try:
|
||||||
|
return json.loads(self.voice_config)
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
class GiftMessage:
|
class GiftMessage:
|
||||||
"""
|
"""
|
||||||
@ -217,9 +265,10 @@ class GiftMessage:
|
|||||||
:param gift_type: 礼物类型(未知)
|
:param gift_type: 礼物类型(未知)
|
||||||
:param action: 目前遇到的有'喂食'、'赠送'
|
:param action: 目前遇到的有'喂食'、'赠送'
|
||||||
:param price: 礼物单价瓜子数
|
:param price: 礼物单价瓜子数
|
||||||
:param rnd: 随机数,可能是去重用的
|
:param rnd: 随机数,可能是去重用的。有时是时间戳+去重ID,有时是UUID
|
||||||
:param coin_type: 瓜子类型,'silver'或'gold'
|
:param coin_type: 瓜子类型,'silver'或'gold',1000金瓜子 = 1元
|
||||||
:param total_coin: 总瓜子数
|
:param total_coin: 总瓜子数
|
||||||
|
:param tid: 可能是事务ID,有时和rnd相同
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -238,6 +287,7 @@ class GiftMessage:
|
|||||||
rnd: str = None,
|
rnd: str = None,
|
||||||
coin_type: str = None,
|
coin_type: str = None,
|
||||||
total_coin: int = None,
|
total_coin: int = None,
|
||||||
|
tid: str = None,
|
||||||
):
|
):
|
||||||
self.gift_name = gift_name
|
self.gift_name = gift_name
|
||||||
self.num = num
|
self.num = num
|
||||||
@ -253,6 +303,7 @@ class GiftMessage:
|
|||||||
self.rnd = rnd
|
self.rnd = rnd
|
||||||
self.coin_type = coin_type
|
self.coin_type = coin_type
|
||||||
self.total_coin = total_coin
|
self.total_coin = total_coin
|
||||||
|
self.tid = tid
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_command(cls, data: dict):
|
def from_command(cls, data: dict):
|
||||||
@ -271,6 +322,7 @@ class GiftMessage:
|
|||||||
rnd=data['rnd'],
|
rnd=data['rnd'],
|
||||||
coin_type=data['coin_type'],
|
coin_type=data['coin_type'],
|
||||||
total_coin=data['total_coin'],
|
total_coin=data['total_coin'],
|
||||||
|
tid=data['tid'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -285,8 +337,8 @@ class GuardBuyMessage:
|
|||||||
:param price: 单价金瓜子数
|
:param price: 单价金瓜子数
|
||||||
:param gift_id: 礼物ID
|
:param gift_id: 礼物ID
|
||||||
:param gift_name: 礼物名
|
:param gift_name: 礼物名
|
||||||
:param start_time: 开始时间戳,和结束时间戳一样
|
:param start_time: 开始时间戳,和结束时间戳相同
|
||||||
:param end_time: 结束时间戳,和开始时间戳一样
|
:param end_time: 结束时间戳,和开始时间戳相同
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -332,10 +384,10 @@ class SuperChatMessage:
|
|||||||
|
|
||||||
:param price: 价格(人民币)
|
:param price: 价格(人民币)
|
||||||
:param message: 消息
|
:param message: 消息
|
||||||
:param message_jpn: 消息日文翻译(目前只出现在SUPER_CHAT_MESSAGE_JPN)
|
:param message_trans: 消息日文翻译(目前只出现在SUPER_CHAT_MESSAGE_JPN)
|
||||||
:param start_time: 开始时间戳
|
:param start_time: 开始时间戳
|
||||||
:param end_time: 结束时间戳
|
:param end_time: 结束时间戳
|
||||||
:param time: 持续时间(结束时间戳 - 开始时间戳)
|
:param time: 剩余时间(约等于 结束时间戳 - 开始时间戳)
|
||||||
:param id_: str,醒目留言ID,删除时用
|
:param id_: str,醒目留言ID,删除时用
|
||||||
:param gift_id: 礼物ID
|
:param gift_id: 礼物ID
|
||||||
:param gift_name: 礼物名
|
:param gift_name: 礼物名
|
||||||
@ -355,7 +407,7 @@ class SuperChatMessage:
|
|||||||
self,
|
self,
|
||||||
price: int = None,
|
price: int = None,
|
||||||
message: str = None,
|
message: str = None,
|
||||||
message_jpn: str = None,
|
message_trans: str = None,
|
||||||
start_time: int = None,
|
start_time: int = None,
|
||||||
end_time: int = None,
|
end_time: int = None,
|
||||||
time: int = None,
|
time: int = None,
|
||||||
@ -375,7 +427,7 @@ class SuperChatMessage:
|
|||||||
):
|
):
|
||||||
self.price: int = price
|
self.price: int = price
|
||||||
self.message: str = message
|
self.message: str = message
|
||||||
self.message_jpn: str = message_jpn
|
self.message_trans: str = message_trans
|
||||||
self.start_time: int = start_time
|
self.start_time: int = start_time
|
||||||
self.end_time: int = end_time
|
self.end_time: int = end_time
|
||||||
self.time: int = time
|
self.time: int = time
|
||||||
@ -398,7 +450,7 @@ class SuperChatMessage:
|
|||||||
return cls(
|
return cls(
|
||||||
price=data['price'],
|
price=data['price'],
|
||||||
message=data['message'],
|
message=data['message'],
|
||||||
message_jpn=data['message_trans'],
|
message_trans=data['message_trans'],
|
||||||
start_time=data['start_time'],
|
start_time=data['start_time'],
|
||||||
end_time=data['end_time'],
|
end_time=data['end_time'],
|
||||||
time=data['time'],
|
time=data['time'],
|
||||||
|
@ -1 +1,2 @@
|
|||||||
aiohttp==3.7.4
|
aiohttp==3.7.4
|
||||||
|
Brotli==1.0.9
|
||||||
|
Loading…
Reference in New Issue
Block a user