ffprobe working
This commit is contained in:
Родитель
d02d2a8d53
Коммит
a01f71e5fe
|
@ -8,6 +8,7 @@ module.exports = {
|
|||
"ecmaVersion": 2017
|
||||
},
|
||||
globals: { process: true },
|
||||
sourceType: "module",
|
||||
plugins: ["prettier"],
|
||||
rules: {
|
||||
"prettier/prettier": "error",
|
||||
|
|
119
index.js
119
index.js
|
@ -1,7 +1,122 @@
|
|||
module.exports.handler = async function handler(event, context, callback) {
|
||||
const {join} = require('path');
|
||||
const {tmpdir} = require('os');
|
||||
const {unlink, createReadStream, createWriteStream, readdirSync, existsSync, mkdirSync} = require('fs');
|
||||
const {spawn, execFile} = require('child_process');
|
||||
const VIDEO_MAX_DURATION = 600;
|
||||
const AWS = require('aws-sdk');
|
||||
|
||||
// Relies upon https://github.com/serverlesspub/ffmpeg-aws-lambda-layer being deployed
|
||||
|
||||
// Shamelessly taken from https://gist.github.com/6174/6062387
|
||||
const createKey = () =>
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15) +
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15);
|
||||
|
||||
const log = console.log;
|
||||
|
||||
/** @type string **/
|
||||
const tempDir = process.env['TEMP'] || tmpdir();
|
||||
const tempFile = join(tempDir, 'tempFile');
|
||||
|
||||
// https://github.com/binoculars/aws-lambda-ffmpeg
|
||||
function ffprobe() {
|
||||
log('Starting FFprobe');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = [
|
||||
'-v', 'quiet',
|
||||
'-print_format', 'json',
|
||||
'-show_format',
|
||||
'-show_streams',
|
||||
'-i', 'tempFile'
|
||||
];
|
||||
const opts = {
|
||||
cwd: tempDir
|
||||
};
|
||||
const cb = (error, stdout) => {
|
||||
if (error)
|
||||
reject(error);
|
||||
|
||||
log(stdout);
|
||||
|
||||
const {streams, format} = JSON.parse(stdout);
|
||||
log(JSON.stringify(streams))
|
||||
log(JSON.stringify(format))
|
||||
|
||||
const hasVideoStream = streams.some(({codec_type, duration}) =>
|
||||
codec_type === 'video' &&
|
||||
(duration || format.duration) <= VIDEO_MAX_DURATION
|
||||
);
|
||||
|
||||
if (!hasVideoStream)
|
||||
reject('FFprobe: no valid video stream found');
|
||||
else {
|
||||
log('Valid video stream found. FFprobe finished.');
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
execFile('ffprobe', args, opts, cb)
|
||||
.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
// Perform a GET to /init to get a upload URL and key to pass to convert for conversion
|
||||
module.exports.init = async function init(event, context, callback) {
|
||||
const { scratchBucketId, scratchBucketRegion } = process.env;
|
||||
const key = createKey();
|
||||
|
||||
const s3 = new AWS.S3({
|
||||
region: scratchBucketRegion,
|
||||
signatureVersion: "v4"
|
||||
});
|
||||
|
||||
const uploadUrl = s3.getSignedUrl("putObject", {
|
||||
Bucket: scratchBucketId,
|
||||
Key: key,
|
||||
Expires: 240
|
||||
});
|
||||
|
||||
return callback(null, {
|
||||
statusCode: 200,
|
||||
body: "OK",
|
||||
body: JSON.stringify({ uploadUrl, key }),
|
||||
isBase64Encoded: false
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.convert = async function convert(event, context, callback) {
|
||||
const queryStringParameters = event.queryStringParameters || {};
|
||||
|
||||
const { scratchBucketId, scratchBucketRegion } = process.env;
|
||||
const s3 = new AWS.S3({
|
||||
region: scratchBucketRegion,
|
||||
signatureVersion: "v4"
|
||||
});
|
||||
|
||||
const sourceKey = queryStringParameters.key || "odbpaimwsvp475ha2gphik";
|
||||
const destKey = createKey();
|
||||
|
||||
let readStream;
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
s3
|
||||
.getObject({ Bucket: scratchBucketId, Key: sourceKey })
|
||||
.on("error", error => reject(`S3 Download Error: ${error}`))
|
||||
.createReadStream()
|
||||
.on('end', () => { log('Download finished'); resolve(); })
|
||||
.on('error', reject)
|
||||
.pipe(createWriteStream(tempFile));
|
||||
});
|
||||
|
||||
await ffprobe();
|
||||
|
||||
return callback(null, {
|
||||
statusCode: 200,
|
||||
body: destKey,
|
||||
isBase64Encoded: false
|
||||
});
|
||||
};
|
||||
|
|
|
@ -6,7 +6,8 @@ provider:
|
|||
stackName: speelycaptor-${opt:stage, 'dev'}
|
||||
stage: ${opt:stage, 'dev'}
|
||||
region: ${file(config.json):speelycaptor-region}
|
||||
timeout: 30
|
||||
timeout: 120
|
||||
memorySize: 3000
|
||||
role: ${file(config.json):speelycaptor-iam-role}
|
||||
deploymentBucket:
|
||||
name: ${file(config.json):speelycaptor-bucket-id}
|
||||
|
@ -26,8 +27,20 @@ provider:
|
|||
aws:sourceVpc: ${file(config.json):speelycaptor-vpc-id}
|
||||
|
||||
functions:
|
||||
app:
|
||||
handler: index.handler
|
||||
initialize:
|
||||
handler: index.init
|
||||
environment:
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-region}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-public-scratch-bucket-id}
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
path: init
|
||||
convert:
|
||||
handler: index.convert
|
||||
environment:
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-region}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-public-scratch-bucket-id}
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
|
|
|
@ -2,11 +2,12 @@ service: speelycaptor
|
|||
|
||||
provider:
|
||||
name: aws
|
||||
runtime: nodejs8.10
|
||||
runtime: nodejs10.x
|
||||
stackName: speelycaptor-public
|
||||
stage: public
|
||||
region: ${file(config.json):speelycaptor-region}
|
||||
timeout: 30
|
||||
memorySize: 3000
|
||||
timeout: 120
|
||||
role: ${file(config.json):speelycaptor-public-iam-role}
|
||||
deploymentBucket:
|
||||
name: ${file(config.json):speelycaptor-public-bucket-id}
|
||||
|
@ -19,11 +20,22 @@ provider:
|
|||
burstLimit: 10
|
||||
|
||||
functions:
|
||||
app:
|
||||
handler: index.handler
|
||||
initialize:
|
||||
handler: index.init
|
||||
environment:
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-bucket-id}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-scratch-bucket-id}
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-region}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-public-scratch-bucket-id}
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
path: init
|
||||
convert:
|
||||
handler: index.convert
|
||||
layers:
|
||||
- ${file(config.json):ffmpeg-lambda-layer-arn}
|
||||
environment:
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-region}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-public-scratch-bucket-id}
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
|
|
|
@ -2,10 +2,11 @@ service: speelycaptor
|
|||
|
||||
provider:
|
||||
name: aws
|
||||
runtime: nodejs8.10
|
||||
runtime: nodejs10.x
|
||||
stackName: speelycaptor-public
|
||||
stage: public
|
||||
region: ${file(config.json):speelycaptor-region}
|
||||
memorySize: 3000
|
||||
timeout: 30
|
||||
role: ${file(config.json):speelycaptor-public-iam-role}
|
||||
deploymentBucket:
|
||||
|
@ -19,11 +20,22 @@ provider:
|
|||
burstLimit: 10
|
||||
|
||||
functions:
|
||||
app:
|
||||
handler: index.handler
|
||||
initialize:
|
||||
handler: index.init
|
||||
environment:
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-bucket-id}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-scratch-bucket-id}
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-region}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-public-scratch-bucket-id}
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
path: init
|
||||
convert:
|
||||
handler: index.convert
|
||||
layers:
|
||||
- ${file(config.json):ffmpeg-lambda-layer-arn}
|
||||
environment:
|
||||
scratchBucketRegion: ${file(config.json):speelycaptor-region}
|
||||
scratchBucketId: ${file(config.json):speelycaptor-public-scratch-bucket-id}
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
|
|
Загрузка…
Ссылка в новой задаче