Fix(Huya): refactor anticode generation using getCdnTokenInfoEx API (#1575)

* Fix(Huya): refactor anticode generation using getCdnTokenInfoEx API

* chore: cleanup

* chore: get random sHuYaUA

* chore: 代码复用
This commit is contained in:
XuanRan_Nyan authored and GitHub committed 2025-12-21 13:03:52 +00:00
1 parent 218b8bd127
commit caf106c3f8
20 files changed
+2801 -1991

No files matched your search

+1 -1
View File
@@ -191,7 +191,7 @@ const Dashboard: React.FC = () => {
{Object.entries(plugins)
.filter(([key]) => key !== 'Cookie')
.map(([key, Plugin]) => (
<Plugin entity={entity} list={list} />
<Plugin key={key} entity={entity} list={list} />
))}
<plugins.Cookie entity={entity} list={list} />
</Collapse>
+10 -9
View File
@@ -17,14 +17,6 @@ interface LogContentProps {
}
const LogContent = ({ logs, logContainerRef, isLoading }: LogContentProps) => {
if (isLoading) {
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
<Spin size="large" />
</div>
)
}
// 判断滚动条是否接近底部
const isScrolledToBottom = () => {
const containers = document.getElementsByClassName('log-container');
@@ -53,6 +45,14 @@ const LogContent = ({ logs, logContainerRef, isLoading }: LogContentProps) => {
}
}, [logs]);
if (isLoading) {
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
<Spin size="large" />
</div>
)
}
return (
<div
className="log-container"
@@ -151,6 +151,7 @@ export default function LogViewer() {
wsRef.current.close()
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTab])
const handleFileChange = (value: string) => {
@@ -211,7 +212,7 @@ export default function LogViewer() {
activeKey={activeTab}
onChange={handleFileChange}
tabBarExtraContent={
<div style={{ display: 'flex', gap: 8, alignItems: 'center'}}>
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
<Button
icon={<IconSave />}
onClick={() => (window.location.href = `/static/${activeTab}.log`)}
+8 -7
View File
@@ -12,9 +12,10 @@ interface PlayerConfig {
function playFlv(video: HTMLVideoElement, url: string, art: Artplayer) {
if (mpegts.isSupported()) {
if (art.flv) {
art.flv.destroy()
art.flv = null
const artWithFlv = art as Artplayer & { flv?: mpegts.Player | null }
if (artWithFlv.flv) {
artWithFlv.flv.destroy()
artWithFlv.flv = null
}
const flv = mpegts.createPlayer({
@@ -22,11 +23,11 @@ function playFlv(video: HTMLVideoElement, url: string, art: Artplayer) {
url: url,
})
art.flv = flv
artWithFlv.flv = flv
art.on('destroy', () => {
if (art.flv) {
art.flv.destroy()
art.flv = null
if (artWithFlv.flv) {
artWithFlv.flv.destroy()
artWithFlv.flv = null
}
})
+228 -258
View File
@@ -5,7 +5,7 @@ import time
import html
from enum import Enum
from dataclasses import dataclass
from urllib.parse import parse_qs, unquote
from urllib.parse import parse_qs, unquote, quote
from async_lru import alru_cache
from typing import (
Any,
@@ -21,17 +21,18 @@ from ..engine.download import DownloadBase
from . import logger, match1, json_loads
from biliup.plugins.huya_wup import Wup, DEFAULT_TICKET_NUMBER
from biliup.plugins.huya_wup.packet import (
HuyaGetCdnTokenReq,
HuyaGetCdnTokenRsp
)
from biliup.plugins.huya_wup.packet import *
from biliup.plugins.huya_wup.wup_struct.UserId import HuyaUserId
HUYA_WEB_BASE_URL = "https://www.huya.com"
HUYA_MOBILE_BASE_URL = "https://m.huya.com"
HUYA_MP_BASE_URL = "https://mp.huya.com"
HUYA_WUP_BASE_URL = "https://wup.huya.com"
HUYA_WUP_YST_URL = "https://snmhuya.yst.aisee.tv"
HUYA_WEB_ROOM_DATA_REGEX = r"var TT_ROOM_DATA = (.*?);"
rotl64 = lambda t: ((t & 0xFFFFFFFF) << 8 | (t & 0xFFFFFFFF) >> 24) & 0xFFFFFFFF | (t & ~0xFFFFFFFF)
@Plugin.download(regexp=r'https?://(?:(?:www|m)\.)?huya\.com')
class Huya(DownloadBase):
def __init__(self, fname, url, config, suffix='flv'):
@@ -45,7 +46,7 @@ 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)
self.huya_use_wup = (not self.huya_mobile_api)
async def acheck_stream(self, is_check=False):
@@ -67,20 +68,18 @@ class Huya(DownloadBase):
# 兼容 biliup/biliup#1200
self.room_title = room_profile['room_title']
# 虎牙回放
if self.room_title.startswith('【回放】'):
logger.debug(f"{self.plugin_msg}: {self.room_title}")
return False
# 过滤回放
for key in ["回放", "重播"]:
# 前三或后三
if key in self.room_title[:3] or key in self.room_title[-3:]:
logger.debug(f"{self.plugin_msg}: {self.room_title}")
return False
if is_check:
return True
# self.room_title = room_profile['room_title']
# is_xingxiu = (room_profile['gid'] == 1663)
gid_blacklist = [1663, ]
skip_query_build = room_profile['gid'] in gid_blacklist
stream_urls = await self.build_stream_urls(room_profile['streams_info'], skip_query_build)
stream_urls = await self.build_stream_urls(room_profile['streams_info'])
print(stream_urls)
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]
@@ -116,7 +115,7 @@ class Huya(DownloadBase):
if not room_profile['live']:
logger.debug(f"{self.plugin_msg}: {room_profile['message']}")
return False
stream_urls = await self.build_stream_urls(room_profile['streams_info'], skip_query_build)
stream_urls = await self.build_stream_urls(room_profile['streams_info'])
self.raw_stream_url = self.add_ratio(
stream_urls[self.huya_cdn],
@@ -126,10 +125,12 @@ class Huya(DownloadBase):
return True
def danmaku_init(self):
if self.huya_danmaku:
self.danmaku = DanmakuClient(self.url, self.gen_download_filename())
def add_ratio(self, url: str, bitrate_info: Dict[str, Any], max_bitrate: int) -> str:
'''
添加码率
@@ -159,25 +160,26 @@ class Huya(DownloadBase):
raise KeyError(f"确定码率时发生错误") from e
return url
def get_stream_name(self, stream_name: str) -> str:
if self.huya_imgplus:
return stream_name
return stream_name.replace('-imgplus', '')
async def build_stream_urls(
self,
streams_info: List[Dict[str, Any]],
skip_query_build: bool
streams_info: List[Dict[str, Any]]
) -> List[Dict[str, Any]]:
'''
构建流地址
:param streams_info: 流信息
:param skip_query_build: 跳过构建anti_code
:return: 流地址
'''
proto = self.huya_protocol
streams = {}
weights = {} # https://cdnweb.huya.com/getUidsDomainList?anchor_uid={anchor_uid}
cached_anticode = ""
for stream in streams_info:
# 优先级<0代表不可用
priority = stream['iWebPriorityRate']
@@ -186,27 +188,23 @@ class Huya(DownloadBase):
stream_name = self.get_stream_name(stream['sStreamName'])
cdn = stream['sCdnType']
suffix = stream[f's{proto}UrlSuffix']
# 默认不修改 anticode
anti_code = stream[f's{proto}AntiCode']
if (
# 禁用 imgplus
not self.huya_imgplus
or
# 禁用 wup ,流信息不来自移动端,不在分区黑名单中
not (self.huya_use_wup or self.huya_mobile_api or skip_query_build)
):
logger.debug(f"{self.plugin_msg}: 构建 anticode")
anti_code = self.build_query(stream_name, anti_code, self.get_uid(stream['lPresenterUid']))
# 启用 imgplus、wup 且非 mobile api
elif self.huya_use_wup and not self.huya_mobile_api:
# 使用 Wup 获取的 anti_code,必须使用 Wup UA 进行连接
anti_code = await self.get_true_anticode(cdn, stream_name, self.get_uid(stream['lPresenterUid']), proto)
anti_code = f"{anti_code}&codec={self.huya_codec}"
if not cached_anticode:
# 小程序API不修改
if self.huya_mobile_api and self.huya_imgplus:
cached_anticode = stream[f's{proto}AntiCode']
else:
cached_anticode = self.build_anticode(
stream_name,
(await self.get_cdn_token_info_ex(stream_name)),
stream['lPresenterUid']
)
cached_anticode += f"&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}"
streams[cdn] = f"{base_url}/{stream_name}.{suffix}?{cached_anticode}"
weights[cdn] = priority
return self.__weight_sorting(streams, weights)
def extract_room_profile(self, data: Union[str, Dict[str, Any]]) -> Dict[str, Any]:
'''
ON: 直播
@@ -250,6 +248,7 @@ class Huya(DownloadBase):
'streams_info': streams_info,
}
async def get_room_profile(self, use_api=False) -> dict:
'''
获取房间信息
@@ -279,90 +278,130 @@ class Huya(DownloadBase):
_raise_for_room_block(resp)
return self.extract_room_profile(resp)
async def get_true_anticode(
self,
cdn: str,
stream_name: str,
presenter_uid: int,
proto: str,
) -> str:
async def get_cdn_token_info_ex(self, stream_name: str) -> str:
'''
获取 wup anti_code
:param cdn: cdn类型
:param stream_name: 流名称
getCdnTokenInfoEx
:param stream_name: stream_name
:param presenter_uid: 主播uid
:param proto: 协议类型
:return: wup anti_code
:return: sFlvToken
'''
proto = "hls" if proto == "Hls" else "flv"
headers = {}
self.update_headers(headers)
servant = "liveui"
func = "getCdnTokenInfoEx"
tid = HuyaUserId()
# Generate random sHuYaUA using UAGenerator
tid.sHuYaUA = UAGenerator.get_random_hyapp_ua()
print(f"sHuYaUA: {tid.sHuYaUA}")
wup_req = Wup()
wup_req.requestid = abs(DEFAULT_TICKET_NUMBER)
wup_req.servant = "liveui"
wup_req.func = "getCdnTokenInfo"
token_info_req = HuyaGetCdnTokenReq()
token_info_req.cdnType = cdn
token_info_req.streamName = stream_name
token_info_req.presenterUid = presenter_uid
wup_req.put(HuyaGetCdnTokenReq, "tReq", token_info_req)
wup_req.servant = servant
wup_req.func = func
getCdnTokenInfoExReq = HuyaGetCdnTokenExReq()
getCdnTokenInfoExReq.sStreamName = stream_name
# getCdnTokenInfoExReq.iLoopTime = 15 * 60 # 防盗链过期时间
getCdnTokenInfoExReq.tId = tid
wup_req.put(
vtype=HuyaGetCdnTokenExReq,
name="tReq",
value=getCdnTokenInfoExReq
)
data = wup_req.encode_v3()
rsp = await client.post(HUYA_WUP_BASE_URL, data=data, headers=headers)
url = HUYA_WUP_BASE_URL
if random.random() > 0.5:
url = f"{HUYA_WUP_YST_URL}/{servant}/{func}"
print(f"send requests to {url}")
rsp = await client.post(url, data=data)
rsp_bytes = rsp.content
wup_rsp = Wup()
wup_rsp.decode_v3(rsp.content)
token_info_rsp = wup_rsp.get(HuyaGetCdnTokenRsp,"tRsp")
# print(token_info_rsp.as_dict())
token_info = token_info_rsp.as_dict()
logger.debug(f"{self.plugin_msg}: wup token_info {token_info}")
return token_info[f'{proto}AntiCode']
wup_rsp.decode_v3(rsp_bytes)
getCdnTokenInfoExRsp = wup_rsp.get(
vtype=HuyaGetCdnTokenExRsp,
name="tRsp"
)
cdn_token_info_ex = getCdnTokenInfoExRsp.as_dict()
print(f"{self.plugin_msg}: wup token_info {cdn_token_info_ex}")
return cdn_token_info_ex['sFlvToken']
def build_query(self, stream_name, anti_code, uid: int) -> str:
def build_anticode(
self,
stream_name: str,
anti_code: str,
uid: Union[str, int] = 0,
random_platform: bool = False
) -> str:
'''
构建anti_code
:param stream_name: 流名称
:param anti_code: 原始anti_code
:param uid: 主播uid
:return: 构建后的anti_code
构建anticode
:param stream_name: streamname
:param anti_code: anticode
:param uid: 用户uid
:return: Parsed anticode
'''
url_query = parse_qs(anti_code)
platform_id = url_query.get('t', [100])[0]
ws_time = url_query['wsTime'][0]
convert_uid = (uid << 8 | uid >> (32 - 8)) & 0xFFFFFFFF
seq_id = uid + int(time.time() * 1000)
ctype = url_query['ctype'][0]
if not url_query.get("fm"):
return anti_code
ctype = url_query.get('ctype', [])
platform_id = url_query.get('t', [])
if len(ctype) == 0 or random_platform:
ctype, platform_id = PLATFORM.get_random_as_tuple()
elif len(platform_id) == 0:
ctype = ctype[0]
platform_id = PLATFORM.get_platform_id(ctype)
else:
ctype = ctype[0]
platform_id = platform_id[0]
is_wap = int(platform_id) in {103}
clac_start_time = time.time()
if isinstance(uid, str):
uid = int(uid) if uid.isdigit() else 0
if uid == 0:
uid = self.generate_random_uid()
print(f"Using {uid} as uid for calculation")
seq_id = uid + int(clac_start_time * 1000)
secret_hash = hashlib.md5(f"{seq_id}|{ctype}|{platform_id}".encode()).hexdigest()
convert_uid = rotl64(uid)
clac_uid = uid if is_wap else convert_uid
fm = unquote(url_query['fm'][0])
ct = int((int(ws_time, 16) + random.random()) * 1000)
ws_secret_prefix = base64.b64decode(fm.encode()).decode().split('_')[0]
ws_secret_hash = hashlib.md5(f"{seq_id}|{ctype}|{platform_id}".encode()).hexdigest()
secret_str = f'{ws_secret_prefix}_{convert_uid}_{stream_name}_{ws_secret_hash}_{ws_time}'
secret_prefix = base64.b64decode(fm.encode()).decode().split('_')[0]
ws_time = url_query['wsTime'][0]
# 修复 hls m3u8 链接过期时间
if int(ws_time, 16) - int(clac_start_time) < (20 * 60):
# 如果过期时间小于 20 分钟,调整过期时间为 1 天
ws_time = hex(24 * 60 * 60 + int(clac_start_time))[2:]
secret_str = f'{secret_prefix}_{clac_uid}_{stream_name}_{secret_hash}_{ws_time}'
ws_secret = hashlib.md5(secret_str.encode()).hexdigest()
# &codec=av1
# &codec=264
# &codec=265
# dMod: wcs-25 / mesh-0 DecodeMod-SupportMod
# chrome > 104 or safari = mseh, chrome = mses
# sdkPcdn: 1_1 第一个1连接次数 第二个1是因为什么连接
# t: 平台信息 100 web(ctype=huya_live/huya_webh5) 102 小程序(ctype=tars_mp)
# PLATFORM_TYPE = {'adr': 2, 'huya_liveshareh5': 104, 'ios': 3, 'mini_app': 102, 'wap': 103, 'web': 100}
# sv: 2401090219 版本
# sdk_sid: _sessionId sdkInRoomTs 当前毫秒时间
# return f"wsSecret={ws_secret}&wsTime={ws_time}&seqid={seq_id}&ctype={url_query['ctype'][0]}&ver=1&fs={url_query['fs'][0]}&u={convert_uid}&t={platform_id}&sv=2401090219&sdk_sid={int(time.time() * 1000)}&codec=264"
ct = int((int(ws_time, 16) + random.random()) * 1000)
uuid = str(int((ct % 1e10 + random.random()) * 1e3 % 0xffffffff))
anti_code = {
"wsSecret": ws_secret,
"wsTime": ws_time,
"seqid": str(seq_id),
"seqid": seq_id,
"ctype": ctype,
"ver": "1",
"fs": url_query['fs'][0],
"fm": quote(url_query['fm'][0], encoding='utf-8'),
"t": platform_id,
"u": convert_uid,
"uuid": str(int((ct % 1e10 + random.random()) * 1e3 % 0xffffffff)),
"sdk_sid": str(int(time.time() * 1000)),
# "codec": self.huya_codec,
}
if is_wap:
anti_code.update({
"uid": uid,
"uuid": uuid,
})
else:
anti_code.update({
"u": convert_uid,
})
return '&'.join([f"{k}={v}" for k, v in anti_code.items()])
@staticmethod
def __weight_sorting(
data: Dict[str, Any], weights: Dict[str, Any]
@@ -372,197 +411,128 @@ class Huya(DownloadBase):
return dict(sorted(data.items(), key=lambda x: weights[x[0]], reverse=True))
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)
def generate_random_uid() -> int:
return int(f"1234{random.randint(0, 9999):04d}") \
if random.random() > 0.5 else \
int(f"140000{random.randint(0, 9999999):07d}")
async def get_anonymous_uid(self) -> int:
try:
rsp = await client.post(
url='https://udblgn.huya.com/web/anonymousLogin',
headers=self.fake_headers,
json={
"appId": 5002,
"byPass": 3,
"context": "",
"version": "2.4",
"data": {},
}
)
rsp = json_loads(rsp.text)
except:
rsp = {}
return rsp.get('data', {}).get('uid', self.get_uid())
def update_headers(self, headers: dict):
if self.huya_use_wup:
user_agent = UAGenerator.build_user_agent(UAType.HYSDK, Platform.WINDOWS)
# 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
# async def get_anonymous_uid(self) -> int:
# try:
# rsp = await client.post(
# url='https://udblgn.huya.com/web/anonymousLogin',
# headers=self.fake_headers,
# json={
# "appId": 5002,
# "byPass": 3,
# "context": "",
# "version": "2.4",
# "data": {},
# }
# )
# rsp = json_loads(rsp.text)
# except:
# rsp = {}
# return rsp.get('data', {}).get('uid', self.get_uid())
class UAType(Enum):
MEDIA_PLAYER = 'media_player'
HYSDK = 'hysdk'
# def update_headers(self, headers: dict):
# if self.huya_use_wup:
# user_agent = UAGenerator.build_user_agent(UAType.HYSDK, Platform.WINDOWS)
# # 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
class PLATFORM(Enum):
HUYA_PC_EXE = 0
HUYA_ADR = 2
HUYA_IOS = 3
TV_HUYA_NFTV = 10
HUYA_WEBH5 = 100
HUYA_LIVE = 100
TARS_MP = 102
TARS_MOBILE = 103
HUYA_LIVESHAREH5 = 104
@classmethod
def get_random_as_tuple(cls):
_ = random.choice(list(cls))
return _.name.lower(), _.value
@classmethod
def get_platform_id(cls, platform: str) -> int:
return cls[platform.upper()].value if platform.upper() in cls.__members__ else 100
@property
def short_name(self) -> str:
"""获取平台短名称"""
name = self.name.lower()
idx = name.find('_')
return name[idx + 1:] if idx != -1 else name
class Platform(Enum):
ANDROID = 'adr'
HUYA_NFTV = 'huya_nftv'
WEBSOCKET = 'webh5'
WINDOWS = 'pc_exe'
class UAGenerator:
# 配置字典
# Configuration dictionary mapping PLATFORM enum to UA components
HYAPP_CONFIGS = {
Platform.ANDROID: {
'platform': Platform.ANDROID,
'version': '0.0.0', # LocalVersion or "0.0.0" + hotfix_version
'channel': 'live'
PLATFORM.HUYA_ADR: {
'version': '13.1.0', # LocalVersion or "0.0.0" + hotfix_version
},
Platform.HUYA_NFTV: {
'platform': Platform.HUYA_NFTV,
'version': '2.5.1.3141',
'channel': 'official'
PLATFORM.HUYA_IOS: {
'version': '13.1.0',
},
Platform.WINDOWS: {
'platform': Platform.WINDOWS,
'version': '6100301',
'channel': 'official'
PLATFORM.TV_HUYA_NFTV: {
'version': '2.6.10',
},
Platform.WEBSOCKET: { # UnUsed
'platform': Platform.WEBSOCKET,
'version': '2505091506',
'channel': 'websocket'
}
PLATFORM.HUYA_PC_EXE: {
'version': '7000000',
},
# PLATFORM.HUYA_WEBH5: { # 星秀区不可用
# 'version': '%y%m%d%H%M', # 2410101630
# 'channel': 'websocket'
# }
}
HYSDK_CONFIGS = {
Platform.ANDROID: {
'platform': 'Android',
'version': '30000002'
},
Platform.WINDOWS: {
'platform': 'Windows',
'version': '30000002'
}
}
TRANS_MOD_CONFIGS = {
Platform.HUYA_NFTV: {
'name': 'trans',
'version': '1.24.99-rel-tv'
},
Platform.ANDROID: {
'name': 'trans',
'version': '2.22.13-rel'
},
Platform.WINDOWS: {
'name': 'trans',
'version': '2.24.0.5157'
}
}
@staticmethod
def get_hyapp_ua(platform: Platform = Platform.WINDOWS) -> str:
def generate_hyapp_ua(platform: PLATFORM) -> str:
'''
生成 hyapp 用户代理字符串
:param platform: 平台类型
:return: 用户代理字符串
Generate hyapp user agent string
:param platform: Platform type from PLATFORM enum
:return: User agent string
'''
config = UAGenerator.HYAPP_CONFIGS.get(platform)
if not config:
raise ValueError(f"不支持的平台: {platform}")
# Fallback if platform not supported
platform = random.choice(list(UAGenerator.HYAPP_CONFIGS.keys()))
config = UAGenerator.HYAPP_CONFIGS[platform]
hyapp_platform = config['platform']
hyapp_version = config['version']
hyapp_channel = config['channel']
hyapp_platform = platform.short_name
hyapp_version = config.get("version", "0.0.0") # TODO: 日期格式化
hyapp_channel = config.get("channel", "official")
# Add random build number for version
if platform in {PLATFORM.HUYA_ADR, PLATFORM.TV_HUYA_NFTV}:
hyapp_version += f".{random.randint(3000, 5000)}"
ua = f"{hyapp_platform}&{hyapp_version}&{hyapp_channel}"
# windows 和 websocket 不需要添加 android_api_level
if platform not in {Platform.WINDOWS, Platform.WEBSOCKET}:
android_api_level = random.randint(28, 35)
# Add android_api_level for android platforms
if platform in {PLATFORM.HUYA_ADR, PLATFORM.TV_HUYA_NFTV}:
android_api_level = random.randint(28, 36)
ua = f"{ua}&{android_api_level}"
return ua
@staticmethod
def get_hysdk_ua(platform: Platform = Platform.WINDOWS) -> str:
'''
生成 hysdk 用户代理字符串
:param platform: 平台类型 (Android 或 Windows)
:return: 用户代理字符串
'''
config = UAGenerator.HYSDK_CONFIGS.get(platform)
if not config:
raise ValueError(f"HYSDK 不支持的平台: {platform}")
hysdk_platform = config['platform']
hysdk_version = config['version']
return f"HYSDK({hysdk_platform}, {hysdk_version})"
@staticmethod
def get_hy_media_player_ua(platform: Platform = Platform.WINDOWS) -> str:
def get_random_hyapp_ua() -> str:
'''
生成 hy_media_player 用户代理字符串
:param platform: 平台类型
:return: 用户代理字符串
Generate random hyapp user agent string by randomly selecting a platform
:return: User agent string
'''
# 目前只支持 android 平台
hy_mp_platform = 'android'
hy_mp_version = '20000313'
return f"{hy_mp_platform}, {hy_mp_version}"
@staticmethod
def get_hy_trans_mod_ua(platform: Platform = Platform.WINDOWS) -> str:
'''
生成 hy_trans_mod 用户代理字符串
:param platform: 平台类型
:return: 用户代理字符串
'''
config = UAGenerator.TRANS_MOD_CONFIGS.get(platform)
if not config:
raise ValueError(f"Trans mod 不支持的平台: {platform}")
hy_trans_mod_name = config['name']
hy_trans_mod_version = config['version']
return f"{hy_trans_mod_name}&{hy_trans_mod_version}"
@staticmethod
def build_user_agent(
ua_type: UAType = UAType.HYSDK,
platform: Platform = Platform.WINDOWS
) -> str:
'''
构建完整的用户代理字符串
:param ua_type: UA 类型 (MEDIA_PLAYER 或 HYSDK)
:param platform: 平台类型
:return: 完整的用户代理字符串
'''
# 获取各个组件的 UA
hyapp_ua = UAGenerator.get_hyapp_ua(platform)
trans_mod_ua = UAGenerator.get_hy_trans_mod_ua(platform)
if ua_type == UAType.MEDIA_PLAYER:
media_player_ua = UAGenerator.get_hy_media_player_ua(platform)
return f"{media_player_ua}_APP({hyapp_ua})_SDK({trans_mod_ua})"
elif ua_type == UAType.HYSDK:
sdk_platform = platform if platform in {Platform.ANDROID, Platform.HUYA_NFTV} else Platform.WINDOWS
hysdk_ua = UAGenerator.get_hysdk_ua(sdk_platform)
return f"{hysdk_ua}_APP({hyapp_ua})_SDK({trans_mod_ua})"
else:
raise ValueError(f"不支持的 UA 类型: {ua_type}")
random_platform = random.choice(list(PLATFORM))
return UAGenerator.generate_hyapp_ua(random_platform)
def _raise_for_room_block(text: str):
+7 -5
View File
@@ -1,8 +1,10 @@
from .getCdnTokenInfo import (
HuyaGetCdnTokenReq,
HuyaGetCdnTokenRsp
from .getCdnTokenEx import (
HuyaGetCdnTokenExReq,
HuyaGetCdnTokenExRsp
)
__all__ = ['HuyaGetCdnTokenReq', 'HuyaGetCdnTokenRsp']
__all__ = [
'HuyaGetCdnTokenExReq',
'HuyaGetCdnTokenExRsp'
]
+36 -6
View File
@@ -6,19 +6,49 @@ STANDARD_CHARSET = 'utf-8'
def auto_decode_fields(cls):
"""自动解码类中的bytes类型数据"""
"""自动解码类中的bytes类型数据,包括vector和map中的字符串"""
original_read_from = cls.readFrom
def _decode_recursive(obj):
"""递归解码对象中的bytes字段"""
if isinstance(obj, bytes):
try:
return obj.decode(STANDARD_CHARSET)
except UnicodeDecodeError:
# 如果解码失败,返回原始bytes
return obj
elif isinstance(obj, list):
# 处理vector类型(继承自list)- 必须在 hasattr(__dict__) 之前检查
for i in range(len(obj)):
obj[i] = _decode_recursive(obj[i])
elif isinstance(obj, dict):
# 处理map类型(继承自dict)- 必须在 hasattr(__dict__) 之前检查
keys_to_update = []
for key in obj.keys():
decoded_key = _decode_recursive(key)
decoded_value = _decode_recursive(obj[key])
keys_to_update.append((key, decoded_key, decoded_value))
# 更新字典
for old_key, new_key, new_value in keys_to_update:
if old_key != new_key:
del obj[old_key]
obj[new_key] = new_value
else:
obj[old_key] = new_value
elif hasattr(obj, '__dict__'):
# 处理结构体对象
for attr_name, attr_value in vars(obj).items():
setattr(obj, attr_name, _decode_recursive(attr_value))
return obj
@staticmethod
@wraps(original_read_from)
def wrapped_read_from(ios: tarscore.TarsInputStream):
value = original_read_from(ios)
# 遍历对象的所有属性
# 遍历对象的所有属性进行解码
for attr_name, attr_value in vars(value).items():
# 如果是bytes类型
if isinstance(attr_value, bytes):
# 将其解码为字符串
setattr(value, attr_name, attr_value.decode(STANDARD_CHARSET))
setattr(value, attr_name, _decode_recursive(attr_value))
return value
cls.readFrom = wrapped_read_from
@@ -0,0 +1,60 @@
from biliup.common.tars import tarscore
from .__util import auto_decode_fields
from ..wup_struct.UserId import HuyaUserId
@auto_decode_fields
class HuyaGetCdnTokenExReq(tarscore.struct):
__tars_class__ = "HUYA.GetCdnTokenExReq"
def __init__(self):
self.sFlvUrl: tarscore.string = ""
self.sStreamName: tarscore.string = ""
self.iLoopTime: tarscore.int32 = 0
self.tId: HuyaUserId = HuyaUserId()
self.iAppId: tarscore.int32 = 66
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.string, 0, value.sFlvUrl)
oos.write(tarscore.string, 1, value.sStreamName)
oos.write(tarscore.int32, 2, value.iLoopTime)
oos.write(HuyaUserId, 3, value.tId)
oos.write(tarscore.int32, 4, value.iAppId)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaGetCdnTokenExReq()
value.sFlvUrl = ios.read(tarscore.string, 0, False)
value.sStreamName = ios.read(tarscore.string, 1, False)
value.iLoopTime = ios.read(tarscore.int32, 2, False)
value.tId = ios.read(HuyaUserId, 3, False)
value.iAppId = ios.read(tarscore.int32, 4, False)
return value
def as_dict(self):
return self.__dict__.copy()
@auto_decode_fields
class HuyaGetCdnTokenExRsp(tarscore.struct):
__tars_class__ = "HUYA.GetCdnTokenExRsp"
def __init__(self):
self.sFlvToken: tarscore.string = ""
self.iExpireTime: tarscore.int64 = 0
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.string, 0, value.sFlvToken)
oos.write(tarscore.int64, 1, value.iExpireTime)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaGetCdnTokenExRsp()
value.sFlvToken = ios.read(tarscore.string, 0, False)
value.iExpireTime = ios.read(tarscore.int64, 1, False)
return value
def as_dict(self):
return self.__dict__.copy()
@@ -1,74 +0,0 @@
from biliup.common.tars import tarscore
from .__util import auto_decode_fields
@auto_decode_fields
class HuyaGetCdnTokenReq(tarscore.struct):
__tars_class__ = "HUYA.GetCdnTokenReq"
def __init__(self):
self.url: tarscore.string = ""
self.cdnType: tarscore.string = ""
self.streamName: tarscore.string = ""
self.presenterUid: tarscore.int32 = 0
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.string, 0, value.url)
oos.write(tarscore.string, 1, value.cdnType)
oos.write(tarscore.string, 2, value.streamName)
oos.write(tarscore.int64, 3, value.presenterUid)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaGetCdnTokenReq()
value.url = ios.read(tarscore.string, 0, False)
value.cdnType = ios.read(tarscore.string, 1, False)
value.streamName = ios.read(tarscore.string, 2, False)
value.presenterUid = ios.read(tarscore.int64, 3, False)
return value
def as_dict(self):
return self.__dict__.copy()
@auto_decode_fields
class HuyaGetCdnTokenRsp(tarscore.struct):
__tars_class__ = "HUYA.GetCdnTokenRsp"
def __init__(self):
self.url: tarscore.string = ""
self.cdnType: tarscore.string = ""
self.streamName: tarscore.string = ""
self.presenterUid: tarscore.int64 = 0
self.antiCode: tarscore.string = ""
self.sTime: tarscore.string = ""
self.flvAntiCode: tarscore.string = ""
self.hlsAntiCode: tarscore.string = ""
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.string, 0, value.url)
oos.write(tarscore.string, 1, value.cdnType)
oos.write(tarscore.string, 2, value.streamName)
oos.write(tarscore.int64, 3, value.presenterUid)
oos.write(tarscore.string, 4, value.antiCode)
oos.write(tarscore.string, 5, value.sTime)
oos.write(tarscore.string, 6, value.flvAntiCode)
oos.write(tarscore.string, 7, value.hlsAntiCode)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaGetCdnTokenRsp()
value.url = ios.read(tarscore.string, 0, False)
value.cdnType = ios.read(tarscore.string, 1, False)
value.streamName = ios.read(tarscore.string, 2, False)
value.presenterUid = ios.read(tarscore.int64, 3, False)
value.antiCode = ios.read(tarscore.string, 4, False)
value.sTime = ios.read(tarscore.string, 5, False)
value.flvAntiCode = ios.read(tarscore.string, 6, False)
value.hlsAntiCode = ios.read(tarscore.string, 7, False)
return value
def as_dict(self):
return self.__dict__.copy()
@@ -1,60 +0,0 @@
from biliup.common.tars import tarscore
from .__util import auto_decode_fields
from ..wup_struct.UserId import HuyaUserId
from ..wup_struct.BeginLiveNotice import HuyaBeginLiveNotice
from ..wup_struct.StreamSettingNotice import HuyaStreamSettingNotice
class HuyaGetLivingInfoReq(tarscore.struct):
__tars_class__ = "Huya.GetLivingInfoReq"
def __init__(self):
self.tId: HuyaUserId = HuyaUserId()
self.lTopSid: tarscore.int64 = 0
self.lSubSid: tarscore.int64 = 0
self.lPresenterUid: tarscore.int64 = 0
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(HuyaUserId, 0, value.tId)
oos.write(tarscore.int64, 1, value.lTopSid)
oos.write(tarscore.int64, 2, value.lSubSid)
oos.write(tarscore.int64, 3, value.lPresenterUid)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaGetLivingInfoReq()
value.tId = ios.read(HuyaUserId, 0, False)
value.lTopSid = ios.read(tarscore.int64, 1, False)
value.lSubSid = ios.read(tarscore.int64, 2, False)
value.lPresenterUid = ios.read(tarscore.int64, 3, False)
return value
class HuyaGetLivingInfoRsp(tarscore.struct):
__tars_class__ = "Huya.GetLivingInfoRsp"
def __init__(self):
self.bIsLiving: tarscore.int32 = 0
self.tNotice: HuyaBeginLiveNotice = HuyaBeginLiveNotice()
self.tStreamSettingNotice: HuyaStreamSettingNotice = HuyaStreamSettingNotice()
self.bIsSelfLiving: tarscore.int32 = 0
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.int32, 0, value.bIsLiving)
oos.write(HuyaBeginLiveNotice, 1, value.tNotice)
oos.write(HuyaStreamSettingNotice, 2, value.tStreamSettingNotice)
oos.write(tarscore.int32, 3, value.bIsSelfLiving)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaGetLivingInfoRsp()
value.bIsLiving = ios.read(tarscore.int32, 0, False)
value.tNotice = ios.read(HuyaBeginLiveNotice, 1, False)
value.tStreamSettingNotice = ios.read(HuyaStreamSettingNotice, 2, False)
value.bIsSelfLiving = ios.read(tarscore.int32, 3, False)
return value
-47
View File
@@ -1,47 +0,0 @@
from biliup.plugins.huya_wup import Wup, DEFAULT_TICKET_NUMBER
from biliup.plugins.huya_wup.packet import (
HuyaGetCdnTokenReq,
HuyaGetCdnTokenRsp
)
from biliup.plugins.huya_wup.packet.__util import STANDARD_CHARSET
import httpx
client = httpx.Client()
if __name__ == "__main__":
# import base64
cdn: str = "TX"
stream_name: str = "1199627305549-1199627305549-5718448156589424640-2399254734554-10057-A-0-1-imgplus.flv"
presenter_uid: int = 1199627305549
wup_url: str = "https://wup.huya.com"
huya_headers: dict = {
"user-agent": f"HYSDK(Windows, 30000002)_APP(pc_exe&6090007&official)_SDK(trans&2.24.0.5157)",
"referer": "https://www.huya.com/",
"origin": "https://www.huya.com",
}
# TupVersion3 = 3
wup_req = Wup()
# wup_req.version = TupVersion3
wup_req.requestid = abs(DEFAULT_TICKET_NUMBER)
wup_req.servant = "liveui"
wup_req.func = "getCdnTokenInfo"
token_info_req = HuyaGetCdnTokenReq()
token_info_req.cdnType = cdn
token_info_req.streamName = stream_name
token_info_req.presenterUid = presenter_uid
wup_req.put(
vtype=HuyaGetCdnTokenRsp,
name="tReq",
value=token_info_req
)
data = wup_req.encode_v3()
rsp = client.post(wup_url, data=data, headers=huya_headers)
rsp_bytes = rsp.content
wup_rsp = Wup()
wup_rsp.decode_v3(rsp_bytes)
token_info_rsp = wup_rsp.get(
vtype=HuyaGetCdnTokenRsp,
# name=bytes("tRsp", encoding=STANDARD_CHARSET)
name="tRsp"
)
print(token_info_rsp.as_dict())
+1
View File
@@ -57,6 +57,7 @@ class Wup(TarsUniPacket):
name = name.encode(STANDARD_CHARSET)
if (name in self.__new_buffer) == False:
print(self.__new_buffer)
raise Exception("UniAttribute not found key:%s" % name)
t = self.__new_buffer[name]
@@ -1,134 +0,0 @@
from biliup.common.tars import tarscore
from .StreamInfo import HuyaStreamInfo
from .MultiStreamInfo import HuyaMultiStreamInfo
class HuyaBeginLiveNotice(tarscore.struct):
__tars_class__ = "Huya.BeginLiveNotice"
def __init__(self):
self.lPresenterUid: tarscore.int64 = 0
self.iGameId: tarscore.int32 = 0
self.sGameName: tarscore.string = ""
self.iRandomRange: tarscore.int32 = 0
self.iStreamType: tarscore.int32 = 0
self.vStreamInfo: tarscore.vector = tarscore.vector(HuyaStreamInfo) # FIXME
self.vCdnList: tarscore.vector = tarscore.vector(tarscore.string) # FIXME
self.lLiveId: tarscore.int64 = 0
self.iPCDefaultBitRate: tarscore.int32 = 0
self.iWebDefaultBitRate: tarscore.int32 = 0
self.iMobileDefaultBitRate: tarscore.int32 = 0
self.lMultiStreamFlag: tarscore.int64 = 0
self.sNick: tarscore.string = ""
self.lYYId: tarscore.int64 = 0
self.lAttendeeCount: tarscore.int64 = 0
self.iCodecType: tarscore.int32 = 0
self.iScreenType: tarscore.int32 = 0
self.vMultiStreamInfo: tarscore.vector = tarscore.vector(HuyaMultiStreamInfo) # FIXME
self.sLiveDesc: tarscore.string = ""
self.lLiveCompatibleFlag: tarscore.int64 = 0
self.sAvatarUrl: tarscore.string = ""
self.iSourceType: tarscore.int32 = 0
self.sSubchannelName: tarscore.string = ""
self.sVideoCaptureUrl: tarscore.string = ""
self.iStartTime: tarscore.int32 = 0
self.lChannelId: tarscore.int64 = 0
self.lSubChannelId: tarscore.int64 = 0
self.sLocation: tarscore.string = ""
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.int64, 0, value.lPresenterUid)
oos.write(tarscore.int32, 1, value.iGameId)
oos.write(tarscore.string, 2, value.sGameName)
oos.write(tarscore.int32, 3, value.iRandomRange)
oos.write(tarscore.int32, 4, value.iStreamType)
oos.write(tarscore.vector, 5, value.vStreamInfo)
oos.write(tarscore.vector, 6, value.vCdnList)
oos.write(tarscore.int64, 7, value.lLiveId)
oos.write(tarscore.int32, 8, value.iPCDefaultBitRate)
oos.write(tarscore.int32, 9, value.iWebDefaultBitRate)
oos.write(tarscore.int32, 10, value.iMobileDefaultBitRate)
oos.write(tarscore.int64, 11, value.lMultiStreamFlag)
oos.write(tarscore.string, 12, value.sNick)
oos.write(tarscore.int64, 13, value.lYYId)
oos.write(tarscore.int64, 14, value.lAttendeeCount)
oos.write(tarscore.int32, 15, value.iCodecType)
oos.write(tarscore.int32, 16, value.iScreenType)
oos.write(tarscore.vector, 17, value.vMultiStreamInfo)
oos.write(tarscore.string, 18, value.sLiveDesc)
oos.write(tarscore.int64, 19, value.lLiveCompatibleFlag)
oos.write(tarscore.string, 20, value.sAvatarUrl)
oos.write(tarscore.int32, 21, value.iSourceType)
oos.write(tarscore.string, 22, value.sSubchannelName)
oos.write(tarscore.string, 23, value.sVideoCaptureUrl)
oos.write(tarscore.int32, 24, value.iStartTime)
oos.write(tarscore.int64, 25, value.lChannelId)
oos.write(tarscore.int64, 26, value.lSubChannelId)
oos.write(tarscore.string, 27, value.sLocation)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaBeginLiveNotice()
value.lPresenterUid = ios.read(tarscore.int64, 0, False)
value.iGameId = ios.read(tarscore.int32, 1, False)
value.sGameName = ios.read(tarscore.string, 2, False)
value.iRandomRange = ios.read(tarscore.int32, 3, False)
value.iStreamType = ios.read(tarscore.int32, 4, False)
value.vStreamInfo = ios.read(tarscore.vector, 5, False)
value.vCdnList = ios.read(tarscore.vector, 6, False)
value.lLiveId = ios.read(tarscore.int64, 7, False)
value.iPCDefaultBitRate = ios.read(tarscore.int32, 8, False)
value.iWebDefaultBitRate = ios.read(tarscore.int32, 9, False)
value.iMobileDefaultBitRate = ios.read(tarscore.int32, 10, False)
value.lMultiStreamFlag = ios.read(tarscore.int64, 11, False)
value.sNick = ios.read(tarscore.string, 12, False)
value.lYYId = ios.read(tarscore.int64, 13, False)
value.lAttendeeCount = ios.read(tarscore.int64, 14, False)
value.iCodecType = ios.read(tarscore.int32, 15, False)
value.iScreenType = ios.read(tarscore.int32, 16, False)
value.vMultiStreamInfo = ios.read(tarscore.vector, 17, False)
value.sLiveDesc = ios.read(tarscore.string, 18, False)
value.lLiveCompatibleFlag = ios.read(tarscore.int64, 19, False)
value.sAvatarUrl = ios.read(tarscore.string, 20, False)
value.iSourceType = ios.read(tarscore.int32, 21, False)
value.sSubchannelName = ios.read(tarscore.string, 22, False)
value.sVideoCaptureUrl = ios.read(tarscore.string, 23, False)
value.iStartTime = ios.read(tarscore.int32, 24, False)
value.lChannelId = ios.read(tarscore.int64, 25, False)
value.lSubChannelId = ios.read(tarscore.int64, 26, False)
value.sLocation = ios.read(tarscore.string, 27, False)
return value
def as_dict(self):
return {
"lPresenterUid": self.lPresenterUid,
"iGameId": self.iGameId,
"sGameName": self.sGameName,
"iRandomRange": self.iRandomRange,
"iStreamType": self.iStreamType,
"vStreamInfo": self.vStreamInfo,
"vCdnList": self.vCdnList,
"lLiveId": self.lLiveId,
"iPCDefaultBitRate": self.iPCDefaultBitRate,
"iWebDefaultBitRate": self.iWebDefaultBitRate,
"iMobileDefaultBitRate": self.iMobileDefaultBitRate,
"lMultiStreamFlag": self.lMultiStreamFlag,
"sNick": self.sNick,
"lYYId": self.lYYId,
"lAttendeeCount": self.lAttendeeCount,
"iCodecType": self.iCodecType,
"iScreenType": self.iScreenType,
"vMultiStreamInfo": self.vMultiStreamInfo,
"sLiveDesc": self.sLiveDesc,
"lLiveCompatibleFlag": self.lLiveCompatibleFlag,
"sAvatarUrl": self.sAvatarUrl,
"iSourceType": self.iSourceType,
"sSubchannelName": self.sSubchannelName,
"sVideoCaptureUrl": self.sVideoCaptureUrl,
"iStartTime": self.iStartTime,
"lChannelId": self.lChannelId,
"lSubChannelId": self.lSubChannelId,
"sLocation": self.sLocation
}
@@ -1,27 +0,0 @@
from biliup.common.tars import tarscore
class HuyaMultiStreamInfo(tarscore.struct):
__tars_class__ = "Huya.MultiStreamInfo"
def __init__(self):
self.sDisplayName: tarscore.string = ""
self.iBitRate: tarscore.int32 = 0
self.iCodecType: tarscore.int32 = 0
self.iCompatibleFlag: tarscore.int32 = 0
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.string, 0, value.sDisplayName)
oos.write(tarscore.int32, 1, value.iBitRate)
oos.write(tarscore.int32, 2, value.iCodecType)
oos.write(tarscore.int32, 3, value.iCompatibleFlag)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaMultiStreamInfo()
value.sDisplayName = ios.read(tarscore.string, 0, False)
value.iBitRate = ios.read(tarscore.int32, 1, False)
value.iCodecType = ios.read(tarscore.int32, 2, False)
value.iCompatibleFlag = ios.read(tarscore.int32, 3, False)
return value
@@ -1,69 +0,0 @@
from biliup.common.tars import tarscore
class HuyaStreamInfo(tarscore.struct):
__tars_class__ = "Huya.StreamInfo"
def __init__(self):
self.sCdnType: tarscore.string = ""
self.iIsMaster: tarscore.int32 = 0
self.lChannelId: tarscore.int64 = 0
self.lSubChannelId: tarscore.int64 = 0
self.lPresenterUid: tarscore.int64 = 0
self.sStreamName: tarscore.string = ""
self.sFlvUrl: tarscore.string = ""
self.sFlvUrlSuffix: tarscore.string = ""
self.sFlvAntiCode: tarscore.string = ""
self.sHlsUrl: tarscore.string = ""
self.sHlsUrlSuffix: tarscore.string = ""
self.sHlsAntiCode: tarscore.string = ""
self.iLineIndex: tarscore.int32 = 0
self.iIsMultiStream: tarscore.int32 = 0
self.iPCPriorityRate: tarscore.int32 = 0
self.iWebPriorityRate: tarscore.int32 = 0
self.iMobilePriorityRate: tarscore.int32 = 0
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.string, 0, value.sCdnType)
oos.write(tarscore.int32, 1, value.iIsMaster)
oos.write(tarscore.int64, 2, value.lChannelId)
oos.write(tarscore.int64, 3, value.lSubChannelId)
oos.write(tarscore.int64, 4, value.lPresenterUid)
oos.write(tarscore.string, 5, value.sStreamName)
oos.write(tarscore.string, 6, value.sFlvUrl)
oos.write(tarscore.string, 7, value.sFlvUrlSuffix)
oos.write(tarscore.string, 8, value.sFlvAntiCode)
oos.write(tarscore.string, 9, value.sHlsUrl)
oos.write(tarscore.string, 10, value.sHlsUrlSuffix)
oos.write(tarscore.string, 11, value.sHlsAntiCode)
oos.write(tarscore.int32, 12, value.iLineIndex)
oos.write(tarscore.int32, 13, value.iIsMultiStream)
oos.write(tarscore.int32, 14, value.iPCPriorityRate)
oos.write(tarscore.int32, 15, value.iWebPriorityRate)
oos.write(tarscore.int32, 16, value.iMobilePriorityRate)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaStreamInfo()
value.sCdnType = ios.read(tarscore.string, 0, False)
value.iIsMaster = ios.read(tarscore.int32, 1, False)
value.lChannelId = ios.read(tarscore.int64, 2, False)
value.lSubChannelId = ios.read(tarscore.int64, 3, False)
value.lPresenterUid = ios.read(tarscore.int64, 4, False)
value.sStreamName = ios.read(tarscore.string, 5, False)
value.sFlvUrl = ios.read(tarscore.string, 6, False)
value.sFlvUrlSuffix = ios.read(tarscore.string, 7, False)
value.sFlvAntiCode = ios.read(tarscore.string, 8, False)
value.sHlsUrl = ios.read(tarscore.string, 9, False)
value.sHlsUrlSuffix = ios.read(tarscore.string, 10, False)
value.sHlsAntiCode = ios.read(tarscore.string, 11, False)
value.iLineIndex = ios.read(tarscore.int32, 12, False)
value.iIsMultiStream = ios.read(tarscore.int32, 13, False)
value.iPCPriorityRate = ios.read(tarscore.int32, 14, False)
value.iWebPriorityRate = ios.read(tarscore.int32, 15, False)
value.iMobilePriorityRate = ios.read(tarscore.int32, 16, False)
return value
@@ -1,34 +0,0 @@
from biliup.common.tars import tarscore
class HuyaStreamSettingNotice(tarscore.struct):
__tars_class__ = "Huya.StreamSettingNotice"
def __init__(self):
self.lPresenterUid: tarscore.int64 = 0
self.iBitRate: tarscore.int32 = 0
self.iResolution: tarscore.int32 = 0
self.iFrameRate: tarscore.int32 = 0
self.lLiveId: tarscore.int64 = 0
self.sDisplayName: tarscore.string = ""
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
oos.write(tarscore.int64, 0, value.lPresenterUid)
oos.write(tarscore.int32, 1, value.iBitRate)
oos.write(tarscore.int32, 2, value.iResolution)
oos.write(tarscore.int32, 3, value.iFrameRate)
oos.write(tarscore.int64, 4, value.lLiveId)
oos.write(tarscore.string, 5, value.sDisplayName)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaStreamSettingNotice()
value.lPresenterUid = ios.read(tarscore.int64, 0, False)
value.iBitRate = ios.read(tarscore.int32, 1, False)
value.iResolution = ios.read(tarscore.int32, 2, False)
value.iFrameRate = ios.read(tarscore.int32, 3, False)
value.lLiveId = ios.read(tarscore.int64, 4, False)
value.sDisplayName = ios.read(tarscore.string, 5, False)
return value
+12 -6
View File
@@ -1,8 +1,10 @@
from biliup.common.tars import tarscore
from ..packet.__util import auto_decode_fields
@auto_decode_fields
class HuyaUserId(tarscore.struct):
__tars_class__ = "Huya.UserId"
__tars_class__ = "HUYA.UserId"
def __init__(self):
self.lUid: tarscore.int64 = 0
@@ -10,6 +12,9 @@ class HuyaUserId(tarscore.struct):
self.sToken: tarscore.string = ""
self.sHuYaUA: tarscore.string = ""
self.sCookie: tarscore.string = ""
self.iTokenType: tarscore.int32 = 0
self.sDeviceId: tarscore.string = ""
self.sQIMEI: tarscore.string = ""
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
@@ -18,18 +23,19 @@ class HuyaUserId(tarscore.struct):
oos.write(tarscore.string, 2, value.sToken)
oos.write(tarscore.string, 3, value.sHuYaUA)
oos.write(tarscore.string, 4, value.sCookie)
oos.write(tarscore.int32, 5, value.iTokenType)
oos.write(tarscore.string, 6, value.sDeviceId)
oos.write(tarscore.string, 7, value.sQIMEI)
@staticmethod
def readFrom(ios: tarscore.TarsInputStream):
value = HuyaUserId()
value.lUid = ios.read(tarscore.int64, 0, False)
# print(("lUid = %d" % value.lUid))
value.sGuid = ios.read(tarscore.string, 1, False)
# print(("sGuid = %s" % value.sGuid))
value.sToken = ios.read(tarscore.string, 2, False)
# print(("sToken = %s" % value.sToken))
value.sHuYaUA = ios.read(tarscore.string, 3, False)
# print(("sHuYaUA = %s" % value.sHuYaUA))
value.sCookie = ios.read(tarscore.string, 4, False)
# print(("sCookie = %s" % value.sCookie))
value.iTokenType = ios.read(tarscore.int32, 5, False)
value.sDeviceId = ios.read(tarscore.string, 6, False)
value.sQIMEI = ios.read(tarscore.string, 7, False)
return value
@@ -1,7 +1,7 @@
from biliup.common.tars import tarscore
class HuyaWSUserInfo(tarscore.struct):
__tars_class__ = "Huya.WSUserInfo"
__tars_class__ = "HUYA.WSUserInfo"
def __init__(self):
self.lUid: tarscore.int64 = 0
@@ -2,11 +2,16 @@ from biliup.common.tars import tarscore
from biliup.common.tars.__tars import BinBuffer
class HuyaWebSocketCommand(tarscore.struct):
__tars_class__ = "Huya.WebSocketCommand"
__tars_class__ = "HUYA.WebSocketCommand"
def __init__(self):
self.iCmdType: tarscore.int32 = 0
self.vData: tarscore.bytes = b''
self.lRequestId: tarscore.int64 = 0
self.traceId: tarscore.string = ""
self.iEncryptType: tarscore.int32 = 0
self.lTime: tarscore.int64 = 0
self.sMD5: tarscore.string = ""
@staticmethod
def writeTo(oos: tarscore.TarsOutputStream, value):
+2428 -1249
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -24,11 +24,11 @@
"@types/node": "^20.13.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"eslint": "^9.17.0",
"eslint-config-next": "^15.1.3",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.26",
"eslint-config-prettier": "^9.1.0",
"ncp": "^2.0.0",
"sass": "^1.87.0",
"typescript": "^5.7.2"
}
}
}