使用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