- Published on
- 约 796 字
Node.js实现批量下载m3u8视频文件并进行合并
- Authors
- Name
- 小辉辉
前言
事情的经过是这样的,一朋友在看一个限时提供的网课视频,来问我有没有办法把整个视频给下载下来,这样就可以在后面慢慢看了,我拿到地址了,大致看了下视频的加载方式,他们使用的是m3u8文件加载方案,这个方案之前有接触过,于是便试了试,最终终于把网课视频给下载到本地了。
实现思路
下面就是来讲讲我的实现思路,总体分为三个部分。
m3u8文件加载基本原理
现在大多数的在线视频播放基本采用的是分段加载方案,主要原理为给播放器提供一个m3u8的文件,播放器下载完文件后会对内容进行解析,里面内容我们可以简单理解成一串的播放列表。
这个播放列表由多个视频片段组成,每个视频片段标注了对应的信息,其中最主要的是视频播放时长和每段视频单独的加载地址,一般以ts格式结尾,播放器解析结束后,按照播放进度加载对应的视频片段来完成整个视频的播放。
看的出来,利用上述的m3u8方案可以显著提升视频的播放效率和加载速度,同时可以避免加载当前不必要播放的资源。
Node.js实现批量下载m3u8视频文件
核心代码片段:
// 引入必要的模块
import got from 'got';
import pLimit from 'p-limit';
import {readFileSync, createWriteStream} from "fs";
const prefix = 'xxx'; // 视频文件的前缀
const limit = pLimit(2); // 限制同时视频下载个数,以防被服务器拦截
const file =readFileSync('./index.m3u8', {encoding:'utf8'}); // 读取文件内容
const urls = file.split('\n').filter(d=>d.includes('.ts')).map(url=>{
return limit(() => got.stream(`${prefix}/${url}`).pipe(createWriteStream(`./movie/${url}`)))
});
// 开始批量下载ts资源
Promise.all(urls).then((v)=>{
console.log('finish');
}).catch(err=>{
console.error('视频文件加载出差!', err);
})
上述代码可以实现把已经下载好的index.m3u8文件里的视频文件批量下载到movie文件夹中。
Node.js实现ts文件合并
核心代码片段:
import fs from 'fs'
import path from 'path';
const streamMerge = (sourceFileDirectory, targetFile) => {
const fileWriteStream = fs.createWriteStream(path.resolve(__dirname, targetFile));
const scripts =fs.readFileSync('./index.m3u8', {encoding:'utf8'}).split('\n').filter(d=>d.includes('.ts'));
// 调用合并文件
return streamMergeRecursive(scripts, fileWriteStream, sourceFileDirectory);
}
const streamMergeRecursive = (scripts=[], fileWriteStream, sourceFileDirectory) => {
// 递归到尾部情况判断
if (!scripts.length) {
return fileWriteStream.end("console.log('Stream 合并完成')");
}
const currentFile = path.resolve(__dirname, sourceFileDirectory, scripts.shift());
const currentReadStream = fs.createReadStream(currentFile);
currentReadStream.pipe(fileWriteStream, { end: false });
currentReadStream.on('end', function() {
// 单个文件合并结束,继续下一个
streamMergeRecursive(scripts, fileWriteStream, sourceFileDirectory);
});
currentReadStream.on('error', function(error) {
console.error(error);
fileWriteStream.close();
});
}
streamMerge('./movie', './movie.mp4');
上述代码实现了将movie下的ts片段合并为movie.mp4文件,注意,为了保证合并顺序,这里还用到了m3u8文件里的原始视频片段的排序。
总结
整体流程下来,从最开始理清原理到代码实现花了比较多的时间,但后面运行代码也就耗时2分钟左右。
特别要主要的是视频加载一定要加上个数限制,否则很容易被对方的服务器给封禁,这样一来就得不偿失了。