# ====================== 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