mirror of
https://github.com/ihmily/DouyinLiveRecorder.git
synced 2025-12-26 05:48:32 +08:00
Add kuaishou live record
This commit is contained in:
parent
0acb7a5562
commit
e3d4e95f36
23
README.md
23
README.md
@ -25,13 +25,15 @@
|
||||
- 运行主文件main.py启动程序
|
||||
- 在config文件夹内的配置文件中对录制进行配置以及添加录制直播间地址
|
||||
- 录制需要使用到PC端直播间页面的Cookie,请先在config.ini配置文件中添加后再进行录制
|
||||
- 注意事项① 录制使用到了ffmpeg,如果没有则无法进行录制
|
||||
- 注意事项① 录制使用到了ffmpeg,如果没有则无法进行录制,请将ffmpeg.exe放置运行文件同个文件夹
|
||||
- 注意事项② 录制Tiktok时需要使用vpn代理,请先在配置文件中设置开启代理并添加proxy_addr
|
||||
- 注意事项③ 如果电脑开启了全局或者规则代理,可不用添加proxy_addr参数值但仍需在config.ini配置文件中设置开启代理
|
||||
- 抖音app端直播间分享地址和网页端长地址都能正常进行录制(尽量用长链接,避免因短链接转换失效导致不能正常录制),Tiktok直播间地址目前只支持一种
|
||||
- 注意事项④,不知道是不是ffmpeg的原因,测试时在Pycharm中运行进行直播录制,录制出来的视频无法正常播放,而在命令控制台DOS界面运行代码,录制出来的视频可正常播放,这点请注意,别误认为不能录制。
|
||||
|
||||
 
