Commit efd6b78f authored by lijiawei's avatar lijiawei

新增 多音频合并成1个音频

parents
Pipeline #37100 canceled with stages
.vscode/launch.json
node_modules
\ No newline at end of file
FROM amazon/aws-lambda-nodejs:latest
RUN yum update -y
RUN yum install -y libpng-devel libjpeg-devel libtiff-devel libuuid-devel gcc wget tar xz vim
ARG GM_VERSION=1.3.31
RUN echo ${GM_VERSION}
# chrome动态链接库依赖
RUN yum install -y atk at-spi2-atk libxkbcommon-x11-devel libXcomposite gtk3 alsa-lib-devel
RUN curl -o ffmpeg-release-amd64-static.tar.xz https://laihua-resources.s3.cn-northwest-1.amazonaws.com.cn/packages/ffmpeg-release-amd64-static.tar.xz \
&& tar -xJf ffmpeg-release-amd64-static.tar.xz
RUN mv ./ffmpeg*/ffmpeg ./ffmpeg*/ffprobe /usr/bin \
&& rm -rf ./ffmpeg*
COPY ./package.json ./
RUN npm i --registry=https://registry.npm.taobao.org
COPY . .
# RUN yum -y install gcc automake autoconf libtool make gcc-c++ cmake
CMD [ "index.handler" ]
\ No newline at end of file
多个音频文件合并成一个
\ No newline at end of file
const storageClass = process.env.STORAGE_CLASS || 'ONEZONE_IA'//aws的存储类型
module.exports = {
accessKeyId: 'AKIAYBBCRUOVHKBABJOA',
secretAccessKey: '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',
region: 'cn-northwest-1',
bucket: 'laihua-resources',
cdn: 'https://resources.laihua.com',
errorlog_prefix: 'errorlogs',
storageClass: storageClass || 'STANDARD_IA', //上传为标准-IA存储类
debug: process.env.DEBUG || false
}
\ No newline at end of file
const util = require("util"),
cp = require("child_process"),
exec = util.promisify(cp.exec),
config = require("../config"),
uuid = require("uuid").v1,
awaitTo = require("await-to-js").default,
fs = require("fs"),
path = require("path"),
AWS = require("aws-sdk");
class Utils {
/**
* 下载 s3 音频
* @param {*} params
* @returns
*/
async download(params) {
const S3 = new AWS.S3({
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
region: config.region,
});
// 保存的文件路径
const filePath = path.join(
__dirname,
`../download/${new Date().getTime()}.mp3`
);
return new Promise((resolve, reject) => {
let stream = S3.getObject({
Bucket: config.bucket,
Key: params.key,
}).createReadStream();
var fileStream = fs.createWriteStream(filePath);
stream.pipe(fileStream);
// on error reject the Promise
stream.on("error", (err) => reject(new Error(err)));
// on end resolve the Promise
stream.on("end", () => {
resolve(filePath);
});
});
}
/**
* 上传文件到 s3 并删除原本地文件
* @param {*} params
* @param {string} params.key 文件名,上传后的文件的名字
* @returns
*/
async upload(params) {
const S3 = new AWS.S3({
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
region: config.region,
}),
that = this;
return new Promise((resolve, reject) => {
const type = params.contentType || that._getContentType(params.key);
const options = {
Bucket: config.bucket,
Key: params.key,
ServerSideEncryption: "AES256",
ContentType: type,
StorageClass: params.storageClass || config.storageClass,
};
// 获取需要上传的文件所在路径
const filePath = path.join(__dirname, "../upload", params.key);
if (!fs.existsSync(filePath)) {
return reject({ code: 412 });
}
// 读取文件
options.Body = fs.readFileSync(filePath);
console.log("----> start upload:", params.key);
S3.putObject(options, function (err, data) {
if (err) {
reject(`[upload error]:` + err.toString());
}
if (data && data.ETag) {
if (fs.existsSync(filePath)) {
// 删除本地文件
fs.unlink(filePath, (err) => {
if (err) console.log("---删除已上传的文件失败", err);
});
}
console.log("---> upload done");
return resolve(options.Key);
}
});
});
}
// 获取上传素材的meta类型
_getContentType(key) {
const fileType = key.split(".").pop().toLowerCase();
switch (fileType) {
case "mp4":
return "video/mp4";
case "mp3":
return "audio/mp3";
case "jpeg":
case "jpg":
return "image/jpeg";
case "png":
return "image/png";
case "svg":
return "text/xml";
case "txt":
case "log":
return "text/plain";
case "pdf":
return "application/pdf";
case "ppt":
case "pptx":
return "application/x-ppt";
case "gif":
return "image/gif";
case "json":
return "application/json";
default:
return "application/octet-stream";
}
}
/**
* 合并多个音频文件
* @param {Array} files 需要合并的文件路径
* @return {Object} {filePath: 文件路径,filename: 合并后的文件名}
*/
async mergeAudio(files = []) {
try {
if (files.length) {
let fileString = "concat:";
for (let i = 0; i < files.length; i++) {
fileString += `${files[i]}|`;
}
const date = new Date(),
dateDir =
date.getFullYear() +
"-" +
(date.getMonth() - 0 + 1) +
"-" +
date.getDate(),
// 新的音频文件名称
filename = `${dateDir}/${uuid()}.mp3`,
// 合并后的音频文件路径
filePath = path.join(__dirname, "../upload", filename),
baseDir = path.dirname(filePath);
// 如果文件夹不存在,则新创建文件夹
if (!fs.existsSync(baseDir)) {
fs.mkdirSync(baseDir, {
recursive: true,
});
}
// ffmpeg 的命令行
let cmd = `ffmpeg -i "${fileString}" -acodec copy ${filePath}`;
const [err, output] = await awaitTo(exec(cmd));
if (err) {
throw new Error(err);
} else {
console.log("---merge--", output);
// 删除文件
files.forEach((element) => {
fs.unlink(element, (err) => {
if (err) console.log("---删除文件失败", err);
});
});
// 成功后返回合并后的文件名字,文件路径
return {
filePath,
filename,
};
}
}
} catch (e) {
console.log("---合并失败", e);
}
}
}
module.exports = Utils;
const Utils = require("./helper/utils");
exports.handler = async (event) => {
let body = event;
let info = {};
if (body) {
if (typeof body === "string") {
info = JSON.parse(body);
} else {
info = body;
}
}
const utils = new Utils();
const downloadQueue = info.urls.map((file) =>
utils.download({
key: file,
name: file.split("/").pop(),
})
);
const downloads = await Promise.all(downloadQueue);
console.log("download done", downloads);
const { filePath, filename } = await utils.mergeAudio(downloads);
const fileUrl = await utils.upload({
filename: filePath,
key: filename,
});
return fileUrl;
};
{
"name": "lambda-merge-audio",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@gitlab.laihua.com:aws-lambda/lambda-merge-audio.git"
},
"author": "",
"license": "ISC",
"dependencies": {
"await-to-js": "^3.0.0",
"aws-sdk": "^2.1322.0",
"child_process": "^1.0.2",
"express": "^4.18.2",
"util": "^0.12.5",
"uuid": "^9.0.0"
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment