别再手动下载了!用Python+Flask写个自动化脚本,把m3u8视频存本地再传到Cloudflare R2
从m3u8到云端PythonFlask自动化视频处理实战每次手动下载m3u8视频片段时你是否也经历过这样的痛苦打开开发者工具、逐个复制.ts链接、等待下载完成、合并文件...这种重复劳动不仅耗时还容易出错。作为开发者我们完全可以用代码解放双手——本文将带你构建一个完整的自动化系统从视频抓取到云端存储一气呵成。1. 系统架构设计这套自动化方案的核心在于模块化设计和流程解耦。我们不是简单堆砌代码而是构建一个可扩展的生产级工具。整体架构分为三个关键层采集层负责m3u8索引解析与视频片段下载处理层本地文件存储与校验存储层云端同步与版本管理# 架构示意图伪代码 class VideoPipeline: def __init__(self): self.downloader M3U8Downloader() self.storage LocalStorage() self.cloud R2Uploader() def run(self, url): segments self.downloader.fetch(url) local_files self.storage.save(segments) cloud_urls self.cloud.sync(local_files) return cloud_urls这种分层设计带来的优势非常明显故障隔离任一模块出错不影响整体流程灵活替换可轻松更换存储后端如从R2切换到S3性能优化各层可独立进行并发处理2. 核心功能实现2.1 m3u8解析与下载处理m3u8文件需要特别注意相对路径转换和重试机制。以下是经过实战检验的下载器实现要点def parse_m3u8(url): 解析m3u8文件并返回绝对路径的ts列表 response requests.get(url, headersHEADERS) base_url /.join(url.split(/)[:-1]) / ts_list [] for line in response.text.split(\n): if line.endswith(.ts): if line.startswith(http): ts_list.append(line) else: ts_list.append(base_url line) return ts_list关键细节处理自动补全相对路径支持https证书验证超时设置建议10-15秒分段下载进度显示提示遇到403/404错误时检查请求头中的Referer和User-Agent是否与浏览器一致2.2 本地存储优化直接保存原始ts文件会面临两个问题文件碎片化和命名冲突。我们的解决方案是目录结构标准化videos/ └── {video_id}/ ├── meta.json # 存储视频元数据 ├── segments/ # 原始ts片段 └── merged.mp4 # 最终合并文件智能文件命名def generate_filename(ts_url, index): 生成规范化的文件名 ts_name ts_url.split(/)[-1].split(?)[0] return fseg_{index:04d}_{ts_name}完整性校验def verify_download(filepath): 检查视频片段是否完整 try: return os.path.getsize(filepath) 1024 # 小于1KB视为无效 except: return False2.3 Cloudflare R2集成与S3兼容的API设计让R2集成变得简单但生产环境还需要考虑连接配置最佳实践def create_r2_client(): return boto3.client( s3, endpoint_urlconfig.R2_ENDPOINT, aws_access_key_idconfig.R2_ACCESS_KEY, aws_secret_access_keyconfig.R2_SECRET_KEY, region_nameauto )上传优化技巧使用多线程上传建议3-5个并发对大文件启用分块上传添加Content-Type元数据video/MP2Tdef upload_to_r2(filepath, bucket, key): extra_args { ContentType: video/MP2T, Metadata: {source: m3u8-downloader} } client create_r2_client() client.upload_file( filepath, bucket, key, ExtraArgsextra_args )3. Flask API封装将功能封装为Web服务后可以方便地集成到现有系统中。我们设计两个核心端点3.1 任务提交接口POST /api/download { url: https://example.com/video.m3u8, callback: https://your-webhook.com/notify }参数说明字段类型必填说明urlstring是m3u8文件地址callbackstring否完成回调URLqualitystring否指定清晰度如果有多个3.2 状态查询接口GET /api/status/task_id响应示例{ status: processing, progress: 65, download_url: null, error: null }状态机设计stateDiagram [*] -- pending pending -- downloading: 开始处理 downloading -- merging: 下载完成 merging -- uploading: 合并完成 uploading -- completed: 上传完成 any -- failed: 发生错误4. 生产环境优化4.1 错误处理机制完善的错误处理需要考虑这些场景网络波动自动重试3次指数退避无效片段跳过损坏的ts文件存储不足触发告警通知认证失效自动刷新Cookiedef download_with_retry(url, max_retries3): for attempt in range(max_retries): try: return requests.get(url, timeout15) except Exception as e: if attempt max_retries - 1: raise time.sleep(2 ** attempt)4.2 性能提升方案并发下载实现from concurrent.futures import ThreadPoolExecutor def batch_download(urls): with ThreadPoolExecutor(max_workers5) as executor: futures {executor.submit(download_ts, url): url for url in urls} for future in as_completed(futures): url futures[future] try: data future.result() save_to_disk(url, data) except Exception as e: log_error(url, str(e))内存优化技巧使用流式下载streamTrue限制并发任务的内存占用及时清理临时文件4.3 监控与日志建议记录这些关键指标平均下载速度任务成功率存储空间使用率API响应时间日志格式示例2023-08-20 14:30:45 [INFO] task_idabc123 eventdownload_start urlhttps://... 2023-08-20 14:32:18 [SUCCESS] task_idabc123 duration93s segments425. 扩展应用场景这个框架经过简单改造后还可以用于直播流录制定时检查m3u8更新视频转码预处理下载后自动触发FFmpeg处理多CDN源切换当主源失效时自动尝试备用源教育视频归档配合爬虫实现课程批量保存配置示例# config.yaml storage: local: path: /data/videos retention_days: 7 cloud: provider: r2 bucket: video-archive region: auto在实际项目中这套系统已经稳定运行超过6个月日均处理300视频任务。最关键的收获是自动化脚本必须考虑异常情况的处理而不仅仅是理想流程。比如遇到服务器重启时如何恢复中断的下载任务当云存储配额不足时如何优雅降级到本地存储等。