【改良】用python+ffmpeg下载m3u8为mp4


思路:下载m3u8中的每个ts文件,将m3u8里的ts的链接替换成本地ts地址,用ffmpeg下载这个新的m3u8
经测试,这样比直接用ffmpeg下载要快一点
把ffmpeg.exe放在py文件同一目录即可
源码:

[Python] 纯文本查看 复制代码
import logging
import asyncio
import subprocess
from pathlib import Path

import m3u8
import aiohttp
from tqdm.asyncio import tqdm_asyncio

async def load_m3u8(s, m3u8_url):
    async with s.get(m3u8_url) as r:
        return m3u8.loads(await r.text(), uri=m3u8_url)

async def fetch(s, index, segment):
    ts_name = f'{index}.ts'
    with open(f'ts/{ts_name}', 'wb') as f:
        async with s.get(segment.absolute_uri) as r:
            async for chunk in r.content.iter_chunked(64 * 1024):
                f.write(chunk)

async def download_ts(s, playlist):
    Path('ts').mkdir(exist_ok=True)
    tasks = (fetch(s, index, segment) for index, segment in enumerate(playlist.segments))
    await tqdm_asyncio.gather(*tasks)

def new_m3u8(playlist):
    for index, segment in enumerate(playlist.segments):
        segment.uri = f"ts/{index}.ts"
    playlist.dump('new.m3u8')

def m3u82mp4(capture_output=True):
    subprocess.run(['ffmpeg',
                    '-allowed_extensions', 'ALL',
                    '-i', 'new.m3u8',
                    '-c', 'copy',
                    'output.mp4'], check=True, capture_output=capture_output)

def clean_up():
    for ts_file in Path('ts').iterdir():
        ts_file.unlink()
    Path('ts').rmdir()
    Path('new.m3u8').unlink()

async def main():
    connector = aiohttp.TCPConnector(limit=limit)
    async with aiohttp.ClientSession(connector=connector) as s:
        logging.info(f'正在读取m3u8链接:{m3u8_url}')
        playlist = await load_m3u8(s, m3u8_url)
        logging.info('正在下载ts文件')
        await download_ts(s, playlist)
    logging.info('正在生成新的m3u8文件')
    new_m3u8(playlist)
    logging.info('正在转换新的m3u8文件为mp4文件')
    m3u82mp4()
    logging.info('正在清理临时文件')
    clean_up()

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
    limit = 30
    m3u8_url = 'url'
    asyncio.run(main())

获取更多资讯请加入交流群


    协助本站SEO优化一下,谢谢!
    关键词不能为空

-

记【某小剧场】永久会员过程

评 论
更换验证码