Snippets

Kees van Bemmel Video Thumbnail Generation

Created by Kees van Bemmel
/*
 * Author: Incentro Cloud
 */

'use strict';

const gcs = require('@google-cloud/storage')();
const path = require('path');
const fs = require('fs');

const ffmpeg = require('fluent-ffmpeg');
const ffmpeg_static = require('ffmpeg-static');
const ffprobe_static = require('ffprobe-static');

// Set the ffmpeg path to use the deployed binaries
const binPath = path.resolve(__dirname, 'ffmpeg');
ffmpeg.setFfmpegPath(ffmpeg_static.path);
ffmpeg.setFfprobePath(ffprobe_static.path);

exports.videoGenerateThumbnail = function videoGenerateThumbnail(event) {
    const pubsubMessage = event.data;
    const messageData = Buffer.from(pubsubMessage.data, 'base64').toString();

    const dataObject = JSON.parse(messageData);
    const bucket = dataObject.file.bucket;
    const filename = dataObject.file.name;
    const assetid = dataObject.assetid;

    const file = gcs.bucket(bucket).file(filename);

    console.log('Processing file: ' + filename + ' for assetid ' + assetid);

    var justFile = path.basename(filename);
    var destinationPath = '/tmp/' + justFile;

    return Promise.resolve()
        .then(() => {
            console.log('downloading video file...')

            return downloadFile(file, filename, destinationPath);
        }).then(() => {

            console.log('extracting thumbnail from video')
            return generateThumbnail(destinationPath, bucket, filename);
        }).catch((err) => {
            return Promise.reject(err);
        });
};

function generateThumbnail(fileName, thumbnailBucketName, gcsfilename) {
    return new Promise((resolve, reject) => {
        ffmpeg(fileName)
            .on('end', function () {
                console.log('extracted thumbnail');
                resolve();
            })
            .screenshots({
                timestamps: ['50%'],
                filename: 'thumbnail.png',
                size: '500x?',
                folder: '/tmp/'
            });
    }).then(() => {
        console.log('Uploading thumbnail to GCS: gs://' + thumbnailBucketName + "/" + gcsfilename + "/thumbnail.png");
        return uploadFile(gcs.bucket(thumbnailBucketName), '/tmp/thumbnail.png', gcsfilename + "/thumbnail.png");
    }).then(() => {
        //make file public so the front-end can serve the image
        console.log("making thumbnail public");
        return gcs.bucket(thumbnailBucketName).file(gcsfilename + "/thumbnail.png").makePublic();
    }).then(() => {         
        fs.unlinkSync('/tmp/thumbnail.png');
        console.log('cleanup successful!');
        return Promise.resolve();
    });
}

function uploadFile(bucket, source, destfilename) {
    return new Promise((resolve, reject) => {
    var file = bucket.file(destfilename);
        fs.createReadStream(source)
          .pipe(file.createWriteStream({ validation: false }))
          .on('error', function(err) {
            console.log("error: " + err);
            reject(err);
          })
          .on('finish', function() {
            console.log("done uploading: " + destfilename);
            resolve(destfilename);// The file upload is complete.
        });
    });
}

function downloadFile(file, fileName, destinationPath) {
    return new Promise((resolve, reject) => {
        var onlyPath = path.dirname(destinationPath);
        if (!fs.existsSync(onlyPath)) {
            fs.mkdirSync(onlyPath);
        }
        file.download({
            destination: destinationPath
        }).then((error) => {
            if (error.length > 0) {
                reject(error);
            } else {
                resolve(destinationPath);
            }
        })
    });
}

Comments (0)