Loading

douyinliverecorder 斗鱼直播录制解析

斗鱼直播录制的逻辑主要涉及 spider.py, stream.pymain.py。以下是代码如何获取并录制斗鱼直播流的详细解析:


1. 获取斗鱼直播信息

spider.py 中,函数 get_douyu_info_data(url, proxy_addr, cookies) 负责获取斗鱼直播的基本信息:

@trace_error_decorator
async def get_douyu_info_data(url: str, proxy_addr: OptionalStr = None, cookies: OptionalStr = None) -> dict:
    headers = {
        'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 ...)',
        'Referer': 'https://m.douyu.com/...',
        'Cookie': 'dy_did=413b835d2ae00270f0c69f6400031601; ...'
    }
    if cookies:
        headers['Cookie'] = cookies

    match_rid = re.search('rid=(.*?)(?=&|$)', url)
    if match_rid:
        rid = match_rid.group(1)
    else:
        rid = re.search('douyu.com/(.*?)(?=\\?|$)', url).group(1)
        html_str = await async_req(url=f'https://m.douyu.com/{rid}', proxy_addr=proxy_addr, headers=headers)
        json_str = re.findall('<script id="vike_pageContext" type="application/json">(.*?)</script>', html_str)[0]
        json_data = json.loads(json_str)
        rid = json_data['pageProps']['room']['roomInfo']['roomInfo']['rid']

    headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; ...)'
    url2 = f'https://www.douyu.com/betard/{rid}'
    json_str = await async_req(url=url2, proxy_addr=proxy_addr, headers=headers)
    json_data = json.loads(json_str)

    result = {
        "anchor_name": json_data['room']['nickname'],
        "is_live": False
    }
    if json_data['room']['videoLoop'] == 0 and json_data['room']['show_status'] == 1:
        result["title"] = json_data['room']['room_name'].replace('&nbsp;', '')
        result["is_live"] = True
        result["room_id"] = json_data['room']['room_id']
    return result

解析

  • 通过访问 https://m.douyu.com/{房间号} 获取基础信息。
  • 解析出 room_id,判断 show_status 是否为 1,表示当前直播是否在线。
  • 返回主播昵称 (anchor_name),直播标题 (title) 和 is_live 状态。

2. 获取斗鱼直播流地址

spider.py 中,函数 get_douyu_stream_data(rid, rate, proxy_addr, cookies) 负责获取斗鱼的直播流:

@trace_error_decorator
async def get_douyu_stream_data(rid: str, rate: str = '-1', proxy_addr: OptionalStr = None, cookies: OptionalStr = None) -> dict:
    did = '10000000000000000000000000003306'
    params_list = await get_token_js(rid, did, proxy_addr=proxy_addr)
    headers = {
        'User-Agent': 'ios/7.830 (ios 17.0; ...)',
        'Referer': 'https://m.douyu.com/...',
        'Cookie': 'dy_did=413b835d2ae00270f0c69f6400031601; ...'
    }
    if cookies:
        headers['Cookie'] = cookies

    data = {
        'v': params_list[0],
        'did': params_list[1],
        'tt': params_list[2],
        'sign': params_list[3],
        'ver': '22011191',
        'rid': rid,
        'rate': rate,  # 0蓝光、3超清、2高清、-1默认
    }

    app_api = f'https://www.douyu.com/lapi/live/getH5Play/{rid}'
    json_str = await async_req(url=app_api, proxy_addr=proxy_addr, headers=headers, data=data)
    json_data = json.loads(json_str)
    return json_data

解析

  • 需要生成 params_list 作为认证信息。
  • 访问 https://www.douyu.com/lapi/live/getH5Play/{rid} 获取直播流信息。
  • rate 参数决定了视频清晰度:
    • 0:蓝光
    • 3:超清
    • 2:高清
    • -1:默认

3. 解析直播流 URL

stream.py,函数 get_douyu_stream_url(json_data, video_quality, cookies, proxy_addr) 负责最终解析直播流:

@trace_error_decorator
async def get_douyu_stream_url(json_data: dict, video_quality: str, cookies: str, proxy_addr: str) -> dict:
    if not json_data["is_live"]:
        return json_data

    video_quality_options = {
        "OD": '0',
        "BD": '0',
        "UHD": '3',
        "HD": '2',
        "SD": '1',
        "LD": '1'
    }

    rid = str(json_data["room_id"])
    json_data.pop("room_id")
    rate = video_quality_options.get(video_quality, '0')
    flv_data = await get_douyu_stream_data(rid, rate, cookies=cookies, proxy_addr=proxy_addr)
    rtmp_url = flv_data['data'].get('rtmp_url')
    rtmp_live = flv_data['data'].get('rtmp_live')

    if rtmp_live:
        flv_url = f'{rtmp_url}/{rtmp_live}'
        json_data |= {'quality': video_quality, 'flv_url': flv_url, 'record_url': flv_url}
    return json_data

解析

  • 传入 video_quality 选择清晰度。
  • 通过 get_douyu_stream_data 获取 rtmp_urlrtmp_live
  • 生成最终的 flv_url 用于录制。

4. 录制直播流

main.py,函数 start_record(url_data: tuple, count_variable: int = -1) 负责执行录制:

elif record_url.find("https://www.douyu.com/") > -1:
    platform = '斗鱼直播'
    with semaphore:
        json_data = asyncio.run(spider.get_douyu_info_data(
            url=record_url, proxy_addr=proxy_address, cookies=douyu_cookie))
        port_info = asyncio.run(stream.get_douyu_stream_url(
            json_data, video_quality=record_quality, cookies=douyu_cookie, proxy_addr=proxy_address
        ))

之后,调用 ffmpeg 录制:

ffmpeg_command = [
    'ffmpeg', "-y",
    "-v", "verbose",
    "-rw_timeout", "15000000",
    "-loglevel", "error",
    "-hide_banner",
    "-user_agent", user_agent,
    "-protocol_whitelist", "rtmp,crypto,file,http,https,tcp,tls,udp,rtp,httpproxy",
    "-thread_queue_size", "1024",
    "-analyzeduration", analyzeduration,
    "-probesize", probesize,
    "-fflags", "+discardcorrupt",
    "-re", "-i", real_url,
    "-bufsize", bufsize,
    "-sn", "-dn",
    "-reconnect_delay_max", "60",
    "-reconnect_streamed", "-reconnect_at_eof",
    "-max_muxing_queue_size", max_muxing_queue_size,
    "-correct_ts_overflow", "1",
    "-avoid_negative_ts", "1"
]

解析

  • ffmpeg 读取 flv_url 进行录制。
  • -re 选项保证实时录制,防止 ffmpeg 过快读取导致流中断。

总结

  1. 获取直播间信息spider.get_douyu_info_data()
  2. 获取直播流 URLspider.get_douyu_stream_data()
  3. 解析最终直播地址stream.get_douyu_stream_url()
  4. 使用 ffmpeg 录制start_record()

这套逻辑确保了斗鱼直播录制的稳定性和高效性。

posted @ 2025-03-11 03:36  BaguetteShimada  阅读(272)  评论(0)    收藏  举报