当老婆又让我下载一个腾讯视频时...

17,313 阅读4分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

我们结婚了!

是的,这次不是女朋友啦,是老婆了!

WechatIMG56.jpeg

WechatIMG57.jpeg

WechatIMG58.jpeg

时隔将近一个月,老婆又让我给她下载腾讯视频,如果按照上次探索的内容来下载的话,倒是可以一步步下载,合并,不过很麻烦,程序员不都是为了解决麻烦的吗,这么麻烦的步骤,有没有简单点呢。有!当然有,有很多简单的工具,上一期很多朋友给我推荐了各种工具,这里我没有一一查看,我可以列举出来,有需要的同学可以尝试看看,不想尝试的也可以看看我下面为了偷懒准备的方法。

心路历程

最初,我是想着把我之前的步骤,用无头浏览器加载一遍,然后用代码去下载ts片段,然后在机器上用ffmpeg进行合并,但是仿佛还是有些许麻烦,然后我就去npm搜了一下关键词:m3u8tomp4

image.png

m3u8-to-mp4

于是我点击了第一个包:m3u8-to-mp4

image.png

纳尼?这个包就一个版本,用了3年,而且周下载量还不少

image.png

于是我想着这个包要么就是很牛逼,一次性解决了m3u8转mp4的问题,一劳永逸,所以3年没更新过了,要么就是作者忘记了自己还有这个包

于是我就用了这个3年没人维护没人更新的包。

用法也很简单,就copy example 就好了。代码如下:


var m3u8ToMp4 = require("m3u8-to-mp4");
var converter = new m3u8ToMp4();
(async function() {
    var url = "https://apd-666945ea97106754c57813479384d30c.v.smtcdns.com/omts.tc.qq.com/AofRtrergNwkAhpHs4RrxH2_9DWLWSG8xjDMZDQoFGyY/uwMROfz2r55kIaQXGdGnC2deOm68BrdPrRewQlOzrMAbixNO/svp_50001/cKAgRbCb6Re4BpHkI-IlK_KN1VJ8gQVK2sZtkHEY3vQUIlxVz7AtWmVJRifZrrPfozBS0va-SSJFhQhOFSKVNmqVi165fCQJoPl8V5QZBcGZBDpSIfrpCImJKryoZOdR5C0oGYkzIW77I4his7UkPY9Iwmf1QWjaHwNV2hpKv3aD9ysL_-YByA/szg_9276_50001_0bc3uuaa2aaafmaff4e3ijqvdjodbwsqadka.f304110.ts.m3u8?ver=4"
  await converter
    .setInputFile(url)
    .setOutputFile("dummy.mp4")
    .start();
  console.log("File converted");
})();

视频地址是 v.qq.com/x/page/v331…

然后视频就转换成功了,哇哦!

so easy ! so beautiful!

原理

带着好奇,我想看下这个包是如何进行转换的

于是我点进去m3u8-to-mp4这个包文件

包文件内容如下

image.png

只有一个文件?

然后我打开了index.js ,只有64行😂

全部代码如下

/**
* @description M3U8 to MP4 Converter
* @author Furkan Inanc
* @version 1.0.0
*/

let ffmpeg = require("fluent-ffmpeg");

/**
* A class to convert M3U8 to MP4
* @class
*/
class m3u8ToMp4Converter {
 /**
  * Sets the input file
  * @param {String} filename M3U8 file path. You can use remote URL
  * @returns {Function}
  */
 setInputFile(filename) {
   if (!filename) throw new Error("You must specify the M3U8 file address");
   this.M3U8_FILE = filename;

   return this;
 }

 /**
  * Sets the output file
  * @param {String} filename Output file path. Has to be local :)
  * @returns {Function}
  */
 setOutputFile(filename) {
   if (!filename) throw new Error("You must specify the file path and name");
   this.OUTPUT_FILE = filename;

   return this;
 }

 /**
  * Starts the process
  */
 start() {
   return new Promise((resolve, reject) => {
     if (!this.M3U8_FILE || !this.OUTPUT_FILE) {
       reject(new Error("You must specify the input and the output files"));
       return;
     }

     ffmpeg(this.M3U8_FILE)
       .on("error", error => {
         reject(new Error(error));
       })
       .on("end", () => {
         resolve();
       })
       .outputOptions("-c copy")
       .outputOptions("-bsf:a aac_adtstoasc")
       .output(this.OUTPUT_FILE)
       .run();
   });
 }
}

module.exports = m3u8ToMp4Converter;

大致看了下这个包做的内容,就是检测并设置了输入链接,和输出文件名,然后调用了fluent-ffmpeg这个库

???

站在巨人的肩膀上吗,自己就包了一层😂

接着看fluent-ffmpeg这个包,是如何实现转换的

image.png

然后我们在这个包文件夹下面搜索.run方法,用来定位到具体执行的地方

image.png

凭借多年的cv经验,感觉应该是processor.js这个文件里的,然后我们打开这个文件,定位到该方法处

image.png

往下看代码,我注意到了这段代码

image.png

因为都是基于ffmpeg这个大爹来做的工具,所以最底层也都是去调用ffmpeg的command

image.png

这几个if判断都是对结果进行捕获异常,那么我们在这个核心代码的地方打个端点看下

image.png

貌似是调用了几个命令行参数

于是我就有了一个大胆的想法!

image.png

是的,我手动在终端将这个命令拼接起来,用我的本地命令去跑应该也没问题的吧,于是我尝试了一下

image.png

没想到还成功了,其实成功是必然的,因为都是借助来ffmpeg这个包,只不过我是手动去操作,框架是代码去拼接这个命令而已

剩余的时间里,我看了看fluent-ffmpeg的其他代码,它做的东西比较多,比如去本查找ffmpeg的绝对路径啊,对ffmpeg的结果进行捕获异常信息等...

后续

现在,给老婆下载视频的过程是这样的

  • 去网页端腾讯视频找m3u8链接
  • 粘贴url到我的这个node程序中
  • 执行命令
  • 老婆开心!😄

网友提到的方法

  • N_m3u8DL-CLI
  • chrmoVideo Downloader professional 插件。
  • Downie
  • IDM插件
  • you-get
  • Neat Download Management

关于我

微信:cjs764901388

公众号:xstxoo

我的公众号:小松同学哦

可以关注我,一起学习前端知识,喜欢把生活中用到技术的地方记录下来,并且研究一下🧐