Files
gitlab-instance-0a899031_dy…/liveback
eric e49b8b6865 '
2025-09-13 08:49:26 +08:00

110 lines
3.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import subprocess
import asyncio
import uuid
import signal
import sys
import spider
import stream
import threading
import time
class HLS2YouTube:
def __init__(self):
self.processes = {}
self.stop_flag = threading.Event()
def start_stream(self, real_url, youtube_key, room_name=None):
room_name = room_name or f"抖音_{str(uuid.uuid4())[:8]}"
print(f"[{room_name}] 启动推流,目标 YouTube Key: {youtube_key}")
threading.Thread(target=self._stream_thread, args=(real_url, youtube_key, room_name), daemon=True).start()
def _stream_thread(self, real_url, youtube_key, room_name):
while not self.stop_flag.is_set():
cmd = [
"ffmpeg",
"-rw_timeout", "50000000",
"-user_agent", "Mozilla/5.0",
"-headers", "Referer: https://www.douyin.com/",
"-fflags", "+nobuffer+genpts",
"-flags", "low_delay",
"-reconnect", "1",
"-reconnect_at_eof", "1",
"-reconnect_streamed", "1",
"-reconnect_delay_max", "10",
"-i", real_url,
"-c:v", "libx264",
"-preset", "veryfast",
"-tune", "zerolatency",
"-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:
proc = subprocess.Popen(cmd)
self.processes[room_name] = proc
while proc.poll() is None and not self.stop_flag.is_set():
time.sleep(1)
if proc.poll() is None:
proc.terminate()
print(f"[{room_name}] 推流中断5秒后重连")
time.sleep(5)
except Exception as e:
print(f"[{room_name}] 推流异常: {e}, 5秒后重试")
time.sleep(5)
def stop_all(self):
print("停止所有推流...")
self.stop_flag.set()
for room_name, proc in self.processes.items():
if proc.poll() is None:
proc.terminate()
# ----------------- 抖音解析逻辑 -----------------
async def get_douyin_real_url(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_douyin_to_youtube(record_url, youtube_key, room_name=None):
try:
real_url = asyncio.run(get_douyin_real_url(record_url))
except Exception as e:
print(f"获取真实直播流失败: {e}")
return
if not real_url:
print("获取真实直播流失败")
return
print(f"实际直播流: {real_url}")
hls2yt = HLS2YouTube()
hls2yt.start_stream(real_url, youtube_key, room_name)
return hls2yt
# ----------------- 示例 -----------------
if __name__ == "__main__":
DOUYIN_URL = "https://live.douyin.com/104914538985" # 抖音直播 URL
YOUTUBE_KEY = "qxvb-r47b-r5ju-6ud3-6k7z" # YouTube 直播 Key
hls_instance = start_douyin_to_youtube(DOUYIN_URL, YOUTUBE_KEY)
def signal_handler(sig, frame):
if hls_instance:
hls_instance.stop_all()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
while True:
time.sleep(60)