用Serverless写一个视频下载器
前言
越能体现人性尊严的快乐,越是一种最大的快乐,因为他跟人的尊严是相关的。有很多快乐,是降低了人性的尊严。而越能体现人性尊严的快乐,越是一种最高级的快乐,我们之所以读书行路,其实就是希望我们能够不断的。享受什么的快乐呢?高级的快乐。—- 罗翔老师经典语录
开始
今天看到一个开源库,用Node.js
下载Youtube 视频,我眼前一亮,马上打开页面,看了一下介绍,好家伙,这么容易使用,那以后打工人上下班看离线视频那不是方便多了。我们先看一下API
https://github.com/fent/node-ytdl-core
这API可真是简洁啊,我们把包在本地安装,然后下载不就好了。事情肯定没有这么简单,网络不通,哈哈。没关系~我有云,我有Serverless,我不用,就是玩。不不不,确实要用。
这里我的思路就是通过API网关生成一个URL,调用之后转到云函数,云函数下载视频到临时文件夹,云函数使用运行角色密钥上传视频文件至COS,我们再通过COS客户端在手机上面看视频。把函数部署到香港地域就没有网络的限制了,说着说着我都激动了一把。
大概思路就是图上这样。那我们开干吧。
这里我选择腾讯云作为云提供商,因为腾讯云一直有免费的额度可以用,我们这一点点运算量,基本上不要米。技术上我们用Node.js
,当然要上TypeScript
这样才有逼格。
我们通过Serverless这个框架创建一个SCF
函数,然后基于它编写代码。
$ npm i serverless -g
$ serverless init scf-demo
这样一个项目就创建好了
我们进入src/index.js
下编写文件,先把后缀改为.ts
,然后接着配置
$ npm i ytdl-core cos-nodejs-sdk-v5 -S
$ npm i typescript ts-node prettier -D
这里ytdl-core
是下载视频的包,cos-nodejs-sdk-v5
是上传视频到COS的Node SDK
然后我们这里还需要一个强悍的打包工具,把所有代码打包到一起,毕竟云函数是不支持运行TS的。
这里我推荐一个很好用的打包工具ncc,零配置,内置TS,按需加载,支持所有node包
$ ncc build input.js -o dist
可以看到,打包方法非常简单,到时候我们把这个脚本配置到npm build
命令里那不是美滋滋。我们全局安装一下
$ npm i -g @vercel/ncc
编码
接下来我们编写代码:
const fs = require('fs')
const path = require('path')
const ytdl = require('ytdl-core')
const COS = require('cos-nodejs-sdk-v5')
exports.main_handler = (event, context, callback) => {
ytdl('https://www.youtube.com/watch?v=aqz-KE-bpKQ', {
// 这里为了演示,只下载一小段,免得浪费大家流量
range: {
start: 0,
end: 5355705,
},
})
.pipe(fs.createWriteStream(path.join('/tmp', 'video.mp4')))
.on('finish', () => {
// 这里有个坑,临时密钥一定要填这个SESSION TOKEN 不然怎么都上传不了
// 通过运行角色获取临时密钥
const environment = JSON.parse(context.environment)
const cos = new COS({
SecretId: environment.TENCENTCLOUD_SECRETID,
SecretKey: environment.TENCENTCLOUD_SECRETKEY,
SecurityToken: environment.TENCENTCLOUD_SESSIONTOKEN,
})
cos.putObject(
{
Bucket: 'youtube-1253555942' /* 我们创建的COS Bucket */,
Region: 'ap-hongkong' /* 地域 */,
Key: `video-${Date.now()}.mp4` /* 文件名 */,
StorageClass: 'STANDARD' /* 默认就好了 */,
Body: fs.createReadStream(path.join('/tmp', 'video.mp4')), // 上传文件对象
onProgress: function (progressData) {
console.log(JSON.stringify(progressData))
},
},
function (err, data) {
console.log(err || data)
callback(null, 'ok')
},
)
})
.on('error', (e) => {
console.log(e)
})
}
这段代码的逻辑:引入包,进入主函数main_handler
,编写下载逻辑,存入临时文件,创建COS对象,上传COS文件,结束。一气呵成,非常顺滑。TS的类型就交给你们补充了。云函数支持两种异步方法,一种async,一种callback,这里我们用到了流所以callback
的方式会简单一些,调用callback告诉引擎函数执行完毕。
我们再配置一下项目就可以运行起来了。首先是serverless.yml
这个是上传至云函数的配置,这里用到香港地域,还有代码路径填我们打包后的目录,这样可以少上传些文件,让部署速度更快,其它配置基本不变。
#应用信息
app: scf-demo-3723d4bb
#组件信息
component: scf # (必填) 引用 component 的名称,当前用到的是 tencent-scf 组件
name: youtube # (必填) 创建的实例名称,请修改成您的实例名称
#组件参数
inputs:
name: ${name}-${stage} #函数名称
src: ./dist #代码路径
handler: index.main_handler #入口
runtime: Nodejs10.15 # 云函数运行时的环境
region: ap-hongkong # 云函数所在区域
events: # 触发器
- apigw: # 网关触发器
parameters:
endpoints:
- path: /
method: GET
再配置一下我们的deploy
脚本,这样我们运行npm run deploy
时,会先执行打包再部署。
"scripts": {
"start": "ts-node src/local.ts",
"build": "ncc build src/index.ts",
"deploy": "npm run build && sls deploy"
},
一切准备就绪,运行npm run deploy
,可以看到已经成功上传到云函数了。并且还帮我们创建了一个网关触发器,可以通过URL直接触发访问函数
我们登上函数控制台页面,在函数配置这里把运行角色给加上,后续上传到COS,就可以直接从函数运行上下文中取到SecretKey和SecretID了,不用写死在代码里面,很方便。
我们手动测试一下函数
不错,成功了
可以看到COS里已经有我们想下载的视频文件了,xdm是不是很方便。
这里我偷个懒,通过网关URL参数获取视频地址,这个功能就交给你们开发了。
我把代码提交一下,大家可以直接Fork到自己仓库下开发。
再见
感谢大家支持,我们下期再见。