import os import subprocess import threading import time import glob import asyncio import uuid import spider import stream class Douyin2YouTube: def __init__(self, cache_dir="cache", segment_time=10): self.cache_dir = cache_dir self.segment_time = segment_time os.makedirs(cache_dir, exist_ok=True) async def get_real_url(self, record_url, record_quality="原画"): # 调用你的抖音爬虫模块获取真实直播流 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(self, record_url, youtube_key, room_name=None): room_name = room_name or f"抖音_{str(uuid.uuid4())[:8]}" real_url = asyncio.run(self.get_real_url(record_url)) if not real_url: print(f"[{room_name}] 获取真实直播流失败") return print(f"[{room_name}] 实际直播流: {real_url}") tmp_prefix = os.path.join(self.cache_dir, f"{room_name}_") for f in glob.glob(f"{tmp_prefix}*.ts"): os.remove(f) # ----------------- 拉流线程 ----------------- def record_thread(): while True: cmd = [ "ffmpeg", "-user_agent", "Mozilla/5.0", "-headers", "Referer: https://www.douyin.com/", "-rw_timeout", "15000000", "-fflags", "+genpts+igndts+nobuffer", "-flags", "low_delay", "-reconnect", "1", "-reconnect_streamed", "1", "-reconnect_delay_max", "10", "-i", real_url, "-c", "copy", "-f", "segment", "-segment_time", str(self.segment_time), "-reset_timestamps", "1", f"{tmp_prefix}%03d.ts" ] try: subprocess.run(cmd) except Exception as e: print(f"[{room_name}] 拉流异常: {e}, 10秒后重试") time.sleep(10) # ----------------- 推流线程 ----------------- def push_thread(): pushed_files = set() while True: segments = sorted(glob.glob(f"{tmp_prefix}*.ts")) new_segments = [s for s in segments if s not in pushed_files] for seg in new_segments: cmd = [ "ffmpeg", "-re", "-i", seg, "-c:v", "libx264", "-preset", "veryfast", "-b:v", "3000k", "-maxrate", "3000k", "-bufsize", "6000k", "-r", "30", "-g", "60", "-c:a", "aac", "-b:a", "128k", "-f", "flv", f"rtmp://a.rtmp.youtube.com/live2/{youtube_key}" ] try: subprocess.run(cmd) pushed_files.add(seg) except Exception as e: print(f"[{room_name}] 推流异常: {e}, 10秒后重试") time.sleep(10) time.sleep(1) threading.Thread(target=record_thread, daemon=True).start() threading.Thread(target=push_thread, daemon=True).start() print(f"[{room_name}] 转播线程已启动,YouTube 推流保证连续") # ----------------- 示例 ----------------- if __name__ == "__main__": DOUYIN_URL = "https://live.douyin.com/210443559964" # 填抖音直播 URL YOUTUBE_KEY = "qxvb-r47b-r5ju-6ud3-6k7z" # 填 YouTube 直播 Key broadcaster = Douyin2YouTube() broadcaster.start(DOUYIN_URL, YOUTUBE_KEY) while True: time.sleep(60)