'use strict'
const async = require('async')
const config = require('config')
const ffmpeg = require('fluent-ffmpeg')
const fs = require('fs')
const map = require('lodash/map')
const pathUtils = require('path')
const constants = require('../initializers/constants')
const logger = require('../helpers/logger')
const utils = require('../helpers/utils')
const Videos = require('../models/videos')
const webtorrent = require('../lib/webtorrent')
const uploadDir = pathUtils.join(__dirname, '..', '..', config.get('storage.uploads'))
const thumbnailsDir = pathUtils.join(__dirname, '..', '..', config.get('storage.thumbnails'))
const videos = {
convertVideoToRemote: convertVideoToRemote,
createRemoteVideos: createRemoteVideos,
getVideoDuration: getVideoDuration,
getVideoState: getVideoState,
createVideoThumbnail: createVideoThumbnail,
removeVideosDataFromDisk: removeVideosDataFromDisk,
removeRemoteVideos: removeRemoteVideos,
seed: seed,
seedAllExisting: seedAllExisting
}
function convertVideoToRemote (video, callback) {
fs.readFile(thumbnailsDir + video.thumbnail, function (err, thumbnailData) {
if (err) {
logger.error('Cannot read the thumbnail of the video')
return callback(err)
}
const remoteVideo = {
name: video.name,
description: video.description,
magnetUri: video.magnetUri,
author: video.author,
duration: video.duration,
thumbnailBase64: new Buffer(thumbnailData).toString('base64'),
tags: video.tags,
createdDate: video.createdDate,
podUrl: video.podUrl
}
return callback(null, remoteVideo)
})
}
function createRemoteVideos (videos, callback) {
// Create the remote videos from the new pod
createRemoteVideoObjects(videos, function (err, remoteVideos) {
if (err) return callback(err)
Videos.addRemotes(remoteVideos, callback)
})
}
function getVideoDuration (videoPath, callback) {
ffmpeg.ffprobe(videoPath, function (err, metadata) {
if (err) return callback(err)
return callback(null, Math.floor(metadata.format.duration))
})
}
function getVideoState (video) {
const exist = (video !== null)
let owned = false
if (exist === true) {
owned = (video.namePath !== null)
}
return { exist: exist, owned: owned }
}
function createVideoThumbnail (videoPath, callback) {
const filename = pathUtils.basename(videoPath) + '.jpg'
ffmpeg(videoPath)
.on('error', callback)
.on('end', function () {
callback(null, filename)
})
.thumbnail({
count: 1,
folder: thumbnailsDir,
size: constants.THUMBNAILS_SIZE,
filename: filename
})
}
// Remove video datas from disk (video file, thumbnail...)
function removeVideosDataFromDisk (videos, callback) {
async.each(videos, function (video, callbackEach) {
fs.unlink(thumbnailsDir + video.thumbnail, function (err) {
if (err) logger.error('Cannot remove the video thumbnail')
if (getVideoState(video).owned === true) {
fs.unlink(uploadDir + video.namePath, function (err) {
if (err) {
logger.error('Cannot remove this video file.')
return callbackEach(err)
}
callbackEach(null)
})
} else {
callbackEach(null)
}
})
}, callback)
}
function removeRemoteVideos (videos, callback) {
Videos.removeByIds(map(videos, '_id'), function (err) {
if (err) return callback(err)
removeVideosDataFromDisk(videos, callback)
})
}
function seed (path, callback) {
logger.info('Seeding %s...', path)
webtorrent.seed(path, function (torrent) {
logger.info('%s seeded (%s).', path, torrent.magnetURI)
return callback(null, torrent)
})
}
function seedAllExisting (callback) {
Videos.listOwned(function (err, videosList) {
if (err) {
logger.error('Cannot get list of the videos to seed.')
return callback(err)
}
async.each(videosList, function (video, callbackEach) {
seed(uploadDir + video.namePath, function (err) {
if (err) {
logger.error('Cannot seed this video.')
return callback(err)
}
callbackEach(null)
})
}, callback)
})
}
// ---------------------------------------------------------------------------
module.exports = videos
// ---------------------------------------------------------------------------
function createRemoteVideoObjects (videos, callback) {
const remoteVideos = []
async.each(videos, function (video, callbackEach) {
// Creating the thumbnail for this remote video
utils.generateRandomString(16, function (err, randomString) {
if (err) return callbackEach(err)
const thumbnailName = randomString + '.jpg'
createThumbnailFromBase64(thumbnailName, video.thumbnailBase64, function (err) {
if (err) return callbackEach(err)
const params = {
name: video.name,
description: video.description,
magnetUri: video.magnetUri,
podUrl: video.podUrl,
duration: video.duration,
thumbnail: thumbnailName,
tags: video.tags,
author: video.author
}
remoteVideos.push(params)
callbackEach(null)
})
})
},
function (err) {
if (err) return callback(err)
callback(null, remoteVideos)
})
}
function createThumbnailFromBase64 (thumbnailName, data, callback) {
fs.writeFile(thumbnailsDir + thumbnailName, data, { encoding: 'base64' }, callback)
}