diff --git a/blivedm/__init__.py b/blivedm/__init__.py index 910cede..5dc4d0e 100644 --- a/blivedm/__init__.py +++ b/blivedm/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- - from .blivedm import * +from .models import * diff --git a/blivedm/blivedm.py b/blivedm/blivedm.py index 98f4e4f..0e61135 100644 --- a/blivedm/blivedm.py +++ b/blivedm/blivedm.py @@ -1,17 +1,18 @@ # -*- coding: utf-8 -*- - import asyncio +import collections +import enum import json import logging import ssl as ssl_ import struct import zlib -from collections import namedtuple -from enum import IntEnum from typing import * import aiohttp +from . import models + logger = logging.getLogger('blivedm') ROOM_INIT_URL = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom' @@ -21,14 +22,14 @@ DEFAULT_DANMAKU_SERVER_LIST = [ ] HEADER_STRUCT = struct.Struct('>I2H2I') -HeaderTuple = namedtuple('HeaderTuple', ('pack_len', 'raw_header_size', 'ver', 'operation', 'seq_id')) +HeaderTuple = collections.namedtuple('HeaderTuple', ('pack_len', 'raw_header_size', 'ver', 'operation', 'seq_id')) WS_BODY_PROTOCOL_VERSION_INFLATE = 0 WS_BODY_PROTOCOL_VERSION_NORMAL = 1 WS_BODY_PROTOCOL_VERSION_DEFLATE = 2 # go-common\app\service\main\broadcast\model\operation.go -class Operation(IntEnum): +class Operation(enum.IntEnum): HANDSHAKE = 0 HANDSHAKE_REPLY = 1 HEARTBEAT = 2 @@ -56,270 +57,28 @@ class InitError(Exception): """初始化失败""" -class DanmakuMessage: - def __init__(self, mode, font_size, color, timestamp, rnd, uid_crc32, msg_type, bubble, - msg, - uid, uname, admin, vip, svip, urank, mobile_verify, uname_color, - medal_level, medal_name, runame, room_id, mcolor, special_medal, - user_level, ulevel_color, ulevel_rank, - old_title, title, - privilege_type): - """ - :param mode: 弹幕显示模式(滚动、顶部、底部) - :param font_size: 字体尺寸 - :param color: 颜色 - :param timestamp: 时间戳 - :param rnd: 随机数 - :param uid_crc32: 用户ID文本的CRC32 - :param msg_type: 是否礼物弹幕(节奏风暴) - :param bubble: 右侧评论栏气泡 - - :param msg: 弹幕内容 - - :param uid: 用户ID - :param uname: 用户名 - :param admin: 是否房管 - :param vip: 是否月费老爷 - :param svip: 是否年费老爷 - :param urank: 用户身份,用来判断是否正式会员,猜测非正式会员为5000,正式会员为10000 - :param mobile_verify: 是否绑定手机 - :param uname_color: 用户名颜色 - - :param medal_level: 勋章等级 - :param medal_name: 勋章名 - :param runame: 勋章房间主播名 - :param room_id: 勋章房间ID - :param mcolor: 勋章颜色 - :param special_medal: 特殊勋章 - - :param user_level: 用户等级 - :param ulevel_color: 用户等级颜色 - :param ulevel_rank: 用户等级排名,>50000时为'>50000' - - :param old_title: 旧头衔 - :param title: 头衔 - - :param privilege_type: 舰队类型,0非舰队,1总督,2提督,3舰长 - """ - self.mode = mode - self.font_size = font_size - self.color = color - self.timestamp = timestamp - self.rnd = rnd - self.uid_crc32 = uid_crc32 - self.msg_type = msg_type - self.bubble = bubble - - self.msg = msg - - self.uid = uid - self.uname = uname - self.admin = admin - self.vip = vip - self.svip = svip - self.urank = urank - self.mobile_verify = mobile_verify - self.uname_color = uname_color - - self.medal_level = medal_level - self.medal_name = medal_name - self.runame = runame - self.room_id = room_id - self.mcolor = mcolor - self.special_medal = special_medal - - self.user_level = user_level - self.ulevel_color = ulevel_color - self.ulevel_rank = ulevel_rank - - self.old_title = old_title - self.title = title - - self.privilege_type = privilege_type - - @classmethod - def from_command(cls, info: dict): - return cls( - info[0][1], info[0][2], info[0][3], info[0][4], info[0][5], info[0][7], info[0][9], info[0][10], - info[1], - *info[2][:8], - *(info[3][:6] or (0, '', '', 0, 0, 0)), - info[4][0], info[4][2], info[4][3], - *info[5][:2], - info[7] - ) - - -class GiftMessage: - def __init__(self, gift_name, num, uname, face, guard_level, uid, timestamp, gift_id, - gift_type, action, price, rnd, coin_type, total_coin): - """ - :param gift_name: 礼物名 - :param num: 礼物数量 - :param uname: 用户名 - :param face: 用户头像URL - :param guard_level: 舰队等级,0非舰队,1总督,2提督,3舰长 - :param uid: 用户ID - :param timestamp: 时间戳 - :param gift_id: 礼物ID - :param gift_type: 礼物类型(未知) - :param action: 目前遇到的有'喂食'、'赠送' - :param price: 礼物单价瓜子数 - :param rnd: 随机数 - :param coin_type: 瓜子类型,'silver'或'gold' - :param total_coin: 总瓜子数 - """ - self.gift_name = gift_name - self.num = num - self.uname = uname - self.face = face - self.guard_level = guard_level - self.uid = uid - self.timestamp = timestamp - self.gift_id = gift_id - self.gift_type = gift_type - self.action = action - self.price = price - self.rnd = rnd - self.coin_type = coin_type - self.total_coin = total_coin - - @classmethod - def from_command(cls, data: dict): - return cls( - data['giftName'], data['num'], data['uname'], data['face'], data['guard_level'], - data['uid'], data['timestamp'], data['giftId'], data['giftType'], - data['action'], data['price'], data['rnd'], data['coin_type'], data['total_coin'] - ) - - -class GuardBuyMessage: - def __init__(self, uid, username, guard_level, num, price, gift_id, gift_name, - start_time, end_time): - """ - :param uid: 用户ID - :param username: 用户名 - :param guard_level: 舰队等级,0非舰队,1总督,2提督,3舰长 - :param num: 数量 - :param price: 单价金瓜子数 - :param gift_id: 礼物ID - :param gift_name: 礼物名 - :param start_time: 开始时间戳? - :param end_time: 结束时间戳? - """ - self.uid = uid - self.username = username - self.guard_level = guard_level - self.num = num - self.price = price - self.gift_id = gift_id - self.gift_name = gift_name - self.start_time = start_time - self.end_time = end_time - - @classmethod - def from_command(cls, data: dict): - return cls( - data['uid'], data['username'], data['guard_level'], data['num'], data['price'], - data['gift_id'], data['gift_name'], data['start_time'], data['end_time'] - ) - - -class SuperChatMessage: - def __init__(self, price, message, message_jpn, start_time, end_time, time, id_, - gift_id, gift_name, uid, uname, face, guard_level, user_level, - background_bottom_color, background_color, background_icon, background_image, - background_price_color): - """ - :param price: 价格(人民币) - :param message: 消息 - :param message_jpn: 消息日文翻译(目前只出现在SUPER_CHAT_MESSAGE_JPN) - :param start_time: 开始时间戳 - :param end_time: 结束时间戳 - :param time: 剩余时间 - :param id_: str,消息ID,删除时用 - :param gift_id: 礼物ID - :param gift_name: 礼物名 - :param uid: 用户ID - :param uname: 用户名 - :param face: 用户头像URL - :param guard_level: 舰队等级,0非舰队,1总督,2提督,3舰长 - :param user_level: 用户等级 - :param background_bottom_color: 底部背景色 - :param background_color: 背景色 - :param background_icon: 背景图标 - :param background_image: 背景图 - :param background_price_color: 背景价格颜色 - """ - self.price = price - self.message = message - self.message_jpn = message_jpn - self.start_time = start_time - self.end_time = end_time - self.time = time - self.id = id_ - self.gift_id = gift_id - self.gift_name = gift_name - self.uid = uid - self.uname = uname - self.face = face - self.guard_level = guard_level - self.user_level = user_level - self.background_bottom_color = background_bottom_color - self.background_color = background_color - self.background_icon = background_icon - self.background_image = background_image - self.background_price_color = background_price_color - - @classmethod - def from_command(cls, data: dict): - return cls( - data['price'], data['message'], data['message_trans'], data['start_time'], - data['end_time'], data['time'], data['id'], data['gift']['gift_id'], - data['gift']['gift_name'], data['uid'], data['user_info']['uname'], - data['user_info']['face'], data['user_info']['guard_level'], - data['user_info']['user_level'], data['background_bottom_color'], - data['background_color'], data['background_icon'], data['background_image'], - data['background_price_color'] - ) - - -class SuperChatDeleteMessage: - def __init__(self, ids): - """ - :param ids: 消息ID数组 - """ - self.ids = ids - - @classmethod - def from_command(cls, data: dict): - return cls( - data['ids'] - ) - - class BLiveClient: _COMMAND_HANDLERS: Dict[str, Optional[Callable[['BLiveClient', dict], Awaitable]]] = { # 收到弹幕 # go-common\app\service\live\live-dm\service\v1\send.go - 'DANMU_MSG': lambda client, command: client._on_receive_danmaku( - DanmakuMessage.from_command(command['info']) + 'DANMU_MSG': lambda client, command: client._on_receive_danmaku( # noqa + models.DanmakuMessage.from_command(command['info']) ), # 有人送礼 - 'SEND_GIFT': lambda client, command: client._on_receive_gift( - GiftMessage.from_command(command['data']) + 'SEND_GIFT': lambda client, command: client._on_receive_gift( # noqa + models.GiftMessage.from_command(command['data']) ), # 有人上舰 - 'GUARD_BUY': lambda client, command: client._on_buy_guard( - GuardBuyMessage.from_command(command['data']) + 'GUARD_BUY': lambda client, command: client._on_buy_guard( # noqa + models.GuardBuyMessage.from_command(command['data']) ), # 醒目留言 - 'SUPER_CHAT_MESSAGE': lambda client, command: client._on_super_chat( - SuperChatMessage.from_command(command['data']) + 'SUPER_CHAT_MESSAGE': lambda client, command: client._on_super_chat( # noqa + models.SuperChatMessage.from_command(command['data']) ), # 删除醒目留言 - 'SUPER_CHAT_MESSAGE_DELETE': lambda client, command: client._on_super_chat_delete( - SuperChatDeleteMessage.from_command(command['data']) + 'SUPER_CHAT_MESSAGE_DELETE': lambda client, command: client._on_super_chat_delete( # noqa + models.SuperChatDeleteMessage.from_command(command['data']) ) } # 其他常见命令 @@ -332,7 +91,7 @@ class BLiveClient: _COMMAND_HANDLERS[cmd] = None del cmd - def __init__(self, room_id, uid=0, session: aiohttp.ClientSession=None, + def __init__(self, room_id, uid=0, session: aiohttp.ClientSession = None, heartbeat_interval=30, ssl=True, loop=None): """ :param room_id: URL中的房间ID,可以为短ID @@ -354,8 +113,7 @@ class BLiveClient: if loop is not None: self._loop = loop elif session is not None: - # noinspection PyDeprecation - self._loop = session.loop + self._loop = session.loop # noqa else: self._loop = asyncio.get_event_loop() self._future = None @@ -366,13 +124,11 @@ class BLiveClient: else: self._session = session self._own_session = False - # noinspection PyDeprecation - if self._session.loop is not self._loop: + if self._session.loop is not self._loop: # noqa raise RuntimeError('BLiveClient and session has to use same event loop') self._heartbeat_interval = heartbeat_interval - # noinspection PyProtectedMember - self._ssl = ssl if ssl else ssl_._create_unverified_context() + self._ssl = ssl if ssl else ssl_._create_unverified_context() # noqa self._websocket = None self._heartbeat_timer_handle = None @@ -556,7 +312,8 @@ class BLiveClient: ) # 处理消息 - async for message in websocket: # type: aiohttp.WSMessage + message: aiohttp.WSMessage + async for message in websocket: retry_count = 0 if message.type != aiohttp.WSMsgType.BINARY: logger.warning('room %d 未知的websocket消息:type=%s %s', self.room_id, @@ -567,7 +324,7 @@ class BLiveClient: await self._handle_message(message.data) except asyncio.CancelledError: raise - except Exception: + except Exception: # noqa logger.exception('room %d 处理消息时发生错误:', self.room_id) except asyncio.CancelledError: @@ -659,31 +416,31 @@ class BLiveClient: """ pass - async def _on_receive_danmaku(self, danmaku: DanmakuMessage): + async def _on_receive_danmaku(self, danmaku: models.DanmakuMessage): """ 收到弹幕 """ pass - async def _on_receive_gift(self, gift: GiftMessage): + async def _on_receive_gift(self, gift: models.GiftMessage): """ 收到礼物 """ pass - async def _on_buy_guard(self, message: GuardBuyMessage): + async def _on_buy_guard(self, message: models.GuardBuyMessage): """ 有人上舰 """ pass - async def _on_super_chat(self, message: SuperChatMessage): + async def _on_super_chat(self, message: models.SuperChatMessage): """ 醒目留言 """ pass - async def _on_super_chat_delete(self, message: SuperChatDeleteMessage): + async def _on_super_chat_delete(self, message: models.SuperChatDeleteMessage): """ 删除醒目留言 """ diff --git a/blivedm/models.py b/blivedm/models.py new file mode 100644 index 0000000..ca20033 --- /dev/null +++ b/blivedm/models.py @@ -0,0 +1,417 @@ +# -*- coding: utf-8 -*- +from typing import * + +__all__ = ( + 'DanmakuMessage', + 'GiftMessage', + 'GuardBuyMessage', + 'SuperChatMessage', + 'SuperChatDeleteMessage', +) + + +class DanmakuMessage: + """ + 弹幕消息 + + :param mode: 弹幕显示模式(滚动、顶部、底部) + :param font_size: 字体尺寸 + :param color: 颜色 + :param timestamp: 时间戳(毫秒) + :param rnd: 随机数 + :param uid_crc32: 用户ID文本的CRC32 + :param msg_type: 是否礼物弹幕(节奏风暴) + :param bubble: 右侧评论栏气泡 + + :param msg: 弹幕内容 + + :param uid: 用户ID + :param uname: 用户名 + :param admin: 是否房管 + :param vip: 是否月费老爷 + :param svip: 是否年费老爷 + :param urank: 用户身份,用来判断是否正式会员,猜测非正式会员为5000,正式会员为10000 + :param mobile_verify: 是否绑定手机 + :param uname_color: 用户名颜色 + + :param medal_level: 勋章等级 + :param medal_name: 勋章名 + :param runame: 勋章房间主播名 + :param medal_room_id: 勋章房间ID + :param mcolor: 勋章颜色 + :param special_medal: 特殊勋章 + + :param user_level: 用户等级 + :param ulevel_color: 用户等级颜色 + :param ulevel_rank: 用户等级排名,>50000时为'>50000' + + :param old_title: 旧头衔 + :param title: 头衔 + + :param privilege_type: 舰队类型,0非舰队,1总督,2提督,3舰长 + """ + + def __init__( + self, + mode: int = None, + font_size: int = None, + color: int = None, + timestamp: int = None, + rnd: int = None, + uid_crc32: str = None, + msg_type: int = None, + bubble: int = None, + + msg: str = None, + + uid: int = None, + uname: str = None, + admin: int = None, + vip: int = None, + svip: int = None, + urank: int = None, + mobile_verify: int = None, + uname_color: str = None, + + medal_level: str = None, + medal_name: str = None, + runame: str = None, + medal_room_id: int = None, + mcolor: int = None, + special_medal: str = None, + + user_level: int = None, + ulevel_color: int = None, + ulevel_rank: str = None, + + old_title: str = None, + title: str = None, + + privilege_type: int = None, + ): + self.mode: int = mode + self.font_size: int = font_size + self.color: int = color + self.timestamp: int = timestamp + self.rnd: int = rnd + self.uid_crc32: str = uid_crc32 + self.msg_type: int = msg_type + self.bubble: int = bubble + + self.msg: str = msg + + self.uid: int = uid + self.uname: str = uname + self.admin: int = admin + self.vip: int = vip + self.svip: int = svip + self.urank: int = urank + self.mobile_verify: int = mobile_verify + self.uname_color: str = uname_color + + self.medal_level: str = medal_level + self.medal_name: str = medal_name + self.runame: str = runame + self.medal_room_id: int = medal_room_id + self.mcolor: int = mcolor + self.special_medal: str = special_medal + + self.user_level: int = user_level + self.ulevel_color: int = ulevel_color + self.ulevel_rank: str = ulevel_rank + + self.old_title: str = old_title + self.title: str = title + + self.privilege_type: int = privilege_type + + @classmethod + def from_command(cls, info: dict): + if len(info[3]) != 0: + medal_level = info[3][0] + medal_name = info[3][1] + runame = info[3][2] + room_id = info[3][3] + mcolor = info[3][4] + special_medal = info[3][5] + else: + medal_level = 0 + medal_name = '' + runame = '' + room_id = 0 + mcolor = 0 + special_medal = 0 + + return cls( + mode=info[0][1], + font_size=info[0][2], + color=info[0][3], + timestamp=info[0][4], + rnd=info[0][5], + uid_crc32=info[0][7], + msg_type=info[0][9], + bubble=info[0][10], + + msg=info[1], + + uid=info[2][0], + uname=info[2][1], + admin=info[2][2], + vip=info[2][3], + svip=info[2][4], + urank=info[2][5], + mobile_verify=info[2][6], + uname_color=info[2][7], + + medal_level=medal_level, + medal_name=medal_name, + runame=runame, + medal_room_id=room_id, + mcolor=mcolor, + special_medal=special_medal, + + user_level=info[4][0], + ulevel_color=info[4][2], + ulevel_rank=info[4][3], + + old_title=info[5][0], + title=info[5][1], + + privilege_type=info[7], + ) + + +class GiftMessage: + """ + 礼物消息 + + :param gift_name: 礼物名 + :param num: 数量 + :param uname: 用户名 + :param face: 用户头像URL + :param guard_level: 舰队等级,0非舰队,1总督,2提督,3舰长 + :param uid: 用户ID + :param timestamp: 时间戳 + :param gift_id: 礼物ID + :param gift_type: 礼物类型(未知) + :param action: 目前遇到的有'喂食'、'赠送' + :param price: 礼物单价瓜子数 + :param rnd: 随机数,估计是去重用的 + :param coin_type: 瓜子类型,'silver'或'gold' + :param total_coin: 总瓜子数 + """ + + def __init__( + self, + gift_name: str = None, + num: int = None, + uname: str = None, + face: str = None, + guard_level: int = None, + uid: int = None, + timestamp: int = None, + gift_id: int = None, + gift_type: int = None, + action: str = None, + price: int = None, + rnd: str = None, + coin_type: str = None, + total_coin: int = None, + ): + self.gift_name = gift_name + self.num = num + self.uname = uname + self.face = face + self.guard_level = guard_level + self.uid = uid + self.timestamp = timestamp + self.gift_id = gift_id + self.gift_type = gift_type + self.action = action + self.price = price + self.rnd = rnd + self.coin_type = coin_type + self.total_coin = total_coin + + @classmethod + def from_command(cls, data: dict): + return cls( + gift_name=data['giftName'], + num=data['num'], + uname=data['uname'], + face=data['face'], + guard_level=data['guard_level'], + uid=data['uid'], + timestamp=data['timestamp'], + gift_id=data['giftId'], + gift_type=data['giftType'], + action=data['action'], + price=data['price'], + rnd=data['rnd'], + coin_type=data['coin_type'], + total_coin=data['total_coin'], + ) + + +class GuardBuyMessage: + """ + 上舰消息 + + :param uid: 用户ID + :param username: 用户名 + :param guard_level: 舰队等级,0非舰队,1总督,2提督,3舰长 + :param num: 数量 + :param price: 单价金瓜子数 + :param gift_id: 礼物ID + :param gift_name: 礼物名 + :param start_time: 开始时间戳,和结束时间戳一样 + :param end_time: 结束时间戳,和开始时间戳一样 + """ + + def __init__( + self, + uid: int = None, + username: str = None, + guard_level: int = None, + num: int = None, + price: int = None, + gift_id: int = None, + gift_name: str = None, + start_time: int = None, + end_time: int = None, + ): + self.uid: int = uid + self.username: str = username + self.guard_level: int = guard_level + self.num: int = num + self.price: int = price + self.gift_id: int = gift_id + self.gift_name: str = gift_name + self.start_time: int = start_time + self.end_time: int = end_time + + @classmethod + def from_command(cls, data: dict): + return cls( + uid=data['uid'], + username=data['username'], + guard_level=data['guard_level'], + num=data['num'], + price=data['price'], + gift_id=data['gift_id'], + gift_name=data['gift_name'], + start_time=data['start_time'], + end_time=data['end_time'], + ) + + +class SuperChatMessage: + """ + 醒目留言消息 + + :param price: 价格(人民币) + :param message: 消息 + :param message_jpn: 消息日文翻译(目前只出现在SUPER_CHAT_MESSAGE_JPN) + :param start_time: 开始时间戳 + :param end_time: 结束时间戳 + :param time: 持续时间(结束时间戳 - 开始时间戳) + :param id_: str,醒目留言ID,删除时用 + :param gift_id: 礼物ID + :param gift_name: 礼物名 + :param uid: 用户ID + :param uname: 用户名 + :param face: 用户头像URL + :param guard_level: 舰队等级,0非舰队,1总督,2提督,3舰长 + :param user_level: 用户等级 + :param background_bottom_color: 底部背景色,'#rrggbb' + :param background_color: 背景色,'#rrggbb' + :param background_icon: 背景图标 + :param background_image: 背景图URL + :param background_price_color: 背景价格颜色,'#rrggbb' + """ + + def __init__( + self, + price: int = None, + message: str = None, + message_jpn: str = None, + start_time: int = None, + end_time: int = None, + time: int = None, + id_: int = None, + gift_id: int = None, + gift_name: str = None, + uid: int = None, + uname: str = None, + face: str = None, + guard_level: int = None, + user_level: int = None, + background_bottom_color: str = None, + background_color: str = None, + background_icon: str = None, + background_image: str = None, + background_price_color: str = None, + ): + self.price: int = price + self.message: str = message + self.message_jpn: str = message_jpn + self.start_time: int = start_time + self.end_time: int = end_time + self.time: int = time + self.id: int = id_ + self.gift_id: int = gift_id + self.gift_name: str = gift_name + self.uid: int = uid + self.uname: str = uname + self.face: str = face + self.guard_level: int = guard_level + self.user_level: int = user_level + self.background_bottom_color: str = background_bottom_color + self.background_color: str = background_color + self.background_icon: str = background_icon + self.background_image: str = background_image + self.background_price_color: str = background_price_color + + @classmethod + def from_command(cls, data: dict): + return cls( + price=data['price'], + message=data['message'], + message_jpn=data['message_trans'], + start_time=data['start_time'], + end_time=data['end_time'], + time=data['time'], + id_=data['id'], + gift_id=data['gift']['gift_id'], + gift_name=data['gift']['gift_name'], + uid=data['uid'], + uname=data['user_info']['uname'], + face=data['user_info']['face'], + guard_level=data['user_info']['guard_level'], + user_level=data['user_info']['user_level'], + background_bottom_color=data['background_bottom_color'], + background_color=data['background_color'], + background_icon=data['background_icon'], + background_image=data['background_image'], + background_price_color=data['background_price_color'], + ) + + +class SuperChatDeleteMessage: + """ + 删除醒目留言消息 + + :param ids: 醒目留言ID数组 + """ + + def __init__( + self, + ids: List[int] = None, + ): + self.ids: List[int] = ids + + @classmethod + def from_command(cls, data: dict): + return cls( + ids=data['ids'], + ) diff --git a/sample.py b/sample.py index 0b194c2..471e266 100644 --- a/sample.py +++ b/sample.py @@ -1,10 +1,24 @@ # -*- coding: utf-8 -*- - import asyncio import blivedm +async def main(): + # 直播间ID的取值看直播间URL + # 如果SSL验证失败就把ssl设为False,B站真的有过忘续证书的情况 + client = MyBLiveClient(room_id=21224291, ssl=True) + future = client.start() + try: + # 5秒后停止,测试用 + # await asyncio.sleep(5) + # future = client.stop() + + await future + finally: + await client.close() + + class MyBLiveClient(blivedm.BLiveClient): # 演示如何自定义handler _COMMAND_HANDLERS = blivedm.BLiveClient._COMMAND_HANDLERS.copy() @@ -29,20 +43,5 @@ class MyBLiveClient(blivedm.BLiveClient): print(f'醒目留言 ¥{message.price} {message.uname}:{message.message}') -async def main(): - # 直播间ID的取值看直播间URL - # 如果SSL验证失败就把ssl设为False,B站真的有过忘续证书的情况 - client = MyBLiveClient(room_id=21449083, ssl=True) - future = client.start() - try: - # 5秒后停止,测试用 - # await asyncio.sleep(5) - # future = client.stop() - - await future - finally: - await client.close() - - if __name__ == '__main__': asyncio.get_event_loop().run_until_complete(main())