diff --git a/README.md b/README.md
index 306b69d..f0697c5 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,7 @@
- 当同时在录制多个直播时,最好线程数设置大一些,否则可能出现其中一个直播录制出错。当然设置的过大也没用,要同时考虑自身电脑的配置,如CPU内核数、网络带宽等限制。
- 如果想直接使用打包好的录制软件,进入[Releases](https://github.com/ihmily/DouyinLiveRecorder/releases) 下载最新发布的 zip压缩包即可,可能有些电脑会报毒,直接忽略即可,这是pyinstaller打包的锅。
- 如果要长时间挂着软件循环监测直播,最好循环时间设置长一点,避免因请求频繁导致被官方封禁IP 。
+- 最好使用自己的cookie,切记!
@@ -120,18 +121,20 @@ GET https://hmily.vip/api/jx/live/convert.php?url=https://v.douyin.com/iQLgKSj/
## ⏳提交日志
+- 20230919
+ - 修复了快手版本更新后录制出错的问题,增加了其自动获取cookie(稳定性未知)
+ - 修复了Tiktok显示正在直播但不进行录制的问题
+
- 20230907
- 修复了因抖音官方更新了版本导致的录制出错以及短链接转换出错
-
+
- 修复B站无法录制原画视频的bug
-
+
- 修改了配置文件字段,新增各平台自定义设置Cookie
-
- 20230903
- 修复了Tiktok录制时报644无法录制的问题
- 新增直播状态推送到钉钉和微信的功能,如有需要请看 [设置推送教程](https://d04vqdiqwr3.feishu.cn/docx/XFPwdDDvfobbzlxhmMYcvouynDh?from=from_copylink)
- 最近比较忙,其他问题有时间再更新
-
- 20230816
- 修复斗鱼直播(官方更新了字段)和快手直播录制出错的问题
- 20230814
diff --git a/api/index.php b/api/index.php
index 643cf72..e911931 100644
--- a/api/index.php
+++ b/api/index.php
@@ -4,7 +4,7 @@
* Author: Hmily
* Github:https://github.com/ihmily
* Date: 2023-07-20 21:06:20
- * Update: 2023-09-07 23:53:07
+ * Update: 2023-09-17 20:23:00
* Copyright (c) 2023 by Hmily, All Rights Reserved.
* Function:Spider the live stream url
* Address:https://github.com/ihmily/DouyinLiveRecorder
@@ -12,6 +12,7 @@
// 本API代码只有解析抖音、快手和虎牙的,有需要其他的可自己根据源码增加
+// 注意:抖音和快手的 要添加上自己的cookie才能用
header('Content-type: application/json; charset=utf-8');
if(empty($_GET['url'])){
@@ -51,30 +52,23 @@ function get_douyin_json_data($url) {
'Referer: https://live.douyin.com/',
);
- $cookies='ttwid=1%7CIkooT8SJQrpeYtHlSALuhz9BdcHpaaf9tHQRKHuDaYE%7C1687785070%7C6690250483b63b6482128174d0f93bd879614d76f1b6e03ca52e032cf7fbaafd; passport_csrf_token=52bece134ac246c81163cc93b72f86a6; passport_csrf_token_default=52bece134ac246c81163cc93b72f86a6; d_ticket=2b9e3eb3626216c0122f0d980f867deb7b414; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; passport_auth_status=a74f300f376940d65914eb148d55ca96%2C9ca487aea255972120d502f736c5dd7b; passport_auth_status_ss=a74f300f376940d65914eb148d55ca96%2C9ca487aea255972120d502f736c5dd7b; sso_auth_status=52ecac30d95890cc7896c880366aa21a; sso_auth_status_ss=52ecac30d95890cc7896c880366aa21a; LOGIN_STATUS=1; store-region=cn-fj; store-region-src=uid; __security_server_data_status=1; __live_version__=%221.1.1.1853%22; live_can_add_dy_2_desktop=%220%22; xgplayer_user_id=528819598596; msToken=ZfXzPPa_KqQDF9wkHigKqgyUMIt33-qgLl1qqthGsAea4L69i9wxWaGH4GaQ9M_Q-eqhLpnD4v8FRGIj9KGJGIyLmjPkR1uepZ0gBaqhCkqK1KaauPXT_VK_uVgW6q4=; home_can_add_dy_2_desktop=%220%22; strategyABtestKey=%221689685952.92%22; FOLLOW_LIVE_POINT_INFO=%22MS4wLjABAAAAf6aekfyBsc4u8jMkeYbgnkFa0ksIWKWpGOywuyHXyo4%2F1689609600000%2F0%2F1689606316434%2F0%22; FOLLOW_NUMBER_YELLOW_POINT_INFO=%22MS4wLjABAAAAf6aekfyBsc4u8jMkeYbgnkFa0ksIWKWpGOywuyHXyo4%2F1689609600000%2F0%2F0%2F1689594083273%22; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Atrue%2C%22volume%22%3A0.6%7D; device_web_cpu_core=8; device_web_memory_size=-1; webcast_local_quality=origin; csrf_session_id=0446f50cc7e08f146ad07351af90f413; __ac_nonce=064be522600a12daa29ff; __ac_signature=_02B4Z6wo00f0145FB4AAAIDCkga5P5okFMuOdAMAAIc3h1Lmbu.WZmNdgawlJBkHRSAf1yndkZFgF.zN2OHlE62.f.4ZFt740eSkTrQW8j3EM2s9s3vtK9LGh-h9jhUkgSbj4UOtYTqpCZZc88; webcast_leading_last_show_time=1690194481638; webcast_leading_total_show_times=1; odin_tt=6ebbe0a3c1b4e5bc6d333c5c7514fc88a288b3b03b1f0cf34826dee5d6d6394620f17fd4eb624b710954233f38fa3c67fd4a5338bffaa792a2cf71d1b51d837f079925497d6b372f47a577d779036a71; msToken=uHqyINCG79-ojuC5cXU6tYm0Av3BqNzqLkFGvbNw5QmSCtFY7xYHJjJ3wu-gk2Evj5QQ7D6UMsz2inlRN-aZf8xTGMAnpmgieOrygPqoK7QboFwCXR7aLi4KKcFXvFu2; tt_scid=BVvDLf3XEG4PZlY2-haad4.kR2BYWdq4X88b6-sPA2Wpg2lsSDI5M7YuZ7H-GPf.6646';
+ $cookies='your cookie'; # 任意抖音直播间页面的Cookie
$html_str = get_curl($url,$headers,$cookies);
- // print_r($html_str);
-
- $pattern = '/self\.__pace_f\.push(.*?)<\/script>
\
'[',
']"' => ']',
- '"{' => '{',
- '}"' => '}',
+ '"{' => '{',
+ '}"' => '}',
'u0026' => '&'
);
-
$cleaned_string = strtr($cleaned_string, $replacements);
- $json_str='{"state":'.$cleaned_string;
- // echo $json_str;
- $json_data = json_decode($json_str, true);
+ $json_data = json_decode($cleaned_string, true);
return $json_data;
}
@@ -147,20 +141,24 @@ function get_kuaishou_stream_url($live_url){
$headers = array(
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.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',
- 'Cookie:clientid=3; did=web_2e5935532808ea57f357c827b45abaf4; didv=1687682547000; client_key=65890b29; kpn=GAME_ZONE; clientid=3; did=web_2e5935532808ea57f357c827b45abaf4; client_key=65890b29; kpn=GAME_ZONE; userId=580178847; kuaishou.live.web_st=ChRrdWFpc2hvdS5saXZlLndlYi5zdBKgAQ-E2wk--dxc2ehil5tQ5PZxSAAy_WocJekwLrvD4yIZxEo4y76RBkXONqX9xSLhyX5WOyhWdsXrwH-Nj0RTgM4csF_UwnsIclnnZT6WNO2tfB3fmNHvZHAIRtqDl6hXsS1x8vwgHCii65me0EiPh1LK855TafkNx9A7wrTma6XPlCPL8L1GNKTjtiQB2L7Y0kuOp-l0zVzIidHhFvGXfFEaEgCrAu8bFEUPixNgRvVq1Nb0ZSIghKUYro_uVYFHrcP3wJ93ACmwb-oSRGVtcLhGUdaI43UoBTAB; kuaishou.live.web_ph=c371edbd1ecfdc90fb87ae8c0c8738ec6f3f; userId=580178847; kuaishou.live.bfb1s=477cb0011daca84b36b3a4676857e5a1'
+
);
- $html_str = get_curl($live_url,$headers);
+
+ $cookies = 'your cookie'; # 任意快手直播间页面的cookie
+
+ $html_str = get_curl($live_url,$headers,$cookies);
preg_match('/__INITIAL_STATE__=(.*?);\(function/', $html_str, $matches);
$json_data = json_decode($matches[1], true);
- $liveroom = $json_data['liveroom'];
- $live_title=$liveroom['liveStream']['caption'];
- $anchor_name = $liveroom['author']['name'];
+
+ $play_list= $json_data['liveroom']['playList'][0];
+ $live_title=$play_list['liveStream']['caption'];
+ $anchor_name = $play_list['author']['name'];
# 获取直播间状态
- $status = $liveroom['isLiving']; # 直播状态True是正在直播.False是未开播
+ $status = $play_list['isLiving']; # 直播状态True是正在直播.False是未开播
if (!$status) {
$data=["live_status"=>'主播未开播或者直播已经结束!'];
}else{
- $stream_data=$liveroom['liveStream']['playUrls'][0]['adaptationSet']['representation'];
+ $stream_data=$play_list['liveStream']['playUrls'][0]['adaptationSet']['representation'];
$data=["title"=>$live_title,'stream'=>$stream_data];
}
@@ -252,7 +250,3 @@ function get_curl($url,$headers=array(),$cookies=''){
-
-
-
-
diff --git a/config/config.ini b/config/config.ini
index 7245e45..b802027 100644
--- a/config/config.ini
+++ b/config/config.ini
@@ -7,7 +7,6 @@
同一时间访问网络的线程数 = 3
循环时间(秒) = 60
排队读取网址时间(秒) = 0
-是否显示直播地址 = 否
是否显示循环秒数 = 否
ts格式分段录制是否开启 = 否
视频分段大小(兆) = 1000
diff --git a/main.py b/main.py
index 6680a1f..546f07b 100644
--- a/main.py
+++ b/main.py
@@ -4,12 +4,11 @@
Author: Hmily
Github: https://github.com/ihmily
Date: 2023-07-17 23:52:05
-Update: 2023-09-07 10:56:25
+Update: 2023-09-19 00:16:38
Copyright (c) 2023 by Hmily, All Rights Reserved.
Function: Record live stream video.
"""
-
import functools
import random
import os
@@ -27,7 +26,7 @@ from web_rid import *
from msg_push import *
# 版本号
-version = "v1.0.8"
+version = "v1.0.9"
platforms = "抖音|Tiktok|快手|虎牙|斗鱼|YY|B站"
# --------------------------log日志-------------------------------------
@@ -50,6 +49,7 @@ recording = set()
unrecording = set()
warning_count = 0
max_request = 0
+Monitoring = 0
runing_list = []
url_tuples_list = []
textNoRepeatUrl = []
@@ -80,10 +80,11 @@ def trace_error_decorator(func):
return func(*args, **kwargs)
except Exception as e:
error_line = traceback.extract_tb(e.__traceback__)[-1].lineno
- error_info=f"错误信息: type: {type(e).__name__}, {str(e)} in function {func.__name__} at line: {error_line}"
+ error_info = f"错误信息: type: {type(e).__name__}, {str(e)} in function {func.__name__} at line: {error_line}"
print(error_info)
logger.warning(error_info)
return []
+
return wrapper
@@ -134,7 +135,7 @@ def display_info():
else:
start5_time = now_time
except Exception as e:
- print("错误信息644:" + str(e) + "\r\n发生错误的行数: " + str(e.__traceback__.tb_lineno))
+ print("错误信息:" + str(e) + "\r\n发生错误的行数: " + str(e.__traceback__.tb_lineno))
logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
@@ -249,201 +250,242 @@ def change_max_connect():
@trace_error_decorator
def get_douyin_stream_url(json_data):
- # TODO: 获取抖音直播源地址
- room_info = json_data['roomInfo']
- anchor_name = room_info['anchor']['nickname']
- status = 4
- # 获取直播间状态
- if 'room' in room_info:
- status = room_info["room"]["status"] # 直播状态2是正在直播.4是未开播
+ room_info = json_data.get('roomInfo', {})
+ anchor_name = room_info.get('anchor', {}).get('nickname', '')
- if status == 4:
- data = [anchor_name, False, '', '']
- else:
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
+
+ status = room_info.get('room', {}).get("status", 4) # 直播状态 2 是正在直播、4 是未开播
+
+ if status == 2:
stream_url = room_info['room']['stream_url']
- # flv视频流链接
flv_url_list = stream_url['flv_pull_url']
- # m3u8视频流链接
m3u8_url_list = stream_url['hls_pull_url_map']
- # origin蓝光1080P、720超清hd、720高清sd、540标清ld
- if video_quality == "原画" or video_quality == "蓝光":
- m3u8_url = m3u8_url_list["FULL_HD1"]
- flv_url = flv_url_list["FULL_HD1"]
- elif video_quality == "超清":
- m3u8_url = m3u8_url_list["HD1"]
- flv_url = flv_url_list["HD1"]
- elif video_quality == "高清":
- m3u8_url = m3u8_url_list["SD1"]
- flv_url = flv_url_list["SD1"]
- elif video_quality == "标清":
- m3u8_url = m3u8_url_list["SD2"]
- flv_url = flv_url_list["SD2"]
+ video_qualities = {
+ "原画": "FULL_HD1",
+ "蓝光": "FULL_HD1",
+ "超清": "HD1",
+ "高清": "SD1",
+ "标清": "SD2",
+ }
- data = [anchor_name, True, m3u8_url, flv_url]
- return data
+ quality_key = video_qualities.get(video_quality)
+ if quality_key:
+ m3u8_url = m3u8_url_list.get(quality_key)
+ flv_url = flv_url_list.get(quality_key)
+
+ result['m3u8_url'] = m3u8_url
+ result['flv_url'] = flv_url
+ result['is_live'] = True
+ result['record_url'] = m3u8_url # 使用 m3u8 链接进行录制
+
+ return result
@trace_error_decorator
def get_tiktok_stream_url(json_data):
- # TODO: 获取Tiktok直播源地址
- live_room = json_data['LiveRoom']['liveRoomUserInfo']
- anchor_name = live_room['user']['nickname']
- status = live_room['user']["status"]
- # 直播状态2是正在直播.4是未开播
- if status == 4:
- data = [anchor_name, False, '', '']
- else:
- # 画质从高到低:origin>uhd>sd>sd>ld
- # {origin:'原画质或蓝光',uhd:'1080P或720P',sd:'540P或480P',ld:'360P标清'}
- # 上面画质对应只是一般情况,具体情况有可能不一样 可以看对应画质的sdk_params参数,里面有如1080P等参数
- stream_data = live_room['liveRoom']['streamData']['pull_data']['stream_data']
- stream_data = json.loads(stream_data)['data']
- if video_quality == "原画" or video_quality == "蓝光":
- m3u8_url = stream_data["origin"]['main']['hls']
- flv_url = stream_data["origin"]['main']['flv']
- elif video_quality == "超清":
- m3u8_url = stream_data["uhd"]['main']['hls']
- flv_url = stream_data["uhd"]['main']['flv']
- elif video_quality == "高清":
- m3u8_url = stream_data["sd"]['main']['hls']
- flv_url = stream_data["sd"]['main']['flv']
- elif video_quality == "标清":
- m3u8_url = stream_data["ld"]['main']['hls']
- flv_url = stream_data["ld"]['main']['flv']
- # 注意,这里要将链接改为http协议,否则无法使用ffmpeg录制,原因是代理大都是http
- m3u8_url = re.sub("https", "http", m3u8_url)
- flv_url = re.sub("https", "http", flv_url)
- data = [anchor_name, True, m3u8_url, flv_url]
- return data
+ def get_video_quality_url(stream_data, quality_key):
+ return {
+ 'hls': re.sub("https", "http", stream_data[quality_key]['main']['hls']),
+ 'flv': re.sub("https", "http", stream_data[quality_key]['main']['flv']),
+ }
+
+ live_room = json_data.get('LiveRoom', {}).get('liveRoomUserInfo', {})
+ user = live_room.get('user', {})
+ anchor_name = user.get('nickname', '')
+ status = user.get("status", 4)
+
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
+
+ if status == 2:
+ stream_data = live_room.get('liveRoom', {}).get('streamData', {}).get('pull_data', {}).get('stream_data', '{}')
+ stream_data = json.loads(stream_data).get('data', {})
+
+ video_qualities = {
+ "原画": "origin",
+ "蓝光": "origin",
+ "超清": "uhd",
+ "高清": "sd",
+ "标清": "ld",
+ }
+
+ quality_key = video_qualities.get(video_quality)
+ if quality_key:
+ video_quality_urls = get_video_quality_url(stream_data,quality_key)
+ result['flv_url'] = video_quality_urls['flv']
+ result['m3u8_url'] = video_quality_urls['hls']
+ result['is_live'] = True
+ if result['m3u8_url']:
+ result['record_url'] = video_quality_urls['hls']
+ else:
+ result['record_url'] = video_quality_urls['flv']
+ return result
@trace_error_decorator
def get_kuaishou_stream_url(json_data):
- # TODO: 获取快手直播源地址
- live_room = json_data['liveroom']
- anchor_name = live_room['author']['name']
- # 获取直播间状态
- status = live_room['isLiving']
- # 直播状态True是正在直播.False是未开播
- if not status:
- data = [anchor_name, False, '', '']
- else:
- stream_data = live_room['liveStream']['playUrls'][0]['adaptationSet']['representation']
- # stream_data数组中索引从小到大分别是高清、超清、蓝光4M、蓝光8M (每个直播间不一样)
- quality_list = [i for i in range(len(stream_data))][::-1]
- while len(quality_list) < 4:
- quality_list.append(quality_list[-1])
+ live_room = json_data.get('liveroom', {}).get('playList')[0]
+ anchor_name = live_room.get('author', {}).get('name', '')
- if video_quality == "原画" or video_quality == "蓝光":
- flv_url = stream_data[quality_list[0]]['url']
- elif video_quality == "超清":
- flv_url = stream_data[quality_list[1]]['url']
- elif video_quality == "高清":
- flv_url = stream_data[quality_list[2]]['url']
- elif video_quality == "标清":
- flv_url = stream_data[quality_list[3]]['url']
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
- data = [anchor_name, True, flv_url, flv_url] # 快手只有flv视频流
- return data
+ status = live_room.get('isLiving', False)
+ if status:
+ stream_data = live_room.get('liveStream', {}).get('playUrls', [{}])[0].get('adaptationSet', {}).get(
+ 'representation', [])
+
+ if stream_data:
+ quality_list = [i for i in range(len(stream_data))][::-1]
+
+ while len(quality_list) < 4:
+ quality_list.append(quality_list[-1])
+
+ video_quality_options = {
+ "原画": quality_list[0],
+ "蓝光": quality_list[0],
+ "超清": quality_list[1],
+ "高清": quality_list[2],
+ "标清": quality_list[3]
+ }
+
+ if video_quality not in video_quality_options:
+ raise ValueError(
+ f"Invalid video quality. Available options are: {', '.join(video_quality_options.keys())}")
+
+ flv_url = stream_data[video_quality_options[video_quality]]['url']
+
+ result['flv_url'] = flv_url
+ result['is_live'] = True
+ result['record_url'] = flv_url # 快手只有flv视频流
+ return result
@trace_error_decorator
def get_huya_stream_url(json_data):
- # TODO: 获取虎牙直播源地址
- game_live_info = json_data['data'][0]['gameLiveInfo']
- stream_info_list = json_data['data'][0]['gameStreamInfoList']
- anchor_name = game_live_info['nick']
- # 如果stream_info_list 值为空,则未开直播
- if len(stream_info_list) == 0:
- data = [anchor_name, False, '', '']
- else:
- # stream_info_list 索引从小到大 分别是'al', 'tx', 'hw', 'hs'四种cdn线路
- # 默认使用第一种 即host链接开头为al的cdn
+ game_live_info = json_data.get('data', [])[0].get('gameLiveInfo', {})
+ stream_info_list = json_data.get('data', [])[0].get('gameStreamInfoList', [])
+ anchor_name = game_live_info.get('nick', '')
+
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
+
+ if stream_info_list:
select_cdn = stream_info_list[0]
- s_flv_url = select_cdn['sFlvUrl']
- s_stream_name = select_cdn['sStreamName']
- s_flv_url_suffix = select_cdn['sFlvUrlSuffix']
- s_hls_url = select_cdn['sHlsUrl']
- s_hls_url_suffix = select_cdn['sHlsUrlSuffix']
- s_flv_anti_code = select_cdn['sFlvAntiCode']
- quality_list = s_flv_anti_code.split('&exsphd=')
+ s_flv_url = select_cdn.get('sFlvUrl')
+ s_stream_name = select_cdn.get('sStreamName')
+ s_flv_url_suffix = select_cdn.get('sFlvUrlSuffix')
+ s_hls_url = select_cdn.get('sHlsUrl')
+ s_hls_url_suffix = select_cdn.get('sHlsUrlSuffix')
+ s_flv_anti_code = select_cdn.get('sFlvAntiCode')
flv_url = f'{s_flv_url}/{s_stream_name}.{s_flv_url_suffix}?{s_flv_anti_code}&ratio='
m3u8_url = f'{s_hls_url}/{s_stream_name}.{s_hls_url_suffix}?{s_flv_anti_code}&ratio='
- if len(quality_list) != 1:
+
+ quality_list = s_flv_anti_code.split('&exsphd=')
+ if len(quality_list) > 1:
pattern = r"(?<=264_)\d+"
quality_list = [x for x in re.findall(pattern, quality_list[1])][::-1]
while len(quality_list) < 4:
quality_list.append(quality_list[-1])
- if video_quality == "原画" or video_quality == "蓝光":
- flv_url = flv_url + str(quality_list[0])
- m3u8_url = m3u8_url + str(quality_list[0])
- elif video_quality == "超清":
- flv_url = flv_url + str(quality_list[1])
- m3u8_url = m3u8_url + str(quality_list[1])
- elif video_quality == "高清":
- flv_url = flv_url + str(quality_list[2])
- m3u8_url = m3u8_url + str(quality_list[2])
- elif video_quality == "标清":
- flv_url = flv_url + str(quality_list[3])
- m3u8_url = m3u8_url + str(quality_list[3])
- data = [anchor_name, True, flv_url, m3u8_url] # 虎牙目前只能使用flv视频流录制
- return data
+
+ video_quality_options = {
+ "原画": quality_list[0],
+ "蓝光": quality_list[0],
+ "超清": quality_list[1],
+ "高清": quality_list[2],
+ "标清": quality_list[3]
+ }
+
+ if video_quality not in video_quality_options:
+ raise ValueError(
+ f"Invalid video quality. Available options are: {', '.join(video_quality_options.keys())}")
+
+ flv_url = flv_url + str(video_quality_options[video_quality])
+ m3u8_url = m3u8_url + str(video_quality_options[video_quality])
+
+ result['flv_url'] = flv_url
+ result['m3u8_url'] = m3u8_url
+ result['is_live'] = True
+ result['record_url'] = flv_url # 虎牙使用flv视频流录制
+
+ return result
@trace_error_decorator
-def get_douyu_stream_url(json_data):
- # TODO: 获取斗鱼直播源地址
+def get_douyu_stream_url(json_data, cookies):
+ # 获取斗鱼直播源地址
- room_info = json_data.get('pageContext',json_data)['pageProps']['room']['roomInfo']['roomInfo']
- anchor_name = room_info['nickname']
- status = room_info['isLive']
+ video_quality_options = {
+ "原画": '0',
+ "蓝光": '0',
+ "超清": '3',
+ "高清": '2',
+ "标清": '1'
+ }
+ room_info = json_data.get('pageContext', json_data)['pageProps']['room']['roomInfo']['roomInfo']
+ anchor_name = room_info.get('nickname', '')
+ status = room_info.get('isLive', False)
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
# 如果status值为1,则正在直播
# 这边有个bug,就是如果是直播回放,状态也是在直播 待修复
- if status != 1:
- data = [anchor_name, False, '', '']
- else:
- # rate: 1流畅;2高清;3超清;4蓝光4M;0蓝光8M或10M
+ if status == 1:
rid = str(room_info['rid'])
- if video_quality == "原画" or video_quality == "蓝光":
- flv_url = get_douyu_stream_data(rid, rate='0')['data']['url']
- elif video_quality == "超清":
- flv_url = get_douyu_stream_data(rid, rate='3')['data']['url']
- elif video_quality == "高清":
- flv_url = get_douyu_stream_data(rid, rate='2')['data']['url']
- elif video_quality == "标清":
- flv_url = get_douyu_stream_data(rid, rate='1')['data']['url']
-
- data = [anchor_name, True, flv_url, flv_url] # 斗鱼目前只能使用flv视频流录制
- return data
+ rate = video_quality_options.get(video_quality, '0') # 默认为原画
+ flv_data = get_douyu_stream_data(rid, rate, cookies)
+ flv_url = flv_data['data']['url']
+ result['flv_url'] = flv_url
+ result['is_live'] = True
+ result['record_url'] = flv_url # 斗鱼目前只能使用flv视频流录制
+ return result
@trace_error_decorator
def get_yy_stream_url(json_data):
# TODO: 获取YY直播源地址
- anchor_name = json_data['anchor_name']
- if 'avp_info_res' not in json_data:
- data = [anchor_name, False, '', '']
- else:
+ anchor_name = json_data.get('anchor_name', '')
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
+ if 'avp_info_res' in json_data:
stream_line_addr = json_data['avp_info_res']['stream_line_addr']
# 获取最后一个键的值
cdn_info = list(stream_line_addr.values())[0]
- stream_url = cdn_info['cdn_info']['url'] # 清晰度暂时默认高清
- data = [anchor_name, True, stream_url, stream_url] # 斗鱼目前只能使用flv视频流录制
- return data
+ flv_url = cdn_info['cdn_info']['url'] # 清晰度暂时默认高清
+ result['flv_url'] = flv_url
+ result['is_live'] = True
+ result['record_url'] = flv_url
+ return result
@trace_error_decorator
def get_bilibili_stream_url(json_data):
# TODO: 获取B站直播源地址
- anchor_name = json_data['roomInfoRes']['data']['anchor_info']['base_info']['uname']
+ anchor_name = json_data.get('roomInfoRes', {}).get('data', {}).get('anchor_info', {}).get('base_info', {}).get(
+ 'uname', '')
playurl_info = json_data['roomInitRes']['data']['playurl_info']
- if not playurl_info:
- data = [anchor_name, False, '', '']
- else:
+ result = {
+ "anchor_name": anchor_name,
+ "is_live": False,
+ }
+ if playurl_info:
def get_url(m, n):
format_list = ['.flv', '.m3u8']
# 字典中的键就是qn,其中qn=30000为杜比 20000为4K 10000为原画 400蓝光 250超清 150高清,qn=0是默认画质
@@ -476,16 +518,24 @@ def get_bilibili_stream_url(json_data):
elif video_quality == "标清":
flv_url = get_url(0, 3)
m3u8_url = get_url(1, 3)
- data = [anchor_name, True, m3u8_url, flv_url] # B站使用m3u8链接进行录制
- return data
+ else:
+ flv_url = get_url(0, 0)
+ m3u8_url = get_url(1, 0)
+
+ result['flv_url'] = flv_url
+ result['m3u8_url'] = m3u8_url
+ result['is_live'] = True
+ result['record_url'] = m3u8_url # B站使用m3u8链接进行录制
+ return result
-def start_record(line, count_variable=-1):
+def start_record(url_tuple, count_variable=-1):
global warning_count
global video_save_path
global live_list
global not_record_list
global recording_time_list
+
while True:
try:
record_finished = False
@@ -493,7 +543,6 @@ def start_record(line, count_variable=-1):
Runonce = False
is_long_url = False
count_time = time.time()
- url_tuple = line
record_url = url_tuple[0]
anchor_name = url_tuple[1]
print("\r运行新线程,传入地址 " + record_url)
@@ -524,7 +573,7 @@ def start_record(line, count_variable=-1):
with semaphore:
if use_proxy:
if global_proxy or proxy_addr != '':
- json_data = get_tiktok_stream_data(record_url, proxy_addr,tiktok_cookie)
+ json_data = get_tiktok_stream_data(record_url, proxy_addr, tiktok_cookie)
port_info = get_tiktok_stream_url(json_data)
elif record_url.find("https://live.kuaishou.com/") > -1:
@@ -534,31 +583,30 @@ def start_record(line, count_variable=-1):
elif record_url.find("https://www.huya.com/") > -1:
with semaphore:
- json_data = get_huya_stream_data(record_url,hy_cookie)
+ json_data = get_huya_stream_data(record_url, hy_cookie)
port_info = get_huya_stream_url(json_data)
elif record_url.find("https://www.douyu.com/") > -1:
with semaphore:
json_data = get_douyu_info_data(record_url)
- port_info = get_douyu_stream_url(json_data,douyu_cookie)
+ port_info = get_douyu_stream_url(json_data, douyu_cookie)
elif record_url.find("https://www.yy.com/") > -1:
with semaphore:
- json_data = get_yy_stream_data(record_url,yy_cookie)
+ json_data = get_yy_stream_data(record_url, yy_cookie)
port_info = get_yy_stream_url(json_data)
elif record_url.find("https://live.bilibili.com/") > -1:
with semaphore:
- json_data = get_bilibili_stream_data(record_url,bili_cookie)
+ json_data = get_bilibili_stream_data(record_url, bili_cookie)
port_info = get_bilibili_stream_url(json_data)
- # print("端口信息:" + str(port_info))
- # port_info=['主播名','状态码','m3u8地址','flv地址']
- if len(port_info) != 4:
- print(f'序号{count_variable} 网址内容获取失败,进行重试中...获取失败的地址是:{line}')
+ anchor_name = port_info.get("anchor_name", '')
+
+ if not anchor_name:
+ print(f'序号{count_variable} 网址内容获取失败,进行重试中...获取失败的地址是:{url_tuple}')
warning_count += 1
else:
- anchor_name = port_info[0]
anchor_name = re.sub(rstr, "_", anchor_name) # 过滤不能作为文件名的字符,替换为下划线
record_name = f'序号{count_variable} {anchor_name}'
@@ -574,7 +622,7 @@ def start_record(line, count_variable=-1):
name_list.append(f'{record_url}|{record_url},主播: {anchor_name.strip()}')
Runonce = True
- if port_info[1] is False:
+ if port_info['is_live'] is False:
print(f"{record_name} 等待直播... ")
else:
content = f"{record_name} 正在直播中..."
@@ -582,25 +630,13 @@ def start_record(line, count_variable=-1):
# 推送通知
if live_status_push != '':
if '微信' in live_status_push:
- xizhi(xizhi_api_url,content)
+ xizhi(xizhi_api_url, content)
if '钉钉' in live_status_push:
dingtalk(dingtalk_api_url, content, dingtalk_phone_num)
-
- # 是否显示直播地址
- if video_m3u8:
- if video_save_type == "FLV":
- print(f"{port_info[0]} 直播地址为:{port_info[3]}")
- else:
- print(f"{port_info[0]} 直播地址为:{port_info[2]}")
-
- real_url = port_info[2] # 默认使用第一种地址进行下载
+ real_url = port_info['record_url']
full_path = f'{default_path}/{anchor_name}'
-
- if real_url == "":
- print('解析错误,直播间视频流未找到...')
- pass
- else:
+ if real_url != "":
live_list.append(anchor_name)
now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
try:
@@ -620,8 +656,7 @@ def start_record(line, count_variable=-1):
if not os.path.exists(full_path):
print("保存路径不存在,不能生成录制.请避免把本程序放在c盘,桌面,下载文件夹,qq默认传输目录.请重新检查设置")
- video_save_path = ""
- print(f"因为配置文件的路径错误,本次录制在程序目录 {default_path}")
+ logger.warning("错误信息: 保存路径不存在,不能生成录制.请避免把本程序放在c盘,桌面,下载文件夹,qq默认传输目录.请重新检查设置")
ffmpeg_command = [
ffmpeg_path, "-y",
@@ -678,14 +713,17 @@ def start_record(line, count_variable=-1):
try:
# “port_info[3]”对应的是flv地址,使用老方法下载(直接请求下载flv)只能是下载flv流的。
- real_url = port_info[3]
+ real_url = port_info['flv_url']
_filepath, _ = urllib.request.urlretrieve(real_url, full_path + '/' + filename)
record_finished = True
record_finished_2 = True
count_time = time.time()
- except:
+
+ except Exception as e:
print('\r' + time.strftime('%Y-%m-%d %H:%M:%S ') + anchor_name + ' 未开播')
+ logger.warning(
+ "错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
elif video_save_type == "MKV":
@@ -852,8 +890,8 @@ def start_record(line, count_variable=-1):
threading.Thread(target=converts_m4a, args=(file,)).start()
except subprocess.CalledProcessError as e:
- # logging.warning(str(e.output))
- # logger.warning("错误信息: "+str(e) +" 发生错误的行数: "+str(e.__traceback__.tb_lineno))
+ logging.warning(str(e.output))
+ logger.warning("错误信息: "+str(e) +" 发生错误的行数: "+str(e.__traceback__.tb_lineno))
break
@@ -913,7 +951,7 @@ def start_record(line, count_variable=-1):
except Exception as e:
print(
- "错误信息644:" + str(e) + "\r\n读取的地址为: " + str(record_url) + " 发生错误的行数: " + str(
+ "错误信息:" + str(e) + "\r\n读取的地址为: " + str(record_url) + " 发生错误的行数: " + str(
e.__traceback__.tb_lineno))
logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
warning_count += 1
@@ -942,14 +980,13 @@ def start_record(line, count_variable=-1):
# 这里是正常循环
while x:
x = x - 1
- # print('\r循环等待%d秒 '%x)
if loop_time:
print('\r' + anchor_name + ' 循环等待%d秒 ' % x, end="")
time.sleep(1)
if loop_time:
print('\r检测直播间中...', end="")
except Exception as e:
- print("错误信息644:" + str(e) + "\r\n发生错误的行数: " + str(e.__traceback__.tb_lineno))
+ print("错误信息:" + str(e) + "\r\n发生错误的行数: " + str(e.__traceback__.tb_lineno))
logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
print("线程崩溃2秒后重试.错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
warning_count += 1
@@ -1031,7 +1068,6 @@ if not os.path.exists('./config'):
# 备份配置
t3 = threading.Thread(target=backup_file_start, args=(), daemon=True)
t3.start()
-Monitoring = 0
# 录制tiktok时,如果开启了电脑全局/规则代理,可以不用再在配置文件中填写代理地址
# 但强烈建议还是配置一下代理地址,否则非常不稳定
@@ -1094,7 +1130,6 @@ while True:
semaphore = threading.Semaphore(max_request)
delay_default = int(read_config_value(config, '录制设置', '循环时间(秒)', 60))
local_delay_default = int(read_config_value(config, '录制设置', '排队读取网址时间(秒)', 0))
- video_m3u8 = read_config_value(config, '录制设置', '是否显示直播地址', "否")
loop_time = read_config_value(config, '录制设置', '是否显示循环秒数', "否")
Splitvideobysize = read_config_value(config, '录制设置', 'TS格式分段录制是否开启', "否")
Splitsize = int(read_config_value(config, '录制设置', '视频分段大小(兆)', '1000'))
@@ -1151,7 +1186,6 @@ while True:
"否": False
}
use_proxy = options.get(use_proxy, False) # 是否使用代理ip
- video_m3u8 = options.get(video_m3u8, False) # 是否显示直播地址
loop_time = options.get(loop_time, False) # 是否显示循环秒数
Splitvideobysize = options.get(Splitvideobysize, False) # 这里是控制TS是否分段
create_time_file = options.get(create_time_file, False) # 这里控制是否生成时间文件
@@ -1198,7 +1232,6 @@ while True:
if replacewords[0] != replacewords[1]:
update_file(url_config_file, replacewords[0], replacewords[1])
- # print('url_tuples_list:',url_tuples_list)
if len(url_tuples_list) > 0:
textNoRepeatUrl = list(set(url_tuples_list))
if len(textNoRepeatUrl) > 0:
@@ -1221,7 +1254,7 @@ while True:
first_start = False
except Exception as e:
- print("错误信息644:" + str(e) + "\r\n发生错误的行数: " + str(e.__traceback__.tb_lineno))
+ print("错误信息:" + str(e) + "\r\n发生错误的行数: " + str(e.__traceback__.tb_lineno))
logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
if firstRunOtherLine:
@@ -1233,4 +1266,7 @@ while True:
firstRunOtherLine = False
# 总体循环3s
- time.sleep(3)
\ No newline at end of file
+ time.sleep(3)
+
+
+
diff --git a/spider.py b/spider.py
index ece60cc..6b32d15 100644
--- a/spider.py
+++ b/spider.py
@@ -4,7 +4,7 @@
Author: Hmily
Github:https://github.com/ihmily
Date: 2023-07-15 23:15:00
-Update: 2023-09-14 00:27:55
+Update: 2023-09-17 16:59:01
Copyright (c) 2023 by Hmily, All Rights Reserved.
Function: Get live stream data.
"""
@@ -25,14 +25,14 @@ opener = urllib.request.build_opener(no_proxy_handler)
# 直接选择从网页HTML中获取直播间数据
def get_douyin_stream_data(url, cookies=''):
- cookie = 'ttwid=1%7CB1qls3GdnZhUov9o2NxOMxxYS2ff6OSvEWbv0ytbES4%7C1680522049%7C280d802d6d478e3e78d0c807f7c487e7ffec0ae4e5fdd6a0fe74c3c6af149511; my_rd=1; passport_csrf_token=3ab34460fa656183fccfb904b16ff742; passport_csrf_token_default=3ab34460fa656183fccfb904b16ff742; d_ticket=9f562383ac0547d0b561904513229d76c9c21; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; store-region=cn-fj; store-region-src=uid; LOGIN_STATUS=1; __security_server_data_status=1; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; pwa2=%223%7C0%7C3%7C0%22; download_guide=%223%2F20230729%2F0%22; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.6%7D; strategyABtestKey=%221690824679.923%22; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; VIDEO_FILTER_MEMO_SELECT=%7B%22expireTime%22%3A1691443863751%2C%22type%22%3Anull%7D; home_can_add_dy_2_desktop=%221%22; __live_version__=%221.1.1.2169%22; device_web_cpu_core=8; device_web_memory_size=8; xgplayer_user_id=346045893336; csrf_session_id=2e00356b5cd8544d17a0e66484946f28; odin_tt=724eb4dd23bc6ffaed9a1571ac4c757ef597768a70c75fef695b95845b7ffcd8b1524278c2ac31c2587996d058e03414595f0a4e856c53bd0d5e5f56dc6d82e24004dc77773e6b83ced6f80f1bb70627; __ac_nonce=064caded4009deafd8b89; __ac_signature=_02B4Z6wo00f01HLUuwwAAIDBh6tRkVLvBQBy9L-AAHiHf7; ttcid=2e9619ebbb8449eaa3d5a42d8ce88ec835; webcast_leading_last_show_time=1691016922379; webcast_leading_total_show_times=1; webcast_local_quality=sd; live_can_add_dy_2_desktop=%221%22; msToken=1JDHnVPw_9yTvzIrwb7cQj8dCMNOoesXbA_IooV8cezcOdpe4pzusZE7NB7tZn9TBXPr0ylxmv-KMs5rqbNUBHP4P7VBFUu0ZAht_BEylqrLpzgt3y5ne_38hXDOX8o=; msToken=jV_yeN1IQKUd9PlNtpL7k5vthGKcHo0dEh_QPUQhr8G3cuYv-Jbb4NnIxGDmhVOkZOCSihNpA2kvYtHiTW25XNNX_yrsv5FN8O6zm3qmCIXcEe0LywLn7oBO2gITEeg=; tt_scid=mYfqpfbDjqXrIGJuQ7q-DlQJfUSG51qG.KUdzztuGP83OjuVLXnQHjsz-BRHRJu4e986'
- if cookies != '':
- cookie = cookies
+ if cookies == '':
+ cookies = 'ttwid=1%7CB1qls3GdnZhUov9o2NxOMxxYS2ff6OSvEWbv0ytbES4%7C1680522049%7C280d802d6d478e3e78d0c807f7c487e7ffec0ae4e5fdd6a0fe74c3c6af149511; my_rd=1; passport_csrf_token=3ab34460fa656183fccfb904b16ff742; passport_csrf_token_default=3ab34460fa656183fccfb904b16ff742; d_ticket=9f562383ac0547d0b561904513229d76c9c21; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; store-region=cn-fj; store-region-src=uid; LOGIN_STATUS=1; __security_server_data_status=1; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; pwa2=%223%7C0%7C3%7C0%22; download_guide=%223%2F20230729%2F0%22; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.6%7D; strategyABtestKey=%221690824679.923%22; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; VIDEO_FILTER_MEMO_SELECT=%7B%22expireTime%22%3A1691443863751%2C%22type%22%3Anull%7D; home_can_add_dy_2_desktop=%221%22; __live_version__=%221.1.1.2169%22; device_web_cpu_core=8; device_web_memory_size=8; xgplayer_user_id=346045893336; csrf_session_id=2e00356b5cd8544d17a0e66484946f28; odin_tt=724eb4dd23bc6ffaed9a1571ac4c757ef597768a70c75fef695b95845b7ffcd8b1524278c2ac31c2587996d058e03414595f0a4e856c53bd0d5e5f56dc6d82e24004dc77773e6b83ced6f80f1bb70627; __ac_nonce=064caded4009deafd8b89; __ac_signature=_02B4Z6wo00f01HLUuwwAAIDBh6tRkVLvBQBy9L-AAHiHf7; ttcid=2e9619ebbb8449eaa3d5a42d8ce88ec835; webcast_leading_last_show_time=1691016922379; webcast_leading_total_show_times=1; webcast_local_quality=sd; live_can_add_dy_2_desktop=%221%22; msToken=1JDHnVPw_9yTvzIrwb7cQj8dCMNOoesXbA_IooV8cezcOdpe4pzusZE7NB7tZn9TBXPr0ylxmv-KMs5rqbNUBHP4P7VBFUu0ZAht_BEylqrLpzgt3y5ne_38hXDOX8o=; msToken=jV_yeN1IQKUd9PlNtpL7k5vthGKcHo0dEh_QPUQhr8G3cuYv-Jbb4NnIxGDmhVOkZOCSihNpA2kvYtHiTW25XNNX_yrsv5FN8O6zm3qmCIXcEe0LywLn7oBO2gITEeg=; tt_scid=mYfqpfbDjqXrIGJuQ7q-DlQJfUSG51qG.KUdzztuGP83OjuVLXnQHjsz-BRHRJu4e986'
+
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.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://live.douyin.com/',
- 'Cookie': cookie
+ 'Cookie': cookies
}
# response = requests.get(url, headers=headers)
@@ -53,12 +53,11 @@ def get_douyin_stream_data(url, cookies=''):
def get_tiktok_stream_data(url, proxy_addr, cookies=''):
- 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 != '':
- cookie = cookies
+ if cookies == '':
+ cookies = '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='
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': cookie
+ 'Cookie': cookies
}
if proxy_addr != '':
@@ -79,37 +78,39 @@ def get_tiktok_stream_data(url, proxy_addr, cookies=''):
json_str = re.findall(
'