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

查看 78|回复 10
作者:icer233   
思路:下载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())

文件, 链接

52pe   

试了下:为什么我感觉并不快,反而还导致电脑比较卡顿呢?难道错觉?
个人建议加上重试,解密功能建议保留,可以依实际情况选择是否解密。感觉现在好多都是有加密的
159357ssy   

感谢分享,学习一下
guhuishou   

这个想法不错,github上还有一个类似的项目N_m3u8DL-CLI,可以作为参考
leijun666   

需要下载哪些依赖包呢,有加密的是否也支持
青春莫相随   

感谢分享
一场荒唐半生梦   

楼主有打包的吗?
Echo001   

有点东西,下载好用
hope1314520   

这个想法不错,
icer233
OP
  


leijun666 发表于 2025-2-1 17:17
需要下载哪些依赖包呢,有加密的是否也支持

刚把解密的部分删了(
依赖的话,开头import的都装一下就行了,大多是自带的
您需要登录后才可以回帖 登录 | 立即注册

返回顶部