From 6a94a109b4b89a97fe7bfeded3125fb7aad2ac3b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 11 Nov 2016 11:52:24 +0100 Subject: [PATCH] Server: add video preview --- .gitignore | 1 + config/default.yaml | 1 + server.js | 7 ++++++- server/initializers/checker.js | 2 +- server/initializers/constants.js | 4 ++++ server/models/video.js | 27 ++++++++++++++++++++++++++- 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index bd43f0bd1..28dec58f3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /uploads/ /videos/ /thumbnails/ +/previews/ /certs/ /logs/ /torrents/ diff --git a/config/default.yaml b/config/default.yaml index ad27b4eb8..90f4b9466 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -16,5 +16,6 @@ storage: certs: 'certs/' videos: 'videos/' logs: 'logs/' + previews: 'previews/' thumbnails: 'thumbnails/' torrents: 'torrents/' diff --git a/server.js b/server.js index d3d3661ad..16e27e852 100644 --- 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')) diff --git a/server/initializers/checker.js b/server/initializers/checker.js index dad8525fa..aea013fa9 100644 --- a/server/initializers/checker.js +++ b/server/initializers/checker.js @@ -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 = [] diff --git a/server/initializers/constants.js b/server/initializers/constants.js index d345776ff..a50eb2f66 100644 --- a/server/initializers/constants.js +++ b/server/initializers/constants.js @@ -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, diff --git a/server/models/video.js b/server/models/video.js index 673ccabf8..bfa1fca15 100644 --- a/server/models/video.js +++ b/server/models/video.js @@ -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)