|
||||
|
||||
抖音app端直播间分享地址和网页端长地址都能正常进行录制(尽量用长链接,避免因短链接转换失效导致不能正常录制),Tiktok和快手直播间地址目前只支持一种。
|
||||
|
||||
抖音直播间链接示例:
|
||||
|
||||
```
|
||||
@ -55,16 +57,25 @@ https://www.tiktok.com/@bougiebulliesandbirds/live
|
||||
|
||||
请求示例:https://hmily.vip/api/dy/live/?url=https://live.douyin.com/573716250978
|
||||
|
||||
(只支持抖音,Tiktok的没写)
|
||||
短地址转换长地址:https://hmily.vip/api/dy/live/convert?url=https://v.douyin.com/iQLgKSj/
|
||||
|
||||
注:本测试API只写了抖音的
|
||||
|
||||
 
|
||||
|
||||
## ❤️贡献者
|
||||
|
||||
   [](https://github.com/ihmily)
|
||||
|
||||
 
|
||||
|
||||
## 提交日志
|
||||
|
||||
 
|
||||
- 20230804
|
||||
- 新增了快手直播录制,优化了部分代码
|
||||
|
||||
- 20230803
|
||||
- 通宵更新 一直熬夜一直爽
|
||||
- 通宵更新
|
||||
- 新增了国际版抖音Tiktok的直播录制,去除冗余 简化了部分代码
|
||||
|
||||
- 20230724
|
||||
@ -73,6 +84,6 @@ https://www.tiktok.com/@bougiebulliesandbirds/live
|
||||
|
||||
 
|
||||
|
||||
## 有问题可以提issue 或 参与pr,后续我会在这里不断更新其他直播平台的录制 欢迎给个star
|
||||
## 有问题可以提issue 或 参与pr,后续我会在这里不断更新其他直播平台的录制 欢迎给个Star
|
||||
|
||||
####
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
https://live.douyin.com/326500301367
|
||||
https://live.douyin.com/466747346712
|
||||
https://live.douyin.com/973349577278
|
||||
https://live.kuaishou.com/u/yall1102
|
||||
@ -15,7 +15,5 @@ ts录制完成后自动增加生成mp4格式 = 否
|
||||
ts录制完成后自动增加生成m4a格式 = 否
|
||||
追加格式后删除原文件 = 否
|
||||
生成时间文件 = 否
|
||||
是否显示浏览器 = 否
|
||||
仅用浏览器录制 = 否
|
||||
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
|
||||
|
||||
|
||||
186
main.py
186
main.py
@ -4,9 +4,9 @@
|
||||
Author: Hmily
|
||||
Github: https://github.com/ihmily
|
||||
Date: 2023-07-17 23:52:05
|
||||
Update: 2023-08-03 08:06:43
|
||||
Update: 2023-08-04 06:30:00
|
||||
Copyright (c) 2023 by Hmily, All Rights Reserved.
|
||||
Function: Record douyin and titok live stream.
|
||||
Function: Record live stream video.
|
||||
"""
|
||||
|
||||
import random
|
||||
@ -55,8 +55,9 @@ name_list = []
|
||||
firstRunOtherLine = True
|
||||
live_list = []
|
||||
not_record_list = []
|
||||
start5 = datetime.datetime.now()
|
||||
start5_time = datetime.datetime.now()
|
||||
global_proxy = False
|
||||
recording_time_list={}
|
||||
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'
|
||||
}
|
||||
@ -66,13 +67,15 @@ backup_dir = './backup_config'
|
||||
encoding = 'utf-8-sig'
|
||||
rstr = r"[\/\\\:\*\?\"\<\>\|&u]"
|
||||
ffmpeg_path = "ffmpeg" # ffmpeg文件路径
|
||||
default_path = os.getcwd()
|
||||
|
||||
|
||||
# --------------------------用到的函数-------------------------------------
|
||||
|
||||
def display_info():
|
||||
# TODO: 显示当前录制配置信息
|
||||
global start5
|
||||
global start5_time
|
||||
global recording_time_list
|
||||
time.sleep(5)
|
||||
while True:
|
||||
try:
|
||||
@ -85,25 +88,22 @@ def display_info():
|
||||
print("配置文件里,直播保存路径并不存在,请重新输入一个正确的路径.或留空表示当前目录,按回车退出")
|
||||
input("程序结束")
|
||||
os._exit(0)
|
||||
|
||||
if use_proxy:
|
||||
is_use_proxy='是'
|
||||
else:
|
||||
print("视频保存路径: " + video_save_path, end=" | ")
|
||||
pass
|
||||
else:
|
||||
print("视频保存路径: 当前目录", end=" | ")
|
||||
is_use_proxy = '否'
|
||||
print(f"是否开启代理录制: {is_use_proxy}", end=" | ")
|
||||
|
||||
if Splitvideobysize:
|
||||
print("TS录制分段开启,录制分段大小为 %d M" % Splitsize, end=" | ")
|
||||
|
||||
if only_browser:
|
||||
print("浏览器检测录制", end=" | ")
|
||||
else:
|
||||
print("Cookies录制", end=" | ")
|
||||
|
||||
print("录制视频质量为: " + str(video_quality), end=" | ")
|
||||
print("录制视频格式为: " + str(video_save_type), end=" | ")
|
||||
print("目前瞬时错误数为: " + str(warning_count), end=" | ")
|
||||
nowdate = time.strftime("%H:%M:%S", time.localtime())
|
||||
print(nowdate)
|
||||
print(f"当前时间: {nowdate}")
|
||||
|
||||
if len(recording) == 0 and len(unrecording) == 0:
|
||||
time.sleep(5)
|
||||
@ -111,17 +111,19 @@ def display_info():
|
||||
print("")
|
||||
continue
|
||||
else:
|
||||
now_time = datetime.datetime.now()
|
||||
if len(recording) > 0:
|
||||
print("x" * 60)
|
||||
NoRepeatrecording = list(set(recording))
|
||||
print("正在录制{}个直播: ".format(str(len(NoRepeatrecording))))
|
||||
print(f"正在录制{len(NoRepeatrecording)}个直播: ")
|
||||
for recording_live in NoRepeatrecording:
|
||||
print(recording_live + " 正在录制中")
|
||||
end = datetime.datetime.now()
|
||||
print('总共录制时间: ' + str(end - start5))
|
||||
have_record_time=now_time-recording_time_list[recording_live]
|
||||
print(f"{recording_live} 正在录制中 "+str(have_record_time).split('.')[0])
|
||||
|
||||
# print('\n本软件已运行:'+str(now_time - start5_time).split('.')[0])
|
||||
print("x" * 60)
|
||||
else:
|
||||
start5 = datetime.datetime.now()
|
||||
start5_time = now_time
|
||||
except Exception as e:
|
||||
print("错误信息644:" + str(e) + "\r\n发生错误的行数: "+str(e.__traceback__.tb_lineno))
|
||||
logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
|
||||
@ -245,13 +247,14 @@ def get_douyin_stream_url(json_data):
|
||||
roomInfo = roomStore['roomInfo']
|
||||
anchor_name = roomInfo['anchor']['nickname']
|
||||
data.append(anchor_name)
|
||||
status=4
|
||||
# 获取直播间状态
|
||||
if 'room' in roomInfo:
|
||||
status = roomInfo["room"]["status"] # 直播状态2是正在直播.4是未开播
|
||||
|
||||
if status == 4:
|
||||
data = [anchor_name, status, '', '']
|
||||
data = [anchor_name, False, '', '']
|
||||
else:
|
||||
is_login = json_data['app']['odin']['user_is_login']
|
||||
stream_url = roomInfo['room']['stream_url']
|
||||
# flv视频流链接
|
||||
flv_url_list = stream_url['flv_pull_url']
|
||||
@ -272,7 +275,7 @@ def get_douyin_stream_url(json_data):
|
||||
m3u8_url = m3u8_url_list["SD2"]
|
||||
flv_url = flv_url_list["SD2"]
|
||||
|
||||
data = [anchor_name, status, m3u8_url, flv_url]
|
||||
data = [anchor_name, True, m3u8_url, flv_url]
|
||||
return data
|
||||
|
||||
def get_tiktok_stream_url(json_data):
|
||||
@ -286,7 +289,7 @@ def get_tiktok_stream_url(json_data):
|
||||
status = LiveRoom['user']["status"] # 直播状态2是正在直播.4是未开播
|
||||
|
||||
if status == 4:
|
||||
data = [anchor_name, status, '', '']
|
||||
data = [anchor_name, False, '', '']
|
||||
else:
|
||||
# 画质从高到低:origin>uhd>sd>sd>ld
|
||||
# {origin:'原画质或蓝光',uhd:'1080P或720P',sd:'540P或480P',ld:'360P标清'}
|
||||
@ -308,16 +311,43 @@ def get_tiktok_stream_url(json_data):
|
||||
# 注意,这里要将链接改为http协议,否则无法使用ffmpeg录制,原因是代理大都是http
|
||||
m3u8_url = re.sub("https", "http", m3u8_url)
|
||||
flv_url = re.sub("https", "http", flv_url)
|
||||
data = [anchor_name, status, m3u8_url, flv_url]
|
||||
data = [anchor_name, True, m3u8_url, flv_url]
|
||||
return data
|
||||
|
||||
def get_kuaishou_stream_url(json_data):
|
||||
# TODO: 获取快手直播源地址
|
||||
data = [] # 定义一个返回数据列表
|
||||
|
||||
|
||||
liveroom = json_data['liveroom']
|
||||
anchor_name = liveroom['author']['name']
|
||||
data.append(anchor_name)
|
||||
# 获取直播间状态
|
||||
status = liveroom['isLiving'] # 直播状态True是正在直播.False是未开播
|
||||
|
||||
if not status:
|
||||
data = [anchor_name, False, '', '']
|
||||
else:
|
||||
stream_data = liveroom['liveStream']['playUrls'][0]['adaptationSet']['representation']
|
||||
# stream_data数组中索引从小到大分别是高清、超清、蓝光4M、蓝光8M (每个直播间不一样)
|
||||
if video_quality == "原画" or video_quality == "蓝光":
|
||||
flv_url = stream_data[-1]['url']
|
||||
elif video_quality == "超清":
|
||||
flv_url = stream_data[-2]['url']
|
||||
elif video_quality == "高清":
|
||||
flv_url = stream_data[1]['url']
|
||||
elif video_quality == "标清":
|
||||
flv_url = stream_data[0]['url']
|
||||
|
||||
data = [anchor_name, True, flv_url, flv_url] # 快手只有flv视频流
|
||||
return data
|
||||
|
||||
def start_record(line, count_variable=-1):
|
||||
global warning_count
|
||||
global video_save_path
|
||||
global live_list
|
||||
global not_record_list
|
||||
global need_proxy_url_list
|
||||
global recording_time_list
|
||||
while True:
|
||||
try:
|
||||
record_finished = False
|
||||
@ -358,6 +388,11 @@ def start_record(line, count_variable=-1):
|
||||
json_data = get_tiktok_stream_data(record_url,proxy_addr)
|
||||
port_info = get_tiktok_stream_url(json_data)
|
||||
|
||||
elif record_url.find("https://live.kuaishou.com/") > -1:
|
||||
with semaphore:
|
||||
json_data = get_kuaishou_stream_data(record_url)
|
||||
port_info = get_kuaishou_stream_url(json_data)
|
||||
|
||||
# print("端口信息:" + str(port_info))
|
||||
# port_info=['主播名','状态码','m3u8地址','flv地址']
|
||||
if len(port_info) != 4:
|
||||
@ -380,7 +415,7 @@ def start_record(line, count_variable=-1):
|
||||
Runonce = True
|
||||
|
||||
# 判断状态码 如果是2则正在直播,如果是4则未在直播
|
||||
if port_info[1] != 2:
|
||||
if not port_info[1]:
|
||||
print(f"序号{count_variable} {port_info[0]} 等待直播... ")
|
||||
anchor_name = port_info[0]
|
||||
else:
|
||||
@ -402,11 +437,13 @@ def start_record(line, count_variable=-1):
|
||||
live_list.append(anchor_name)
|
||||
now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
|
||||
try:
|
||||
full_path = f'{default_path}/{anchor_name}'
|
||||
if len(video_save_path) > 0:
|
||||
if video_save_path[-1] != "/":
|
||||
video_save_path = video_save_path + "/"
|
||||
if not os.path.exists(video_save_path + anchor_name):
|
||||
os.makedirs(video_save_path + anchor_name)
|
||||
full_path = f'{video_save_path}/{anchor_name}'
|
||||
if not os.path.exists(full_path):
|
||||
os.makedirs(full_path)
|
||||
else:
|
||||
if not os.path.exists(anchor_name):
|
||||
os.makedirs('./' + anchor_name)
|
||||
@ -415,10 +452,9 @@ def start_record(line, count_variable=-1):
|
||||
print("路径错误信息708: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
|
||||
logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno))
|
||||
|
||||
if not os.path.exists(video_save_path + anchor_name):
|
||||
if not os.path.exists(full_path):
|
||||
print("保存路径不存在,不能生成录制.请避免把本程序放在c盘,桌面,下载文件夹,qq默认传输目录.请重新检查设置")
|
||||
video_save_path = ""
|
||||
default_path = os.getcwd()
|
||||
print(f"因为配置文件的路径错误,本次录制在程序目录 {default_path}")
|
||||
|
||||
|
||||
@ -452,27 +488,23 @@ def start_record(line, count_variable=-1):
|
||||
]
|
||||
|
||||
# 添加代理参数
|
||||
if 'douyin' not in real_url:
|
||||
if 'tiktok' in real_url:
|
||||
if use_proxy and proxy_addr != '':
|
||||
# os.environ["http_proxy"] = proxy_addr
|
||||
ffmpeg_command.insert(1, "-http_proxy")
|
||||
ffmpeg_command.insert(2, proxy_addr)
|
||||
|
||||
|
||||
recording.add(f'序号{count_variable} ' + anchor_name)
|
||||
record_name=f'序号{count_variable} ' + anchor_name
|
||||
recording.add(record_name)
|
||||
start_record_time = datetime.datetime.now()
|
||||
recording_time_list[record_name] = start_record_time
|
||||
rec_info=f"\r{anchor_name} 录制视频中: {full_path}"
|
||||
filename_short = full_path + '/' + anchor_name + '_' + now
|
||||
|
||||
if video_save_type == "FLV":
|
||||
filename = anchor_name + '_' + now + '.flv'
|
||||
|
||||
if len(video_save_path) == 0:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename)
|
||||
else:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename)
|
||||
|
||||
|
||||
filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now
|
||||
print(f'{rec_info}/{filename}')
|
||||
|
||||
if create_time_file:
|
||||
filename_gruop = [anchor_name, filename_short]
|
||||
@ -484,7 +516,7 @@ def start_record(line, count_variable=-1):
|
||||
try:
|
||||
# “port_info[3]”对应的是flv地址,使用老方法下载(直接请求下载flv)只能是下载flv流的。
|
||||
real_url = port_info[3]
|
||||
_filepath, _ = urllib.request.urlretrieve(real_url,video_save_path + anchor_name + '/' + filename)
|
||||
_filepath, _ = urllib.request.urlretrieve(real_url,full_path + '/' + filename)
|
||||
record_finished = True
|
||||
record_finished_2 = True
|
||||
count_time = time.time()
|
||||
@ -500,14 +532,8 @@ def start_record(line, count_variable=-1):
|
||||
|
||||
elif video_save_type == "MKV":
|
||||
filename = anchor_name + '_' + now + ".mkv"
|
||||
if len(video_save_path) == 0:
|
||||
print("\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename)
|
||||
else:
|
||||
print("\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename)
|
||||
|
||||
file = video_save_path + anchor_name + '/' + filename
|
||||
filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now
|
||||
|
||||
print(f'{rec_info}/{filename}')
|
||||
file = full_path + '/' + filename
|
||||
if create_time_file:
|
||||
filename_gruop = [anchor_name, filename_short]
|
||||
create_var[str(filename_short)] = threading.Thread(target=create_ass_file,
|
||||
@ -540,17 +566,10 @@ def start_record(line, count_variable=-1):
|
||||
unrecording.add(anchor_name)
|
||||
|
||||
elif video_save_type == "MP4":
|
||||
|
||||
filename = anchor_name + '_' + now + ".mp4"
|
||||
if len(video_save_path) == 0:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename)
|
||||
else:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename)
|
||||
|
||||
file = video_save_path + anchor_name + '/' + filename
|
||||
|
||||
filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now
|
||||
print(f'{rec_info}/{filename}')
|
||||
file = full_path + '/' + filename
|
||||
|
||||
if create_time_file:
|
||||
filename_gruop = [anchor_name, filename_short]
|
||||
@ -589,14 +608,9 @@ def start_record(line, count_variable=-1):
|
||||
|
||||
elif video_save_type == "MKV音频":
|
||||
filename = anchor_name + '_' + now + ".mkv"
|
||||
if len(video_save_path) == 0:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制MKV音频中: " + os.getcwd() + "/" + anchor_name + '/' + filename)
|
||||
else:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制MKV音频中: " + video_save_path + anchor_name + '/' + filename)
|
||||
print(f'{rec_info}/{filename}')
|
||||
file = full_path + '/' + filename
|
||||
|
||||
file = video_save_path + anchor_name + '/' + filename
|
||||
try:
|
||||
command = [
|
||||
"-map", "0:a", # 不同点
|
||||
@ -624,14 +638,9 @@ def start_record(line, count_variable=-1):
|
||||
|
||||
elif video_save_type == "TS音频":
|
||||
filename = anchor_name + '_' + now + ".ts"
|
||||
if len(video_save_path) == 0:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制TS音频中: " + os.getcwd() + "/" + anchor_name + '/' + filename)
|
||||
else:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制TS音频中: " + video_save_path + anchor_name + '/' + filename)
|
||||
print(f'{rec_info}/{filename}')
|
||||
file = full_path + '/' + filename
|
||||
|
||||
file = video_save_path + anchor_name + '/' + filename
|
||||
try:
|
||||
command = [
|
||||
"-map", "0:a", # 不同点
|
||||
@ -663,15 +672,8 @@ def start_record(line, count_variable=-1):
|
||||
while True:
|
||||
now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
|
||||
filename = anchor_name + '_' + now + ".ts"
|
||||
if len(video_save_path) == 0:
|
||||
print(
|
||||
"\r" + anchor_name + " 分段录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename + " 每录满: %d M 存一个视频" % Splitsize)
|
||||
else:
|
||||
print(
|
||||
"\r" + anchor_name + " 分段录制视频中: " + video_save_path + anchor_name + '/' + filename + " 每录满: %d M 存一个视频" % Splitsize)
|
||||
|
||||
file = video_save_path + anchor_name + '/' + filename
|
||||
filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now
|
||||
print(f'{rec_info}/{filename}')
|
||||
file = full_path + '/' + filename
|
||||
|
||||
if create_time_file:
|
||||
filename_gruop = [anchor_name, filename_short]
|
||||
@ -718,15 +720,9 @@ def start_record(line, count_variable=-1):
|
||||
|
||||
else:
|
||||
filename = anchor_name + '_' + now + ".ts"
|
||||
if len(video_save_path) == 0:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename)
|
||||
else:
|
||||
print(
|
||||
"\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename)
|
||||
|
||||
file = video_save_path + anchor_name + '/' + filename
|
||||
filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now
|
||||
print(f'{rec_info}/{filename}')
|
||||
file = full_path + '/' + filename
|
||||
|
||||
if create_time_file:
|
||||
filename_gruop = [anchor_name, filename_short]
|
||||
@ -955,8 +951,6 @@ while True:
|
||||
tsconvert_to_m4a = read_config_value(config, '1', 'TS录制完成后自动增加生成m4a格式', "否")
|
||||
delFilebeforeconversion = read_config_value(config, '1', '追加格式后删除原文件', "否")
|
||||
create_time_file = read_config_value(config, '1', '生成时间文件', "否")
|
||||
display_chrome = read_config_value(config, '1', '是否显示浏览器', "否")
|
||||
only_browser = read_config_value(config, '1', '仅用浏览器录制', "否")
|
||||
cookies_set = read_config_value(config, '1', 'cookies(不可为空)', '')
|
||||
|
||||
if len(video_save_type) > 0:
|
||||
@ -1005,14 +999,11 @@ while True:
|
||||
loop_time = options.get(loop_time, False) # 是否显示循环秒数
|
||||
Splitvideobysize = options.get(Splitvideobysize, False) # 这里是控制TS是否分段
|
||||
create_time_file = options.get(create_time_file, False) # 这里控制是否生成时间文件
|
||||
display_chrome = options.get(display_chrome, False) # 这里控制是否生显示浏览器
|
||||
only_browser = options.get(only_browser, False) # 这里是控制采用浏览器录制
|
||||
delFilebeforeconversion = options.get(delFilebeforeconversion, False) # 追加格式后,是否删除原文件
|
||||
tsconvert_to_m4a = options.get(tsconvert_to_m4a, False) # 这里是控制TS是否追加m4a格式
|
||||
tsconvert_to_mp4 = options.get(tsconvert_to_mp4, False) # 这里是控制TS是否追加mp4格式
|
||||
|
||||
|
||||
|
||||
# 读取url_config.ini文件
|
||||
try:
|
||||
with open(url_config_file, "r", encoding=encoding) as file:
|
||||
@ -1027,7 +1018,7 @@ while True:
|
||||
split_line = [line, '']
|
||||
url = split_line[0]
|
||||
url_host=url.split('/')[2]
|
||||
host_list=['live.douyin.com','v.douyin.com','www.tiktok.com']
|
||||
host_list=['live.douyin.com','v.douyin.com','www.tiktok.com','live.kuaishou.com']
|
||||
if url_host in host_list:
|
||||
new_line = (url, split_line[1])
|
||||
url_tuples_list.append(new_line)
|
||||
@ -1058,7 +1049,6 @@ while True:
|
||||
create_var['thread' + str(Monitoring)].daemon = True
|
||||
create_var['thread' + str(Monitoring)].start()
|
||||
runing_list.append(url_tuple[0])
|
||||
# print("\r"+str(local_delay_default)+" 秒后读取下一个地址(如果存在) ")
|
||||
time.sleep(local_delay_default)
|
||||
url_tuples_list = []
|
||||
first_start = False
|
||||
|
||||
40
spider.py
40
spider.py
@ -4,9 +4,9 @@
|
||||
Author: Hmily
|
||||
Github:https://github.com/ihmily
|
||||
Date: 2023-07-15 23:15:00
|
||||
Update: 2023-08-03 08:06:43
|
||||
Update: 2023-08-04 06:30:00
|
||||
Copyright (c) 2023 by Hmily, All Rights Reserved.
|
||||
Function: Get douyin and titok live stream.
|
||||
Function: Get live stream data.
|
||||
"""
|
||||
import urllib
|
||||
import urllib.parse
|
||||
@ -14,14 +14,13 @@ import requests
|
||||
import re
|
||||
import json
|
||||
|
||||
# 直接选择从网页HTML中获取直播间数据
|
||||
def get_douyin_stream_data(url,cookies):
|
||||
|
||||
# 直接选择从网页HTML中获取直播间数据
|
||||
def get_douyin_stream_data(url, cookies):
|
||||
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':'ttwid=1^%^7CIkooT8SJQrpeYtHlSALuhz9BdcHpaaf9tHQRKHuDaYE^%^7C1687785070^%^7C6690250483b63b6482128174d0f93bd879614d76f1b6e03ca52e032cf7fbaafd; passport_csrf_token=52bece134ac246c81163cc93b72f86a6; passport_csrf_token_default=52bece134ac246c81163cc93b72f86a6; d_ticket=2b9e3eb3626216c0122f0d980f867deb7b414; odin_tt=36dcfa4bd95b1edf0e6445dc9584a7371b4b90a2a8c390292b9be44af8161e06d10e34e6e575bf43c45c0a5871229533; passport_assist_user=CjxqZLHwcDmhxMjoh8u0-Jz4Zmhcq9VzKQqpAjK3P9Ve87i4njjbsai_u6NAI6MebG4KH4QXtbfNRbRFWRgaSAo8oBvHC_eXhqSGSo1uWPz4KBGu9uo-UdwM-5ynbDuDQRybofj0pQlPexcYmVoryiYqpC7yMdKO4rSVclgNEJbxtA0Yia_WVCIBA78Lg84^%^3D; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; passport_auth_status=a74f300f376940d65914eb148d55ca96^%^2C9ca487aea255972120d502f736c5dd7b; passport_auth_status_ss=a74f300f376940d65914eb148d55ca96^%^2C9ca487aea255972120d502f736c5dd7b; sso_auth_status=52ecac30d95890cc7896c880366aa21a; sso_auth_status_ss=52ecac30d95890cc7896c880366aa21a; sso_uid_tt=a71f659bc416b890eb13929ee82a4340; sso_uid_tt_ss=a71f659bc416b890eb13929ee82a4340; toutiao_sso_user=da6c1f563492114cf1ad2dac7617e3f4; toutiao_sso_user_ss=da6c1f563492114cf1ad2dac7617e3f4; sid_ucp_sso_v1=1.0.0-KDNhOTk2NzYzZjkzMGZkZDdlNDU4ODE3YjczNGE3MGExYTBhOGQ0OGIKHQjRpfzk8AEQn6LmpAYY7zEgDDCRxffLBTgCQPEHGgJsZiIgZGE2YzFmNTYzNDkyMTE0Y2YxYWQyZGFjNzYxN2UzZjQ; ssid_ucp_sso_v1=1.0.0-KDNhOTk2NzYzZjkzMGZkZDdlNDU4ODE3YjczNGE3MGExYTBhOGQ0OGIKHQjRpfzk8AEQn6LmpAYY7zEgDDCRxffLBTgCQPEHGgJsZiIgZGE2YzFmNTYzNDkyMTE0Y2YxYWQyZGFjNzYxN2UzZjQ; sid_guard=219f9f2d8838724307589f32debd7d62^%^7C1687785774^%^7C5183988^%^7CFri^%^2C+25-Aug-2023+13^%^3A22^%^3A42+GMT; uid_tt=9f33ebaf781ad75909d6d4edb0b46b86; uid_tt_ss=9f33ebaf781ad75909d6d4edb0b46b86; sid_tt=219f9f2d8838724307589f32debd7d62; sessionid=219f9f2d8838724307589f32debd7d62; sessionid_ss=219f9f2d8838724307589f32debd7d62; sid_ucp_v1=1.0.0-KGZkMzE1MGRhMTZiOTI4M2ZkOTkzMjIwNjQ5NmJhMjhjMzlhZmFmMGYKGQjRpfzk8AEQrqLmpAYY7zEgDDgCQPEHSAQaAmxmIiAyMTlmOWYyZDg4Mzg3MjQzMDc1ODlmMzJkZWJkN2Q2Mg; ssid_ucp_v1=1.0.0-KGZkMzE1MGRhMTZiOTI4M2ZkOTkzMjIwNjQ5NmJhMjhjMzlhZmFmMGYKGQjRpfzk8AEQrqLmpAYY7zEgDDgCQPEHSAQaAmxmIiAyMTlmOWYyZDg4Mzg3MjQzMDc1ODlmMzJkZWJkN2Q2Mg; LOGIN_STATUS=1; store-region=cn-fj; store-region-src=uid; __security_server_data_status=1; __live_version__=^%^221.1.1.1250^%^22; live_can_add_dy_2_desktop=^%^220^%^22; xgplayer_user_id=528819598596; publish_badge_show_info=^%^220^%^2C0^%^2C0^%^2C1689195658062^%^22; msToken=OqErXe8WFLs1OjcJCNX2pNWTvnMSJIKjUXQRa74H4uQo8Ea5hpI8L3zlpK2eq5GUyrHcnTbQ-Kw4UgEntfb9dXu4Ijfowp_LSMxN6AISaoDf-OZCFv2IFS1P4UY2DHYG; ttcid=b8ea42abb1954fd2a913086620d2447f25; download_guide=^%^223^%^2F20230713^%^2F0^%^22; home_can_add_dy_2_desktop=^%^220^%^22; strategyABtestKey=^%^221689299939.836^%^22; FOLLOW_LIVE_POINT_INFO=^%^22MS4wLjABAAAAf6aekfyBsc4u8jMkeYbgnkFa0ksIWKWpGOywuyHXyo4^%^2F1689350400000^%^2F0^%^2F1689299940112^%^2F0^%^22; VIDEO_FILTER_MEMO_SELECT=^%^7B^%^22expireTime^%^22^%^3A1689904741009^%^2C^%^22type^%^22^%^3Anull^%^7D; device_web_cpu_core=8; device_web_memory_size=-1; webcast_local_quality=origin; csrf_session_id=ce1e9bc7ba69feec32889636027ce79a; passport_fe_beating_status=false; webcast_leading_last_show_time=1689300023141; webcast_leading_total_show_times=1; tt_scid=PgQO8z6aK2zeofuxFGselkNp2kSbPFCuPmOMwU9ih.SXbBp8iA7l2EiqrurdBuMWf204; msToken=T5-gdGi61ytJtas2VgUQAogURSJT2pQDWT5E_TPGT9paO9OtCuHOGAl72YAxHhrkKJdNhx6O1JgGn0uzdkfHw_a_MWJS-OJlgroduiLAcJzzSCmib6GfWqIgWT8m2qA3; __ac_nonce=064b0be450072f85a1215; __ac_signature=_02B4Z6wo00f01eL3lWgAAIDA.rQr1mcyUx3ixpHAABwPwM4wuxfDlht-h5js2proCQ84O246NPRhh7I6Pv0tJwHeCCotGZpibWazzH51O7kDcl18lUJy6o8VYLGIG..jFlP-zEpspGjM6AZO34; __ac_referer=https://live.douyin.com/',
|
||||
'Cookie': cookies
|
||||
}
|
||||
|
||||
@ -38,12 +37,12 @@ def get_douyin_stream_data(url,cookies):
|
||||
return json_data
|
||||
|
||||
|
||||
def get_tiktok_stream_data(url,proxy_addr):
|
||||
def get_tiktok_stream_data(url, proxy_addr):
|
||||
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'
|
||||
}
|
||||
|
||||
if proxy_addr !='':
|
||||
if proxy_addr != '':
|
||||
# 设置代理
|
||||
proxies = {
|
||||
'http': proxy_addr,
|
||||
@ -67,10 +66,27 @@ def get_tiktok_stream_data(url,proxy_addr):
|
||||
return json_data
|
||||
|
||||
|
||||
def get_kuaishou_stream_data(url):
|
||||
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',
|
||||
}
|
||||
|
||||
request = urllib.request.Request(url, headers=headers)
|
||||
response = urllib.request.urlopen(request, timeout=10)
|
||||
html_str = response.read().decode('utf-8')
|
||||
json_str = re.findall('__INITIAL_STATE__=(.*?);\(function', html_str)[0]
|
||||
# print(json_str)
|
||||
json_data = json.loads(json_str)
|
||||
return json_data
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
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'
|
||||
url="https://live.douyin.com/803023607352" # douyin live
|
||||
url="https://live.douyin.com/745964462470" # douyin live
|
||||
# url = "https://www.tiktok.com/@pearlgaga88/live" # tiktok live
|
||||
print(get_douyin_stream_data(url,Cookie))
|
||||
# 抖音直播间页面的cookie
|
||||
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'
|
||||
url = "https://live.douyin.com/745964462470" # 抖音直播
|
||||
# url = "https://www.tiktok.com/@pearlgaga88/live" # Tiktok 直播
|
||||
# url = "https://live.kuaishou.com/u/yall1102" # 快手直播
|
||||
# print(get_douyin_stream_data(url,Cookie))
|
||||
# print(get_tiktok_stream_data(url,''))
|
||||
# print(get_kuaishou_stream_data(url))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user