feat: add live room title

This commit is contained in:
ihmily 2024-10-28 00:36:10 +08:00
parent da09583de8
commit f0007db68e
5 changed files with 484 additions and 149 deletions

View File

@ -3,6 +3,8 @@
直播保存路径(不填则默认) =
保存文件夹是否以作者区分 =
保存文件夹是否以时间区分 =
保存文件夹是否以标题区分 =
保存文件名是否包含标题 =
视频保存格式ts|mkv|flv|mp4|mp3音频|m4a音频 = ts
原画|超清|高清|标清|流畅 = 原画
是否使用代理ip是/否) =
@ -19,7 +21,7 @@ ts录制完成后自动转为mp4格式 = 是
生成时间字幕文件 =
是否录制完成后执行bash脚本 =
bash脚本路径 =
使用代理录制的平台(逗号分隔) = tiktok, afreecatv, pandalive, winktv, flextv, popkontv, twitch, liveme, showroom, chzzk
使用代理录制的平台(逗号分隔) = tiktok, afreecatv, soop, pandalive, winktv, flextv, popkontv, twitch, liveme, showroom, chzzk
额外使用代理录制的平台(逗号分隔) =
[推送配置]

193
demo.py Normal file
View File

@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
from douyinliverecorder.logger import logger
from douyinliverecorder import spider
# 以下示例直播间链接不保证时效性,请自行查看链接是否能正常访问
LIVE_STREAM_CONFIG = {
"douyin": {
"url": "https://live.douyin.com/745964462470",
"func": spider.get_douyin_app_stream_data,
},
"tiktok": {
"url": "https://www.tiktok.com/@pearlgaga88/live",
"func": spider.get_tiktok_stream_data,
},
"kuaishou": {
"url": "https://live.kuaishou.com/u/yall1102",
"func": spider.get_kuaishou_stream_data,
},
"huya": {
"url": "https://www.huya.com/116",
"func": spider.get_huya_app_stream_url,
},
"douyu": {
"url": "https://www.douyu.com/topic/wzDBLS6?rid=4921614&dyshid=",
"func": spider.get_douyu_info_data,
},
"yy": {
"url": "https://www.yy.com/22490906/22490906",
"func": spider.get_yy_stream_data,
},
"bilibili": {
"url": "https://live.bilibili.com/21593109",
"func": spider.get_bilibili_stream_data,
},
"xhs": {
"url": "http://xhslink.com/O9f9fM",
"func": spider.get_xhs_stream_url,
},
"bigo": {
"url": "https://www.bigo.tv/cn/716418802",
"func": spider.get_bigo_stream_url,
},
"blued": {
"url": "https://app.blued.cn/live?id=Mp6G2R",
"func": spider.get_blued_stream_url,
},
"afreecatv": {
"url": "https://play.afreecatv.com/sw7love",
"func": spider.get_afreecatv_stream_data,
},
"soop": {
"url": "https://play.sooplive.co.kr/sw7love",
"func": spider.get_afreecatv_stream_data,
},
"netease": {
"url": "https://cc.163.com/583946984",
"func": spider.get_netease_stream_data,
},
"qiandurebo": {
"url": "https://qiandurebo.com/web/video.php?roomnumber=33333",
"func": spider.get_qiandurebo_stream_data,
},
"pandatv": {
"url": "https://www.pandalive.co.kr/live/play/bara0109",
"func": spider.get_pandatv_stream_data,
},
"maoerfm": {
"url": "https://fm.missevan.com/live/868895007",
"func": spider.get_maoerfm_stream_url,
},
"winktv": {
"url": "https://www.winktv.co.kr/live/play/anjer1004",
"func": spider.get_winktv_stream_data,
},
"flextv": {
"url": "https://www.flextv.co.kr/channels/593127/live",
"func": spider.get_flextv_stream_data,
},
"looklive": {
"url": "https://look.163.com/live?id=65108820&position=3",
"func": spider.get_looklive_stream_url,
},
"popkontv": {
"url": "https://www.popkontv.com/live/view?castId=wjfal007&partnerCode=P-00117",
"func": spider.get_popkontv_stream_url,
},
"twitcasting": {
"url": "https://twitcasting.tv/c:uonq",
"func": spider.get_twitcasting_stream_url,
},
"baidu": {
"url": "https://live.baidu.com/m/media/pclive/pchome/live.html?room_id=9175031377&tab_category",
"func": spider.get_baidu_stream_data,
},
"weibo": {
"url": "https://weibo.com/u/7849520225",
"func": spider.get_weibo_stream_data,
},
"kugou": {
"url": "https://fanxing2.kugou.com/50428671?refer=2177&sourceFrom=",
"func": spider.get_kugou_stream_url,
},
"twitchtv": {
"url": "https://www.twitch.tv/gamerbee",
"func": spider.get_twitchtv_stream_data,
},
"liveme": {
"url": "https://www.liveme.com/zh/v/17141937295821012854/index.html",
"func": spider.get_liveme_stream_url,
},
"huajiao": {
"url": "https://www.huajiao.com/user/207446325",
"func": spider.get_huajiao_stream_url,
},
"showroom": {
"url": "https://www.showroom-live.com/room/profile?room_id=511033",
"func": spider.get_showroom_stream_data,
},
"acfun": {
"url": "https://live.acfun.cn/live/17912421",
"func": spider.get_acfun_stream_data,
},
"changliao": {
"url": "https://www.tlclw.com/801044397",
"func": spider.get_changliao_stream_url,
},
"yingke": {
"url": "https://www.inke.cn/liveroom/index.html?uid=710032101&id=1720857535354099",
"func": spider.get_yingke_stream_url,
},
"yinbo": {
"url": "https://live.ybw1666.com/800008687",
"func": spider.get_yinbo_stream_url,
},
"zhihu": {
"url": "https://www.zhihu.com/theater/114453",
"func": spider.get_zhihu_stream_url,
},
"chzzk": {
"url": "https://chzzk.naver.com/live/458f6ec20b034f49e0fc6d03921646d2",
"func": spider.get_chzzk_stream_data,
},
"haixiu": {
"url": "https://www.haixiutv.com/6095106",
"func": spider.get_haixiu_stream_url,
},
"vvxqiu": {
"url": "https://h5webcdn-pro.vvxqiu.com//activity/videoShare/videoShare.html?h5Server=https://h5p.vvxqiu.com"
"&roomId=LP115924473&platformId=vvstar",
"func": spider.get_vvxqiu_stream_url,
},
"17live": {
"url": "https://17.live/en/live/6302408",
"func": spider.get_17live_stream_url,
},
"langlive": {
"url": "https://www.lang.live/en-US/room/3349463",
"func": spider.get_langlive_stream_url,
},
"pplive": {
"url": "https://m.pp.weimipopo.com/live/preview.html?uid=91648673&anchorUid=91625862&app=plpl",
"func": spider.get_pplive_stream_url,
},
"6room": {
"url": "https://v.6.cn/634435",
"func": spider.get_6room_stream_url,
},
"lehai": {
"url": "https://www.lehaitv.com/8059096",
"func": spider.get_haixiu_stream_url,
},
"huamao": {
"url": "https://h.catshow168.com/live/preview.html?uid=19066357&anchorUid=18895331",
"func": spider.get_pplive_stream_url,
}
}
def test_live_stream(platform_name: str, proxy_addr=None) -> None:
if platform_name in LIVE_STREAM_CONFIG:
config = LIVE_STREAM_CONFIG[platform_name]
try:
stream_data = config['func'](config['url'], proxy_addr=proxy_addr)
logger.debug(f"Stream data for {platform_name}: {stream_data}")
except Exception as e:
logger.error(f"Error fetching stream data for {platform_name}: {e}")
else:
logger.warning(f"No configuration found for platform: {platform_name}")
if __name__ == "__main__":
platform = "douyin"
test_live_stream(platform)

View File

