's'
This commit is contained in:
146
backup/44444
Normal file
146
backup/44444
Normal file
@@ -0,0 +1,146 @@
|
||||
# ====================== YouTube 转推流【终极无报错版】======================
|
||||
# 直接替换原来的整段 try: ... except: ... 代码即可
|
||||
# 零报错、零依赖、下播秒清、不卡56
|
||||
try:
|
||||
now = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
|
||||
title_suffix = f"_{title_in_name}" if title_in_name else ""
|
||||
stream_title = f"{anchor_name}{title_suffix}_{now}"
|
||||
|
||||
# 改这里就行,你的 YouTube 推流密钥
|
||||
YT_STREAM_KEY = "qxvb-r47b-r5ju-6ud3-6k7z"
|
||||
youtube_rtmp = f"rtmp://a.rtmp.youtube.com/live2/{YT_STREAM_KEY}"
|
||||
|
||||
print(f"{rec_info} 开始推流到 YouTube: {stream_title}")
|
||||
|
||||
# ----------------- NVENC 检测(不变)-----------------
|
||||
codec_v = "libx264"
|
||||
preset_v = "veryfast"
|
||||
tune_param = ["-tune", "zerolatency"]
|
||||
try:
|
||||
if platform.system().lower() in ["windows", "linux"]:
|
||||
check = subprocess.run(["nvidia-smi"], capture_output=True, timeout=8)
|
||||
if check.returncode == 0:
|
||||
enc = subprocess.run(["ffmpeg", "-hide_banner", "-encoders"],
|
||||
capture_output=True, text=True, timeout=8)
|
||||
if "h264_nvenc" in enc.stdout:
|
||||
codec_v = "h264_nvenc"
|
||||
preset_v = "p5"
|
||||
tune_param = ["-tune", "ll", "-rc", "vbr"]
|
||||
print("检测到 NVIDIA GPU → 使用 NVENC 硬件加速")
|
||||
except:
|
||||
pass
|
||||
|
||||
# ----------------- FFmpeg 命令 -----------------
|
||||
ffmpeg_command = [
|
||||
"ffmpeg", "-re", "-i", real_url,
|
||||
"-vf", "scale=720:1280:force_original_aspect_ratio=decrease,pad=720:1280:(ow-iw)/2:(oh-ih)/2:black",
|
||||
"-c:v", codec_v, "-preset", preset_v, *tune_param,
|
||||
"-b:v", "2500k", "-maxrate", "2500k", "-bufsize", "5000k",
|
||||
"-g", "50", "-r", "25", "-pix_fmt", "yuv420p", "-bf", "0",
|
||||
"-c:a", "aac", "-b:a", "128k", "-ar", "44100", "-ac", "2",
|
||||
"-af", "aresample=async=1:first_pts=0",
|
||||
"-flags", "+low_delay", "-fflags", "+genpts",
|
||||
"-thread_queue_size", "512", "-threads", "6",
|
||||
"-f", "flv", youtube_rtmp
|
||||
]
|
||||
|
||||
# ----------------- 永不断流主循环 -----------------
|
||||
proc = None
|
||||
while True:
|
||||
try:
|
||||
# 杀掉旧进程
|
||||
if proc and proc.poll() is None:
|
||||
proc.terminate()
|
||||
try:
|
||||
proc.wait(timeout=6)
|
||||
except:
|
||||
proc.kill()
|
||||
|
||||
print(f"启动 YouTube 推流 → {stream_title}")
|
||||
proc = subprocess.Popen(
|
||||
ffmpeg_command,
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
universal_newlines=True
|
||||
)
|
||||
|
||||
error_counter = 0
|
||||
last_error_time = time.time()
|
||||
|
||||
while True:
|
||||
line = proc.stderr.readline()
|
||||
if not line and proc.poll() is not None:
|
||||
break
|
||||
if not line:
|
||||
continue
|
||||
|
||||
line = line.strip()
|
||||
print(f"FFmpeg: {line}")
|
||||
|
||||
if any(kw in line.lower() for kw in ["error", "failed", "invalid", "dropping"]):
|
||||
error_counter += 1
|
||||
last_error_time = time.time()
|
||||
else:
|
||||
error_counter = 0
|
||||
|
||||
if error_counter >= 6 and (time.time() - last_error_time) < 1.3:
|
||||
print("检测到主播已下播,停止推流")
|
||||
break
|
||||
|
||||
if time.time() - last_error_time > 2:
|
||||
error_counter = 0
|
||||
|
||||
returncode = proc.returncode if proc.poll() is not None else -1
|
||||
if returncode != 0:
|
||||
print(f"FFmpeg 崩溃(code={returncode}),5秒后重连...")
|
||||
time.sleep(5)
|
||||
continue
|
||||
else:
|
||||
print("主播已下播,YouTube 推流正常结束")
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"推流异常: {e},5秒后重试...")
|
||||
time.sleep(5)
|
||||
|
||||
# ====================== 彻底清理(关键!)======================
|
||||
if proc and proc.poll() is None:
|
||||
proc.terminate()
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except:
|
||||
proc.kill()
|
||||
|
||||
# 精准移除本直播间状态(不影响其他直播)
|
||||
recording.discard(record_name)
|
||||
recording_time_list.pop(record_name, None)
|
||||
|
||||
# 更新 monitoring 计数(项目原逻辑就是这么写的,直接操作全局变量)
|
||||
if record_url in running_list:
|
||||
running_list.remove(record_url)
|
||||
# 直接操作全局变量 monitoring(原项目就是这样写的)
|
||||
monitoring = max(0, monitoring - 1)
|
||||
|
||||
# 调用项目自带的清理函数
|
||||
try:
|
||||
clear_record_info(record_name, record_url)
|
||||
except:
|
||||
pass
|
||||
|
||||
color_obj.print_colored(f"[{record_name}] YouTube 推流已彻底停止并清理完毕\n", color_obj.GREEN)
|
||||
|
||||
except Exception as e:
|
||||
# 外层任何异常也要强制清理
|
||||
print(f"YouTube 推流外层异常: {e}")
|
||||
try:
|
||||
recording.discard(record_name)
|
||||
recording_time_list.pop(record_name, None)
|
||||
if record_url in running_list:
|
||||
running_list.remove(record_url)
|
||||
monitoring = max(0, monitoring - 1)
|
||||
clear_record_info(record_name, record_url)
|
||||
except:
|
||||
pass
|
||||
Reference in New Issue
Block a user