使用python和ffmpeg下载并合并加密m3u8列表里的ts文件


最近看到某有色网站的视频不错,可是这个网站的网速不太理想,就想下载看,偏偏视频又是加密的,遂破解之。

 

# -*- coding: utf-8 -*-
"""
Created on 2022-03-21 0021 21:45
@Software : PyCharm
@author: Administrator
"""

import requests, os, pyperclip, re
from tqdm import tqdm

path = r'E:\pojie'
headers = {
    'Connection': 'keep-alive',
    '其他header': '信息隐藏',
}
proxy = {
    'http': None,
    'https': None
}


def get_res(url, file_path):
    """
    下载ts视频流
    :param url: ts流链接
    :param file_path: 临时文件路径
    :param key: 加密密钥
    """
    try:
        response = requests.get(url=url, timeout=120, headers=headers)
        with open(file_path, 'wb+') as f:
            f.write(response.content)
    except Exception as e:
        print(e)


def get_list(url):
    response = requests.get(url, headers=headers, proxies=proxy)
    return response


def get_keys(url):
    """
    获取加密密钥
    :param url: 密钥网址
    :return:
    """
    response = requests.get(url, proxies=proxy)
    return response


def write_keys(response, filename):
    """
    写入密钥文件
    :param response: 返回的密钥响应
    :param filename: 密钥文件名
    :return:
    """
    file_path = os.path.join(path, filename)
    # print(file_path)
    with open(file_path, 'wb+') as fp:
        fp.write(response.content)


def get_links_from_file(path):
    """
    从文件中批量读取网址
    :param path: 文件所在位置
    :return:
    """

    with open(path, 'r', encoding='utf-8') as fp:
        st = fp.readlines()
        return st


def write_list(list_path1, list_path2, keystring):
    """
    重写本地m3u8文件,用于ffmpeg合成用
    :param list_path1:
    :param list_path2:
    :param keystring: 记录密钥信息的那一行的字符串,
                      例如''#EXT-X-KEY:METHOD=AES-128,URI="E:/pojie/videokey",IV=0x00000000000000000000000000000000\n'
    :return: 不返回信息
    """
    fp1 = open(list_path1, 'r', encoding='utf-8')
    fp2 = open(list_path2, 'w+', encoding='utf-8')
    st_list = fp1.readlines()
    fp1.close()
    index = 0
    for st in st_list:
        if st[:10] == '#EXT-X-KEY':
            if index < 1:
                fp2.write(keystring)
            continue
        elif st[:1] == "#":
            fp2.write(st)
        else:
            if index < 9:
                filename = f'00{index + 1}.ts'
            elif index < 99:
                filename = f'0{index + 1}.ts'
            else:
                filename = f'{index + 1}.ts'
            fp2.write(filename + '\n')
            index += 1
    fp2.close()

def get_key_url(path):
    """
    从下载好的m3u8文件里读取密钥网址
    :param path:
    :return:
    """
    with open(path, 'r') as f:
        st = f.read()
        ur = re.findall('#EXT-X-KEY:METHOD=AES-128,URI="(.*?)"', st)
        url = ur[0]
        # print(url)
        return url


def write_video(response, filename):
    """
    下载视频
    :param response: response响应
    :param filename: 视频保存的文件名
    :return:
    """
    video_path = os.path.join(path, filename)
    if not os.path.exists(path):
        os.mkdir(path)
    with open(video_path, 'wb+') as fp:
        fp.write(response.content)


def join_video(listname, newfilename):
    """
    利用ffmpeg合并加密的ts文件
    :param listname: 本地m3u8文件路径
    :param newfilename: 待合成的文件名称
    :return:
    """
    command = f'ffmpeg -allowed_extensions ALL -i {listname} -c copy {newfilename}'
    command1 = 'cd /d E:/pojie'
    print(command)
    os.system(command1)
    os.system(command)


def d_k(path):
    """
    下载密钥
    :return:
    """
    filename = 'videokey'
    url = get_key_url(path)
    res = get_keys(url)
    write_keys(res, filename)
    return res


