mirror of
https://github.com/wbt5/real-url.git
synced 2025-07-30 21:32:14 +08:00
Compare commits
No commits in common. "cab036f982ba947bfee2427cb0c1d71db4935c69" and "9a9828fc2345766c262666e0efe09eadca256cb6" have entirely different histories.
cab036f982
...
9a9828fc23
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
目前已实现:
|
目前已实现:
|
||||||
|
|
||||||
**59** 个直播平台的直播源获取:斗鱼直播、虎牙直播、哔哩哔哩直播、战旗直播、网易 CC 直播、火猫直播、企鹅电竞、YY 直播、一直播、快手直播、花椒直播、映客直播、西瓜直播、触手直播(已倒闭)、NOW 直播、抖音直播,爱奇艺直播、酷狗直播、龙珠直播、PPS 奇秀直播、六间房、17 直播、来疯直播、优酷轮播台、网易 LOOK 直播、千帆直播、陌陌直播、小米直播、迅雷直播、京东直播、企鹅体育、人人直播、棉花糖直播、九秀直播、羚萌直播、95秀、新浪疯播、红人直播、艾米直播、KK直播、酷我聚星、乐嗨直播、秀色直播、星光直播、我秀直播、热猫直播、艺气山直播、AcFun 直播、猫耳FM、畅秀阁、Twitch、TikTok、央视频、PP体育、zhibotv、腾讯体育直播、爱奇艺体育直播、liveU、bigolive、咪咕视频体育。
|
**58** 个直播平台的直播源获取:斗鱼直播、虎牙直播、哔哩哔哩直播、战旗直播、网易 CC 直播、火猫直播、企鹅电竞、YY 直播、一直播、快手直播、花椒直播、映客直播、西瓜直播、触手直播(已倒闭)、NOW 直播、抖音直播,爱奇艺直播、酷狗直播、龙珠直播、PPS 奇秀直播、六间房、17 直播、来疯直播、优酷轮播台、网易 LOOK 直播、千帆直播、陌陌直播、小米直播、迅雷直播、京东直播、企鹅体育、人人直播、棉花糖直播、九秀直播、羚萌直播、95秀、新浪疯播、红人直播、艾米直播、KK直播、酷我聚星、乐嗨直播、秀色直播、星光直播、我秀直播、热猫直播、艺气山直播、AcFun 直播、猫耳FM、畅秀阁、Twitch、TikTok、央视频、PP体育、zhibotv、腾讯体育直播、爱奇艺体育直播、liveU、bigolive。
|
||||||
|
|
||||||
**18** 个直播平台的弹幕获取:斗鱼直播、虎牙直播、哔哩哔哩直播、快手直播、火猫直播、企鹅电竞、花椒直播、映客直播、网易 CC 直播、酷狗直播、龙珠直播、PPS 奇秀、搜狐千帆、战旗直播、来疯直播、网易 LOOK 直播、AcFun 直播、艺气山直播。
|
**18** 个直播平台的弹幕获取:斗鱼直播、虎牙直播、哔哩哔哩直播、快手直播、火猫直播、企鹅电竞、花椒直播、映客直播、网易 CC 直播、酷狗直播、龙珠直播、PPS 奇秀、搜狐千帆、战旗直播、来疯直播、网易 LOOK 直播、AcFun 直播、艺气山直播。
|
||||||
|
|
||||||
@ -26,8 +26,6 @@
|
|||||||
有直播平台失效或新增其他平台解析的,可发 [issue](https://github.com/wbt5/real-url/issues/new)。
|
有直播平台失效或新增其他平台解析的,可发 [issue](https://github.com/wbt5/real-url/issues/new)。
|
||||||
|
|
||||||
## 更新
|
## 更新
|
||||||
2021.11.7::sparkles:新增咪咕体育。
|
|
||||||
|
|
||||||
2021.8.15::sparkles:新增 liveU、bigolive。
|
2021.8.15::sparkles:新增 liveU、bigolive。
|
||||||
|
|
||||||
2021.7.4::art:更新哔哩哔哩直播源;:bug:修复Acfun直播弹幕;:bug:修复企鹅电竞弹幕。
|
2021.7.4::art:更新哔哩哔哩直播源;:bug:修复Acfun直播弹幕;:bug:修复企鹅电竞弹幕。
|
||||||
|
98
huya.py
98
huya.py
@ -1,4 +1,5 @@
|
|||||||
# 获取虎牙直播的真实流媒体地址。
|
# 获取虎牙直播的真实流媒体地址。
|
||||||
|
# 虎牙"一起看"频道的直播间可能会卡顿,尝试将返回地址 tx.hls.huya.com 中的 tx 改为 bd、migu-bd。
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
@ -6,52 +7,61 @@ import base64
|
|||||||
import urllib.parse
|
import urllib.parse
|
||||||
import hashlib
|
import hashlib
|
||||||
import time
|
import time
|
||||||
|
import json
|
||||||
def live(e):
|
|
||||||
i, b = e.split('?')
|
|
||||||
r = i.split('/')
|
|
||||||
s = re.sub(r'.(flv|m3u8)', '', r[-1])
|
|
||||||
c = b.split('&', 3)
|
|
||||||
c = [i for i in c if i != '']
|
|
||||||
n = {i.split('=')[0]: i.split('=')[1] for i in c}
|
|
||||||
fm = urllib.parse.unquote(n['fm'])
|
|
||||||
u = base64.b64decode(fm).decode('utf-8')
|
|
||||||
p = u.split('_')[0]
|
|
||||||
f = str(int(time.time() * 1e7))
|
|
||||||
l = n['wsTime']
|
|
||||||
t = '0'
|
|
||||||
h = '_'.join([p, t, s, f, l])
|
|
||||||
m = hashlib.md5(h.encode('utf-8')).hexdigest()
|
|
||||||
y = c[-1]
|
|
||||||
url = "{}?wsSecret={}&wsTime={}&u={}&seqid={}&{}".format(i, m, l, t, f, y)
|
|
||||||
return url
|
|
||||||
|
|
||||||
|
|
||||||
def get_real_url(room_id):
|
class HuYa:
|
||||||
try:
|
|
||||||
room_url = 'https://m.huya.com/' + str(room_id)
|
def __init__(self, rid):
|
||||||
header = {
|
self.rid = rid
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) '
|
def get_real_url(self):
|
||||||
'Chrome/75.0.3770.100 Mobile Safari/537.36 '
|
try:
|
||||||
}
|
room_url = 'https://m.huya.com/' + str(self.rid)
|
||||||
response = requests.get(url=room_url, headers=header).text
|
header = {
|
||||||
liveLineUrl = re.findall(r'"liveLineUrl":"([\s\S]*?)",', response)[0]
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
liveline = base64.b64decode(liveLineUrl).decode('utf-8')
|
'User-Agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 '
|
||||||
if liveline:
|
'(KHTML, like Gecko) Chrome/75.0.3770.100 Mobile Safari/537.36 '
|
||||||
if 'replay' in liveline:
|
}
|
||||||
return '直播录像:' + liveline
|
response = requests.get(url=room_url, headers=header).text
|
||||||
|
info = json.loads(re.findall(r"<script> window.HNF_GLOBAL_INIT = (.*)</script>", response)[0])
|
||||||
|
if info == {'exceptionType': 0}:
|
||||||
|
raise Exception('房间不存在')
|
||||||
|
roomInfo = info["roomInfo"]
|
||||||
|
real_url = {}
|
||||||
|
|
||||||
|
# not live
|
||||||
|
if roomInfo["eLiveStatus"] == 1:
|
||||||
|
raise Exception('未开播')
|
||||||
|
|
||||||
|
# live
|
||||||
|
elif roomInfo["eLiveStatus"] == 2:
|
||||||
|
streamInfos = roomInfo["tLiveInfo"]["tLiveStreamInfo"]["vStreamInfo"]["value"]
|
||||||
|
for streamInfo in streamInfos:
|
||||||
|
real_url[streamInfo["sCdnType"].lower() + "_flv"] = streamInfo["sFlvUrl"] + "/" + streamInfo["sStreamName"] + "." + \
|
||||||
|
streamInfo["sFlvUrlSuffix"] + "?" + streamInfo["sFlvAntiCode"]
|
||||||
|
real_url[streamInfo["sCdnType"].lower() + "_hls"] = streamInfo["sHlsUrl"] + "/" + streamInfo["sStreamName"] + "." + \
|
||||||
|
streamInfo["sHlsUrlSuffix"] + "?" + streamInfo["sHlsAntiCode"]
|
||||||
|
|
||||||
|
# replay
|
||||||
|
elif roomInfo["eLiveStatus"] == 3:
|
||||||
|
real_url["replay"] = roomInfo["tReplayInfo"]["tReplayVideoInfo"]["sUrl"]
|
||||||
else:
|
else:
|
||||||
liveline = live(liveline)
|
raise Exception('未知错误')
|
||||||
real_url = ("https:" + liveline).replace("hls", "flv").replace("m3u8", "flv")
|
except Exception as e:
|
||||||
else:
|
raise Exception(e)
|
||||||
real_url = '未开播或直播间不存在'
|
return real_url
|
||||||
except:
|
|
||||||
real_url = '未开播或直播间不存在'
|
|
||||||
return real_url
|
|
||||||
|
|
||||||
|
|
||||||
rid = input('输入虎牙直播房间号:\n')
|
def get_real_url(rid):
|
||||||
real_url = get_real_url(rid)
|
try:
|
||||||
print('该直播间源地址为:')
|
hy = HuYa(rid)
|
||||||
print(real_url)
|
return hy.get_real_url()
|
||||||
|
except Exception as e:
|
||||||
|
print('Exception:', e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
rid = input('输入虎牙直播房间号:\n')
|
||||||
|
print(get_real_url(rid))
|
115
migu.py
115
migu.py
@ -1,115 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @Time: 2021/11/6 10:51
|
|
||||||
# @Project: real-url
|
|
||||||
# @Author: wbt5
|
|
||||||
# @Blog: https://wbt5.com
|
|
||||||
|
|
||||||
import requests
|
|
||||||
from urllib import parse
|
|
||||||
|
|
||||||
|
|
||||||
class MiGu:
|
|
||||||
"""
|
|
||||||
获取咪咕体育直播的流媒体地址
|
|
||||||
直播列表:https://www.miguvideo.com/mgs/website/prd/sportMatchDetail.html
|
|
||||||
直播间地址形式:https://www.miguvideo.com/mgs/website/prd/sportLive.html?mgdbId=120000173758
|
|
||||||
mgdbId 120000173758即为房间号
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, rid, rate=3):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
rate:估计是清晰度,默认rate=3是高清
|
|
||||||
rid:房间号,如 120000173758
|
|
||||||
"""
|
|
||||||
self.rid = rid
|
|
||||||
self.rate = rate
|
|
||||||
|
|
||||||
def get_real_url(self):
|
|
||||||
"""
|
|
||||||
先获取contId
|
|
||||||
Returns:
|
|
||||||
url
|
|
||||||
"""
|
|
||||||
headers = {
|
|
||||||
'appId': 'miguvideo',
|
|
||||||
'clientId': '',
|
|
||||||
'SDKCEId': '',
|
|
||||||
'terminalId': 'www',
|
|
||||||
'userId': '',
|
|
||||||
'userToken': '',
|
|
||||||
'X-UP-CLIENT-CHANNEL-ID': '',
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
|
||||||
'Chrome/95.0.4638.69 Safari/537.36',
|
|
||||||
'Referer': 'https://www.miguvideo.com/',
|
|
||||||
}
|
|
||||||
url = 'https://app-sc.miguvideo.com/vms-match/v3/staticcache/basic/basic-data/{}'.format(self.rid)
|
|
||||||
|
|
||||||
with requests.Session() as session:
|
|
||||||
res = session.get(url, headers=headers).json()
|
|
||||||
try:
|
|
||||||
contid = res['body']['pId']
|
|
||||||
url = f'https://webapi.miguvideo.com/gateway/playurl/v3/play/playurl?contId={contid}&rateType={self.rate}'
|
|
||||||
res = session.get(url, headers=headers).json()
|
|
||||||
try:
|
|
||||||
playurl = res['body']['urlInfo']['url']
|
|
||||||
real_url = self.calcu(playurl)
|
|
||||||
return real_url
|
|
||||||
except KeyError:
|
|
||||||
return '未获取到url,可能参数错误!'
|
|
||||||
except KeyError:
|
|
||||||
return '未获取到contId'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def calcu(pre_url):
|
|
||||||
"""
|
|
||||||
计算ddCalcu,原始过程在pcPlayer.js的9432行到9460行。
|
|
||||||
这里直接用python代码还原,其实可以简化。
|
|
||||||
Args:
|
|
||||||
pre_url:playurl请求返回的url用来拼接计算ddCalcu
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
real_url:添加ddCalcu后的播放地址
|
|
||||||
"""
|
|
||||||
params = dict(parse.parse_qsl(pre_url.split('?')[-1]))
|
|
||||||
t = 'eeeeeeeee'
|
|
||||||
r = str(params['timestamp'])
|
|
||||||
n = str(params['ProgramID'])
|
|
||||||
a = params['Channel_ID']
|
|
||||||
o = params['puData']
|
|
||||||
# s = '2624'
|
|
||||||
# js里是遍历s,这里直接写死
|
|
||||||
u = t[2] or 'e'
|
|
||||||
ll = r[6] or 't'
|
|
||||||
c = n[2] or "c"
|
|
||||||
f = a[len(a) - 4] or 'n'
|
|
||||||
d = o
|
|
||||||
h = []
|
|
||||||
for p in range(0, int(len(d) / 2)):
|
|
||||||
h.append(d[len(d) - p - 1])
|
|
||||||
if p < len(d) - p - 1:
|
|
||||||
h.append(o[p])
|
|
||||||
x = {
|
|
||||||
1: u,
|
|
||||||
2: ll,
|
|
||||||
3: c,
|
|
||||||
4: f
|
|
||||||
}
|
|
||||||
h.append(x[p]) if p in [1, 2, 3, 4] else ''
|
|
||||||
v = ''.join(h)
|
|
||||||
real_url = pre_url + '&ddCalcu=' + v
|
|
||||||
return real_url
|
|
||||||
|
|
||||||
|
|
||||||
def get_real_url(rid):
|
|
||||||
try:
|
|
||||||
mg = MiGu(rid)
|
|
||||||
return mg.get_real_url()
|
|
||||||
except Exception as e:
|
|
||||||
print('Exception:', e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
rr = input('请输入咪咕直播间号:\n')
|
|
||||||
print(get_real_url(rr))
|
|
Loading…
x
Reference in New Issue
Block a user