Server: add video preview
authorChocobozzz <florian.bigard@gmail.com>
Fri, 11 Nov 2016 10:52:24 +0000 (11:52 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Wed, 16 Nov 2016 19:29:26 +0000 (20:29 +0100)
.gitignore
config/default.yaml
server.js
server/initializers/checker.js
server/initializers/constants.js
server/models/video.js

index bd43f0bd1c4f80d912571b05695a6c6594eb2d6e..28dec58f3ded7da845dd17bd11367c09b44bb655 100644 (file)
@@ -8,6 +8,7 @@
 /uploads/
 /videos/
 /thumbnails/
+/previews/
 /certs/
 /logs/
 /torrents/
index ad27b4eb899f7156774ab00104e9db0c5cc97953..90f4b94665785fd419e0df5ed8660840b7d7a5b1 100644 (file)
@@ -16,5 +16,6 @@ storage:
   certs: 'certs/'
   videos: 'videos/'
   logs: 'logs/'
+  previews: 'previews/'
   thumbnails: 'thumbnails/'
   torrents: 'torrents/'
index d3d3661add49ceec6ed25750ba999a065beaacb9..16e27e852cba100efa20ee9614f82a53599a100a 100644 (file)
--- a/server.js
+++ b/server.js
@@ -71,7 +71,8 @@ const apiRoute = '/api/' + constants.API_VERSION
 app.use(apiRoute, routes.api)
 app.use('/', routes.client)
 
-// Static files
+// Static client files
+// TODO: move in client
 app.use('/client', express.static(path.join(__dirname, '/client/dist'), { maxAge: constants.STATIC_MAX_AGE }))
 // 404 for static files not found
 app.use('/client/*', function (req, res, next) {
@@ -89,6 +90,10 @@ app.use(constants.STATIC_PATHS.WEBSEED, cors(), express.static(videosPhysicalPat
 const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR
 app.use(constants.STATIC_PATHS.THUMBNAILS, express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE }))
 
+// Video previews path for express
+const previewsPhysicalPath = constants.CONFIG.STORAGE.PREVIEWS_DIR
+app.use(constants.STATIC_PATHS.PREVIEWS, express.static(previewsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE }))
+
 // Always serve index client page
 app.use('/*', function (req, res, next) {
   res.sendFile(path.join(__dirname, './client/dist/index.html'))
index dad8525fa72e10492aaf0d40c6d4a43f53e0c481..aea013fa9ab169a072f8f048c7cc7e151901ae86 100644 (file)
@@ -30,7 +30,7 @@ function checkMissedConfig () {
   const required = [ 'listen.port',
     'webserver.https', 'webserver.hostname', 'webserver.port',
     'database.hostname', 'database.port', 'database.suffix',
-    'storage.certs', 'storage.videos', 'storage.logs', 'storage.thumbnails'
+    'storage.certs', 'storage.videos', 'storage.logs', 'storage.thumbnails', 'storage.previews'
   ]
   const miss = []
 
index d345776ff2afb53e74cd371cfce281ce637b5e2f..a50eb2f662fed5930ac6c089b488d48caa92d1c2 100644 (file)
@@ -44,6 +44,7 @@ const CONFIG = {
     LOG_DIR: path.join(__dirname, '..', '..', config.get('storage.logs')),
     VIDEOS_DIR: path.join(__dirname, '..', '..', config.get('storage.videos')),
     THUMBNAILS_DIR: path.join(__dirname, '..', '..', config.get('storage.thumbnails')),
+    PREVIEWS_DIR: path.join(__dirname, '..', '..', config.get('storage.previews')),
     TORRENTS_DIR: path.join(__dirname, '..', '..', config.get('storage.torrents'))
   },
   WEBSERVER: {
@@ -135,6 +136,7 @@ const BCRYPT_SALT_SIZE = 10
 
 // Express static paths (router)
 const STATIC_PATHS = {
+  PREVIEWS: '/static/previews',
   THUMBNAILS: '/static/thumbnails',
   TORRENTS: '/static/torrents/',
   WEBSEED: '/static/webseed/'
@@ -145,6 +147,7 @@ let STATIC_MAX_AGE = '30d'
 
 // Videos thumbnail size
 const THUMBNAILS_SIZE = '200x110'
+const PREVIEWS_SIZE = '640x480'
 
 const USER_ROLES = {
   ADMIN: 'admin',
@@ -179,6 +182,7 @@ module.exports = {
   REQUESTS_INTERVAL,
   REQUESTS_LIMIT,
   RETRY_REQUESTS,
+  PREVIEWS_SIZE,
   SEARCHABLE_COLUMNS,
   SORTABLE_COLUMNS,
   STATIC_MAX_AGE,
index 673ccabf8ef3337f05cb6f215dc86598558a59a9..bfa1fca15415eb7d18c94a031b0b3b5c9fe31ae9 100644 (file)
@@ -82,6 +82,9 @@ VideoSchema.pre('remove', function (next) {
       },
       function (callback) {
         removeTorrent(video, callback)
+      },
+      function (callback) {
+        removePreview(video, callback)
       }
     )
   }
@@ -125,6 +128,9 @@ VideoSchema.pre('save', function (next) {
       },
       function (callback) {
         createThumbnail(videoPath, callback)
+      },
+      function (callback) {
+        createPreview(videoPath, callback)
       }
     )
 
@@ -261,11 +267,30 @@ function removeFile (video, callback) {
   fs.unlink(constants.CONFIG.STORAGE.VIDEOS_DIR + video.filename, callback)
 }
 
-// Maybe the torrent is not seeded, but we catch the error to don't stop the removing process
 function removeTorrent (video, callback) {
   fs.unlink(constants.CONFIG.STORAGE.TORRENTS_DIR + video.filename + '.torrent', callback)
 }
 
+function removePreview (video, callback) {
+  // Same name than video thumnail
+  // TODO: refractoring
+  fs.unlink(constants.CONFIG.STORAGE.PREVIEWS_DIR + video.thumbnail, callback)
+}
+
+function createPreview (videoPath, callback) {
+  const filename = pathUtils.basename(videoPath) + '.jpg'
+  ffmpeg(videoPath)
+    .on('error', callback)
+    .on('end', function () {
+      callback(null, filename)
+    })
+    .thumbnail({
+      count: 1,
+      folder: constants.CONFIG.STORAGE.PREVIEWS_DIR,
+      filename: filename
+    })
+}
+
 function createThumbnail (videoPath, callback) {
   const filename = pathUtils.basename(videoPath) + '.jpg'
   ffmpeg(videoPath)