aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video.js
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-05-02 22:02:27 +0200
committerChocobozzz <florian.bigard@gmail.com>2017-05-04 21:12:32 +0200
commit227d02feadbc9b1fc916a12528ccc0623fb3069e (patch)
tree0b6bcc8c2c081591588714bc040ac6e810e333de /server/models/video.js
parent15d4ee04a94230e1ea83c2959a1981105699ba22 (diff)
downloadPeerTube-227d02feadbc9b1fc916a12528ccc0623fb3069e.tar.gz
PeerTube-227d02feadbc9b1fc916a12528ccc0623fb3069e.tar.zst
PeerTube-227d02feadbc9b1fc916a12528ccc0623fb3069e.zip
Server: add job scheduler to transcode video files
Diffstat (limited to 'server/models/video.js')
-rw-r--r--server/models/video.js116
1 files changed, 94 insertions, 22 deletions
diff --git a/server/models/video.js b/server/models/video.js
index 029cb6d7c..da4ddb420 100644
--- a/server/models/video.js
+++ b/server/models/video.js
@@ -7,6 +7,7 @@ const fs = require('fs')
7const magnetUtil = require('magnet-uri') 7const magnetUtil = require('magnet-uri')
8const map = require('lodash/map') 8const map = require('lodash/map')
9const parallel = require('async/parallel') 9const parallel = require('async/parallel')
10const series = require('async/series')
10const parseTorrent = require('parse-torrent') 11const parseTorrent = require('parse-torrent')
11const pathUtils = require('path') 12const pathUtils = require('path')
12const values = require('lodash/values') 13const values = require('lodash/values')
@@ -17,6 +18,7 @@ const friends = require('../lib/friends')
17const modelUtils = require('./utils') 18const modelUtils = require('./utils')
18const customVideosValidators = require('../helpers/custom-validators').videos 19const customVideosValidators = require('../helpers/custom-validators').videos
19const db = require('../initializers/database') 20const db = require('../initializers/database')
21const jobScheduler = require('../lib/jobs/job-scheduler')
20 22
21// --------------------------------------------------------------------------- 23// ---------------------------------------------------------------------------
22 24
@@ -203,6 +205,7 @@ module.exports = function (sequelize, DataTypes) {
203 toFormatedJSON, 205 toFormatedJSON,
204 toAddRemoteJSON, 206 toAddRemoteJSON,
205 toUpdateRemoteJSON, 207 toUpdateRemoteJSON,
208 transcodeVideofile,
206 removeFromBlacklist 209 removeFromBlacklist
207 }, 210 },
208 hooks: { 211 hooks: {
@@ -234,38 +237,30 @@ function beforeCreate (video, options, next) {
234 237
235 tasks.push( 238 tasks.push(
236 function createVideoTorrent (callback) { 239 function createVideoTorrent (callback) {
237 const options = { 240 createTorrentFromVideo(video, videoPath, callback)
238 announceList: [
239 [ constants.CONFIG.WEBSERVER.WS + '://' + constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT + '/tracker/socket' ]
240 ],
241 urlList: [
242 constants.CONFIG.WEBSERVER.URL + constants.STATIC_PATHS.WEBSEED + video.getVideoFilename()
243 ]
244 }
245
246 createTorrent(videoPath, options, function (err, torrent) {
247 if (err) return callback(err)
248
249 const filePath = pathUtils.join(constants.CONFIG.STORAGE.TORRENTS_DIR, video.getTorrentName())
250 fs.writeFile(filePath, torrent, function (err) {
251 if (err) return callback(err)
252
253 const parsedTorrent = parseTorrent(torrent)
254 video.set('infoHash', parsedTorrent.infoHash)
255 video.validate().asCallback(callback)
256 })
257 })
258 }, 241 },
259 242
260 function createVideoThumbnail (callback) { 243 function createVideoThumbnail (callback) {
261 createThumbnail(video, videoPath, callback) 244 createThumbnail(video, videoPath, callback)
262 }, 245 },
263 246
264 function createVIdeoPreview (callback) { 247 function createVideoPreview (callback) {
265 createPreview(video, videoPath, callback) 248 createPreview(video, videoPath, callback)
266 } 249 }
267 ) 250 )
268 251
252 if (constants.CONFIG.TRANSCODING.ENABLED === true) {
253 tasks.push(
254 function createVideoTranscoderJob (callback) {
255 const dataInput = {
256 id: video.id
257 }
258
259 jobScheduler.createJob(options.transaction, 'videoTranscoder', dataInput, callback)
260 }
261 )
262 }
263
269 return parallel(tasks, next) 264 return parallel(tasks, next)
270 } 265 }
271 266
@@ -503,6 +498,59 @@ function toUpdateRemoteJSON (callback) {
503 return json 498 return json
504} 499}
505 500
501function transcodeVideofile (finalCallback) {
502 const video = this
503
504 const videosDirectory = constants.CONFIG.STORAGE.VIDEOS_DIR
505 const newExtname = '.mp4'
506 const videoInputPath = pathUtils.join(videosDirectory, video.getVideoFilename())
507 const videoOutputPath = pathUtils.join(videosDirectory, video.id + '-transcoded' + newExtname)
508
509 ffmpeg(videoInputPath)
510 .output(videoOutputPath)
511 .videoCodec('libx264')
512 .outputOption('-threads ' + constants.CONFIG.TRANSCODING.THREADS)
513 .outputOption('-movflags faststart')
514 .on('error', finalCallback)
515 .on('end', function () {
516 series([
517 function removeOldFile (callback) {
518 fs.unlink(videoInputPath, callback)
519 },
520
521 function moveNewFile (callback) {
522 // Important to do this before getVideoFilename() to take in account the new file extension
523 video.set('extname', newExtname)
524
525 const newVideoPath = pathUtils.join(videosDirectory, video.getVideoFilename())
526 fs.rename(videoOutputPath, newVideoPath, callback)
527 },
528
529 function torrent (callback) {
530 const newVideoPath = pathUtils.join(videosDirectory, video.getVideoFilename())
531 createTorrentFromVideo(video, newVideoPath, callback)
532 },
533
534 function videoExtension (callback) {
535 video.save().asCallback(callback)
536 }
537
538 ], function (err) {
539 if (err) {
540 // Autodescruction...
541 video.destroy().asCallback(function (err) {
542 if (err) logger.error('Cannot destruct video after transcoding failure.', { error: err })
543 })
544
545 return finalCallback(err)
546 }
547
548 return finalCallback(null)
549 })
550 })
551 .run()
552}
553
506// ------------------------------ STATICS ------------------------------ 554// ------------------------------ STATICS ------------------------------
507 555
508function generateThumbnailFromData (video, thumbnailData, callback) { 556function generateThumbnailFromData (video, thumbnailData, callback) {
@@ -737,6 +785,30 @@ function removePreview (video, callback) {
737 fs.unlink(constants.CONFIG.STORAGE.PREVIEWS_DIR + video.getPreviewName(), callback) 785 fs.unlink(constants.CONFIG.STORAGE.PREVIEWS_DIR + video.getPreviewName(), callback)
738} 786}
739 787
788function createTorrentFromVideo (video, videoPath, callback) {
789 const options = {
790 announceList: [
791 [ constants.CONFIG.WEBSERVER.WS + '://' + constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT + '/tracker/socket' ]
792 ],
793 urlList: [
794 constants.CONFIG.WEBSERVER.URL + constants.STATIC_PATHS.WEBSEED + video.getVideoFilename()
795 ]
796 }
797
798 createTorrent(videoPath, options, function (err, torrent) {
799 if (err) return callback(err)
800
801 const filePath = pathUtils.join(constants.CONFIG.STORAGE.TORRENTS_DIR, video.getTorrentName())
802 fs.writeFile(filePath, torrent, function (err) {
803 if (err) return callback(err)
804
805 const parsedTorrent = parseTorrent(torrent)
806 video.set('infoHash', parsedTorrent.infoHash)
807 video.validate().asCallback(callback)
808 })
809 })
810}
811
740function createPreview (video, videoPath, callback) { 812function createPreview (video, videoPath, callback) {
741 generateImage(video, videoPath, constants.CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), callback) 813 generateImage(video, videoPath, constants.CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), callback)
742} 814}