摘要
@lzwme/m3u8-dl 是一个基于Node.js开发的支持多线程并发批量下载M3U8视频的命令行工具,其最基本的功能是可以根据给定的一个或多个M3U8链接进行多线程的并发下载,然后转换为 mp4 格式,同时也支持 API 方式调用。
当前各主流视频网站都提供了会员服务,对于热门的电影、电视剧和综艺等节目,基本都需要会员付费购买,或者观看大量漫长到令人难以忍受的广告。开一个视频网站付费会员是大多数人都可以接受的,但问题是一些热门剧往往被一个平台买断版权,只是为了看单个剧集而需再多开一个会员,还是会令人三思一下。
从上一篇文章《免费电影网站建设的模式与技术内幕》介绍的内容中,我们知道了免费电影站的影音视频资源来源实际上来源于资源采集站,但是由于使用它们服务的免费电影网站及免费影视观看软件很多,使得在高峰时期下载速度往往非常慢,观影卡顿是最明显的感受,也是比较难以忍受的,这使得免费电影站的视频播放存在较高的不稳定性,观影体验并不好。如果能够预下载下来,就解决了这个最为主要的问题。
实际上,我们可以直接从采集站搜索并获取想要观看的电影的 m3u8(M3U8 格式与在线视频播放播简介) 链接,然后基于 m3u8 链接对 ts 分片视频进行下载,最后再合并为完整的 mp4 格式视频文件即可完成视频下载。
上述内容来源于2023年春节期间个人追看热门剧《狂飙》的总结。在追剧的过程中开发了一个 M3U8 视频下载工具 @lzwme/m3u8-dl,它是一个基于 Node.js 开发的支持多线程并发批量下载 M3U8 视频的命令行工具,其最基本的功能是可以根据给定的一个或多个 M3U8 链接进行多线程的并发下载,然后转换为 mp4 格式(需 ffmpeg 支持),同时也支持 API 方式调用。
后面又继续丰富了功能,可以支持指定影视资源采集站 API 接口,从其接口搜索想要观看的内容,并提取 M3U8 视频地址进行下载,也基于 HLS 流媒体协议的特点支持了边下边看模式。
1 @lzwme/m3u8-dl
实现 m3u8 文件视频下载的原理
其实现原理其实是比较简单的,大致内容包括:
- 首先将给定的 m3u8 地址进行下载,得到 m3u8 文件文本内容。
- 然后借助开源库 m3u8-parser进行解析,可以得到其所有分片信息。
- 基于 http 方式实现对分片 ts 文件的下载。
- 基于 Node.js 的
worker_threads
模块实现对分片 ts 文件的多线程并发下载。若存在加密信息,还需使用 AES 等算法进行 ts 文件解密。然后缓存下载的 ts 文件至本地。 - 根据 ts 分片信息的数量、时长等数据,实现对下载信息的进度计算逻辑。
- 全部 ts 分片文件都下载完成后,借助
ffmpeg
实现将它们合成一个 mp4 格式的完整视频文件。 - 如果启动了边下边看模式,在下载到一定比例数量的 ts 分片文件后,即启动一个内置 web server,基于
hls.js
库实现基于浏览器的边看边下支持。
若有兴趣,可详细阅读其源码实现进行进一步的了解:
2 @lzwme/m3u8-dl
的安装
首先需要安装 Node.js,可从官方网站下载并安装:https://nodejs.org/zh-cn
然后(windows系统为例)打开 powershell 或 cmd 命令提示符等终端,执行如下命令进行全局安装:
# 全局安装 npm i -g @lzwme/m3u8-dl
继续执行 m3u8dl -h
和 m3u8dl s -h
命令查看使用帮助,可以得到如下内容:
$ m3u8dl -h Usage: m3u8dl [options] [command] <m3u8Urls...> Batch download of m3u8 files and convert to mp4 Arguments: m3u8Urls m3u8 url。也可以是本地 txt 文件,指定一组 m3u8,适用于批量下载的场景 Options: -v, --version output the version number --silent 开启静默模式。 --debug 开启调试模式。 -f, --filename <name> 指定下载文件的保存名称。默认取 url md5 值。若指定了多个 url 地址,则会在末尾增加序号 -n, --thread-num <number> 并发下载线程数。默认为 cpu * 2。可设置不同数值观察下载效果 -F, --force 启用强制执行模式。文件已存在时,是否仍继续下载和生成 --no-progress 是否不打印进度信息 -p, --play 是否边下边看 -C, --cache-dir <dirpath> 临时文件保存目录。默认为 cache -S, --save-dir <dirpath> 下载文件保存的路径。默认为当前目录 --no-del-cache 下载成功后是否删除临时文件。默认为 true。保存临时文件可以在重复下载时识别缓存 -h, --help display help for command Commands: search|s [options] [keyword] m3u8视频在线搜索与下载 $ m3u8dl s -h Usage: m3u8dl search|s [options] [keyword] m3u8视频在线搜索与下载 Options: -u,--url <api...> 影视搜索的接口地址(m3u8采集站标准接口) -R,--remote-config-url <url> 自定义远程配置加载地址。默认从主仓库配置读取 -h, --help display help for command
3 使用 @lzwme/m3u8-dl
进行视频资源下载
3.1 根据给定的 m3u8 链接进行下载
最简单的使用方法,给定一个 m3u8 视频地址,即可进行资源下载:
m3u8dl "https://dl.test.com/play/zbqMZYRb/index.m3u8" --filename "三体-第一集"
也支持指定剧集的多个地址进行批量下载:
m3u8dl "第1集|https://dl.test.com/play/zbqMZYRb/index.m3u8" "第2集|https://dl.test.com/play/PdyJXrwe/index.m3u8" --filename "三体"
还可以支持指定一个文本文件,对多个 m3u8 地址进行批量下载。新建文件 三体.txt
,内容格式参考:
第1集$https://dl.test.com/play/zbqMZYRb/index.m3u8 第2集$https://dl.test.com/play/PdyJXrwe/index.m3u8 第3集$https://dl.test.com/play/oeE6x9Ka/index.m3u8
然后执行如下命令即可启动批量下载:
m3u8dl 三体.txt
3.2 基于 API 的调用
@lzwme/m3u8-dl
导出了方法 m3u8Download
等以供自编程应用程序调用。示例:
import { m3u8Download } from '@lzwme/m3u8-dl'; // 示例:单文件下载 m3u8Download('test/t.m3u8', { debug: true, filenmae: '测试视频' }); // 示例:批量下载 const fileList = ['第一集$$test/t.m3u8']; for (const filepath of fileList) { const r = await m3u8Download(filepath, { debug: true, filenmae: '测试视频' }); console.log('文件已下载:', r.filepath); }
3.3 根据给定的资源采集站 API 搜索并下载
执行如下命令,然后按提示步骤继续操作即可(示例中的 API 地址为示例地址,并非真实可用的资源采集站API)
m3u8dl search -h # 指定采集站 API url 地址(会缓存),然后按提示操作 m3u8dl s -u https://api.test.com/provide/vod/