forked from wbt5/real-url
-
Notifications
You must be signed in to change notification settings - Fork 0
/
douyu.py
137 lines (115 loc) · 4.67 KB
/
douyu.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# 获取斗鱼直播间的真实流媒体地址,默认最高画质
# 使用 https://github.com/wbt5/real-url/issues/185 中两位大佬@wjxgzz @4bbu6j5885o3gpv6ss8找到的的CDN,在此感谢!
import hashlib
import re
import time
import execjs
import requests
class DouYu:
"""
可用来替换返回链接中的主机部分
两个阿里的CDN:
dyscdnali1.douyucdn.cn
dyscdnali3.douyucdn.cn
墙外不用带尾巴的akm cdn:
hls3-akm.douyucdn.cn
hlsa-akm.douyucdn.cn
hls1a-akm.douyucdn.cn
"""
def __init__(self, rid):
"""
房间号通常为1~8位纯数字,浏览器地址栏中看到的房间号不一定是真实rid.
Args:
rid:
"""
self.did = '10000000000000000000000000001501'
self.t10 = str(int(time.time()))
self.t13 = str(int((time.time() * 1000)))
self.s = requests.Session()
self.res = self.s.get('https://m.douyu.com/' + str(rid)).text
result = re.search(r'rid":(\d{1,8}),"vipId', self.res)
if result:
self.rid = result.group(1)
else:
raise Exception('房间号错误')
@staticmethod
def md5(data):
return hashlib.md5(data.encode('utf-8')).hexdigest()
def get_pre(self):
url = 'https://playweb.douyucdn.cn/lapi/live/hlsH5Preview/' + self.rid
data = {
'rid': self.rid,
'did': self.did
}
auth = DouYu.md5(self.rid + self.t13)
headers = {
'rid': self.rid,
'time': self.t13,
'auth': auth
}
res = self.s.post(url, headers=headers, data=data).json()
error = res['error']
data = res['data']
key = ''
if data:
rtmp_live = data['rtmp_live']
key = re.search(r'(\d{1,8}[0-9a-zA-Z]+)_?\d{0,4}(/playlist|.m3u8)', rtmp_live).group(1)
return error, key
def get_js(self):
result = re.search(r'(function ub98484234.*)\s(var.*)', self.res).group()
func_ub9 = re.sub(r'eval.*;}', 'strc;}', result)
js = execjs.compile(func_ub9)
res = js.call('ub98484234')
v = re.search(r'v=(\d+)', res).group(1)
rb = DouYu.md5(self.rid + self.did + self.t10 + v)
func_sign = re.sub(r'return rt;}\);?', 'return rt;}', res)
func_sign = func_sign.replace('(function (', 'function sign(')
func_sign = func_sign.replace('CryptoJS.MD5(cb).toString()', '"' + rb + '"')
js = execjs.compile(func_sign)
params = js.call('sign', self.rid, self.did, self.t10)
params += '&ver=219032101&rid={}&rate=-1'.format(self.rid)
url = 'https://m.douyu.com/api/room/ratestream'
res = self.s.post(url, params=params).text
key = re.search(r'(\d{1,8}[0-9a-zA-Z]+)_?\d{0,4}(.m3u8|/playlist)', res).group(1)
return key
def get_pc_js(self, cdn='ws-h5', rate=0):
"""
通过PC网页端的接口获取完整直播源。
:param cdn: 主线路ws-h5、备用线路tct-h5
:param rate: 1流畅;2高清;3超清;4蓝光4M;0蓝光8M或10M
:return: JSON格式
"""
res = self.s.get('https://www.douyu.com/' + str(self.rid)).text
result = re.search(r'(vdwdae325w_64we[\s\S]*function ub98484234[\s\S]*?)function', res).group(1)
func_ub9 = re.sub(r'eval.*?;}', 'strc;}', result)
js = execjs.compile(func_ub9)
res = js.call('ub98484234')
v = re.search(r'v=(\d+)', res).group(1)
rb = DouYu.md5(self.rid + self.did + self.t10 + v)
func_sign = re.sub(r'return rt;}\);?', 'return rt;}', res)
func_sign = func_sign.replace('(function (', 'function sign(')
func_sign = func_sign.replace('CryptoJS.MD5(cb).toString()', '"' + rb + '"')
js = execjs.compile(func_sign)
params = js.call('sign', self.rid, self.did, self.t10)
params += '&cdn={}&rate={}'.format(cdn, rate)
url = 'https://www.douyu.com/lapi/live/getH5Play/{}'.format(self.rid)
res = self.s.post(url, params=params).json()
return res
def get_real_url(self):
error, key = self.get_pre()
if error == 0:
pass
elif error == 102:
raise Exception('房间不存在')
elif error == 104:
raise Exception('房间未开播')
else:
key = self.get_js()
real_url = {}
real_url["flv"] = "http://dyscdnali1.douyucdn.cn/live/{}.flv?uuid=".format(key)
real_url["x-p2p"] = "http://tx2play1.douyucdn.cn/live/{}.xs?uuid=".format(key)
return real_url
if __name__ == '__main__':
r = input('输入斗鱼直播间号:\n')
s = DouYu(r)
print(s.get_real_url())