@ -4,7 +4,7 @@
Author: Hmily
GitHub: https://github.com/ihmily
Date: 2023-07-15 23:15:00
Update: 2024-10-16 23:28:12
Update: 2024-10-28 00:32:16
Copyright (c) 2023-2024 by Hmily, All Rights Reserved.
Function: Get live stream data.
"""
@ -32,7 +32,6 @@ from .logger import script_path
from .room import get_sec_user_id, get_unique_id
from . import JS_SCRIPT_PATH
no_proxy_handler = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(no_proxy_handler)
@ -176,7 +175,16 @@ def get_douyin_app_stream_data(url: str, proxy_addr: Union[str, None] = None, co
headers['Cookie'] = cookies
def get_app_data(room_id, sec_uid):
api2 = f'https://webcast.amemv.com/webcast/room/reflow/info/?verifyFp=verify_lxj5zv70_7szNlAB7_pxNY_48Vh_ALKF_GA1Uf3yteoOY&type_id=0&live_id=1&room_id={room_id}&sec_user_id={sec_uid}&version_code=99.99.99&app_id=1128'
app_params = {
"verifyFp": "verify_lxj5zv70_7szNlAB7_pxNY_48Vh_ALKF_GA1Uf3yteoOY",
"type_id": "0",
"live_id": "1",
"room_id": room_id,
"sec_user_id": sec_uid,
"version_code": "99.99.99",
"app_id": "1128"
}
api2 = f'https://webcast.amemv.com/webcast/room/reflow/info/?{urllib.parse.urlencode(app_params)}'
json_str2 = get_req(url=api2, proxy_addr=proxy_addr, headers=headers)
json_data2 = json.loads(json_str2)['data']
room_data2 = json_data2['room']
@ -187,7 +195,20 @@ def get_douyin_app_stream_data(url: str, proxy_addr: Union[str, None] = None, co
web_rid = url.split('?')[0].split('live.douyin.com/')
if len(web_rid) > 1:
web_rid = web_rid[1]
api = f'https://live.douyin.com/webcast/room/web/enter/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&language=zh-CN&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=116.0.0.0&web_rid={web_rid}'
params = {
"aid": "6383",
"app_name": "douyin_web",
"live_id": "1",
"device_platform": "web",
"language": "zh-CN",
"browser_language": "zh-CN",
"browser_platform": "Win32",
"browser_name": "Chrome",
"browser_version": "116.0.0.0",
"web_rid": web_rid
}
api = f'https://live.douyin.com/webcast/room/web/enter/?{urllib.parse.urlencode(params)}'
json_str = get_req(url=api, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)['data']
room_data = json_data['data'][0]
@ -288,7 +309,7 @@ def get_douyin_stream_data(url: str, proxy_addr: Union[str, None] = None, cookie
def get_tiktok_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.79',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
'Cookie': 'ttwid=1%7CM-rF193sJugKuNz2RGNt-rh6pAAR9IMceUSzlDnPCNI%7C1683274418%7Cf726d4947f2fc37fecc7aeb0cdaee52892244d04efde6f8a8edd2bb168263269; tiktok_webapp_theme=light; tt_chain_token=VWkygAWDlm1cFg/k8whmOg==; passport_csrf_token=6e422c5a7991f8cec7033a8082921510; passport_csrf_token_default=6e422c5a7991f8cec7033a8082921510; d_ticket=f8c267d4af4523c97be1ccb355e9991e2ae06; odin_tt=320b5f386cdc23f347be018e588873db7f7aea4ea5d1813681c3fbc018ea025dde957b94f74146dbc0e3612426b865ccb95ec8abe4ee36cca65f15dbffec0deff7b0e69e8ea536d46e0f82a4fc37d211; cmpl_token=AgQQAPNSF-RO0rT04baWtZ0T_jUjl4fVP4PZYM2QPw; uid_tt=319b558dbba684bb1557206c92089cd113a875526a89aee30595925d804b81c7; uid_tt_ss=319b558dbba684bb1557206c92089cd113a875526a89aee30595925d804b81c7; sid_tt=ad5e736f4bedb2f6d42ccd849e706b1d; sessionid=ad5e736f4bedb2f6d42ccd849e706b1d; sessionid_ss=ad5e736f4bedb2f6d42ccd849e706b1d; store-idc=useast5; store-country-code=us; store-country-code-src=uid; tt-target-idc=useast5; tt-target-idc-sign=qXNk0bb1pDQ0FbCNF120Pl9WWMLZg9Edv5PkfyCbS4lIk5ieW5tfLP7XWROnN0mEaSlc5hg6Oji1pF-yz_3ZXnUiNMrA9wNMPvI6D9IFKKVmq555aQzwPIGHv0aQC5dNRgKo5Z5LBkgxUMWEojTKclq2_L8lBciw0IGdhFm_XyVJtbqbBKKgybGDLzK8ZyxF4Jl_cYRXaDlshZjc38JdS6wruDueRSHe7YvNbjxCnApEFUv-OwJANSPU_4rvcqpVhq3JI2VCCfw-cs_4MFIPCDOKisk5EhAo2JlHh3VF7_CLuv80FXg_7ZqQ2pJeMOog294rqxwbbQhl3ATvjQV_JsWyUsMd9zwqecpylrPvtySI2u1qfoggx1owLrrUynee1R48QlanLQnTNW_z1WpmZBgVJqgEGLwFoVOmRzJuFFNj8vIqdjM2nDSdWqX8_wX3wplohkzkPSFPfZgjzGnQX28krhgTytLt7BXYty5dpfGtsdb11WOFHM6MZ9R9uLVB; sid_guard=ad5e736f4bedb2f6d42ccd849e706b1d%7C1690990657%7C15525213%7CMon%2C+29-Jan-2024+08%3A11%3A10+GMT; sid_ucp_v1=1.0.0-KGM3YzgwYjZhODgyYWI1NjIwNTA0NjBmOWUxMGRhMjIzYTI2YjMxNDUKGAiqiJ30keKD5WQQwfCppgYYsws4AkDsBxAEGgd1c2Vhc3Q1IiBhZDVlNzM2ZjRiZWRiMmY2ZDQyY2NkODQ5ZTcwNmIxZA; ssid_ucp_v1=1.0.0-KGM3YzgwYjZhODgyYWI1NjIwNTA0NjBmOWUxMGRhMjIzYTI2YjMxNDUKGAiqiJ30keKD5WQQwfCppgYYsws4AkDsBxAEGgd1c2Vhc3Q1IiBhZDVlNzM2ZjRiZWRiMmY2ZDQyY2NkODQ5ZTcwNmIxZA; tt_csrf_token=dD0EIH8q-pe3qDQsCyyD1jLN6KizJDRjOEyk; __tea_cache_tokens_1988={%22_type_%22:%22default%22%2C%22user_unique_id%22:%227229608516049831425%22%2C%22timestamp%22:1683274422659}; ttwid=1%7CM-rF193sJugKuNz2RGNt-rh6pAAR9IMceUSzlDnPCNI%7C1694002151%7Cd89b77afc809b1a610661a9d1c2784d80ebef9efdd166f06de0d28e27f7e4efe; msToken=KfJAVZ7r9D_QVeQlYAUZzDFbc1Yx-nZz6GF33eOxgd8KlqvTg1lF9bMXW7gFV-qW4MCgUwnBIhbiwU9kdaSpgHJCk-PABsHCtTO5J3qC4oCTsrXQ1_E0XtbqiE4OVLZ_jdF1EYWgKNPT2SnwGkQ=; msToken=KfJAVZ7r9D_QVeQlYAUZzDFbc1Yx-nZz6GF33eOxgd8KlqvTg1lF9bMXW7gFV-qW4MCgUwnBIhbiwU9kdaSpgHJCk-PABsHCtTO5J3qC4oCTsrXQ1_E0XtbqiE4OVLZ_jdF1EYWgKNPT2SnwGkQ='
}
if cookies:
@ -337,7 +358,7 @@ def get_kuaishou_stream_data(url: str, proxy_addr: Union[str, None] = None, cook
result = {"type": 2, "is_live": False}
if 'errorType' in play_list or 'liveStream' not in play_list:
error_msg = play_list.get('errorType', {}).get('title', '') + play_list.get('errorType', {}).get('content', '')
error_msg = play_list['errorType']['title'] + play_list['errorType']['content']
print(f'失败地址:{url} 错误信息: {error_msg}')
return result
@ -359,7 +380,7 @@ def get_kuaishou_stream_data(url: str, proxy_addr: Union[str, None] = None, cook
def get_kuaishou_stream_data2(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Referer': "https://www.kuaishou.com/short-video/3x224rwabjmuc9y?fid=1712760877&cc=share_copylink&followRefer=151&shareMethod=TOKEN&docId=9&kpn=KUAISHOU&subBiz=BROWSE_SLIDE_PHOTO&photoId=3x224rwabjmuc9y&shareId=17144298796566&shareToken=X-6FTMeYTsY97qYL&shareResourceType=PHOTO_OTHER&userId=3xtnuitaz2982eg&shareType=1&et=1_i/2000048330179867715_h3052&shareMode=APP&originShareId=17144298796566&appType=21&shareObjectId=5230086626478274600&shareUrlOpened=0&timestamp=1663833792288&utm_source=app_share&utm_medium=app_share&utm_campaign=app_share&location=app_share",
'content-type': 'application/json',
@ -421,7 +442,7 @@ def get_huya_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies:
def get_huya_app_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003137) NetType/WIFI Language/zh_CN WeChat/8.0.49.33 CFNetwork/1474 Darwin/23.0.0',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'xweb_xhr': '1',
'referer': 'https://servicewechat.com/wx74767bf0b684f7d3/301/page-frame.html',
'accept-language': 'zh-CN,zh;q=0.9',
@ -450,6 +471,7 @@ def get_huya_app_stream_url(url: str, proxy_addr: Union[str, None] = None, cooki
json_data = json.loads(json_str)
anchor_name = json_data['data']['profileInfo']['nick']
live_status = json_data['data']['realLiveStatus']
live_title = json_data['data']['liveData']['introduction']
if live_status != 'ON':
return {'anchor_name': anchor_name, 'is_live': False}
else:
@ -483,6 +505,7 @@ def get_huya_app_stream_url(url: str, proxy_addr: Union[str, None] = None, cooki
'm3u8_url': play_url_list[0]['m3u8_url'],
'flv_url': play_url_list[0]['flv_url'],
'record_url': record_url,
'title': live_title
}
@ -491,14 +514,7 @@ def md5(data):
def get_token_js(rid: str, did: str, proxy_addr: Union[str, None] = None) -> Union[list, Dict[str, Any]]:
"""
通过PC网页端的接口获取完整直播源
:param proxy_addr:
:param did:
:param rid:
:param cdn: 主线路ws-h5备用线路tct-h5
:param rate: 1流畅2高清3超清4蓝光4M0蓝光8M或10M
"""
url = f'https://www.douyu.com/{rid}'
html_str = get_req(url=url, proxy_addr=proxy_addr)
result = re.search(r'(vdwdae325w_64we[\s\S]*function ub98484234[\s\S]*?)function', html_str).group(1)
@ -524,7 +540,7 @@ def get_token_js(rid: str, did: str, proxy_addr: Union[str, None] = None) -> Uni
def get_douyu_info_data(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> Dict[
str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Referer': 'https://m.douyu.com/3125893?rid=3125893&dyshid=0-96003918aa5365bc6dcb4933000316p1&dyshci=181',
'Cookie': 'dy_did=413b835d2ae00270f0c69f6400031601; acf_did=413b835d2ae00270f0c69f6400031601; Hm_lvt_e99aee90ec1b2106afe7ec3b199020a7=1692068308,1694003758; m_did=96003918aa5365bc6dcb4933000316p1; dy_teen_mode=%7B%22uid%22%3A%22472647365%22%2C%22status%22%3A0%2C%22birthday%22%3A%22%22%2C%22password%22%3A%22%22%7D; PHPSESSID=td59qi2fu2gepngb8mlehbeme3; acf_auth=94fc9s%2FeNj%2BKlpU%2Br8tZC3Jo9sZ0wz9ClcHQ1akL2Nhb6ZyCmfjVWSlR3LFFPuePWHRAMo0dt9vPSCoezkFPOeNy4mYcdVOM1a8CbW0ZAee4ipyNB%2Bflr58; dy_auth=bec5yzM8bUFYe%2FnVAjmUAljyrsX%2FcwRW%2FyMHaoArYb5qi8FS9tWR%2B96iCzSnmAryLOjB3Qbeu%2BBD42clnI7CR9vNAo9mva5HyyL41HGsbksx1tEYFOEwxSI; wan_auth37wan=5fd69ed5b27fGM%2FGoswWwDo%2BL%2FRMtnEa4Ix9a%2FsH26qF0sR4iddKMqfnPIhgfHZUqkAk%2FA1d8TX%2B6F7SNp7l6buIxAVf3t9YxmSso8bvHY0%2Fa6RUiv8; acf_uid=472647365; acf_username=472647365; acf_nickname=%E7%94%A8%E6%88%B776576662; acf_own_room=0; acf_groupid=1; acf_phonestatus=1; acf_avatar=https%3A%2F%2Fapic.douyucdn.cn%2Fupload%2Favatar%2Fdefault%2F24_; acf_ct=0; acf_ltkid=25305099; acf_biz=1; acf_stk=90754f8ed18f0c24; Hm_lpvt_e99aee90ec1b2106afe7ec3b199020a7=1694003778'
}
@ -542,7 +558,7 @@ def get_douyu_info_data(url: str, proxy_addr: Union[str, None] = None, cookies:
rid = json_data['pageProps']['room']['roomInfo']['roomInfo']['rid']
headers[
'User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0'
'User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0'
url2 = f'https://www.douyu.com/betard/{rid}'
json_str = get_req(url=url2, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
@ -551,9 +567,9 @@ def get_douyu_info_data(url: str, proxy_addr: Union[str, None] = None, cookies:
"is_live": False
}
if json_data['room']['videoLoop'] == 0 and json_data['room']['show_status'] == 1:
result["title"] = json_data['room']['room_name'].replace(' ', '')
result["is_live"] = True
result["room_id"] = json_data['room']['room_id']
return result
@ -563,7 +579,7 @@ def get_douyu_stream_data(rid: str, rate: str = '-1', proxy_addr: Union[str, Non
did = '10000000000000000000000000003306'
params_list = get_token_js(rid, did, proxy_addr=proxy_addr)
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Referer': 'https://m.douyu.com/3125893?rid=3125893&dyshid=0-96003918aa5365bc6dcb4933000316p1&dyshci=181',
'Cookie': 'dy_did=413b835d2ae00270f0c69f6400031601; acf_did=413b835d2ae00270f0c69f6400031601; Hm_lvt_e99aee90ec1b2106afe7ec3b199020a7=1692068308,1694003758; m_did=96003918aa5365bc6dcb4933000316p1; dy_teen_mode=%7B%22uid%22%3A%22472647365%22%2C%22status%22%3A0%2C%22birthday%22%3A%22%22%2C%22password%22%3A%22%22%7D; PHPSESSID=td59qi2fu2gepngb8mlehbeme3; acf_auth=94fc9s%2FeNj%2BKlpU%2Br8tZC3Jo9sZ0wz9ClcHQ1akL2Nhb6ZyCmfjVWSlR3LFFPuePWHRAMo0dt9vPSCoezkFPOeNy4mYcdVOM1a8CbW0ZAee4ipyNB%2Bflr58; dy_auth=bec5yzM8bUFYe%2FnVAjmUAljyrsX%2FcwRW%2FyMHaoArYb5qi8FS9tWR%2B96iCzSnmAryLOjB3Qbeu%2BBD42clnI7CR9vNAo9mva5HyyL41HGsbksx1tEYFOEwxSI; wan_auth37wan=5fd69ed5b27fGM%2FGoswWwDo%2BL%2FRMtnEa4Ix9a%2FsH26qF0sR4iddKMqfnPIhgfHZUqkAk%2FA1d8TX%2B6F7SNp7l6buIxAVf3t9YxmSso8bvHY0%2Fa6RUiv8; acf_uid=472647365; acf_username=472647365; acf_nickname=%E7%94%A8%E6%88%B776576662; acf_own_room=0; acf_groupid=1; acf_phonestatus=1; acf_avatar=https%3A%2F%2Fapic.douyucdn.cn%2Fupload%2Favatar%2Fdefault%2F24_; acf_ct=0; acf_ltkid=25305099; acf_biz=1; acf_stk=90754f8ed18f0c24; Hm_lpvt_e99aee90ec1b2106afe7ec3b199020a7=1694003778'
}
@ -605,13 +621,51 @@ def get_yy_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies: U
data = '{"head":{"seq":1701869217590,"appidstr":"0","bidstr":"121","cidstr":"' + cid + '","sidstr":"' + cid + '","uid64":0,"client_type":108,"client_ver":"5.17.0","stream_sys_ver":1,"app":"yylive_web","playersdk_ver":"5.17.0","thundersdk_ver":"0","streamsdk_ver":"5.17.0"},"client_attribute":{"client":"web","model":"web0","cpu":"","graphics_card":"","os":"chrome","osversion":"0","vsdk_version":"","app_identify":"","app_version":"","business":"","width":"1920","height":"1080","scale":"","client_type":8,"h265":0},"avp_parameter":{"version":1,"client_type":8,"service_type":0,"imsi":0,"send_time":1701869217,"line_seq":-1,"gear":4,"ssl":1,"stream_format":0}}'
data_bytes = data.encode('utf-8')
url2 = f'https://stream-manager.yy.com/v3/channel/streams?uid=0&cid={cid}&sid={cid}&appid=0&sequence=1701869217590&encode=json'
params = {
"uid": "0",
"cid": cid,
"sid": cid,
"appid": "0",
"sequence": "1701869217590",
"encode": "json"
}
url2 = f'https://stream-manager.yy.com/v3/channel/streams?{urllib.parse.urlencode(params)}'
json_str = get_req(url=url2, data=data_bytes, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
json_data['anchor_name'] = anchor_name
params = {
'uid': '',
'sid': cid,
'ssid': cid,
'_': int(time.time() * 1000),
}
detail_api = f'https://www.yy.com/live/detail?{urllib.parse.urlencode(params)}'
json_str2 = get_req(detail_api, proxy_addr=proxy_addr, headers=headers)
json_data2 = json.loads(json_str2)
json_data['title'] = json_data2['data']['roomName']
return json_data
@trace_error_decorator
def get_bilibili_room_info_h5(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
str:
headers = {
'origin': 'https://live.bilibili.com',
'referer': 'https://live.bilibili.com/',
'user-agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
}
if cookies:
headers['Cookie'] = cookies
room_id = url.split('?')[0].rsplit('/', maxsplit=1)[1]
api = f'https://api.live.bilibili.com/xlive/web-room/v1/index/getH5InfoByRoom?room_id={room_id}'
json_str = get_req(api, proxy_addr=proxy_addr, headers=headers)
room_info = json.loads(json_str)
title = room_info['data']['room_info']['title']
return title
@trace_error_decorator
def get_bilibili_room_info(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
@ -635,7 +689,9 @@ def get_bilibili_room_info(url: str, proxy_addr: Union[str, None] = None, cookie
json_str2 = get_req(url=api, proxy_addr=proxy_addr, headers=headers)
anchor_info = json.loads(json_str2)
anchor_name = anchor_info['data']['info']['uname']
return {"anchor_name": anchor_name, "live_status": live_status, "room_url": url}
title = get_bilibili_room_info_h5(url, proxy_addr, cookies)
return {"anchor_name": anchor_name, "live_status": live_status, "room_url": url, "title": title}
except Exception as e:
print(e)
return {"anchor_name": '', "live_status": False, "room_url": url}
@ -730,12 +786,14 @@ def get_xhs_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: U
json_str = get_req(api, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
anchor_name = json_data['data']['host_info']['nickname']
live_title = json_data['data']['room']['name']
live_status = json_data['data']['room']['status']
result["anchor_name"] = anchor_name
# 这个判断不准确无论是否在直播status都为0
if live_status == 0:
result['is_live'] = True
result['title'] = live_title
flv_url = f'http://live-play.xhscdn.com/live/{room_id}.flv'
result['flv_url'] = flv_url
result['record_url'] = flv_url
@ -801,6 +859,8 @@ def get_bigo_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies:
}
if live_status == 1:
live_title = json_data['data']['roomTopic']
result['title'] = live_title
m3u8_url = json_data['data']['hls_src']
result['m3u8_url'] = m3u8_url
result['is_live'] = True
@ -816,7 +876,7 @@ def get_bigo_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies:
def get_blued_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
}
@ -1013,26 +1073,26 @@ def get_afreecatv_stream_data(
play_url_list.append(url_prefix + i.strip())
bandwidth_pattern = re.compile(r'BANDWIDTH=(\d+)')
bandwidth_list = bandwidth_pattern.findall(resp)
url_to_bandwidth = {url: int(bandwidth) for bandwidth, url in zip(bandwidth_list, play_url_list)}
play_url_list = sorted(play_url_list, key=lambda url: url_to_bandwidth[url], reverse=True)
url_to_bandwidth = {purl: int(bandwidth) for bandwidth, purl in zip(bandwidth_list, play_url_list)}
play_url_list = sorted(play_url_list, key=lambda purl: url_to_bandwidth[purl], reverse=True)
return play_url_list
if not anchor_name:
def handle_login():
cookie = login_afreecatv(username, password, proxy_addr=proxy_addr)
if 'PdboxBbs=' in cookie:
if 'AuthTicket=' in cookie:
print('SOOP[AfreecaTV]平台登录成功!开始获取直播数据...')
return cookie
def fetch_data(cookie):
aid_token = get_afreecatv_tk(url, rtype='aid', proxy_addr=proxy_addr, cookies=cookie)
anchor_name, broad_no = get_afreecatv_tk(url, rtype='info', proxy_addr=proxy_addr, cookies=cookie)
view_url = get_afreecatv_cdn_url(broad_no, proxy_addr=proxy_addr)['view_url']
m3u8_url = view_url + '?aid=' + aid_token
result['anchor_name'] = anchor_name
result['m3u8_url'] = m3u8_url
_anchor_name, _broad_no = get_afreecatv_tk(url, rtype='info', proxy_addr=proxy_addr, cookies=cookie)
_view_url = get_afreecatv_cdn_url(_broad_no, proxy_addr=proxy_addr)['view_url']
_m3u8_url = _view_url + '?aid=' + aid_token
result['anchor_name'] = _anchor_name
result['m3u8_url'] = _m3u8_url
result['is_live'] = True
result['play_url_list'] = get_url_list(m3u8_url)
result['play_url_list'] = get_url_list(_m3u8_url)
result['new_cookies'] = cookie
return result
@ -1076,7 +1136,7 @@ def get_netease_stream_data(url: str, proxy_addr: Union[str, None] = None, cooki
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://cc.163.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1093,8 +1153,9 @@ def get_netease_stream_data(url: str, proxy_addr: Union[str, None] = None, cooki
result["anchor_name"] = room_data['nickname']
else:
result["anchor_name"] = live_data['nickname']
result["stream_list"] = live_data['quickplay']
result["is_live"] = True
result["title"] = live_data['title']
result["stream_list"] = live_data['quickplay']
return result
@ -1102,10 +1163,11 @@ def get_netease_stream_data(url: str, proxy_addr: Union[str, None] = None, cooki
def get_qiandurebo_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,'
'application/signed-exchange;v=b3;q=0.7',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://qiandurebo.com/web/index.php',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1133,7 +1195,7 @@ def get_pandatv_stream_data(url: str, proxy_addr: Union[str, None] = None, cooki
headers = {
'origin': 'https://www.pandalive.co.kr',
'referer': 'https://www.pandalive.co.kr/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1186,8 +1248,7 @@ def get_maoerfm_stream_url(url: str, proxy_addr: Union[str, None] = None, cookie
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://fm.missevan.com/live/868895007',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1211,6 +1272,7 @@ def get_maoerfm_stream_url(url: str, proxy_addr: Union[str, None] = None, cookie
stream_list = json_data['info']['room']['channel']
m3u8_url = stream_list['hls_pull_url']
flv_url = stream_list['flv_pull_url']
result['title'] = json_data['info']['room']['name']
result['m3u8_url'] = m3u8_url
result['flv_url'] = flv_url
result['is_live'] = True
@ -1226,7 +1288,7 @@ def get_winktv_bj_info(url: str, proxy_addr: Union[str, None] = None, cookies: U
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'content-type': 'application/x-www-form-urlencoded',
'referer': 'https://www.winktv.co.kr/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1254,7 +1316,7 @@ def get_winktv_stream_data(url: str, proxy_addr: Union[str, None] = None, cookie
'content-type': 'application/x-www-form-urlencoded',
'referer': 'https://www.winktv.co.kr',
'origin': 'https://www.winktv.co.kr',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
@ -1297,7 +1359,7 @@ def login_flextv(username: str, password: str, proxy_addr: Union[str, None] = No
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'content-type': 'application/json;charset=UTF-8',
'referer': 'https://www.flextv.co.kr/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
data = {
@ -1347,7 +1409,7 @@ def get_flextv_stream_url(
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://www.flextv.co.kr/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
user_id = url.split('/live')[0].rsplit('/', maxsplit=1)[-1]
if cookie:
@ -1387,7 +1449,7 @@ def get_flextv_stream_data(
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://www.flextv.co.kr/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1436,23 +1498,23 @@ def get_looklive_secret_data(text):
charset = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-=[]{}|;:,.<>?'
return ''.join(secrets.choice(charset) for _ in range(size)).encode('utf-8')
def aes_encrypt(text: Union[str, bytes], seckey: Union[str, bytes]) -> bytes:
if isinstance(text, str):
text = text.encode('utf-8')
if isinstance(seckey, str):
seckey = seckey.encode('utf-8')
seckey = seckey[:16] # 16 (AES-128), 24 (AES-192), or 32 (AES-256) bytes
def aes_encrypt(_text: Union[str, bytes], _sec_key: Union[str, bytes]) -> bytes:
if isinstance(_text, str):
_text = _text.encode('utf-8')
if isinstance(_sec_key, str):
_sec_key = _sec_key.encode('utf-8')
_sec_key = _sec_key[:16] # 16 (AES-128), 24 (AES-192), or 32 (AES-256) bytes
iv = bytes('0102030405060708', 'utf-8')
encryptor = AES.new(seckey, AES.MODE_CBC, iv)
padded_text = pad(text, AES.block_size)
encryptor = AES.new(_sec_key, AES.MODE_CBC, iv)
padded_text = pad(_text, AES.block_size)
ciphertext = encryptor.encrypt(padded_text)
encoded_ciphertext = base64.b64encode(ciphertext)
return encoded_ciphertext
def rsa_encrypt(text: Union[str, bytes], pub_key: str, mod: str) -> str:
if isinstance(text, str):
text = text.encode('utf-8')
text_reversed = text[::-1]
def rsa_encrypt(_text: Union[str, bytes], pub_key: str, mod: str) -> str:
if isinstance(_text, str):
_text = _text.encode('utf-8')
text_reversed = _text[::-1]
text_int = int(binascii.hexlify(text_reversed), 16)
encrypted_int = pow(text_int, int(pub_key, 16), int(mod, 16))
return format(encrypted_int, 'x').zfill(256)
@ -1498,6 +1560,8 @@ def get_looklive_stream_url(
print('Look直播暂时只支持音频直播不支持Look视频直播!')
else:
play_url_list = json_data['data']['roomInfo']['liveUrl']
live_title = json_data['data']['roomInfo']['title']
result["title"] = live_title
result["flv_url"] = play_url_list['httpPullUrl']
result["m3u8_url"] = play_url_list['hlsPullUrl']
result["record_url"] = play_url_list['hlsPullUrl']
@ -1514,7 +1578,7 @@ def login_popkontv(
'Authorization': 'Basic FpAhe6mh8Qtz116OENBmRddbYVirNKasktdXQiuHfm88zRaFydTsFy63tzkdZY0u',
'Content-Type': 'application/json',
'Origin': 'https://www.popkontv.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
data = {
@ -1562,7 +1626,7 @@ def get_popkontv_stream_data(
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Content-Type': 'application/json',
'Origin': 'https://www.popkontv.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1632,7 +1696,7 @@ def get_popkontv_stream_url(
'ClientKey': 'Client FpAhe6mh8Qtz116OENBmRddbYVirNKasktdXQiuHfm88zRaFydTsFy63tzkdZY0u',
'Content-Type': 'application/json',
'Origin': 'https://www.popkontv.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if access_token:
@ -1719,7 +1783,7 @@ def login_twitcasting(
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'https://twitcasting.tv/indexcaslogin.php?redir=%2Findexloginwindow.php%3Fnext%3D%252F&keep=1',
'Cookie': 'hl=zh; did=04fb08f1b15d248644f1dfa82816d323; _ga=GA1.1.1021187740.1709706998; keep=1; mfadid=yrQiEB26ruRg7mlMavABMBZWdOddzojW; _ga_X8R46Y30YM=GS1.1.1709706998.1.1.1709712274.0.0.0',
'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
}
if cookies:
@ -1778,7 +1842,7 @@ def get_twitcasting_stream_url(
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Referer': 'https://twitcasting.tv/?ch0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
anchor_id = url.split('/')[3]
@ -1789,9 +1853,10 @@ def get_twitcasting_stream_url(
def get_data(header):
html_str = get_req(url, proxy_addr=proxy_addr, headers=header)
anchor = re.search("<title>(.*?) \\(@(.*?)\\) 的直播 - Twit", html_str)
title = re.search('<meta name="twitter:title" content="(.*?)">\n\\s+<meta', html_str)
status = re.search('data-is-onlive="(.*?)"\n\\s+data-view-mode', html_str)
movie_id = re.search('data-movie-id="(.*?)" data-audience-id', html_str)
return f'{anchor.group(1).strip()}-{anchor.group(2)}-{movie_id.group(1)}', status.group(1)
return f'{anchor.group(1).strip()}-{anchor.group(2)}-{movie_id.group(1)}', status.group(1), title.group(1)
result = {"anchor_name": '', "is_live": False}
new_cookie = None
@ -1805,7 +1870,7 @@ def get_twitcasting_stream_url(
raise RuntimeError('TwitCasting登录失败,请检查配置文件中的账号密码是否正确')
print('TwitCasting 登录成功!开始获取数据...')
headers['Cookie'] = new_cookie
anchor_name, live_status = get_data(headers)
anchor_name, live_status, live_title = get_data(headers)
except AttributeError:
print('获取TwitCasting数据失败正在尝试登录...')
new_cookie = login_twitcasting(account_type=account_type, username=username, password=password,
@ -1814,7 +1879,7 @@ def get_twitcasting_stream_url(
raise RuntimeError('TwitCasting登录失败,请检查配置文件中的账号密码是否正确')
print('TwitCasting 登录成功!开始获取数据...')
headers['Cookie'] = new_cookie
anchor_name, live_status = get_data(headers)
anchor_name, live_status, live_title = get_data(headers)
result["anchor_name"] = anchor_name
if live_status == 'true':
@ -1822,6 +1887,7 @@ def get_twitcasting_stream_url(
result['m3u8_url'] = play_url
result['record_url'] = play_url
result['is_live'] = True
result['title'] = live_title
result['new_cookies'] = new_cookie
return result
@ -1833,7 +1899,7 @@ def get_baidu_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Connection': 'keep-alive',
'Referer': 'https://live.baidu.com/',
'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
}
if cookies:
headers['Cookie'] = cookies
@ -1849,16 +1915,20 @@ def get_baidu_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
'action': 'star',
'service': 'bdbox',
'osname': 'baiduboxapp',
'data': '{"data":{"room_id":"' + room_id + '","device_id":"h5-683e85bdf741bf2492586f7ca39bf465","source_type":0,"osname":"baiduboxapp"},"replay_slice":0,"nid":"","schemeParams":{"src_pre":"pc","src_suf":"other","bd_vid":"","share_uid":"","share_cuk":"","share_ecid":"","zb_tag":"","shareTaskInfo":"{\\"room_id\\":\\"9175031377\\"}","share_from":"","ext_params":"","nid":""}}',
'data': '{"data":{"room_id":"' + room_id + '","device_id":"h5-683e85bdf741bf2492586f7ca39bf465",'
'"source_type":0,"osname":"baiduboxapp"},"replay_slice":0,'
'"nid":"","schemeParams":{"src_pre":"pc","src_suf":"other",'
'"bd_vid":"","share_uid":"","share_cuk":"","share_ecid":"",'
'"zb_tag":"","shareTaskInfo":"{\\"room_id\\":\\"9175031377\\"}",'
'"share_from":"","ext_params":"","nid":""}}',
'ua': '360_740_ANDROID_0',
'bd_vid': '',
'uid': uid,
'_': str(int(time.time() * 1000)),
'callback': '__jsonp_callback_1__',
}
app_api = f'https://mbd.baidu.com/searchbox?{urllib.parse.urlencode(params)}'
jsonp_str = get_req(url=app_api, proxy_addr=proxy_addr, headers=headers)
json_data = jsonp_to_json(jsonp_str)
json_str = get_req(url=app_api, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
key = list(json_data['data'].keys())[0]
data = json_data['data'][key]
anchor_name = data['host']['name']
@ -1866,9 +1936,9 @@ def get_baidu_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
"anchor_name": anchor_name,
"is_live": False,
}
live_status = data['video']['stream']
if live_status == 1:
if data['status'] == "0":
result["is_live"] = True
live_title = data['video']['title']
play_url_list = data['video']['url_clarity_list']
url_list = []
prefix = 'https://hls.liveshow.bdstatic.com/live/'
@ -1883,6 +1953,7 @@ def get_baidu_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
if url_list:
result['play_url_list'] = url_list
result['title'] = live_title
result['is_live'] = True
return result
@ -1893,7 +1964,7 @@ def get_weibo_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
headers = {
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Cookie': 'XSRF-TOKEN=qAP-pIY5V4tO6blNOhA4IIOD; SUB=_2AkMRNMCwf8NxqwFRmfwWymPrbI9-zgzEieKnaDFrJRMxHRl-yT9kqmkhtRB6OrTuX5z9N_7qk9C3xxEmNR-8WLcyo2PM; SUBP=0033WrSXqPxfM72-Ws9jqgMF55529P9D9WWemwcqkukCduUO11o9sBqA; WBPSESS=Wk6CxkYDejV3DDBcnx2LOXN9V1LjdSTNQPMbBDWe4lO2HbPmXG_coMffJ30T-Avn_ccQWtEYFcq9fab1p5RR6PEI6w661JcW7-56BszujMlaiAhLX-9vT4Zjboy1yf2l',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}
if cookies:
headers['Cookie'] = cookies
@ -1927,9 +1998,11 @@ def get_weibo_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
if live_status == 1:
result["is_live"] = True
live_title = json_data['data']['item']['desc']
play_url_list = json_data['data']['item']['stream_info']['pull']
m3u8_url = play_url_list['live_origin_hls_url']
flv_url = play_url_list['live_origin_flv_url']
result['title'] = live_title
result['play_url_list'] = [
{"m3u8_url": m3u8_url, "flv_url": flv_url},
{"m3u8_url": m3u8_url.split('_')[0] + '.m3u8', "flv_url": flv_url.split('_')[0] + '.flv'}
@ -1980,9 +2053,9 @@ def get_kugou_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies:
'appid': '1010',
'_': str(int(time.time() * 1000)),
}
stream_api = f'https://fx1.service.kugou.com/video/pc/live/pull/mutiline/streamaddr?{urllib.parse.urlencode(params)}'
api = f'https://fx1.service.kugou.com/video/pc/live/pull/mutiline/streamaddr?{urllib.parse.urlencode(params)}'
json_str2 = get_req(url=stream_api, proxy_addr=proxy_addr, headers=headers)
json_str2 = get_req(api, proxy_addr=proxy_addr, headers=headers)
json_data2 = json.loads(json_str2)
stream_data = json_data2['data']['lines']
if stream_data:
@ -2035,7 +2108,7 @@ def get_twitchtv_room_info(url: str, token: str, proxy_addr: Union[str, None] =
def get_twitchtv_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
'Accept-Language': 'en-US',
'Referer': 'https://www.twitch.tv/',
'Client-ID': 'kimne78kx3ncx6brgo4mv6wki5h1ko',
@ -2047,7 +2120,12 @@ def get_twitchtv_stream_data(url: str, proxy_addr: Union[str, None] = None, cook
data = {
"operationName": "PlaybackAccessToken_Template",
"query": "query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, $isVod: Boolean!, $playerType: String!) { streamPlaybackAccessToken(channelName: $login, params: {platform: \"web\", playerBackend: \"mediaplayer\", playerType: $playerType}) @include(if: $isLive) { value signature authorization { isForbidden forbiddenReasonCode } __typename } videoPlaybackAccessToken(id: $vodID, params: {platform: \"web\", playerBackend: \"mediaplayer\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}",
"query": "query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, "
"$isVod: Boolean!, $playerType: String!) { streamPlaybackAccessToken(channelName: $login, "
"params: {platform: \"web\", playerBackend: \"mediaplayer\", playerType: $playerType}) @include(if: "
"$isLive) { value signature authorization { isForbidden forbiddenReasonCode } __typename "
"} videoPlaybackAccessToken(id: $vodID, params: {platform: \"web\", playerBackend: \"mediaplayer\", "
"playerType: $playerType}) @include(if: $isVod) { value signature __typename }}",
"variables": {
"isLive": True,
"login": uid,
@ -2098,17 +2176,17 @@ def get_twitchtv_stream_data(url: str, proxy_addr: Union[str, None] = None, cook
@trace_error_decorator
def get_liveme_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'origin': 'https://www.liveme.com',
'referer': 'https://www.liveme.com',
'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36',
'user-agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
}
if cookies:
headers['Cookie'] = cookies
room_id = url.split("/index.html")[0].rsplit('/', maxsplit=1)[-1]
sign_data = execjs.compile(open(f'{JS_SCRIPT_PATH}/liveme.js').read()).call('sign', room_id, f'{JS_SCRIPT_PATH}/crypto-js.min.js')
sign_data = execjs.compile(open(f'{JS_SCRIPT_PATH}/liveme.js').read()).call('sign', room_id,
f'{JS_SCRIPT_PATH}/crypto-js.min.js')
lm_s_sign = sign_data.pop("lm_s_sign")
tongdun_black_box = sign_data.pop("tongdun_black_box")
platform = sign_data.pop("os")
@ -2144,7 +2222,7 @@ def get_huajiao_sn(url: str, cookies: Union[str, None] = None, proxy_addr: Union
headers = {
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://www.huajiao.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
@ -2170,7 +2248,7 @@ def get_huajiao_user_info(url: str, cookies: Union[str, None] = None, proxy_addr
headers = {
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://www.huajiao.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
@ -2205,17 +2283,43 @@ def get_huajiao_user_info(url: str, cookies: Union[str, None] = None, proxy_addr
return '未知直播间', None
def get_huajiao_stream_url_app(url: str, proxy_addr: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'living/9.4.0 (com.huajiao.seeding; build:2410231746; iOS 17.0.0) Alamofire/9.4.0',
'accept-language': 'zh-Hans-US;q=1.0',
'sdk_version': '1',
}
room_id = url.rsplit('/', maxsplit=1)[1]
api = f'https://live.huajiao.com/feed/getFeedInfo?relateid={room_id}'
json_str = get_req(api, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
result = {"anchor_name": "", "is_live": False}
if not json_data.get('data'):
print('获取直播间数据失败,花椒直播间地址是非固定的,请手动更换地址进行录制')
return result
result["is_live"] = True
result['anchor_name'] = json_data['data']['feed']['title']
play_url = f'https://al2-flv.live.huajiao.com/live_huajiao_h265/{json_data["data"]["feed"]["sn"]}.flv'
result['flv_url'] = play_url
result['record_url'] = play_url
return result
@trace_error_decorator
def get_huajiao_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'referer': 'https://www.huajiao.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
headers['Cookie'] = cookies
if '/user' not in url:
return get_huajiao_stream_url_app(url, proxy_addr)
anchor_name, room_info = get_huajiao_user_info(url)
result = {"anchor_name": anchor_name, "is_live": False}
@ -2246,14 +2350,19 @@ def get_liuxing_stream_url(url: str, proxy_addr: Union[str, None] = None, cookie
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Referer': 'https://wap.7u66.com/198189?promoters=0',
'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
}
if cookies:
headers['Cookie'] = cookies
room_id = url.split('?')[0].rsplit('/', maxsplit=1)[1]
api = f'https://wap.7u66.com/api/ui/room/v1.0.0/live.ashx?promoters=0&roomidx={room_id}&currentUrl=https://www.7u66.com/{room_id}?promoters=0'
params = {
"promoters": "0",
"roomidx": room_id,
"currentUrl": f"https://www.7u66.com/{room_id}?promoters=0"
}
api = f'https://wap.7u66.com/api/ui/room/v1.0.0/live.ashx?{urllib.parse.urlencode(params)}'
json_str = get_req(url=api, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
room_info = json_data['data']['roomInfo']
@ -2276,7 +2385,7 @@ def get_showroom_stream_data(url: str, proxy_addr: Union[str, None] = None, cook
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
headers['Cookie'] = cookies
@ -2322,7 +2431,7 @@ def get_acfun_sign_params(proxy_addr: Union[str, None] = None, cookies: Union[st
did = f'web_{generate_random_string(16)}'
headers = {
'referer': 'https://live.acfun.cn/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
'cookie': f'_did={did};',
}
if cookies:
@ -2343,7 +2452,7 @@ def get_acfun_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
Dict[str, Any]:
headers = {
'referer': 'https://live.acfun.cn/live/17912421',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
headers['Cookie'] = cookies
@ -2374,10 +2483,12 @@ def get_acfun_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
play_api = f'https://api.kuaishouzt.com/rest/zt/live/web/startPlay?{urllib.parse.urlencode(params)}'
json_str = get_req(play_api, data=data, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
live_title = json_data['data']['caption']
videoPlayRes = json_data['data']['videoPlayRes']
play_url_list = json.loads(videoPlayRes)['liveAdaptiveManifest'][0]['adaptationSet']['representation']
play_url_list = sorted(play_url_list, key=itemgetter('bitrate'), reverse=True)
result['play_url_list'] = play_url_list
result['title'] = live_title
return result
@ -2386,7 +2497,7 @@ def get_acfun_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
def get_changliao_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Referer': 'https://wap.tlclw.com/phone/801044397?promoters=0',
@ -2432,7 +2543,7 @@ def get_yingke_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
Dict[str, Any]:
headers = {
'Referer': 'https://www.inke.cn/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
headers['Cookie'] = cookies
@ -2468,7 +2579,7 @@ def get_yingke_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
def get_yinbo_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Referer': 'https://live.ybw1666.com/800005143?promoters=0',
@ -2515,7 +2626,7 @@ def get_zhihu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies:
Dict[str, Any]:
headers = {
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'user-agent': 'Mozilla/5.0 (iPad; CPU OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 Edg/121.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
headers['Cookie'] = cookies
@ -2529,8 +2640,10 @@ def get_zhihu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies:
live_status = live_data['drama']['status']
result = {"anchor_name": anchor_name, "is_live": False}
if live_status == 1:
live_title = live_data['theme']
play_url = live_data['drama']['playInfo']
result["is_live"] = True
result["title"] = live_title
result["m3u8_url"] = play_url['hlsUrl']
result["flv_url"] = play_url['playUrl']
result["record_url"] = play_url['hlsUrl']
@ -2545,7 +2658,7 @@ def get_chzzk_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'origin': 'https://chzzk.naver.com',
'referer': 'https://chzzk.naver.com/live/458f6ec20b034f49e0fc6d03921646d2',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
}
if cookies:
headers['Cookie'] = cookies
@ -2577,7 +2690,7 @@ def get_haixiu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
headers = {
'origin': 'https://www.haixiutv.com',
'referer': 'https://www.haixiutv.com/',
'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36',
'user-agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
}
if cookies:
headers['Cookie'] = cookies
@ -2592,13 +2705,14 @@ def get_haixiu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
"accessToken": access_token,
"tku": "3000006",
"c": "10138100100000",
"_st1": int(time.time()*1000)
"_st1": int(time.time() * 1000)
}
ajax_data = execjs.compile(open(f'{JS_SCRIPT_PATH}/haixiu.js').read()).call('sign', params, f'{JS_SCRIPT_PATH}/crypto-js.min.js')
ajax_data = execjs.compile(open(f'{JS_SCRIPT_PATH}/haixiu.js').read()).call('sign', params,
f'{JS_SCRIPT_PATH}/crypto-js.min.js')
params["accessToken"] = urllib.parse.unquote(urllib.parse.unquote(access_token))
params['_ajaxData1'] = ajax_data
params['_'] = int(time.time()*1000)
params['_'] = int(time.time() * 1000)
if 'haixiutv' in url:
api = f'https://service.haixiutv.com/v2/room/{room_id}/media/advanceInfoRoom?{urllib.parse.urlencode(params)}'
@ -2629,7 +2743,7 @@ def get_haixiu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
def get_vvxqiu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Dict[str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 (A2846/A3089/A3090/A3092))',
'Access-Control-Request-Method': 'GET',
'Origin': 'https://h5webcdn-pro.vvxqiu.com',
'Referer': 'https://h5webcdn-pro.vvxqiu.com/',
@ -2647,9 +2761,11 @@ def get_vvxqiu_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
"anchor_name": anchor_name,
"is_live": False,
}
if json_data['data']['anchorRank'] != 0:
m3u8_url = f'https://liveplay-pro.wasaixiu.com/live/1400442770_{room_id}_{room_id[2:]}_single.m3u8'
resp = get_req(m3u8_url, proxy_addr=proxy_addr, headers=headers)
if 'Not Found' not in resp:
result["is_live"] = True
m3u8_url = f'https://liveplay-pro.wasaixiu.com/live/1400442770_{room_id}_{room_id[2:]}_single.m3u8'
result['m3u8_url'] = m3u8_url
result['record_url'] = m3u8_url
return result
@ -2682,7 +2798,8 @@ def get_17live_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies
api_1 = f'https://wap-api.17app.co/api/v1/lives/{room_id}/viewers/alive'
json_str = get_req(api_1, json_data=json_data, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
if json_data['status'] == 2:
live_status = json_data.get("status")
if live_status and live_status == 2:
result["is_live"] = True
flv_url = json_data['pullURLsInfo']['rtmpURLs'][0]['urlHighQuality']
result['flv_url'] = flv_url
@ -2803,4 +2920,4 @@ def get_6room_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies:
flv_url = f'https://wlive.6rooms.com/httpflv/{flv_title}.flv'
result['flv_url'] = flv_url
result['record_url'] = get_req(flv_url, proxy_addr=proxy_addr, headers=headers, redirect_url=True)
return result
return result

View File

@ -4,7 +4,7 @@
Author: Hmily
GitHub: https://github.com/ihmily
Date: 2023-07-15 23:15:00
Update: 2024-10-02 04:36:12
Update: 2024-10-27 17:15:00
Copyright (c) 2023-2024 by Hmily, All Rights Reserved.
Function: Get live stream data.
"""
@ -26,7 +26,7 @@ from .spider import (
@trace_error_decorator
def get_douyin_stream_url(json_data: dict, video_quality: str) -> Dict[str, Any]:
anchor_name = json_data.get('anchor_name', None)
anchor_name = json_data.get('anchor_name')
result = {
"anchor_name": anchor_name,
@ -50,6 +50,7 @@ def get_douyin_stream_url(json_data: dict, video_quality: str) -> Dict[str, Any]
quality_index = video_qualities.get(video_quality)
m3u8_url = m3u8_url_list[quality_index]
flv_url = flv_url_list[quality_index]
result['title'] = json_data['title']
result['m3u8_url'] = m3u8_url
result['flv_url'] = flv_url
result['is_live'] = True
@ -101,6 +102,7 @@ def get_tiktok_stream_url(json_data: dict, video_quality: str) -> Dict[str, Any]
m3u8_url_list.append(m3u8_url_list[-1])
video_qualities = {"原画": 0, "蓝光": 0, "超清": 1, "高清": 2, "标清": 3, '流畅': 4}
quality_index = video_qualities.get(video_quality)
result['title'] = live_room['liveRoom']['title']
result['flv_url'] = flv_url_list[quality_index]['url']
result['m3u8_url'] = m3u8_url_list[quality_index]['url']
result['is_live'] = True
@ -226,6 +228,7 @@ def get_huya_stream_url(json_data: dict, video_quality: str) -> Dict[str, Any]:
flv_url = flv_url + str(video_quality_options[video_quality])
m3u8_url = m3u8_url + str(video_quality_options[video_quality])
result['title'] = game_live_info['introduction']
result['flv_url'] = flv_url
result['m3u8_url'] = m3u8_url
result['is_live'] = True
@ -248,11 +251,11 @@ def get_douyu_stream_url(json_data: dict, video_quality: str, cookies: str, prox
}
rid = str(json_data["room_id"])
json_data.pop("room_id", None)
json_data.pop("room_id")
rate = video_quality_options.get(video_quality, '0')
flv_data = get_douyu_stream_data(rid, rate, cookies=cookies, proxy_addr=proxy_addr)
rtmp_url = flv_data['data'].get('rtmp_url', None)
rtmp_live = flv_data['data'].get('rtmp_live', None)
rtmp_url = flv_data['data'].get('rtmp_url')
rtmp_live = flv_data['data'].get('rtmp_live')
if rtmp_live:
flv_url = f'{rtmp_url}/{rtmp_live}'
json_data['flv_url'] = flv_url
@ -271,6 +274,7 @@ def get_yy_stream_url(json_data: dict) -> Dict[str, Any]:
stream_line_addr = json_data['avp_info_res']['stream_line_addr']
cdn_info = list(stream_line_addr.values())[0]
flv_url = cdn_info['cdn_info']['url']
result['title'] = json_data['title']
result['flv_url'] = flv_url
result['is_live'] = True
result['record_url'] = flv_url
@ -303,6 +307,7 @@ def get_bilibili_stream_url(json_data: dict, video_quality: str, proxy_addr: str
return {
'anchor_name': json_data['anchor_name'],
'is_live': True,
'title': json_data['title'],
'record_url': play_url
}
@ -324,6 +329,7 @@ def get_netease_stream_url(json_data: dict, video_quality: str) -> Dict[str, Any
return {
"is_live": True,
"anchor_name": json_data['anchor_name'],
"title": json_data['title'],
"flv_url": flv_url,
"record_url": flv_url
}
@ -352,4 +358,5 @@ def get_stream_url(json_data: dict, video_quality: str, url_type: str = 'm3u8',
flv = play_url_list[selected_quality][extra_key] if extra_key else play_url_list[selected_quality]
data["flv_url"] = flv
data["record_url"] = flv
data['title'] = json_data.get('title')
return data

100
main.py
View File

@ -4,7 +4,7 @@
Author: Hmily
GitHub: https://github.com/ihmily
Date: 2023-07-17 23:52:05
Update: 2024-10-16 23:27:00
Update: 2024-10-28 00:21:00
Copyright (c) 2023-2024 by Hmily, All Rights Reserved.
Function: Record live stream video.
"""
@ -37,8 +37,8 @@ from msg_push import (
version = "v3.0.9"
platforms = ("\n国内站点:抖音|快手|虎牙|斗鱼|YY|B站|小红书|bigo|blued|网易CC|千度热播|猫耳FM|Look|TwitCasting|百度|微博|"
"酷狗|花椒|流星|Acfun|时光|映客|音播|知乎|嗨秀|VV星球|17Live|漂漂|六间房|乐嗨|花猫"
"\n海外站点TikTok|SOOP[AfreecaTV]|PandaTV|WinkTV|FlexTV|PopkonTV|TwitchTV|LiveMe|ShowRoom|CHZZK|浪Live")
"酷狗|花椒|流星|Acfun|畅聊|映客|音播|知乎|嗨秀|VV星球|17Live|浪Live|漂漂|六间房|乐嗨|花猫"
"\n海外站点TikTok|SOOP[AfreecaTV]|PandaTV|WinkTV|FlexTV|PopkonTV|TwitchTV|LiveMe|ShowRoom|CHZZK")
recording = set()
error_count = 0
@ -65,7 +65,7 @@ config_file = f'{script_path}/config/config.ini'
url_config_file = f'{script_path}/config/URL_config.ini'
backup_dir = f'{script_path}/backup_config'
text_encoding = 'utf-8-sig'
rstr = r"[\/\\\:\*\?\"\<\>\|&#.。, ~]"
rstr = r"[\/\\\:\*\\"\<\>\|&#.。, ~!·]"
ffmpeg_path = f"{script_path}/ffmpeg.exe"
default_path = f'{script_path}/downloads'
os.makedirs(default_path, exist_ok=True)
@ -299,12 +299,12 @@ def clear_record_info(record_name: str, record_url: str):
def check_subprocess(record_name: str, record_url: str, ffmpeg_command: list, save_type: str,
bash_file_path: Union[str, None] = None) -> bool:
save_path_name = ffmpeg_command[-1]
save_file_path = ffmpeg_command[-1]
process = subprocess.Popen(
ffmpeg_command, stderr=subprocess.STDOUT, startupinfo=get_startup_info(os_type)
)
subs_file_path = save_path_name.rsplit('.', maxsplit=1)[0]
subs_file_path = save_file_path.rsplit('.', maxsplit=1)[0]
subs_thread_name = f'subs_{Path(subs_file_path).name}'
if create_time_file and not split_video_by_time and '音频' not in save_type:
create_var[subs_thread_name] = threading.Thread(
@ -327,19 +327,19 @@ def check_subprocess(record_name: str, record_url: str, ffmpeg_command: list, sa
if return_code == 0:
if ts_to_mp4 and save_type == 'TS':
if split_video_by_time:
file_paths = get_file_paths(os.path.dirname(save_path_name))
prefix = os.path.basename(save_path_name).rsplit('_', maxsplit=1)[0]
file_paths = get_file_paths(os.path.dirname(save_file_path))
prefix = os.path.basename(save_file_path).rsplit('_', maxsplit=1)[0]
for path in file_paths:
if prefix in path:
threading.Thread(target=converts_mp4, args=(path, delete_origin_file)).start()
else:
threading.Thread(target=converts_mp4, args=(save_path_name, delete_origin_file)).start()
threading.Thread(target=converts_mp4, args=(save_file_path, delete_origin_file)).start()
print(f"\n{record_name} {stop_time} 直播录制完成\n")
if bash_file_path:
if os_type != 'nt':
print(f'准备执行自定义Bash脚本请确认脚本是否有执行权限! 路径:{bash_file_path}')
bash_command = [bash_file_path, record_name.split(' ', maxsplit=1)[-1], save_path_name, save_type,
bash_command = [bash_file_path, record_name.split(' ', maxsplit=1)[-1], save_file_path, save_type,
split_video_by_time, ts_to_mp4]
run_bash(bash_command)
else:
@ -371,14 +371,14 @@ def start_record(url_data: tuple, count_variable: int = -1):
if proxy_addr:
proxy_address = None
for platform in enable_proxy_platform_list:
if platform and platform.strip() in url:
if platform and platform.strip() in record_url:
proxy_address = proxy_addr
break
if not proxy_address:
if extra_enable_proxy_platform_list:
for pt in extra_enable_proxy_platform_list:
if pt and pt.strip() in url:
if pt and pt.strip() in record_url:
proxy_address = proxy_addr_bak or None
# print(f'\r代理地址:{proxy_address}')
@ -493,7 +493,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
username=afreecatv_username,
password=afreecatv_password
)
if json_data and json_data.get('new_cookies', None):
if json_data and json_data.get('new_cookies'):
update_config(config_file, 'Cookie', 'afreecatv_cookie', json_data['new_cookies'])
port_info = stream.get_stream_url(json_data, record_quality, spec=True)
else:
@ -553,7 +553,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
username=flextv_username,
password=flextv_password
)
if json_data and json_data.get('new_cookies', None):
if json_data and json_data.get('new_cookies'):
update_config(config_file, 'Cookie', 'flextv_cookie', json_data['new_cookies'])
port_info = stream.get_stream_url(json_data, record_quality, spec=True)
else:
@ -770,8 +770,8 @@ def start_record(url_data: tuple, count_variable: int = -1):
error_window.append(1)
else:
anchor_name = re.sub(rstr, "_", anchor_name)
anchor_name = remove_emojis(anchor_name, '_')
anchor_name = anchor_name.replace("", "(").replace("", ")")
anchor_name = remove_emojis(anchor_name, '_').strip('_')
record_name = f'序号{count_variable} {anchor_name}'
if record_url in url_comments:
@ -829,10 +829,17 @@ def start_record(url_data: tuple, count_variable: int = -1):
time.sleep(push_check_seconds)
continue
real_url = port_info.get('record_url', None)
real_url = port_info.get('record_url')
full_path = f'{default_path}/{platform}'
if len(real_url) > 0:
if real_url:
now = datetime.datetime.today().strftime("%Y-%m-%d_%H-%M-%S")
live_title = port_info.get('title')
title_in_name = ''
if live_title:
live_title = re.sub(rstr, "_", live_title).strip()
live_title = live_title.replace("", "(").replace("", ")")
live_title = remove_emojis(live_title, '_').strip('_')
title_in_name = live_title + '_' if filename_by_title else ''
try:
if len(video_save_path) > 0:
@ -846,6 +853,11 @@ def start_record(url_data: tuple, count_variable: int = -1):
full_path = f'{full_path}/{anchor_name}'
if folder_by_time:
full_path = f'{full_path}/{now[:10]}'
if folder_by_title and port_info.get('title'):
if folder_by_time:
full_path = f'{full_path}/{live_title}_{anchor_name}'
else:
full_path = f'{full_path}/{now[:10]}_{live_title}'
if not os.path.exists(full_path):
os.makedirs(full_path)
except Exception as e:
@ -899,7 +911,8 @@ def start_record(url_data: tuple, count_variable: int = -1):
'17Live': 'referer:https://17.live/en/live/6302408',
'浪Live': 'referer:https://www.lang.live',
}
headers = record_headers.get(platform, '')
headers = record_headers.get(platform)
if headers:
ffmpeg_command.insert(11, "-headers")
ffmpeg_command.insert(12, headers)
@ -921,7 +934,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
f"{platform} | {anchor_name} | 直播源地址: {port_info['record_url']}")
if video_save_type == "FLV":
filename = anchor_name + '_' + now + '.flv'
filename = anchor_name + f'_{title_in_name}' + now + '.flv'
save_file_path = f'{full_path}/{filename}'
print(f'{rec_info}/{filename}')
@ -935,7 +948,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
create_var[subs_thread_name].start()
try:
flv_url = port_info.get('flv_url', None)
flv_url = port_info.get('flv_url')
if flv_url:
_filepath, _ = urllib.request.urlretrieve(real_url, save_file_path)
record_finished = True
@ -951,14 +964,14 @@ def start_record(url_data: tuple, count_variable: int = -1):
error_window.append(1)
elif video_save_type == "MKV":
filename = anchor_name + '_' + now + ".mkv"
filename = anchor_name + f'_{title_in_name}' + now + ".mkv"
print(f'{rec_info}/{filename}')
save_file_path = full_path + '/' + filename
try:
if split_video_by_time:
now = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
save_file_path = f"{full_path}/{anchor_name}_{now}_%03d.mkv"
save_file_path = f"{full_path}/{anchor_name}_{title_in_name}{now}_%03d.mkv"
command = [
"-flags", "global_header",
"-c:v", "copy",
@ -999,14 +1012,14 @@ def start_record(url_data: tuple, count_variable: int = -1):
error_window.append(1)
elif video_save_type == "MP4":
filename = anchor_name + '_' + now + ".mp4"
filename = anchor_name + f'_{title_in_name}' + now + ".mp4"
print(f'{rec_info}/{filename}')
save_file_path = full_path + '/' + filename
try:
if split_video_by_time:
now = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
save_file_path = f"{full_path}/{anchor_name}_{now}_%03d.mp4"
save_file_path = f"{full_path}/{anchor_name}_{title_in_name}{now}_%03d.mp4"
command = [
"-c:v", "copy",
"-c:a", "aac",
@ -1025,7 +1038,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-c:v", "copy",
"-c:a", "copy",
"-f", "mp4",
"{path}".format(path=save_file_path),
save_file_path,
]
ffmpeg_command.extend(command)
@ -1050,10 +1063,11 @@ def start_record(url_data: tuple, count_variable: int = -1):
now = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
extension = "mp3" if "MP3" in video_save_type else "m4a"
name_format = "_%03d" if split_video_by_time else ""
save_path_name = f"{full_path}/{anchor_name}_{now}{name_format}.{extension}"
save_file_path = (f"{full_path}/{anchor_name}_{title_in_name}{now}"
f"{name_format}.{extension}")
if split_video_by_time:
print(f'\r{anchor_name} 准备开始录制音频: {save_path_name}')
print(f'\r{anchor_name} 准备开始录制音频: {save_file_path}')
if "MP3" in video_save_type:
command = [
@ -1063,7 +1077,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-f", "segment",
"-segment_time", split_time,
"-reset_timestamps", "1",
save_path_name,
save_file_path,
]
else:
command = [
@ -1075,7 +1089,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-segment_time", split_time,
"-segment_format", 'mpegts',
"-reset_timestamps", "1",
save_path_name,
save_file_path,
]
else:
@ -1084,7 +1098,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-map", "0:a",
"-c:a", "libmp3lame",
"-ab", "320k",
save_path_name,
save_file_path,
]
else:
@ -1094,7 +1108,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-bsf:a", "aac_adtstoasc",
"-ab", "320k",
"-movflags", "+faststart",
save_path_name,
save_file_path,
]
ffmpeg_command.extend(command)
@ -1117,11 +1131,11 @@ def start_record(url_data: tuple, count_variable: int = -1):
else:
if split_video_by_time:
now = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
filename = anchor_name + '_' + now + ".ts"
filename = anchor_name + f'_{title_in_name}' + now + ".ts"
print(f'{rec_info}/{filename}')
try:
save_path_name = f"{full_path}/{anchor_name}_{now}_%03d.ts"
save_file_path = f"{full_path}/{anchor_name}_{title_in_name}{now}_%03d.ts"
command = [
"-c:v", "copy",
"-c:a", "copy",
@ -1130,7 +1144,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-segment_time", split_time,
"-segment_format", 'mpegts',
"-reset_timestamps", "1",
save_path_name,
save_file_path,
]
ffmpeg_command.extend(command)
@ -1143,8 +1157,8 @@ def start_record(url_data: tuple, count_variable: int = -1):
)
if comment_end:
if ts_to_mp4:
file_paths = get_file_paths(os.path.dirname(save_path_name))
prefix = os.path.basename(save_path_name).rsplit('_', maxsplit=1)[0]
file_paths = get_file_paths(os.path.dirname(save_file_path))
prefix = os.path.basename(save_file_path).rsplit('_', maxsplit=1)[0]
for path in file_paths:
if prefix in path:
threading.Thread(
@ -1161,7 +1175,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
error_window.append(1)
else:
filename = anchor_name + '_' + now + ".ts"
filename = anchor_name + f'_{title_in_name}' + now + ".ts"
print(f'{rec_info}/{filename}')
save_file_path = full_path + '/' + filename
@ -1171,7 +1185,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
"-c:a", "copy",
"-map", "0",
"-f", "mpegts",
"{path}".format(path=save_file_path),
save_file_path,
]
ffmpeg_command.extend(command)
@ -1397,6 +1411,8 @@ while True:
video_save_path = read_config_value(config, '录制设置', '直播保存路径(不填则默认)', "")
folder_by_author = options.get(read_config_value(config, '录制设置', '保存文件夹是否以作者区分', ""), False)
folder_by_time = options.get(read_config_value(config, '录制设置', '保存文件夹是否以时间区分', ""), False)
folder_by_title = options.get(read_config_value(config, '录制设置', '保存文件夹是否以标题区分', ""), False)
filename_by_title = options.get(read_config_value(config, '录制设置', '保存文件名是否包含标题', ""), False)
video_save_type = read_config_value(config, '录制设置', '视频保存格式ts|mkv|flv|mp4|mp3音频|m4a音频', "ts")
video_record_quality = read_config_value(config, '录制设置', '原画|超清|高清|标清|流畅', "原画")
use_proxy = options.get(read_config_value(config, '录制设置', '是否使用代理ip是/否)', ""), False)
@ -1591,6 +1607,7 @@ while True:
'www.haixiutv.com',
"h5webcdn-pro.vvxqiu.com",
"17.live",
'www.lang.live',
"m.pp.weimipopo.com",
"v.6.cn",
"m.6.cn",
@ -1611,8 +1628,7 @@ while True:
'www.liveme.com',
'www.showroom-live.com',
'chzzk.naver.com',
'm.chzzk.naver.com',
'www.lang.live'
'm.chzzk.naver.com'
]
platform_host.extend(overseas_platform_host)
@ -1688,4 +1704,4 @@ while True:
t2.start()
first_run = False
time.sleep(3)
time.sleep(3)