mirror of
https://github.com/wbt5/real-url.git
synced 2025-07-29 21:00:30 +08:00
新增酷狗直播弹幕
This commit is contained in:
parent
155c47a67a
commit
071a83cd3a
229
danmu/danmaku/kugou.py
Normal file
229
danmu/danmaku/kugou.py
Normal file
@ -0,0 +1,229 @@
|
||||
from . import kugou_pb2 as pb
|
||||
import struct
|
||||
import requests
|
||||
|
||||
|
||||
class InitKugou:
|
||||
|
||||
def __init__(self):
|
||||
self.MAGIC = {
|
||||
'index': 0,
|
||||
'length': 1,
|
||||
'value': 100
|
||||
}
|
||||
self.VERSION = {
|
||||
'index': 1,
|
||||
'length': 2,
|
||||
'value': 1
|
||||
}
|
||||
self.TYPE = {
|
||||
'index': 2,
|
||||
'length': 1,
|
||||
'value': 1
|
||||
}
|
||||
self.HEADER = {
|
||||
'index': 3,
|
||||
'length': 2,
|
||||
'value': 12
|
||||
}
|
||||
self.CMD = {
|
||||
'index': 4,
|
||||
'length': 4,
|
||||
'value': 0
|
||||
}
|
||||
self.PAYLOAD = {
|
||||
'index': 5,
|
||||
'length': 4,
|
||||
'value': 0
|
||||
}
|
||||
self.ATTR = {
|
||||
'index': 6,
|
||||
'length': 1,
|
||||
'value': 0
|
||||
}
|
||||
self.CRC = {
|
||||
'index': 7,
|
||||
'length': 2,
|
||||
'value': 0
|
||||
}
|
||||
self.SKIP = {
|
||||
'index': 8,
|
||||
'length': 1,
|
||||
'value': 0
|
||||
}
|
||||
|
||||
self.f = [self.MAGIC, self.VERSION, self.TYPE, self.HEADER,
|
||||
self.CMD, self.PAYLOAD, self.ATTR, self.CRC, self.SKIP]
|
||||
|
||||
def reg(self, rid):
|
||||
url = 'https://fx2.service.kugou.com/socket_scheduler/pc/v2/address.jsonp'
|
||||
payload = {
|
||||
'rid': rid,
|
||||
'_v': '7.0.0',
|
||||
'_p': 0,
|
||||
'pv': 20191231,
|
||||
'at': 102,
|
||||
'cid': 105
|
||||
}
|
||||
|
||||
with requests.Session() as s:
|
||||
r = s.get(url, params=payload).json()
|
||||
soctoken = r['data']['soctoken']
|
||||
|
||||
reg_data = {
|
||||
'appid': 1010,
|
||||
'clientid': 105,
|
||||
'cmd': 201,
|
||||
'deviceNo': '4edc0e89-ccaf-452c-bce4-00f4cb6bb5bb',
|
||||
'kugouid': 0,
|
||||
'platid': 18,
|
||||
'referer': 0,
|
||||
'roomid': rid,
|
||||
'sid': '8b9b79a7-a742-4397-fcc0-94efa3a1c920',
|
||||
'soctoken': soctoken,
|
||||
'v': 20191231
|
||||
}
|
||||
|
||||
a = pb.LoginRequest()
|
||||
for k, v in reg_data.items():
|
||||
setattr(a, k, v)
|
||||
b = pb.Message()
|
||||
b.content = a.SerializeToString()
|
||||
e = b.SerializeToString()
|
||||
reg = self.encode_(e, reg_data['cmd'])
|
||||
return reg
|
||||
|
||||
def g(self, *e):
|
||||
if len(e) > 1 and e[1]:
|
||||
t = e[1]
|
||||
else:
|
||||
t = 12
|
||||
n = 0
|
||||
i = 0
|
||||
e = e[0]
|
||||
while i < e and i < len(self.f):
|
||||
n += self.f[i]['length']
|
||||
i += 1
|
||||
if e == len(self.f):
|
||||
return n + t - 12
|
||||
else:
|
||||
return n
|
||||
|
||||
def encode_(self, e, t):
|
||||
n = len(self.f)
|
||||
i = len(e)
|
||||
# r = self.g(n) + i
|
||||
self.PAYLOAD['value'] = i
|
||||
self.CMD['value'] = t
|
||||
|
||||
buf = b''
|
||||
for s in self.f:
|
||||
# offset = self.g(s['index'])
|
||||
value = s['value']
|
||||
if s['length'] == 1:
|
||||
fmt = '!b'
|
||||
elif s['length'] == 2:
|
||||
fmt = '!h'
|
||||
else:
|
||||
fmt = '!i'
|
||||
buf += struct.pack(fmt, value)
|
||||
|
||||
buf += struct.pack('!i', i)
|
||||
buf = buf[:self.g(n)] + e
|
||||
return buf
|
||||
|
||||
def v(self, e, t):
|
||||
if t['length'] == 1:
|
||||
fmt = '!b'
|
||||
elif t['length'] == 2:
|
||||
fmt = '!h'
|
||||
else:
|
||||
fmt = '!i'
|
||||
r, = struct.unpack_from(fmt, e, self.g(t['index']))
|
||||
return r
|
||||
|
||||
# def k(self, e, i, o=False):
|
||||
# if i == 1:
|
||||
# a = zlib.decompress(e)
|
||||
# elif i == 2:
|
||||
# a = zlib.decompress(e)
|
||||
# else:
|
||||
# a = e
|
||||
# if o:
|
||||
# return self.r(a)
|
||||
# else:
|
||||
# return a
|
||||
#
|
||||
# def r(self, e):
|
||||
# pass
|
||||
|
||||
def decode_(self, message):
|
||||
t = len(message)
|
||||
n = len(self.f)
|
||||
|
||||
if t <= 0:
|
||||
return {}
|
||||
|
||||
if self.v(message, self.TYPE) == 0:
|
||||
return {}
|
||||
|
||||
r = self.v(message, self.HEADER)
|
||||
cmd = self.v(message, self.CMD) # cmd
|
||||
a = self.g(n, r)
|
||||
|
||||
if t < a:
|
||||
return {}
|
||||
|
||||
o = message[a:] # payloadBuffer
|
||||
|
||||
if not o or not cmd:
|
||||
return
|
||||
|
||||
msgs = []
|
||||
msg = {'name': '', 'content': '', 'msg_type': 'other'}
|
||||
if cmd == 201 or cmd == 501:
|
||||
# CMD
|
||||
# 201:LoginResponse,欢迎信息;
|
||||
# 501:ChatResponse,聊天信息;
|
||||
# 602:ContentMessage,礼物信息;
|
||||
# 901:ErrorResponse;
|
||||
s = pb.Message()
|
||||
s.ParseFromString(o)
|
||||
if s.codec == 1:
|
||||
# if s.compression:
|
||||
# s.content = self.k(s.content, s.compression)
|
||||
s1 = pb.ContentMessage()
|
||||
s1.ParseFromString(s.content)
|
||||
if s1.codec == 1:
|
||||
# if hasattr(s1, 'compression'):
|
||||
# s1.content = self.k(s1.content, s1.compression)
|
||||
s2 = pb.ChatResponse()
|
||||
s2.ParseFromString(s1.content)
|
||||
if cmd == 201:
|
||||
msg['name'] = 'SYS'
|
||||
msg['content'] = s2.receivername.replace('%nick', s2.chatmsg)
|
||||
msg['msg_type'] = 'danmaku'
|
||||
elif cmd == 501:
|
||||
msg['name'] = s2.sendername
|
||||
msg['content'] = s2.chatmsg
|
||||
msg['msg_type'] = 'danmaku'
|
||||
msgs.append(msg.copy())
|
||||
return msgs
|
||||
|
||||
|
||||
class KuGou:
|
||||
heartbeat = b'\x64\x00\x01\x00'
|
||||
wss_url = 'wss://chat1wss.kugou.com/acksocket'
|
||||
heartbeatInterval = 10
|
||||
s = InitKugou()
|
||||
|
||||
@staticmethod
|
||||
async def get_ws_info(url):
|
||||
rid = url.split('/')[-1]
|
||||
reg_data = KuGou.s.reg(int(rid))
|
||||
return KuGou.wss_url, [reg_data]
|
||||
|
||||
@staticmethod
|
||||
def decode_msg(data):
|
||||
msgs = KuGou.s.decode_(data)
|
||||
return msgs
|
Loading…
x
Reference in New Issue
Block a user