支持自动获取UID、添加使用已登录账号连接的演示
This commit is contained in:
parent
28645d5e37
commit
d55f001c67
@ -9,6 +9,7 @@ from typing import *
|
|||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import brotli
|
import brotli
|
||||||
|
import yarl
|
||||||
|
|
||||||
from . import handlers
|
from . import handlers
|
||||||
|
|
||||||
@ -18,6 +19,12 @@ __all__ = (
|
|||||||
|
|
||||||
logger = logging.getLogger('blivedm')
|
logger = logging.getLogger('blivedm')
|
||||||
|
|
||||||
|
USER_AGENT = (
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'
|
||||||
|
)
|
||||||
|
|
||||||
|
UID_INIT_URL = 'https://api.bilibili.com/x/web-interface/nav'
|
||||||
|
BUVID_INIT_URL = 'https://data.bilibili.com/v/'
|
||||||
ROOM_INIT_URL = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom'
|
ROOM_INIT_URL = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom'
|
||||||
DANMAKU_SERVER_CONF_URL = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo'
|
DANMAKU_SERVER_CONF_URL = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo'
|
||||||
DEFAULT_DANMAKU_SERVER_LIST = [
|
DEFAULT_DANMAKU_SERVER_LIST = [
|
||||||
@ -87,7 +94,7 @@ class BLiveClient:
|
|||||||
B站直播弹幕客户端,负责连接房间
|
B站直播弹幕客户端,负责连接房间
|
||||||
|
|
||||||
:param room_id: URL中的房间ID,可以用短ID
|
:param room_id: URL中的房间ID,可以用短ID
|
||||||
:param uid: B站用户ID,0表示未登录
|
:param uid: B站用户ID,0表示未登录,None表示自动获取
|
||||||
:param session: cookie、连接池
|
:param session: cookie、连接池
|
||||||
:param heartbeat_interval: 发送心跳包的间隔时间(秒)
|
:param heartbeat_interval: 发送心跳包的间隔时间(秒)
|
||||||
:param ssl: True表示用默认的SSLContext验证,False表示不验证,也可以传入SSLContext
|
:param ssl: True表示用默认的SSLContext验证,False表示不验证,也可以传入SSLContext
|
||||||
@ -96,7 +103,7 @@ class BLiveClient:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
room_id,
|
room_id,
|
||||||
uid=0,
|
uid=None,
|
||||||
session: Optional[aiohttp.ClientSession] = None,
|
session: Optional[aiohttp.ClientSession] = None,
|
||||||
heartbeat_interval=30,
|
heartbeat_interval=30,
|
||||||
ssl: Union[bool, ssl_.SSLContext] = True,
|
ssl: Union[bool, ssl_.SSLContext] = True,
|
||||||
@ -170,6 +177,13 @@ class BLiveClient:
|
|||||||
"""
|
"""
|
||||||
return self._room_owner_uid
|
return self._room_owner_uid
|
||||||
|
|
||||||
|
@property
|
||||||
|
def uid(self) -> Optional[int]:
|
||||||
|
"""
|
||||||
|
当前登录的用户ID,未登录则为0,调用init_room后初始化
|
||||||
|
"""
|
||||||
|
return self._uid
|
||||||
|
|
||||||
def add_handler(self, handler: 'handlers.HandlerInterface'):
|
def add_handler(self, handler: 'handlers.HandlerInterface'):
|
||||||
"""
|
"""
|
||||||
添加消息处理器
|
添加消息处理器
|
||||||
@ -248,6 +262,15 @@ class BLiveClient:
|
|||||||
|
|
||||||
:return: True代表没有降级,如果需要降级后还可用,重载这个函数返回True
|
:return: True代表没有降级,如果需要降级后还可用,重载这个函数返回True
|
||||||
"""
|
"""
|
||||||
|
if self._uid is None:
|
||||||
|
if not await self._init_uid():
|
||||||
|
logger.warning('room=%d _init_uid() failed', self._tmp_room_id)
|
||||||
|
self._uid = 0
|
||||||
|
|
||||||
|
if self._get_buvid() == '':
|
||||||
|
if not await self._init_buvid():
|
||||||
|
logger.warning('room=%d _init_buvid() failed', self._tmp_room_id)
|
||||||
|
|
||||||
res = True
|
res = True
|
||||||
if not await self._init_room_id_and_owner():
|
if not await self._init_room_id_and_owner():
|
||||||
res = False
|
res = False
|
||||||
@ -262,14 +285,64 @@ class BLiveClient:
|
|||||||
self._host_server_token = None
|
self._host_server_token = None
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
async def _init_uid(self):
|
||||||
|
try:
|
||||||
|
async with self._session.get(
|
||||||
|
UID_INIT_URL,
|
||||||
|
headers={'User-Agent': USER_AGENT},
|
||||||
|
ssl=self._ssl
|
||||||
|
) as res:
|
||||||
|
if res.status != 200:
|
||||||
|
logger.warning('room=%d _init_uid() failed, status=%d, reason=%s', self._tmp_room_id,
|
||||||
|
res.status, res.reason)
|
||||||
|
return False
|
||||||
|
data = await res.json()
|
||||||
|
if data['code'] != 0:
|
||||||
|
if data['code'] == -101:
|
||||||
|
# 未登录
|
||||||
|
self._uid = 0
|
||||||
|
return True
|
||||||
|
logger.warning('room=%d _init_uid() failed, message=%s', self._tmp_room_id,
|
||||||
|
data['message'])
|
||||||
|
return False
|
||||||
|
|
||||||
|
data = data['data']
|
||||||
|
if not data['isLogin']:
|
||||||
|
# 未登录
|
||||||
|
self._uid = 0
|
||||||
|
else:
|
||||||
|
self._uid = data['mid']
|
||||||
|
return True
|
||||||
|
except (aiohttp.ClientConnectionError, asyncio.TimeoutError):
|
||||||
|
logger.exception('room=%d _init_uid() failed:', self._tmp_room_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _get_buvid(self):
|
||||||
|
cookies = self._session.cookie_jar.filter_cookies(yarl.URL(BUVID_INIT_URL))
|
||||||
|
buvid_cookie = cookies.get('buvid3', None)
|
||||||
|
if buvid_cookie is None:
|
||||||
|
return ''
|
||||||
|
return buvid_cookie.value
|
||||||
|
|
||||||
|
async def _init_buvid(self):
|
||||||
|
try:
|
||||||
|
async with self._session.get(
|
||||||
|
BUVID_INIT_URL,
|
||||||
|
headers={'User-Agent': USER_AGENT},
|
||||||
|
ssl=self._ssl
|
||||||
|
) as res:
|
||||||
|
if res.status != 200:
|
||||||
|
logger.warning('room=%d _init_buvid() status error, status=%d, reason=%s',
|
||||||
|
self._tmp_room_id, res.status, res.reason)
|
||||||
|
except (aiohttp.ClientConnectionError, asyncio.TimeoutError):
|
||||||
|
logger.exception('room=%d _init_buvid() exception:', self._tmp_room_id)
|
||||||
|
return self._get_buvid() != ''
|
||||||
|
|
||||||
async def _init_room_id_and_owner(self):
|
async def _init_room_id_and_owner(self):
|
||||||
try:
|
try:
|
||||||
async with self._session.get(
|
async with self._session.get(
|
||||||
ROOM_INIT_URL,
|
ROOM_INIT_URL,
|
||||||
headers={
|
headers={'User-Agent': USER_AGENT},
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
|
|
||||||
' Chrome/102.0.0.0 Safari/537.36'
|
|
||||||
},
|
|
||||||
params={
|
params={
|
||||||
'room_id': self._tmp_room_id
|
'room_id': self._tmp_room_id
|
||||||
},
|
},
|
||||||
@ -302,10 +375,7 @@ class BLiveClient:
|
|||||||
try:
|
try:
|
||||||
async with self._session.get(
|
async with self._session.get(
|
||||||
DANMAKU_SERVER_CONF_URL,
|
DANMAKU_SERVER_CONF_URL,
|
||||||
headers={
|
headers={'User-Agent': USER_AGENT},
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
|
|
||||||
' Chrome/102.0.0.0 Safari/537.36'
|
|
||||||
},
|
|
||||||
params={
|
params={
|
||||||
'id': self._room_id,
|
'id': self._room_id,
|
||||||
'type': 0
|
'type': 0
|
||||||
@ -385,10 +455,7 @@ class BLiveClient:
|
|||||||
host_server = self._host_server_list[retry_count % len(self._host_server_list)]
|
host_server = self._host_server_list[retry_count % len(self._host_server_list)]
|
||||||
async with self._session.ws_connect(
|
async with self._session.ws_connect(
|
||||||
f"wss://{host_server['host']}:{host_server['wss_port']}/sub",
|
f"wss://{host_server['host']}:{host_server['wss_port']}/sub",
|
||||||
headers={
|
headers={'User-Agent': USER_AGENT},
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
|
|
||||||
' Chrome/102.0.0.0 Safari/537.36'
|
|
||||||
},
|
|
||||||
receive_timeout=self._heartbeat_interval + 5,
|
receive_timeout=self._heartbeat_interval + 5,
|
||||||
ssl=self._ssl
|
ssl=self._ssl
|
||||||
) as websocket:
|
) as websocket:
|
||||||
@ -444,11 +511,12 @@ class BLiveClient:
|
|||||||
发送认证包
|
发送认证包
|
||||||
"""
|
"""
|
||||||
auth_params = {
|
auth_params = {
|
||||||
'uid': self._uid or self.room_owner_uid or 0,
|
'uid': self._uid,
|
||||||
'roomid': self._room_id,
|
'roomid': self._room_id,
|
||||||
'protover': 3,
|
'protover': 3,
|
||||||
'platform': 'web',
|
'platform': 'web',
|
||||||
'type': 2
|
'type': 2,
|
||||||
|
'buvid': self._get_buvid(),
|
||||||
}
|
}
|
||||||
if self._host_server_token is not None:
|
if self._host_server_token is not None:
|
||||||
auth_params['key'] = self._host_server_token
|
auth_params['key'] = self._host_server_token
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
aiohttp==3.8.5
|
aiohttp==3.8.5
|
||||||
Brotli==1.0.9
|
Brotli==1.0.9
|
||||||
pure-protobuf==3.0.0a5
|
pure-protobuf==3.0.0a5
|
||||||
|
yarl==1.8.2
|
||||||
|
22
sample.py
22
sample.py
@ -1,7 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import http.cookies
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
import blivedm
|
import blivedm
|
||||||
|
|
||||||
# 直播间ID的取值看直播间URL
|
# 直播间ID的取值看直播间URL
|
||||||
@ -13,19 +16,34 @@ TEST_ROOM_IDS = [
|
|||||||
23105590,
|
23105590,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
session = None
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
init_session()
|
||||||
|
|
||||||
await run_single_client()
|
await run_single_client()
|
||||||
await run_multi_clients()
|
await run_multi_clients()
|
||||||
|
|
||||||
|
|
||||||
|
def init_session():
|
||||||
|
# 这里填一个已登录账号的cookie。不填cookie也可以连接,但是收到弹幕的用户名会打码,UID会变成0
|
||||||
|
cookies = http.cookies.SimpleCookie()
|
||||||
|
cookies['SESSDATA'] = ''
|
||||||
|
cookies['SESSDATA']['domain'] = 'bilibili.com'
|
||||||
|
|
||||||
|
global session
|
||||||
|
session = aiohttp.ClientSession()
|
||||||
|
session.cookie_jar.update_cookies(cookies)
|
||||||
|
|
||||||
|
|
||||||
async def run_single_client():
|
async def run_single_client():
|
||||||
"""
|
"""
|
||||||
演示监听一个直播间
|
演示监听一个直播间
|
||||||
"""
|
"""
|
||||||
room_id = random.choice(TEST_ROOM_IDS)
|
room_id = random.choice(TEST_ROOM_IDS)
|
||||||
# 如果SSL验证失败就把ssl设为False,B站真的有过忘续证书的情况
|
# 如果SSL验证失败就把ssl设为False,B站真的有过忘续证书的情况
|
||||||
client = blivedm.BLiveClient(room_id, ssl=True)
|
client = blivedm.BLiveClient(room_id, session=session, ssl=True)
|
||||||
handler = MyHandler()
|
handler = MyHandler()
|
||||||
client.add_handler(handler)
|
client.add_handler(handler)
|
||||||
|
|
||||||
@ -44,7 +62,7 @@ async def run_multi_clients():
|
|||||||
"""
|
"""
|
||||||
演示同时监听多个直播间
|
演示同时监听多个直播间
|
||||||
"""
|
"""
|
||||||
clients = [blivedm.BLiveClient(room_id) for room_id in TEST_ROOM_IDS]
|
clients = [blivedm.BLiveClient(room_id, session=session) for room_id in TEST_ROOM_IDS]
|
||||||
handler = MyHandler()
|
handler = MyHandler()
|
||||||
for client in clients:
|
for client in clients:
|
||||||
client.add_handler(handler)
|
client.add_handler(handler)
|
||||||
|
Loading…
Reference in New Issue
Block a user