def d_l(url):
    """
    下载m3u8列表
    :return:
    """
    filename = '01.m3u8'
    res = get_list(url)
    write_video(res, filename)


def d_v(url_left, list_path, key):
    """
    下载视频
    :return:
    """
    url_list = get_links_from_file(list_path)
    index = 0
    for url in url_list:
        if url[:1] == 'v':
            if index < 9:
                filename = f'00{index + 1}.ts'
            elif index < 99:
                filename = f'0{index + 1}.ts'
            else:
                filename = f'{index + 1}.ts'
            new_url = url_left + url
            new_url = new_url.strip()
            file_path = os.path.join(path, filename)
            downloadFile(new_url, file_path)
            # time.sleep(2)
            index += 1

        else:
            continue


def get_url_left(url):
    """
    读取m3u8的网址前缀
    :param url:
    :return:
    """
    url_list = url.split('/')
    url_list[1] = 'https:/'
    new_url = '/'.join(url_list[1:-1])
    new_url = new_url + '/'
    return new_url


def rename():
    """
    重命名合成后的文件
    :return:
    """
    txt_path = r'C:\Users\rabbit\PycharmProjects\utils\video\links.txt'
    fp = open(txt_path, 'r', encoding='utf-8')
    st_list = fp.readlines()
    fp.close()
    path1 = r'E:\pojie'
    old_path = r"E:\pojie\03.mp4"
    filename = st_list[0].strip() + '.mp4'
    new_path = os.path.join(path1, filename)
    os.rename(old_path, new_path)
    fo = open(txt_path, 'w', encoding='utf-8')
    for index, line in enumerate(st_list):
        if index == 0:
            continue
        else:
            fo.write(line)
    fo.close()
    return new_path


def delete_TS():
    """
    永久删除下载的ts视频流分段
    :return:
    """
    path = r'E:\pojie'
    file_list = os.listdir(path)
    for file in file_list:
        if file[-2:] == 'ts':
            print(f'{file}已删除')
            file_path = os.path.join(path, file)
            os.remove(file_path)


def downloadFile(url, name):
    """
    下载实时显示速度
    :param url:
    :param name:
    :return:
    """
    # print(url)
    # 用流stream的方式获取url的数据
    resp = requests.get(url, stream=True, headers=headers, proxies=proxy)
    # 拿到文件的长度,并把total初始化为0
    total = int(resp.headers.get('content-length', 0))
    # 打开当前目录的fname文件(名字你来传入)
    # 初始化tqdm,传入总数,文件名等数据,接着就是写入,更新等操作了
    with open(name, 'wb+') as file, tqdm(
            desc=name,
            total=total,
            unit='iB',
            unit_scale=True,
            unit_divisor=1024,
    ) as bar:
        for data in resp.iter_content(chunk_size=1024):
            size = file.write(data)
            bar.update(size)


def mainone():
    """
    主程序入口
    :return:
    """
    # 读取剪贴板中的m3u8链接
    url = pyperclip.paste()

    if not os.path.exists(path):
        os.mkdir(path)

    path1 = "E:\\pojie\\01.m3u8"
    path2 = "E:\\pojie\\02.m3u8"
    keystring = '#EXT-X-KEY:METHOD=AES-128,URI="E:/pojie/videokey",IV=0x00000000000000000000000000000000\n'

    # 获取m3u8链接前缀,用于拼接ts网址
    url_left = get_url_left(url)

    # 下载m3u8列表
    d_l(url)

    # 下载密钥,保存到此文件中,E:/pojie/videokey
    res = d_k(path1)

    # 下载TS分段
    d_v(url_left, path1, res.content)

    # 下载完分段后,重写本地的m3u8文件,方便后续使用ffmpeg合成
    write_list(path1, path2, keystring)
    filename = 'E:\\pojie\\03.mp4'

    # 合并文件
    join_video(path2, filename)

    # 读取目录文件并重命名
    np = rename()

    # 删除TS分段
    delete_TS()

    # 输出已下载好的文件名
    print(np)


if __name__ == '__main__':
    mainone()

  

  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM