Fix xiaohongshu live record and add afreecatv login

This commit is contained in:
ihmily 2024-02-09 04:04:51 +08:00
parent 63670d0025
commit 753c5e003d
5 changed files with 279 additions and 53 deletions

View File

@ -5,6 +5,7 @@
[![Supported Platforms](https://img.shields.io/badge/platforms-Windows%20%7C%20Linux-blue.svg)](https://github.com/ihmily/DouyinLiveRecorder)
[![Docker Pulls](https://img.shields.io/docker/pulls/ihmily/douyin-live-recorder?label=Docker%20Pulls&color=blue&logo=docker)](https://hub.docker.com/r/ihmily/douyin-live-recorder/tags)
![GitHub issues](https://img.shields.io/github/issues/ihmily/DouyinLiveRecorder.svg)
[![Latest Release](https://img.shields.io/github/v/release/ihmily/DouyinLiveRecorder)](https://github.com/ihmily/DouyinLiveRecorder/releases/latest)
![Downloads](https://img.shields.io/github/downloads/ihmily/DouyinLiveRecorder/total)
一款简易的可循环值守的直播录制工具基于FFmpeg实现多平台直播源录制支持自定义配置录制以及直播状态推送。
@ -106,7 +107,7 @@ B站
https://live.bilibili.com/320
小红书:
https://www.xiaohongshu.com/hina/livestream/568980065082002402?appuid=5f3f478a00000000010005b3&apptime=
https://www.redelight.cn/hina/livestream/569077534207413574/1707413727088?appuid=5f3f478a00000000010005b3&
bigo直播
https://www.bigo.tv/cn/716418802
@ -138,23 +139,9 @@ https://fm.missevan.com/live/868895007
该解析接口 ~~仅供演示~~(演示接口暂时停止,后续再开放),并且只包含抖音、快手、虎牙直播的解析,其他平台如有需要请自行添加,源码在这里 [DouyinLiveRecorder/api](https://github.com/ihmily/DouyinLiveRecorder/tree/main/api)
```HTTP
GET https://hmily.vip/api/jx/live/?url=
```
请求示例:
```HTTP
GET https://hmily.vip/api/jx/live/?url=https://live.douyin.com/573716250978
```
若需要将抖音直播间短链接转换为长链接,使用以下接口:
```HTTP
GET https://hmily.vip/api/jx/live/convert.php?url=https://v.douyin.com/iQLgKSj/
```
在线播放m3u8和flv视频网站[M3U8 在线视频播放器 ](https://jx.hmily.vip/play/)
在线播放m3u8和flv视频网站[M3U8 在线视频播放器 ](https://jx.hmily.vip/play/),源码是 [index.html](https://github.com/ihmily/DouyinLiveRecorder/blob/main/index.html)
 
@ -165,6 +152,7 @@ GET https://hmily.vip/api/jx/live/convert.php?url=https://v.douyin.com/iQLgKSj/
```bash
git clone https://github.com/ihmily/DouyinLiveRecorder.git
```
2.进入项目文件夹,安装依赖
@ -262,9 +250,13 @@ docker-compose stop
## ⏳提交日志
- 20240209
- 优化AfreecaTV录制新增账号密码登录获取cookie以及持久保存
- 修复了小红书直播因官方更新直播域名,导致无法录制直播的问题
- 修复了更新URL配置文件的bug
- 最后,祝大家新年快乐!
- 20240129
- 新增猫耳FM直播录制
- 20240127
- 新增千度热播直播录制、新增pandaTV(韩国)直播录制
@ -273,15 +265,12 @@ docker-compose stop
- 新增自定义设置不同直播间的录制画质(即每个直播间录制画质可不同)
- 修改录制视频保存路径为 `downloads` 文件夹,并且分平台进行保存。
- 20240114
- 新增网易cc直播录制优化ffmpeg参数修改AfreecaTV输入直播地址格式
- 修改日志记录器 @[iridescentGray](https://github.com/iridescentGray)
- 20240102
- 修复Linux上运行新增docker配置文件
- 20231210
- 修复录制分段bug修复bigo录制检测bug

View File

@ -38,4 +38,8 @@ afreecatv_cookie =
netease_cookie =
千度热播_cookie =
pandatv_cookie =
猫耳FM_cookie =
猫耳FM_cookie =
[账号密码]
afreecatv账号 =
afreecatv密码 =

28
main.py
View File

@ -4,7 +4,7 @@
Author: Hmily
GitHub: https://github.com/ihmily
Date: 2023-07-17 23:52:05
Update: 2024-01-29 18:45:09
Update: 2024-02-09 02:41:18
Copyright (c) 2023-2024 by Hmily, All Rights Reserved.
Function: Record live stream video.
"""
@ -146,13 +146,16 @@ def display_info():
logger.warning(f"错误信息: {e} 发生错误的行数: {e.__traceback__.tb_lineno}")
def update_file(file_path: str, old_str: str, new_str: str):
def update_file(file_path: str, old_str: str, new_str: str, start_str: str = None):
# TODO: 更新文件操作
file_data = ""
with open(file_path, "r", encoding="utf-8-sig") as f:
for text_line in f:
if old_str in text_line:
text_line = text_line.replace(old_str, new_str)
if start_str:
text_line = f'{start_str}{text_line}'
file_data += text_line
with open(file_path, "w", encoding="utf-8-sig") as f:
f.write(file_data)
@ -576,7 +579,7 @@ def start_record(url_data: tuple, count_variable: int = -1):
no_error = True
new_record_url = ''
count_time = time.time()
retry = 0
record_quality, record_url, anchor_name = url_data
print(f"\r运行新线程,传入地址 {record_url}")
@ -648,10 +651,14 @@ def start_record(url_data: tuple, count_variable: int = -1):
json_data = get_bilibili_stream_data(record_url, cookies=bili_cookie)
port_info = get_bilibili_stream_url(json_data, record_quality)
elif record_url.find("https://www.xiaohongshu.com/") > -1:
elif record_url.find("https://www.redelight.cn/") > -1:
platform = '小红书直播'
if retry > 0:
time.sleep(7200)
retry = 0
with semaphore:
port_info = get_xhs_stream_url(record_url, cookies=xhs_cookie)
retry += 1
elif record_url.find("https://www.bigo.tv/") > -1:
platform = 'bigo直播'
@ -1322,7 +1329,7 @@ while True:
# 读取URL_config.ini文件
try:
with open(url_config_file, "r", encoding=encoding) as file:
with open(url_config_file, "r", encoding=encoding, errors='ignore') as file:
for line in file:
line = line.strip()
if line.startswith("#") or len(line) < 20:
@ -1362,7 +1369,7 @@ while True:
'www.douyu.com',
'www.yy.com',
'live.bilibili.com',
'www.xiaohongshu.com',
'www.redelight.cn',
'www.bigo.tv',
'app.blued.cn',
'play.afreecatv.com',
@ -1378,12 +1385,19 @@ while True:
url_tuples_list.append(new_line)
else:
print(f"{url} 未知链接.此条跳过")
update_file(url_config_file, url, url, start_str='#')
while len(name_list):
a = name_list.pop()
replace_words = a.split('|')
if replace_words[0] != replace_words[1]:
update_file(url_config_file, replace_words[0], replace_words[1])
if replace_words[1].startswith("#"):
start_with = '#'
new_word = replace_words[1][1:]
else:
start_with = None
new_word = replace_words[1]
update_file(url_config_file, replace_words[0], new_word, start_str=start_with)
if len(url_tuples_list) > 0:
text_no_repeat_url = list(set(url_tuples_list))

198
spider.py
View File

@ -4,7 +4,7 @@
Author: Hmily
GitHub:https://github.com/ihmily
Date: 2023-07-15 23:15:00
Update: 2024-01-29 18:57:12
Update: 2024-02-09 03:33:50
Copyright (c) 2023 by Hmily, All Rights Reserved.
Function: Get live stream data.
"""
@ -18,7 +18,14 @@ import re
import json
import execjs
import urllib.request
from utils import trace_error_decorator
from utils import (
trace_error_decorator,
update_config,
read_config_value,
dict_to_cookie_str
)
import http.cookiejar
from urllib.request import Request
no_proxy_handler = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(no_proxy_handler)
@ -68,7 +75,7 @@ def get_douyin_stream_data(url: str, cookies: Union[str, None] = None) -> Dict[s
@trace_error_decorator
def get_tiktok_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> Dict[
str, Any]:
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',
'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='
@ -348,17 +355,19 @@ def get_bilibili_stream_data(url: str, cookies: Union[str, None] = None) -> Dict
@trace_error_decorator
def get_xhs_stream_url(url: str, 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': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0',
'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://www.xiaohongshu.com/hina/livestream/568979931846654360',
'Referer': 'https://www.redelight.cn/hina/livestream/569077534207413574/1707413727088?share_source=&share_source_id=null&source=share_out_of_app&host_id=58bafe4282ec39085a56ece9&xhsshare=WeixinSession&appuid=5f3f478a00000000010005b3&apptime=1707413727',
}
if cookies:
headers['Cookie'] = cookies
room_id = url.split('?')[0].rsplit('/', maxsplit=1)[1]
appuid = re.search('appuid=(.*?)&', url).group(1)
app_api = f'https://www.xiaohongshu.com/api/sns/red/live/app/v1/ecology/outside/share_info?room_id={room_id}'
room_id = url.split('?')[0].rsplit('/', maxsplit=2)[1]
# 原域名
# app_api = f'https://www.xiaohongshu.com/api/sns/red/live/app/v1/ecology/outside/share_info?room_id={room_id}'
app_api = f'https://www.redelight.cn/api/sns/red/live/app/v1/ecology/outside/share_info?room_id={room_id}'
req = urllib.request.Request(app_api, headers=headers)
response = opener.open(req, timeout=15)
json_str = response.read().decode('utf-8')
@ -370,7 +379,7 @@ def get_xhs_stream_url(url: str, cookies: Union[str, None] = None) -> Dict[str,
"is_live": False,
}
# 这个判断不准确,无论是否在直播都为0
# 这个判断不准确,无论是否在直播status都为0
if live_status == 0:
flv_url = f'http://live-play.xhscdn.com/live/{room_id}.flv?uid={appuid}'
result['flv_url'] = flv_url
@ -450,8 +459,9 @@ def get_blued_stream_url(url: str, cookies: Union[str, None] = None) -> Dict[str
return result
@trace_error_decorator
def get_afreecatv_cdn_url(broad_no: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> Dict[
str, Any]:
str, Any]:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0',
'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',
@ -492,8 +502,106 @@ def get_afreecatv_cdn_url(broad_no: str, proxy_addr: Union[str, None] = None, co
@trace_error_decorator
def get_afreecatv_stream_url(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> Dict[
str, Any]:
def login_afreecatv(username: str, password: str, proxy_addr: Union[str, None] = None) -> Union[str, None]:
if len(username.strip()) < 6 or len(password.strip()) < 10:
raise RuntimeError('AfreecaTV登录失败请在config.ini配置文件中填写正确的AfreecaTV平台的账号和密码')
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0',
'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://login.afreecatv.com/afreeca/login.php?szFrom=full&request_uri=https%3A%2F%2Fwww.afreecatv.com%2F',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
}
data = {
'szWork': 'login',
'szType': 'json',
'szUid': str(username),
'szPassword': str(password),
'isSaveId': 'true',
'szScriptVar': 'oLoginRet',
'szAction': '',
'isLoginRetain': 'Y',
}
url = 'https://login.afreecatv.com/app/LoginAction.php?callback=jQuery17208926278503069585_1707311376418'
try:
if proxy_addr:
proxies = {
'http': proxy_addr,
'https': proxy_addr
}
response = requests.post(url, data=data, headers=headers, proxies=proxies, timeout=15)
cookie_dict = response.cookies.get_dict()
else:
data = urllib.parse.urlencode(data).encode('utf-8')
cookie_jar = http.cookiejar.CookieJar()
login_opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie_jar))
req = Request(url, data=data, headers=headers)
_ = login_opener.open(req, timeout=15)
cookie_dict = {cookie.name: cookie.value for cookie in cookie_jar}
cookie = dict_to_cookie_str(cookie_dict)
return cookie
except Exception:
print('AfreecaTV登录失败,请检查配置文件中的账号密码是否正确')
@trace_error_decorator
def get_afreecatv_tk(url: str, rtype: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> \
Union[str, tuple, None]:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0',
'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://play.afreecatv.com/secretx/250989857',
'Content-Type': 'application/x-www-form-urlencoded',
}
if cookies:
headers['Cookie'] = cookies
split_url = url.split('/')
bj_id = split_url[3] if len(split_url) < 6 else split_url[5]
data = {
'bid': bj_id,
'bno': '',
'type': rtype,
'pwd': '',
'player_type': 'html5',
'stream_type': 'common',
'quality': 'master',
'mode': 'landing',
'from_api': '0',
}
url2 = f'https://live.afreecatv.com/afreeca/player_live_api.php?bjid={bj_id}'
if proxy_addr:
proxies = {
'http': proxy_addr,
'https': proxy_addr
}
response = requests.post(url2, data=data, headers=headers, proxies=proxies, timeout=15)
json_data = response.json()
else:
data_encoded = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url2, data=data_encoded, headers=headers)
response = urllib.request.urlopen(req, timeout=15)
json_str = response.read().decode('utf-8')
json_data = json.loads(json_str)
if rtype == 'aid':
token = json_data["CHANNEL"]["AID"]
return token
else:
return json_data['CHANNEL']['BJNICK'], json_data['CHANNEL']['BNO']
@trace_error_decorator
def get_afreecatv_stream_url(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; rv:109.0) Gecko/20100101 Firefox/119.0',
'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',
@ -516,6 +624,7 @@ def get_afreecatv_stream_url(url: str, proxy_addr: Union[str, None] = None, cook
}
url2 = 'http://api.m.afreecatv.com/broad/a/watch'
if proxy_addr:
proxies = {
'http': proxy_addr,
@ -523,27 +632,65 @@ def get_afreecatv_stream_url(url: str, proxy_addr: Union[str, None] = None, cook
}
response = requests.post(url2, data=data, headers=headers, proxies=proxies, timeout=15)
json_data = response.json()
else:
data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url2, data=data, headers=headers)
data_encoded = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url2, data=data_encoded, headers=headers)
response = urllib.request.urlopen(req, timeout=15)
json_str = response.read().decode('utf-8')
json_data = json.loads(json_str)
anchor_name = json_data['data']['user_nick']
if not anchor_name:
if json_data['data']['code'] == -3004:
print("AfreecaTV直播获取失败:", json_data['data']['message'])
elif json_data['data']['code'] == -3002:
print("AfreecaTV直播获取失败:", json_data['data']['message'])
if 'user_nick' in json_data['data']:
anchor_name = json_data['data']['user_nick']
else:
anchor_name = ''
result = {
"anchor_name": '' if anchor_name is None else anchor_name,
"is_live": False,
}
if json_data['result'] == 1:
if not anchor_name:
def handle_login():
username = read_config_value('./config/config.ini', '账号密码', 'afreecatv账号')
password = read_config_value('./config/config.ini', '账号密码', 'afreecatv密码')
cookie = login_afreecatv(username, password, proxy_addr=proxy_addr)
if 'PdboxBbs=' in cookie:
print('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
result['is_live'] = True
result['record_url'] = m3u8_url
return result
if json_data['data']['code'] == -3001:
print("AfreecaTV直播获取失败[直播刚结束]:", json_data['data']['message'])
return result
elif json_data['data']['code'] == -3002:
print("AfreecaTV直播获取失败[未登录]: 19+", json_data['data']['message'])
print("正在尝试使用您的账号和密码登录AfreecaTV直播平台请确保已配置")
new_cookie = handle_login()
if new_cookie and len(new_cookie) > 0:
update_config('./config/config.ini', 'Cookie', 'afreecatv_cookie', new_cookie)
return fetch_data(new_cookie)
raise RuntimeError('AfreecaTV登录失败请检查账号和密码是否正确')
elif json_data['data']['code'] == -3004:
# print("AfreecaTV直播获取失败[未认证]:", json_data['data']['message'])
if cookies and len(cookies) > 0:
return fetch_data(cookies)
else:
raise RuntimeError('AfreecaTV登录失败请检查账号和密码是否正确')
elif json_data['data']['code'] == -6001:
print(f"错误信息:{json_data['data']['message']}请检查输入的直播间地址是否正确")
return result
if json_data['result'] == 1 and anchor_name:
broad_no = json_data['data']['broad_no']
hls_authentication_key = json_data['data']['hls_authentication_key']
view_url = get_afreecatv_cdn_url(broad_no, proxy_addr=proxy_addr)['view_url']
@ -554,7 +701,7 @@ def get_afreecatv_stream_url(url: str, proxy_addr: Union[str, None] = None, cook
return result
# @trace_error_decorator
@trace_error_decorator
def get_netease_stream_data(url: str, cookies: Union[str, None] = None) -> Dict[str, Any]:
headers = {
'accept': 'application/json, text/plain, */*',
@ -615,7 +762,7 @@ def get_qiandurebo_stream_data(url: str, cookies: Union[str, None] = None) -> Di
@trace_error_decorator
def get_pandatv_stream_data(url: str, proxy_addr: Union[str, None] = None, cookies: Union[str, None] = None) -> Dict[
str, Any]:
str, Any]:
headers = {
'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',
@ -730,11 +877,12 @@ if __name__ == '__main__':
# room_url = 'https://www.yy.com/22490906/22490906' # YY直播
# room_url = 'https://live.bilibili.com/21593109' # b站直播
# 小红书直播
# room_url = 'https://www.xiaohongshu.com/hina/livestream/568980065082002402?appuid=5f3f478a00000000010005b3&apptime='
# room_url = 'https://www.redelight.cn/hina/livestream/569077534207413574/1707413727088?appuid=5f3f478a00000000010005b3&'
# room_url = 'https://www.bigo.tv/cn/716418802' # bigo直播
# room_url = 'https://app.blued.cn/live?id=Mp6G2R' # blued直播
# room_url = 'https://play.afreecatv.com/sw7love' # afreecatv直播
# room_url = 'https://m.afreecatv.com/#/player/hl6260' # afreecatv直播
# room_url = 'https://play.afreecatv.com/secretx' # afreecatv直播
# room_url = 'https://cc.163.com/583946984' # 网易cc直播
# room_url = 'https://qiandurebo.com/web/video.php?roomnumber=33333' # 千度热播
# room_url = 'https://www.pandalive.co.kr/live/play/bara0109' # pandaTV

View File

@ -4,6 +4,7 @@ import functools
import hashlib
import traceback
from logger import logger
import configparser
def trace_error_decorator(func):
@ -27,3 +28,73 @@ def check_md5(file_path):
with open(file_path, 'rb') as fp:
file_md5 = hashlib.md5(fp.read()).hexdigest()
return file_md5
def dict_to_cookie_str(cookies_dict):
cookie_str = '; '.join([f"{key}={value}" for key, value in cookies_dict.items()])
return cookie_str
def read_config_value(file_path, section, key):
"""
从配置文件中读取指定键的值
参数:
- file_path: 配置文件的路径
- section: 部分名称
- key: 键名称
返回:
- 键的值如果部分或键不存在则返回None
"""
config = configparser.ConfigParser()
try:
config.read(file_path, encoding='utf-8-sig')
except Exception as e:
print(f"读取配置文件时出错: {e}")
return None
if section in config:
if key in config[section]:
return config[section][key]
else:
print(f"键[{key}]不存在于部分[{section}]中。")
else:
print(f"部分[{section}]不存在于文件中。")
return None
def update_config(file_path, section, key, new_value):
"""
更新配置文件中的键值
参数:
- file_path: 配置文件的路径
- section: 要更新的部分名称
- key: 要更新的键名称
- new_value: 新的键值
"""
config = configparser.ConfigParser()
try:
config.read(file_path, encoding='utf-8-sig')
except Exception as e:
print(f"读取配置文件时出错: {e}")
return
if section not in config:
print(f"部分[{section}]不存在于文件中。")
return
# 转义%字符
escaped_value = new_value.replace('%', '%%')
config[section][key] = escaped_value
try:
with open(file_path, 'w', encoding='utf-8-sig') as configfile:
config.write(configfile)
print(f"配置文件中[{section}]下的{key}的值已更新")
except Exception as e:
print(f"写入配置文件时出错: {e}")