From cd6d39210e63140f145cb422ed57e432df44d4b8 Mon Sep 17 00:00:00 2001 From: eric Date: Mon, 15 Sep 2025 16:21:28 +0800 Subject: [PATCH] 's' --- backup/back | 2 +- list | 4 +- live.py | 139 ++++++++++++++++++---------------------------------- 3 files changed, 52 insertions(+), 93 deletions(-) diff --git a/backup/back b/backup/back index b91cef9..8342828 100644 --- a/backup/back +++ b/backup/back @@ -145,7 +145,7 @@ def start_douyin_to_youtube(record_url, youtube_key, room_name=None, delay_sec=3 # ----------------- 示例 ----------------- if __name__ == "__main__": - DOUYIN_URL = "https://live.douyin.com/640087893839" + DOUYIN_URL = "https://live.douyin.com/743565594721" YOUTUBE_KEY = "qxvb-r47b-r5ju-6ud3-6k7z" hls_instance = start_douyin_to_youtube(DOUYIN_URL, YOUTUBE_KEY, delay_sec=30) diff --git a/list b/list index 384d35b..6959581 100644 --- a/list +++ b/list @@ -1,4 +1,6 @@ https://live.douyin.com/525514386431 https://live.douyin.com/8687122573 https://live.douyin.com/642534242822 -https://live.douyin.com/589037028237 \ No newline at end of file +https://live.douyin.com/589037028237 +https://live.douyin.com/743565594721 +https://live.douyin.com/249578288248 \ No newline at end of file diff --git a/live.py b/live.py index 8ae0740..f16aec1 100644 --- a/live.py +++ b/live.py @@ -11,7 +11,6 @@ import shutil import spider import stream - class AdaptiveHLS2YouTube: def __init__(self, max_bitrate=5000, min_bitrate=3000, audio_bitrate=192, delay_sec=40, segment_time=2, check_interval=5): @@ -20,7 +19,7 @@ class AdaptiveHLS2YouTube: self.delay_sec = delay_sec self.segment_time = segment_time self.check_interval = check_interval - self.buffer_queue = queue.Queue(maxsize=800) + self.buffer_queue = queue.Queue() self.max_bitrate = max_bitrate self.min_bitrate = min_bitrate self.audio_bitrate = audio_bitrate @@ -45,41 +44,22 @@ class AdaptiveHLS2YouTube: "-reconnect_at_eof", "1", "-reconnect_streamed", "1", "-reconnect_delay_max", "10", - "-f", "hls", # 强制 HLS "-i", real_url, "-c", "copy", "-f", "mpegts", "-" ] try: - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=10**8) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) print("[拉流] FFmpeg 启动成功") - - def read_stderr(): - while proc.poll() is None: - try: - line = proc.stderr.readline() - if not line: - continue - print(f"[拉流FFmpeg]: {line.decode(errors='ignore').strip()}") - except Exception: - continue - threading.Thread(target=read_stderr, daemon=True).start() - while not self.stop_flag.is_set(): - try: - data = proc.stdout.read(188 * 5000) - if not data: - time.sleep(0.05) - continue - self.buffer_queue.put_nowait(data) - except queue.Full: + data = proc.stdout.read(188*500) # 读取更大块,减少空跑 + if not data: + time.sleep(0.05) continue - except Exception as e: - print(f"[拉流异常] {e}") - time.sleep(1) + self.buffer_queue.put(data) except Exception as e: - print(f"拉流进程异常: {e}") + print(f"拉流异常: {e}") def _push_thread(self, youtube_key, room_name): min_buffer = max(1, self.delay_sec // self.segment_time) @@ -96,7 +76,6 @@ class AdaptiveHLS2YouTube: "-c:v", "libx264", "-preset", "veryfast", "-tune", "zerolatency", - "-x264-params", "keyint=60:scenecut=0", "-b:v", f"{self.current_bitrate}k", "-maxrate", f"{self.current_bitrate}k", "-bufsize", f"{self.current_bitrate*4}k", @@ -107,87 +86,64 @@ class AdaptiveHLS2YouTube: "-b:a", f"{self.audio_bitrate}k", "-ar", "44100", "-ac", "2", - "-strict", "-2", "-f", "flv", "-rtmp_live", "live", f"rtmp://a.rtmp.youtube.com/live2/{youtube_key}" ] try: - proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=10**8) + proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE) self.processes[room_name] = proc def read_stderr(): while proc.poll() is None: - try: - line = proc.stderr.readline() - if not line: - continue + line = proc.stderr.readline() + if line: print(f"[{room_name} FFmpeg]: {line.decode(errors='ignore').strip()}") - except Exception: - continue threading.Thread(target=read_stderr, daemon=True).start() while not self.stop_flag.is_set(): try: - data = self.buffer_queue.get(timeout=0.5) - if not data: - continue - try: - proc.stdin.write(data) - proc.stdin.flush() - except (BrokenPipeError, OSError): - print(f"[{room_name}] 推流管道断开,准备重启") - break + data = self.buffer_queue.get(timeout=1) + proc.stdin.write(data) + proc.stdin.flush() except queue.Empty: continue - except Exception as e: - print(f"[{room_name}] 推流异常: {e}") - break except Exception as e: - print(f"[{room_name}] 推流进程启动失败: {e}") - time.sleep(5) + print(f"[{room_name}] 推流异常: {e}") def _abr_thread(self): while not self.stop_flag.is_set(): - try: - queue_len = self.buffer_queue.qsize() - if queue_len > 200: - new_bitrate = max(self.min_bitrate, self.current_bitrate - 500) - elif queue_len < 20: - new_bitrate = min(self.max_bitrate, self.current_bitrate + 500) - else: - new_bitrate = self.current_bitrate - if new_bitrate != self.current_bitrate: - print(f"[ABR] 调整码率: {self.current_bitrate}k -> {new_bitrate}k") - self.current_bitrate = new_bitrate - except Exception: - pass - time.sleep(max(self.check_interval, 10)) + queue_len = self.buffer_queue.qsize() + if queue_len > 100: + new_bitrate = max(self.min_bitrate, self.current_bitrate - 300) + elif queue_len < 30: + new_bitrate = min(self.max_bitrate, self.current_bitrate + 300) + else: + new_bitrate = self.current_bitrate + if new_bitrate != self.current_bitrate: + print(f"[ABR] 调整码率: {self.current_bitrate}k -> {new_bitrate}k") + self.current_bitrate = new_bitrate + time.sleep(self.check_interval) def stop_all(self): print("停止所有推流...") self.stop_flag.set() for proc in self.processes.values(): - try: - if proc and proc.poll() is None: - proc.terminate() - except Exception: - continue + if proc.poll() is None: + proc.terminate() +# ----------------- 抖音解析逻辑 ----------------- async def get_douyin_real_url(record_url, record_quality="原画"): - try: - if 'v.douyin.com' not in record_url and '/user/' not in record_url: - json_data = await spider.get_douyin_stream_data(url=record_url) - else: - json_data = await spider.get_douyin_app_stream_data(url=record_url) - port_info = await stream.get_douyin_stream_url(json_data, record_quality, None) - return port_info.get("record_url") - except Exception as e: - print(f"获取抖音真实地址失败: {e}") - return None + if 'v.douyin.com' not in record_url and '/user/' not in record_url: + json_data = await spider.get_douyin_stream_data(url=record_url) + else: + json_data = await spider.get_douyin_app_stream_data(url=record_url) + port_info = await stream.get_douyin_stream_url(json_data, record_quality, None) + return port_info.get("record_url") +# ----------------- 启动推流 ----------------- def start_douyin_to_youtube(record_url, youtube_key, room_name=None, delay_sec=40): try: real_url = asyncio.run(get_douyin_real_url(record_url)) @@ -203,28 +159,27 @@ def start_douyin_to_youtube(record_url, youtube_key, room_name=None, delay_sec=4 return hls2yt +# ----------------- 控制台监控面板 ----------------- def monitor_panel_thread(hls_instance, interval=2, max_width=50): - term_width, _ = shutil.get_terminal_size(fallback=(80, 20)) + term_width, _ = shutil.get_terminal_size() bar_width = min(max_width, term_width - 30) while not hls_instance.stop_flag.is_set(): - try: - queue_len = hls_instance.buffer_queue.qsize() - bitrate = hls_instance.current_bitrate - active_push = sum(1 for proc in hls_instance.processes.values() if proc and proc.poll() is None) + queue_len = hls_instance.buffer_queue.qsize() + bitrate = hls_instance.current_bitrate + active_push = any(proc and proc.poll() is None for proc in hls_instance.processes.values()) - queue_bar_len = min(bar_width, queue_len) - queue_bar = "#" * queue_bar_len + "-" * (bar_width - queue_bar_len) + queue_bar_len = min(bar_width, queue_len) + queue_bar = "#" * queue_bar_len + "-" * (bar_width - queue_bar_len) - print("\r", end="") - print(f"[监控] 队列: [{queue_bar}] {queue_len:4} | 码率: {bitrate:4}k | 推流进程: {active_push}", end="") - except Exception: - pass + print("\r", end="") + print(f"[监控] 队列: [{queue_bar}] {queue_len:4} | 码率: {bitrate:4}k | 推流活跃: {active_push}", end="") time.sleep(interval) +# ----------------- 示例 ----------------- if __name__ == "__main__": - DOUYIN_URL = "https://live.douyin.com/97282309368" + DOUYIN_URL = "https://live.douyin.com/354098231885" YOUTUBE_KEY = "qxvb-r47b-r5ju-6ud3-6k7z" hls_instance = start_douyin_to_youtube(DOUYIN_URL, YOUTUBE_KEY, delay_sec=40) @@ -245,3 +200,5 @@ if __name__ == "__main__": print("程序已启动,按 Ctrl+C 停止...") while True: time.sleep(60) + +# back3 \ No newline at end of file