python m3u8模块下载m3u8视频并合并
# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: m3u8下载器
# Author: yunhgu
# Date: 2022/3/4 9:35
# Description:
# -------------------------------------------------------------------------------
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
from traceback import format_exc
import m3u8
import requests
from log_color.log_color import Logger
from progress.bar import IncrementalBar
class ProcessData:
def __init__(self, src, dst, name, num=10):
self.src = src
self.num = num
self.name = name
self.dst = Path(dst)
if self.dst.exists():
self.logger = Logger(name=str(self.dst.joinpath("m3u8下载器.log")))
else:
self.logger = Logger(name="m3u8下载器.log")
def start(self):
try:
self.process_data()
except Exception as e:
self.logger.error(f"运行失败:{format_exc()}:{e}")
@staticmethod
def get_content(file):
with open(file, encoding="utf-8", mode="r") as f:
return f.read()
def process_data(self):
if Path(self.src).is_file():
m3u8_ob = m3u8.loads(self.get_content(self.src))
self.download_ts(m3u8_ob)
elif str(self.src).lower().startswith("http"):
m3u8_ob = m3u8.load(self.src)
self.download_ts(m3u8_ob)
@staticmethod
def download(id_url):
id_int, url = id_url
content = requests.get(url).content
return id_int, content
def download_ts(self, m3u8_ob):
id_content_dic = {}
with ThreadPoolExecutor(max_workers=self.num) as p:
task_list = []
for id_int, seg in enumerate(m3u8_ob.segments):
uri = seg.uri
if seg.base_uri is not None:
uri = f"{seg.base_uri}{uri}"
task_list.append(p.submit(self.download, (id_int, uri)))
suffix = '%(percent)d%% [%(index)d/%(max)d in %(elapsed)ds (eta:%(eta_td)s)]'
with IncrementalBar("下载进度:", max=len(task_list), suffix=suffix) as bar:
for task in as_completed(task_list):
if task.done():
id_int, content = task.result()
id_content_dic[id_int] = content
# output_file = self.dst.joinpath(self.name).joinpath(f"{id_int}.ts")
# output_file.parent.mkdir(parents=True, exist_ok=True)
# self.save_ts(content, output_file)
bar.next()
output_file = self.dst.joinpath(f"{self.name}.ts")
self.save_all_ts(id_content_dic, output_file)
def save_all_ts(self, id_content_dic, file):
suffix = '%(percent)d%% [%(index)d/%(max)d in %(elapsed)ds (eta:%(eta_td)s)]'
with IncrementalBar("保存进度:", max=len(id_content_dic), suffix=suffix) as bar:
with open(file, "wb+") as f:
for _, content in sorted(id_content_dic.items()):
f.write(content)
bar.next()
self.logger.info(f"\r视频生成位置:{file}")
@staticmethod
def save_ts(content, file):
with open(file, "wb") as f:
f.write(content)
if __name__ == '__main__':
print("******** 开始 ********")
# input_folder = input("请输入原始文件夹:").strip("\"")
# output_folder = input("请输入结果保存文件夹:").strip("\"")
# input_folder = r"F:\测试代码\个人学习\m3u8下载器\index.m3u8"
input_folder = "https://1257120875.vod2.myqcloud.com/0ef121cdvodtransgzp1257120875/3055695e5285890780828799271/v.f230.m3u8"
output_folder = r"F:\测试代码\个人学习\m3u8下载器\output"
pd = ProcessData(src=input_folder, dst=output_folder, name="video1", num=100)
pd.start()
print("******** 结束 ********")
不论你在什么时候开始,重要的是开始之后就不要停止。
不论你在什么时候结束,重要的是结束之后就不要悔恨。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律