mirror of
https://github.com/ihmily/DouyinLiveRecorder.git
synced 2026-03-22 15:39:03 +08:00
fix: add ntfy message push
This commit is contained in:
@@ -23,7 +23,8 @@ bash脚本路径 =
|
||||
额外使用代理录制的平台(逗号分隔) =
|
||||
|
||||
[推送配置]
|
||||
直播状态通知(可选微信|钉钉|tg|邮箱|bark或者都填) =
|
||||
# 可选微信|钉钉|tg|邮箱|bark|ntfy 可填多个
|
||||
直播状态推送渠道 =
|
||||
钉钉推送接口链接 =
|
||||
微信推送接口链接 =
|
||||
bark推送接口链接 =
|
||||
@@ -38,6 +39,10 @@ smtp邮件服务器 =
|
||||
发件人邮箱 =
|
||||
发件人显示昵称 =
|
||||
收件人邮箱 =
|
||||
ntfy推送地址 = https://ntfy.sh/xxxx
|
||||
ntfy推送标签 = tada
|
||||
ntfy推送邮箱 =
|
||||
自定义推送标题 =
|
||||
自定义开播推送内容 =
|
||||
自定义关播推送内容 =
|
||||
只推送通知不录制(是/否) = 否
|
||||
@@ -46,7 +51,8 @@ smtp邮件服务器 =
|
||||
关播推送开启(是/否)= 否
|
||||
|
||||
[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
|
||||
# 录制抖音必填
|
||||
抖音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
|
||||
快手cookie =
|
||||
tiktok_cookie =
|
||||
虎牙cookie =
|
||||
|
||||
51
main.py
51
main.py
@@ -32,7 +32,7 @@ from douyinliverecorder.utils import (
|
||||
get_file_paths, remove_emojis
|
||||
)
|
||||
from msg_push import (
|
||||
dingtalk, xizhi, tg_bot, email_message, bark
|
||||
dingtalk, xizhi, tg_bot, send_email, bark, ntfy
|
||||
)
|
||||
|
||||
version = "v3.0.9"
|
||||
@@ -160,7 +160,7 @@ def delete_line(file_path: str, del_line: str):
|
||||
f.write(txt_line)
|
||||
|
||||
|
||||
def get_startup_info(system_type):
|
||||
def get_startup_info(system_type: str):
|
||||
if system_type == 'nt':
|
||||
startup_info = subprocess.STARTUPINFO()
|
||||
startup_info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
@@ -249,17 +249,22 @@ def adjust_max_request():
|
||||
error_count = 0
|
||||
|
||||
|
||||
def push_message(record_name, content: str) -> None:
|
||||
def push_message(record_name: str, live_url: str, content: str) -> None:
|
||||
msg_title = push_message_title.strip() or "直播间状态更新通知"
|
||||
push_functions = {
|
||||
'微信': lambda: xizhi(xizhi_api_url, content),
|
||||
'微信': lambda: xizhi(xizhi_api_url, msg_title, content),
|
||||
'钉钉': lambda: dingtalk(dingtalk_api_url, content, dingtalk_phone_num),
|
||||
'邮箱': lambda: email_message(
|
||||
'邮箱': lambda: send_email(
|
||||
email_host, login_email, email_password, sender_email, sender_name,
|
||||
to_email, "直播间状态更新通知", content
|
||||
to_email, msg_title, content
|
||||
),
|
||||
'TG': lambda: tg_bot(tg_chat_id, tg_token, content),
|
||||
'BARK': lambda: bark(
|
||||
bark_msg_api, title="直播录制通知", content=content, level=bark_msg_level, sound=bark_msg_ring),
|
||||
bark_msg_api, title=msg_title, content=content, level=bark_msg_level, sound=bark_msg_ring
|
||||
),
|
||||
'NTFY': lambda: ntfy(
|
||||
ntfy_api, title=msg_title, content=content, tags=ntfy_tags, action_url=live_url, email=ntfy_email
|
||||
),
|
||||
}
|
||||
|
||||
for platform, func in push_functions.items():
|
||||
@@ -272,7 +277,7 @@ def push_message(record_name, content: str) -> None:
|
||||
print(f"直播消息推送到{platform}失败: {e}")
|
||||
|
||||
|
||||
def run_bash(command):
|
||||
def run_bash(command: list):
|
||||
process = subprocess.Popen(
|
||||
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=get_startup_info(os_type)
|
||||
)
|
||||
@@ -283,7 +288,7 @@ def run_bash(command):
|
||||
print(stderr_decoded)
|
||||
|
||||
|
||||
def clear_record_info(record_name, record_url):
|
||||
def clear_record_info(record_name: str, record_url: str):
|
||||
global monitoring
|
||||
recording.discard(record_name)
|
||||
if record_url in url_comments and record_url in running_list:
|
||||
@@ -794,9 +799,13 @@ def start_record(url_data: tuple, count_variable: int = -1):
|
||||
|
||||
push_content = (push_content.replace('[直播间名称]', record_name).
|
||||
replace('[时间]', push_at))
|
||||
push_message(record_name, push_content.replace(r'\n', '\n'))
|
||||
|
||||
threading.Thread(
|
||||
target=push_message,
|
||||
args=(record_name, record_url, push_content.replace(r'\n', '\n')),
|
||||
daemon=True
|
||||
).start()
|
||||
start_pushed = False
|
||||
|
||||
else:
|
||||
content = f"\r{record_name} 正在直播中..."
|
||||
print(content)
|
||||
@@ -809,8 +818,11 @@ def start_record(url_data: tuple, count_variable: int = -1):
|
||||
|
||||
push_content = (push_content.replace('[直播间名称]', record_name).
|
||||
replace('[时间]', push_at))
|
||||
push_message(record_name, push_content.replace(r'\n', '\n'))
|
||||
|
||||
threading.Thread(
|
||||
target=push_message,
|
||||
args=(record_name, record_url, push_content.replace(r'\n', '\n')),
|
||||
daemon=True
|
||||
).start()
|
||||
start_pushed = True
|
||||
|
||||
if disable_record:
|
||||
@@ -1293,8 +1305,7 @@ def check_ffmpeg_existence():
|
||||
# print(f"已将ffmpeg路径添加到环境变量:{ffmpeg_path}")
|
||||
return True
|
||||
else:
|
||||
logger.error(
|
||||
"未检测到ffmpeg。请确保ffmpeg位于系统路径中,或将其路径添加到环境变量。缺少ffmpeg将导致无法进行录制。")
|
||||
logger.error("未检测到ffmpeg,请确保ffmpeg位于系统路径中,或将其路径添加到环境变量。")
|
||||
sys.exit(0)
|
||||
finally:
|
||||
dev_null.close()
|
||||
@@ -1302,7 +1313,7 @@ def check_ffmpeg_existence():
|
||||
|
||||
|
||||
if not check_ffmpeg_existence():
|
||||
logger.error("ffmpeg检查失败,程序将退出。")
|
||||
logger.error("缺少ffmpeg无法进行录制,程序退出")
|
||||
sys.exit(1)
|
||||
|
||||
# --------------------------初始化程序-------------------------------------
|
||||
@@ -1411,7 +1422,7 @@ while True:
|
||||
enable_proxy_platform_list = enable_proxy_platform.replace(',', ',').split(',') if enable_proxy_platform else None
|
||||
extra_enable_proxy = read_config_value(config, '录制设置', '额外使用代理录制的平台(逗号分隔)', '')
|
||||
extra_enable_proxy_platform_list = extra_enable_proxy.replace(',', ',').split(',') if extra_enable_proxy else None
|
||||
live_status_push = read_config_value(config, '推送配置', '直播状态通知(可选微信|钉钉|tg|邮箱|bark或者都填)', "")
|
||||
live_status_push = read_config_value(config, '推送配置', '直播状态推送渠道', "")
|
||||
dingtalk_api_url = read_config_value(config, '推送配置', '钉钉推送接口链接', "")
|
||||
xizhi_api_url = read_config_value(config, '推送配置', '微信推送接口链接', "")
|
||||
bark_msg_api = read_config_value(config, '推送配置', 'bark推送接口链接', "")
|
||||
@@ -1426,6 +1437,10 @@ while True:
|
||||
sender_email = read_config_value(config, '推送配置', '发件人邮箱', "")
|
||||
sender_name = read_config_value(config, '推送配置', '发件人显示昵称', "")
|
||||
to_email = read_config_value(config, '推送配置', '收件人邮箱', "")
|
||||
ntfy_api = read_config_value(config, '推送配置', 'ntfy推送地址', "")
|
||||
ntfy_tags = read_config_value(config, '推送配置', 'ntfy推送标签', "tada")
|
||||
ntfy_email = read_config_value(config, '推送配置', 'ntfy推送邮箱', "")
|
||||
push_message_title = read_config_value(config, '推送配置', '自定义推送标题', "直播间状态更新通知")
|
||||
begin_push_message_text = read_config_value(config, '推送配置', '自定义开播推送内容', "")
|
||||
over_push_message_text = read_config_value(config, '推送配置', '自定义关播推送内容', "")
|
||||
disable_record = options.get(read_config_value(config, '推送配置', '只推送通知不录制(是/否)', "否"), False)
|
||||
@@ -1443,7 +1458,7 @@ while True:
|
||||
twitcasting_username = read_config_value(config, '账号密码', 'twitcasting账号', '')
|
||||
twitcasting_password = read_config_value(config, '账号密码', 'twitcasting密码', '')
|
||||
popkontv_access_token = read_config_value(config, 'Authorization', 'popkontv_token', '')
|
||||
dy_cookie = read_config_value(config, 'Cookie', '抖音cookie(录制抖音必须要有)', '')
|
||||
dy_cookie = read_config_value(config, 'Cookie', '抖音cookie', '')
|
||||
ks_cookie = read_config_value(config, 'Cookie', '快手cookie', '')
|
||||
tiktok_cookie = read_config_value(config, 'Cookie', 'tiktok_cookie', '')
|
||||
hy_cookie = read_config_value(config, 'Cookie', '虎牙cookie', '')
|
||||
|
||||
66
msg_push.py
66
msg_push.py
@@ -7,10 +7,11 @@ Date: 2023-09-03 19:18:36
|
||||
Update: 2024-10-23 23:37:12
|
||||
Copyright (c) 2023-2024 by Hmily, All Rights Reserved.
|
||||
"""
|
||||
from typing import Dict, Any, Optional
|
||||
from typing import Dict, Any
|
||||
import json
|
||||
import base64
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import smtplib
|
||||
from email.header import Header
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
@@ -21,7 +22,7 @@ opener = urllib.request.build_opener(no_proxy_handler)
|
||||
headers: Dict[str, str] = {'Content-Type': 'application/json'}
|
||||
|
||||
|
||||
def dingtalk(url: str, content: str, number: Optional[str] = '') -> Dict[str, Any]:
|
||||
def dingtalk(url: str, content: str, number: str = None) -> Dict[str, Any]:
|
||||
success = []
|
||||
error = []
|
||||
api_list = url.replace(',', ',').split(',') if url.strip() else []
|
||||
@@ -54,11 +55,10 @@ def dingtalk(url: str, content: str, number: Optional[str] = '') -> Dict[str, An
|
||||
return {"success": success, "error": error}
|
||||
|
||||
|
||||
def xizhi(url: str, content: str, title: str = None) -> Dict[str, Any]:
|
||||
def xizhi(url: str, title: str, content: str) -> Dict[str, Any]:
|
||||
success = []
|
||||
error = []
|
||||
api_list = url.replace(',', ',').split(',') if url.strip() else []
|
||||
title = title if title else '直播间状态更新'
|
||||
for api in api_list:
|
||||
json_data = {
|
||||
'title': title,
|
||||
@@ -81,8 +81,8 @@ def xizhi(url: str, content: str, title: str = None) -> Dict[str, Any]:
|
||||
return {"success": success, "error": error}
|
||||
|
||||
|
||||
def email_message(email_host: str, login_email: str, email_pass: str, sender_email: str, sender_name: str,
|
||||
to_email: str, title: str, content: str) -> Dict[str, Any]:
|
||||
def send_email(email_host: str, login_email: str, email_pass: str, sender_email: str, sender_name: str,
|
||||
to_email: str, title: str, content: str) -> Dict[str, Any]:
|
||||
receivers = to_email.replace(',', ',').split(',') if to_email.strip() else []
|
||||
|
||||
try:
|
||||
@@ -159,6 +159,54 @@ def bark(api: str, title: str = "message", content: str = 'test', level: str = "
|
||||
return {"success": success, "error": error}
|
||||
|
||||
|
||||
def ntfy(api: str, title: str = "message", content: str = 'test', tags: str = 'tada', priority: int = 3,
|
||||
action_url: str = "", attach: str = "", filename: str = "", click: str = "", icon: str = "",
|
||||
delay: str = "", email: str = "", call: str = "") -> Dict[str, Any]:
|
||||
success = []
|
||||
error = []
|
||||
api_list = api.replace(',', ',').split(',') if api.strip() else []
|
||||
tags = tags.replace(',', ',').split(',') if tags else ['partying_face']
|
||||
actions = [{"action": "view", "label": "view live", "url": action_url}] if action_url else []
|
||||
for _api in api_list:
|
||||
server, topic = _api.rsplit('/', maxsplit=1)
|
||||
json_data = {
|
||||
"topic": topic,
|
||||
"title": title,
|
||||
"message": content,
|
||||
"tags": tags,
|
||||
"priority": priority,
|
||||
"attach": attach,
|
||||
"filename": filename,
|
||||
"click": click,
|
||||
"actions": actions,
|
||||
"markdown": False,
|
||||
"icon": icon,
|
||||
"delay": delay,
|
||||
"email": email,
|
||||
"call": call
|
||||
}
|
||||
|
||||
try:
|
||||
data = json.dumps(json_data, ensure_ascii=False).encode('utf-8')
|
||||
req = urllib.request.Request(server, data=data, headers=headers)
|
||||
response = opener.open(req, timeout=10)
|
||||
json_str = response.read().decode("utf-8")
|
||||
json_data = json.loads(json_str)
|
||||
if "error" not in json_data:
|
||||
success.append(_api)
|
||||
else:
|
||||
error.append(_api)
|
||||
print(f'ntfy推送失败, 推送地址:{_api}, 失败信息:{json_data["error"]}')
|
||||
except urllib.error.HTTPError as e:
|
||||
error.append(_api)
|
||||
error_msg = e.read().decode("utf-8")
|
||||
print(f'ntfy推送失败, 推送地址:{_api}, 错误信息:{json.loads(error_msg)["error"]}')
|
||||
except Exception as e:
|
||||
error.append(api)
|
||||
print(f'ntfy推送失败, 推送地址:{_api}, 错误信息:{e}')
|
||||
return {"success": success, "error": error}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
send_title = '直播通知' # 标题
|
||||
send_content = '张三 开播了!' # 推送内容
|
||||
@@ -192,3 +240,9 @@ if __name__ == '__main__':
|
||||
|
||||
bark_url = 'https://xxx.xxx.com/key/'
|
||||
# bark(bark_url, send_title, send_content)
|
||||
|
||||
ntfy(
|
||||
api="https://ntfy.sh/xxxxx",
|
||||
title="直播推送",
|
||||
content="xxx已开播",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user