fix(Plugins.Huya): Update HuYaUA (#1291)

* fix(Plugins.Huya): HuYaUA

* add options to disable wup headers

* cleanup

* Update __init__.py

---------

Co-authored-by: ForgQi <34411314+ForgQi@users.noreply.github.com>
This commit is contained in:
XuanRan_NyanandForgQi authored and GitHub committed 2025-05-12 03:58:19 +00:00
1 parent b61ff5ed08
commit 45839c7e88
4 files changed
+78 -26

No files matched your search

+12 -2
View File
@@ -120,8 +120,18 @@ const Huya: React.FC<Props> = props => {
/>
<Form.Switch
field="huya_mobile_api"
extraText="使用移动端API可以绕过 PCWEB 端对原画的时长限制"
label="虎牙使用移动端API(huya_mobile_api)"
extraText="移动端 API 请求直播间信息,可能解决部分直播分区 2 分钟分段问题"
label="使用移动端 API(huya_mobile_api)"
fieldStyle={{
alignSelf: 'stretch',
padding: 0,
}}
/>
<Form.Switch
field="huya_use_wup"
extraText="使用 WUP 协议的请求头,可能解决部分直播分区 2 分钟分段问题"
label="使用 WUP 协议(huya_use_wup)"
initValue={entity?.hasOwnProperty('huya_use_wup') ? entity['huya_use_wup'] : true}
fieldStyle={{
alignSelf: 'stretch',
padding: 0,
+1 -1
View File
@@ -2,7 +2,7 @@ import logging
import platform
import sys
__version__ = "0.4.97"
__version__ = "0.4.98"
LOG_CONF = {
'version': 1,
+6 -3
View File
@@ -104,13 +104,16 @@ class DownloadBase(ABC):
return True
def download(self):
logger.info(f"{self.plugin_msg}: Start downloading {self.raw_stream_url}")
# print(f"{self.plugin_msg}: Plugin settings - {self.__dict__}")
logger.info(f"{self.plugin_msg}: Plugin settings - {self.__dict__}")
# logger.info(f"{self.plugin_msg}: Request headers - {self.fake_headers}")
logger.info(f"{self.plugin_msg}: Request url - {self.raw_stream_url}")
# 调试使用边录边上传功能
# self.downloader = 'sync-downloader'
if self.is_download:
if not shutil.which("ffmpeg"):
logger.error("未安装 FFMpeg 或不存在于 PATH 内")
logger.debug("Current user's PATH is:" + os.getenv("PATH"))
logger.info("Current user's PATH is:" + os.getenv("PATH"))
return False
else:
return self.ffmpeg_segment_download()
@@ -119,7 +122,7 @@ class DownloadBase(ABC):
if self.downloader != 'stream-gears':
if not shutil.which("ffmpeg"):
logger.error("未安装 FFMpeg 或不存在于 PATH 内,本次下载使用 stream-gears")
logger.debug("Current user's PATH is:" + os.getenv("PATH"))
logger.info("Current user's PATH is:" + os.getenv("PATH"))
else:
# 同步下载上传器
if self.downloader == 'sync-downloader':
+59 -20
View File
@@ -37,8 +37,10 @@ class Huya(DownloadBase):
self.huya_cdn_fallback = config.get('huya_cdn_fallback', False)
self.huya_mobile_api = config.get('huya_mobile_api', False)
self.huya_codec = config.get('huya_codec', '264')
self.huya_use_wup = config.get('huya_use_wup', True)
async def acheck_stream(self, is_check=False):
try:
if not self.__room_id.isdigit():
client.headers.update(self.fake_headers)
@@ -67,14 +69,17 @@ class Huya(DownloadBase):
# self.room_title = room_profile['room_title']
is_xingxiu = (room_profile['gid'] == 1663)
stream_urls = self.build_stream_urls(room_profile['streams_info'], is_xingxiu)
# is_xingxiu = (room_profile['gid'] == 1663)
gid_blacklist = [1663, ]
skip_query_build = self.huya_imgplus and (self.huya_mobile_api or room_profile['gid'] in gid_blacklist)
stream_urls = self.build_stream_urls(room_profile['streams_info'], skip_query_build)
cdn_list = list(stream_urls.keys())
if not self.huya_cdn or self.huya_cdn not in cdn_list:
self.huya_cdn = cdn_list[0]
# Thx stream-rec
self.update_user_agent(self.fake_headers)
if self.huya_use_wup:
self.update_headers(self.fake_headers)
try:
self.raw_stream_url = self.add_ratio(
@@ -86,7 +91,7 @@ class Huya(DownloadBase):
logger.error(f"{self.plugin_msg}: {e}", exc_info=True)
return False
# 虎牙直播流只允许连接一次
# HTTPS的直播流只允许连接一次
if self.huya_cdn_fallback:
_url = await self.acheck_url_healthy(self.raw_stream_url)
if _url is None:
@@ -107,7 +112,7 @@ class Huya(DownloadBase):
if not room_profile['live']:
logger.debug(f"{self.plugin_msg}: {room_profile['message']}")
return False
stream_urls = self.build_stream_urls(room_profile['streams_info'], is_xingxiu)
stream_urls = self.build_stream_urls(room_profile['streams_info'], skip_query_build)
self.raw_stream_url = self.add_ratio(
stream_urls[self.huya_cdn],
@@ -181,10 +186,11 @@ class Huya(DownloadBase):
stream_name = self.get_stream_name(stream['sStreamName'])
cdn = stream['sCdnType']
suffix = stream[f's{proto}UrlSuffix']
anti_code = stream[f's{proto}AntiCode'] + f"&codec={self.huya_codec}"
anti_code = stream[f's{proto}AntiCode']
if not skip_query_build:
anti_code = self.build_query(stream_name, anti_code, stream['lPresenterUid'])
base_url = stream[f's{proto}Url'].replace('http://', 'https://')
anti_code = self.build_query(stream_name, anti_code, self.get_uid(stream['lPresenterUid']))
anti_code = f"{anti_code}&codec={self.huya_codec}"
base_url = stream[f's{proto}Url'].replace('http://', 'https://') # 强制https
streams[cdn] = f"{base_url}/{stream_name}.{suffix}?{anti_code}"
weights[cdn] = priority
return self.__weight_sorting(streams, weights)
@@ -305,7 +311,7 @@ class Huya(DownloadBase):
"u": convert_uid,
"uuid": str(int((ct % 1e10 + random.random()) * 1e3 % 0xffffffff)),
"sdk_sid": str(int(time.time() * 1000)),
"codec": self.huya_codec,
# "codec": self.huya_codec,
}
return '&'.join([f"{k}={v}" for k, v in anti_code.items()])
@@ -319,6 +325,16 @@ class Huya(DownloadBase):
return {}
@staticmethod
def get_uid(uid: Union[str, int, None] = None) -> int:
try:
if isinstance(uid, str):
uid = int(uid)
except ValueError:
pass
return uid or random.randint(1400000000000, 1499999999999)
async def get_anonymous_uid(self) -> int:
try:
rsp = await client.post(
@@ -332,21 +348,44 @@ class Huya(DownloadBase):
"data": {},
}
)
data = json_loads(rsp.text)
rsp = json_loads(rsp.text)
except:
return random.randint(1400000000000, 1499999999999)
else:
return data['data']['uid']
rsp = {}
return rsp.get('data', {}).get('uid', self.get_uid())
@staticmethod
def update_user_agent(headers: dict):
# copied from stream-rec commit b48c9cd
valid_ts = 20000308
current_ts = int(time.time())
version = str(current_ts)[-8:]
version = version if int(version) > valid_ts else (valid_ts + (current_ts / 100))
headers['user-agent'] = f"HYSDK(Windows, {version})"
def get_hyapp_ua() -> str:
hyapp_platform = 'huya_nftv' # adr or huya_nftv, pc_exe, webh5
hyapp_version = '2.5.1.3141' # adr/nftv: LocalVersion or "0.0.0" + hotfix_version, pc_exe: 6070100, ws: 2505091506
hyapp_channel = 'official' # adr: live, nftv/pc_exe: official, websocket
android_api_level = random.randint(28, 35) # Build.VERSION.SDK_INT
ua = f"{hyapp_platform}&{hyapp_version}&{hyapp_channel}"
return ua if hyapp_platform in {'pc_exe', 'webh5'} else f"{ua}&{android_api_level}"
@staticmethod
def get_hysdk_ua() -> str:
hysdk_platform = 'Android' # Android, Windows
hysdk_version = '30000002' # 30000002
return f"HYSDK({hysdk_platform}, {hysdk_version})"
@staticmethod
def get_hy_media_player_ua() -> str:
hy_mp_platform = 'android' # android
hy_mp_version = '20000313' # 20000313
return f"{hy_mp_platform}, {hy_mp_version}"
@staticmethod
def get_hy_trans_mod_ua() -> str:
hy_trans_mod_name = 'trans' # trans
hy_trans_mod_version = '1.24.99-rel-tv' # nftv: 1.24.99-rel-tv, adr: 2.22.13-rel, win: 2.21.0.4784
return f"{hy_trans_mod_name}&{hy_trans_mod_version}"
@staticmethod
def update_headers(headers: dict):
user_agent = f"{Huya.get_hy_media_player_ua()}_APP({Huya.get_hyapp_ua()})_SDK({Huya.get_hy_trans_mod_ua()})"
# user_agent = f"{Huya.get_hysdk_ua()}_APP({Huya.get_hyapp_ua()})_SDK({Huya.get_hy_trans_mod_ua()})"
headers['user-agent'] = user_agent
headers['origin'] = HUYA_WEB_BASE_URL